bireactive 0.2.3 → 0.3.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/dist/animation/anim.js +4 -0
- package/dist/coll.d.ts +7 -7
- package/dist/coll.js +3 -1
- package/dist/core/cell.d.ts +89 -66
- package/dist/core/cell.js +642 -401
- package/dist/core/index.d.ts +4 -14
- package/dist/core/index.js +4 -14
- package/dist/core/lenses/aggregates.d.ts +1 -1
- package/dist/core/lenses/aggregates.js +4 -3
- package/dist/core/lenses/closed-form-policies.js +6 -6
- package/dist/core/lenses/decompositions.js +3 -3
- package/dist/core/lenses/domain-aggregates.js +5 -5
- package/dist/core/lenses/geometry.d.ts +1 -1
- package/dist/core/lenses/geometry.js +6 -7
- package/dist/core/lenses/memory.d.ts +2 -2
- package/dist/core/lenses/memory.js +3 -3
- package/dist/core/lenses/typed-factor.js +4 -3
- package/dist/core/traits.d.ts +1 -0
- package/dist/core/values/box.js +7 -7
- package/dist/core/values/color.js +5 -5
- package/dist/core/values/field.d.ts +70 -0
- package/dist/core/values/field.js +230 -0
- package/dist/core/values/gpu.d.ts +4 -2
- package/dist/core/values/gpu.js +11 -4
- package/dist/core/values/matrix.js +7 -7
- package/dist/core/values/num.d.ts +1 -1
- package/dist/core/values/num.js +1 -1
- package/dist/core/values/pose.js +4 -4
- package/dist/core/values/range.js +6 -6
- package/dist/core/values/template.d.ts +1 -1
- package/dist/core/values/template.js +2 -1
- package/dist/core/values/transform.js +7 -7
- package/dist/core/values/tri.js +3 -3
- package/dist/core/values/vec.js +8 -12
- package/dist/ext/timeline.js +2 -2
- package/dist/formats/cst.d.ts +127 -0
- package/dist/formats/cst.js +280 -0
- package/dist/formats/edn.d.ts +2 -0
- package/dist/formats/edn.js +301 -0
- package/dist/formats/index.d.ts +6 -0
- package/dist/formats/index.js +8 -0
- package/dist/formats/json.d.ts +2 -0
- package/dist/formats/json.js +332 -0
- package/dist/formats/lens.d.ts +8 -0
- package/dist/formats/lens.js +54 -0
- package/dist/formats/toml.d.ts +2 -0
- package/dist/formats/toml.js +526 -0
- package/dist/formats/yaml.d.ts +2 -0
- package/dist/formats/yaml.js +661 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/learn/data.d.ts +49 -0
- package/dist/learn/data.js +181 -0
- package/dist/learn/index.d.ts +3 -0
- package/dist/learn/index.js +6 -0
- package/dist/learn/lens-net.d.ts +63 -0
- package/dist/learn/lens-net.js +219 -0
- package/dist/learn/mlp.d.ts +77 -0
- package/dist/learn/mlp.js +292 -0
- package/dist/propagators/csp.d.ts +13 -0
- package/dist/propagators/csp.js +52 -0
- package/dist/propagators/flex.d.ts +31 -0
- package/dist/propagators/flex.js +189 -0
- package/dist/propagators/graph.d.ts +73 -0
- package/dist/propagators/graph.js +543 -0
- package/dist/propagators/index.d.ts +8 -6
- package/dist/propagators/index.js +15 -6
- package/dist/propagators/lattice.d.ts +45 -0
- package/dist/propagators/lattice.js +113 -0
- package/dist/propagators/layout.d.ts +1 -27
- package/dist/propagators/layout.js +6 -175
- package/dist/propagators/numeric.d.ts +17 -0
- package/dist/propagators/numeric.js +93 -0
- package/dist/propagators/solver.d.ts +51 -0
- package/dist/propagators/solver.js +175 -0
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema/lens.d.ts +121 -0
- package/dist/schema/lens.js +429 -0
- package/dist/shapes/annular-sector.js +4 -4
- package/dist/shapes/button.js +1 -1
- package/dist/shapes/circle.js +1 -1
- package/dist/shapes/handle.js +2 -2
- package/dist/shapes/label.js +1 -1
- package/dist/shapes/layout.js +2 -2
- package/dist/shapes/rect.js +7 -7
- package/dist/shapes/shape.js +8 -8
- package/dist/tex/tex.js +9 -2
- package/dist/web/diagram.js +2 -2
- package/package.json +9 -19
- package/dist/propagators/network.d.ts +0 -52
- package/dist/propagators/network.js +0 -185
- package/dist/propagators/propagator.d.ts +0 -12
- package/dist/propagators/propagator.js +0 -16
- package/dist/propagators/range.d.ts +0 -45
- package/dist/propagators/range.js +0 -147
- package/dist/propagators/relations.d.ts +0 -60
- package/dist/propagators/relations.js +0 -343
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
// yaml.ts — tolerant YAML adapter (block subset).
|
|
2
|
+
//
|
|
3
|
+
// Supports block maps and sequences, compact `- key: value` items,
|
|
4
|
+
// single-line flow collections, plain/quoted scalars, and comments.
|
|
5
|
+
// Anchors, tags, block scalars, and multi-document streams are out of
|
|
6
|
+
// scope: such lines become whole-line error regions, which keeps the
|
|
7
|
+
// rest of the document live. Comments survive surgical edits because
|
|
8
|
+
// scalar value spans exclude them and standalone comment lines sit
|
|
9
|
+
// outside entry spans.
|
|
10
|
+
import { isObject, } from "./cst.js";
|
|
11
|
+
const NUMRE = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
|
|
12
|
+
const PLAIN_KEY = /^[A-Za-z_][\w-]*$/;
|
|
13
|
+
const PLAIN_STR = /^[A-Za-z0-9_][A-Za-z0-9_ ./@-]*$/;
|
|
14
|
+
function inferScalar(s) {
|
|
15
|
+
if (s === "true")
|
|
16
|
+
return true;
|
|
17
|
+
if (s === "false")
|
|
18
|
+
return false;
|
|
19
|
+
if (s === "null" || s === "~" || s === "")
|
|
20
|
+
return null;
|
|
21
|
+
if (NUMRE.test(s))
|
|
22
|
+
return Number(s);
|
|
23
|
+
return s;
|
|
24
|
+
}
|
|
25
|
+
class P {
|
|
26
|
+
text;
|
|
27
|
+
errors = [];
|
|
28
|
+
lines = [];
|
|
29
|
+
constructor(text) {
|
|
30
|
+
this.text = text;
|
|
31
|
+
let pos = 0;
|
|
32
|
+
while (pos <= text.length - 1) {
|
|
33
|
+
let end = text.indexOf("\n", pos);
|
|
34
|
+
if (end === -1)
|
|
35
|
+
end = text.length;
|
|
36
|
+
let indent = 0;
|
|
37
|
+
while (pos + indent < end && text[pos + indent] === " ")
|
|
38
|
+
indent++;
|
|
39
|
+
const contentStart = pos + indent;
|
|
40
|
+
// Blank (or tab-led — flagged) lines are structurally invisible.
|
|
41
|
+
if (contentStart < end && text[contentStart] !== "\r") {
|
|
42
|
+
if (text[contentStart] === "\t") {
|
|
43
|
+
this.errors.push({ start: pos, end, message: "tab indentation is not supported" });
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
this.lines.push({ start: pos, end, indent, contentStart });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
pos = end + 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
err(start, end, message) {
|
|
53
|
+
this.errors.push({ start, end, message });
|
|
54
|
+
}
|
|
55
|
+
/** Comment-aware effective end of a line region, trailing ws trimmed. */
|
|
56
|
+
effEnd(from, lineEnd) {
|
|
57
|
+
const t = this.text;
|
|
58
|
+
let p = from;
|
|
59
|
+
let q = null;
|
|
60
|
+
while (p < lineEnd) {
|
|
61
|
+
const c = t[p];
|
|
62
|
+
if (q === '"') {
|
|
63
|
+
if (c === "\\")
|
|
64
|
+
p++;
|
|
65
|
+
else if (c === '"')
|
|
66
|
+
q = null;
|
|
67
|
+
}
|
|
68
|
+
else if (q === "'") {
|
|
69
|
+
if (c === "'")
|
|
70
|
+
q = null;
|
|
71
|
+
}
|
|
72
|
+
else if (c === '"')
|
|
73
|
+
q = '"';
|
|
74
|
+
else if (c === "'")
|
|
75
|
+
q = "'";
|
|
76
|
+
else if (c === "#" && (p === from || t[p - 1] === " " || t[p - 1] === "\t"))
|
|
77
|
+
break;
|
|
78
|
+
p++;
|
|
79
|
+
}
|
|
80
|
+
while (p > from && (t[p - 1] === " " || t[p - 1] === "\t" || t[p - 1] === "\r"))
|
|
81
|
+
p--;
|
|
82
|
+
return p;
|
|
83
|
+
}
|
|
84
|
+
isComment(li, cs) {
|
|
85
|
+
return this.text[cs ?? this.lines[li].contentStart] === "#";
|
|
86
|
+
}
|
|
87
|
+
/** Next structural line index at or after `i` (skips comment lines). */
|
|
88
|
+
nextContent(i) {
|
|
89
|
+
let j = i;
|
|
90
|
+
while (j < this.lines.length && this.isComment(j))
|
|
91
|
+
j++;
|
|
92
|
+
return j < this.lines.length ? j : -1;
|
|
93
|
+
}
|
|
94
|
+
isSeqItem(cs, end) {
|
|
95
|
+
if (this.text[cs] !== "-")
|
|
96
|
+
return false;
|
|
97
|
+
return cs + 1 >= end || this.text[cs + 1] === " ";
|
|
98
|
+
}
|
|
99
|
+
/** `key:` scan at a content start. Returns null when the region isn't
|
|
100
|
+
* a mapping entry (plain scalar, flow value, …). */
|
|
101
|
+
scanKey(cs, end) {
|
|
102
|
+
const t = this.text;
|
|
103
|
+
const c = t[cs];
|
|
104
|
+
if (c === "[" || c === "{" || c === undefined)
|
|
105
|
+
return null;
|
|
106
|
+
if (c === '"' || c === "'") {
|
|
107
|
+
const s = this.scanQuoted(cs, end);
|
|
108
|
+
if (s === null)
|
|
109
|
+
return null;
|
|
110
|
+
let p = s.end;
|
|
111
|
+
while (p < end && t[p] === " ")
|
|
112
|
+
p++;
|
|
113
|
+
if (t[p] !== ":")
|
|
114
|
+
return null;
|
|
115
|
+
if (p + 1 < end && t[p + 1] !== " ")
|
|
116
|
+
return null;
|
|
117
|
+
return { key: s.value, colonEnd: p + 1 };
|
|
118
|
+
}
|
|
119
|
+
for (let p = cs; p < end; p++) {
|
|
120
|
+
if (t[p] === ":" && (p + 1 >= end || t[p + 1] === " ")) {
|
|
121
|
+
const key = t.slice(cs, p).trim();
|
|
122
|
+
if (key.length === 0 || key.includes("#"))
|
|
123
|
+
return null;
|
|
124
|
+
return { key, colonEnd: p + 1 };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
scanQuoted(start, max) {
|
|
130
|
+
const t = this.text;
|
|
131
|
+
const q = t[start];
|
|
132
|
+
let out = "";
|
|
133
|
+
let p = start + 1;
|
|
134
|
+
while (p < max) {
|
|
135
|
+
const c = t[p];
|
|
136
|
+
if (q === '"' && c === "\\") {
|
|
137
|
+
const esc = t[p + 1];
|
|
138
|
+
p += 2;
|
|
139
|
+
if (esc === "n")
|
|
140
|
+
out += "\n";
|
|
141
|
+
else if (esc === "t")
|
|
142
|
+
out += "\t";
|
|
143
|
+
else
|
|
144
|
+
out += esc ?? "";
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (c === q) {
|
|
148
|
+
if (q === "'" && t[p + 1] === "'") {
|
|
149
|
+
out += "'";
|
|
150
|
+
p += 2;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
return { value: out, end: p + 1 };
|
|
154
|
+
}
|
|
155
|
+
out += c;
|
|
156
|
+
p++;
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
// -- flow (single-line [..] / {..}) -------------------------------------
|
|
161
|
+
flowSkip(p, end) {
|
|
162
|
+
while (p < end && (this.text[p] === " " || this.text[p] === ","))
|
|
163
|
+
p++;
|
|
164
|
+
return p;
|
|
165
|
+
}
|
|
166
|
+
flowGarbage(start, end, message) {
|
|
167
|
+
const t = this.text;
|
|
168
|
+
let p = start;
|
|
169
|
+
let depth = 0;
|
|
170
|
+
while (p < end) {
|
|
171
|
+
const c = t[p];
|
|
172
|
+
if (c === "[" || c === "{")
|
|
173
|
+
depth++;
|
|
174
|
+
else if (c === "]" || c === "}") {
|
|
175
|
+
if (depth === 0)
|
|
176
|
+
break;
|
|
177
|
+
depth--;
|
|
178
|
+
}
|
|
179
|
+
else if (depth === 0 && c === ",")
|
|
180
|
+
break;
|
|
181
|
+
p++;
|
|
182
|
+
}
|
|
183
|
+
const e = Math.max(p, start + 1);
|
|
184
|
+
this.err(start, e, message);
|
|
185
|
+
return { node: { kind: "error", start, end: e }, pos: p };
|
|
186
|
+
}
|
|
187
|
+
flowValue(p0, end) {
|
|
188
|
+
const t = this.text;
|
|
189
|
+
const p = this.flowSkip(p0, end);
|
|
190
|
+
const c = t[p];
|
|
191
|
+
if (c === "[") {
|
|
192
|
+
const items = [];
|
|
193
|
+
let q = p + 1;
|
|
194
|
+
for (;;) {
|
|
195
|
+
q = this.flowSkip(q, end);
|
|
196
|
+
if (q >= end) {
|
|
197
|
+
this.err(p, p + 1, "unclosed flow sequence");
|
|
198
|
+
return {
|
|
199
|
+
node: { kind: "array", start: p, end: q, items, meta: seqMeta(0, true) },
|
|
200
|
+
pos: q,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
if (t[q] === "]") {
|
|
204
|
+
return {
|
|
205
|
+
node: { kind: "array", start: p, end: q + 1, items, meta: seqMeta(0, true) },
|
|
206
|
+
pos: q + 1,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
const r = this.flowValue(q, end);
|
|
210
|
+
items.push(r.node);
|
|
211
|
+
q = r.pos;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (c === "{") {
|
|
215
|
+
const entries = [];
|
|
216
|
+
let q = p + 1;
|
|
217
|
+
for (;;) {
|
|
218
|
+
q = this.flowSkip(q, end);
|
|
219
|
+
if (q >= end) {
|
|
220
|
+
this.err(p, p + 1, "unclosed flow mapping");
|
|
221
|
+
return {
|
|
222
|
+
node: { kind: "object", start: p, end: q, entries, meta: mapMeta(0, true) },
|
|
223
|
+
pos: q,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
if (t[q] === "}") {
|
|
227
|
+
return {
|
|
228
|
+
node: { kind: "object", start: p, end: q + 1, entries, meta: mapMeta(0, true) },
|
|
229
|
+
pos: q + 1,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
const entryStart = q;
|
|
233
|
+
let key = null;
|
|
234
|
+
let kEnd = q;
|
|
235
|
+
if (t[q] === '"' || t[q] === "'") {
|
|
236
|
+
const s = this.scanQuoted(q, end);
|
|
237
|
+
if (s !== null) {
|
|
238
|
+
key = s.value;
|
|
239
|
+
kEnd = s.end;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
let e2 = q;
|
|
244
|
+
while (e2 < end && !":,]}".includes(t[e2]))
|
|
245
|
+
e2++;
|
|
246
|
+
if (t[e2] === ":") {
|
|
247
|
+
key = t.slice(q, e2).trim();
|
|
248
|
+
kEnd = e2;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
kEnd = this.flowSkip(kEnd, end);
|
|
252
|
+
if (key === null || t[kEnd] !== ":") {
|
|
253
|
+
const g = this.flowGarbage(q, end, "expected 'key:' in flow mapping");
|
|
254
|
+
entries.push({ key: undefined, start: entryStart, end: g.node.end, node: g.node });
|
|
255
|
+
q = g.pos;
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
const r = this.flowValue(kEnd + 1, end);
|
|
259
|
+
entries.push({
|
|
260
|
+
key: r.node.kind === "error" ? undefined : key,
|
|
261
|
+
start: entryStart,
|
|
262
|
+
end: r.node.end,
|
|
263
|
+
node: r.node,
|
|
264
|
+
});
|
|
265
|
+
q = r.pos;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (c === '"' || c === "'") {
|
|
269
|
+
const s = this.scanQuoted(p, end);
|
|
270
|
+
if (s === null)
|
|
271
|
+
return this.flowGarbage(p, end, "unterminated string");
|
|
272
|
+
return { node: { kind: "scalar", start: p, end: s.end, value: s.value }, pos: s.end };
|
|
273
|
+
}
|
|
274
|
+
// Plain scalar: run to a flow delimiter.
|
|
275
|
+
let q = p;
|
|
276
|
+
while (q < end && !",]}".includes(t[q]))
|
|
277
|
+
q++;
|
|
278
|
+
let e = q;
|
|
279
|
+
while (e > p && t[e - 1] === " ")
|
|
280
|
+
e--;
|
|
281
|
+
if (e === p)
|
|
282
|
+
return this.flowGarbage(p, end, "expected a value");
|
|
283
|
+
const raw = t.slice(p, e);
|
|
284
|
+
if ("&*!|>".includes(raw[0])) {
|
|
285
|
+
this.err(p, e, "unsupported YAML feature");
|
|
286
|
+
return { node: { kind: "error", start: p, end: e }, pos: q };
|
|
287
|
+
}
|
|
288
|
+
return { node: { kind: "scalar", start: p, end: e, value: inferScalar(raw) }, pos: q };
|
|
289
|
+
}
|
|
290
|
+
/** Inline value region of a line: flow collection or scalar. */
|
|
291
|
+
parseInline(start, end) {
|
|
292
|
+
const t = this.text;
|
|
293
|
+
const c = t[start];
|
|
294
|
+
if (c === "[" || c === "{") {
|
|
295
|
+
const r = this.flowValue(start, end);
|
|
296
|
+
let p = r.pos;
|
|
297
|
+
while (p < end && t[p] === " ")
|
|
298
|
+
p++;
|
|
299
|
+
if (p < end) {
|
|
300
|
+
this.err(start, end, "trailing content after flow value");
|
|
301
|
+
return { kind: "error", start, end };
|
|
302
|
+
}
|
|
303
|
+
return r.node;
|
|
304
|
+
}
|
|
305
|
+
if (c === '"' || c === "'") {
|
|
306
|
+
const s = this.scanQuoted(start, end);
|
|
307
|
+
if (s === null || s.end < end) {
|
|
308
|
+
this.err(start, end, s === null ? "unterminated string" : "trailing content after string");
|
|
309
|
+
return { kind: "error", start, end };
|
|
310
|
+
}
|
|
311
|
+
return { kind: "scalar", start, end: s.end, value: s.value };
|
|
312
|
+
}
|
|
313
|
+
const raw = t.slice(start, end);
|
|
314
|
+
if ("&*!|>".includes(raw[0])) {
|
|
315
|
+
this.err(start, end, "unsupported YAML feature");
|
|
316
|
+
return { kind: "error", start, end };
|
|
317
|
+
}
|
|
318
|
+
return { kind: "scalar", start, end, value: inferScalar(raw) };
|
|
319
|
+
}
|
|
320
|
+
// -- block structure ------------------------------------------------------
|
|
321
|
+
parseBlock(i, indent) {
|
|
322
|
+
const line = this.lines[i];
|
|
323
|
+
const e = this.effEnd(line.contentStart, line.end);
|
|
324
|
+
if (this.isSeqItem(line.contentStart, e))
|
|
325
|
+
return this.parseSeq(i, indent);
|
|
326
|
+
if (this.scanKey(line.contentStart, e) !== null)
|
|
327
|
+
return this.parseMap(i, indent);
|
|
328
|
+
return { node: this.parseInline(line.contentStart, e), next: i + 1 };
|
|
329
|
+
}
|
|
330
|
+
parseMap(i, indent, compact) {
|
|
331
|
+
const entries = [];
|
|
332
|
+
let idx = i;
|
|
333
|
+
let start = -1;
|
|
334
|
+
while (idx < this.lines.length) {
|
|
335
|
+
const line = this.lines[idx];
|
|
336
|
+
const first = compact !== undefined && idx === i;
|
|
337
|
+
const cs = first ? compact.keyStart : line.contentStart;
|
|
338
|
+
const ind = cs - line.start;
|
|
339
|
+
if (this.isComment(idx, cs)) {
|
|
340
|
+
idx++;
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
if (ind < indent)
|
|
344
|
+
break;
|
|
345
|
+
const lineEff = this.effEnd(cs, line.end);
|
|
346
|
+
if (ind > indent) {
|
|
347
|
+
this.err(cs, lineEff, "unexpected indentation");
|
|
348
|
+
entries.push({
|
|
349
|
+
key: undefined,
|
|
350
|
+
start: line.start,
|
|
351
|
+
end: lineEff,
|
|
352
|
+
node: { kind: "error", start: cs, end: lineEff },
|
|
353
|
+
});
|
|
354
|
+
idx++;
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
if (this.isSeqItem(cs, lineEff))
|
|
358
|
+
break;
|
|
359
|
+
const k = this.scanKey(cs, lineEff);
|
|
360
|
+
if (k === null) {
|
|
361
|
+
this.err(cs, lineEff, "expected 'key: value'");
|
|
362
|
+
entries.push({
|
|
363
|
+
key: undefined,
|
|
364
|
+
start: line.start,
|
|
365
|
+
end: lineEff,
|
|
366
|
+
node: { kind: "error", start: cs, end: lineEff },
|
|
367
|
+
});
|
|
368
|
+
idx++;
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
if (start === -1)
|
|
372
|
+
start = first ? compact.keyStart : line.start;
|
|
373
|
+
let vstart = k.colonEnd;
|
|
374
|
+
while (vstart < lineEff && this.text[vstart] === " ")
|
|
375
|
+
vstart++;
|
|
376
|
+
let node;
|
|
377
|
+
let inline;
|
|
378
|
+
if (vstart >= lineEff) {
|
|
379
|
+
const j = this.nextContent(idx + 1);
|
|
380
|
+
if (j !== -1 && this.lines[j].indent > indent) {
|
|
381
|
+
const child = this.parseBlock(j, this.lines[j].indent);
|
|
382
|
+
node = child.node;
|
|
383
|
+
idx = child.next;
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
node = { kind: "scalar", start: k.colonEnd, end: k.colonEnd, value: null };
|
|
387
|
+
idx++;
|
|
388
|
+
}
|
|
389
|
+
inline = false;
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
node = this.parseInline(vstart, lineEff);
|
|
393
|
+
idx++;
|
|
394
|
+
inline = true;
|
|
395
|
+
}
|
|
396
|
+
const meta = {
|
|
397
|
+
colonEnd: k.colonEnd,
|
|
398
|
+
indent,
|
|
399
|
+
inline,
|
|
400
|
+
compactFirst: first,
|
|
401
|
+
};
|
|
402
|
+
entries.push({
|
|
403
|
+
key: k.key,
|
|
404
|
+
start: first ? compact.keyStart : line.start,
|
|
405
|
+
end: Math.max(node.end, k.colonEnd),
|
|
406
|
+
node,
|
|
407
|
+
meta,
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
const s = start === -1 ? this.lines[i].start : start;
|
|
411
|
+
return {
|
|
412
|
+
node: {
|
|
413
|
+
kind: "object",
|
|
414
|
+
start: s,
|
|
415
|
+
end: entries.length > 0 ? entries[entries.length - 1].end : s,
|
|
416
|
+
entries,
|
|
417
|
+
meta: mapMeta(indent, false),
|
|
418
|
+
},
|
|
419
|
+
next: idx,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
parseSeq(i, indent) {
|
|
423
|
+
const items = [];
|
|
424
|
+
const itemMeta = [];
|
|
425
|
+
let idx = i;
|
|
426
|
+
while (idx < this.lines.length) {
|
|
427
|
+
const line = this.lines[idx];
|
|
428
|
+
if (this.isComment(idx)) {
|
|
429
|
+
idx++;
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
if (line.indent !== indent)
|
|
433
|
+
break;
|
|
434
|
+
const lineEff = this.effEnd(line.contentStart, line.end);
|
|
435
|
+
if (!this.isSeqItem(line.contentStart, lineEff))
|
|
436
|
+
break;
|
|
437
|
+
const dashEnd = line.contentStart + 1;
|
|
438
|
+
let restStart = dashEnd;
|
|
439
|
+
while (restStart < lineEff && this.text[restStart] === " ")
|
|
440
|
+
restStart++;
|
|
441
|
+
let node;
|
|
442
|
+
if (restStart >= lineEff) {
|
|
443
|
+
const j = this.nextContent(idx + 1);
|
|
444
|
+
if (j !== -1 && this.lines[j].indent > indent) {
|
|
445
|
+
const child = this.parseBlock(j, this.lines[j].indent);
|
|
446
|
+
node = child.node;
|
|
447
|
+
idx = child.next;
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
node = { kind: "scalar", start: dashEnd, end: dashEnd, value: null };
|
|
451
|
+
idx++;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
else if (this.scanKey(restStart, lineEff) !== null) {
|
|
455
|
+
const m = this.parseMap(idx, restStart - line.start, { keyStart: restStart });
|
|
456
|
+
node = m.node;
|
|
457
|
+
idx = m.next;
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
node = this.parseInline(restStart, lineEff);
|
|
461
|
+
idx++;
|
|
462
|
+
}
|
|
463
|
+
items.push(node);
|
|
464
|
+
itemMeta.push({ dashEnd });
|
|
465
|
+
}
|
|
466
|
+
return {
|
|
467
|
+
node: {
|
|
468
|
+
kind: "array",
|
|
469
|
+
start: this.lines[i].start,
|
|
470
|
+
end: items.length > 0 ? items[items.length - 1].end : this.lines[i].start,
|
|
471
|
+
items,
|
|
472
|
+
meta: { indent, flow: false, itemMeta },
|
|
473
|
+
},
|
|
474
|
+
next: idx,
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
const mapMeta = (indent, flow) => ({ indent, flow });
|
|
479
|
+
const seqMeta = (indent, flow) => ({ indent, flow, itemMeta: [] });
|
|
480
|
+
function parse(text) {
|
|
481
|
+
const p = new P(text);
|
|
482
|
+
const first = p.nextContent(0);
|
|
483
|
+
if (first === -1) {
|
|
484
|
+
p.err(0, 0, "empty document");
|
|
485
|
+
return { tree: { kind: "error", start: 0, end: 0 }, errors: p.errors };
|
|
486
|
+
}
|
|
487
|
+
const { node, next } = p.parseBlock(first, p.lines[first].indent);
|
|
488
|
+
for (let j = next; j < p.lines.length; j++) {
|
|
489
|
+
if (p.isComment(j))
|
|
490
|
+
continue;
|
|
491
|
+
const l = p.lines[j];
|
|
492
|
+
p.err(l.contentStart, p.effEnd(l.contentStart, l.end), "content after the document root");
|
|
493
|
+
}
|
|
494
|
+
return { tree: node, errors: p.errors };
|
|
495
|
+
}
|
|
496
|
+
// -- printing ----------------------------------------------------------------
|
|
497
|
+
function pkey(k) {
|
|
498
|
+
return PLAIN_KEY.test(k) ? k : JSON.stringify(k);
|
|
499
|
+
}
|
|
500
|
+
function inlineScalar(v) {
|
|
501
|
+
if (v === null)
|
|
502
|
+
return "null";
|
|
503
|
+
if (typeof v === "string") {
|
|
504
|
+
return PLAIN_STR.test(v) && !v.endsWith(" ") && inferScalar(v) === v ? v : JSON.stringify(v);
|
|
505
|
+
}
|
|
506
|
+
return String(v);
|
|
507
|
+
}
|
|
508
|
+
const isScalar = (v) => v === null || typeof v !== "object";
|
|
509
|
+
/** Inline-printable: a scalar or an empty container. */
|
|
510
|
+
function inlineable(v) {
|
|
511
|
+
if (isScalar(v))
|
|
512
|
+
return true;
|
|
513
|
+
if (Array.isArray(v))
|
|
514
|
+
return v.length === 0;
|
|
515
|
+
return Object.keys(v).length === 0;
|
|
516
|
+
}
|
|
517
|
+
function inline(v) {
|
|
518
|
+
if (isScalar(v))
|
|
519
|
+
return inlineScalar(v);
|
|
520
|
+
return printFlow(v);
|
|
521
|
+
}
|
|
522
|
+
/** Single-line flow rendering (used inside flow contexts). */
|
|
523
|
+
function printFlow(v) {
|
|
524
|
+
if (isScalar(v))
|
|
525
|
+
return inlineScalar(v);
|
|
526
|
+
if (Array.isArray(v))
|
|
527
|
+
return `[${v.map(printFlow).join(", ")}]`;
|
|
528
|
+
const keys = Object.keys(v);
|
|
529
|
+
return `{${keys.map(k => `${pkey(k)}: ${printFlow(v[k])}`).join(", ")}}`;
|
|
530
|
+
}
|
|
531
|
+
function printMapBlock(obj, indent) {
|
|
532
|
+
const ind = " ".repeat(indent);
|
|
533
|
+
return Object.keys(obj)
|
|
534
|
+
.map(k => {
|
|
535
|
+
const v = obj[k];
|
|
536
|
+
if (inlineable(v))
|
|
537
|
+
return `${ind}${pkey(k)}: ${inline(v)}`;
|
|
538
|
+
return `${ind}${pkey(k)}:\n${blockOf(v, indent + 2)}`;
|
|
539
|
+
})
|
|
540
|
+
.join("\n");
|
|
541
|
+
}
|
|
542
|
+
function printSeqBlock(arr, indent) {
|
|
543
|
+
const ind = " ".repeat(indent);
|
|
544
|
+
return arr
|
|
545
|
+
.map(v => {
|
|
546
|
+
if (inlineable(v))
|
|
547
|
+
return `${ind}- ${inline(v)}`;
|
|
548
|
+
if (isObject(v)) {
|
|
549
|
+
const block = printMapBlock(v, indent + 2);
|
|
550
|
+
return `${ind}- ${block.slice(indent + 2)}`;
|
|
551
|
+
}
|
|
552
|
+
return `${ind}-\n${printSeqBlock(v, indent + 2)}`;
|
|
553
|
+
})
|
|
554
|
+
.join("\n");
|
|
555
|
+
}
|
|
556
|
+
function blockOf(v, indent) {
|
|
557
|
+
if (isObject(v))
|
|
558
|
+
return printMapBlock(v, indent);
|
|
559
|
+
if (Array.isArray(v))
|
|
560
|
+
return printSeqBlock(v, indent);
|
|
561
|
+
return `${" ".repeat(indent)}${inlineScalar(v)}`;
|
|
562
|
+
}
|
|
563
|
+
function rootText(v) {
|
|
564
|
+
if (inlineable(v))
|
|
565
|
+
return inline(v);
|
|
566
|
+
return blockOf(v, 0);
|
|
567
|
+
}
|
|
568
|
+
function print(value) {
|
|
569
|
+
return `${rootText(value)}\n`;
|
|
570
|
+
}
|
|
571
|
+
// -- ops → edits ---------------------------------------------------------------
|
|
572
|
+
function endOfLine(text, pos) {
|
|
573
|
+
const nl = text.indexOf("\n", pos);
|
|
574
|
+
return nl === -1 ? text.length : nl;
|
|
575
|
+
}
|
|
576
|
+
function opToEdit(op, text) {
|
|
577
|
+
switch (op.type) {
|
|
578
|
+
case "replace": {
|
|
579
|
+
const v = op.value;
|
|
580
|
+
const node = op.node;
|
|
581
|
+
// Flow context: stay in flow style.
|
|
582
|
+
const inFlowSeq = op.container?.kind === "array" && op.container.meta.flow;
|
|
583
|
+
const inFlowMap = op.container?.kind === "object" && op.container.meta.flow;
|
|
584
|
+
if (inFlowSeq || inFlowMap) {
|
|
585
|
+
return [{ start: node.start, end: node.end, text: printFlow(v) }];
|
|
586
|
+
}
|
|
587
|
+
// Block map entry value.
|
|
588
|
+
if (op.entry?.meta !== undefined && op.container?.kind === "object") {
|
|
589
|
+
const em = op.entry.meta;
|
|
590
|
+
const nodeFlow = (node.kind === "object" || node.kind === "array") &&
|
|
591
|
+
node.meta.flow;
|
|
592
|
+
if (em.inline && (node.kind === "scalar" || nodeFlow)) {
|
|
593
|
+
if (inlineable(v) || nodeFlow) {
|
|
594
|
+
return [
|
|
595
|
+
{
|
|
596
|
+
start: node.start,
|
|
597
|
+
end: node.end,
|
|
598
|
+
text: nodeFlow && !isScalar(v) ? printFlow(v) : inline(v),
|
|
599
|
+
},
|
|
600
|
+
];
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
const tail = inlineable(v) ? ` ${inline(v)}` : `\n${blockOf(v, em.indent + 2)}`;
|
|
604
|
+
return [{ start: em.colonEnd, end: op.entry.end, text: tail }];
|
|
605
|
+
}
|
|
606
|
+
// Block seq item.
|
|
607
|
+
if (op.container?.kind === "array" && op.index !== undefined) {
|
|
608
|
+
const am = op.container.meta;
|
|
609
|
+
const im = am.itemMeta[op.index];
|
|
610
|
+
if (im === undefined)
|
|
611
|
+
return null;
|
|
612
|
+
if (node.kind === "scalar" && inlineable(v)) {
|
|
613
|
+
return [{ start: node.start, end: node.end, text: inline(v) }];
|
|
614
|
+
}
|
|
615
|
+
if (isObject(v) && Object.keys(v).length > 0) {
|
|
616
|
+
const block = printMapBlock(v, am.indent + 2);
|
|
617
|
+
return [{ start: im.dashEnd, end: node.end, text: ` ${block.slice(am.indent + 2)}` }];
|
|
618
|
+
}
|
|
619
|
+
if (inlineable(v))
|
|
620
|
+
return [{ start: im.dashEnd, end: node.end, text: ` ${inline(v)}` }];
|
|
621
|
+
return [{ start: im.dashEnd, end: node.end, text: `\n${blockOf(v, am.indent + 2)}` }];
|
|
622
|
+
}
|
|
623
|
+
// Root.
|
|
624
|
+
return [{ start: node.start, end: node.end, text: rootText(v) }];
|
|
625
|
+
}
|
|
626
|
+
case "insert": {
|
|
627
|
+
const { obj, key, value } = op;
|
|
628
|
+
const meta = obj.meta;
|
|
629
|
+
if (meta.flow) {
|
|
630
|
+
if (obj.entries.length === 0)
|
|
631
|
+
return null;
|
|
632
|
+
const anchor = (op.after ?? obj.entries[obj.entries.length - 1]).end;
|
|
633
|
+
return [{ start: anchor, end: anchor, text: `, ${pkey(key)}: ${printFlow(value)}` }];
|
|
634
|
+
}
|
|
635
|
+
const anchor = endOfLine(text, op.after?.end ?? obj.end);
|
|
636
|
+
const ind = " ".repeat(meta.indent);
|
|
637
|
+
const tail = inlineable(value) ? ` ${inline(value)}` : `\n${blockOf(value, meta.indent + 2)}`;
|
|
638
|
+
return [{ start: anchor, end: anchor, text: `\n${ind}${pkey(key)}:${tail}` }];
|
|
639
|
+
}
|
|
640
|
+
case "delete": {
|
|
641
|
+
const { obj, entry } = op;
|
|
642
|
+
const meta = obj.meta;
|
|
643
|
+
if (meta.flow) {
|
|
644
|
+
const idx = obj.entries.indexOf(entry);
|
|
645
|
+
const next = obj.entries[idx + 1];
|
|
646
|
+
if (next !== undefined)
|
|
647
|
+
return [{ start: entry.start, end: next.start, text: "" }];
|
|
648
|
+
const prev = obj.entries[idx - 1];
|
|
649
|
+
const start = prev !== undefined ? prev.end : obj.start + 1;
|
|
650
|
+
return [{ start, end: entry.end, text: "" }];
|
|
651
|
+
}
|
|
652
|
+
const em = entry.meta;
|
|
653
|
+
if (em?.compactFirst)
|
|
654
|
+
return null;
|
|
655
|
+
const eol = endOfLine(text, entry.end);
|
|
656
|
+
const end = eol < text.length ? eol + 1 : eol;
|
|
657
|
+
return [{ start: entry.start, end, text: "" }];
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
export const yamlFormat = { name: "YAML", parse, print, opToEdit };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
|
+
/** @group Reactivity */
|
|
2
|
+
/** @group Animation */
|
|
1
3
|
export * from "./animation/index.js";
|
|
4
|
+
/** @group Utilities */
|
|
2
5
|
export * from "./assert/index.js";
|
|
6
|
+
/** @group Rendering */
|
|
3
7
|
export { type CodeOpts, CodeShape, code, codeStyles, type Token, tokenize } from "./code/index.js";
|
|
8
|
+
/** @group Utilities */
|
|
4
9
|
export * from "./coll.js";
|
|
5
10
|
export * from "./core/index.js";
|
|
11
|
+
/** @group Utilities */
|
|
6
12
|
export * from "./ext/index.js";
|
|
13
|
+
/** @group Shapes */
|
|
7
14
|
export * from "./shapes/index.js";
|
|
15
|
+
/** @group Rendering */
|
|
8
16
|
export * from "./tex/index.js";
|
|
17
|
+
/** @group Utilities */
|
|
9
18
|
export { allNodes, atPath, isLeaf, leavesOf, node as treeNode, nodeCount, type TreeNode, walkTree, } from "./tree.js";
|
|
19
|
+
/** @group Web */
|
|
10
20
|
export * from "./web/index.js";
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
|
+
/** @group Reactivity */
|
|
2
|
+
/** @group Animation */
|
|
1
3
|
export * from "./animation/index.js";
|
|
4
|
+
/** @group Utilities */
|
|
2
5
|
export * from "./assert/index.js";
|
|
3
6
|
// `code` and `tex` both export `Part`; re-export `code`'s other symbols
|
|
4
7
|
// explicitly so the wildcard below lets `tex`'s `Part` win.
|
|
8
|
+
/** @group Rendering */
|
|
5
9
|
export { CodeShape, code, codeStyles, tokenize } from "./code/index.js";
|
|
10
|
+
/** @group Utilities */
|
|
6
11
|
export * from "./coll.js";
|
|
7
12
|
export * from "./core/index.js";
|
|
13
|
+
/** @group Utilities */
|
|
8
14
|
export * from "./ext/index.js";
|
|
15
|
+
/** @group Shapes */
|
|
9
16
|
export * from "./shapes/index.js";
|
|
17
|
+
/** @group Rendering */
|
|
10
18
|
export * from "./tex/index.js";
|
|
19
|
+
/** @group Utilities */
|
|
11
20
|
export { allNodes, atPath, isLeaf, leavesOf, node as treeNode, nodeCount, walkTree, } from "./tree.js";
|
|
21
|
+
/** @group Web */
|
|
12
22
|
export * from "./web/index.js";
|