-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d76016e
commit 434c3da
Showing
26 changed files
with
2,102 additions
and
621 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,62 @@ | ||
#!/usr/bin/env node | ||
|
||
import * as command from "@oclif/command"; | ||
import * as errors from "@oclif/errors"; | ||
|
||
async function alfa() { | ||
try { | ||
await command.run(); | ||
} catch (err) { | ||
errors.handle(err); | ||
} | ||
} | ||
|
||
alfa(); | ||
/// <reference types="node" /> | ||
|
||
import * as path from "path"; | ||
import * as process from "process"; | ||
import * as tty from "tty"; | ||
|
||
import { Command, Flag } from "@siteimprove/alfa-command"; | ||
import { None } from "@siteimprove/alfa-option"; | ||
import { Err } from "@siteimprove/alfa-result"; | ||
|
||
import * as pkg from "../package.json"; | ||
|
||
import audit from "./alfa/command/audit"; | ||
import scrape from "./alfa/command/scrape"; | ||
|
||
const { | ||
argv: [node, bin], | ||
platform, | ||
arch, | ||
version, | ||
} = process; | ||
|
||
const application = Command.withSubcommands( | ||
path.basename(bin), | ||
`${pkg.name}/${pkg.version} ${platform}-${arch} node-${version}`, | ||
`The tool for all your accessibility needs on the command line.`, | ||
{ | ||
help: Flag.help("Display the help information."), | ||
version: Flag.version("Output the current version."), | ||
}, | ||
(self) => ({ | ||
audit: audit(self), | ||
scrape: scrape(self), | ||
}), | ||
None | ||
); | ||
|
||
application | ||
.run(process.argv.slice(2)) | ||
.catch((err: Error) => Err.of(`${err.message}`)) | ||
.then((result) => { | ||
let stream: tty.WriteStream; | ||
let output: string; | ||
|
||
if (result.isOk()) { | ||
stream = process.stdout; | ||
output = result.get(); | ||
} else { | ||
stream = process.stderr; | ||
output = result.getErr(); | ||
} | ||
|
||
output = output.trimRight(); | ||
|
||
if (output.length > 0) { | ||
stream.write(output + "\n"); | ||
} | ||
|
||
process.exit(result.isOk() ? 0 : 1); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { Command } from "@siteimprove/alfa-command"; | ||
import { Option } from "@siteimprove/alfa-option"; | ||
|
||
import { Arguments } from "./audit/arguments"; | ||
import { Flags } from "./audit/flags"; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export default (parent: Command) => | ||
Command.withArguments( | ||
"audit", | ||
parent.version, | ||
"Perform an accessibility audit of a page.", | ||
Flags, | ||
Arguments, | ||
Option.of(parent), | ||
() => async (...args) => { | ||
const { run } = await import("./audit/run"); | ||
return run(...args); | ||
} | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { Argument } from "@siteimprove/alfa-command"; | ||
|
||
export const Arguments = { | ||
url: Argument.string( | ||
"url", | ||
`The URL of the page to audit. Both remote and local protocols are | ||
supported so the URL can either be an address of a remote page or a path to | ||
a local file. If no URL is provided, an already serialised page will be read | ||
from stdin.` | ||
).optional(), | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { Flag } from "@siteimprove/alfa-command"; | ||
|
||
import * as scrape from "../scrape/flags"; | ||
|
||
export const Flags = { | ||
help: Flag.help("Display the help information."), | ||
|
||
interactive: Flag.boolean( | ||
"interactive", | ||
"Whether or not to run an interactive audit." | ||
) | ||
.alias("i") | ||
.default(false), | ||
|
||
format: Flag.string("format", "The reporting format to use.") | ||
.type("format or package") | ||
.alias("f") | ||
.default("earl"), | ||
|
||
output: Flag.string( | ||
"output", | ||
`The path to write results to. If no path is provided, results are written | ||
to stdout.` | ||
) | ||
.type("path") | ||
.alias("o") | ||
.optional(), | ||
|
||
outcomes: Flag.string( | ||
"outcome", | ||
`The type of outcome to include in the results. If not provided, all types | ||
of outcomes are included. This flag can be repeated to include multiple | ||
types of outcomes.` | ||
) | ||
.choices("passed", "failed", "inapplicable", "cantTell") | ||
.repeatable() | ||
.optional(), | ||
|
||
...scrape.Flags, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/// <reference types="node" /> | ||
|
||
import * as fs from "fs"; | ||
|
||
import { Audit, Outcome } from "@siteimprove/alfa-act"; | ||
import { Command } from "@siteimprove/alfa-command"; | ||
import { Node } from "@siteimprove/alfa-dom"; | ||
import { Formatter } from "@siteimprove/alfa-formatter"; | ||
import { Iterable } from "@siteimprove/alfa-iterable"; | ||
import { None } from "@siteimprove/alfa-option"; | ||
import { Ok } from "@siteimprove/alfa-result"; | ||
import { Rules, Question } from "@siteimprove/alfa-rules"; | ||
import { Page } from "@siteimprove/alfa-web"; | ||
|
||
import { Oracle } from "../../oracle"; | ||
|
||
import type { Arguments } from "./arguments"; | ||
import type { Flags } from "./flags"; | ||
|
||
import * as scrape from "../scrape/run"; | ||
|
||
type Input = Page; | ||
type Target = Node | Iterable<Node>; | ||
|
||
export const run: Command.Runner<typeof Flags, typeof Arguments> = async ({ | ||
flags, | ||
args: { url: target }, | ||
}) => { | ||
const formatter = Formatter.load<Input, Target, Question>(flags.format); | ||
|
||
if (formatter.isErr()) { | ||
return formatter; | ||
} | ||
|
||
let json: string; | ||
|
||
if (target.isNone()) { | ||
json = fs.readFileSync(0, "utf-8"); | ||
} else { | ||
const result = await scrape.run({ | ||
flags: { | ||
...flags, | ||
output: None, | ||
}, | ||
args: { | ||
url: target.get(), | ||
}, | ||
}); | ||
|
||
if (result.isErr()) { | ||
return result; | ||
} | ||
|
||
json = result.get(); | ||
} | ||
|
||
const page = Page.from(JSON.parse(json)); | ||
|
||
const audit = Rules.reduce( | ||
(audit, rule) => audit.add(rule), | ||
Audit.of<Input, Target, Question>( | ||
page, | ||
flags.interactive ? Oracle(page) : undefined | ||
) | ||
); | ||
|
||
let outcomes = await audit.evaluate(); | ||
|
||
if (flags.outcomes.isSome()) { | ||
const filter = new Set(flags.outcomes.get()); | ||
|
||
outcomes = Iterable.filter(outcomes, (outcome) => { | ||
if (Outcome.isPassed(outcome)) { | ||
return filter.has("passed"); | ||
} | ||
|
||
if (Outcome.isFailed(outcome)) { | ||
return filter.has("failed"); | ||
} | ||
|
||
if (Outcome.isInapplicable(outcome)) { | ||
return filter.has("inapplicable"); | ||
} | ||
|
||
return filter.has("cantTell"); | ||
}); | ||
} | ||
|
||
const output = formatter.get()(page, outcomes); | ||
|
||
if (flags.output.isNone()) { | ||
return Ok.of(output); | ||
} else { | ||
fs.writeFileSync(flags.output.get() + "\n", output); | ||
return Ok.of(""); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { Command } from "@siteimprove/alfa-command"; | ||
import { Option } from "@siteimprove/alfa-option"; | ||
|
||
import { Arguments } from "./scrape/arguments"; | ||
import { Flags } from "./scrape/flags"; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export default (parent: Command) => | ||
Command.withArguments( | ||
"scrape", | ||
parent.version, | ||
"Scrape a page and output it in a serialisable format.", | ||
Flags, | ||
Arguments, | ||
Option.of(parent), | ||
() => async (...args) => { | ||
const { run } = await import("./scrape/run"); | ||
return run(...args); | ||
} | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { Argument } from "@siteimprove/alfa-command"; | ||
|
||
export const Arguments = { | ||
url: Argument.string( | ||
"url", | ||
`The URL of the page to scrape. Both remote and local protocols are | ||
supported so the URL can either be an address of a remote page or a path to | ||
a local file.` | ||
), | ||
}; |
Oops, something went wrong.