@telorun/analyzer 0.57.0 → 0.59.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/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +91 -9
- package/dist/cel-environment.d.ts.map +1 -1
- package/dist/cel-environment.js +6 -3
- package/dist/definition-registry.d.ts +5 -0
- package/dist/definition-registry.d.ts.map +1 -1
- package/dist/definition-registry.js +9 -0
- package/dist/index.d.ts +11 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/invocation-contract.d.ts +58 -13
- package/dist/invocation-contract.d.ts.map +1 -1
- package/dist/invocation-contract.js +123 -46
- package/dist/loaded-types.d.ts +13 -0
- package/dist/loaded-types.d.ts.map +1 -1
- package/dist/manifest-loader.d.ts +8 -1
- package/dist/manifest-loader.d.ts.map +1 -1
- package/dist/manifest-loader.js +33 -6
- package/dist/migrations/driver.d.ts +69 -0
- package/dist/migrations/driver.d.ts.map +1 -0
- package/dist/migrations/driver.js +200 -0
- package/dist/migrations/entries/index.d.ts +3 -0
- package/dist/migrations/entries/index.d.ts.map +1 -0
- package/dist/migrations/entries/index.js +9 -0
- package/dist/migrations/entries/normalize-value-types.json +48 -0
- package/dist/migrations/entries/ref-slot-scalar-type.json +20 -0
- package/dist/migrations/entry-data.d.ts +25 -0
- package/dist/migrations/entry-data.d.ts.map +1 -0
- package/dist/migrations/entry-data.js +171 -0
- package/dist/migrations/index.d.ts +22 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +19 -0
- package/dist/migrations/match.d.ts +162 -0
- package/dist/migrations/match.d.ts.map +1 -0
- package/dist/migrations/match.js +295 -0
- package/dist/migrations/patch.d.ts +68 -0
- package/dist/migrations/patch.d.ts.map +1 -0
- package/dist/migrations/patch.js +236 -0
- package/dist/migrations/provenance.d.ts +25 -0
- package/dist/migrations/provenance.d.ts.map +1 -0
- package/dist/migrations/provenance.js +118 -0
- package/dist/migrations/registry.d.ts +35 -0
- package/dist/migrations/registry.d.ts.map +1 -0
- package/dist/migrations/registry.js +35 -0
- package/dist/migrations/report.d.ts +28 -0
- package/dist/migrations/report.d.ts.map +1 -0
- package/dist/migrations/report.js +144 -0
- package/dist/migrations/types.d.ts +115 -0
- package/dist/migrations/types.d.ts.map +1 -0
- package/dist/migrations/types.js +24 -0
- package/dist/migrations/yaml-edit.d.ts +21 -0
- package/dist/migrations/yaml-edit.d.ts.map +1 -0
- package/dist/migrations/yaml-edit.js +245 -0
- package/dist/parse-loaded-file.d.ts +8 -0
- package/dist/parse-loaded-file.d.ts.map +1 -1
- package/dist/parse-loaded-file.js +22 -13
- package/dist/resolve-schema-type-refs.d.ts +29 -12
- package/dist/resolve-schema-type-refs.d.ts.map +1 -1
- package/dist/resolve-schema-type-refs.js +89 -16
- package/dist/schema-compat.d.ts +53 -9
- package/dist/schema-compat.d.ts.map +1 -1
- package/dist/schema-compat.js +245 -66
- package/dist/schema-region.d.ts +33 -0
- package/dist/schema-region.d.ts.map +1 -0
- package/dist/schema-region.js +45 -0
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/validate-cel-context.d.ts.map +1 -1
- package/dist/validate-cel-context.js +97 -15
- package/dist/validate-step-inputs.d.ts +8 -1
- package/dist/validate-step-inputs.d.ts.map +1 -1
- package/dist/validate-step-inputs.js +47 -2
- package/dist/validate-value-type-slots.d.ts +43 -0
- package/dist/validate-value-type-slots.d.ts.map +1 -0
- package/dist/validate-value-type-slots.js +142 -0
- package/dist/value-type-keyword.d.ts +60 -0
- package/dist/value-type-keyword.d.ts.map +1 -0
- package/dist/value-type-keyword.js +119 -0
- package/dist/yaml-source-edit.d.ts +56 -0
- package/dist/yaml-source-edit.d.ts.map +1 -0
- package/dist/yaml-source-edit.js +93 -0
- package/package.json +3 -3
- package/src/analyzer.ts +99 -6
- package/src/cel-environment.ts +6 -3
- package/src/definition-registry.ts +10 -0
- package/src/index.ts +34 -3
- package/src/invocation-contract.ts +134 -48
- package/src/loaded-types.ts +13 -0
- package/src/manifest-loader.ts +37 -6
- package/src/migrations/driver.ts +262 -0
- package/src/migrations/entries/index.ts +10 -0
- package/src/migrations/entries/normalize-value-types.json +48 -0
- package/src/migrations/entries/ref-slot-scalar-type.json +20 -0
- package/src/migrations/entry-data.ts +207 -0
- package/src/migrations/index.ts +22 -0
- package/src/migrations/match.ts +382 -0
- package/src/migrations/patch.ts +265 -0
- package/src/migrations/provenance.ts +167 -0
- package/src/migrations/registry.ts +40 -0
- package/src/migrations/report.ts +169 -0
- package/src/migrations/types.ts +144 -0
- package/src/migrations/yaml-edit.ts +260 -0
- package/src/parse-loaded-file.ts +31 -12
- package/src/resolve-schema-type-refs.ts +93 -16
- package/src/schema-compat.ts +277 -75
- package/src/schema-region.ts +46 -0
- package/src/types.ts +17 -0
- package/src/validate-cel-context.ts +117 -15
- package/src/validate-step-inputs.ts +56 -1
- package/src/validate-value-type-slots.ts +182 -0
- package/src/value-type-keyword.ts +135 -0
- package/src/yaml-source-edit.ts +106 -0
- package/dist/binary-slot.d.ts +0 -39
- package/dist/binary-slot.d.ts.map +0 -1
- package/dist/binary-slot.js +0 -58
- package/src/binary-slot.ts +0 -71
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/** Writing a value back into YAML SOURCE — the two primitives every in-place
|
|
2
|
+
* repair is built from, and the one place their rules are stated.
|
|
3
|
+
*
|
|
4
|
+
* A repair is a byte splice over the author's own text, never
|
|
5
|
+
* `Document.toString()`: re-serializing re-folds block scalars, drops
|
|
6
|
+
* quote-style hints and reflows long strings, so a one-key edit would arrive
|
|
7
|
+
* as a whole-file diff. That leaves two questions every writer has to answer
|
|
8
|
+
* identically — how a value is re-quoted to occupy a span, and how overlapping
|
|
9
|
+
* spans are spliced — and three surfaces asking them: the editors' quick fix
|
|
10
|
+
* (`@telorun/ide-support`), `telo migrate` (the migration driver), and
|
|
11
|
+
* `telo upgrade`'s pin rewrite.
|
|
12
|
+
*
|
|
13
|
+
* They live HERE, in the lowest package of the three, because they are pure
|
|
14
|
+
* string work with no Node dependency and because a copy per surface is a
|
|
15
|
+
* silent-divergence risk of exactly the kind Telo's cross-cutting primitives
|
|
16
|
+
* rule exists to prevent: two writers editing the same file from two copies of
|
|
17
|
+
* a subtle quoting rule will eventually quote one value two ways, and nothing
|
|
18
|
+
* would catch it. Same precedent as `ref-slot.ts` / `binary-slot.ts` — a rule
|
|
19
|
+
* several surfaces must agree on gets one reader. */
|
|
20
|
+
|
|
21
|
+
/** Characters that make a plain (unquoted) YAML scalar reparse as something
|
|
22
|
+
* else. `-` and `?` are indicators only when followed by a space, so they are
|
|
23
|
+
* handled by the leading-token check rather than listed here. */
|
|
24
|
+
const PLAIN_UNSAFE_LEAD = new Set([
|
|
25
|
+
"&", "*", "!", "|", ">", "%", "@", "`", "#", "'", '"', "{", "[", "}", "]", ",",
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
/** Whether `value` can be written as a plain scalar without changing meaning. */
|
|
29
|
+
export function isPlainSafe(value: string): boolean {
|
|
30
|
+
if (value === "" || value.trim() !== value) return false;
|
|
31
|
+
if (PLAIN_UNSAFE_LEAD.has(value[0]!)) return false;
|
|
32
|
+
// `-`/`?`/`:` lead only matter when a space follows — `-x` is a scalar,
|
|
33
|
+
// `- x` is a sequence entry.
|
|
34
|
+
if (/^[-?:]\s/.test(value)) return false;
|
|
35
|
+
// A colon-space anywhere opens a mapping; a space-hash opens a comment.
|
|
36
|
+
if (value.includes(": ") || value.includes(" #")) return false;
|
|
37
|
+
if (value.endsWith(":")) return false;
|
|
38
|
+
return !/[\n\r]/.test(value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Quote style of the source text a repair is replacing. */
|
|
42
|
+
export type QuoteStyle = "double" | "single" | "plain";
|
|
43
|
+
|
|
44
|
+
export function quoteStyleOf(source: string): QuoteStyle {
|
|
45
|
+
if (source.length >= 2 && source.startsWith('"') && source.endsWith('"')) return "double";
|
|
46
|
+
if (source.length >= 2 && source.startsWith("'") && source.endsWith("'")) return "single";
|
|
47
|
+
return "plain";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Render `replacement` so it occupies `originalSource`'s span as the same
|
|
51
|
+
* scalar the author would have written by hand, or `undefined` when the span
|
|
52
|
+
* cannot be rewritten safely.
|
|
53
|
+
*
|
|
54
|
+
* A plain original is kept plain when it can be — rewriting `Run.Sequenc` to
|
|
55
|
+
* `"Run.Sequence"` would be a correct but noisy diff on a kind name — and
|
|
56
|
+
* promoted to double quotes when the new value would not survive unquoted.
|
|
57
|
+
*
|
|
58
|
+
* **A multi-line span is refused.** A block scalar's span covers its `|`/`>-`
|
|
59
|
+
* indicator AND its trailing newline, so writing a single-line scalar over it
|
|
60
|
+
* deletes the line break that ended the mapping entry and glues the next key
|
|
61
|
+
* onto the value — the document stops parsing. Re-emitting a block scalar
|
|
62
|
+
* correctly needs the node's indentation, which no consumer of this function
|
|
63
|
+
* has. A multi-line REPLACEMENT is refused for the mirror reason: its
|
|
64
|
+
* continuation lines would land at column 0, which is not a legal mapping
|
|
65
|
+
* value. A quick fix promises a repair that can be applied without review, so
|
|
66
|
+
* the only honest answer for these is no repair. */
|
|
67
|
+
export function renderFixReplacement(
|
|
68
|
+
originalSource: string,
|
|
69
|
+
replacement: string,
|
|
70
|
+
): string | undefined {
|
|
71
|
+
if (/[\n\r]/.test(originalSource) || /[\n\r]/.test(replacement)) return undefined;
|
|
72
|
+
const style = quoteStyleOf(originalSource);
|
|
73
|
+
|
|
74
|
+
if (style === "single") {
|
|
75
|
+
// A single-quoted YAML scalar escapes only the quote, by doubling it. CEL
|
|
76
|
+
// string literals use single quotes constantly, so this is the common case
|
|
77
|
+
// for an expression written in a single-quoted scalar.
|
|
78
|
+
return `'${replacement.replaceAll("'", "''")}'`;
|
|
79
|
+
}
|
|
80
|
+
if (style === "double" || !isPlainSafe(replacement)) {
|
|
81
|
+
return `"${replacement.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
|
|
82
|
+
}
|
|
83
|
+
return replacement;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** A splice over a source file: replace `[start, end)` with `newText`. An empty
|
|
87
|
+
* span is a pure insertion. */
|
|
88
|
+
export interface TextEdit {
|
|
89
|
+
/** Byte offset of the first replaced character (inclusive). */
|
|
90
|
+
readonly start: number;
|
|
91
|
+
/** Byte offset one past the last replaced character. */
|
|
92
|
+
readonly end: number;
|
|
93
|
+
readonly newText: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Splice `edits` into `text`, right to left so earlier offsets stay valid.
|
|
97
|
+
* Callers are responsible for edits not overlapping; two splices contending
|
|
98
|
+
* for the same bytes cannot both be honoured, and this does not arbitrate. */
|
|
99
|
+
export function applyTextEdits(text: string, edits: readonly TextEdit[]): string {
|
|
100
|
+
if (edits.length === 0) return text;
|
|
101
|
+
let out = text;
|
|
102
|
+
for (const edit of [...edits].sort((a, b) => b.start - a.start)) {
|
|
103
|
+
out = out.slice(0, edit.start) + edit.newText + out.slice(edit.end);
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
package/dist/binary-slot.d.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type { KeywordDefinition } from "ajv";
|
|
2
|
-
/**
|
|
3
|
-
* `x-telo-binary: true` — the annotation that gives a byte buffer a declared
|
|
4
|
-
* identity, and the single accessor every surface reads it through (the
|
|
5
|
-
* `ref-slot.ts` precedent).
|
|
6
|
-
*
|
|
7
|
-
* WHY AN ANNOTATION RATHER THAN A TYPE. Bytes are not expressible in JSON
|
|
8
|
-
* Schema's type vocabulary. `type: object` is the closest fit and it is a lie
|
|
9
|
-
* that costs a real check: every arbitrary object satisfies it, so a mistyped
|
|
10
|
-
* `content: { foo: bar }` reaches the controller instead of failing statically.
|
|
11
|
-
* `type: binary` would fix the honesty and break everything else — AJV refuses
|
|
12
|
-
* to compile an unknown type at all (`type must be JSONType or JSONType[]`),
|
|
13
|
-
* with no option to allow it, so the schema would produce no validator; and a
|
|
14
|
-
* published `telo.yaml` would stop being JSON Schema, which is what the hub, the
|
|
15
|
-
* editor and any third-party reader consume. An `x-` keyword is ignored by
|
|
16
|
-
* unaware tooling BY SPECIFICATION, so it degrades to "unconstrained" rather
|
|
17
|
-
* than to "cannot validate this kind at all".
|
|
18
|
-
*
|
|
19
|
-
* ONE RULE, BOTH HALVES. The keyword is implemented as AJV CODEGEN rather than a
|
|
20
|
-
* `validate` function so it inlines into standalone-compiled validators — the
|
|
21
|
-
* kernel compiles and caches those, and a function-valued keyword would not
|
|
22
|
-
* survive serialization. The analyzer registers the identical keyword, and
|
|
23
|
-
* `celPlaceholderForSchema` hands a real `Uint8Array` to a CEL leaf at a binary
|
|
24
|
-
* slot, so static and runtime agree by construction instead of by two rules kept
|
|
25
|
-
* in step. What falls out is the check the annotation exists for: **bytes can
|
|
26
|
-
* never be manifest-authored** — no YAML literal is a `Uint8Array` — so a literal
|
|
27
|
-
* at a binary slot is rejected while a value arriving by reference passes.
|
|
28
|
-
*/
|
|
29
|
-
export declare const X_TELO_BINARY = "x-telo-binary";
|
|
30
|
-
/** True when this schema node declares its value to be raw bytes. */
|
|
31
|
-
export declare function isBinarySlot(schema: unknown): boolean;
|
|
32
|
-
/**
|
|
33
|
-
* The AJV keyword. `Uint8Array` is the structural test rather than any richer
|
|
34
|
-
* notion of "binary": it is what every byte producer in the runtime hands over
|
|
35
|
-
* (`Buffer` extends it, so Node buffers pass), and it is the one check that means
|
|
36
|
-
* the same thing in a browser-side analyzer and in the kernel.
|
|
37
|
-
*/
|
|
38
|
-
export declare function binaryKeyword(): KeywordDefinition;
|
|
39
|
-
//# sourceMappingURL=binary-slot.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"binary-slot.d.ts","sourceRoot":"","sources":["../src/binary-slot.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,KAAK,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAE7C,qEAAqE;AACrE,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAMrD;AAWD;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,iBAAiB,CAajD"}
|
package/dist/binary-slot.js
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import * as AjvNS from "ajv";
|
|
2
|
-
/**
|
|
3
|
-
* `x-telo-binary: true` — the annotation that gives a byte buffer a declared
|
|
4
|
-
* identity, and the single accessor every surface reads it through (the
|
|
5
|
-
* `ref-slot.ts` precedent).
|
|
6
|
-
*
|
|
7
|
-
* WHY AN ANNOTATION RATHER THAN A TYPE. Bytes are not expressible in JSON
|
|
8
|
-
* Schema's type vocabulary. `type: object` is the closest fit and it is a lie
|
|
9
|
-
* that costs a real check: every arbitrary object satisfies it, so a mistyped
|
|
10
|
-
* `content: { foo: bar }` reaches the controller instead of failing statically.
|
|
11
|
-
* `type: binary` would fix the honesty and break everything else — AJV refuses
|
|
12
|
-
* to compile an unknown type at all (`type must be JSONType or JSONType[]`),
|
|
13
|
-
* with no option to allow it, so the schema would produce no validator; and a
|
|
14
|
-
* published `telo.yaml` would stop being JSON Schema, which is what the hub, the
|
|
15
|
-
* editor and any third-party reader consume. An `x-` keyword is ignored by
|
|
16
|
-
* unaware tooling BY SPECIFICATION, so it degrades to "unconstrained" rather
|
|
17
|
-
* than to "cannot validate this kind at all".
|
|
18
|
-
*
|
|
19
|
-
* ONE RULE, BOTH HALVES. The keyword is implemented as AJV CODEGEN rather than a
|
|
20
|
-
* `validate` function so it inlines into standalone-compiled validators — the
|
|
21
|
-
* kernel compiles and caches those, and a function-valued keyword would not
|
|
22
|
-
* survive serialization. The analyzer registers the identical keyword, and
|
|
23
|
-
* `celPlaceholderForSchema` hands a real `Uint8Array` to a CEL leaf at a binary
|
|
24
|
-
* slot, so static and runtime agree by construction instead of by two rules kept
|
|
25
|
-
* in step. What falls out is the check the annotation exists for: **bytes can
|
|
26
|
-
* never be manifest-authored** — no YAML literal is a `Uint8Array` — so a literal
|
|
27
|
-
* at a binary slot is rejected while a value arriving by reference passes.
|
|
28
|
-
*/
|
|
29
|
-
export const X_TELO_BINARY = "x-telo-binary";
|
|
30
|
-
/** True when this schema node declares its value to be raw bytes. */
|
|
31
|
-
export function isBinarySlot(schema) {
|
|
32
|
-
return (typeof schema === "object" &&
|
|
33
|
-
schema !== null &&
|
|
34
|
-
schema[X_TELO_BINARY] === true);
|
|
35
|
-
}
|
|
36
|
-
const ajvExports = AjvNS.default ?? AjvNS;
|
|
37
|
-
const codegen = ajvExports._ ?? AjvNS._;
|
|
38
|
-
/**
|
|
39
|
-
* The AJV keyword. `Uint8Array` is the structural test rather than any richer
|
|
40
|
-
* notion of "binary": it is what every byte producer in the runtime hands over
|
|
41
|
-
* (`Buffer` extends it, so Node buffers pass), and it is the one check that means
|
|
42
|
-
* the same thing in a browser-side analyzer and in the kernel.
|
|
43
|
-
*/
|
|
44
|
-
export function binaryKeyword() {
|
|
45
|
-
return {
|
|
46
|
-
keyword: X_TELO_BINARY,
|
|
47
|
-
schemaType: "boolean",
|
|
48
|
-
code(cxt) {
|
|
49
|
-
// `x-telo-binary: false` states nothing, so it constrains nothing.
|
|
50
|
-
if (cxt.schema !== true)
|
|
51
|
-
return;
|
|
52
|
-
cxt.pass(codegen `${cxt.data} instanceof Uint8Array`);
|
|
53
|
-
},
|
|
54
|
-
error: {
|
|
55
|
-
message: "must be raw bytes (a Uint8Array) — bytes cannot be written inline in a manifest",
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
}
|
package/src/binary-slot.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import * as AjvNS from "ajv";
|
|
2
|
-
import type { KeywordDefinition } from "ajv";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* `x-telo-binary: true` — the annotation that gives a byte buffer a declared
|
|
6
|
-
* identity, and the single accessor every surface reads it through (the
|
|
7
|
-
* `ref-slot.ts` precedent).
|
|
8
|
-
*
|
|
9
|
-
* WHY AN ANNOTATION RATHER THAN A TYPE. Bytes are not expressible in JSON
|
|
10
|
-
* Schema's type vocabulary. `type: object` is the closest fit and it is a lie
|
|
11
|
-
* that costs a real check: every arbitrary object satisfies it, so a mistyped
|
|
12
|
-
* `content: { foo: bar }` reaches the controller instead of failing statically.
|
|
13
|
-
* `type: binary` would fix the honesty and break everything else — AJV refuses
|
|
14
|
-
* to compile an unknown type at all (`type must be JSONType or JSONType[]`),
|
|
15
|
-
* with no option to allow it, so the schema would produce no validator; and a
|
|
16
|
-
* published `telo.yaml` would stop being JSON Schema, which is what the hub, the
|
|
17
|
-
* editor and any third-party reader consume. An `x-` keyword is ignored by
|
|
18
|
-
* unaware tooling BY SPECIFICATION, so it degrades to "unconstrained" rather
|
|
19
|
-
* than to "cannot validate this kind at all".
|
|
20
|
-
*
|
|
21
|
-
* ONE RULE, BOTH HALVES. The keyword is implemented as AJV CODEGEN rather than a
|
|
22
|
-
* `validate` function so it inlines into standalone-compiled validators — the
|
|
23
|
-
* kernel compiles and caches those, and a function-valued keyword would not
|
|
24
|
-
* survive serialization. The analyzer registers the identical keyword, and
|
|
25
|
-
* `celPlaceholderForSchema` hands a real `Uint8Array` to a CEL leaf at a binary
|
|
26
|
-
* slot, so static and runtime agree by construction instead of by two rules kept
|
|
27
|
-
* in step. What falls out is the check the annotation exists for: **bytes can
|
|
28
|
-
* never be manifest-authored** — no YAML literal is a `Uint8Array` — so a literal
|
|
29
|
-
* at a binary slot is rejected while a value arriving by reference passes.
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
export const X_TELO_BINARY = "x-telo-binary";
|
|
33
|
-
|
|
34
|
-
/** True when this schema node declares its value to be raw bytes. */
|
|
35
|
-
export function isBinarySlot(schema: unknown): boolean {
|
|
36
|
-
return (
|
|
37
|
-
typeof schema === "object" &&
|
|
38
|
-
schema !== null &&
|
|
39
|
-
(schema as Record<string, unknown>)[X_TELO_BINARY] === true
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// AJV's codegen template tag. The package is consumed in both ESM and CJS interop
|
|
44
|
-
// shapes, so the named export may sit on the namespace or behind `.default` —
|
|
45
|
-
// the same fallback `schema-compat` uses to reach the constructor. Skipping it
|
|
46
|
-
// would leave `codegen` undefined under a loader that does not detect AJV's named
|
|
47
|
-
// CJS re-exports, and the keyword would throw on its first compile.
|
|
48
|
-
type CodegenTag = (s: TemplateStringsArray, ...a: unknown[]) => unknown;
|
|
49
|
-
const ajvExports = (AjvNS as any).default ?? AjvNS;
|
|
50
|
-
const codegen: CodegenTag = ajvExports._ ?? (AjvNS as any)._;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* The AJV keyword. `Uint8Array` is the structural test rather than any richer
|
|
54
|
-
* notion of "binary": it is what every byte producer in the runtime hands over
|
|
55
|
-
* (`Buffer` extends it, so Node buffers pass), and it is the one check that means
|
|
56
|
-
* the same thing in a browser-side analyzer and in the kernel.
|
|
57
|
-
*/
|
|
58
|
-
export function binaryKeyword(): KeywordDefinition {
|
|
59
|
-
return {
|
|
60
|
-
keyword: X_TELO_BINARY,
|
|
61
|
-
schemaType: "boolean",
|
|
62
|
-
code(cxt: any) {
|
|
63
|
-
// `x-telo-binary: false` states nothing, so it constrains nothing.
|
|
64
|
-
if (cxt.schema !== true) return;
|
|
65
|
-
cxt.pass(codegen`${cxt.data} instanceof Uint8Array`);
|
|
66
|
-
},
|
|
67
|
-
error: {
|
|
68
|
-
message: "must be raw bytes (a Uint8Array) — bytes cannot be written inline in a manifest",
|
|
69
|
-
},
|
|
70
|
-
} as KeywordDefinition;
|
|
71
|
-
}
|