@reventlessdev/reventless-spec 3.0.0-alpha.127 → 3.0.0-alpha.129
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 +52 -0
- package/package.json +2 -2
- package/schema/platform-api.graphql +1 -0
- package/src/AnsiStyle.res +31 -7
- package/src/AnsiStyle.res.mjs +16 -2
- package/src/components/Plugin.res +66 -84
- package/src/components/Plugin.res.mjs +46 -81
- package/src/components/Sensitive.res +137 -0
- package/src/components/Sensitive.res.mjs +74 -0
- package/src/generator/GraftTrait.res +5 -4
- package/src/generator/GraftTrait.res.mjs +4 -4
- package/src/semantic/Bytes.res +21 -21
- package/src/semantic/Bytes.res.mjs +35 -0
- package/src/semantic/CaptionedImage.res +100 -0
- package/src/semantic/CaptionedImage.res.mjs +35 -0
- package/src/semantic/Duration.res +22 -24
- package/src/semantic/Duration.res.mjs +43 -0
- package/src/semantic/MemberRef.res +119 -0
- package/src/semantic/MemberRef.res.mjs +57 -0
- package/src/semantic/Offload.res.mjs +2 -2
- package/src/semantic/Percent.res +9 -20
- package/src/semantic/Percent.res.mjs +5 -0
- package/src/semantic/Semantic.res +63 -0
- package/src/semantic/Semantic.res.mjs +39 -0
- package/src/semantic/StorageRef.res.mjs +1 -1
- package/src/semantic/Template.res +412 -0
- package/src/semantic/Template.res.mjs +545 -0
- package/src/types/Message.res +14 -12
- package/src/types/Message.res.mjs +2 -1
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
5
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
|
+
import * as Stdlib_Result from "@rescript/runtime/lib/es6/Stdlib_Result.js";
|
|
7
|
+
import * as Bytes$Reventless from "./Bytes.res.mjs";
|
|
8
|
+
import * as Money$Reventless from "./Money.res.mjs";
|
|
9
|
+
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
10
|
+
import * as Percent$Reventless from "./Percent.res.mjs";
|
|
11
|
+
import * as Duration$Reventless from "./Duration.res.mjs";
|
|
12
|
+
import * as GeoPoint$Reventless from "./GeoPoint.res.mjs";
|
|
13
|
+
import * as Semantic$Reventless from "./Semantic.res.mjs";
|
|
14
|
+
import * as DateRange$Reventless from "./DateRange.res.mjs";
|
|
15
|
+
import * as Sensitive$Reventless from "../components/Sensitive.res.mjs";
|
|
16
|
+
|
|
17
|
+
let rawFormatter = "raw";
|
|
18
|
+
|
|
19
|
+
let formatters = [
|
|
20
|
+
rawFormatter,
|
|
21
|
+
Semantic$Reventless.Id.money,
|
|
22
|
+
Semantic$Reventless.Id.percent,
|
|
23
|
+
Semantic$Reventless.Id.bytes,
|
|
24
|
+
Semantic$Reventless.Id.duration,
|
|
25
|
+
Semantic$Reventless.Id.dateRange,
|
|
26
|
+
Semantic$Reventless.Id.geoPoint
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
let segmentGrammar = /^[A-Za-z0-9_]+$/;
|
|
30
|
+
|
|
31
|
+
let whitespace = /\s+/g;
|
|
32
|
+
|
|
33
|
+
function parsePath(raw, insideEach) {
|
|
34
|
+
let text = raw.trim();
|
|
35
|
+
if (text === "") {
|
|
36
|
+
return {
|
|
37
|
+
TAG: "Error",
|
|
38
|
+
_0: "a tag with no path"
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
let relative = text.startsWith(".");
|
|
42
|
+
if (relative && !insideEach) {
|
|
43
|
+
return {
|
|
44
|
+
TAG: "Error",
|
|
45
|
+
_0: `"` + text + `" is item-relative, and there is no item outside an "each"`
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
let body = relative ? text.slice(1) : text;
|
|
49
|
+
let segments = body === "" ? [] : body.split(".");
|
|
50
|
+
if (segments.every(segment => segmentGrammar.test(segment))) {
|
|
51
|
+
return {
|
|
52
|
+
TAG: "Ok",
|
|
53
|
+
_0: {
|
|
54
|
+
text: text,
|
|
55
|
+
relative: relative,
|
|
56
|
+
segments: segments
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
} else {
|
|
60
|
+
return {
|
|
61
|
+
TAG: "Error",
|
|
62
|
+
_0: `"` + text + `" is not a path — segments are letters, digits and underscores, separated by dots`
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function tokenize(source) {
|
|
68
|
+
let tokens = [];
|
|
69
|
+
let rest = source;
|
|
70
|
+
let failure;
|
|
71
|
+
let running = true;
|
|
72
|
+
while (running) {
|
|
73
|
+
let current = rest;
|
|
74
|
+
let start = current.indexOf("{{");
|
|
75
|
+
if (start !== -1) {
|
|
76
|
+
let before = current.slice(0, start);
|
|
77
|
+
if (before !== "") {
|
|
78
|
+
tokens.push({
|
|
79
|
+
TAG: "TextToken",
|
|
80
|
+
_0: before
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
let after = current.slice(start + 2 | 0);
|
|
84
|
+
let stop = after.indexOf("}}");
|
|
85
|
+
if (stop !== -1) {
|
|
86
|
+
tokens.push({
|
|
87
|
+
TAG: "TagToken",
|
|
88
|
+
_0: after.slice(0, stop).replace(whitespace, " ").trim()
|
|
89
|
+
});
|
|
90
|
+
rest = after.slice(stop + 2 | 0);
|
|
91
|
+
} else {
|
|
92
|
+
failure = `an opening "{{" with no closing "}}"`;
|
|
93
|
+
running = false;
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
if (current !== "") {
|
|
97
|
+
tokens.push({
|
|
98
|
+
TAG: "TextToken",
|
|
99
|
+
_0: current
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
running = false;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
let message = failure;
|
|
106
|
+
if (message !== undefined) {
|
|
107
|
+
return {
|
|
108
|
+
TAG: "Error",
|
|
109
|
+
_0: message
|
|
110
|
+
};
|
|
111
|
+
} else {
|
|
112
|
+
return {
|
|
113
|
+
TAG: "Ok",
|
|
114
|
+
_0: tokens
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function blockWord(kind) {
|
|
120
|
+
if (kind === "IfBlock") {
|
|
121
|
+
return "if";
|
|
122
|
+
} else {
|
|
123
|
+
return "each";
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function parse(source) {
|
|
128
|
+
let message = tokenize(source);
|
|
129
|
+
if (message.TAG !== "Ok") {
|
|
130
|
+
return {
|
|
131
|
+
TAG: "Error",
|
|
132
|
+
_0: message._0
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
let root = [];
|
|
136
|
+
let stack = [];
|
|
137
|
+
let failure = {
|
|
138
|
+
contents: undefined
|
|
139
|
+
};
|
|
140
|
+
let fail = message => {
|
|
141
|
+
if (Stdlib_Option.isNone(failure.contents)) {
|
|
142
|
+
failure.contents = message;
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
let body = () => {
|
|
147
|
+
let frame = stack.at(-1);
|
|
148
|
+
if (frame !== undefined) {
|
|
149
|
+
return frame.body;
|
|
150
|
+
} else {
|
|
151
|
+
return root;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
let insideEach = () => stack.some(frame => frame.kind === "EachBlock");
|
|
155
|
+
let addField = (rawPath, formatter) => {
|
|
156
|
+
let message = parsePath(rawPath, insideEach());
|
|
157
|
+
if (message.TAG !== "Ok") {
|
|
158
|
+
return fail(message._0);
|
|
159
|
+
}
|
|
160
|
+
body().push({
|
|
161
|
+
TAG: "Field",
|
|
162
|
+
path: message._0,
|
|
163
|
+
formatter: formatter
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
let openBlock = (kind, rawPath) => {
|
|
167
|
+
if (kind === "EachBlock" && insideEach()) {
|
|
168
|
+
return fail(`an "each" inside an "each" — iteration is one level deep`);
|
|
169
|
+
}
|
|
170
|
+
let message = parsePath(rawPath, insideEach());
|
|
171
|
+
if (message.TAG !== "Ok") {
|
|
172
|
+
return fail(message._0);
|
|
173
|
+
}
|
|
174
|
+
stack.push({
|
|
175
|
+
kind: kind,
|
|
176
|
+
path: message._0,
|
|
177
|
+
body: []
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
message._0.forEach(token => {
|
|
181
|
+
if (!Stdlib_Option.isNone(failure.contents)) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (token.TAG === "TextToken") {
|
|
185
|
+
body().push({
|
|
186
|
+
TAG: "Text",
|
|
187
|
+
_0: token._0
|
|
188
|
+
});
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
let tag = token._0;
|
|
192
|
+
if (tag.startsWith("#")) {
|
|
193
|
+
let rest = tag.slice(1).trim();
|
|
194
|
+
let at = rest.indexOf(" ");
|
|
195
|
+
if (at === -1) {
|
|
196
|
+
return fail(`"{{# ` + rest + ` }}" opens a block with no path`);
|
|
197
|
+
}
|
|
198
|
+
let word = rest.slice(0, at);
|
|
199
|
+
switch (word) {
|
|
200
|
+
case "each" :
|
|
201
|
+
return openBlock("EachBlock", rest.slice(at + 1 | 0));
|
|
202
|
+
case "if" :
|
|
203
|
+
return openBlock("IfBlock", rest.slice(at + 1 | 0));
|
|
204
|
+
default:
|
|
205
|
+
return fail(`"` + word + `" is not a block — "if" and "each" are`);
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
if (tag.startsWith("/")) {
|
|
209
|
+
let word$1 = tag.slice(1).trim();
|
|
210
|
+
let frame = stack.pop();
|
|
211
|
+
if (frame === undefined) {
|
|
212
|
+
return fail(`a closing "{{/ ` + word$1 + ` }}" with nothing open`);
|
|
213
|
+
}
|
|
214
|
+
if (blockWord(frame.kind) !== word$1) {
|
|
215
|
+
return fail(`"{{/ ` + word$1 + ` }}" closes a "` + blockWord(frame.kind) + `"`);
|
|
216
|
+
}
|
|
217
|
+
let match = frame.kind;
|
|
218
|
+
let tmp;
|
|
219
|
+
tmp = match === "IfBlock" ? ({
|
|
220
|
+
TAG: "If",
|
|
221
|
+
path: frame.path,
|
|
222
|
+
body: frame.body
|
|
223
|
+
}) : ({
|
|
224
|
+
TAG: "Each",
|
|
225
|
+
path: frame.path,
|
|
226
|
+
body: frame.body
|
|
227
|
+
});
|
|
228
|
+
body().push(tmp);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
let match$1 = tag.split("|");
|
|
232
|
+
let len = match$1.length;
|
|
233
|
+
if (len >= 3) {
|
|
234
|
+
return fail(`"` + tag + `" names more than one formatter`);
|
|
235
|
+
}
|
|
236
|
+
switch (len) {
|
|
237
|
+
case 0 :
|
|
238
|
+
return fail(`"` + tag + `" names more than one formatter`);
|
|
239
|
+
case 1 :
|
|
240
|
+
let rawPath = match$1[0];
|
|
241
|
+
return addField(rawPath, undefined);
|
|
242
|
+
case 2 :
|
|
243
|
+
let rawPath$1 = match$1[0];
|
|
244
|
+
let name = match$1[1];
|
|
245
|
+
let formatter = name.trim();
|
|
246
|
+
if (formatters.includes(formatter)) {
|
|
247
|
+
return addField(rawPath$1, formatter);
|
|
248
|
+
} else {
|
|
249
|
+
return fail(`"` + formatter + `" is not a formatter — one of ` + formatters.join(", "));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
let message$1 = failure.contents;
|
|
255
|
+
if (message$1 !== undefined) {
|
|
256
|
+
return {
|
|
257
|
+
TAG: "Error",
|
|
258
|
+
_0: message$1
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
let frame = stack.at(-1);
|
|
262
|
+
if (frame !== undefined) {
|
|
263
|
+
return {
|
|
264
|
+
TAG: "Error",
|
|
265
|
+
_0: `"{{# ` + blockWord(frame.kind) + ` ` + frame.path.text + ` }}" was never closed`
|
|
266
|
+
};
|
|
267
|
+
} else {
|
|
268
|
+
return {
|
|
269
|
+
TAG: "Ok",
|
|
270
|
+
_0: root
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
let nothing = {
|
|
276
|
+
value: undefined,
|
|
277
|
+
schema: undefined
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
function missing(path) {
|
|
281
|
+
return `[missing: ` + path.text + `]`;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function withheld(path) {
|
|
285
|
+
return `[withheld: ` + path.text + `]`;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function unwrap(schema) {
|
|
289
|
+
return Stdlib_Option.getOr(Semantic$Reventless.unwrapOptional(schema), schema);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function propertyOf(schema, name) {
|
|
293
|
+
let match = Stdlib_Option.getOr(Semantic$Reventless.unwrapOptional(schema), schema);
|
|
294
|
+
if (match.type === "object") {
|
|
295
|
+
return match.properties[name];
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function elementOf(schema) {
|
|
300
|
+
let match = Stdlib_Option.getOr(Semantic$Reventless.unwrapOptional(schema), schema);
|
|
301
|
+
if (match.type !== "array") {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
let item = match.additionalItems;
|
|
305
|
+
if (item === "strip" || item === "strict") {
|
|
306
|
+
return;
|
|
307
|
+
} else {
|
|
308
|
+
return item;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function step(scope, segment) {
|
|
313
|
+
let match = scope.value;
|
|
314
|
+
let tmp;
|
|
315
|
+
tmp = typeof match === "object" && match !== null && !Array.isArray(match) ? match[segment] : undefined;
|
|
316
|
+
return {
|
|
317
|
+
value: tmp,
|
|
318
|
+
schema: Stdlib_Option.flatMap(scope.schema, __x => propertyOf(__x, segment))
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function resolve(path, root, item) {
|
|
323
|
+
return Stdlib_Array.reduce(path.segments, path.relative ? Stdlib_Option.getOr(item, nothing) : root, step);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function lookup(payload, dotted) {
|
|
327
|
+
return Stdlib_Array.reduce(dotted.split("."), {
|
|
328
|
+
value: payload,
|
|
329
|
+
schema: undefined
|
|
330
|
+
}, step).value;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function isWithheld(schema) {
|
|
334
|
+
if (schema === undefined) {
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
if (Sensitive$Reventless.isFieldSensitive(schema)) {
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
let match = Semantic$Reventless.getFrom(schema);
|
|
341
|
+
if (match !== undefined) {
|
|
342
|
+
return Sensitive$Reventless.impliedBySemantic(match.id);
|
|
343
|
+
} else {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function parseSafely(json, schema) {
|
|
349
|
+
try {
|
|
350
|
+
return Primitive_option.some(S.parseOrThrow(json, schema));
|
|
351
|
+
} catch (exn) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function formatBySemantic(json, id) {
|
|
357
|
+
if (id === Semantic$Reventless.Id.money) {
|
|
358
|
+
return Stdlib_Option.map(parseSafely(json, Money$Reventless.schema), Money$Reventless.format);
|
|
359
|
+
} else if (id === Semantic$Reventless.Id.dateRange) {
|
|
360
|
+
return Stdlib_Option.map(parseSafely(json, DateRange$Reventless.schema), DateRange$Reventless.format);
|
|
361
|
+
} else if (id === Semantic$Reventless.Id.geoPoint) {
|
|
362
|
+
return Stdlib_Option.map(parseSafely(json, GeoPoint$Reventless.schema), GeoPoint$Reventless.format);
|
|
363
|
+
} else if (typeof json === "number") {
|
|
364
|
+
if (id === Semantic$Reventless.Id.percent) {
|
|
365
|
+
return Percent$Reventless.format(json);
|
|
366
|
+
} else if (id === Semantic$Reventless.Id.bytes) {
|
|
367
|
+
return Bytes$Reventless.format(json);
|
|
368
|
+
} else if (id === Semantic$Reventless.Id.duration) {
|
|
369
|
+
return Duration$Reventless.format(json | 0);
|
|
370
|
+
} else {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
} else {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function scalar(value) {
|
|
379
|
+
if (value === null) {
|
|
380
|
+
return "";
|
|
381
|
+
}
|
|
382
|
+
if (Array.isArray(value)) {
|
|
383
|
+
return JSON.stringify(value);
|
|
384
|
+
}
|
|
385
|
+
switch (typeof value) {
|
|
386
|
+
case "boolean" :
|
|
387
|
+
if (value) {
|
|
388
|
+
return "true";
|
|
389
|
+
} else {
|
|
390
|
+
return "false";
|
|
391
|
+
}
|
|
392
|
+
case "string" :
|
|
393
|
+
return value;
|
|
394
|
+
case "number" :
|
|
395
|
+
return value.toString();
|
|
396
|
+
case "object" :
|
|
397
|
+
return JSON.stringify(value);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function truthy(value) {
|
|
402
|
+
if (value === undefined) {
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
if (value === null) {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
if (Array.isArray(value)) {
|
|
409
|
+
return value.length !== 0;
|
|
410
|
+
}
|
|
411
|
+
switch (typeof value) {
|
|
412
|
+
case "boolean" :
|
|
413
|
+
return value;
|
|
414
|
+
case "string" :
|
|
415
|
+
return value !== "";
|
|
416
|
+
case "number" :
|
|
417
|
+
return value !== 0.0;
|
|
418
|
+
case "object" :
|
|
419
|
+
return true;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function renderField(path, formatter, root, item) {
|
|
424
|
+
let scope = resolve(path, root, item);
|
|
425
|
+
if (isWithheld(scope.schema)) {
|
|
426
|
+
return withheld(path);
|
|
427
|
+
}
|
|
428
|
+
let value = scope.value;
|
|
429
|
+
if (value === undefined) {
|
|
430
|
+
return missing(path);
|
|
431
|
+
}
|
|
432
|
+
if (value === null) {
|
|
433
|
+
return missing(path);
|
|
434
|
+
}
|
|
435
|
+
if (formatter !== undefined) {
|
|
436
|
+
if (formatter === rawFormatter) {
|
|
437
|
+
return scalar(value);
|
|
438
|
+
} else {
|
|
439
|
+
return Stdlib_Option.getOr(formatBySemantic(value, formatter), scalar(value));
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
let match = Stdlib_Option.flatMap(scope.schema, Semantic$Reventless.getFrom);
|
|
443
|
+
if (match !== undefined) {
|
|
444
|
+
return Stdlib_Option.getOr(formatBySemantic(value, match.id), scalar(value));
|
|
445
|
+
} else {
|
|
446
|
+
return scalar(value);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function renderNodes(nodes, root, item, out) {
|
|
451
|
+
nodes.forEach(node => {
|
|
452
|
+
switch (node.TAG) {
|
|
453
|
+
case "Text" :
|
|
454
|
+
out.push(node._0);
|
|
455
|
+
return;
|
|
456
|
+
case "Field" :
|
|
457
|
+
out.push(renderField(node.path, node.formatter, root, item));
|
|
458
|
+
return;
|
|
459
|
+
case "If" :
|
|
460
|
+
if (truthy(resolve(node.path, root, item).value)) {
|
|
461
|
+
return renderNodes(node.body, root, item, out);
|
|
462
|
+
} else {
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
case "Each" :
|
|
466
|
+
let body = node.body;
|
|
467
|
+
let path = node.path;
|
|
468
|
+
let scope = resolve(path, root, item);
|
|
469
|
+
if (isWithheld(scope.schema)) {
|
|
470
|
+
out.push(withheld(path));
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
let match = scope.value;
|
|
474
|
+
if (Array.isArray(match)) {
|
|
475
|
+
let element = Stdlib_Option.flatMap(scope.schema, elementOf);
|
|
476
|
+
let total = match.length;
|
|
477
|
+
let shown = total > 100 ? 100 : total;
|
|
478
|
+
for (let index = 0; index < shown; ++index) {
|
|
479
|
+
renderNodes(body, root, {
|
|
480
|
+
value: match[index],
|
|
481
|
+
schema: element
|
|
482
|
+
}, out);
|
|
483
|
+
}
|
|
484
|
+
if (total > shown) {
|
|
485
|
+
out.push(`[… ` + (total - shown | 0).toString() + ` more]`);
|
|
486
|
+
return;
|
|
487
|
+
} else {
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
out.push(missing(path));
|
|
492
|
+
return;
|
|
493
|
+
break;
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function render(template, payload, schema) {
|
|
499
|
+
let out = [];
|
|
500
|
+
renderNodes(template, {
|
|
501
|
+
value: payload,
|
|
502
|
+
schema: schema
|
|
503
|
+
}, undefined, out);
|
|
504
|
+
return out.join("");
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function renderSource(source, payload, schema) {
|
|
508
|
+
return Stdlib_Result.map(parse(source), template => render(template, payload, schema));
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
let variantSchema = Semantic$Reventless.unionVariant;
|
|
512
|
+
|
|
513
|
+
let maxItems = 100;
|
|
514
|
+
|
|
515
|
+
export {
|
|
516
|
+
rawFormatter,
|
|
517
|
+
formatters,
|
|
518
|
+
segmentGrammar,
|
|
519
|
+
whitespace,
|
|
520
|
+
parsePath,
|
|
521
|
+
tokenize,
|
|
522
|
+
blockWord,
|
|
523
|
+
parse,
|
|
524
|
+
nothing,
|
|
525
|
+
missing,
|
|
526
|
+
withheld,
|
|
527
|
+
maxItems,
|
|
528
|
+
unwrap,
|
|
529
|
+
propertyOf,
|
|
530
|
+
elementOf,
|
|
531
|
+
step,
|
|
532
|
+
resolve,
|
|
533
|
+
lookup,
|
|
534
|
+
isWithheld,
|
|
535
|
+
parseSafely,
|
|
536
|
+
formatBySemantic,
|
|
537
|
+
scalar,
|
|
538
|
+
truthy,
|
|
539
|
+
renderField,
|
|
540
|
+
renderNodes,
|
|
541
|
+
render,
|
|
542
|
+
renderSource,
|
|
543
|
+
variantSchema,
|
|
544
|
+
}
|
|
545
|
+
/* S Not a pure module */
|
package/src/types/Message.res
CHANGED
|
@@ -141,22 +141,23 @@ type commandJson = {
|
|
|
141
141
|
|
|
142
142
|
// ── Schema-migration-on-read ──────────────────────────────────────────────────
|
|
143
143
|
// Nested `@schema` types (notably `pluginDefinition`/`pluginStructure`) gain fields
|
|
144
|
-
// over time — `kind`, `chapter`, `events`, `extensionPoints`, `apiExposed`, …
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
// an aggregate that rehydrates from its own event log (the Plugin lifecycle aggregate),
|
|
151
|
-
// that single event then freezes EVERY later heartbeat/redetect/connect on that instance
|
|
152
|
-
// — a silent lifecycle freeze with no error surfaced near the operator.
|
|
144
|
+
// over time — `kind`, `chapter`, `events`, `extensionPoints`, `apiExposed`, … A field
|
|
145
|
+
// that is not optional is *present-required on decode*, so ONE message persisted before
|
|
146
|
+
// it was added SuryError-bricks decode. For an aggregate that rehydrates from its own
|
|
147
|
+
// event log (the Plugin lifecycle aggregate), that single event then freezes EVERY later
|
|
148
|
+
// heartbeat/redetect/connect on that instance — a silent lifecycle freeze with no error
|
|
149
|
+
// surfaced near the operator.
|
|
153
150
|
//
|
|
154
151
|
// We heal on read. Strict decode stays the fast path (unchanged for every current
|
|
155
152
|
// message); only when it throws do we schema-guide the raw JSON and retry once. The fill
|
|
156
153
|
// walks the target sury schema and inserts, for any absent field, the value that field's
|
|
157
|
-
// schema expects: `null` for a `T | null` union (→ `None`),
|
|
154
|
+
// schema expects: `null` for a `T | null` union (→ `None`), nothing at all for an
|
|
155
|
+
// `option` (a union admitting `undefined` — also `None`), `[]` for a missing array, the
|
|
158
156
|
// first variant of a mandatory enum (`kind` → `Domain`), a filled `{}` for a missing
|
|
159
|
-
// nested object, and a zero value for a missing scalar.
|
|
157
|
+
// nested object, and a zero value for a missing scalar. The `undefined` arm mirrors the
|
|
158
|
+
// `null` one and must precede the enum/object guesses below it: an absent `option<enum>`
|
|
159
|
+
// would otherwise heal to that enum's first variant and an absent `option<record>` to a
|
|
160
|
+
// filled `{}`, turning `None` into a `Some` of an invented value. It descends only into values
|
|
160
161
|
// actually present, matches tagged-union members by their `TAG` const, is purely additive
|
|
161
162
|
// (clones via a JSON round-trip; never re-encodes through the schema), is idempotent on
|
|
162
163
|
// valid data, and falls back to the ORIGINAL error when the fill doesn't resolve the
|
|
@@ -229,6 +230,7 @@ let fillMissingDefaults: (S.t<'a>, JSON.t, array<string>) => JSON.t = %raw(`func
|
|
|
229
230
|
var has=schema.has||{};
|
|
230
231
|
if(value===undefined){
|
|
231
232
|
if(has.null) return null;
|
|
233
|
+
if(has.undefined) return undefined;
|
|
232
234
|
var c=firstConst(schema.anyOf); if(c!==undefined) return c;
|
|
233
235
|
var obj=(schema.anyOf||[]).find(function(s){return s.type==="object";}); if(obj) return fill(obj,{},path);
|
|
234
236
|
return undefined;
|
|
@@ -273,7 +275,7 @@ let parseJsonTolerant = (json, schema) =>
|
|
|
273
275
|
->Int.toString} missing scalar field(s): ${scalarFills->Array.join(
|
|
274
276
|
", ",
|
|
275
277
|
)}. A required scalar was added to a persisted type after this message was ` ++
|
|
276
|
-
`written; the value above is fabricated, not recovered. Prefer
|
|
278
|
+
`written; the value above is fabricated, not recovered. Prefer an optional field.`,
|
|
277
279
|
)
|
|
278
280
|
}
|
|
279
281
|
value
|
|
@@ -87,6 +87,7 @@ let fillMissingDefaults = (function(schema, json, scalarFills){
|
|
|
87
87
|
var has=schema.has||{};
|
|
88
88
|
if(value===undefined){
|
|
89
89
|
if(has.null) return null;
|
|
90
|
+
if(has.undefined) return undefined;
|
|
90
91
|
var c=firstConst(schema.anyOf); if(c!==undefined) return c;
|
|
91
92
|
var obj=(schema.anyOf||[]).find(function(s){return s.type==="object";}); if(obj) return fill(obj,{},path);
|
|
92
93
|
return undefined;
|
|
@@ -126,7 +127,7 @@ function parseJsonTolerant(json, schema) {
|
|
|
126
127
|
throw firstErr;
|
|
127
128
|
}
|
|
128
129
|
if (scalarFills.length !== 0) {
|
|
129
|
-
console.warn(`[reventless] decoded a stored message by inventing ` + scalarFills.length.toString() + ` missing scalar field(s): ` + scalarFills.join(", ") + `. A required scalar was added to a persisted type after this message was written; the value above is fabricated, not recovered. Prefer
|
|
130
|
+
console.warn(`[reventless] decoded a stored message by inventing ` + scalarFills.length.toString() + ` missing scalar field(s): ` + scalarFills.join(", ") + `. A required scalar was added to a persisted type after this message was written; the value above is fabricated, not recovered. Prefer an optional field.`);
|
|
130
131
|
}
|
|
131
132
|
return value;
|
|
132
133
|
}
|