openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
658 lines (657 loc) • 29.3 kB
JavaScript
import { t as parseConfigPathArrayIndex } from "./path-array-index-BDeCXbeb.js";
import { Compile } from "typebox/compile";
//#region src/shared/json-schema-defaults.ts
const schemaResourceIds = /* @__PURE__ */ new WeakMap();
let nextSchemaResourceId = 1;
const schemaMapKeywords = new Set([
"$defs",
"definitions",
"dependentSchemas",
"patternProperties",
"properties"
]);
const schemaValueKeywords = new Set([
"additionalItems",
"additionalProperties",
"contains",
"else",
"if",
"items",
"not",
"propertyNames",
"then",
"unevaluatedItems",
"unevaluatedProperties"
]);
const schemaArrayKeywords = new Set([
"allOf",
"anyOf",
"oneOf",
"prefixItems"
]);
const schemaCombinatorKeywords = new Set([
"allOf",
"anyOf",
"oneOf"
]);
const jsonSchemaTypes = new Set([
"array",
"boolean",
"integer",
"null",
"number",
"object",
"string"
]);
const schemaStringKeywords = new Set([
"$anchor",
"$comment",
"$dynamicAnchor",
"$dynamicRef",
"$id",
"$schema",
"$ref",
"contentEncoding",
"contentMediaType",
"description",
"format",
"pattern",
"title"
]);
const schemaNumberKeywords = new Set([
"exclusiveMaximum",
"exclusiveMinimum",
"maximum",
"minimum",
"multipleOf"
]);
const schemaIntegerKeywords = new Set([
"maxContains",
"maxItems",
"maxLength",
"maxProperties",
"minContains",
"minItems",
"minLength",
"minProperties"
]);
const schemaBooleanKeywords = new Set([
"deprecated",
"readOnly",
"uniqueItems",
"writeOnly"
]);
function isRecord(value) {
return Boolean(value && typeof value === "object" && !Array.isArray(value));
}
function schemaTypeIncludes(schema, type) {
return schema.type === type || Array.isArray(schema.type) && schema.type.includes(type);
}
function schemaResourceRefKey(resourceRoot, ref, baseId) {
if (!isRecord(resourceRoot)) return `boolean:${String(resourceRoot)}:${baseId ?? ""}:${ref}`;
let id = schemaResourceIds.get(resourceRoot);
if (id === void 0) {
id = nextSchemaResourceId++;
schemaResourceIds.set(resourceRoot, id);
}
return `schema:${id}:${baseId ?? ""}:${ref}`;
}
function normalizeSchemaMap(value) {
if (!isRecord(value)) return value;
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, normalizeJsonSchemaNode(entry)]));
}
function compilesUnicodePattern(pattern) {
try {
new RegExp(pattern, "u");
return true;
} catch {
return false;
}
}
/** Repair JSON Schema regex patterns that fail TypeBox's unicode RegExp compile. */
function repairJsonSchemaPatternForUnicodeRegExp(pattern) {
if (compilesUnicodePattern(pattern)) return pattern;
const repaired = pattern.replace(/\\([^\\])/g, (match, ch) => {
if (ch === ":" || ch === "/") return ch;
return match;
});
return compilesUnicodePattern(repaired) ? repaired : pattern;
}
function normalizeSchemaDependencies(value) {
if (!isRecord(value)) return value;
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, isStringArray(entry) ? entry : normalizeJsonSchemaNode(entry)]));
}
function normalizePatternProperties(value) {
const normalized = /* @__PURE__ */ new Map();
for (const [pattern, propertySchema] of Object.entries(value)) {
const repairedPattern = repairJsonSchemaPatternForUnicodeRegExp(pattern);
const repairedSchema = normalizeJsonSchemaNode(propertySchema);
const existingSchema = normalized.get(repairedPattern);
normalized.set(repairedPattern, existingSchema === void 0 ? repairedSchema : { allOf: [existingSchema, repairedSchema] });
}
return Object.fromEntries(normalized);
}
function expandJsonSchemaTypeArray(schema) {
const { nullable, type, ...rest } = schema;
const types = Array.isArray(type) ? [...type] : typeof type === "string" ? [type] : null;
if (!types) return schema;
if (nullable === true && !types.includes("null")) types.push("null");
if (types.length === 1 && !Array.isArray(type)) return schema;
return { anyOf: types.map((entry) => Object.assign({}, rest, { type: entry })) };
}
function normalizeAdditionalPropertiesSchema(schema) {
if (!isRecord(schema.additionalProperties) || isRecord(schema.properties) || isRecord(schema.patternProperties)) return schema;
const { additionalProperties, ...rest } = schema;
return {
...rest,
patternProperties: { ".*": additionalProperties },
additionalProperties: false
};
}
function normalizeJsonSchemaNode(schema) {
if (Array.isArray(schema)) return schema.map((entry) => normalizeJsonSchemaNode(entry));
if (!isRecord(schema)) return schema;
const normalizedSchema = normalizeAdditionalPropertiesSchema(expandJsonSchemaTypeArray(schema));
return Object.fromEntries(Object.entries(normalizedSchema).map(([key, value]) => {
if (key === "$dynamicRef" && normalizedSchema.$ref === void 0) return ["$ref", value];
if (key === "pattern" && typeof value === "string") return [key, repairJsonSchemaPatternForUnicodeRegExp(value)];
if (key === "patternProperties" && isRecord(value)) return [key, normalizePatternProperties(value)];
if (schemaMapKeywords.has(key)) return [key, normalizeSchemaMap(value)];
if (key === "dependencies") return [key, normalizeSchemaDependencies(value)];
if (schemaValueKeywords.has(key) || schemaArrayKeywords.has(key)) return [key, normalizeJsonSchemaNode(value)];
return [key, value];
}));
}
function validateTypeKeyword(type, path) {
if (typeof type === "string") return jsonSchemaTypes.has(type) ? void 0 : `${path}.type: unsupported JSON Schema type`;
if (Array.isArray(type) && type.length > 0) {
if (type.find((entry) => typeof entry !== "string" || !jsonSchemaTypes.has(entry)) !== void 0) return `${path}.type: unsupported JSON Schema type`;
return new Set(type).size === type.length ? void 0 : `${path}.type: expected unique JSON Schema types`;
}
return `${path}.type: expected string or non-empty string array`;
}
function decodePointerSegment(segment) {
let decodedSegment;
try {
decodedSegment = decodeURIComponent(segment);
} catch {
decodedSegment = segment;
}
return decodedSegment.replace(/~1/g, "/").replace(/~0/g, "~");
}
function resolveLocalAnchor(schema, anchor, isRoot = true) {
if (!isRecord(schema)) return;
if (!isRoot && typeof schema.$id === "string") return;
if (schema.$anchor === anchor || schema.$dynamicAnchor === anchor) return schema;
for (const key of schemaMapKeywords) {
const value = schema[key];
if (!isRecord(value)) continue;
for (const entry of Object.values(value)) {
const resolved = resolveLocalAnchor(entry, anchor, false);
if (resolved !== void 0) return resolved;
}
}
if (isRecord(schema.dependencies)) for (const entry of Object.values(schema.dependencies)) {
if (isStringArray(entry)) continue;
const resolved = resolveLocalAnchor(entry, anchor, false);
if (resolved !== void 0) return resolved;
}
for (const key of schemaValueKeywords) {
const value = schema[key];
if (typeof value === "boolean" || isRecord(value)) {
const resolved = resolveLocalAnchor(value, anchor, false);
if (resolved !== void 0) return resolved;
continue;
}
if (key === "items" && Array.isArray(value)) for (const entry of value) {
const resolved = resolveLocalAnchor(entry, anchor, false);
if (resolved !== void 0) return resolved;
}
}
for (const key of schemaArrayKeywords) {
const value = schema[key];
if (!Array.isArray(value)) continue;
for (const entry of value) {
const resolved = resolveLocalAnchor(entry, anchor, false);
if (resolved !== void 0) return resolved;
}
}
}
function resolveLocalRef(resourceRoot, ref, resourceBaseId) {
if (isRecord(resourceRoot) && typeof resourceRoot.$id === "string" && resourceRoot.$id !== "") {
if (ref === resourceRoot.$id) return {
found: true,
schema: resourceRoot,
resourceRoot,
resourceBaseId
};
if (ref.startsWith(`${resourceRoot.$id}#`)) return resolveLocalRef(resourceRoot, ref.slice(resourceRoot.$id.length), resourceBaseId);
}
if (ref === "#") return {
found: true,
schema: resourceRoot,
resourceRoot,
resourceBaseId
};
if (ref.startsWith("#/")) {
let current = resourceRoot;
let currentResourceRoot = resourceRoot;
let currentResourceBaseId = resourceBaseId;
for (const segment of ref.slice(2).split("/").map(decodePointerSegment)) {
if (Array.isArray(current)) {
const index = parseConfigPathArrayIndex(segment);
if (index === void 0) return { found: false };
current = current[index];
} else if (isRecord(current)) current = current[segment];
else return { found: false };
if (isRecord(current) && typeof current.$id === "string") {
currentResourceRoot = current;
currentResourceBaseId = resolveSchemaId(current.$id, currentResourceBaseId);
}
}
return typeof current === "boolean" || isRecord(current) ? {
found: true,
schema: current,
resourceRoot: currentResourceRoot,
resourceBaseId: currentResourceBaseId
} : { found: false };
}
if (ref.startsWith("#")) {
const resolved = resolveLocalAnchor(resourceRoot, decodeURIComponent(ref.slice(1)));
return resolved === void 0 ? { found: false } : {
found: true,
schema: resolved,
resourceRoot,
resourceBaseId
};
}
return { found: false };
}
function splitResourceRef(ref) {
const hashIndex = ref.indexOf("#");
return hashIndex === -1 ? {
resource: ref,
fragment: ""
} : {
resource: ref.slice(0, hashIndex),
fragment: ref.slice(hashIndex)
};
}
function stripFragment(id) {
return splitResourceRef(id).resource;
}
function resolveSchemaId(id, baseId) {
if (!baseId) return stripFragment(id);
try {
return stripFragment(new URL(id, baseId).href);
} catch {
return stripFragment(id);
}
}
function resolveSchemaResourceRef(schema, ref, baseId) {
const refParts = splitResourceRef(ref);
const resolvedRefResource = refParts.resource === "" ? refParts.resource : resolveSchemaId(refParts.resource, baseId);
const seen = /* @__PURE__ */ new Set();
const visit = (current, baseIdLocal) => {
if (!isRecord(current) || seen.has(current)) return { found: false };
seen.add(current);
let currentBaseId = baseIdLocal;
if (typeof current.$id === "string" && current.$id !== "") {
const resolvedId = resolveSchemaId(current.$id, baseIdLocal);
currentBaseId = resolvedId;
if (resolvedRefResource === resolvedId || refParts.resource === stripFragment(current.$id)) return refParts.fragment ? resolveLocalRef(current, refParts.fragment, currentBaseId) : {
found: true,
schema: current,
resourceRoot: current,
resourceBaseId: currentBaseId
};
}
for (const key of schemaMapKeywords) {
const value = current[key];
if (!isRecord(value)) continue;
for (const entry of Object.values(value)) {
const resolved = visit(entry, currentBaseId);
if (resolved.found) return resolved;
}
}
if (isRecord(current.dependencies)) for (const entry of Object.values(current.dependencies)) {
if (isStringArray(entry)) continue;
const resolved = visit(entry, currentBaseId);
if (resolved.found) return resolved;
}
for (const key of schemaValueKeywords) {
const value = current[key];
if (typeof value === "boolean" || isRecord(value)) {
const resolved = visit(value, currentBaseId);
if (resolved.found) return resolved;
continue;
}
if (key === "items" && Array.isArray(value)) for (const entry of value) {
const resolved = visit(entry, currentBaseId);
if (resolved.found) return resolved;
}
}
for (const key of schemaArrayKeywords) {
const value = current[key];
if (!Array.isArray(value)) continue;
for (const entry of value) {
const resolved = visit(entry, currentBaseId);
if (resolved.found) return resolved;
}
}
return { found: false };
};
return visit(schema, void 0);
}
function resolveSchemaRef(root, resourceRoot, ref, baseId) {
const localTarget = resolveLocalRef(resourceRoot, ref, baseId);
return localTarget.found ? localTarget : resolveSchemaResourceRef(root, ref, baseId);
}
/** Normalize JSON Schema constructs into the TypeBox compiler subset used by plugin validators. */
function normalizeJsonSchemaForTypeBox(schema) {
return normalizeJsonSchemaNode(schema);
}
function isStringArray(value) {
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
}
function hasDuplicateJsonValues(values) {
const seen = /* @__PURE__ */ new Set();
for (const value of values) {
const key = JSON.stringify(value);
if (seen.has(key)) return true;
seen.add(key);
}
return false;
}
function validateSchemaKeywordShapes(schema, path) {
for (const key of schemaStringKeywords) {
const value = schema[key];
if (value !== void 0 && typeof value !== "string") return `${path}.${key}: expected string`;
}
for (const key of schemaNumberKeywords) {
const value = schema[key];
if (value !== void 0 && typeof value !== "number") return `${path}.${key}: expected number`;
}
for (const key of schemaIntegerKeywords) {
const value = schema[key];
if (value !== void 0 && (!Number.isInteger(value) || typeof value === "number" && value < 0)) return `${path}.${key}: expected non-negative integer`;
}
for (const key of schemaBooleanKeywords) {
const value = schema[key];
if (value !== void 0 && typeof value !== "boolean") return `${path}.${key}: expected boolean`;
}
if (schema.multipleOf !== void 0 && typeof schema.multipleOf === "number" && schema.multipleOf <= 0) return `${path}.multipleOf: expected positive number`;
if (schema.required !== void 0) {
if (!isStringArray(schema.required)) return `${path}.required: expected string array`;
if (new Set(schema.required).size !== schema.required.length) return `${path}.required: expected unique string array`;
}
if (schema.enum !== void 0) {
if (!Array.isArray(schema.enum)) return `${path}.enum: expected array`;
if (schema.enum.length === 0 || hasDuplicateJsonValues(schema.enum)) return `${path}.enum: expected non-empty array with unique values`;
}
for (const key of schemaCombinatorKeywords) {
const value = schema[key];
if (Array.isArray(value) && value.length === 0) return `${path}.${key}: expected non-empty schema array`;
}
if (schema.dependentRequired !== void 0) {
if (!isRecord(schema.dependentRequired)) return `${path}.dependentRequired: expected string array map`;
for (const [key, value] of Object.entries(schema.dependentRequired)) if (!isStringArray(value)) return `${path}.dependentRequired.${key}: expected string array`;
}
if (schema.dependencies !== void 0) {
if (!isRecord(schema.dependencies)) return `${path}.dependencies: expected schema or string array map`;
for (const [key, value] of Object.entries(schema.dependencies)) if (!isStringArray(value) && typeof value !== "boolean" && !isRecord(value)) return `${path}.dependencies.${key}: expected schema or string array`;
}
}
function findJsonSchemaNodeError(schema, path, root, resourceRoot, resourceBaseId) {
if (typeof schema === "boolean") return;
if (!isRecord(schema)) return `${path}: schema must be an object or boolean`;
if (Object.hasOwn(schema, "type")) {
const typeError = validateTypeKeyword(schema.type, path);
if (typeError) return typeError;
}
if (schema.nullable !== void 0) {
if (typeof schema.nullable !== "boolean") return `${path}.nullable: expected boolean`;
if (!Object.hasOwn(schema, "type")) return `${path}.nullable: expected type`;
}
const keywordError = validateSchemaKeywordShapes(schema, path);
if (keywordError) return keywordError;
const currentResourceRoot = typeof schema.$id === "string" ? schema : resourceRoot;
const currentResourceBaseId = typeof schema.$id === "string" ? resolveSchemaId(schema.$id, resourceBaseId) : resourceBaseId;
if (typeof schema.$ref === "string") {
if (!resolveSchemaRef(root, currentResourceRoot, schema.$ref, currentResourceBaseId).found) return `${path}.$ref: unresolved ref`;
}
if (typeof schema.$dynamicRef === "string") {
if (!resolveSchemaRef(root, currentResourceRoot, schema.$dynamicRef, currentResourceBaseId).found) return `${path}.$dynamicRef: unresolved ref`;
}
for (const key of schemaMapKeywords) {
const value = schema[key];
if (value === void 0) continue;
if (!isRecord(value)) return `${path}.${key}: expected schema map`;
for (const [entryKey, entry] of Object.entries(value)) {
const error = findJsonSchemaNodeError(entry, `${path}.${key}.${entryKey}`, root, currentResourceRoot, currentResourceBaseId);
if (error) return error;
}
}
if (isRecord(schema.dependencies)) for (const [key, value] of Object.entries(schema.dependencies)) {
if (isStringArray(value)) continue;
const error = findJsonSchemaNodeError(value, `${path}.dependencies.${key}`, root, currentResourceRoot, currentResourceBaseId);
if (error) return error;
}
for (const key of schemaValueKeywords) {
const value = schema[key];
if (value === void 0 || typeof value === "boolean") continue;
if (Array.isArray(value)) {
if (key !== "items") return `${path}.${key}: expected schema`;
for (const [index, entry] of value.entries()) {
const error = findJsonSchemaNodeError(entry, `${path}.${key}.${index}`, root, currentResourceRoot, currentResourceBaseId);
if (error) return error;
}
continue;
}
const error = findJsonSchemaNodeError(value, `${path}.${key}`, root, currentResourceRoot, currentResourceBaseId);
if (error) return error;
}
for (const key of schemaArrayKeywords) {
const value = schema[key];
if (value === void 0) continue;
if (!Array.isArray(value)) return `${path}.${key}: expected schema array`;
for (const [index, entry] of value.entries()) {
const error = findJsonSchemaNodeError(entry, `${path}.${key}.${index}`, root, currentResourceRoot, currentResourceBaseId);
if (error) return error;
}
}
}
/** Return the first structural JSON Schema error that would make validation/defaulting unsafe. */
function findJsonSchemaShapeError(schema) {
return findJsonSchemaNodeError(schema, "<schema>", schema, schema, void 0);
}
function cloneDefault(value) {
if (value === void 0 || value === null) return value;
return structuredClone(value);
}
function getDefault(schema) {
if (!isRecord(schema) || !Object.hasOwn(schema, "default")) return;
return cloneDefault(schema.default);
}
function schemaWithResourceContext(schema, resourceRoot) {
if (!isRecord(schema) || !isRecord(resourceRoot)) return schema;
return {
...schema,
...typeof resourceRoot.$id === "string" && schema.$id === void 0 ? { $id: resourceRoot.$id } : {},
...isRecord(resourceRoot.$defs) ? { $defs: resourceRoot.$defs } : {},
...isRecord(resourceRoot.definitions) ? { definitions: resourceRoot.definitions } : {}
};
}
function inlineLocalRefsForMatch(schema, root, resourceRoot, resourceBaseId, resolvingRefs = /* @__PURE__ */ new Set()) {
if (Array.isArray(schema)) return schema.map((entry) => inlineLocalRefsForMatch(entry, root, resourceRoot, resourceBaseId, resolvingRefs));
if (!isRecord(schema)) return schema;
const currentResourceRoot = typeof schema.$id === "string" ? schema : resourceRoot;
const currentResourceBaseId = typeof schema.$id === "string" ? resolveSchemaId(schema.$id, resourceBaseId) : resourceBaseId;
if (isRecord(schema) && typeof schema.$ref === "string") {
const refKey = schemaResourceRefKey(currentResourceRoot, schema.$ref, currentResourceBaseId);
const target = resolvingRefs.has(refKey) ? { found: false } : resolveSchemaRef(root, currentResourceRoot, schema.$ref, currentResourceBaseId);
if (target.found) {
const { $ref: _$ref, ...siblingSchema } = schema;
resolvingRefs.add(refKey);
const inlinedTarget = inlineLocalRefsForMatch(target.schema, root, target.resourceRoot, target.resourceBaseId, resolvingRefs);
resolvingRefs.delete(refKey);
if (Object.keys(siblingSchema).length === 0) return inlinedTarget;
return { allOf: [inlinedTarget, inlineLocalRefsForMatch(siblingSchema, root, currentResourceRoot, currentResourceBaseId, resolvingRefs)] };
}
}
return Object.fromEntries(Object.entries(schema).map(([key, value]) => {
if (schemaMapKeywords.has(key) && isRecord(value)) return [key, Object.fromEntries(Object.entries(value).map(([entryKey, entry]) => [entryKey, inlineLocalRefsForMatch(entry, root, currentResourceRoot, currentResourceBaseId, resolvingRefs)]))];
if (key === "dependencies" && isRecord(value)) return [key, Object.fromEntries(Object.entries(value).map(([entryKey, entry]) => [entryKey, isStringArray(entry) ? entry : inlineLocalRefsForMatch(entry, root, currentResourceRoot, currentResourceBaseId, resolvingRefs)]))];
if (schemaValueKeywords.has(key) || schemaArrayKeywords.has(key)) return [key, inlineLocalRefsForMatch(value, root, currentResourceRoot, currentResourceBaseId, resolvingRefs)];
return [key, value];
}));
}
function schemaMatches(schema, value, root, resourceRoot, resourceBaseId) {
try {
return Compile(normalizeJsonSchemaForTypeBox(schemaWithResourceContext(inlineLocalRefsForMatch(schema, root, resourceRoot, resourceBaseId), resourceRoot))).Check(value);
} catch {
return false;
}
}
function applyObjectPropertyDefaults(schema, value, root, resolvingRefs, currentResourceRoot, currentResourceBaseId) {
const properties = isRecord(schema.properties) ? schema.properties : {};
for (const [key, propertySchema] of Object.entries(properties)) {
const currentValue = value[key];
const defaultedValue = applySchemaDefaults(propertySchema, currentValue, root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
if (defaultedValue !== currentValue || currentValue === void 0) {
if (defaultedValue !== void 0) value[key] = defaultedValue;
}
}
const patternMatchedKeys = /* @__PURE__ */ new Set();
if (isRecord(schema.patternProperties)) for (const [pattern, propertySchema] of Object.entries(schema.patternProperties)) {
let regex;
try {
regex = new RegExp(pattern);
} catch {
continue;
}
for (const key of Object.keys(value)) {
if (!regex.test(key)) continue;
patternMatchedKeys.add(key);
value[key] = applySchemaDefaults(propertySchema, value[key], root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
}
}
if (isRecord(schema.additionalProperties)) {
const additionalSchema = schema.additionalProperties;
for (const key of Object.keys(value)) {
if (Object.hasOwn(properties, key) || patternMatchedKeys.has(key)) continue;
value[key] = applySchemaDefaults(additionalSchema, value[key], root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
}
}
return value;
}
function applyObjectDependencyDefaults(schema, value, root, resolvingRefs, currentResourceRoot, currentResourceBaseId) {
let nextValue = value;
if (isRecord(schema.dependencies)) for (const [key, dependencySchema] of Object.entries(schema.dependencies)) {
if (!Object.hasOwn(nextValue, key) || isStringArray(dependencySchema)) continue;
nextValue = applySchemaDefaults(dependencySchema, nextValue, root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
}
if (isRecord(schema.dependentSchemas)) for (const [key, dependentSchema] of Object.entries(schema.dependentSchemas)) {
if (!Object.hasOwn(nextValue, key)) continue;
nextValue = applySchemaDefaults(dependentSchema, nextValue, root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
}
return nextValue;
}
function applyObjectConditionalDefaults(schema, value, root, resolvingRefs, currentResourceRoot, currentResourceBaseId) {
if (!(typeof schema.if === "boolean" || isRecord(schema.if))) return value;
const branch = schemaMatches(schema.if, value, root, currentResourceRoot, currentResourceBaseId) ? schema.then : schema.else;
if (!(typeof branch === "boolean" || isRecord(branch))) return value;
return applySchemaDefaults(branch, value, root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
}
function countSchemaNodes(schema, seen = /* @__PURE__ */ new Set()) {
if (typeof schema === "boolean" || !isRecord(schema) || seen.has(schema)) return 1;
seen.add(schema);
let count = 1;
for (const key of schemaMapKeywords) {
const value = schema[key];
if (!isRecord(value)) continue;
for (const entry of Object.values(value)) count += countSchemaNodes(entry, seen);
}
if (isRecord(schema.dependencies)) {
for (const entry of Object.values(schema.dependencies)) if (!isStringArray(entry)) count += countSchemaNodes(entry, seen);
}
for (const key of schemaValueKeywords) {
const value = schema[key];
if (typeof value === "boolean" || isRecord(value)) {
count += countSchemaNodes(value, seen);
continue;
}
if (key === "items" && Array.isArray(value)) for (const entry of value) count += countSchemaNodes(entry, seen);
}
for (const key of schemaArrayKeywords) {
const value = schema[key];
if (!Array.isArray(value)) continue;
for (const entry of value) count += countSchemaNodes(entry, seen);
}
return count;
}
function applyObjectApplicatorDefaults(schema, value, root, resolvingRefs, currentResourceRoot, currentResourceBaseId) {
let nextValue = applyObjectPropertyAndDependencyDefaults(schema, value, root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
nextValue = applyObjectConditionalDefaults(schema, nextValue, root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
return applyObjectPropertyAndDependencyDefaults(schema, nextValue, root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
}
function applyObjectPropertyAndDependencyDefaults(schema, value, root, resolvingRefs, currentResourceRoot, currentResourceBaseId) {
let nextValue = value;
const maxIterations = countSchemaNodes(schema);
for (let index = 0; index < maxIterations; index++) {
const before = JSON.stringify(nextValue);
nextValue = applyObjectPropertyDefaults(schema, nextValue, root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
nextValue = applyObjectDependencyDefaults(schema, nextValue, root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
if (JSON.stringify(nextValue) === before) break;
}
return nextValue;
}
function applySchemaDefaults(schema, valueInput, root = schema, resolvingRefs = /* @__PURE__ */ new Set(), resourceRoot = root, resourceBaseId) {
let value = valueInput;
if (value === void 0) {
const defaultValue = getDefault(schema);
if (defaultValue !== void 0) value = defaultValue;
}
if (!isRecord(schema)) return value;
const currentResourceRoot = typeof schema.$id === "string" ? schema : resourceRoot;
const currentResourceBaseId = typeof schema.$id === "string" ? resolveSchemaId(schema.$id, resourceBaseId) : resourceBaseId;
let nextValue = value;
const refKey = typeof schema.$ref === "string" ? schemaResourceRefKey(currentResourceRoot, schema.$ref, currentResourceBaseId) : void 0;
if (typeof schema.$ref === "string" && refKey !== void 0 && !resolvingRefs.has(refKey)) {
const target = resolveSchemaRef(root, currentResourceRoot, schema.$ref, currentResourceBaseId);
if (target.found) {
resolvingRefs.add(refKey);
nextValue = applySchemaDefaults(target.schema, nextValue, root, resolvingRefs, target.resourceRoot, target.resourceBaseId);
resolvingRefs.delete(refKey);
}
}
const composedSchemas = [...Array.isArray(schema.allOf) ? schema.allOf : []];
for (const branch of composedSchemas) nextValue = applySchemaDefaults(branch, nextValue, root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
const hasObjectApplicators = isRecord(schema.properties) || isRecord(schema.patternProperties) || isRecord(schema.additionalProperties) || isRecord(schema.dependencies) || isRecord(schema.dependentSchemas) || typeof schema.if === "boolean" || isRecord(schema.if);
if ((schemaTypeIncludes(schema, "object") || hasObjectApplicators) && isRecord(nextValue)) {
nextValue = applyObjectApplicatorDefaults(schema, nextValue, root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
return nextValue;
}
if ((schemaTypeIncludes(schema, "array") || schema.items !== void 0 || schema.prefixItems !== void 0) && Array.isArray(nextValue)) {
const tupleSchemas = Array.isArray(schema.prefixItems) ? schema.prefixItems : Array.isArray(schema.items) ? schema.items : null;
if (tupleSchemas) {
const result = nextValue.slice();
for (const [index, itemSchema] of tupleSchemas.entries()) {
const defaultedValue = applySchemaDefaults(itemSchema, result[index], root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
if (defaultedValue !== void 0) result[index] = defaultedValue;
}
const restSchema = isRecord(schema.items) ? schema.items : isRecord(schema.additionalItems) ? schema.additionalItems : null;
if (restSchema) for (let index = tupleSchemas.length; index < result.length; index++) result[index] = applySchemaDefaults(restSchema, result[index], root, resolvingRefs, currentResourceRoot, currentResourceBaseId);
return result;
}
if (!isRecord(schema.items)) return nextValue;
return nextValue.map((item) => applySchemaDefaults(schema.items, item, root, resolvingRefs, currentResourceRoot, currentResourceBaseId));
}
return nextValue;
}
/** Apply schema defaults to a config value while preserving caller-owned value shape. */
function applyJsonSchemaDefaults(schema, value) {
return applySchemaDefaults(schema, value);
}
//#endregion
export { findJsonSchemaShapeError as n, normalizeJsonSchemaForTypeBox as r, applyJsonSchemaDefaults as t };