UNPKG

metadata-booster

Version:

Emits detailed metadata of your types. You can then get it in runtime to deal with schema-aware operation, like defining GraphQL schemas, ORM operations, etc.

115 lines 4.75 kB
"use strict"; /* eslint-disable @typescript-eslint/ban-ts-comment */ Object.defineProperty(exports, "__esModule", { value: true }); exports.getClassInfo = void 0; const ts_morph_1 = require("ts-morph"); function getClassInfo(classNode, checker) { if (!classNode.name) return; const node = (0, ts_morph_1.createWrappedNode)(classNode, { typeChecker: checker }).asKindOrThrow(ts_morph_1.SyntaxKind.ClassDeclaration); return { name: node.getNameOrThrow(), fields: getInstanceProperties(node).map((p) => ({ name: p.getName(), typeInfo: getTypeInfo(p.getType(), p) })), methods: node.getMethods().map((m) => ({ name: m.getName(), typeInfo: getTypeInfo(m.getReturnType(), m) })), }; } exports.getClassInfo = getClassInfo; function getInstanceProperties(classDeclaration) { if (classDeclaration == undefined) { return []; } // Ensure to get the properties of the base classes too return [...getInstanceProperties(classDeclaration.getBaseClass()), ...classDeclaration.getInstanceProperties()]; } function hasQuestionTokenNode(node) { // @ts-ignore if (node && typeof node['hasQuestionToken'] === 'function') { // @ts-ignore return node === null || node === void 0 ? void 0 : node.hasQuestionToken(); } return false; } function getTypeInfo(type, node) { var _a, _b, _c, _d; const typeGroupTuples = [ [(t) => t.isString(), 'String'], [(t) => t.isNumber(), 'Number'], [(t) => t.isBoolean(), 'Boolean'], [(t) => t.isEnum(), 'Enum'], [(t) => t.isUnion(), 'Union'], [(t) => t.isIntersection(), 'Intersection'], [(t) => t.isClass(), 'Class'], [(t) => t.isInterface(), 'Interface'], [(t) => t.getAliasSymbol() != null, 'Type'], [(t) => t.isArray(), 'Array'], [(t) => t.getCallSignatures().length > 0, 'Function'], [(t) => isReadonlyArray(t), 'ReadonlyArray'], [(t) => t.isObject(), 'Object'], ]; const hasQuestionToken = hasQuestionTokenNode(node); const isNullable = type.isNullable() || hasQuestionToken; type = type.getNonNullableType(); const typeInfo = { name: type.getText(node), typeName: '', typeGroup: ((_a = typeGroupTuples.find(([fn]) => fn(type))) === null || _a === void 0 ? void 0 : _a[1]) || 'Other', isNullable, parameters: [], }; switch (typeInfo.typeGroup) { case 'Enum': typeInfo.parameters = type.getUnionTypes().map((t) => getTypeInfo(t)); break; case 'Union': typeInfo.parameters = type.getUnionTypes().map((t) => getTypeInfo(t, node)); break; case 'Intersection': typeInfo.parameters = type.getIntersectionTypes().map((t) => getTypeInfo(t, node)); break; default: typeInfo.parameters = type.getTypeArguments().map((a) => getTypeInfo(a, node)); } // typeName is used for referencing the type in the metadata switch (typeInfo.typeGroup) { case 'String': case 'Number': case 'Boolean': typeInfo.typeName = typeInfo.typeGroup; break; case 'Union': case 'Intersection': typeInfo.typeName = null; break; case 'Enum': case 'Class': case 'ReadonlyArray': case 'Array': // getSymbol() is used for complex types, in which cases getText() returns too much information (e.g. Map<User> instead of just Map) typeInfo.typeName = ((_b = type.getSymbol()) === null || _b === void 0 ? void 0 : _b.getName()) || ''; break; case 'Object': typeInfo.typeName = ((_c = type.getSymbol()) === null || _c === void 0 ? void 0 : _c.getName()) || ''; if (typeInfo.typeName === '__type') { // This happens for literal objects like `{ a: string, b: { c: string } }` typeInfo.typeName = 'Object'; } break; case 'Interface': case 'Type': case 'Function': case 'Other': if (type.isEnumLiteral()) { typeInfo.name = ((_d = type.getSymbol()) === null || _d === void 0 ? void 0 : _d.getName()) || ''; // e.g. "Small" } typeInfo.typeName = null; break; } if (typeInfo.typeName === '') throw new Error(`Could not extract typeName for type ${JSON.stringify(typeInfo)}`); return typeInfo; } function isReadonlyArray(t) { var _a; return t.isObject() && (((_a = t.getSymbol()) === null || _a === void 0 ? void 0 : _a.getName()) || '') === 'ReadonlyArray'; } //# sourceMappingURL=metadata-extractors.js.map