UNPKG

dtsgenerator

Version:

TypeScript d.ts file generator for JSON Schema file

290 lines (289 loc) 11.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.addOptionalInformation = exports.addComment = exports.buildTypeReferenceNode = exports.buildTupleTypeNode = exports.buildIntersectionTypeNode = exports.buildUnionTypeNode = exports.buildFreeFormObjectTypeLiteralNode = exports.buildTypeLiteralNode = exports.buildIndexSignatureNode = exports.buildPropertySignature = exports.buildTypeAliasNode = exports.buildInterfaceNode = exports.buildNamespaceNode = exports.buildBooleanLiteralTypeNode = exports.buildNumericLiteralTypeNode = exports.buildStringLiteralTypeNode = exports.buildNullKeyword = exports.buildSimpleArrayNode = exports.buildStringKeyword = exports.buildVoidKeyword = exports.buildUnknownKeyword = exports.buildNeverKeyword = exports.buildAnyKeyword = exports.buildKeyword = void 0; const tslib_1 = require("tslib"); const ts = tslib_1.__importStar(require("typescript")); const config_1 = tslib_1.__importDefault(require("./config")); const validateIdentifier_1 = require("./validateIdentifier"); function buildTypeNameIdentifier(name) { return ts.factory.createIdentifier((0, validateIdentifier_1.toValidIdentifier)(name, config_1.default.target)); } function buildPropertyNameIdentifier(name) { if ((0, validateIdentifier_1.checkInvalidCharacter)(name, config_1.default.target)) { return ts.factory.createIdentifier(name); } else { return ts.factory.createStringLiteral(name); } } function buildKeyword(kind) { return ts.factory.createKeywordTypeNode(kind); } exports.buildKeyword = buildKeyword; function buildAnyKeyword() { return buildKeyword(ts.SyntaxKind.AnyKeyword); } exports.buildAnyKeyword = buildAnyKeyword; function buildNeverKeyword() { return buildKeyword(ts.SyntaxKind.NeverKeyword); } exports.buildNeverKeyword = buildNeverKeyword; function buildUnknownKeyword() { return buildKeyword(ts.SyntaxKind.UnknownKeyword); } exports.buildUnknownKeyword = buildUnknownKeyword; function buildVoidKeyword() { return buildKeyword(ts.SyntaxKind.VoidKeyword); } exports.buildVoidKeyword = buildVoidKeyword; function buildStringKeyword() { return buildKeyword(ts.SyntaxKind.StringKeyword); } exports.buildStringKeyword = buildStringKeyword; function buildSimpleArrayNode(element) { return ts.factory.createArrayTypeNode(element); } exports.buildSimpleArrayNode = buildSimpleArrayNode; function buildNullKeyword() { return ts.factory.createLiteralTypeNode(ts.factory.createToken(ts.SyntaxKind.NullKeyword)); } exports.buildNullKeyword = buildNullKeyword; function buildStringLiteralTypeNode(s) { return ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(s)); } exports.buildStringLiteralTypeNode = buildStringLiteralTypeNode; function buildNumericLiteralTypeNode(n) { if (!isNaN(parseFloat(n)) && parseFloat(n) < 0) { return ts.factory.createLiteralTypeNode(ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, ts.factory.createNumericLiteral(Math.abs(parseFloat(n))))); } return ts.factory.createLiteralTypeNode(ts.factory.createNumericLiteral(n)); } exports.buildNumericLiteralTypeNode = buildNumericLiteralTypeNode; function buildBooleanLiteralTypeNode(b) { return ts.factory.createLiteralTypeNode(b ? ts.factory.createTrue() : ts.factory.createFalse()); } exports.buildBooleanLiteralTypeNode = buildBooleanLiteralTypeNode; function buildNamespaceNode(name, statements, root) { const modifiers = root ? [ts.factory.createModifier(ts.SyntaxKind.DeclareKeyword)] : undefined; return ts.factory.createModuleDeclaration(modifiers, buildTypeNameIdentifier(name), ts.factory.createModuleBlock(statements), ts.NodeFlags.Namespace | ts.NodeFlags.ExportContext | ts.NodeFlags.ContextFlags); } exports.buildNamespaceNode = buildNamespaceNode; function buildInterfaceNode(id, members, root) { const name = getLastTypeName(id); const modifiers = root ? [ts.factory.createModifier(ts.SyntaxKind.DeclareKeyword)] : [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)]; return ts.factory.createInterfaceDeclaration(modifiers, buildTypeNameIdentifier(name), undefined, undefined, members); } exports.buildInterfaceNode = buildInterfaceNode; function buildTypeAliasNode(id, type, root) { const name = getLastTypeName(id); const modifiers = root ? [ts.factory.createModifier(ts.SyntaxKind.DeclareKeyword)] : [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)]; return ts.factory.createTypeAliasDeclaration(modifiers, buildTypeNameIdentifier(name), undefined, type); } exports.buildTypeAliasNode = buildTypeAliasNode; function buildPropertySignature(_schema, propertyName, valueType, required, isPattern) { const modifiers = undefined; const questionToken = !(required === null || required === void 0 ? void 0 : required.includes(propertyName)) ? ts.factory.createToken(ts.SyntaxKind.QuestionToken) : undefined; if (isPattern) { return ts.factory.createIndexSignature(modifiers, [ ts.factory.createParameterDeclaration([], undefined, ts.factory.createIdentifier('pattern'), undefined, ts.factory.createTypeReferenceNode('string', []), undefined), ], valueType); } return ts.factory.createPropertySignature(modifiers, buildPropertyNameIdentifier(propertyName), questionToken, valueType); } exports.buildPropertySignature = buildPropertySignature; function buildIndexSignatureNode(name, indexType, valueType) { return ts.factory.createIndexSignature(undefined, [ ts.factory.createParameterDeclaration(undefined, undefined, buildTypeNameIdentifier(name), undefined, indexType, undefined), ], valueType); } exports.buildIndexSignatureNode = buildIndexSignatureNode; function buildTypeLiteralNode(elements) { return ts.factory.createTypeLiteralNode(elements); } exports.buildTypeLiteralNode = buildTypeLiteralNode; function buildFreeFormObjectTypeLiteralNode() { return ts.factory.createTypeLiteralNode([ buildIndexSignatureNode('key', buildStringKeyword(), buildAnyKeyword()), ]); } exports.buildFreeFormObjectTypeLiteralNode = buildFreeFormObjectTypeLiteralNode; function buildUnionTypeNode(types, builder, terminate) { const node = ts.factory.createUnionTypeNode(types.map(builder)); if (terminate) { return node; } return ts.factory.createParenthesizedType(node); } exports.buildUnionTypeNode = buildUnionTypeNode; function buildIntersectionTypeNode(types, terminate) { const node = ts.factory.createIntersectionTypeNode(types); if (terminate) { return node; } return ts.factory.createParenthesizedType(node); } exports.buildIntersectionTypeNode = buildIntersectionTypeNode; function buildTupleTypeNode(types, minItems, maxItems, additionalItems) { function typesIsArray(types) { return Array.isArray(types); } const typesLength = typesIsArray(types) ? types.length : 1; const nodes = []; if (additionalItems === false && (minItems !== null && minItems !== void 0 ? minItems : 0) > typesLength) { return buildNeverKeyword(); } const itemCount = maxItems != null ? additionalItems === false ? typesLength : maxItems : Math.max(typesLength, minItems !== null && minItems !== void 0 ? minItems : 0); for (let i = 0; i < itemCount; i++) { let node = typesIsArray(types) ? i < types.length ? types[i] : additionalItems !== undefined ? additionalItems === false ? buildNeverKeyword() : additionalItems : buildAnyKeyword() : types; if (minItems == null || i >= minItems) { node = ts.factory.createOptionalTypeNode(node); } nodes.push(node); } if (maxItems == null && (!typesIsArray(types) || additionalItems !== false)) { nodes.push(ts.factory.createRestTypeNode(ts.factory.createArrayTypeNode(typesIsArray(types) ? additionalItems !== undefined ? additionalItems : buildAnyKeyword() : types))); } return ts.factory.createTupleTypeNode(nodes); } exports.buildTupleTypeNode = buildTupleTypeNode; function buildTypeReferenceNode(schema, currentSchema) { const typeName = getTypename(schema.id, currentSchema); let node; for (const name of typeName) { if (node == null) { node = buildTypeNameIdentifier(name); } else { node = ts.factory.createQualifiedName(node, buildTypeNameIdentifier(name)); } } if (node == null) { throw new Error('TypeName array must not be empty.'); } return ts.factory.createTypeReferenceNode(node, undefined); } exports.buildTypeReferenceNode = buildTypeReferenceNode; function getTypename(id, baseSchema) { const result = id.toNames(); const baseId = baseSchema.id; const baseTypes = baseId.toNames().slice(0, -1); for (const type of baseTypes) { if (result.length === 1) { break; } if (result[0] === type) { result.shift(); } else { break; } } return result; } function addComment(node, schema, terminate) { var _a; const comments = getComment(schema); if (comments.length === 0) { return node; } else if (!terminate && comments.length === 1) { return ts.addSyntheticLeadingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, ` ${(_a = comments[0]) !== null && _a !== void 0 ? _a : ''} `, false); } else { let result = '*\n'; for (const comment of comments) { result += ' * ' + comment + '\n'; } result += ' '; return ts.addSyntheticLeadingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, result, true); } } exports.addComment = addComment; function getComment(schema) { const content = schema.content; let comments = []; function protectComment(str) { return str.replace(/\*\//g, '*\u200B/'); } function appendComment(value) { if (value == null) { return; } const s = typeof value === 'string' ? value : JSON.stringify(value, null, 2); const lines = s.split('\n').map((line) => protectComment(line)); comments = comments.concat(...lines); } if ('$comment' in content) { appendComment(content.$comment); } appendComment(content.title); appendComment(content.description); if ('example' in content || 'examples' in content) { appendComment('example:'); if ('example' in content) { appendComment(content.example); } if ('examples' in content) { if (content.examples) { for (const e of content.examples) { appendComment(e); } } } } return comments; } function addOptionalInformation(node, schema, terminate) { const format = schema.content.format; const pattern = schema.content.pattern; if (!format && !pattern) { return node; } let comment = ''; if (format) { comment += ' ' + format; } if (pattern) { comment += ' ' + pattern; } if (!terminate) { comment += ' '; } const kind = terminate ? ts.SyntaxKind.SingleLineCommentTrivia : ts.SyntaxKind.MultiLineCommentTrivia; return ts.addSyntheticTrailingComment(node, kind, comment, false); } exports.addOptionalInformation = addOptionalInformation; function getLastTypeName(id) { var _a; const names = id.toNames(); return (_a = names[names.length - 1]) !== null && _a !== void 0 ? _a : ''; }