UNPKG

@stryke/json

Version:

A package containing JSON parsing/stringify utilities used by Storm Software.

276 lines (274 loc) 15.4 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); let _stryke_type_checks_is_set_object = require("@stryke/type-checks/is-set-object"); let _stryke_type_checks_is_string = require("@stryke/type-checks/is-string"); let _stryke_type_checks_is_function = require("@stryke/type-checks/is-function"); let _stryke_type_checks_is_object = require("@stryke/type-checks/is-object"); //#region src/schema.ts /** * Type guard for {@link JsonSchemaAllOfType} * * @param schema - The schema to check * @returns True if the schema is a {@link JsonSchemaAllOfType}, false otherwise */ function isJsonSchemaAllOfType(schema) { if ((0, _stryke_type_checks_is_set_object.isSetObject)(schema) && "type" in schema && schema.type === "string") return false; return (0, _stryke_type_checks_is_set_object.isSetObject)(schema) && "allOf" in schema; } /** * Type guard for {@link JsonSchemaAnyOfType} * * @param schema - The schema to check * @returns True if the schema is a {@link JsonSchemaAnyOfType}, false otherwise */ function isJsonSchemaAnyOfType(schema) { return (0, _stryke_type_checks_is_set_object.isSetObject)(schema) && "anyOf" in schema && Array.isArray(schema.anyOf); } /** * Type guard for {@link JsonSchemaObjectType} * * @param schema - The schema to check * @returns True if the schema is a {@link JsonSchemaObjectType}, false otherwise */ function isJsonSchemaObjectType(schema) { return (0, _stryke_type_checks_is_set_object.isSetObject)(schema) && "type" in schema && schema.type === "object"; } /** * Type guard for {@link JsonSchemaStringType} * * @param schema - The schema to check * @returns True if the schema is a {@link JsonSchemaStringType}, false otherwise */ function isJsonSchemaStringType(schema) { return (0, _stryke_type_checks_is_set_object.isSetObject)(schema) && "type" in schema && schema.type === "string"; } /** * Type guard for {@link JsonSchemaNumberType} * * @param schema - The schema to check * @returns True if the schema is a {@link JsonSchemaNumberType}, false otherwise */ function isJsonSchemaNumberType(schema) { return (0, _stryke_type_checks_is_set_object.isSetObject)(schema) && "type" in schema && (schema.type === "number" || schema.type === "integer"); } /** * Type guard for {@link JsonSchemaBooleanType} * * @param schema - The schema to check * @returns True if the schema is a {@link JsonSchemaBooleanType}, false otherwise */ function isJsonSchemaBooleanType(schema) { return (0, _stryke_type_checks_is_set_object.isSetObject)(schema) && "type" in schema && schema.type === "boolean"; } /** * Type guard for {@link JsonSchemaArrayType} * * @param schema - The schema to check * @returns True if the schema is a {@link JsonSchemaArrayType}, false otherwise */ function isJsonSchemaArrayType(schema) { return (0, _stryke_type_checks_is_set_object.isSetObject)(schema) && "type" in schema && schema.type === "array" && "items" in schema; } /** * Type guard for {@link JsonSchemaTupleType} * * @param schema - The schema to check * @returns True if the schema is a {@link JsonSchemaTupleType}, false otherwise */ function isJsonSchemaTupleType(schema) { return (0, _stryke_type_checks_is_set_object.isSetObject)(schema) && "type" in schema && schema.type === "array" && "items" in schema && Array.isArray(schema.items); } /** * Type guard for {@link JsonSchemaPrimitiveLiteralType} * * @param schema - The schema to check * @returns True if the schema is a {@link JsonSchemaPrimitiveLiteralType}, false otherwise */ function isJsonSchemaPrimitiveLiteralType(schema) { if (!(0, _stryke_type_checks_is_set_object.isSetObject)(schema) || !("type" in schema)) return false; const { type } = schema; return (type === "string" || type === "number" || type === "integer" || type === "boolean") && "const" in schema; } /** * Type guard for {@link JsonSchemaLiteralType} * * @param schema - The schema to check * @returns True if the schema is a {@link JsonSchemaLiteralType}, false otherwise */ function isJsonSchemaLiteralType(schema) { if (isJsonSchemaPrimitiveLiteralType(schema)) return true; if (!(0, _stryke_type_checks_is_set_object.isSetObject)(schema) || !("type" in schema)) return false; return schema.type === "object" || schema.type === "array"; } function isJsonSchemaRecordType(schema) { return (0, _stryke_type_checks_is_set_object.isSetObject)(schema) && "type" in schema && schema.type === "object" && "additionalProperties" in schema && (0, _stryke_type_checks_is_set_object.isSetObject)(schema.additionalProperties) && "propertyNames" in schema && (0, _stryke_type_checks_is_set_object.isSetObject)(schema.propertyNames); } function isJsonSchemaMetadata(schema) { return (0, _stryke_type_checks_is_set_object.isSetObject)(schema) && (!("$id" in schema) || (0, _stryke_type_checks_is_string.isString)(schema.$id)) && (!("$schema" in schema) || (0, _stryke_type_checks_is_string.isString)(schema.$schema)) && (!("$comment" in schema) || (0, _stryke_type_checks_is_string.isString)(schema.$comment)) && (!("$defs" in schema) || (0, _stryke_type_checks_is_object.isObject)(schema.$defs)) && (!("$dynamicRef" in schema) || (0, _stryke_type_checks_is_string.isString)(schema.$dynamicRef)) && (!("$dynamicAnchor" in schema) || (0, _stryke_type_checks_is_string.isString)(schema.$dynamicAnchor)) && (!("name" in schema) || (0, _stryke_type_checks_is_string.isString)(schema.name)) && (!("title" in schema) || (0, _stryke_type_checks_is_string.isString)(schema.title)) && (!("description" in schema) || (0, _stryke_type_checks_is_string.isString)(schema.description)) && (!("alias" in schema) || (0, _stryke_type_checks_is_string.isString)(schema.alias) || Array.isArray(schema.alias) && schema.alias.every(_stryke_type_checks_is_string.isString)); } /** * Type guard to check if a value is a {@link StandardJSONSchemaV1 | Standard JSON Schema}. * * @remarks * This function checks if the value has the structure of a Standard JSON Schema, which includes a `~standard` property with a `jsonSchema` object that has `input` and `output` functions. * * @see https://standardschema.dev/json-schema * * @param value - The value to check. * @returns True if the value is a {@link StandardJSONSchemaV1 | Standard JSON Schema}, false otherwise. */ function isStandardJsonSchema(value) { return (0, _stryke_type_checks_is_set_object.isSetObject)(value) && "~standard" in value && (0, _stryke_type_checks_is_set_object.isSetObject)(value["~standard"]) && "jsonSchema" in value["~standard"] && (0, _stryke_type_checks_is_set_object.isSetObject)(value["~standard"].jsonSchema) && "input" in value["~standard"].jsonSchema && (0, _stryke_type_checks_is_function.isFunction)(value["~standard"].jsonSchema.input) && "output" in value["~standard"].jsonSchema && (0, _stryke_type_checks_is_function.isFunction)(value["~standard"].jsonSchema.output); } /** * Merges multiple {@link JsonSchemaMetadata} objects into a single object, combining their properties. If there are conflicting properties, the last one will take precedence. * * @param schemas - The schemas to merge * @returns The merged {@link JsonSchemaMetadata} object, or undefined if no valid schemas are provided */ function mergeMetadataSchemaSafe(...schemas) { const filtered = schemas.filter(isJsonSchemaMetadata); if (filtered.length === 0) return; let result = {}; for (const schema of filtered) result = { ...result, ...schema, $defs: { ...result.$defs, ...schema.$defs } }; return result; } /** * Merges multiple {@link JsonSchemaMetadata} objects into a single object, combining their properties. If there are conflicting properties, the last one will take precedence. * * @remarks * If any of the provided schemas are not valid {@link JsonSchemaMetadata} objects, or if no valid schemas are provided for merging, this function will throw an error. Use {@link mergeMetadataSchemaSafe} if you want to ignore invalid schemas instead. * * @param schemas - The schemas to merge * @returns The merged {@link JsonSchemaMetadata} object * @throws Error if any of the provided schemas are not valid {@link JsonSchemaMetadata} objects, or if no valid schemas are provided for merging. Use {@link mergeMetadataSchemaSafe} if you want to ignore invalid schemas instead. */ function mergeMetadataSchemaStrict(...schemas) { const filtered = schemas.filter(isJsonSchemaMetadata); if (filtered.length !== schemas.length) throw new Error(`All schemas must be of type JsonSchemaMetadata - found ${schemas.length - filtered.length} invalid schema types`); return mergeMetadataSchemaSafe(...schemas); } /** * Merges multiple {@link JsonSchemaObjectType} schemas into a single schema, combining their properties and required fields. If there are no valid object type schemas, throws an error. * * @remarks If there are overlapping properties, the last schema's property definition will take precedence. Required fields from all schemas will be combined, and duplicates will be removed. If all of the provided schemas are not valid {@link JsonSchemaObjectType} objects, or if no valid object type schemas are provided for merging, this function will throw an error. Use {@link mergeObjectTypeSchemaSafe} if you want to ignore invalid schemas instead. * * @param schemas - The schemas to merge * @returns The merged {@link JsonSchemaMetadata} object * @throws Error if all of the provided schemas are not valid {@link JsonSchemaObjectType} objects, or if no valid object type schemas are provided for merging. Use {@link mergeObjectTypeSchemaSafe} if you want to ignore invalid schemas instead. */ function mergeMetadataSchema(...schemas) { const merged = mergeMetadataSchemaSafe(...schemas); if (!merged) throw new Error("No valid JsonSchemaMetadata objects provided for merge"); return merged; } /** * Merges multiple {@link JsonSchemaMetadata} objects into a single object, combining their properties. If there are conflicting properties, the last one will take precedence. * * @param schemas - The schemas to merge * @returns The merged {@link JsonSchemaMetadata} object, or undefined if no valid schemas are provided */ function mergeObjectTypeSchemaSafe(...schemas) { const filtered = schemas.filter(isJsonSchemaObjectType); if (filtered.length === 0) return; const mergedProperties = {}; const mergedRequired = /* @__PURE__ */ new Set(); for (const schema of filtered) { Object.assign(mergedProperties, schema.properties); if (schema.required) for (const prop of schema.required) mergedRequired.add(prop); } return { ...mergeObjectTypeSchemaSafe(...schemas), type: "object", properties: mergedProperties, required: Array.from(mergedRequired) }; } /** * Merges multiple {@link JsonSchemaObjectType} objects into a single object, combining their properties. If there are conflicting properties, the last one will take precedence. * * @remarks * If any of the provided schemas are not valid {@link JsonSchemaObjectType} objects, or if no valid schemas are provided for merging, this function will throw an error. Use {@link mergeObjectTypeSchemaSafe} if you want to ignore invalid schemas instead. * * @param schemas - The schemas to merge * @returns The merged {@link JsonSchemaObjectType} object * @throws Error if any of the provided schemas are not valid {@link JsonSchemaObjectType} objects, or if no valid schemas are provided for merging. Use {@link mergeObjectTypeSchemaSafe} if you want to ignore invalid schemas instead. */ function mergeObjectTypeSchemaStrict(...schemas) { const filtered = schemas.filter(isJsonSchemaObjectType); if (filtered.length !== schemas.length) throw new Error(`All schemas must be of type JsonSchemaObjectType - found ${schemas.length - filtered.length} invalid schema types`); return mergeObjectTypeSchemaSafe(...schemas); } /** * Merges multiple {@link JsonSchemaObjectType} schemas into a single schema, combining their properties and required fields. If there are no valid object type schemas, throws an error. * * @remarks If there are overlapping properties, the last schema's property definition will take precedence. Required fields from all schemas will be combined, and duplicates will be removed. If all of the provided schemas are not valid {@link JsonSchemaObjectType} objects, or if no valid object type schemas are provided for merging, this function will throw an error. Use {@link mergeObjectTypeSchemaSafe} if you want to ignore invalid schemas instead. * * @param schemas - The schemas to merge * @returns The merged {@link JsonSchemaObjectType} object * @throws Error if all of the provided schemas are not valid {@link JsonSchemaObjectType} objects, or if no valid object type schemas are provided for merging. Use {@link mergeObjectTypeSchemaSafe} if you want to ignore invalid schemas instead. */ function mergeObjectTypeSchema(...schemas) { const merged = mergeObjectTypeSchemaSafe(...schemas); if (!merged) throw new Error("No valid JsonSchemaObjectType objects provided for merge"); return merged; } /** * Extracts a {@link JsonSchemaObjectType} from a given {@link JsonSchemaType}, if it exists. * * @param schema - The schema to extract the object type from * @returns The extracted {@link JsonSchemaObjectType}, or undefined if it does not exist */ function extractObjectTypeSchema(schema) { if (isJsonSchemaObjectType(schema)) return schema; if (isJsonSchemaAllOfType(schema)) { const extracted = schema.allOf.map(extractObjectTypeSchema).filter((s) => s !== void 0); if (extracted.length === 0) return; return mergeObjectTypeSchemaSafe(...extracted); } if (isJsonSchemaAnyOfType(schema)) { const extracted = schema.anyOf.map(extractObjectTypeSchema).filter((s) => s !== void 0); if (extracted.length === 0 || extracted.length !== schema.anyOf.length) return; const [first, ...rest] = extracted; const commonProperties = {}; for (const [key, value] of Object.entries(first.properties)) if (rest.every((s) => s.properties && key in s.properties)) commonProperties[key] = value; return { type: "object", properties: commonProperties, required: (first.required ?? []).filter((prop) => rest.every((s) => s.required?.includes(prop))) }; } if (isJsonSchemaRecordType(schema)) return { type: "object", properties: {}, additionalProperties: schema.additionalProperties, required: [] }; } //#endregion exports.extractObjectTypeSchema = extractObjectTypeSchema; exports.isJsonSchemaAllOfType = isJsonSchemaAllOfType; exports.isJsonSchemaAnyOfType = isJsonSchemaAnyOfType; exports.isJsonSchemaArrayType = isJsonSchemaArrayType; exports.isJsonSchemaBooleanType = isJsonSchemaBooleanType; exports.isJsonSchemaLiteralType = isJsonSchemaLiteralType; exports.isJsonSchemaMetadata = isJsonSchemaMetadata; exports.isJsonSchemaNumberType = isJsonSchemaNumberType; exports.isJsonSchemaObjectType = isJsonSchemaObjectType; exports.isJsonSchemaPrimitiveLiteralType = isJsonSchemaPrimitiveLiteralType; exports.isJsonSchemaRecordType = isJsonSchemaRecordType; exports.isJsonSchemaStringType = isJsonSchemaStringType; exports.isJsonSchemaTupleType = isJsonSchemaTupleType; exports.isStandardJsonSchema = isStandardJsonSchema; exports.mergeMetadataSchema = mergeMetadataSchema; exports.mergeMetadataSchemaSafe = mergeMetadataSchemaSafe; exports.mergeMetadataSchemaStrict = mergeMetadataSchemaStrict; exports.mergeObjectTypeSchema = mergeObjectTypeSchema; exports.mergeObjectTypeSchemaSafe = mergeObjectTypeSchemaSafe; exports.mergeObjectTypeSchemaStrict = mergeObjectTypeSchemaStrict;