@jsonjoy.com/json-type
Version:
High-performance JSON Pointer implementation
307 lines • 10.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.objToModule = exports.aliasToTs = void 0;
exports.toTypeScriptAst = toTypeScriptAst;
const classes_1 = require("../type/classes");
const augmentWithComment = (type, node) => {
if (type.title || type.description) {
let comment = '';
if (type.title)
comment += '# ' + type.title;
if (type.title && type.description)
comment += '\n\n';
if (type.description)
comment += type.description;
node.comment = comment;
}
};
/**
* Main router function that converts any Schema to TypeScript AST.
* Uses a switch statement to route to the appropriate converter logic.
*/
function toTypeScriptAst(type) {
const typeName = type.kind();
switch (typeName) {
case 'any': {
const node = { node: 'AnyKeyword' };
return node;
}
case 'bool': {
const node = { node: 'BooleanKeyword' };
return node;
}
case 'con': {
const constSchema = type.getSchema();
const value = constSchema.value;
const valueType = typeof value;
switch (valueType) {
case 'boolean': {
if (value === true) {
const node = { node: 'TrueKeyword' };
return node;
}
else {
const node = { node: 'FalseKeyword' };
return node;
}
}
case 'string': {
const node = {
node: 'StringLiteral',
text: value,
};
return node;
}
case 'number': {
const node = {
node: 'NumericLiteral',
text: String(value),
};
return node;
}
case 'object': {
if (value === null) {
const node = { node: 'NullKeyword' };
return node;
}
// For complex objects, fallback to object keyword
const node = { node: 'ObjectKeyword' };
return node;
}
}
// Fallback for other value types
const node = { node: 'ObjectKeyword' };
return node;
}
case 'num': {
const node = { node: 'NumberKeyword' };
return node;
}
case 'str': {
const node = { node: 'StringKeyword' };
return node;
}
case 'bin': {
const node = {
node: 'GenericTypeAnnotation',
id: {
node: 'Identifier',
name: 'Uint8Array',
},
};
return node;
}
case 'arr': {
const arr = type;
const { _head = [], _type, _tail = [] } = arr;
if (_head.length || _tail.length) {
const node = {
node: 'TupleType',
elements: [],
};
for (const headType of _head) {
node.elements.push(toTypeScriptAst(headType));
}
if (_type) {
const rest = {
node: 'RestType',
type: {
node: 'ArrType',
elementType: toTypeScriptAst(_type),
},
};
node.elements.push(rest);
}
for (const tailType of _tail) {
node.elements.push(toTypeScriptAst(tailType));
}
return node;
}
const node = {
node: 'ArrType',
elementType: toTypeScriptAst(arr._type),
};
return node;
}
case 'obj': {
const obj = type;
const objSchema = type.getSchema();
const node = {
node: 'TypeLiteral',
members: [],
};
// Handle fields
if (obj.keys && obj.keys.length > 0) {
for (const field of obj.keys) {
const member = {
node: 'PropertySignature',
name: field.key,
type: toTypeScriptAst(field.val),
};
if (field.optional === true) {
member.optional = true;
}
// Add comment using the same logic as the original augmentWithComment
const fieldSchema = field.schema;
if (fieldSchema.title || fieldSchema.description) {
let comment = '';
if (fieldSchema.title)
comment += '# ' + fieldSchema.title;
if (fieldSchema.title && fieldSchema.description)
comment += '\n\n';
if (fieldSchema.description)
comment += fieldSchema.description;
member.comment = comment;
}
node.members.push(member);
}
}
// Handle unknown/additional fields
if (objSchema.decodeUnknownKeys || objSchema.encodeUnknownKeys) {
node.members.push({
node: 'IndexSignature',
type: { node: 'UnknownKeyword' },
});
}
// Add comment to the type literal itself using the same logic as augmentWithComment
augmentWithComment(objSchema, node);
return node;
}
case 'map': {
const map = type;
const node = {
node: 'TypeReference',
typeName: 'Record',
typeArguments: [{ node: 'StringKeyword' }, toTypeScriptAst(map._value)],
};
return node;
}
case 'or': {
const or = type;
const node = {
node: 'UnionType',
types: or.types.map((type) => toTypeScriptAst(type)),
};
return node;
}
case 'ref': {
const refSchema = type.getSchema();
const node = {
node: 'GenericTypeAnnotation',
id: {
node: 'Identifier',
name: refSchema.ref,
},
};
return node;
}
case 'fn': {
const fn = type;
const node = {
node: 'FnType',
parameters: [
{
node: 'Parameter',
name: {
node: 'Identifier',
name: 'request',
},
type: toTypeScriptAst(fn.req),
},
],
type: {
node: 'TypeReference',
typeName: {
node: 'Identifier',
name: 'Promise',
},
typeArguments: [toTypeScriptAst(fn.res)],
},
};
return node;
}
case 'fn$': {
const fn = type;
const node = {
node: 'FnType',
parameters: [
{
node: 'Parameter',
name: {
node: 'Identifier',
name: 'request$',
},
type: {
node: 'TypeReference',
typeName: {
node: 'Identifier',
name: 'Observable',
},
typeArguments: [toTypeScriptAst(fn.req)],
},
},
],
type: {
node: 'TypeReference',
typeName: {
node: 'Identifier',
name: 'Observable',
},
typeArguments: [toTypeScriptAst(fn.res)],
},
};
return node;
}
default: {
// Fallback for unknown types
const node = { node: 'UnknownKeyword' };
return node;
}
}
}
const aliasToTs = (alias) => {
const type = alias.type;
if (type instanceof classes_1.ObjType) {
const ast = toTypeScriptAst(type);
const node = {
node: 'InterfaceDeclaration',
name: alias.id,
members: ast.members,
};
return node;
}
else {
const node = {
node: 'TypeAliasDeclaration',
name: alias.id,
type: toTypeScriptAst(type),
};
// TODO: Figure out if this is still needed, and possibly bring it back.
// augmentWithComment(type, node);
return node;
}
};
exports.aliasToTs = aliasToTs;
const objToModule = (obj) => {
const node = {
node: 'ModuleDeclaration',
name: 'Router',
export: true,
statements: [
{
node: 'TypeAliasDeclaration',
name: 'Routes',
type: toTypeScriptAst(obj),
export: true,
},
],
};
const system = obj.system;
if (!system)
throw new Error('system is undefined');
for (const alias of system.aliases.values())
node.statements.push({ ...(0, exports.aliasToTs)(alias.type), export: true });
return node;
};
exports.objToModule = objToModule;
//# sourceMappingURL=converter.js.map