@domandigital/craft 0.19.2 → 0.20.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/CHANGELOG.md +12 -0
- package/README.md +51 -0
- package/STANDARD.md +86 -3
- package/dist/{chunk-EKGHL4D2.js → chunk-3CD3DTEI.js} +2 -2
- package/dist/{chunk-EDM4L5WJ.js → chunk-H4UF2I7V.js} +1 -1
- package/dist/chunk-IJUZ7RV4.js +151 -0
- package/dist/{chunk-D2PEKYKH.js → chunk-LZVTN2KI.js} +22 -9
- package/dist/{chunk-ZKZCPVQ6.js → chunk-RFU5CIST.js} +2 -2
- package/dist/{cli-T3IA7IQK.js → cli-3IAIKGCP.js} +3 -3
- package/dist/{cli-OS5ESEJV.js → cli-5DONIRMR.js} +4 -4
- package/dist/{cli-VLNOQYEL.js → cli-73JCUXAV.js} +2 -2
- package/dist/{cli-GUEBFFF3.js → cli-EDQNTWDD.js} +2 -2
- package/dist/{cli-KTN5OXHZ.js → cli-EOXIJOJN.js} +3 -3
- package/dist/cli-YHS2VPWQ.js +122 -0
- package/dist/{cli-BZSJIUQH.js → cli-YUVATZD5.js} +1 -1
- package/dist/cli.js +1 -1
- package/dist/phone.cjs +548 -21
- package/dist/phone.d.cts +265 -28
- package/dist/phone.d.ts +265 -28
- package/dist/phone.js +534 -21
- package/dist/viewports-cli-RYV4LDQK.js +683 -0
- package/package.json +1 -1
- package/dist/cli-RAH4CKYY.js +0 -249
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EMPTY_BASELINE,
|
|
3
|
+
checkExceptions,
|
|
4
|
+
judgeMeasured,
|
|
5
|
+
judgeStatic,
|
|
6
|
+
scanPhoneFirst,
|
|
7
|
+
writeBaseline
|
|
8
|
+
} from "./chunk-IJUZ7RV4.js";
|
|
9
|
+
import {
|
|
10
|
+
SOURCE_FILE,
|
|
11
|
+
readPaths
|
|
12
|
+
} from "./chunk-LZVTN2KI.js";
|
|
13
|
+
import {
|
|
14
|
+
toJson
|
|
15
|
+
} from "./chunk-QIEDBL4J.js";
|
|
16
|
+
import "./chunk-WK2WMWTH.js";
|
|
17
|
+
import "./chunk-CZ7KT452.js";
|
|
18
|
+
import "./chunk-QYBAVU3P.js";
|
|
19
|
+
|
|
20
|
+
// src/phone/cli.ts
|
|
21
|
+
import { existsSync, readdirSync, readFileSync, writeFileSync } from "fs";
|
|
22
|
+
import { join, resolve } from "path";
|
|
23
|
+
var USAGE = "usage: craft phone-first [--config phone-first.json] [--measured <dir>] [--update-baseline] [--json]";
|
|
24
|
+
function parse(args) {
|
|
25
|
+
const flags = { config: "phone-first.json", update: false, json: false };
|
|
26
|
+
for (let i = 0; i < args.length; i++) {
|
|
27
|
+
const a = args[i];
|
|
28
|
+
if (a === "--update-baseline") flags.update = true;
|
|
29
|
+
else if (a === "--json") flags.json = true;
|
|
30
|
+
else if (a === "--config" || a === "--measured") {
|
|
31
|
+
const v = args[++i];
|
|
32
|
+
if (!v || v.startsWith("--")) return `${a} needs a value`;
|
|
33
|
+
if (a === "--config") flags.config = v;
|
|
34
|
+
else flags.measured = v;
|
|
35
|
+
} else return `unknown argument ${a}`;
|
|
36
|
+
}
|
|
37
|
+
return flags;
|
|
38
|
+
}
|
|
39
|
+
function loadConfig(path) {
|
|
40
|
+
if (!existsSync(path)) throw new Error(`no ${path}. Write one: { "source": ["<dirs with styles and components>"], "baseline": "phone-first.baseline.json" }`);
|
|
41
|
+
const c = JSON.parse(readFileSync(path, "utf8"));
|
|
42
|
+
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`);
|
|
43
|
+
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`);
|
|
44
|
+
if (c.exceptions !== void 0 && !Array.isArray(c.exceptions)) throw new Error(`${path}: "exceptions" should be a list of { "file", "reason" }`);
|
|
45
|
+
return { source: c.source, ignore: c.ignore ?? [], exceptions: c.exceptions ?? [], baseline: c.baseline ?? "phone-first.baseline.json" };
|
|
46
|
+
}
|
|
47
|
+
function loadBaseline(path) {
|
|
48
|
+
if (!existsSync(path)) return EMPTY_BASELINE;
|
|
49
|
+
const b = JSON.parse(readFileSync(path, "utf8"));
|
|
50
|
+
return { ...b.note ? { note: b.note } : {}, static: b.static ?? [], measured: b.measured ?? [] };
|
|
51
|
+
}
|
|
52
|
+
function loadMeasured(dir) {
|
|
53
|
+
if (!existsSync(dir)) throw new Error(`--measured ${dir}: no such folder. Run the portal's phone-first specs first; they write it.`);
|
|
54
|
+
const routes = readdirSync(dir).filter((f) => f.endsWith(".json")).sort().map((f) => JSON.parse(readFileSync(join(dir, f), "utf8")));
|
|
55
|
+
if (routes.length === 0) throw new Error(`--measured ${dir}: no measured routes in it. Did the phone-first specs run?`);
|
|
56
|
+
return routes;
|
|
57
|
+
}
|
|
58
|
+
function runPhoneFirst(args, io) {
|
|
59
|
+
const flags = parse(args);
|
|
60
|
+
if (typeof flags === "string") {
|
|
61
|
+
io.err(`craft phone-first: ${flags}
|
|
62
|
+
${USAGE}`);
|
|
63
|
+
return 2;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const config = loadConfig(resolve(io.cwd, flags.config));
|
|
67
|
+
const baselinePath = resolve(io.cwd, config.baseline);
|
|
68
|
+
const baseline = loadBaseline(baselinePath);
|
|
69
|
+
const exceptionProblems = checkExceptions(config.exceptions, (f) => existsSync(resolve(io.cwd, f)));
|
|
70
|
+
const sources = config.source.filter((s2) => existsSync(resolve(io.cwd, s2)));
|
|
71
|
+
const missing = config.source.filter((s2) => !sources.includes(s2));
|
|
72
|
+
if (missing.length) throw new Error(`${flags.config}: source ${missing.join(", ")} not found`);
|
|
73
|
+
const files = readPaths(sources, io.cwd, SOURCE_FILE, void 0, config.ignore);
|
|
74
|
+
const { findings, excused } = scanPhoneFirst(files, config.exceptions);
|
|
75
|
+
const routes = flags.measured ? loadMeasured(resolve(io.cwd, flags.measured)) : null;
|
|
76
|
+
if (flags.update) {
|
|
77
|
+
const next = writeBaseline(findings, routes ?? [], baseline.note);
|
|
78
|
+
if (!routes) next.measured = baseline.measured;
|
|
79
|
+
writeFileSync(baselinePath, `${JSON.stringify(next, null, 2)}
|
|
80
|
+
`);
|
|
81
|
+
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)`);
|
|
82
|
+
return exceptionProblems.length ? 1 : 0;
|
|
83
|
+
}
|
|
84
|
+
const s = judgeStatic(findings, baseline);
|
|
85
|
+
const m = routes ? judgeMeasured(routes, baseline) : { fresh: [], stale: [], known: 0 };
|
|
86
|
+
const failed = exceptionProblems.length + s.fresh.length + s.stale.length + m.fresh.length + m.stale.length > 0;
|
|
87
|
+
if (flags.json) {
|
|
88
|
+
io.out(toJson({ pass: !failed, files: files.length, excused, routes: routes?.map((r) => r.route) ?? null, exceptionProblems, static: s, measured: m }));
|
|
89
|
+
return failed ? 1 : 0;
|
|
90
|
+
}
|
|
91
|
+
const wide = routes?.some((r) => r.viewports) ?? false;
|
|
92
|
+
const section = (title, lines) => lines.length ? `
|
|
93
|
+
${title}
|
|
94
|
+
${lines.map((l) => ` ${l}`).join("\n")}` : "";
|
|
95
|
+
const known = s.known + m.known;
|
|
96
|
+
const summary = [
|
|
97
|
+
`${files.length} files${routes ? ` and ${routes.length} route${routes.length === 1 ? "" : "s"} at ${wide ? "every viewport" : "375px"}` : ""}`,
|
|
98
|
+
excused ? `${excused} recorded exception${excused === 1 ? "" : "s"}` : null,
|
|
99
|
+
known ? `${known} known breach${known === 1 ? "" : "es"} in ${config.baseline}` : null
|
|
100
|
+
].filter(Boolean).join(", ");
|
|
101
|
+
if (!failed) {
|
|
102
|
+
io.out(`craft phone-first: pass. ${summary}.`);
|
|
103
|
+
return 0;
|
|
104
|
+
}
|
|
105
|
+
io.err(
|
|
106
|
+
[
|
|
107
|
+
`craft phone-first: fail. ${summary}.`,
|
|
108
|
+
section("The exceptions:", exceptionProblems),
|
|
109
|
+
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),
|
|
110
|
+
section(wide ? "Measured across the viewports, phone first:" : "Measured at 375px:", m.fresh),
|
|
111
|
+
section("The baseline claims more than is there (good: lower it, so the fix stays fixed):", [...s.stale, ...m.stale])
|
|
112
|
+
].join("")
|
|
113
|
+
);
|
|
114
|
+
return 1;
|
|
115
|
+
} catch (error) {
|
|
116
|
+
io.err(`craft phone-first: ${error.message}`);
|
|
117
|
+
return 2;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export {
|
|
121
|
+
runPhoneFirst
|
|
122
|
+
};
|