craftar 0.5.0 → 0.6.1

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.
@@ -0,0 +1,188 @@
1
+ import path from "node:path";
2
+ import { IngredientSchema } from "../schema/index.js";
3
+ import { placeholders, substitutedFile } from "./extract.js";
4
+ import { fingerprintOf } from "./fingerprint.js";
5
+ import { parseYaml } from "./forge.js";
6
+ import { substitute } from "./resolve.js";
7
+ import { stripBom, toLf } from "./text.js";
8
+ /**
9
+ * Template-aware import (spec 10): compare a workspace source with the Forge base as sync would
10
+ * render it for the importing profile, and — failing that — infer the values of the base's
11
+ * declared keys from the source. Pure but for the `DirReader` the importer hands in.
12
+ */
13
+ const PLACEHOLDER = /\{\{\s*([A-Za-z0-9_.]+)\s*\}\}/g;
14
+ const norm = (s) => toLf(stripBom(s));
15
+ /** The values sync substitutes into `meta`'s files for the importing workspace: declared defaults, then P, then W (spec 10 §6.1). */
16
+ export function renderMap(meta, profileParams, workspaceParams) {
17
+ const out = Object.create(null);
18
+ for (const [k, v] of Object.entries(meta.params ?? {}))
19
+ if (v.default !== undefined)
20
+ out[k] = v.default;
21
+ for (const [k, v] of Object.entries(profileParams))
22
+ out[k] = v;
23
+ for (const [k, v] of Object.entries(workspaceParams))
24
+ out[k] = v;
25
+ return out;
26
+ }
27
+ /** An ingredient directory as the comparison sees it: its validated metadata and its files, admitted ones as normalized text. */
28
+ export async function readBase(dir, io) {
29
+ const metaFile = path.join(dir, "ingredient.yaml");
30
+ const meta = parseYaml(metaFile, await io.readText(metaFile), IngredientSchema);
31
+ const texts = new Map();
32
+ const bytes = new Map();
33
+ for (const rel of await io.list(dir)) {
34
+ if (rel === "ingredient.yaml")
35
+ continue;
36
+ if (substitutedFile(meta, rel))
37
+ texts.set(rel, norm(await io.readText(path.join(dir, rel))));
38
+ else
39
+ bytes.set(rel, await io.readBytes(path.join(dir, rel)));
40
+ }
41
+ return { meta, texts, bytes, metaFile };
42
+ }
43
+ /** The keys every admitted file of a base cites (`C(X)`). */
44
+ export function citedKeys(texts) {
45
+ const out = new Set();
46
+ for (const t of texts.values())
47
+ for (const k of placeholders(t))
48
+ out.add(k);
49
+ return out;
50
+ }
51
+ /**
52
+ * The fingerprint of a base rendered through `map` (spec 10 §6.2): its metadata without `params`
53
+ * (a workspace cannot express a declaration), admitted files substituted exactly as `ctx.text`
54
+ * does, every other file as bytes. With no declaration and nothing set, this is `fingerprintDir`.
55
+ */
56
+ export function renderedFingerprint(base, map) {
57
+ const meta = { ...base.meta };
58
+ delete meta.params;
59
+ const files = {};
60
+ for (const [rel, text] of base.texts)
61
+ files[rel] = substitute(text, map);
62
+ for (const [rel, b] of base.bytes)
63
+ files[rel] = b;
64
+ try {
65
+ return fingerprintOf(meta, files);
66
+ }
67
+ catch (e) {
68
+ // Named the way fingerprintDir names it: a cyclic alias is a fact about this file.
69
+ throw new Error(`invalid ${path.relative(process.cwd(), base.metaFile)}: ${e.message}`);
70
+ }
71
+ }
72
+ /** A template line split into literal text and holes; placeholders that are not holes are fixed first (§6.3 step 1). */
73
+ function segments(line, holes, map) {
74
+ const out = [];
75
+ let last = 0;
76
+ let lit = "";
77
+ for (const m of line.matchAll(PLACEHOLDER)) {
78
+ lit += line.slice(last, m.index);
79
+ last = m.index + m[0].length;
80
+ const key = m[1];
81
+ if (holes.has(key)) {
82
+ out.push({ lit }, { hole: key });
83
+ lit = "";
84
+ }
85
+ else {
86
+ lit += Object.hasOwn(map, key) ? String(map[key]) : m[0];
87
+ }
88
+ }
89
+ out.push({ lit: lit + line.slice(last) });
90
+ return out.filter((s, i) => !("lit" in s) || s.lit !== "" || i === 0 || i === out.length - 1);
91
+ }
92
+ const validValue = (v) => v !== "" && !/[\n{}]/.test(v) && v === v.trim();
93
+ /** Every assignment of the holes that makes `segs` spell `line`, up to `limit`; `strict` applies the value rules. */
94
+ function solve(segs, line, strict, limit) {
95
+ const found = [];
96
+ const walk = (i, pos, assigned) => {
97
+ if (found.length >= limit)
98
+ return;
99
+ if (i === segs.length) {
100
+ if (pos === line.length)
101
+ found.push({ ...assigned });
102
+ return;
103
+ }
104
+ const s = segs[i];
105
+ if ("lit" in s) {
106
+ if (line.startsWith(s.lit, pos))
107
+ walk(i + 1, pos + s.lit.length, assigned);
108
+ return;
109
+ }
110
+ const next = segs[i + 1];
111
+ const nextLit = next && "lit" in next ? next.lit : "";
112
+ const lastHole = i + 1 >= segs.length || (i + 2 === segs.length && nextLit === "");
113
+ for (let end = pos; end <= line.length; end++) {
114
+ if (lastHole && end !== line.length - nextLit.length)
115
+ continue;
116
+ if (nextLit && !line.startsWith(nextLit, end))
117
+ continue;
118
+ const v = line.slice(pos, end);
119
+ if (strict && !validValue(v))
120
+ continue;
121
+ if (assigned[s.hole] !== undefined && assigned[s.hole] !== v)
122
+ continue;
123
+ const had = assigned[s.hole];
124
+ assigned[s.hole] = v;
125
+ walk(i + 1, end, assigned);
126
+ if (had === undefined)
127
+ delete assigned[s.hole];
128
+ if (found.length >= limit)
129
+ return;
130
+ }
131
+ };
132
+ walk(0, 0, {});
133
+ return found;
134
+ }
135
+ /**
136
+ * Infer the holes' values from the source files (spec 10 §6.3): line by line, every line with a
137
+ * hole must have exactly one solution, and every occurrence of a key must agree across lines and
138
+ * files. Not proved here — the caller renders with the result and compares fingerprints (§6.4).
139
+ */
140
+ export function infer(templates, sources, holes, map) {
141
+ const values = {};
142
+ const where = {};
143
+ for (const [file, template] of templates) {
144
+ const source = sources.get(file);
145
+ if (source === undefined)
146
+ return { fallback: "F5", reason: `${file} differs` };
147
+ const tLines = template.split("\n");
148
+ const sLines = norm(source).split("\n");
149
+ if (tLines.length !== sLines.length)
150
+ return { fallback: "F5", reason: `the template does not match ${file} (line counts differ)` };
151
+ for (let n = 0; n < tLines.length; n++) {
152
+ const segs = segments(tLines[n], holes, map);
153
+ const hasHole = segs.some((s) => "hole" in s);
154
+ if (!hasHole) {
155
+ const lit = segs.map((s) => ("lit" in s ? s.lit : "")).join("");
156
+ if (lit !== sLines[n])
157
+ return { fallback: "F5", reason: `the template does not match line ${n + 1} of ${file}` };
158
+ continue;
159
+ }
160
+ for (let i = 1; i < segs.length; i++) {
161
+ if ("hole" in segs[i] && "hole" in segs[i - 1]) {
162
+ const a = segs[i - 1].hole;
163
+ const b = segs[i].hole;
164
+ return { fallback: "F4", reason: `inference ambiguous: {{${a}}}{{${b}}} are adjacent on line ${n + 1} of ${file}` };
165
+ }
166
+ }
167
+ const sols = solve(segs, sLines[n], true, 2);
168
+ if (sols.length > 1)
169
+ return { fallback: "F6", reason: `inference ambiguous on line ${n + 1} of ${file}` };
170
+ if (sols.length === 0) {
171
+ const [loose] = solve(segs, sLines[n], false, 1);
172
+ const bad = loose && Object.entries(loose).find(([, v]) => !validValue(v));
173
+ if (bad)
174
+ return { fallback: "F7", reason: `${bad[0]} would be ${JSON.stringify(bad[1])}, which a parameter cannot carry` };
175
+ return { fallback: "F5", reason: `the template does not match line ${n + 1} of ${file}` };
176
+ }
177
+ for (const [k, v] of Object.entries(sols[0])) {
178
+ if (values[k] !== undefined && values[k] !== v) {
179
+ return { fallback: "F5", reason: `${k} is ${JSON.stringify(values[k])} in ${where[k]} but ${JSON.stringify(v)} on line ${n + 1} of ${file}` };
180
+ }
181
+ values[k] = v;
182
+ where[k] ??= `line ${n + 1} of ${file}`;
183
+ }
184
+ }
185
+ }
186
+ return { values };
187
+ }
188
+ //# sourceMappingURL=template-import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-import.js","sourceRoot":"","sources":["../../src/core/template-import.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAmB,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAkB,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE3C;;;;GAIG;AAEH,MAAM,WAAW,GAAG,iCAAiC,CAAC;AACtD,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9C,qIAAqI;AACrI,MAAM,UAAU,SAAS,CAAC,IAAgB,EAAE,aAAsC,EAAE,eAAwC;IAC1H,MAAM,GAAG,GAA4B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACzD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;QAAE,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;IACxG,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC/D,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACjE,OAAO,GAAG,CAAC;AACb,CAAC;AAED,iIAAiI;AACjI,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAW,EAAE,EAAa;IACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAC,CAAC;IAChF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,IAAI,GAAG,KAAK,iBAAiB;YAAE,SAAS;QACxC,IAAI,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC;YAAE,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;;YACxF,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AAC1C,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,SAAS,CAAC,KAA0B;IAClD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE;QAAE,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC5E,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAA0C,EAAE,GAA4B;IAC1G,MAAM,IAAI,GAA4B,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IACvD,OAAO,IAAI,CAAC,MAAM,CAAC;IACnB,MAAM,KAAK,GAAoC,EAAE,CAAC;IAClD,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK;QAAE,KAAK,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACzE,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK;QAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,OAAO,aAAa,CAAC,IAAkB,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,mFAAmF;QACnF,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAM,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IACrG,CAAC;AACH,CAAC;AAQD,wHAAwH;AACxH,SAAS,QAAQ,CAAC,IAAY,EAAE,KAAkB,EAAE,GAA4B;IAC9E,MAAM,GAAG,GAAc,EAAE,CAAC;IAC1B,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC3C,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,GAAG,CAAC,CAAC,KAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC9B,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACjB,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACnB,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;YACjC,GAAG,GAAG,EAAE,CAAC;QACX,CAAC;aAAM,CAAC;YACN,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IACD,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1C,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAChG,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AAElF,qHAAqH;AACrH,SAAS,KAAK,CAAC,IAAe,EAAE,IAAY,EAAE,MAAe,EAAE,KAAa;IAC1E,MAAM,KAAK,GAAkC,EAAE,CAAC;IAChD,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,GAAW,EAAE,QAAgC,EAAE,EAAE;QACxE,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK;YAAE,OAAO;QAClC,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;YACtB,IAAI,GAAG,KAAK,IAAI,CAAC,MAAM;gBAAE,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAC;YACrD,OAAO;QACT,CAAC;QACD,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YACf,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC;gBAAE,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC3E,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,MAAM,IAAI,OAAO,KAAK,EAAE,CAAC,CAAC;QACnF,KAAK,IAAI,GAAG,GAAG,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;YAC9C,IAAI,QAAQ,IAAI,GAAG,KAAK,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM;gBAAE,SAAS;YAC/D,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC;gBAAE,SAAS;YACxD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC/B,IAAI,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;gBAAE,SAAS;YACvC,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,SAAS,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;gBAAE,SAAS;YACvE,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC7B,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACrB,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;YAC3B,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC/C,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK;gBAAE,OAAO;QACpC,CAAC;IACH,CAAC,CAAC;IACF,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IACf,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,KAAK,CAAC,SAA8B,EAAE,OAA4B,EAAE,KAAkB,EAAE,GAA4B;IAClI,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,MAAM,KAAK,GAA2B,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,SAAS,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,UAAU,EAAE,CAAC;QAC/E,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM;YAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,+BAA+B,IAAI,uBAAuB,EAAE,CAAC;QACnI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;YAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;YAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAChE,IAAI,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC;oBAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,oCAAoC,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;gBACjH,SAAS;YACX,CAAC;YACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,IAAI,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;oBAC/C,MAAM,CAAC,GAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAsB,CAAC,IAAI,CAAC;oBACjD,MAAM,CAAC,GAAI,IAAI,CAAC,CAAC,CAAsB,CAAC,IAAI,CAAC;oBAC7C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,0BAA0B,CAAC,OAAO,CAAC,2BAA2B,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;gBACtH,CAAC;YACH,CAAC;YACD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC7C,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,+BAA+B,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;YAC1G,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;gBACjD,MAAM,GAAG,GAAG,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC3E,IAAI,GAAG;oBAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,kCAAkC,EAAE,CAAC;gBAC3H,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,oCAAoC,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;YAC5F,CAAC;YACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7C,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC/C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;gBAChJ,CAAC;gBACD,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;gBACd,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;YAC1C,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC"}
@@ -0,0 +1,36 @@
1
+ import YAML from "yaml";
2
+ import { detectEol, stripBom, toLf, withEol } from "./text.js";
3
+ /**
4
+ * Edit a YAML document in place (spec 09 §6.4, generalized by spec 10 §6.6): refuse one that
5
+ * does not round-trip byte for byte — an edit never reformats a line it did not decide — apply
6
+ * `edit`, and restore the EOL and BOM. The width the file was written with decides the width of
7
+ * the edit: `unify` writes with no folding, `import` with yaml's default 80 columns, so both are
8
+ * tried, and the first that reproduces the text is the one the edit is serialized with. Both set
9
+ * `flowCollectionPadding: false`, so a file that spells a flow collection `[a, b]`, the common
10
+ * hand-written form, still round-trips; yaml's default would write it back as `[ a, b ]`.
11
+ */
12
+ const BOM = String.fromCharCode(0xfeff);
13
+ const WIDTHS = [
14
+ { flowCollectionPadding: false, lineWidth: 0 },
15
+ { flowCollectionPadding: false },
16
+ ];
17
+ export function editYamlText(raw, o, edit) {
18
+ const refuse = (why, fix = "reformat it by hand, commit, and re-run") => new Error(`${o.command}: cannot edit ${o.label} in place (${why}) — ${fix}`);
19
+ const eol = detectEol(raw);
20
+ const bom = raw.charCodeAt(0) === BOM.charCodeAt(0);
21
+ const doc = YAML.parseDocument(raw);
22
+ const text = toLf(stripBom(raw));
23
+ const width = doc.errors.length ? undefined : WIDTHS.find((w) => doc.toString(w) === text);
24
+ if (!width)
25
+ throw refuse("it does not round-trip unchanged through the YAML writer");
26
+ for (const key of o.keys) {
27
+ const node = doc.get(key, true);
28
+ if (YAML.isAlias(node))
29
+ throw refuse(`${key} is an alias`, "expand it by hand, commit, and re-run");
30
+ if ((YAML.isMap(node) || YAML.isSeq(node)) && node.flow && node.items.length === 0)
31
+ node.flow = false;
32
+ }
33
+ edit(doc);
34
+ return (bom ? BOM : "") + withEol(doc.toString(width), eol);
35
+ }
36
+ //# sourceMappingURL=yaml-edit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yaml-edit.js","sourceRoot":"","sources":["../../src/core/yaml-edit.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE/D;;;;;;;;GAQG;AAEH,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;AACxC,MAAM,MAAM,GAAG;IACb,EAAE,qBAAqB,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE;IAC9C,EAAE,qBAAqB,EAAE,KAAK,EAAE;CACxB,CAAC;AAWX,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,CAAkB,EAAE,IAAkC;IAC9F,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,GAAG,GAAG,yCAAyC,EAAE,EAAE,CAC9E,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,iBAAiB,CAAC,CAAC,KAAK,cAAc,GAAG,OAAO,GAAG,EAAE,CAAC,CAAC;IAC/E,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC3B,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IAC3F,IAAI,CAAC,KAAK;QAAE,MAAM,MAAM,CAAC,0DAA0D,CAAC,CAAC;IACrF,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAChC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,MAAM,MAAM,CAAC,GAAG,GAAG,cAAc,EAAE,uCAAuC,CAAC,CAAC;QACpG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;IACxG,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;AAC9D,CAAC"}