UNPKG

typia

Version:

Superfast runtime validators with only one line

186 lines (183 loc) 6.57 kB
import { MetadataTypeTagFactory } from '../../MetadataTypeTagFactory.mjs'; import { explore_metadata } from './explore_metadata.mjs'; import { iterate_metadata } from './iterate_metadata.mjs'; const iterate_metadata_intersection = (props) => { if (props.intersected === true) return false; else if (props.type.isIntersection() === false) return false; // CONSTRUCT FAKE METADATA LIST const commit = props.collection.clone(); props.collection["options"] = undefined; const fakeErrors = []; const children = props.type.types.map((t) => explore_metadata({ ...props, options: { ...props.options, absorb: true, functional: false, }, collection: props.collection, errors: fakeErrors, type: t, explore: { ...props.explore, aliased: false, }, intersected: false, })); // ERROR OR ANY TYPE CASE const escape = (out) => { Object.assign(props.collection, commit); return out; }; if (fakeErrors.length) { props.errors.push(...fakeErrors); return escape(true); } else if (children.length === 0) return escape(false); else if (children.some((m) => m.any === true || m.size() === 0)) return escape(false); // PREPARE MEATDATAS AND TAGS const indexes = []; const metadatas = []; const tagObjects = []; children.forEach((child, i) => { if (child.size() === 1 && child.objects.length === 1 && MetadataTypeTagFactory.is(child.objects[0].type)) tagObjects.push(child.objects[0].type); else { indexes.push(i); metadatas.push(child); } }); const nonsensible = () => { props.errors.push({ name: children.map((c) => c.getName()).join(" & "), explore: { ...props.explore }, messages: ["nonsensible intersection"], }); return escape(true); }; // NO METADATA CASE if (metadatas.length === 0) if (tagObjects.length !== 0) { props.errors.push({ name: children.map((c) => c.getName()).join(" & "), explore: { ...props.explore }, messages: ["type tag cannot be standalone"], }); return escape(true); } else return escape(false); // ONLY OBJECTS CASE else if (metadatas.every((m) => m.objects.length === 1) && tagObjects.length === 0) return escape(false); else if (metadatas.length !== 1) { const indexes = metadatas .map((m, i) => m.size() === 1 && m.objects.length === 1 && (m.objects[0].type.properties.length === 0 || m.objects[0].type.properties.every((p) => p.value.optional === true)) ? i : null) .filter((i) => i !== null); if (indexes.length && metadatas.length !== indexes.length) for (const i of indexes.reverse()) metadatas.splice(i, 1); else return nonsensible(); } else if (metadatas.some((m) => m.size() !== 1)) return nonsensible(); const candidates = new Map(); const assigners = []; for (const meta of metadatas) { for (const a of meta.atomics) { candidates.set(a.type, a.type); assigners.push((tags) => props.metadata.atomics .find((atom) => atom.type === a.type) ?.tags.push(tags)); } for (const c of meta.constants) for (const v of c.values) { candidates.set(c.type, c.type); assigners.push((tags) => props.metadata.constants .find((constant) => constant.type === c.type) ?.values.find((value) => value === v) ?.tags?.push(tags)); } for (const t of meta.templates) { candidates.set("string", "string"); assigners.push((tags) => props.metadata.templates .find((tpl) => tpl.getBaseName() === t.getBaseName()) ?.tags.push(tags)); } if (meta.objects.length) { candidates.set("object", "object"); assigners.push((tags) => props.metadata.objects.at(-1)?.tags.push(tags)); } if (meta.arrays.length) { candidates.set("array", "array"); assigners.push((tags) => props.metadata.arrays.at(-1)?.tags.push(tags)); } if (meta.tuples.length) candidates.set("invalid", "tuple"); for (const n of meta.natives) { candidates.set(`native::${n.name}`, "object"); assigners.push((tags) => props.metadata.natives .find((native) => native.name === n.name) ?.tags.push(tags)); } for (const s of meta.sets) { candidates.set(`set::${s.value.getName()}`, "object"); assigners.push((tags) => props.metadata.sets .find((set) => set.value.getName() === s.value.getName()) ?.tags.push(tags)); } for (const e of meta.maps) { candidates.set(`map::${e.key.getName()}::${e.value.getName()}`, "object"); assigners.push((tags) => props.metadata.maps .find((map) => map.key.getName() === e.key.getName() && map.value.getName() === e.value.getName()) ?.tags.push(tags)); } } if (candidates.size !== 1 || candidates.has("nonsensible") // || // (candidates.size !== 1 && // Array.from(candidates.keys()).some((v) => v !== "object")) ) return nonsensible(); const tags = MetadataTypeTagFactory.analyze({ errors: props.errors, type: candidates.values().next().value, objects: tagObjects, explore: props.explore, }); Object.assign(props.collection, commit); iterate_metadata({ ...props, type: props.type.types[indexes[0]], options: { ...props.options, functional: false, }, explore: { ...props.explore, aliased: false, escaped: false, }, intersected: true, }); if (tags.length) assigners.forEach((fn) => fn(tags)); return true; }; export { iterate_metadata_intersection }; //# sourceMappingURL=iterate_metadata_intersection.mjs.map