@benjamolina/pi-antigravity-guard 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/catalog.d.ts +16 -13
- package/dist/catalog.js +9 -8
- package/dist/context.js +1 -1
- package/dist/tool-context.d.ts +1 -1
- package/dist/tool-context.js +4 -1
- package/dist/tool-schema.js +161 -74
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ All seven rows below are registered for text. The exact `antigravity-gemini-3.8-
|
|
|
18
18
|
|
|
19
19
|
| Public ID | Exposed Pi levels | Tool state | Admission |
|
|
20
20
|
|---|---|---|---|
|
|
21
|
-
| `antigravity-gemini-3.8-flash` | off, low, medium, high | Enabled (off) | pi-json-tool-loop/gemini-3.8-flash-off-v1 |
|
|
21
|
+
| `antigravity-gemini-3.8-flash` | off, low, medium, high | Enabled (off, low, medium, high) | pi-json-tool-loop/gemini-3.8-flash-off-v1 |
|
|
22
22
|
| `antigravity-gemini-3.7-flash` | off, low, medium, high | Disabled | missing-direct-evidence |
|
|
23
23
|
| `antigravity-gemini-3.6-flash` | off, low, medium, high | Disabled | missing-direct-evidence |
|
|
24
24
|
| `antigravity-gemini-3.1-pro` | off, low, high | Disabled | missing-direct-evidence |
|
|
@@ -38,7 +38,7 @@ Maintainers can run `npm run build:pi` followed by `npx tsx scripts/pi-tool-loop
|
|
|
38
38
|
|
|
39
39
|
Tool-bearing requests are never silently downgraded to text. When an exact route is eventually enabled, declarations are retained in order and omitted or `auto` choice serializes as `AUTO`; explicit `none` serializes as `NONE`. Forced, required, named, unknown, and constrained-sampling choices are rejected before transport.
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Only the evidence-enabled Gemini 3.8 Flash `off` route uses the `parametersJsonSchema` profile. Its hermetically verified preflight preserves ordinary JSON Schema constraints and JSON values in canonical immutable output, including safe local RFC 6901 `$ref` expansion (`#` and `#/...`) with resolved definitions removed. External, malformed, unresolved, cyclic, or otherwise unsafe references fail closed before transport. This is local serialization and safety evidence, not direct live backend acceptance of constrained or reference-based schemas. Tool results must match the exact call ID and name, remain text-only, and are replayed in assistant source-call order; image-bearing or ambiguous results are rejected. A missing persisted result uses the documented failed response only during context reconstruction.
|
|
42
42
|
|
|
43
43
|
## Text catalog limits and safety
|
|
44
44
|
|
package/dist/catalog.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export interface ToolEvidenceRef {
|
|
|
7
7
|
readonly reasoning: StandardReasoningLevel;
|
|
8
8
|
readonly wireModel: string;
|
|
9
9
|
}
|
|
10
|
+
export declare const GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE: "gemini-parameters-json-schema";
|
|
11
|
+
export type ToolSchemaProfile = typeof GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE;
|
|
10
12
|
export type ToolCapability = {
|
|
11
13
|
readonly state: "disabled";
|
|
12
14
|
readonly contractRevision: 1;
|
|
@@ -18,6 +20,7 @@ export type ToolCapability = {
|
|
|
18
20
|
} | {
|
|
19
21
|
readonly state: "enabled";
|
|
20
22
|
readonly contractRevision: 1;
|
|
23
|
+
readonly schemaProfile: ToolSchemaProfile;
|
|
21
24
|
readonly fixtureEvidence: ToolEvidenceRef;
|
|
22
25
|
readonly directEvidence: ToolEvidenceRef;
|
|
23
26
|
};
|
|
@@ -75,37 +78,37 @@ declare const CATALOG: readonly [{
|
|
|
75
78
|
};
|
|
76
79
|
readonly routes: {
|
|
77
80
|
readonly off: {
|
|
78
|
-
readonly wireModel: "gemini-3.8-flash-
|
|
81
|
+
readonly wireModel: "gemini-3.8-flash-low";
|
|
79
82
|
readonly thinking: {
|
|
80
|
-
readonly kind: "
|
|
81
|
-
readonly
|
|
83
|
+
readonly kind: "budget";
|
|
84
|
+
readonly budget: 0;
|
|
82
85
|
readonly includeThoughts: false;
|
|
83
86
|
};
|
|
84
87
|
readonly tools: ToolCapability;
|
|
85
88
|
};
|
|
86
89
|
readonly low: {
|
|
87
|
-
readonly wireModel: "gemini-3.8-flash-
|
|
90
|
+
readonly wireModel: "gemini-3.8-flash-low";
|
|
88
91
|
readonly thinking: {
|
|
89
|
-
readonly kind: "
|
|
90
|
-
readonly
|
|
92
|
+
readonly kind: "budget";
|
|
93
|
+
readonly budget: 1000;
|
|
91
94
|
readonly includeThoughts: true;
|
|
92
95
|
};
|
|
93
96
|
readonly tools: ToolCapability;
|
|
94
97
|
};
|
|
95
98
|
readonly medium: {
|
|
96
|
-
readonly wireModel: "gemini-3.8-flash-
|
|
99
|
+
readonly wireModel: "gemini-3.8-flash-medium";
|
|
97
100
|
readonly thinking: {
|
|
98
|
-
readonly kind: "
|
|
99
|
-
readonly
|
|
101
|
+
readonly kind: "budget";
|
|
102
|
+
readonly budget: 4000;
|
|
100
103
|
readonly includeThoughts: true;
|
|
101
104
|
};
|
|
102
105
|
readonly tools: ToolCapability;
|
|
103
106
|
};
|
|
104
107
|
readonly high: {
|
|
105
|
-
readonly wireModel: "gemini-3.8-flash-
|
|
108
|
+
readonly wireModel: "gemini-3.8-flash-high";
|
|
106
109
|
readonly thinking: {
|
|
107
|
-
readonly kind: "
|
|
108
|
-
readonly
|
|
110
|
+
readonly kind: "budget";
|
|
111
|
+
readonly budget: -1;
|
|
109
112
|
readonly includeThoughts: true;
|
|
110
113
|
};
|
|
111
114
|
readonly tools: ToolCapability;
|
|
@@ -402,7 +405,7 @@ type Catalog = typeof CATALOG;
|
|
|
402
405
|
export type AntigravityPublicModelId = Catalog[number]["publicId"];
|
|
403
406
|
export type AntigravityWireModelId = Catalog[number]["routes"][keyof Catalog[number]["routes"]]["wireModel"];
|
|
404
407
|
/** Constructs deterministic capability data for hermetic serializer tests only. */
|
|
405
|
-
export declare function createEnabledToolCapability(evidence: ToolEvidenceRef): Extract<ToolCapability, {
|
|
408
|
+
export declare function createEnabledToolCapability(evidence: ToolEvidenceRef, schemaProfile?: ToolSchemaProfile): Extract<ToolCapability, {
|
|
406
409
|
readonly state: "enabled";
|
|
407
410
|
}>;
|
|
408
411
|
export declare function defineCatalog<T extends readonly {
|
package/dist/catalog.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const ANSWER_RESERVE = 1024;
|
|
2
|
+
export const GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE = "gemini-parameters-json-schema";
|
|
2
3
|
const CATALOG = freeze(defineCatalog([{
|
|
3
4
|
publicId: "antigravity-gemini-3.8-flash",
|
|
4
5
|
descriptor: {
|
|
@@ -8,10 +9,10 @@ const CATALOG = freeze(defineCatalog([{
|
|
|
8
9
|
maxTokens: 65_536,
|
|
9
10
|
},
|
|
10
11
|
routes: {
|
|
11
|
-
off: { wireModel: "gemini-3.8-flash-
|
|
12
|
-
low: { wireModel: "gemini-3.8-flash-
|
|
13
|
-
medium: { wireModel: "gemini-3.8-flash-
|
|
14
|
-
high: { wireModel: "gemini-3.8-flash-
|
|
12
|
+
off: { wireModel: "gemini-3.8-flash-low", thinking: { kind: "budget", budget: 0, includeThoughts: false }, tools: enabled({ record: "pi-json-tool-loop", revision: "gemini-3.8-flash-off-v1", publicModelId: "antigravity-gemini-3.8-flash", reasoning: "off", wireModel: "gemini-3.8-flash-low" }, GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE) },
|
|
13
|
+
low: { wireModel: "gemini-3.8-flash-low", thinking: { kind: "budget", budget: 1000, includeThoughts: true }, tools: enabled({ record: "pi-json-tool-loop", revision: "gemini-3.8-flash-low-v1", publicModelId: "antigravity-gemini-3.8-flash", reasoning: "low", wireModel: "gemini-3.8-flash-low" }, GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE) },
|
|
14
|
+
medium: { wireModel: "gemini-3.8-flash-medium", thinking: { kind: "budget", budget: 4000, includeThoughts: true }, tools: enabled({ record: "pi-json-tool-loop", revision: "gemini-3.8-flash-medium-v1", publicModelId: "antigravity-gemini-3.8-flash", reasoning: "medium", wireModel: "gemini-3.8-flash-medium" }, GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE) },
|
|
15
|
+
high: { wireModel: "gemini-3.8-flash-high", thinking: { kind: "budget", budget: -1, includeThoughts: true }, tools: enabled({ record: "pi-json-tool-loop", revision: "gemini-3.8-flash-high-v1", publicModelId: "antigravity-gemini-3.8-flash", reasoning: "high", wireModel: "gemini-3.8-flash-high" }, GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE) },
|
|
15
16
|
},
|
|
16
17
|
replay: { kind: "same-public-model" },
|
|
17
18
|
response: { kind: "gemini-envelope", family: "gemini" },
|
|
@@ -109,12 +110,12 @@ const lookup = new Map(CATALOG.map((entry) => [entry.publicId, entry]));
|
|
|
109
110
|
function disabled(reason) {
|
|
110
111
|
return { state: "disabled", contractRevision: 1, reason };
|
|
111
112
|
}
|
|
112
|
-
function enabled(evidence) {
|
|
113
|
-
return { state: "enabled", contractRevision: 1, fixtureEvidence: evidence, directEvidence: evidence };
|
|
113
|
+
function enabled(evidence, schemaProfile = GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE) {
|
|
114
|
+
return { state: "enabled", contractRevision: 1, schemaProfile, fixtureEvidence: evidence, directEvidence: evidence };
|
|
114
115
|
}
|
|
115
116
|
/** Constructs deterministic capability data for hermetic serializer tests only. */
|
|
116
|
-
export function createEnabledToolCapability(evidence) {
|
|
117
|
-
return freeze({ state: "enabled", contractRevision: 1, fixtureEvidence: evidence, directEvidence: evidence });
|
|
117
|
+
export function createEnabledToolCapability(evidence, schemaProfile = GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE) {
|
|
118
|
+
return freeze({ state: "enabled", contractRevision: 1, schemaProfile, fixtureEvidence: evidence, directEvidence: evidence });
|
|
118
119
|
}
|
|
119
120
|
function freeze(value) {
|
|
120
121
|
if (typeof value === "object" && value !== null) {
|
package/dist/context.js
CHANGED
|
@@ -20,7 +20,7 @@ export function serializeContext(input, injectedSelection, onDiagnostics) {
|
|
|
20
20
|
fail("Invalid tool capability selection.");
|
|
21
21
|
if (selection.tools.state !== "enabled")
|
|
22
22
|
fail(capabilityError(entry.publicId, selection.level, selection.tools));
|
|
23
|
-
const prepared = prepareToolContext(field(context, "tools") ?? [], isRecord(options) ? field(options, "toolChoice") : undefined);
|
|
23
|
+
const prepared = prepareToolContext(field(context, "tools") ?? [], isRecord(options) ? field(options, "toolChoice") : undefined, selection.tools.schemaProfile);
|
|
24
24
|
const { tools: _tools, messages, ...textContext } = context;
|
|
25
25
|
const { toolChoice: _choice, ...textOptions } = isRecord(options) ? options : {};
|
|
26
26
|
const text = serializeTextContext({ ...input, context: { ...textContext, messages: [{ role: "user", content: "placeholder", timestamp: 0 }] }, options: textOptions });
|
package/dist/tool-context.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export interface PreparedToolContext {
|
|
|
4
4
|
readonly mode: "AUTO" | "NONE";
|
|
5
5
|
}
|
|
6
6
|
export declare function hasToolContext(context: unknown): boolean;
|
|
7
|
-
export declare function prepareToolContext(tools: unknown, choice: unknown): PreparedToolContext | undefined;
|
|
7
|
+
export declare function prepareToolContext(tools: unknown, choice: unknown, schemaProfile: unknown): PreparedToolContext | undefined;
|
|
8
8
|
type WirePart = object;
|
|
9
9
|
type WireContent = {
|
|
10
10
|
role: "user" | "model";
|
package/dist/tool-context.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { canonicalJson, ToolPreflightError } from "./tool-contract.js";
|
|
2
|
+
import { GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE } from "./catalog.js";
|
|
2
3
|
import { normalizeToolDeclarations } from "./tool-schema.js";
|
|
3
4
|
export function hasToolContext(context) {
|
|
4
5
|
if (!isRecord(context))
|
|
@@ -16,7 +17,9 @@ export function hasToolContext(context) {
|
|
|
16
17
|
return Array.isArray(content) && content.some((part) => isRecord(part) && value(part, "type") === "toolCall");
|
|
17
18
|
});
|
|
18
19
|
}
|
|
19
|
-
export function prepareToolContext(tools, choice) {
|
|
20
|
+
export function prepareToolContext(tools, choice, schemaProfile) {
|
|
21
|
+
if (schemaProfile !== GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE)
|
|
22
|
+
throw new ToolPreflightError("PI_TOOL_SCHEMA_PROFILE_UNSUPPORTED", "tools", "$");
|
|
20
23
|
const declarations = normalizeToolDeclarations(tools ?? []);
|
|
21
24
|
if (!declarations.length) {
|
|
22
25
|
if (choice === "auto")
|
package/dist/tool-schema.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const TYPES = new Set(["object", "array", "string", "number", "integer", "boolean"]);
|
|
3
|
-
const KEYWORDS = new Set(["type", "description", "nullable", "enum", "const", "properties", "required", "items"]);
|
|
1
|
+
import { denseArray, fail, freeze, ownData, plainObject } from "./tool-contract.js";
|
|
4
2
|
const MAX_SCHEMA_DEPTH = 32;
|
|
5
3
|
const MAX_SCHEMA_NODES = 2048;
|
|
6
4
|
const MAX_SCHEMA_BYTES = 256 * 1024;
|
|
7
5
|
const MAX_TOTAL_SCHEMA_BYTES = 1024 * 1024;
|
|
6
|
+
const METADATA = new Set(["$schema", "$id", "$anchor", "$dynamicAnchor", "$vocabulary", "$comment"]);
|
|
7
|
+
const SCHEMA_MAPS = new Set(["properties", "patternProperties", "dependentSchemas"]);
|
|
8
|
+
const SCHEMAS = new Set(["additionalItems", "additionalProperties", "contains", "contentSchema", "else", "if", "items", "not", "propertyNames", "then", "unevaluatedItems", "unevaluatedProperties"]);
|
|
9
|
+
const SCHEMA_ARRAYS = new Set(["allOf", "anyOf", "oneOf", "prefixItems"]);
|
|
8
10
|
export function normalizeToolDeclarations(value) {
|
|
9
11
|
const tools = denseArray(value, "tools", "$");
|
|
10
12
|
const names = new Set();
|
|
@@ -32,94 +34,179 @@ function normalizeDeclaration(value, index, names) {
|
|
|
32
34
|
const constrainedSampling = ownData(tool, "constrainedSampling", name, path);
|
|
33
35
|
if (constrainedSampling !== undefined && constrainedSampling !== false)
|
|
34
36
|
fail("PI_TOOL_CONSTRAINED_SAMPLING_UNSUPPORTED", name, `${path}.constrainedSampling`);
|
|
35
|
-
const
|
|
36
|
-
if (ownData(
|
|
37
|
+
const root = plainObject(ownData(tool, "parameters", name, path), name, "$");
|
|
38
|
+
if (ownData(root, "type", name, "$") !== "object")
|
|
39
|
+
fail("PI_TOOL_SCHEMA_INVALID", name, "$.type");
|
|
40
|
+
const snapshot = snapshotJson(root, name, "$", { ancestors: new Set(), nodes: 0 });
|
|
41
|
+
if (!isJsonObject(snapshot))
|
|
42
|
+
fail("PI_TOOL_SCHEMA_INVALID", name, "$");
|
|
43
|
+
const parameters = emitSchema(snapshot, snapshot, name, "$", { nodes: 0 }, new Set());
|
|
44
|
+
if (!isJsonObject(parameters) || parameters.type !== "object")
|
|
37
45
|
fail("PI_TOOL_SCHEMA_INVALID", name, "$.type");
|
|
38
|
-
const parameters = normalizeSchema(parameterRoot, name, "$");
|
|
39
46
|
if (Buffer.byteLength(JSON.stringify(parameters), "utf8") > MAX_SCHEMA_BYTES)
|
|
40
47
|
fail("PI_TOOL_SCHEMA_LIMIT", name, "$");
|
|
41
48
|
return freeze({ name, description, parameters });
|
|
42
49
|
}
|
|
43
|
-
function
|
|
50
|
+
function snapshotJson(value, declaration, path, state, depth = 0) {
|
|
44
51
|
if (depth > MAX_SCHEMA_DEPTH || ++state.nodes > MAX_SCHEMA_NODES)
|
|
45
52
|
fail("PI_TOOL_SCHEMA_LIMIT", declaration, path);
|
|
46
|
-
if (typeof value === "
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
54
|
+
return value;
|
|
55
|
+
if (typeof value === "number")
|
|
56
|
+
return Number.isFinite(value) ? value : fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
57
|
+
if (typeof value !== "object" || state.ancestors.has(value))
|
|
58
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
59
|
+
state.ancestors.add(value);
|
|
60
|
+
try {
|
|
61
|
+
if (Array.isArray(value))
|
|
62
|
+
return freeze(snapshotArray(value, declaration, path, state, depth));
|
|
63
|
+
const object = plainObject(value, declaration, path);
|
|
64
|
+
const output = {};
|
|
65
|
+
for (const key of Object.keys(object).sort())
|
|
66
|
+
define(output, key, snapshotJson(ownData(object, key, declaration, path), declaration, pathSegment(path, key), state, depth + 1));
|
|
67
|
+
return freeze(output);
|
|
50
68
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (!KEYWORDS.has(key))
|
|
54
|
-
fail("PI_TOOL_SCHEMA_UNSUPPORTED", declaration, `${path}.${key}`);
|
|
55
|
-
const type = ownData(schema, "type", declaration, path);
|
|
56
|
-
if (typeof type !== "string" || !TYPES.has(type))
|
|
57
|
-
fail("PI_TOOL_SCHEMA_INVALID", declaration, `${path}.type`);
|
|
58
|
-
const output = { type };
|
|
59
|
-
const description = ownData(schema, "description", declaration, path);
|
|
60
|
-
if (description !== undefined) {
|
|
61
|
-
if (typeof description !== "string")
|
|
62
|
-
fail("PI_TOOL_SCHEMA_INVALID", declaration, `${path}.description`);
|
|
63
|
-
output.description = description;
|
|
69
|
+
finally {
|
|
70
|
+
state.ancestors.delete(value);
|
|
64
71
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
72
|
+
}
|
|
73
|
+
function snapshotArray(value, declaration, path, state, depth) {
|
|
74
|
+
if (Object.getPrototypeOf(value) !== Array.prototype || Object.getOwnPropertySymbols(value).length || Object.getOwnPropertyNames(value).length !== value.length + 1)
|
|
75
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
76
|
+
const values = denseArray(value, declaration, path);
|
|
77
|
+
const output = [];
|
|
78
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
79
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
80
|
+
if (!descriptor || !("value" in descriptor))
|
|
81
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, `${path}[${index}]`);
|
|
82
|
+
output.push(snapshotJson(descriptor.value, declaration, `${path}[${index}]`, state, depth + 1));
|
|
70
83
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (type === "object")
|
|
80
|
-
normalizeObject(schema, output, declaration, path, state, depth);
|
|
81
|
-
else if (type === "array")
|
|
82
|
-
normalizeArray(schema, output, declaration, path, state, depth);
|
|
83
|
-
else if (ownData(schema, "properties", declaration, path) !== undefined || ownData(schema, "required", declaration, path) !== undefined || ownData(schema, "items", declaration, path) !== undefined)
|
|
84
|
+
return output;
|
|
85
|
+
}
|
|
86
|
+
function emitSchema(value, root, declaration, path, state, targets, depth = 0) {
|
|
87
|
+
if (depth > MAX_SCHEMA_DEPTH || ++state.nodes > MAX_SCHEMA_NODES)
|
|
88
|
+
fail("PI_TOOL_SCHEMA_LIMIT", declaration, path);
|
|
89
|
+
if (typeof value === "boolean")
|
|
90
|
+
return value;
|
|
91
|
+
if (!isJsonObject(value))
|
|
84
92
|
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
85
|
-
|
|
93
|
+
const reference = value.$ref;
|
|
94
|
+
if (reference !== undefined) {
|
|
95
|
+
const referencePath = pathSegment(path, "$ref");
|
|
96
|
+
const target = resolveReference(reference, root, declaration, referencePath);
|
|
97
|
+
if (isJsonObject(target) && targets.has(target))
|
|
98
|
+
fail("PI_TOOL_SCHEMA_REFERENCE_CYCLE", declaration, referencePath);
|
|
99
|
+
const next = new Set(targets);
|
|
100
|
+
if (isJsonObject(target))
|
|
101
|
+
next.add(target);
|
|
102
|
+
const resolved = emitSchema(target, root, declaration, path, state, next, depth + 1);
|
|
103
|
+
const sibling = emitObject(value, root, declaration, path, state, targets, depth + 1, new Set(["$ref"]));
|
|
104
|
+
if (!Object.keys(sibling).length)
|
|
105
|
+
return resolved;
|
|
106
|
+
if (resolved === true || resolved === false)
|
|
107
|
+
return resolved === true ? sibling : false;
|
|
108
|
+
return freeze({ allOf: freeze([resolved, sibling]) });
|
|
109
|
+
}
|
|
110
|
+
return emitObject(value, root, declaration, path, state, targets, depth, new Set());
|
|
86
111
|
}
|
|
87
|
-
function
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
|
|
112
|
+
function emitObject(value, root, declaration, path, state, targets, depth, omitted) {
|
|
113
|
+
const output = {};
|
|
114
|
+
for (const key of Object.keys(value)) {
|
|
115
|
+
const child = value[key];
|
|
116
|
+
if (omitted.has(key) || METADATA.has(key))
|
|
117
|
+
continue;
|
|
118
|
+
if (key === "$defs" || key === "definitions") {
|
|
119
|
+
emitSchemaMap(child, root, declaration, pathSegment(path, key), state, targets, depth + 1);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (SCHEMA_MAPS.has(key))
|
|
123
|
+
define(output, key, emitSchemaMap(child, root, declaration, pathSegment(path, key), state, targets, depth + 1));
|
|
124
|
+
else if (SCHEMA_ARRAYS.has(key))
|
|
125
|
+
define(output, key, emitSchemaArray(child, root, declaration, pathSegment(path, key), state, targets, depth + 1));
|
|
126
|
+
else if (key === "dependencies")
|
|
127
|
+
define(output, key, emitDependencies(child, root, declaration, pathSegment(path, key), state, targets, depth + 1));
|
|
128
|
+
else if (key === "items" && Array.isArray(child))
|
|
129
|
+
define(output, key, emitSchemaArray(child, root, declaration, pathSegment(path, key), state, targets, depth + 1));
|
|
130
|
+
else if (SCHEMAS.has(key))
|
|
131
|
+
define(output, key, emitSchema(child, root, declaration, pathSegment(path, key), state, targets, depth + 1));
|
|
132
|
+
else
|
|
133
|
+
define(output, key, child);
|
|
104
134
|
}
|
|
135
|
+
return freeze(output);
|
|
105
136
|
}
|
|
106
|
-
function
|
|
107
|
-
if (
|
|
137
|
+
function emitSchemaMap(value, root, declaration, path, state, targets, depth) {
|
|
138
|
+
if (!isJsonObject(value))
|
|
108
139
|
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
109
|
-
output
|
|
140
|
+
const output = {};
|
|
141
|
+
for (const key of Object.keys(value))
|
|
142
|
+
define(output, key, emitSchema(value[key], root, declaration, pathSegment(path, key), state, targets, depth));
|
|
143
|
+
return freeze(output);
|
|
110
144
|
}
|
|
111
|
-
function
|
|
112
|
-
|
|
113
|
-
if (!values.length)
|
|
114
|
-
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
115
|
-
const normalized = values.map((item, index) => validateEnumValue(item, type, nullable, declaration, `${path}[${index}]`));
|
|
116
|
-
if (new Set(normalized.map((item) => JSON.stringify(item))).size !== normalized.length)
|
|
145
|
+
function emitSchemaArray(value, root, declaration, path, state, targets, depth) {
|
|
146
|
+
if (!Array.isArray(value))
|
|
117
147
|
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
118
|
-
return freeze(
|
|
148
|
+
return freeze(value.map((item, index) => emitSchema(item, root, declaration, `${path}[${index}]`, state, targets, depth)));
|
|
119
149
|
}
|
|
120
|
-
function
|
|
121
|
-
|
|
122
|
-
if (typeof json === "object" || (json === null && !nullable) || (json !== null && (type === "integer" ? typeof json !== "number" || !Number.isInteger(json) : typeof json !== type)))
|
|
150
|
+
function emitDependencies(value, root, declaration, path, state, targets, depth) {
|
|
151
|
+
if (!isJsonObject(value))
|
|
123
152
|
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
124
|
-
|
|
153
|
+
const output = {};
|
|
154
|
+
for (const key of Object.keys(value)) {
|
|
155
|
+
const dependency = value[key];
|
|
156
|
+
if (Array.isArray(dependency) && dependency.every((entry) => typeof entry === "string"))
|
|
157
|
+
define(output, key, dependency);
|
|
158
|
+
else
|
|
159
|
+
define(output, key, emitSchema(dependency, root, declaration, pathSegment(path, key), state, targets, depth));
|
|
160
|
+
}
|
|
161
|
+
return freeze(output);
|
|
162
|
+
}
|
|
163
|
+
function resolveReference(reference, root, declaration, path) {
|
|
164
|
+
if (typeof reference !== "string" || (reference !== "#" && !reference.startsWith("#/")))
|
|
165
|
+
fail("PI_TOOL_SCHEMA_REFERENCE_INVALID", declaration, path);
|
|
166
|
+
if (reference === "#")
|
|
167
|
+
return root;
|
|
168
|
+
let pointer;
|
|
169
|
+
try {
|
|
170
|
+
pointer = decodeURIComponent(reference.slice(1));
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return fail("PI_TOOL_SCHEMA_REFERENCE_INVALID", declaration, path);
|
|
174
|
+
}
|
|
175
|
+
let current = root;
|
|
176
|
+
for (const rawToken of pointer.slice(1).split("/")) {
|
|
177
|
+
const token = decodeToken(rawToken, declaration, path);
|
|
178
|
+
if (Array.isArray(current)) {
|
|
179
|
+
if (!/^(0|[1-9][0-9]*)$/.test(token) || !Number.isSafeInteger(Number(token)) || Number(token) >= current.length)
|
|
180
|
+
fail("PI_TOOL_SCHEMA_REFERENCE_INVALID", declaration, path);
|
|
181
|
+
current = current[Number(token)];
|
|
182
|
+
}
|
|
183
|
+
else if (isJsonObject(current)) {
|
|
184
|
+
if (!Object.hasOwn(current, token))
|
|
185
|
+
fail("PI_TOOL_SCHEMA_REFERENCE_INVALID", declaration, path);
|
|
186
|
+
current = current[token];
|
|
187
|
+
}
|
|
188
|
+
else
|
|
189
|
+
fail("PI_TOOL_SCHEMA_REFERENCE_INVALID", declaration, path);
|
|
190
|
+
}
|
|
191
|
+
if (typeof current !== "boolean" && !isJsonObject(current))
|
|
192
|
+
fail("PI_TOOL_SCHEMA_REFERENCE_INVALID", declaration, path);
|
|
193
|
+
return current;
|
|
194
|
+
}
|
|
195
|
+
function decodeToken(value, declaration, path) {
|
|
196
|
+
return value.replace(/~(.)?/g, (escape, next) => {
|
|
197
|
+
if (escape === "~0")
|
|
198
|
+
return "~";
|
|
199
|
+
if (escape === "~1")
|
|
200
|
+
return "/";
|
|
201
|
+
return fail("PI_TOOL_SCHEMA_REFERENCE_INVALID", declaration, path);
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
function pathSegment(path, key) {
|
|
205
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? `${path}.${key}` : `${path}[${JSON.stringify(key)}]`;
|
|
206
|
+
}
|
|
207
|
+
function isJsonObject(value) {
|
|
208
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
209
|
+
}
|
|
210
|
+
function define(target, key, value) {
|
|
211
|
+
Object.defineProperty(target, key, { value, enumerable: true, configurable: false, writable: false });
|
|
125
212
|
}
|