@openuji/speculator 0.3.0 → 0.3.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/README.md +20 -0
- package/bin/speculator.mjs +76 -0
- package/dist/browser.cjs +984 -365
- package/dist/browser.d.cts +189 -32
- package/dist/browser.d.ts +189 -32
- package/dist/browser.js +9 -1
- package/dist/chunk-KC3NVWHK.js +28 -0
- package/dist/chunk-ONLMOJIJ.js +1649 -0
- package/dist/cli/export-assertions.cjs +1713 -0
- package/dist/cli/export-assertions.d.cts +25 -0
- package/dist/cli/export-assertions.d.ts +25 -0
- package/dist/cli/export-assertions.js +107 -0
- package/dist/node.cjs +984 -365
- package/dist/node.d.cts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +14 -23
- package/package.json +13 -4
- package/dist/chunk-U4GQ6EOV.js +0 -1027
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface CliIO {
|
|
2
|
+
readFile?: (p: string, enc?: BufferEncoding) => Promise<string>;
|
|
3
|
+
writeFile?: (p: string, data: string, enc?: BufferEncoding) => Promise<void>;
|
|
4
|
+
stat?: (p: string) => Promise<{
|
|
5
|
+
isFile(): boolean;
|
|
6
|
+
}>;
|
|
7
|
+
env?: Record<string, string | undefined>;
|
|
8
|
+
log?: (msg: string) => void;
|
|
9
|
+
warn?: (msg: string) => void;
|
|
10
|
+
error?: (msg: string) => void;
|
|
11
|
+
}
|
|
12
|
+
interface ExportResultItem {
|
|
13
|
+
id: string;
|
|
14
|
+
url: string;
|
|
15
|
+
type: 'MUST' | 'MUST NOT' | 'SHOULD' | 'MAY';
|
|
16
|
+
}
|
|
17
|
+
interface ExportAssertionsResult {
|
|
18
|
+
exitCode: number;
|
|
19
|
+
outPath?: string;
|
|
20
|
+
items?: ExportResultItem[];
|
|
21
|
+
warnings: string[];
|
|
22
|
+
}
|
|
23
|
+
declare function exportAssertions(argv: string[], io?: CliIO): Promise<ExportAssertionsResult>;
|
|
24
|
+
|
|
25
|
+
export { type CliIO, type ExportAssertionsResult, type ExportResultItem, exportAssertions };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface CliIO {
|
|
2
|
+
readFile?: (p: string, enc?: BufferEncoding) => Promise<string>;
|
|
3
|
+
writeFile?: (p: string, data: string, enc?: BufferEncoding) => Promise<void>;
|
|
4
|
+
stat?: (p: string) => Promise<{
|
|
5
|
+
isFile(): boolean;
|
|
6
|
+
}>;
|
|
7
|
+
env?: Record<string, string | undefined>;
|
|
8
|
+
log?: (msg: string) => void;
|
|
9
|
+
warn?: (msg: string) => void;
|
|
10
|
+
error?: (msg: string) => void;
|
|
11
|
+
}
|
|
12
|
+
interface ExportResultItem {
|
|
13
|
+
id: string;
|
|
14
|
+
url: string;
|
|
15
|
+
type: 'MUST' | 'MUST NOT' | 'SHOULD' | 'MAY';
|
|
16
|
+
}
|
|
17
|
+
interface ExportAssertionsResult {
|
|
18
|
+
exitCode: number;
|
|
19
|
+
outPath?: string;
|
|
20
|
+
items?: ExportResultItem[];
|
|
21
|
+
warnings: string[];
|
|
22
|
+
}
|
|
23
|
+
declare function exportAssertions(argv: string[], io?: CliIO): Promise<ExportAssertionsResult>;
|
|
24
|
+
|
|
25
|
+
export { type CliIO, type ExportAssertionsResult, type ExportResultItem, exportAssertions };
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LinkedomHtmlRenderer,
|
|
3
|
+
Speculator
|
|
4
|
+
} from "../chunk-KC3NVWHK.js";
|
|
5
|
+
import "../chunk-ONLMOJIJ.js";
|
|
6
|
+
|
|
7
|
+
// src/cli/export-assertions.ts
|
|
8
|
+
import fs from "fs/promises";
|
|
9
|
+
import path from "path";
|
|
10
|
+
import { pathToFileURL } from "url";
|
|
11
|
+
function parseArgs(argv) {
|
|
12
|
+
const args = {};
|
|
13
|
+
for (let i = 0; i < argv.length; i++) {
|
|
14
|
+
const a = argv[i];
|
|
15
|
+
if (!a.startsWith("--")) continue;
|
|
16
|
+
const key = a.slice(2);
|
|
17
|
+
const next = argv[i + 1];
|
|
18
|
+
if (key === "strict" || key === "help") {
|
|
19
|
+
args[key] = true;
|
|
20
|
+
} else if (next && !next.startsWith("--")) {
|
|
21
|
+
args[key] = next;
|
|
22
|
+
i++;
|
|
23
|
+
} else {
|
|
24
|
+
args[key] = true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return args;
|
|
28
|
+
}
|
|
29
|
+
async function exportAssertions(argv, io = {}) {
|
|
30
|
+
const warnings = [];
|
|
31
|
+
const readFile = io.readFile || ((p) => fs.readFile(p, "utf8"));
|
|
32
|
+
const writeFile = io.writeFile || ((p, d) => fs.writeFile(p, d, "utf8"));
|
|
33
|
+
const stat = io.stat || ((p) => fs.stat(p));
|
|
34
|
+
const env = io.env || process.env;
|
|
35
|
+
const log = io.log || ((m) => console.log(m));
|
|
36
|
+
const warn = io.warn || ((m) => console.warn(m));
|
|
37
|
+
const error = io.error || ((m) => console.error(m));
|
|
38
|
+
const args = parseArgs(argv);
|
|
39
|
+
if (args.help) {
|
|
40
|
+
log("Usage: speculator export:assertion [--input path|--spec <s> --version <v>] [--spec-dir dir] [--base url] [--out file] [--strict]");
|
|
41
|
+
return { exitCode: 0, warnings };
|
|
42
|
+
}
|
|
43
|
+
let input = args.input;
|
|
44
|
+
let spec = args.spec;
|
|
45
|
+
let version = args.version;
|
|
46
|
+
const strict = !!args.strict;
|
|
47
|
+
const specDir = args["spec-dir"] || env.SPEC_DIR || path.resolve(process.cwd(), "spec");
|
|
48
|
+
if (!input) {
|
|
49
|
+
if (!spec || !version) {
|
|
50
|
+
error("Either --input or both --spec and --version are required.");
|
|
51
|
+
return { exitCode: 1, warnings };
|
|
52
|
+
}
|
|
53
|
+
input = path.join(specDir, spec, version, "index.spec.html");
|
|
54
|
+
}
|
|
55
|
+
const exists = await stat(input).then((s) => s.isFile()).catch(() => false);
|
|
56
|
+
if (!exists) {
|
|
57
|
+
error(`Input not found: ${input}`);
|
|
58
|
+
return { exitCode: 1, warnings };
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
if (!spec || !version) {
|
|
62
|
+
const parts = path.normalize(input).split(path.sep).filter(Boolean);
|
|
63
|
+
if (parts.length >= 3) {
|
|
64
|
+
spec = parts[parts.length - 3];
|
|
65
|
+
version = parts[parts.length - 2];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
70
|
+
const baseUrl = new URL("./", pathToFileURL(input)).toString();
|
|
71
|
+
const html = await readFile(input, "utf8");
|
|
72
|
+
const assertions = {};
|
|
73
|
+
if (spec) assertions.spec = spec;
|
|
74
|
+
if (version) assertions.version = version;
|
|
75
|
+
const speculator = new Speculator({ baseUrl, postprocess: { assertions } });
|
|
76
|
+
let captured = [];
|
|
77
|
+
const hook = (_container, outs) => {
|
|
78
|
+
const items2 = outs["assertions"];
|
|
79
|
+
if (Array.isArray(items2)) captured = items2;
|
|
80
|
+
};
|
|
81
|
+
const htmlRenderer = new LinkedomHtmlRenderer();
|
|
82
|
+
const container = htmlRenderer.parse(html);
|
|
83
|
+
const sections = Array.from(container.children);
|
|
84
|
+
const areas = ["assertions"];
|
|
85
|
+
const res = await speculator.renderDocument({ sections, postProcess: hook }, areas);
|
|
86
|
+
warnings.push(...res.warnings);
|
|
87
|
+
const base = args.base || (spec && version ? `https://spec.openuji.dev/${spec}/${version}/` : "");
|
|
88
|
+
const outPath = args.out || "assertions.json";
|
|
89
|
+
const items = captured.map((it) => ({
|
|
90
|
+
id: it.id,
|
|
91
|
+
url: base ? `${base}#${it.anchorId}` : `#${it.anchorId}`,
|
|
92
|
+
type: it.type,
|
|
93
|
+
snippet: it.snippet
|
|
94
|
+
}));
|
|
95
|
+
await writeFile(outPath, JSON.stringify(items, null, 2) + "\n", "utf8");
|
|
96
|
+
const multiWarnings = warnings.filter((w) => /Multiple normative keywords/.test(w));
|
|
97
|
+
if (multiWarnings.length) {
|
|
98
|
+
warn(`Found ${multiWarnings.length} blocks with multiple normative keywords:`);
|
|
99
|
+
for (const w of multiWarnings) warn(" - " + w);
|
|
100
|
+
if (strict) return { exitCode: 2, outPath, items, warnings };
|
|
101
|
+
}
|
|
102
|
+
log(`Wrote ${items.length} assertions to ${outPath}`);
|
|
103
|
+
return { exitCode: 0, outPath, items, warnings };
|
|
104
|
+
}
|
|
105
|
+
export {
|
|
106
|
+
exportAssertions
|
|
107
|
+
};
|