@domandigital/craft 0.19.0 → 0.19.2
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/CHANGELOG.md +14 -0
- package/README.md +45 -1
- package/STANDARD.md +48 -18
- package/dist/{audit-X7LGATAQ.js → audit-43PC4LMS.js} +3 -3
- package/dist/{chunk-RNHV2SXC.js → chunk-4LJFZH2I.js} +2 -2
- package/dist/{chunk-4QWEAL4G.js → chunk-CZ7KT452.js} +93 -1
- package/dist/{chunk-GNVZGG3E.js → chunk-D2PEKYKH.js} +24 -12
- package/dist/{chunk-NCBCZFDY.js → chunk-EDM4L5WJ.js} +5 -5
- package/dist/{chunk-J35UYAVV.js → chunk-EKGHL4D2.js} +4 -4
- package/dist/{chunk-W7PMRSDG.js → chunk-VDUIIWG7.js} +1 -1
- package/dist/{chunk-IHT6CJOM.js → chunk-WK2WMWTH.js} +1 -1
- package/dist/{chunk-LWKMGJSW.js → chunk-ZKZCPVQ6.js} +5 -5
- package/dist/{cli-DKI37OXK.js → cli-BZSJIUQH.js} +5 -5
- package/dist/{cli-3WWHRJRG.js → cli-GUEBFFF3.js} +4 -4
- package/dist/{cli-ZGB6MUN2.js → cli-KTN5OXHZ.js} +6 -6
- package/dist/{cli-KXVJJDN5.js → cli-OS5ESEJV.js} +9 -9
- package/dist/cli-RAH4CKYY.js +249 -0
- package/dist/{cli-U7WEVPZL.js → cli-T3IA7IQK.js} +6 -6
- package/dist/{cli-YD3VN52R.js → cli-VLNOQYEL.js} +5 -5
- package/dist/{cli-JB4X5LAG.js → cli-VPARW6FY.js} +1 -1
- package/dist/cli.js +3 -3
- package/dist/index.cjs +93 -1
- package/dist/index.js +93 -1
- package/dist/phone.cjs +275 -0
- package/dist/phone.d.cts +185 -0
- package/dist/phone.d.ts +185 -0
- package/dist/phone.js +237 -0
- package/package.json +11 -1
|
@@ -4,16 +4,16 @@ import {
|
|
|
4
4
|
merge,
|
|
5
5
|
resolvePages,
|
|
6
6
|
runAudit
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-EKGHL4D2.js";
|
|
8
|
+
import "./chunk-VDUIIWG7.js";
|
|
9
9
|
import "./chunk-JYNXGCYZ.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-EDM4L5WJ.js";
|
|
11
11
|
import "./chunk-OQXTQQAU.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-D2PEKYKH.js";
|
|
13
13
|
import "./chunk-QIEDBL4J.js";
|
|
14
14
|
import "./chunk-WUACK2HX.js";
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
15
|
+
import "./chunk-WK2WMWTH.js";
|
|
16
|
+
import "./chunk-CZ7KT452.js";
|
|
17
17
|
import "./chunk-QYBAVU3P.js";
|
|
18
18
|
export {
|
|
19
19
|
describeComponents,
|
|
@@ -3,21 +3,21 @@ import {
|
|
|
3
3
|
} from "./chunk-OKVHWXYV.js";
|
|
4
4
|
import {
|
|
5
5
|
merge
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-EKGHL4D2.js";
|
|
7
|
+
import "./chunk-VDUIIWG7.js";
|
|
8
8
|
import "./chunk-JYNXGCYZ.js";
|
|
9
9
|
import {
|
|
10
10
|
SIBLING_AT,
|
|
11
11
|
compareToEstate,
|
|
12
12
|
loadEstate
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-ZKZCPVQ6.js";
|
|
14
14
|
import {
|
|
15
15
|
PAGE_TYPES,
|
|
16
16
|
validateDirection
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-4LJFZH2I.js";
|
|
18
18
|
import {
|
|
19
19
|
loadNull
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-EDM4L5WJ.js";
|
|
21
21
|
import "./chunk-OQXTQQAU.js";
|
|
22
22
|
import {
|
|
23
23
|
COPY_FILE,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
loadExceptions,
|
|
29
29
|
parseFlags,
|
|
30
30
|
readPaths
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-D2PEKYKH.js";
|
|
32
32
|
import {
|
|
33
33
|
toJson
|
|
34
34
|
} from "./chunk-QIEDBL4J.js";
|
|
@@ -42,8 +42,8 @@ import {
|
|
|
42
42
|
fingerprint,
|
|
43
43
|
scanSource,
|
|
44
44
|
typicality
|
|
45
|
-
} from "./chunk-
|
|
46
|
-
import "./chunk-
|
|
45
|
+
} from "./chunk-WK2WMWTH.js";
|
|
46
|
+
import "./chunk-CZ7KT452.js";
|
|
47
47
|
import "./chunk-QYBAVU3P.js";
|
|
48
48
|
|
|
49
49
|
// src/report/cli.ts
|
|
@@ -126,7 +126,7 @@ async function runReport(command, args, io) {
|
|
|
126
126
|
if (/\.json$/i.test(target2) && existsSync(local)) {
|
|
127
127
|
snap = readSnapshot(JSON.parse(readFileSync(local, "utf8")), target2);
|
|
128
128
|
} else {
|
|
129
|
-
const { snapshotUrl } = await import("./audit-
|
|
129
|
+
const { snapshotUrl } = await import("./audit-43PC4LMS.js");
|
|
130
130
|
snap = await snapshotUrl(target2);
|
|
131
131
|
}
|
|
132
132
|
const fp = fingerprint(snap);
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SOURCE_FILE,
|
|
3
|
+
readPaths
|
|
4
|
+
} from "./chunk-D2PEKYKH.js";
|
|
5
|
+
import {
|
|
6
|
+
toJson
|
|
7
|
+
} from "./chunk-QIEDBL4J.js";
|
|
8
|
+
import "./chunk-WK2WMWTH.js";
|
|
9
|
+
import "./chunk-CZ7KT452.js";
|
|
10
|
+
import "./chunk-QYBAVU3P.js";
|
|
11
|
+
|
|
12
|
+
// src/phone/cli.ts
|
|
13
|
+
import { existsSync, readdirSync, readFileSync, writeFileSync } from "fs";
|
|
14
|
+
import { join, resolve } from "path";
|
|
15
|
+
|
|
16
|
+
// src/phone/judge.ts
|
|
17
|
+
var EMPTY_BASELINE = { static: [], measured: [] };
|
|
18
|
+
var MEDIA = /@(?:custom-)?media\b([^{;]*)/g;
|
|
19
|
+
var CAPS_WIDTH = /\bmax-(?:device-)?width\s*:|\bwidth\s*<|>=?\s*(?:device-)?width\b/i;
|
|
20
|
+
var VARIANT = /(?<![\w@-])max-(\[[^\]\s]+\]|[a-z0-9]+):/g;
|
|
21
|
+
var NOT_VARIANTS = /* @__PURE__ */ new Set(["width", "height", "lines", "resolution", "zoom", "inline-size", "block-size"]);
|
|
22
|
+
var OK = /mobile-first-ok\b:?(.*)/;
|
|
23
|
+
function reasonOf(line) {
|
|
24
|
+
const m = line?.match(OK);
|
|
25
|
+
return m ? m[1].replace(/\*\/|-->|[{}]/g, "").trim() : null;
|
|
26
|
+
}
|
|
27
|
+
function scanPhoneFirst(files, exceptions = []) {
|
|
28
|
+
const excusedFiles = new Set(exceptions.filter((e) => e.reason?.trim()).map((e) => e.file));
|
|
29
|
+
const findings = [];
|
|
30
|
+
let excused = 0;
|
|
31
|
+
for (const { path, text } of files) {
|
|
32
|
+
if (excusedFiles.has(path)) continue;
|
|
33
|
+
const lines = text.split("\n");
|
|
34
|
+
const lineOf = (index) => text.slice(0, index).split("\n").length;
|
|
35
|
+
const found = [];
|
|
36
|
+
for (const m of text.matchAll(MEDIA)) {
|
|
37
|
+
if (CAPS_WIDTH.test(m[1])) found.push({ line: lineOf(m.index), what: `${m[0].slice(0, m[0].length - m[1].length)}${m[1].replace(/\s+/g, " ").trimEnd()}` });
|
|
38
|
+
}
|
|
39
|
+
for (const m of text.matchAll(VARIANT)) {
|
|
40
|
+
if (!NOT_VARIANTS.has(m[1])) found.push({ line: lineOf(m.index), what: m[0] });
|
|
41
|
+
}
|
|
42
|
+
for (const { line, what } of found.sort((a, b) => a.line - b.line)) {
|
|
43
|
+
const here = reasonOf(lines[line - 1]);
|
|
44
|
+
const above = reasonOf(lines[line - 2]);
|
|
45
|
+
if (here || above) {
|
|
46
|
+
excused++;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
findings.push({ file: path, line, what: here === "" || above === "" ? `${what} (mobile-first-ok with no reason)` : what });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { findings, excused };
|
|
53
|
+
}
|
|
54
|
+
function checkExceptions(exceptions, exists) {
|
|
55
|
+
const problems = [];
|
|
56
|
+
exceptions.forEach((e, i) => {
|
|
57
|
+
const at = `exceptions[${i}]`;
|
|
58
|
+
const x = e;
|
|
59
|
+
if (typeof x?.file !== "string" || !x.file.trim()) problems.push(`${at}: names no file`);
|
|
60
|
+
else if (typeof x.reason !== "string" || !x.reason.trim()) problems.push(`${at} (${x.file}): no reason. Say why this file needs a max-width query, or remove the exception.`);
|
|
61
|
+
else if (!exists(x.file)) problems.push(`${at}: ${x.file} is not there. Remove the exception.`);
|
|
62
|
+
});
|
|
63
|
+
return problems;
|
|
64
|
+
}
|
|
65
|
+
var normaliseElement = (element) => element.replace(/\d+/g, "#");
|
|
66
|
+
var tally = (items, key) => {
|
|
67
|
+
const m = /* @__PURE__ */ new Map();
|
|
68
|
+
for (const item of items) {
|
|
69
|
+
const k = key(item);
|
|
70
|
+
const had = m.get(k);
|
|
71
|
+
if (had) had.count++;
|
|
72
|
+
else m.set(k, { item, count: 1 });
|
|
73
|
+
}
|
|
74
|
+
return m;
|
|
75
|
+
};
|
|
76
|
+
function judgeStatic(findings, baseline) {
|
|
77
|
+
const byFile = tally(findings, (f) => f.file);
|
|
78
|
+
const allowed = new Map(baseline.static.map((b) => [b.file, b.count]));
|
|
79
|
+
const fresh = [];
|
|
80
|
+
const stale = [];
|
|
81
|
+
let known = 0;
|
|
82
|
+
for (const [file, { count }] of byFile) {
|
|
83
|
+
const allow = allowed.get(file) ?? 0;
|
|
84
|
+
known += Math.min(count, allow);
|
|
85
|
+
if (count > allow) {
|
|
86
|
+
const here = findings.filter((f) => f.file === file);
|
|
87
|
+
const lead = allow ? `${file}: ${count} desktop-first rules, the baseline allows ${allow}. One of these is new:` : `${file}:`;
|
|
88
|
+
fresh.push(`${lead}
|
|
89
|
+
${here.map((f) => ` line ${f.line}: ${f.what}`).join("\n")}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
for (const { file, count } of baseline.static) {
|
|
93
|
+
const now = byFile.get(file)?.count ?? 0;
|
|
94
|
+
if (now < count) stale.push(`${file}: the baseline allows ${count}, there ${now === 1 ? "is" : "are"} ${now} now. Lower it to ${now}${now ? "" : " (remove the line)"}.`);
|
|
95
|
+
}
|
|
96
|
+
return { fresh, stale, known };
|
|
97
|
+
}
|
|
98
|
+
var measuredKey = (route, check, element) => `${route}\0${check}\0${element}`;
|
|
99
|
+
function judgeMeasured(routes, baseline) {
|
|
100
|
+
const fresh = [];
|
|
101
|
+
const stale = [];
|
|
102
|
+
let known = 0;
|
|
103
|
+
const allowed = new Map(baseline.measured.map((b) => [measuredKey(b.route, b.check, b.element), b.count]));
|
|
104
|
+
const seen = /* @__PURE__ */ new Map();
|
|
105
|
+
const measured = new Set(routes.map((r) => r.route));
|
|
106
|
+
for (const { route, findings } of routes) {
|
|
107
|
+
const counted = tally(findings, (f) => measuredKey(route, f.check, normaliseElement(f.element)));
|
|
108
|
+
for (const [key, { item, count }] of counted) {
|
|
109
|
+
seen.set(key, count);
|
|
110
|
+
const allow = allowed.get(key) ?? 0;
|
|
111
|
+
known += Math.min(count, allow);
|
|
112
|
+
if (count > allow) {
|
|
113
|
+
const times = count - allow > 1 ? ` (${count - allow} more than the baseline's ${allow})` : allow ? ` (the baseline allows ${allow})` : "";
|
|
114
|
+
fresh.push(`${route}: ${LABEL[item.check]} ${item.element}: ${item.detail}${times}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const missing = /* @__PURE__ */ new Set();
|
|
119
|
+
for (const b of baseline.measured) {
|
|
120
|
+
const key = measuredKey(b.route, b.check, b.element);
|
|
121
|
+
if (!measured.has(b.route)) {
|
|
122
|
+
if (!missing.has(b.route)) stale.push(`${b.route}: in the baseline but not measured this run. Measure it, or remove its lines.`);
|
|
123
|
+
missing.add(b.route);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const now = seen.get(key) ?? 0;
|
|
127
|
+
if (now < b.count) stale.push(`${b.route}: ${LABEL[b.check]} ${b.element}: the baseline allows ${b.count}, ${now} found. Lower it to ${now}${now ? "" : " (remove the line)"}.`);
|
|
128
|
+
}
|
|
129
|
+
return { fresh, stale, known };
|
|
130
|
+
}
|
|
131
|
+
var LABEL = {
|
|
132
|
+
scroll: "scrolls sideways",
|
|
133
|
+
target: "small target",
|
|
134
|
+
field: "small field",
|
|
135
|
+
text: "small text",
|
|
136
|
+
title: "title cut off"
|
|
137
|
+
};
|
|
138
|
+
function writeBaseline(findings, routes, note) {
|
|
139
|
+
const byFile = tally(findings, (f) => f.file);
|
|
140
|
+
const measured = routes.flatMap(
|
|
141
|
+
({ route, findings: findings2 }) => [...tally(findings2, (f) => measuredKey(route, f.check, normaliseElement(f.element))).values()].map(({ item, count }) => ({ route, check: item.check, element: normaliseElement(item.element), count }))
|
|
142
|
+
);
|
|
143
|
+
return {
|
|
144
|
+
...note ? { note } : {},
|
|
145
|
+
static: [...byFile.values()].map(({ item, count }) => ({ file: item.file, count, found: findings.filter((f) => f.file === item.file).map((f) => f.what) })).sort((a, b) => a.file.localeCompare(b.file)),
|
|
146
|
+
measured: measured.sort((a, b) => a.route.localeCompare(b.route) || a.check.localeCompare(b.check) || a.element.localeCompare(b.element))
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/phone/cli.ts
|
|
151
|
+
var USAGE = "usage: craft phone-first [--config phone-first.json] [--measured <dir>] [--update-baseline] [--json]";
|
|
152
|
+
function parse(args) {
|
|
153
|
+
const flags = { config: "phone-first.json", update: false, json: false };
|
|
154
|
+
for (let i = 0; i < args.length; i++) {
|
|
155
|
+
const a = args[i];
|
|
156
|
+
if (a === "--update-baseline") flags.update = true;
|
|
157
|
+
else if (a === "--json") flags.json = true;
|
|
158
|
+
else if (a === "--config" || a === "--measured") {
|
|
159
|
+
const v = args[++i];
|
|
160
|
+
if (!v || v.startsWith("--")) return `${a} needs a value`;
|
|
161
|
+
if (a === "--config") flags.config = v;
|
|
162
|
+
else flags.measured = v;
|
|
163
|
+
} else return `unknown argument ${a}`;
|
|
164
|
+
}
|
|
165
|
+
return flags;
|
|
166
|
+
}
|
|
167
|
+
function loadConfig(path) {
|
|
168
|
+
if (!existsSync(path)) throw new Error(`no ${path}. Write one: { "source": ["<dirs with styles and components>"], "baseline": "phone-first.baseline.json" }`);
|
|
169
|
+
const c = JSON.parse(readFileSync(path, "utf8"));
|
|
170
|
+
if (!Array.isArray(c.source) || c.source.length === 0 || c.source.some((s) => typeof s !== "string")) throw new Error(`${path}: "source" should list the folders to scan`);
|
|
171
|
+
if (c.ignore !== void 0 && (!Array.isArray(c.ignore) || c.ignore.some((s) => typeof s !== "string"))) throw new Error(`${path}: "ignore" should be a list of globs`);
|
|
172
|
+
if (c.exceptions !== void 0 && !Array.isArray(c.exceptions)) throw new Error(`${path}: "exceptions" should be a list of { "file", "reason" }`);
|
|
173
|
+
return { source: c.source, ignore: c.ignore ?? [], exceptions: c.exceptions ?? [], baseline: c.baseline ?? "phone-first.baseline.json" };
|
|
174
|
+
}
|
|
175
|
+
function loadBaseline(path) {
|
|
176
|
+
if (!existsSync(path)) return EMPTY_BASELINE;
|
|
177
|
+
const b = JSON.parse(readFileSync(path, "utf8"));
|
|
178
|
+
return { ...b.note ? { note: b.note } : {}, static: b.static ?? [], measured: b.measured ?? [] };
|
|
179
|
+
}
|
|
180
|
+
function loadMeasured(dir) {
|
|
181
|
+
if (!existsSync(dir)) throw new Error(`--measured ${dir}: no such folder. Run the portal's phone-first specs first; they write it.`);
|
|
182
|
+
const routes = readdirSync(dir).filter((f) => f.endsWith(".json")).sort().map((f) => JSON.parse(readFileSync(join(dir, f), "utf8")));
|
|
183
|
+
if (routes.length === 0) throw new Error(`--measured ${dir}: no measured routes in it. Did the phone-first specs run?`);
|
|
184
|
+
return routes;
|
|
185
|
+
}
|
|
186
|
+
function runPhoneFirst(args, io) {
|
|
187
|
+
const flags = parse(args);
|
|
188
|
+
if (typeof flags === "string") {
|
|
189
|
+
io.err(`craft phone-first: ${flags}
|
|
190
|
+
${USAGE}`);
|
|
191
|
+
return 2;
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
const config = loadConfig(resolve(io.cwd, flags.config));
|
|
195
|
+
const baselinePath = resolve(io.cwd, config.baseline);
|
|
196
|
+
const baseline = loadBaseline(baselinePath);
|
|
197
|
+
const exceptionProblems = checkExceptions(config.exceptions, (f) => existsSync(resolve(io.cwd, f)));
|
|
198
|
+
const sources = config.source.filter((s2) => existsSync(resolve(io.cwd, s2)));
|
|
199
|
+
const missing = config.source.filter((s2) => !sources.includes(s2));
|
|
200
|
+
if (missing.length) throw new Error(`${flags.config}: source ${missing.join(", ")} not found`);
|
|
201
|
+
const files = readPaths(sources, io.cwd, SOURCE_FILE, void 0, config.ignore);
|
|
202
|
+
const { findings, excused } = scanPhoneFirst(files, config.exceptions);
|
|
203
|
+
const routes = flags.measured ? loadMeasured(resolve(io.cwd, flags.measured)) : null;
|
|
204
|
+
if (flags.update) {
|
|
205
|
+
const next = writeBaseline(findings, routes ?? [], baseline.note);
|
|
206
|
+
if (!routes) next.measured = baseline.measured;
|
|
207
|
+
writeFileSync(baselinePath, `${JSON.stringify(next, null, 2)}
|
|
208
|
+
`);
|
|
209
|
+
io.out(`craft phone-first: wrote ${config.baseline} (${next.static.reduce((n, s2) => n + s2.count, 0)} static, ${next.measured.reduce((n, m2) => n + m2.count, 0)} measured)`);
|
|
210
|
+
return exceptionProblems.length ? 1 : 0;
|
|
211
|
+
}
|
|
212
|
+
const s = judgeStatic(findings, baseline);
|
|
213
|
+
const m = routes ? judgeMeasured(routes, baseline) : { fresh: [], stale: [], known: 0 };
|
|
214
|
+
const failed = exceptionProblems.length + s.fresh.length + s.stale.length + m.fresh.length + m.stale.length > 0;
|
|
215
|
+
if (flags.json) {
|
|
216
|
+
io.out(toJson({ pass: !failed, files: files.length, excused, routes: routes?.map((r) => r.route) ?? null, exceptionProblems, static: s, measured: m }));
|
|
217
|
+
return failed ? 1 : 0;
|
|
218
|
+
}
|
|
219
|
+
const section = (title, lines) => lines.length ? `
|
|
220
|
+
${title}
|
|
221
|
+
${lines.map((l) => ` ${l}`).join("\n")}` : "";
|
|
222
|
+
const known = s.known + m.known;
|
|
223
|
+
const summary = [
|
|
224
|
+
`${files.length} files${routes ? ` and ${routes.length} route${routes.length === 1 ? "" : "s"} at 375px` : ""}`,
|
|
225
|
+
excused ? `${excused} recorded exception${excused === 1 ? "" : "s"}` : null,
|
|
226
|
+
known ? `${known} known breach${known === 1 ? "" : "es"} in ${config.baseline}` : null
|
|
227
|
+
].filter(Boolean).join(", ");
|
|
228
|
+
if (!failed) {
|
|
229
|
+
io.out(`craft phone-first: pass. ${summary}.`);
|
|
230
|
+
return 0;
|
|
231
|
+
}
|
|
232
|
+
io.err(
|
|
233
|
+
[
|
|
234
|
+
`craft phone-first: fail. ${summary}.`,
|
|
235
|
+
section("The exceptions:", exceptionProblems),
|
|
236
|
+
section("Built desktop first (write the phone as the base styles and widen with min-width; a genuine exception takes `mobile-first-ok: <reason>` on its line):", s.fresh),
|
|
237
|
+
section("Measured at 375px:", m.fresh),
|
|
238
|
+
section("The baseline claims more than is there (good: lower it, so the fix stays fixed):", [...s.stale, ...m.stale])
|
|
239
|
+
].join("")
|
|
240
|
+
);
|
|
241
|
+
return 1;
|
|
242
|
+
} catch (error) {
|
|
243
|
+
io.err(`craft phone-first: ${error.message}`);
|
|
244
|
+
return 2;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
export {
|
|
248
|
+
runPhoneFirst
|
|
249
|
+
};
|
|
@@ -4,15 +4,15 @@ import {
|
|
|
4
4
|
formatPairs,
|
|
5
5
|
loadEstate,
|
|
6
6
|
runEstate
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-ZKZCPVQ6.js";
|
|
8
|
+
import "./chunk-4LJFZH2I.js";
|
|
9
|
+
import "./chunk-EDM4L5WJ.js";
|
|
10
10
|
import "./chunk-OQXTQQAU.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-D2PEKYKH.js";
|
|
12
12
|
import "./chunk-QIEDBL4J.js";
|
|
13
13
|
import "./chunk-WUACK2HX.js";
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-WK2WMWTH.js";
|
|
15
|
+
import "./chunk-CZ7KT452.js";
|
|
16
16
|
import "./chunk-QYBAVU3P.js";
|
|
17
17
|
export {
|
|
18
18
|
formatComponentPairs,
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
expandNullTargets,
|
|
6
6
|
loadNull
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-EDM4L5WJ.js";
|
|
8
8
|
import "./chunk-OQXTQQAU.js";
|
|
9
9
|
import {
|
|
10
10
|
parseFlags
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-D2PEKYKH.js";
|
|
12
12
|
import {
|
|
13
13
|
toJson
|
|
14
14
|
} from "./chunk-QIEDBL4J.js";
|
|
@@ -21,8 +21,8 @@ import {
|
|
|
21
21
|
fingerprint,
|
|
22
22
|
scanSource,
|
|
23
23
|
typicality
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import "./chunk-
|
|
24
|
+
} from "./chunk-WK2WMWTH.js";
|
|
25
|
+
import "./chunk-CZ7KT452.js";
|
|
26
26
|
import {
|
|
27
27
|
SNAPSHOT_VERSION
|
|
28
28
|
} from "./chunk-QYBAVU3P.js";
|
|
@@ -188,7 +188,7 @@ async function runCalibrate(args, io) {
|
|
|
188
188
|
if (toTake.length) {
|
|
189
189
|
io.err(`craft calibrate: taking ${toTake.length} snapshot${toTake.length === 1 ? "" : "s"}`);
|
|
190
190
|
try {
|
|
191
|
-
const { snapshotUrls } = await import("./audit-
|
|
191
|
+
const { snapshotUrls } = await import("./audit-43PC4LMS.js");
|
|
192
192
|
const results = await snapshotUrls(toTake.map((t) => t.url));
|
|
193
193
|
results.forEach((r, i) => {
|
|
194
194
|
const { entry, keep } = toTake[i];
|
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
run
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-D2PEKYKH.js";
|
|
5
5
|
import "./chunk-QIEDBL4J.js";
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-WK2WMWTH.js";
|
|
7
|
+
import "./chunk-CZ7KT452.js";
|
|
8
8
|
import "./chunk-QYBAVU3P.js";
|
|
9
9
|
|
|
10
10
|
// src/cli.ts
|
package/dist/index.cjs
CHANGED
|
@@ -4344,8 +4344,100 @@ function markupParts(file) {
|
|
|
4344
4344
|
function textNodeIsProse(body) {
|
|
4345
4345
|
return /[a-zA-Z]{2,}/.test(body) && /\s/.test(body.trim()) || /[a-zA-Z]{4,}[.!?]/.test(body);
|
|
4346
4346
|
}
|
|
4347
|
+
var FRONT_MATTER_PROSE = /* @__PURE__ */ new Set(["title", "description"]);
|
|
4348
|
+
var KEY_LINE = /^(\s*)(?:-\s+)?([A-Za-z][\w-]*)[ \t]*:[ \t]*/;
|
|
4349
|
+
var BLOCK_SCALAR = /^(?:[|>][+-]?\d*|[|>]\d+[+-]?)$/;
|
|
4350
|
+
function readFrontKey(line) {
|
|
4351
|
+
const m = KEY_LINE.exec(line);
|
|
4352
|
+
if (!m) return null;
|
|
4353
|
+
return { indent: m[1].length, name: m[2], valueAt: m[0].length, value: line.slice(m[0].length) };
|
|
4354
|
+
}
|
|
4355
|
+
function indentOf(line) {
|
|
4356
|
+
let i = 0;
|
|
4357
|
+
while (i < line.length && (line[i] === " " || line[i] === " ")) i += 1;
|
|
4358
|
+
return i;
|
|
4359
|
+
}
|
|
4360
|
+
function commentAt(value) {
|
|
4361
|
+
if (value.startsWith("#")) return 0;
|
|
4362
|
+
const found = /[ \t]+#/.exec(value);
|
|
4363
|
+
return found ? found.index : -1;
|
|
4364
|
+
}
|
|
4365
|
+
function keepSpan(line, from, to) {
|
|
4366
|
+
const start = Math.max(0, Math.min(from, line.length));
|
|
4367
|
+
const end = Math.max(start, Math.min(to, line.length));
|
|
4368
|
+
return " ".repeat(start) + line.slice(start, end) + " ".repeat(line.length - end);
|
|
4369
|
+
}
|
|
4370
|
+
function quoteEnd(line, from, quote) {
|
|
4371
|
+
for (let i = from; i < line.length; i += 1) {
|
|
4372
|
+
if (quote === '"' && line[i] === "\\") {
|
|
4373
|
+
i += 1;
|
|
4374
|
+
continue;
|
|
4375
|
+
}
|
|
4376
|
+
if (quote === "'" && line[i] === "'" && line[i + 1] === "'") {
|
|
4377
|
+
i += 1;
|
|
4378
|
+
continue;
|
|
4379
|
+
}
|
|
4380
|
+
if (line[i] === quote) return i;
|
|
4381
|
+
}
|
|
4382
|
+
return -1;
|
|
4383
|
+
}
|
|
4384
|
+
function maskFrontMatter(block) {
|
|
4385
|
+
const lines = block.split("\n");
|
|
4386
|
+
const out = lines.map((line) => blank(line));
|
|
4387
|
+
for (let i = 1; i < lines.length; ) {
|
|
4388
|
+
const line = lines[i];
|
|
4389
|
+
if (line === "---" || line === "...") break;
|
|
4390
|
+
const key = readFrontKey(line);
|
|
4391
|
+
if (!key || !FRONT_MATTER_PROSE.has(key.name.toLowerCase())) {
|
|
4392
|
+
i += 1;
|
|
4393
|
+
continue;
|
|
4394
|
+
}
|
|
4395
|
+
const quote = key.value.startsWith('"') ? '"' : key.value.startsWith("'") ? "'" : "";
|
|
4396
|
+
if (quote) {
|
|
4397
|
+
let cursor = key.valueAt + 1;
|
|
4398
|
+
while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
|
|
4399
|
+
const current = lines[i];
|
|
4400
|
+
const end = quoteEnd(current, cursor, quote);
|
|
4401
|
+
out[i] = keepSpan(current, cursor, end === -1 ? current.length : end);
|
|
4402
|
+
i += 1;
|
|
4403
|
+
cursor = 0;
|
|
4404
|
+
if (end !== -1) break;
|
|
4405
|
+
}
|
|
4406
|
+
continue;
|
|
4407
|
+
}
|
|
4408
|
+
const hash = commentAt(key.value);
|
|
4409
|
+
const body = (hash === -1 ? key.value : key.value.slice(0, hash)).trim();
|
|
4410
|
+
if (BLOCK_SCALAR.test(body)) {
|
|
4411
|
+
i += 1;
|
|
4412
|
+
while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
|
|
4413
|
+
const current = lines[i];
|
|
4414
|
+
if (current.trim() !== "" && indentOf(current) <= key.indent) break;
|
|
4415
|
+
if (current.trim()) out[i] = current;
|
|
4416
|
+
i += 1;
|
|
4417
|
+
}
|
|
4418
|
+
continue;
|
|
4419
|
+
}
|
|
4420
|
+
if (body === "" || body === "~" || /^null$/i.test(body) || body.startsWith("[") || body.startsWith("{")) {
|
|
4421
|
+
i += 1;
|
|
4422
|
+
continue;
|
|
4423
|
+
}
|
|
4424
|
+
out[i] = keepSpan(line, key.valueAt, hash === -1 ? line.length : key.valueAt + hash);
|
|
4425
|
+
i += 1;
|
|
4426
|
+
while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
|
|
4427
|
+
const current = lines[i];
|
|
4428
|
+
if (current.trim() === "" || indentOf(current) <= key.indent) break;
|
|
4429
|
+
if (!/^\s*#/.test(current)) {
|
|
4430
|
+
const cut = commentAt(current);
|
|
4431
|
+
out[i] = cut === -1 ? current : keepSpan(current, 0, cut);
|
|
4432
|
+
}
|
|
4433
|
+
i += 1;
|
|
4434
|
+
}
|
|
4435
|
+
}
|
|
4436
|
+
const masked = out.join("\n");
|
|
4437
|
+
return masked.length === block.length ? masked : blank(block);
|
|
4438
|
+
}
|
|
4347
4439
|
function proseBlocks(file) {
|
|
4348
|
-
const masked = file.text.replace(/^(```|~~~)[\s\S]*?^\1/gm, blank).replace(/`[^`\n]*`/g, (m) => " ".repeat(m.length)).replace(/^---\n[\s\S]*?\n---\n/,
|
|
4440
|
+
const masked = file.text.replace(/^(```|~~~)[\s\S]*?^\1/gm, blank).replace(/`[^`\n]*`/g, (m) => " ".repeat(m.length)).replace(/^---\n[\s\S]*?\n---\n/, (block) => maskFrontMatter(block)).replace(/<!--[\s\S]*?-->/g, blank);
|
|
4349
4441
|
return [{ path: file.path, text: masked, offset: 0 }];
|
|
4350
4442
|
}
|
|
4351
4443
|
function isData(path) {
|
package/dist/index.js
CHANGED
|
@@ -4042,8 +4042,100 @@ function markupParts(file) {
|
|
|
4042
4042
|
function textNodeIsProse(body) {
|
|
4043
4043
|
return /[a-zA-Z]{2,}/.test(body) && /\s/.test(body.trim()) || /[a-zA-Z]{4,}[.!?]/.test(body);
|
|
4044
4044
|
}
|
|
4045
|
+
var FRONT_MATTER_PROSE = /* @__PURE__ */ new Set(["title", "description"]);
|
|
4046
|
+
var KEY_LINE = /^(\s*)(?:-\s+)?([A-Za-z][\w-]*)[ \t]*:[ \t]*/;
|
|
4047
|
+
var BLOCK_SCALAR = /^(?:[|>][+-]?\d*|[|>]\d+[+-]?)$/;
|
|
4048
|
+
function readFrontKey(line) {
|
|
4049
|
+
const m = KEY_LINE.exec(line);
|
|
4050
|
+
if (!m) return null;
|
|
4051
|
+
return { indent: m[1].length, name: m[2], valueAt: m[0].length, value: line.slice(m[0].length) };
|
|
4052
|
+
}
|
|
4053
|
+
function indentOf(line) {
|
|
4054
|
+
let i = 0;
|
|
4055
|
+
while (i < line.length && (line[i] === " " || line[i] === " ")) i += 1;
|
|
4056
|
+
return i;
|
|
4057
|
+
}
|
|
4058
|
+
function commentAt(value) {
|
|
4059
|
+
if (value.startsWith("#")) return 0;
|
|
4060
|
+
const found = /[ \t]+#/.exec(value);
|
|
4061
|
+
return found ? found.index : -1;
|
|
4062
|
+
}
|
|
4063
|
+
function keepSpan(line, from, to) {
|
|
4064
|
+
const start = Math.max(0, Math.min(from, line.length));
|
|
4065
|
+
const end = Math.max(start, Math.min(to, line.length));
|
|
4066
|
+
return " ".repeat(start) + line.slice(start, end) + " ".repeat(line.length - end);
|
|
4067
|
+
}
|
|
4068
|
+
function quoteEnd(line, from, quote) {
|
|
4069
|
+
for (let i = from; i < line.length; i += 1) {
|
|
4070
|
+
if (quote === '"' && line[i] === "\\") {
|
|
4071
|
+
i += 1;
|
|
4072
|
+
continue;
|
|
4073
|
+
}
|
|
4074
|
+
if (quote === "'" && line[i] === "'" && line[i + 1] === "'") {
|
|
4075
|
+
i += 1;
|
|
4076
|
+
continue;
|
|
4077
|
+
}
|
|
4078
|
+
if (line[i] === quote) return i;
|
|
4079
|
+
}
|
|
4080
|
+
return -1;
|
|
4081
|
+
}
|
|
4082
|
+
function maskFrontMatter(block) {
|
|
4083
|
+
const lines = block.split("\n");
|
|
4084
|
+
const out = lines.map((line) => blank(line));
|
|
4085
|
+
for (let i = 1; i < lines.length; ) {
|
|
4086
|
+
const line = lines[i];
|
|
4087
|
+
if (line === "---" || line === "...") break;
|
|
4088
|
+
const key = readFrontKey(line);
|
|
4089
|
+
if (!key || !FRONT_MATTER_PROSE.has(key.name.toLowerCase())) {
|
|
4090
|
+
i += 1;
|
|
4091
|
+
continue;
|
|
4092
|
+
}
|
|
4093
|
+
const quote = key.value.startsWith('"') ? '"' : key.value.startsWith("'") ? "'" : "";
|
|
4094
|
+
if (quote) {
|
|
4095
|
+
let cursor = key.valueAt + 1;
|
|
4096
|
+
while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
|
|
4097
|
+
const current = lines[i];
|
|
4098
|
+
const end = quoteEnd(current, cursor, quote);
|
|
4099
|
+
out[i] = keepSpan(current, cursor, end === -1 ? current.length : end);
|
|
4100
|
+
i += 1;
|
|
4101
|
+
cursor = 0;
|
|
4102
|
+
if (end !== -1) break;
|
|
4103
|
+
}
|
|
4104
|
+
continue;
|
|
4105
|
+
}
|
|
4106
|
+
const hash = commentAt(key.value);
|
|
4107
|
+
const body = (hash === -1 ? key.value : key.value.slice(0, hash)).trim();
|
|
4108
|
+
if (BLOCK_SCALAR.test(body)) {
|
|
4109
|
+
i += 1;
|
|
4110
|
+
while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
|
|
4111
|
+
const current = lines[i];
|
|
4112
|
+
if (current.trim() !== "" && indentOf(current) <= key.indent) break;
|
|
4113
|
+
if (current.trim()) out[i] = current;
|
|
4114
|
+
i += 1;
|
|
4115
|
+
}
|
|
4116
|
+
continue;
|
|
4117
|
+
}
|
|
4118
|
+
if (body === "" || body === "~" || /^null$/i.test(body) || body.startsWith("[") || body.startsWith("{")) {
|
|
4119
|
+
i += 1;
|
|
4120
|
+
continue;
|
|
4121
|
+
}
|
|
4122
|
+
out[i] = keepSpan(line, key.valueAt, hash === -1 ? line.length : key.valueAt + hash);
|
|
4123
|
+
i += 1;
|
|
4124
|
+
while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
|
|
4125
|
+
const current = lines[i];
|
|
4126
|
+
if (current.trim() === "" || indentOf(current) <= key.indent) break;
|
|
4127
|
+
if (!/^\s*#/.test(current)) {
|
|
4128
|
+
const cut = commentAt(current);
|
|
4129
|
+
out[i] = cut === -1 ? current : keepSpan(current, 0, cut);
|
|
4130
|
+
}
|
|
4131
|
+
i += 1;
|
|
4132
|
+
}
|
|
4133
|
+
}
|
|
4134
|
+
const masked = out.join("\n");
|
|
4135
|
+
return masked.length === block.length ? masked : blank(block);
|
|
4136
|
+
}
|
|
4045
4137
|
function proseBlocks(file) {
|
|
4046
|
-
const masked = file.text.replace(/^(```|~~~)[\s\S]*?^\1/gm, blank).replace(/`[^`\n]*`/g, (m) => " ".repeat(m.length)).replace(/^---\n[\s\S]*?\n---\n/,
|
|
4138
|
+
const masked = file.text.replace(/^(```|~~~)[\s\S]*?^\1/gm, blank).replace(/`[^`\n]*`/g, (m) => " ".repeat(m.length)).replace(/^---\n[\s\S]*?\n---\n/, (block) => maskFrontMatter(block)).replace(/<!--[\s\S]*?-->/g, blank);
|
|
4047
4139
|
return [{ path: file.path, text: masked, offset: 0 }];
|
|
4048
4140
|
}
|
|
4049
4141
|
function isData(path) {
|