@hawkeyexl/manni 2.7.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{chunk-2672QGFM.js → chunk-MB3DIO7S.js} +100 -95
- package/dist/chunk-MB3DIO7S.js.map +1 -0
- package/dist/{chunk-3V4FMZHD.js → chunk-MHB242JA.js} +2 -2
- package/dist/{chunk-ELRE54LH.js → chunk-O6RXG33V.js} +58 -12
- package/dist/chunk-O6RXG33V.js.map +1 -0
- package/dist/cli.js +100 -9
- package/dist/cli.js.map +1 -1
- package/dist/docmeta.js +2 -2
- package/dist/index.d.ts +36 -6
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-2672QGFM.js.map +0 -1
- package/dist/chunk-ELRE54LH.js.map +0 -1
- /package/dist/{chunk-3V4FMZHD.js.map → chunk-MHB242JA.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
readStdin,
|
|
8
8
|
reportConfig,
|
|
9
9
|
splitList
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-MHB242JA.js";
|
|
11
11
|
import {
|
|
12
12
|
CiteError,
|
|
13
13
|
KeyError,
|
|
@@ -40,9 +40,10 @@ import {
|
|
|
40
40
|
shortPin,
|
|
41
41
|
shortSrc,
|
|
42
42
|
spellSource
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-O6RXG33V.js";
|
|
44
44
|
import {
|
|
45
45
|
COMMON_FORMAT_LIST,
|
|
46
|
+
FAMILY_CONFIG_NAMES,
|
|
46
47
|
OMITTED_WHEN_CLEAN,
|
|
47
48
|
REPORT_FORMATS,
|
|
48
49
|
REPORT_FORMAT_LIST,
|
|
@@ -62,6 +63,7 @@ import {
|
|
|
62
63
|
isMachineFormat,
|
|
63
64
|
isReportFormat,
|
|
64
65
|
locateFrontmatter,
|
|
66
|
+
matchesFileGlob,
|
|
65
67
|
notice,
|
|
66
68
|
package_default,
|
|
67
69
|
palette,
|
|
@@ -78,7 +80,7 @@ import {
|
|
|
78
80
|
splitPageArgument,
|
|
79
81
|
terminalConfirm,
|
|
80
82
|
valeConfigPath
|
|
81
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-MB3DIO7S.js";
|
|
82
84
|
|
|
83
85
|
// src/cli.ts
|
|
84
86
|
import { Command as Command5 } from "commander";
|
|
@@ -172,6 +174,7 @@ async function crawl(opts, analyzer) {
|
|
|
172
174
|
const frontier = [];
|
|
173
175
|
const seen = /* @__PURE__ */ new Set();
|
|
174
176
|
const visited = /* @__PURE__ */ new Set();
|
|
177
|
+
const excluded = /* @__PURE__ */ new Set();
|
|
175
178
|
const progress = opts.onProgress ?? (() => void 0);
|
|
176
179
|
const enqueue = (raw, source) => {
|
|
177
180
|
let url;
|
|
@@ -184,6 +187,10 @@ async function crawl(opts, analyzer) {
|
|
|
184
187
|
}
|
|
185
188
|
if (source !== "seed" && !isPageLink(url)) return;
|
|
186
189
|
if (!opts.seeds.some((seed) => sameHost(seed, url))) return;
|
|
190
|
+
if (opts.exclude?.matches(url) === true) {
|
|
191
|
+
excluded.add(key);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
187
194
|
if (seen.has(key)) return;
|
|
188
195
|
seen.add(key);
|
|
189
196
|
frontier.push({ url, key, source });
|
|
@@ -199,6 +206,9 @@ async function crawl(opts, analyzer) {
|
|
|
199
206
|
};
|
|
200
207
|
for (const seed of opts.seeds) enqueue(seed, "seed");
|
|
201
208
|
if (opts.crawl) for (const url of opts.extra) enqueue(url, "sitemap");
|
|
209
|
+
if (excluded.size > 0) {
|
|
210
|
+
progress({ kind: "excluded", urls: excluded.size, patterns: opts.exclude?.patterns.length ?? 0 });
|
|
211
|
+
}
|
|
202
212
|
const pages = [];
|
|
203
213
|
let duplicates = 0;
|
|
204
214
|
const capped = () => opts.maxPages !== void 0 && pages.length >= opts.maxPages;
|
|
@@ -229,7 +239,37 @@ async function crawl(opts, analyzer) {
|
|
|
229
239
|
}
|
|
230
240
|
const skipped2 = frontier.length - pages.length - duplicates;
|
|
231
241
|
progress({ kind: "done", checked: pages.length, skipped: skipped2 });
|
|
232
|
-
return { pages, discovered: frontier.length, skipped: skipped2, duplicates };
|
|
242
|
+
return { pages, discovered: frontier.length, skipped: skipped2, duplicates, excluded: excluded.size };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// src/a11y/core/exclude.ts
|
|
246
|
+
var MUST_START_WITH_SLASH = 'must start with "/": it matches a URL path.';
|
|
247
|
+
function isUrlPathGlob(pattern) {
|
|
248
|
+
return pattern.startsWith("/");
|
|
249
|
+
}
|
|
250
|
+
function excludePath(url) {
|
|
251
|
+
let parsed;
|
|
252
|
+
try {
|
|
253
|
+
parsed = new URL(url);
|
|
254
|
+
} catch {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
const path = parsed.pathname;
|
|
258
|
+
return path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
|
|
259
|
+
}
|
|
260
|
+
function createExcludeFilter(patterns) {
|
|
261
|
+
const list = [...patterns];
|
|
262
|
+
const match = (url) => {
|
|
263
|
+
if (list.length === 0) return null;
|
|
264
|
+
const path = excludePath(url);
|
|
265
|
+
if (path === null) return null;
|
|
266
|
+
return list.find((pattern) => matchesFileGlob(path, pattern.glob)) ?? null;
|
|
267
|
+
};
|
|
268
|
+
return {
|
|
269
|
+
patterns: list,
|
|
270
|
+
match,
|
|
271
|
+
matches: (url) => match(url) !== null
|
|
272
|
+
};
|
|
233
273
|
}
|
|
234
274
|
|
|
235
275
|
// src/a11y/core/seeds.ts
|
|
@@ -401,7 +441,8 @@ var CHECK_DEFAULTS = Object.freeze({
|
|
|
401
441
|
crawl: true,
|
|
402
442
|
tags: [],
|
|
403
443
|
severity: "notice",
|
|
404
|
-
timeout: 3e4
|
|
444
|
+
timeout: 3e4,
|
|
445
|
+
exclude: []
|
|
405
446
|
});
|
|
406
447
|
async function runCheck2(opts, deps) {
|
|
407
448
|
const { analyzer } = deps;
|
|
@@ -413,6 +454,12 @@ async function runCheck2(opts, deps) {
|
|
|
413
454
|
if (!isHttpUrl(url)) throw new A11yError(`Not an http(s) URL: "${url}".`);
|
|
414
455
|
}
|
|
415
456
|
const seeds = opts.urls.map(normalizeUrl);
|
|
457
|
+
const exclude = createExcludeFilter(opts.exclude);
|
|
458
|
+
const contradictions = seeds.map((seed) => {
|
|
459
|
+
const pattern = exclude.match(seed);
|
|
460
|
+
return pattern === null ? null : `${pattern.source} excludes the seed ${seed}.`;
|
|
461
|
+
}).filter((line) => line !== null);
|
|
462
|
+
if (contradictions.length > 0) throw new A11yError(contradictions.join("\n"));
|
|
416
463
|
let sitemap = { source: null, urls: [] };
|
|
417
464
|
const first = seeds[0];
|
|
418
465
|
if (opts.crawl && first !== void 0) {
|
|
@@ -425,6 +472,7 @@ async function runCheck2(opts, deps) {
|
|
|
425
472
|
crawl: opts.crawl,
|
|
426
473
|
maxPages: opts.maxPages,
|
|
427
474
|
extra: sitemap.urls,
|
|
475
|
+
exclude,
|
|
428
476
|
analyze: { tags: opts.tags, timeout: opts.timeout },
|
|
429
477
|
onProgress: deps.onProgress
|
|
430
478
|
},
|
|
@@ -446,7 +494,7 @@ function finishPage(page, floor) {
|
|
|
446
494
|
const score = applicable === 0 ? null : Math.round(100 * page.passes / applicable);
|
|
447
495
|
return { ...page, violations, score };
|
|
448
496
|
}
|
|
449
|
-
function summarize(results, { discovered, skipped: skipped2, duplicates }, sitemap, crawl2) {
|
|
497
|
+
function summarize(results, { discovered, skipped: skipped2, duplicates, excluded }, sitemap, crawl2) {
|
|
450
498
|
const bySeverity = { notice: 0, warning: 0, error: 0 };
|
|
451
499
|
let failed = 0;
|
|
452
500
|
let violations = 0;
|
|
@@ -462,6 +510,7 @@ function summarize(results, { discovered, skipped: skipped2, duplicates }, sitem
|
|
|
462
510
|
checked: results.length,
|
|
463
511
|
skipped: skipped2,
|
|
464
512
|
duplicates,
|
|
513
|
+
excluded,
|
|
465
514
|
failed,
|
|
466
515
|
violations,
|
|
467
516
|
bySeverity,
|
|
@@ -585,7 +634,7 @@ function reason(err) {
|
|
|
585
634
|
|
|
586
635
|
// src/a11y/core/config.ts
|
|
587
636
|
var SECTION = "a11y";
|
|
588
|
-
var CONFIG_KEYS = ["urls", "crawl", "maxPages", "tags", "severity", "timeout"];
|
|
637
|
+
var CONFIG_KEYS = ["urls", "crawl", "maxPages", "tags", "severity", "timeout", "exclude"];
|
|
589
638
|
var CONFIG_FILE = {
|
|
590
639
|
section: SECTION,
|
|
591
640
|
// The a11y tool never had a pre-family file of its own.
|
|
@@ -625,8 +674,21 @@ function parseA11yConfig(value, source) {
|
|
|
625
674
|
if (obj.timeout !== void 0) {
|
|
626
675
|
config.timeout = asPositiveInteger(obj.timeout, "timeout", source);
|
|
627
676
|
}
|
|
677
|
+
if (obj.exclude !== void 0) config.exclude = asExcludes(obj.exclude, source);
|
|
628
678
|
return config;
|
|
629
679
|
}
|
|
680
|
+
function excludeEntryLabel(source, index) {
|
|
681
|
+
return `${source}: "${SECTION}.exclude[${String(index)}]"`;
|
|
682
|
+
}
|
|
683
|
+
function asExcludes(value, source) {
|
|
684
|
+
const globs = asStringList(value, "exclude", source);
|
|
685
|
+
globs.forEach((glob, i) => {
|
|
686
|
+
const at = excludeEntryLabel(source, i);
|
|
687
|
+
if (glob === "") throw new A11yError(`${at} must be a non-empty string.`);
|
|
688
|
+
if (!isUrlPathGlob(glob)) throw new A11yError(`${at} ${MUST_START_WITH_SLASH}`);
|
|
689
|
+
});
|
|
690
|
+
return globs;
|
|
691
|
+
}
|
|
630
692
|
function asStringList(value, field, source) {
|
|
631
693
|
if (!Array.isArray(value) || !value.every((v) => typeof v === "string")) {
|
|
632
694
|
throw new A11yError(`${source}: "${SECTION}.${field}" must be a list of strings.`);
|
|
@@ -717,7 +779,7 @@ function renderPretty(run, opts) {
|
|
|
717
779
|
for (const v of page.violations) lines.push(...violationLines(v, c));
|
|
718
780
|
}
|
|
719
781
|
const failed = summary.failed;
|
|
720
|
-
const footer = `${summary.violations} violation${summary.violations === 1 ? "" : "s"} on ${failed} of ${summary.checked} pages` + (summary.skipped > 0 ? `; ${summary.skipped} skipped (--max-pages)` : "") + (summary.duplicates > 0 ? `; ${summary.duplicates} duplicate${summary.duplicates === 1 ? "" : "s"} dropped` : "");
|
|
782
|
+
const footer = `${summary.violations} violation${summary.violations === 1 ? "" : "s"} on ${failed} of ${summary.checked} pages` + (summary.skipped > 0 ? `; ${summary.skipped} skipped (--max-pages)` : "") + (summary.duplicates > 0 ? `; ${summary.duplicates} duplicate${summary.duplicates === 1 ? "" : "s"} dropped` : "") + (summary.excluded > 0 ? `; ${summary.excluded} excluded` : "");
|
|
721
783
|
lines.push("");
|
|
722
784
|
lines.push(failed > 0 ? c.red(footer) : c.green(footer));
|
|
723
785
|
return lines.join("\n");
|
|
@@ -826,6 +888,9 @@ function terminalReporter(opts) {
|
|
|
826
888
|
if (event.source === null) show("No sitemap; following links");
|
|
827
889
|
else showUrl("Sitemap: ", event.source, ` (${plural(event.urls, "page")})`);
|
|
828
890
|
return;
|
|
891
|
+
case "excluded":
|
|
892
|
+
show(`Excluded ${plural(event.urls, "page")} (${plural(event.patterns, "pattern")})`);
|
|
893
|
+
return;
|
|
829
894
|
case "page":
|
|
830
895
|
queued = event.queued;
|
|
831
896
|
showUrl(`${c.dim(counter(event.index, queued))} `, event.url);
|
|
@@ -859,6 +924,9 @@ function plainReporter(stream) {
|
|
|
859
924
|
if (event.source === null) say("no sitemap; following links");
|
|
860
925
|
else say(`sitemap ${event.source} (${plural(event.urls, "page")})`);
|
|
861
926
|
return;
|
|
927
|
+
case "excluded":
|
|
928
|
+
say(`excluded ${plural(event.urls, "page")} (${plural(event.patterns, "pattern")})`);
|
|
929
|
+
return;
|
|
862
930
|
case "page":
|
|
863
931
|
queued = event.queued;
|
|
864
932
|
say(`${counter(event.index, queued)} ${event.url}`);
|
|
@@ -933,6 +1001,18 @@ function resolveMaxPages(flag, configured) {
|
|
|
933
1001
|
function resolveCrawl(flag, configured) {
|
|
934
1002
|
return flag ?? configured ?? CHECK_DEFAULTS.crawl;
|
|
935
1003
|
}
|
|
1004
|
+
function assertExcludeGlobs(globs) {
|
|
1005
|
+
return globs.map((glob) => {
|
|
1006
|
+
if (!isUrlPathGlob(glob)) {
|
|
1007
|
+
throw new A11yError(`--exclude "${glob}" ${MUST_START_WITH_SLASH}`);
|
|
1008
|
+
}
|
|
1009
|
+
return { glob, source: `--exclude "${glob}"` };
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
function configExcludeGlobs(globs, source) {
|
|
1013
|
+
const file = source ?? FAMILY_CONFIG_NAMES[0] ?? "manni.config.yaml";
|
|
1014
|
+
return globs.map((glob, i) => ({ glob, source: excludeEntryLabel(file, i) }));
|
|
1015
|
+
}
|
|
936
1016
|
function assertSeverity(value) {
|
|
937
1017
|
if (!isSeverity(value)) {
|
|
938
1018
|
throw new A11yError(`Unknown --severity "${value}". Use ${SEVERITY_LIST}.`);
|
|
@@ -948,7 +1028,12 @@ function buildProgram2() {
|
|
|
948
1028
|
).option("-f, --format <format>", `output: ${A11Y_FORMAT_LIST}`, "pretty").option("--crawl", "crawl from the given URLs: sitemap and link following (default)").option("--no-crawl", "check exactly the given URLs: no sitemap, no link following").option(
|
|
949
1029
|
"--max-pages <n>",
|
|
950
1030
|
"cap on pages checked; the rest are reported as skipped (default: no cap)"
|
|
951
|
-
).option("--no-max-pages", "check every page found, ignoring a configured maxPages").option(
|
|
1031
|
+
).option("--no-max-pages", "check every page found, ignoring a configured maxPages").option(
|
|
1032
|
+
"--exclude <glob>",
|
|
1033
|
+
"URL path glob to keep out of the crawl; repeatable",
|
|
1034
|
+
collect2,
|
|
1035
|
+
[]
|
|
1036
|
+
).option("--tags <list>", "comma-separated axe tags to restrict the rules to").option(
|
|
952
1037
|
"--severity <level>",
|
|
953
1038
|
`minimum severity reported: ${SEVERITY_LIST}`,
|
|
954
1039
|
CHECK_DEFAULTS.severity
|
|
@@ -972,6 +1057,7 @@ function buildProgram2() {
|
|
|
972
1057
|
const severity = assertSeverity(options.severity);
|
|
973
1058
|
const maxPages = parseMaxPages(options.maxPages);
|
|
974
1059
|
const timeout = positiveInteger(options.timeout, "--timeout");
|
|
1060
|
+
const exclude = assertExcludeGlobs(options.exclude);
|
|
975
1061
|
const loaded = options.config === false ? { config: {}, source: null, collections: [] } : await loadA11yConfig(process.cwd(), options.config);
|
|
976
1062
|
const cfg = loaded.config;
|
|
977
1063
|
const seeds = resolveSeeds({
|
|
@@ -992,6 +1078,11 @@ function buildProgram2() {
|
|
|
992
1078
|
// to, and `--no-max-pages` is the typed way to ask for none.
|
|
993
1079
|
maxPages: resolveMaxPages(maxPages, cfg.maxPages),
|
|
994
1080
|
tags: options.tags !== void 0 ? splitList2(options.tags) : cfg.tags ?? CHECK_DEFAULTS.tags,
|
|
1081
|
+
// A typed flag replaces the config list entirely; the two do not
|
|
1082
|
+
// merge. Merging would only ever let a run exclude *more* than
|
|
1083
|
+
// the repository's default, so checking one excluded section on
|
|
1084
|
+
// purpose would need --no-config, which also drops collections:.
|
|
1085
|
+
exclude: typed("exclude") ? exclude : configExcludeGlobs(cfg.exclude ?? [], loaded.source),
|
|
995
1086
|
severity: typed("severity") ? severity : cfg.severity ?? CHECK_DEFAULTS.severity,
|
|
996
1087
|
timeout: typed("timeout") ? timeout : cfg.timeout ?? CHECK_DEFAULTS.timeout
|
|
997
1088
|
},
|