@nestia/sdk
Version:
Nestia SDK and Swagger generator
348 lines • 15.4 kB
JavaScript
;
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