UNPKG

@nestia/sdk

Version:

Nestia SDK and Swagger generator

348 lines 15.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.JsonSchemasProgrammer = exports.HttpFormDataProgrammer = exports.HttpParameterProgrammer = exports.HttpHeadersProgrammer = exports.HttpQueryProgrammer = exports.JsonMetadataFactory = exports.MetadataFactory = exports.MetadataSchema = exports.MetadataComponents = exports.isSoleLiteralOf = exports.emptyOf = exports.nameOf = exports.sizeOf = void 0; // --------------------------------------------------------------------- // Metadata utility functions — read pre-baked fields, no class wrapping. // --------------------------------------------------------------------- /** `MetadataSchema.size()` → reads the pre-baked `size` field. */ const sizeOf = (m) => { var _a; return (_a = m.size) !== null && _a !== void 0 ? _a : 0; }; exports.sizeOf = sizeOf; /** `MetadataSchema.getName()` → reads the pre-baked `name` field. */ const nameOf = (m) => { var _a; return (_a = m.name) !== null && _a !== void 0 ? _a : ""; }; exports.nameOf = nameOf; /** `MetadataSchema.empty()` → reads the pre-baked `empty` field. */ const emptyOf = (m) => { var _a; return (_a = m.empty) !== null && _a !== void 0 ? _a : false; }; exports.emptyOf = emptyOf; /** * Equivalent of the legacy `MetadataSchema.isSoleLiteral()` method: `true` when * the schema represents exactly one constant literal value and nothing else. * Used by sdk's type printer to fall back to literal emission instead of a * union. */ const isSoleLiteralOf = (m) => { if (m.any) return false; if (m.nullable) return false; if (m.functions.length !== 0) return false; if (m.atomics.length !== 0) return false; if (m.templates.length !== 0) return false; if (m.arrays.length !== 0) return false; if (m.tuples.length !== 0) return false; if (m.objects.length !== 0) return false; if (m.aliases.length !== 0) return false; if (m.natives.length !== 0) return false; if (m.sets.length !== 0) return false; if (m.maps.length !== 0) return false; if (m.rest !== null) return false; if (m.escaped !== null) return false; if (m.constants.length !== 1) return false; return m.constants[0].values.length === 1; }; exports.isSoleLiteralOf = isSoleLiteralOf; // --------------------------------------------------------------------- // `MetadataComponents.from(plain)` — namespace utility, not a class. // --------------------------------------------------------------------- var MetadataComponents; (function (MetadataComponents) { MetadataComponents.from = (plain) => { const dictionary = { objects: new Map(plain.objects.map((o) => [o.name, o])), aliases: new Map(plain.aliases.map((a) => [a.name, a])), arrays: new Map(plain.arrays.map((a) => [a.name, a])), tuples: new Map(plain.tuples.map((t) => [t.name, t])), }; return Object.assign({}, plain, { dictionary }); }; })(MetadataComponents || (exports.MetadataComponents = MetadataComponents = {})); // --------------------------------------------------------------------- // `MetadataSchema.from(plain, _dictionary)` — passthrough. // --------------------------------------------------------------------- var MetadataSchema; (function (MetadataSchema) { /** * Walks the metadata tree and attaches the resolved `.type` field to every * `IReference` it encounters, using the supplied dictionary as the lookup * index. This is idempotent — references whose `.type` has already been * resolved are left alone — and mutates the input, matching the in-place * resolution model `@typia/core` 12.x used. */ MetadataSchema.from = (plain, dictionary) => { if (dictionary !== undefined) { attachTypes(plain, dictionary, new WeakSet()); } return plain; }; })(MetadataSchema || (exports.MetadataSchema = MetadataSchema = {})); /** * The walk tracks visited _targets_ (the IObjectType / IArrayType / … instances * reached through the dictionary), not the wrapper schemas. Wrapper schemas are * reconstructed on the JS side and are not shared across recursive references, * so a `visited<IMetadataSchema>` set never matches and the walk would recurse * forever on cycles like `interface Node { children: Node[] }`. */ const attachTypes = (schema, dict, visited) => { var _a, _b, _c; if (schema === null || schema === undefined) return; attachReferences(schema.arrays, dict.arrays, visited, (target) => attachTypes(target.value, dict, visited)); attachReferences(schema.tuples, dict.tuples, visited, (target) => { for (const elem of target.elements) attachTypes(elem, dict, visited); }); attachReferences(schema.objects, dict.objects, visited, (target) => { for (const prop of target.properties) attachTypes(prop.value, dict, visited); }); attachReferences(schema.aliases, dict.aliases, visited, (target) => attachTypes(target.value, dict, visited)); for (const fn of (_a = schema.functions) !== null && _a !== void 0 ? _a : []) { for (const param of fn.parameters) attachTypes(param.type, dict, visited); attachTypes(fn.output, dict, visited); } for (const set of (_b = schema.sets) !== null && _b !== void 0 ? _b : []) attachTypes(set.value, dict, visited); for (const map of (_c = schema.maps) !== null && _c !== void 0 ? _c : []) { attachTypes(map.key, dict, visited); attachTypes(map.value, dict, visited); } if (schema.rest) attachTypes(schema.rest, dict, visited); if (schema.escaped) { attachTypes(schema.escaped.original, dict, visited); attachTypes(schema.escaped.returns, dict, visited); } }; const attachReferences = (refs, index, visited, walk) => { if (!refs) return; for (const ref of refs) { const mutable = ref; if (mutable.type === undefined) { const target = index.get(ref.name); if (target !== undefined) mutable.type = target; } if (mutable.type !== undefined && visited.has(mutable.type) === false) { visited.add(mutable.type); walk(mutable.type); } } }; // --------------------------------------------------------------------- // Validators — the typia native transform already enforces most of the // invariants the legacy `@typia/core` 12.x helpers re-checked at runtime, // but a few JSON-serialization constraints (bare `bigint` payloads, etc.) // are SDK-policy choices that the SDK still has to flag itself. // --------------------------------------------------------------------- var MetadataFactory; (function (MetadataFactory) { /** * Walks the metadata tree once, invoking the provided validator on each * visited node, and accumulates the produced messages into `IError` entries. * The walk skips back-edges through references so cyclic structures * terminate. This is a faithful reimplementation of the legacy `@typia/core` * walker, kept lean: the typia native transform has already validated * structural invariants, so the validator is only called for SDK-side policy * checks (JSON-serializability, query/header atomic-only rules, …). */ MetadataFactory.validate = (props) => { const errors = []; // Tracks visited *targets* (IObjectType / IArrayType / IAliasType / // ITupleType) so recursive schemas like `interface Node { children: // Node[] }` terminate. Wrapper IMetadataSchema instances are not // shared across recursive references, so they cannot stand in for // the visit marker. const visited = new WeakSet(); const visit = (metadata, explore) => { var _a, _b; var _c; const messages = props.functor({ metadata, explore }); if (messages.length) errors.push({ name: (0, exports.nameOf)(metadata), explore, messages }); for (const obj of metadata.objects) { const type = obj.type; if (type === undefined || visited.has(type)) continue; visited.add(type); for (const prop of type.properties) visit(prop.value, { object: type, property: (0, exports.nameOf)(prop.key) || String((_c = (_b = (_a = prop.key.constants[0]) === null || _a === void 0 ? void 0 : _a.values[0]) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : ""), parameter: null, output: explore.output, }); } for (const arr of metadata.arrays) { const type = arr.type; if (type === undefined || visited.has(type)) continue; visited.add(type); visit(type.value, explore); } for (const tuple of metadata.tuples) { const type = tuple.type; if (type === undefined || visited.has(type)) continue; visited.add(type); for (const elem of type.elements) visit(elem, explore); } for (const alias of metadata.aliases) { const type = alias.type; if (type === undefined || visited.has(type)) continue; visited.add(type); visit(type.value, explore); } if (metadata.escaped) { visit(metadata.escaped.original, explore); visit(metadata.escaped.returns, explore); } }; visit(props.metadata, { object: null, property: null, parameter: null, output: false, }); return errors; }; })(MetadataFactory || (exports.MetadataFactory = MetadataFactory = {})); var JsonMetadataFactory; (function (JsonMetadataFactory) { /** * Rejects metadata that cannot be losslessly JSON-serialized. The typia * native runtime already screens out most structurally invalid types, so this * only adds the JSON-policy bans the legacy `@typia/core` walker enforced — * bare `bigint` payloads, function-typed properties, and `Map` / `Set` * containers that have no canonical JSON representation. */ JsonMetadataFactory.validate = (props) => { const messages = []; if (props.metadata.atomics.some((a) => a.type === "bigint")) messages.push("does not allow bigint type in JSON."); if (props.metadata.functions.length !== 0) messages.push("does not allow function type in JSON."); if (props.metadata.sets.length !== 0) messages.push("does not allow Set type in JSON."); if (props.metadata.maps.length !== 0) messages.push("does not allow Map type in JSON."); return messages; }; })(JsonMetadataFactory || (exports.JsonMetadataFactory = JsonMetadataFactory = {})); var HttpQueryProgrammer; (function (HttpQueryProgrammer) { HttpQueryProgrammer.validate = () => []; })(HttpQueryProgrammer || (exports.HttpQueryProgrammer = HttpQueryProgrammer = {})); var HttpHeadersProgrammer; (function (HttpHeadersProgrammer) { HttpHeadersProgrammer.validate = () => []; })(HttpHeadersProgrammer || (exports.HttpHeadersProgrammer = HttpHeadersProgrammer = {})); var HttpParameterProgrammer; (function (HttpParameterProgrammer) { HttpParameterProgrammer.validate = () => []; })(HttpParameterProgrammer || (exports.HttpParameterProgrammer = HttpParameterProgrammer = {})); var HttpFormDataProgrammer; (function (HttpFormDataProgrammer) { HttpFormDataProgrammer.validate = () => []; })(HttpFormDataProgrammer || (exports.HttpFormDataProgrammer = HttpFormDataProgrammer = {})); // --------------------------------------------------------------------- // `JsonSchemasProgrammer.writeSchemas` — consumes the per-metadata // pre-baked `jsonSchema` field the nestia transform emits. // --------------------------------------------------------------------- var JsonSchemasProgrammer; (function (JsonSchemasProgrammer) { /** * Consumes the per-metadata `jsonSchema` field the nestia transform * pre-bakes. Top-level route metadata (success / parameter / exception) * always carries a baked schema; for nested metadata (object property values * reached by the decomposed-query path), the bake is absent and this function * falls back to a minimal JS-side converter that handles the schema shapes * decompose actually emits — atomics, constants, templates, arrays of those, * named references — without re-implementing the typia native programmer * wholesale. */ JsonSchemasProgrammer.writeSchemas = (props) => { var _a, _b; const components = { schemas: {} }; const schemas = []; for (const m of props.metadatas) { const baked = m.jsonSchema; if (baked !== undefined) { schemas.push(baked.schema); Object.assign(((_a = components.schemas) !== null && _a !== void 0 ? _a : (components.schemas = {})), (_b = baked.components.schemas) !== null && _b !== void 0 ? _b : {}); } else { schemas.push(schemaFromMetadata(m)); } } return { version: props.version, components, schemas, }; }; })(JsonSchemasProgrammer || (exports.JsonSchemasProgrammer = JsonSchemasProgrammer = {})); const schemaFromMetadata = (m) => { const union = []; if (m.nullable) union.push({ type: "null" }); for (const atomic of m.atomics) union.push(schemaFromAtomic(atomic)); for (const constant of m.constants) for (const value of constant.values) union.push({ const: value.value, }); for (const tpl of m.templates) { union.push({ type: "string" }); void tpl; } for (const arr of m.arrays) { const inner = arr.type; union.push({ type: "array", items: inner ? schemaFromMetadata(inner.value) : {}, }); } for (const obj of m.objects) union.push({ $ref: `#/components/schemas/${obj.name}`, }); for (const alias of m.aliases) union.push({ $ref: `#/components/schemas/${alias.name}`, }); if (m.any || union.length === 0) return {}; if (union.length === 1) return union[0]; return { oneOf: union }; }; const schemaFromAtomic = (atomic) => { if (atomic.type === "boolean") return { type: "boolean" }; if (atomic.type === "bigint" || atomic.type === "number") return { type: atomic.type === "bigint" ? "integer" : "number" }; if (atomic.type === "string") return { type: "string" }; return {}; }; //# sourceMappingURL=legacy.js.map