UNPKG

typescript-scaffolder

Version:

![npm version](https://img.shields.io/npm/v/typescript-scaffolder) ![coverage](https://img.shields.io/badge/coverage-97.38%25-green)

116 lines (115 loc) 4.54 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseProperty = parseProperty; exports.extractInterfacesFromFile = extractInterfacesFromFile; const ts_morph_1 = require("ts-morph"); function parseProperty(prop) { const name = prop.getName(); const typeObj = prop.getType(); const symbol = typeObj.getSymbol(); let type = symbol ? symbol.getName() : typeObj.getText(); let elementType; if (typeObj.isArray()) { const elementTypeObj = typeObj.getArrayElementType(); if (elementTypeObj) { if (elementTypeObj.isString()) { type = "array"; elementType = "string"; } else if (elementTypeObj.isNumber()) { type = "array"; elementType = "number"; } else if (elementTypeObj.isBoolean()) { type = "array"; elementType = "boolean"; } else { type = "array"; elementType = elementTypeObj.getText(); } } } // Support for generic array types like Array<string> and ReadonlyArray<number> if (!elementType && (symbol?.getName() === "Array" || symbol?.getName() === "ReadonlyArray")) { const typeArgs = typeObj.getTypeArguments(); if (typeArgs.length === 1) { const arg = typeArgs[0]; type = "array"; if (arg.isString()) { elementType = "string"; } else if (arg.isNumber()) { elementType = "number"; } else if (arg.isBoolean()) { elementType = "boolean"; } else { elementType = arg.getText(); } } } let unionTypes; let enumValues; // Detect enum values if (symbol?.getDeclarations?.()[0]?.getKindName() === "EnumDeclaration") { const enumDecl = symbol.getDeclarations?.()[0]?.asKind(ts_morph_1.ts.SyntaxKind.EnumDeclaration); if (enumDecl) { const members = enumDecl.getMembers(); const values = members.map(m => { const val = m.getValue(); return typeof val === "string" || typeof val === "number" ? val : m.getName(); }); type = "enum"; unionTypes = values; enumValues = values; } } // Detect union of string literals (only if not already marked as enum) if (!enumValues && typeObj.isUnion()) { const union = typeObj.getUnionTypes(); const allLiterals = union.every(t => t.isStringLiteral()); if (allLiterals) { unionTypes = union.map(t => t.getLiteralValue()); type = "union"; } } const optional = prop.hasQuestionToken(); const jsDoc = prop.getJsDocs().map(doc => doc.getComment()).filter(Boolean).join("\n"); return { name, type, optional, jsDoc, unionTypes, elementType, enumValues }; } function extractInterfacesFromFile(filePath) { const projectOptions = { compilerOptions: { target: ts_morph_1.ts.ScriptTarget.ES2015, module: ts_morph_1.ts.ModuleKind.CommonJS, strict: true, esModuleInterop: true, skipLibCheck: true, forceConsistentCasingInFileNames: true, } }; const project = new ts_morph_1.Project(projectOptions); const sourceFile = project.addSourceFileAtPath(filePath); const interfaces = []; sourceFile.getInterfaces().forEach((iface) => { const name = iface.getName(); const typeParameters = iface.getTypeParameters().map(tp => tp.getName()); let properties = iface.getProperties().map(parseProperty); // Merge extended interfaces' properties (inherited) iface.getExtends().forEach(heritageClause => { const baseType = heritageClause.getExpression().getType(); const baseSymbol = baseType.getSymbol(); const baseDeclaration = baseSymbol?.getDeclarations()?.[0]; if (baseDeclaration && ts_morph_1.ts.isInterfaceDeclaration(baseDeclaration.compilerNode)) { const baseIface = baseDeclaration; const baseProps = baseIface.getProperties().map(parseProperty); properties = [...baseProps, ...properties]; } }); interfaces.push({ name, properties, typeParameters }); }); return interfaces; }