nfunc-mcp 0.4.0 → 0.5.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 +38 -4
- package/dist/mappers/a11yDedupe.js +38 -7
- package/dist/mappers/a11yDedupe.js.map +1 -1
- package/dist/mappers/defectFormatter.d.ts +9 -1
- package/dist/mappers/defectFormatter.js +53 -13
- package/dist/mappers/defectFormatter.js.map +1 -1
- package/dist/mappers/priorityMapper.d.ts +42 -0
- package/dist/mappers/priorityMapper.js +58 -0
- package/dist/mappers/priorityMapper.js.map +1 -1
- package/dist/mappers/runComparator.d.ts +85 -0
- package/dist/mappers/runComparator.js +165 -0
- package/dist/mappers/runComparator.js.map +1 -0
- package/dist/mappers/wcagLevels.d.ts +73 -0
- package/dist/mappers/wcagLevels.js +320 -0
- package/dist/mappers/wcagLevels.js.map +1 -0
- package/dist/tools/accessibility.d.ts +1 -0
- package/dist/tools/accessibility.js +488 -63
- package/dist/tools/accessibility.js.map +1 -1
- package/dist/tools/lighthouse.js +370 -102
- package/dist/tools/lighthouse.js.map +1 -1
- package/dist/utils/batchState.d.ts +75 -0
- package/dist/utils/batchState.js +128 -0
- package/dist/utils/batchState.js.map +1 -0
- package/dist/utils/outputParsers.js +26 -30
- package/dist/utils/outputParsers.js.map +1 -1
- package/dist/utils/psiParser.d.ts +11 -0
- package/dist/utils/psiParser.js +2 -2
- package/dist/utils/psiParser.js.map +1 -1
- package/dist/utils/urlInput.d.ts +30 -0
- package/dist/utils/urlInput.js +130 -0
- package/dist/utils/urlInput.js.map +1 -0
- package/docs/manual.md +218 -7
- package/package.json +1 -1
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared machinery for tools that process a list of URLs across several calls.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from the PSI runner, where every piece of it was earned the hard
|
|
5
|
+
* way: an MCP client backgrounds a tool call at 120 seconds, local Lighthouse
|
|
6
|
+
* takes 20-40 seconds per URL per form factor, and both PSI and pa11y fail
|
|
7
|
+
* intermittently on real sites. A batch therefore cannot be one long call, and
|
|
8
|
+
* a failure partway through must not cost the runs that already succeeded.
|
|
9
|
+
*
|
|
10
|
+
* The contract is: bound each call by a clock, write results to disk as they
|
|
11
|
+
* land, merge rather than overwrite an index, and hand back a cursor.
|
|
12
|
+
*/
|
|
13
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
/** Default per-call ceiling. Below the 120s at which Claude Code backgrounds a call. */
|
|
16
|
+
export const DEFAULT_MAX_SECONDS_PER_CALL = 100;
|
|
17
|
+
export function encodeCursor(index) {
|
|
18
|
+
return Buffer.from(JSON.stringify({ i: index })).toString("base64url");
|
|
19
|
+
}
|
|
20
|
+
export function decodeCursor(cursor) {
|
|
21
|
+
if (!cursor)
|
|
22
|
+
return 0;
|
|
23
|
+
try {
|
|
24
|
+
const parsed = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
25
|
+
return typeof parsed.i === "number" && parsed.i >= 0 ? parsed.i : 0;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Cross-product of URLs and variants, in URL-major order so a partial run covers whole pages. */
|
|
32
|
+
export function buildUnits(urls, variants) {
|
|
33
|
+
const units = [];
|
|
34
|
+
for (const url of urls)
|
|
35
|
+
for (const variant of variants)
|
|
36
|
+
units.push({ url, variant });
|
|
37
|
+
return units;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A filesystem-safe stem for a URL.
|
|
41
|
+
*
|
|
42
|
+
* Derived from the path rather than hashed so the files are browsable: someone
|
|
43
|
+
* opening `output_dir` should be able to tell which page each report is for.
|
|
44
|
+
*/
|
|
45
|
+
export function slugForUrl(url) {
|
|
46
|
+
try {
|
|
47
|
+
const parsed = new URL(url);
|
|
48
|
+
const path = parsed.pathname.replace(/^\/|\/$/g, "").replace(/\//g, "-");
|
|
49
|
+
const query = parsed.search ? `-${parsed.search.slice(1).replace(/[^a-z0-9]+/gi, "-")}` : "";
|
|
50
|
+
const stem = `${path || "homepage"}${query}`.replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
51
|
+
// Long paths make unreadable filenames; the tail is the distinguishing part.
|
|
52
|
+
return stem.length > 80 ? stem.slice(-80).replace(/^-/, "") : stem;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return "url";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Merge records into the running index, keyed on URL + variant.
|
|
60
|
+
*
|
|
61
|
+
* Merging rather than overwriting is what lets a second pass fill gaps without
|
|
62
|
+
* discarding the first pass, and what lets the final aggregate cover the whole
|
|
63
|
+
* batch instead of only the last chunk.
|
|
64
|
+
*/
|
|
65
|
+
export async function mergeIndex(dir, records, fileName = "_index.json") {
|
|
66
|
+
await mkdir(dir, { recursive: true });
|
|
67
|
+
const indexPath = join(dir, fileName);
|
|
68
|
+
let existing = [];
|
|
69
|
+
try {
|
|
70
|
+
existing = JSON.parse(await readFile(indexPath, "utf8"));
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
existing = [];
|
|
74
|
+
}
|
|
75
|
+
const byKey = new Map(existing.map((r) => [`${r.url}|${r.variant}`, r]));
|
|
76
|
+
for (const record of records)
|
|
77
|
+
byKey.set(`${record.url}|${record.variant}`, record);
|
|
78
|
+
const merged = [...byKey.values()];
|
|
79
|
+
await writeFile(indexPath, JSON.stringify(merged, null, 2), "utf8");
|
|
80
|
+
return { indexPath, total: merged.length };
|
|
81
|
+
}
|
|
82
|
+
export async function readIndex(dir, fileName = "_index.json") {
|
|
83
|
+
try {
|
|
84
|
+
return JSON.parse(await readFile(join(dir, fileName), "utf8"));
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Drop work already recorded in the index.
|
|
92
|
+
*
|
|
93
|
+
* Re-running to fill gaps is the normal workflow, not an edge case, because
|
|
94
|
+
* these tools fail intermittently on real sites. Without this, the advice
|
|
95
|
+
* "just run it again" silently re-does — and on metered APIs re-charges for —
|
|
96
|
+
* everything that already worked.
|
|
97
|
+
*
|
|
98
|
+
* Only applies when no cursor is in play: a cursor indexes into the unfiltered
|
|
99
|
+
* list, so filtering would misalign it.
|
|
100
|
+
*/
|
|
101
|
+
export async function filterCompleted(dir, units, skipCompleted, cursor) {
|
|
102
|
+
if (!skipCompleted || cursor)
|
|
103
|
+
return { units, skipped: 0 };
|
|
104
|
+
const existing = await readIndex(dir);
|
|
105
|
+
if (existing.length === 0)
|
|
106
|
+
return { units, skipped: 0 };
|
|
107
|
+
const done = new Set(existing.map((r) => `${r.url}|${r.variant}`));
|
|
108
|
+
const remaining = units.filter((u) => !done.has(`${u.url}|${u.variant}`));
|
|
109
|
+
return { units: remaining, skipped: units.length - remaining.length };
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Whether there is room to start another unit.
|
|
113
|
+
*
|
|
114
|
+
* Checked before a unit begins, never mid-unit, and it reserves the expected
|
|
115
|
+
* cost of the work about to start rather than only asking whether the budget is
|
|
116
|
+
* already spent — otherwise a 40-second run beginning at the 99-second mark
|
|
117
|
+
* overshoots by a full unit. The PSI runner overran a 150s budget by 38s
|
|
118
|
+
* before this reserve existed.
|
|
119
|
+
*/
|
|
120
|
+
export function hasBudget(startedAt, budgetMs, reserveMs, unitsDone) {
|
|
121
|
+
if (unitsDone === 0)
|
|
122
|
+
return true; // always attempt at least one
|
|
123
|
+
return Date.now() - startedAt + reserveMs < budgetMs;
|
|
124
|
+
}
|
|
125
|
+
export function elapsedSeconds(startedAt) {
|
|
126
|
+
return Math.round((Date.now() - startedAt) / 1000);
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=batchState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batchState.js","sourceRoot":"","sources":["../../src/utils/batchState.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { criterionFor } from "../mappers/wcagLevels.js";
|
|
1
2
|
export function parseLighthouseJSON(rawJson) {
|
|
2
3
|
const lhr = JSON.parse(rawJson);
|
|
3
4
|
const categoryScores = {};
|
|
@@ -100,28 +101,21 @@ const WCAG_CRITERION_LEVELS = {
|
|
|
100
101
|
"4.1.2": "A",
|
|
101
102
|
"4.1.3": "AA",
|
|
102
103
|
};
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (prefix === "WCAG2AAA")
|
|
119
|
-
return { level: "AAA", criterion };
|
|
120
|
-
if (prefix === "WCAG2AA")
|
|
121
|
-
return { level: "AA", criterion };
|
|
122
|
-
if (prefix === "WCAG2A")
|
|
123
|
-
return { level: "A", criterion };
|
|
124
|
-
return { level: "unknown", criterion };
|
|
104
|
+
/**
|
|
105
|
+
* Resolve a finding to its WCAG success criterion and level.
|
|
106
|
+
*
|
|
107
|
+
* Both engines are handled here now. htmlcs encodes the criterion in its code;
|
|
108
|
+
* axe does not expose WCAG tags through pa11y at all, so its rule ids go
|
|
109
|
+
* through a lookup table. The previous implementation inferred the level from
|
|
110
|
+
* the code's "WCAG2AA" prefix when the criterion was unknown — but that prefix
|
|
111
|
+
* names the *standard being tested against*, not the criterion's own level, so
|
|
112
|
+
* it labelled everything AA and made a level-based priority scheme impossible.
|
|
113
|
+
*/
|
|
114
|
+
function deriveWcagLevel(code, runner) {
|
|
115
|
+
const found = criterionFor(code, runner);
|
|
116
|
+
if (found)
|
|
117
|
+
return { level: found.level, criterion: found.number };
|
|
118
|
+
return { level: "unknown", criterion: null };
|
|
125
119
|
}
|
|
126
120
|
function isAxeImpact(v) {
|
|
127
121
|
return v === "critical" || v === "serious" || v === "moderate" || v === "minor";
|
|
@@ -187,12 +181,14 @@ export function parsePa11yJSON(rawJson) {
|
|
|
187
181
|
const type = (issue.type ?? "error");
|
|
188
182
|
const runner = issue.runner === "axe" ? "axe" : "htmlcs";
|
|
189
183
|
if (runner === "axe") {
|
|
190
|
-
// axe codes are bare rule ids with no WCAG path
|
|
191
|
-
// criterion
|
|
192
|
-
// level "unknown"
|
|
193
|
-
//
|
|
194
|
-
//
|
|
184
|
+
// axe codes are bare rule ids with no WCAG path in them, so they go
|
|
185
|
+
// through the rule → criterion table rather than the code parser. This
|
|
186
|
+
// branch used to hardcode level "unknown" because that table did not
|
|
187
|
+
// exist; leaving it that way after adding the table made every axe
|
|
188
|
+
// finding read as a best-practice nit, including image-alt and
|
|
189
|
+
// color-contrast, which are 1.1.1 (A) and 1.4.3 (AA).
|
|
195
190
|
const impact = issue.runnerExtras?.impact;
|
|
191
|
+
const axeCriterion = deriveWcagLevel(code, runner);
|
|
196
192
|
violations.push({
|
|
197
193
|
code,
|
|
198
194
|
technique: code,
|
|
@@ -200,15 +196,15 @@ export function parsePa11yJSON(rawJson) {
|
|
|
200
196
|
selector: issue.selector ?? "",
|
|
201
197
|
context: issue.context ?? "",
|
|
202
198
|
type,
|
|
203
|
-
wcagLevel:
|
|
204
|
-
criterion:
|
|
199
|
+
wcagLevel: axeCriterion.level,
|
|
200
|
+
criterion: axeCriterion.criterion,
|
|
205
201
|
runner,
|
|
206
202
|
impact: isAxeImpact(impact) ? impact : undefined,
|
|
207
203
|
needsReview: issue.runnerExtras?.needsFurtherReview === true,
|
|
208
204
|
});
|
|
209
205
|
continue;
|
|
210
206
|
}
|
|
211
|
-
const { level, criterion } = deriveWcagLevel(code);
|
|
207
|
+
const { level, criterion } = deriveWcagLevel(code, runner);
|
|
212
208
|
violations.push({
|
|
213
209
|
code,
|
|
214
210
|
technique: extractTechnique(code),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outputParsers.js","sourceRoot":"","sources":["../../src/utils/outputParsers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"outputParsers.js","sourceRoot":"","sources":["../../src/utils/outputParsers.ts"],"names":[],"mappings":"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"}
|
|
@@ -105,6 +105,17 @@ interface RawLoadingExperience {
|
|
|
105
105
|
* and origin CrUX for a homepage says nothing about a checkout page.
|
|
106
106
|
*/
|
|
107
107
|
export declare function parseCrux(urlLevel: RawLoadingExperience | undefined, originLevel: RawLoadingExperience | undefined, originFallback: boolean): ParsedCrux | null;
|
|
108
|
+
/**
|
|
109
|
+
* Lab metrics as numbers.
|
|
110
|
+
*
|
|
111
|
+
* `numericValue`, never `displayValue`. The Five Below CSV recorded TTFB as
|
|
112
|
+
* "Root document took 930 ms" — a localised string containing a non-breaking
|
|
113
|
+
* space — because it read displayValue, which made the whole column
|
|
114
|
+
* unaggregatable while `numericValue: 929` sat in the same audit object.
|
|
115
|
+
* Formatting is a report-time concern; nothing upstream of the report should
|
|
116
|
+
* hold a number as text.
|
|
117
|
+
*/
|
|
118
|
+
export declare function extractLabMetrics(auditsJson: string): LabMetrics;
|
|
108
119
|
export interface ParsePsiOptions {
|
|
109
120
|
strategy: string;
|
|
110
121
|
/** Fall back to origin-wide CrUX per metric when URL-level data is absent. */
|
package/dist/utils/psiParser.js
CHANGED
|
@@ -138,7 +138,7 @@ export function parseCrux(urlLevel, originLevel, originFallback) {
|
|
|
138
138
|
* Formatting is a report-time concern; nothing upstream of the report should
|
|
139
139
|
* hold a number as text.
|
|
140
140
|
*/
|
|
141
|
-
function
|
|
141
|
+
export function extractLabMetrics(auditsJson) {
|
|
142
142
|
const audits = JSON.parse(auditsJson);
|
|
143
143
|
const num = (id) => {
|
|
144
144
|
const v = audits.audits?.[id]?.numericValue;
|
|
@@ -191,7 +191,7 @@ export function parsePsiResponse(rawJson, options) {
|
|
|
191
191
|
fetchTime: lhr.fetchTime ?? null,
|
|
192
192
|
lighthouseVersion: lhr.lighthouseVersion ?? null,
|
|
193
193
|
scores: lighthouse.categoryScores,
|
|
194
|
-
lab:
|
|
194
|
+
lab: extractLabMetrics(lhrJson),
|
|
195
195
|
field: parseCrux(response.loadingExperience, response.originLoadingExperience, originFallback),
|
|
196
196
|
lighthouse,
|
|
197
197
|
runWarnings: lhr.runWarnings ?? [],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"psiParser.js","sourceRoot":"","sources":["../../src/utils/psiParser.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"psiParser.js","sourceRoot":"","sources":["../../src/utils/psiParser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One input, three shapes.
|
|
3
|
+
*
|
|
4
|
+
* People arrive with a URL, a list they pasted from a spreadsheet, or a CSV
|
|
5
|
+
* export. Making them say which is which is a tax on the common case, and an
|
|
6
|
+
* agent relaying a user's request should not have to guess a parameter name.
|
|
7
|
+
* So the `url` input accepts any of the three and this module works out what it
|
|
8
|
+
* was given.
|
|
9
|
+
*
|
|
10
|
+
* Detection is by shape, not by a flag, and deliberately conservative: anything
|
|
11
|
+
* ambiguous is reported rather than guessed at, because silently auditing the
|
|
12
|
+
* wrong set of pages is worse than an error.
|
|
13
|
+
*/
|
|
14
|
+
export type UrlInputKind = "single" | "list" | "csv";
|
|
15
|
+
export interface ResolvedUrls {
|
|
16
|
+
urls: string[];
|
|
17
|
+
kind: UrlInputKind;
|
|
18
|
+
/** Where a CSV was read from, or the column used. Empty for the other kinds. */
|
|
19
|
+
source?: string;
|
|
20
|
+
warnings: string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Resolve whatever was handed in into a URL list.
|
|
24
|
+
*
|
|
25
|
+
* Order matters: the CSV check runs first because a path can contain no commas
|
|
26
|
+
* and no scheme, which would otherwise be coerced into `https://./file.csv`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveUrlInput(input: string): ResolvedUrls;
|
|
29
|
+
/** Accept an explicit array too, for callers that already have one. */
|
|
30
|
+
export declare function resolveUrlInputs(input: string | undefined, urls: string[] | undefined): ResolvedUrls;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One input, three shapes.
|
|
3
|
+
*
|
|
4
|
+
* People arrive with a URL, a list they pasted from a spreadsheet, or a CSV
|
|
5
|
+
* export. Making them say which is which is a tax on the common case, and an
|
|
6
|
+
* agent relaying a user's request should not have to guess a parameter name.
|
|
7
|
+
* So the `url` input accepts any of the three and this module works out what it
|
|
8
|
+
* was given.
|
|
9
|
+
*
|
|
10
|
+
* Detection is by shape, not by a flag, and deliberately conservative: anything
|
|
11
|
+
* ambiguous is reported rather than guessed at, because silently auditing the
|
|
12
|
+
* wrong set of pages is worse than an error.
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync } from "node:fs";
|
|
15
|
+
import { readUrlsFromCsv } from "./csvReader.js";
|
|
16
|
+
const LOOKS_LIKE_URL = /^https?:\/\//i;
|
|
17
|
+
function normalise(raw) {
|
|
18
|
+
const trimmed = raw.trim().replace(/^['"]|['"]$/g, "");
|
|
19
|
+
if (!trimmed)
|
|
20
|
+
return null;
|
|
21
|
+
// A bare domain is what people actually paste; assume https rather than
|
|
22
|
+
// rejecting it, and say so in a warning.
|
|
23
|
+
const candidate = LOOKS_LIKE_URL.test(trimmed) ? trimmed : `https://${trimmed}`;
|
|
24
|
+
try {
|
|
25
|
+
return new URL(candidate).toString();
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function looksLikeCsvPath(value) {
|
|
32
|
+
const trimmed = value.trim();
|
|
33
|
+
if (LOOKS_LIKE_URL.test(trimmed))
|
|
34
|
+
return false;
|
|
35
|
+
if (trimmed.includes(","))
|
|
36
|
+
return false; // a list, not a path
|
|
37
|
+
return /\.(csv|tsv|txt)$/i.test(trimmed) || existsSync(trimmed);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Resolve whatever was handed in into a URL list.
|
|
41
|
+
*
|
|
42
|
+
* Order matters: the CSV check runs first because a path can contain no commas
|
|
43
|
+
* and no scheme, which would otherwise be coerced into `https://./file.csv`.
|
|
44
|
+
*/
|
|
45
|
+
export function resolveUrlInput(input) {
|
|
46
|
+
const warnings = [];
|
|
47
|
+
const raw = input.trim();
|
|
48
|
+
if (!raw)
|
|
49
|
+
throw new Error("No URL, list, or CSV path was provided.");
|
|
50
|
+
if (looksLikeCsvPath(raw)) {
|
|
51
|
+
if (!existsSync(raw)) {
|
|
52
|
+
throw new Error(`"${raw}" looks like a file path but does not exist. Pass a URL, a ` +
|
|
53
|
+
`comma-separated list of URLs, or the path to a readable CSV.`);
|
|
54
|
+
}
|
|
55
|
+
const csv = readUrlsFromCsv(raw);
|
|
56
|
+
warnings.push(...csv.warnings);
|
|
57
|
+
if (csv.urls.length === 0) {
|
|
58
|
+
throw new Error(`No usable URLs found in ${raw}.`);
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
urls: csv.urls,
|
|
62
|
+
kind: "csv",
|
|
63
|
+
source: `${raw} (column "${csv.column}")`,
|
|
64
|
+
warnings,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// Split on commas and newlines — pasted lists arrive both ways, and a
|
|
68
|
+
// multi-line paste is the same intent as a comma-separated one.
|
|
69
|
+
const parts = raw
|
|
70
|
+
.split(/[,\n]/)
|
|
71
|
+
.map((p) => p.trim())
|
|
72
|
+
.filter(Boolean);
|
|
73
|
+
const urls = [];
|
|
74
|
+
const rejected = [];
|
|
75
|
+
const seen = new Set();
|
|
76
|
+
let coerced = 0;
|
|
77
|
+
for (const part of parts) {
|
|
78
|
+
const url = normalise(part);
|
|
79
|
+
if (!url) {
|
|
80
|
+
rejected.push(part);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (!LOOKS_LIKE_URL.test(part.trim()))
|
|
84
|
+
coerced++;
|
|
85
|
+
if (seen.has(url))
|
|
86
|
+
continue;
|
|
87
|
+
seen.add(url);
|
|
88
|
+
urls.push(url);
|
|
89
|
+
}
|
|
90
|
+
if (urls.length === 0) {
|
|
91
|
+
throw new Error(`Could not read any URL from "${raw.slice(0, 120)}". Pass a URL, a ` +
|
|
92
|
+
`comma-separated list, or a path to a CSV.`);
|
|
93
|
+
}
|
|
94
|
+
if (rejected.length > 0) {
|
|
95
|
+
warnings.push(`Ignored ${rejected.length} unparseable entr${rejected.length === 1 ? "y" : "ies"}: ${rejected.slice(0, 3).join(", ")}`);
|
|
96
|
+
}
|
|
97
|
+
if (coerced > 0) {
|
|
98
|
+
warnings.push(`Assumed https:// for ${coerced} entr${coerced === 1 ? "y" : "ies"} that had no scheme.`);
|
|
99
|
+
}
|
|
100
|
+
if (parts.length > urls.length + rejected.length) {
|
|
101
|
+
warnings.push(`Removed ${parts.length - urls.length - rejected.length} duplicate URL(s).`);
|
|
102
|
+
}
|
|
103
|
+
return { urls, kind: urls.length === 1 ? "single" : "list", warnings };
|
|
104
|
+
}
|
|
105
|
+
/** Accept an explicit array too, for callers that already have one. */
|
|
106
|
+
export function resolveUrlInputs(input, urls) {
|
|
107
|
+
if (urls && urls.length > 0) {
|
|
108
|
+
const resolved = [];
|
|
109
|
+
const seen = new Set();
|
|
110
|
+
const warnings = [];
|
|
111
|
+
for (const raw of urls) {
|
|
112
|
+
const url = normalise(raw);
|
|
113
|
+
if (!url) {
|
|
114
|
+
warnings.push(`Ignored unparseable URL "${raw}".`);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (seen.has(url))
|
|
118
|
+
continue;
|
|
119
|
+
seen.add(url);
|
|
120
|
+
resolved.push(url);
|
|
121
|
+
}
|
|
122
|
+
if (resolved.length === 0)
|
|
123
|
+
throw new Error("None of the supplied urls were parseable.");
|
|
124
|
+
return { urls: resolved, kind: resolved.length === 1 ? "single" : "list", warnings };
|
|
125
|
+
}
|
|
126
|
+
if (!input)
|
|
127
|
+
throw new Error("Provide `url` (a URL, comma-separated list, or CSV path) or `urls`.");
|
|
128
|
+
return resolveUrlInput(input);
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=urlInput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"urlInput.js","sourceRoot":"","sources":["../../src/utils/urlInput.ts"],"names":[],"mappings":"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"}
|