| import * as Equal from "../../Equal.js"; | |
| import * as Equivalence from "../../Equivalence.js"; | |
| import { memoize } from "../../Function.js"; | |
| import * as Predicate from "../../Predicate.js"; | |
| import * as SchemaAST from "../../SchemaAST.js"; | |
| import * as SchemaParser from "../../SchemaParser.js"; | |
| import { errorWithPath } from "../errors.js"; | |
| import * as InternalAnnotations from "./annotations.js"; | |
| /** @internal */ | |
| export const toEquivalence = /*#__PURE__*/memoize(ast => { | |
| return recur(ast, []); | |
| }); | |
| function recur(ast, path) { | |
| // --------------------------------------------- | |
| // handle annotations | |
| // --------------------------------------------- | |
| const annotation = InternalAnnotations.resolve(ast)?.["toEquivalence"]; | |
| if (annotation) { | |
| return annotation(SchemaAST.isDeclaration(ast) ? ast.typeParameters.map(tp => recur(tp, path)) : []); | |
| } | |
| switch (ast._tag) { | |
| case "Never": | |
| throw errorWithPath(`Unsupported AST ${ast._tag}`, path); | |
| case "Declaration": | |
| case "Null": | |
| case "Undefined": | |
| case "Void": | |
| case "Unknown": | |
| case "Any": | |
| case "String": | |
| case "Number": | |
| case "Boolean": | |
| case "BigInt": | |
| case "Symbol": | |
| case "Literal": | |
| case "UniqueSymbol": | |
| case "ObjectKeyword": | |
| case "Enum": | |
| case "TemplateLiteral": | |
| return Equal.equals; | |
| case "Arrays": | |
| { | |
| const elements = ast.elements.map((e, i) => recur(e, [...path, i])); | |
| const len = ast.elements.length; | |
| const rest = ast.rest.map((r, i) => recur(r, [...path, len + i])); | |
| return Equivalence.make((a, b) => { | |
| if (!Array.isArray(a) || !Array.isArray(b)) { | |
| return false; | |
| } | |
| const len = a.length; | |
| if (len !== b.length) { | |
| return false; | |
| } | |
| // --------------------------------------------- | |
| // handle elements | |
| // --------------------------------------------- | |
| let i = 0; | |
| for (; i < Math.min(len, ast.elements.length); i++) { | |
| if (!elements[i](a[i], b[i])) { | |
| return false; | |
| } | |
| } | |
| // --------------------------------------------- | |
| // handle rest element | |
| // --------------------------------------------- | |
| if (rest.length > 0) { | |
| const [head, ...tail] = rest; | |
| for (; i < len - tail.length; i++) { | |
| if (!head(a[i], b[i])) { | |
| return false; | |
| } | |
| } | |
| // --------------------------------------------- | |
| // handle post rest elements | |
| // --------------------------------------------- | |
| for (let j = 0; j < tail.length; j++) { | |
| i += j; | |
| if (!tail[j](a[i], b[i])) { | |
| return false; | |
| } | |
| } | |
| } | |
| return true; | |
| }); | |
| } | |
| case "Objects": | |
| { | |
| if (ast.propertySignatures.length === 0 && ast.indexSignatures.length === 0) { | |
| return Equal.equals; | |
| } | |
| const propertySignatures = ast.propertySignatures.map(ps => recur(ps.type, [...path, ps.name])); | |
| const indexSignatures = ast.indexSignatures.map(is => recur(is.type, path)); | |
| return Equivalence.make((a, b) => { | |
| if (!Predicate.isObject(a) || !Predicate.isObject(b)) { | |
| return false; | |
| } | |
| // --------------------------------------------- | |
| // handle property signatures | |
| // --------------------------------------------- | |
| for (let i = 0; i < propertySignatures.length; i++) { | |
| const ps = ast.propertySignatures[i]; | |
| const name = ps.name; | |
| const aHas = Object.hasOwn(a, name); | |
| const bHas = Object.hasOwn(b, name); | |
| if (SchemaAST.isOptional(ps.type)) { | |
| if (aHas !== bHas) { | |
| return false; | |
| } | |
| } | |
| if (aHas && bHas && !propertySignatures[i](a[name], b[name])) { | |
| return false; | |
| } | |
| } | |
| // --------------------------------------------- | |
| // handle index signatures | |
| // --------------------------------------------- | |
| for (let i = 0; i < indexSignatures.length; i++) { | |
| const is = ast.indexSignatures[i]; | |
| const aKeys = SchemaAST.getIndexSignatureKeys(a, is.parameter); | |
| const bKeys = SchemaAST.getIndexSignatureKeys(b, is.parameter); | |
| if (aKeys.length !== bKeys.length) return false; | |
| for (let j = 0; j < aKeys.length; j++) { | |
| const key = aKeys[j]; | |
| if (!Object.hasOwn(b, key) || !indexSignatures[i](a[key], b[key])) { | |
| return false; | |
| } | |
| } | |
| } | |
| return true; | |
| }); | |
| } | |
| case "Union": | |
| return Equivalence.make((a, b) => { | |
| const candidates = SchemaAST.getCandidates(a, ast.types); | |
| const types = candidates.map(SchemaParser._is); | |
| for (let i = 0; i < candidates.length; i++) { | |
| const is = types[i]; | |
| if (is(a) && is(b)) { | |
| return recur(candidates[i], path)(a, b); | |
| } | |
| } | |
| return false; | |
| }); | |
| case "Suspend": | |
| { | |
| const get = SchemaAST.memoizeThunk(() => recur(ast.thunk(), path)); | |
| return Equivalence.make((a, b) => get()(a, b)); | |
| } | |
| } | |
| } | |
| //# sourceMappingURL=equivalence.js.map |
Xet Storage Details
- Size:
- 5.43 kB
- Xet hash:
- 3f34981131bef998ca0a2d9d8eed80deaa00802b81a529493219e18a797a61e0
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.