UNPKG

@supernovaio/cli

Version:

Supernova.io Command Line Interface

911 lines (909 loc) 38.4 kB
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="31412925-e1db-53cd-a40e-7a09aab8dea2")}catch(e){}}(); import path from "node:path"; import * as ts from "typescript"; import { ResolvedTypeKind, } from "./types.js"; import { buildFilter } from "./utils/build-filter.js"; import { isReactComponent } from "./utils/is-react-component.js"; import { trimFileName } from "./utils/trim-file-name.js"; export const defaultOptions = { allowJs: true, checkJs: false, jsx: ts.JsxEmit.React, module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.Latest, }; const isOptional = (prop) => (prop.getFlags() & ts.SymbolFlags.Optional) !== 0; const defaultJSDoc = { description: "", fullComment: "", tags: {}, }; export class Parser { checker; propFilter; savePropValueAsString; shouldExtractLiteralValuesFromEnum; shouldExtractValuesFromUnion; shouldIncludeExpression; shouldIncludePropTagMap; shouldRemoveUndefinedFromOptional; shouldSortUnions; constructor(program, opts) { const { savePropValueAsString, shouldExtractLiteralValuesFromEnum, shouldExtractValuesFromUnion, shouldIncludeExpression, shouldIncludePropTagMap, shouldRemoveUndefinedFromOptional, shouldSortUnions, } = opts; this.checker = program.getTypeChecker(); this.propFilter = buildFilter(opts); this.shouldExtractLiteralValuesFromEnum = Boolean(shouldExtractLiteralValuesFromEnum); this.shouldRemoveUndefinedFromOptional = Boolean(shouldRemoveUndefinedFromOptional); this.shouldExtractValuesFromUnion = Boolean(shouldExtractValuesFromUnion); this.shouldSortUnions = Boolean(shouldSortUnions); this.savePropValueAsString = Boolean(savePropValueAsString); this.shouldIncludePropTagMap = Boolean(shouldIncludePropTagMap); this.shouldIncludeExpression = Boolean(shouldIncludeExpression); } extractDefaultPropsFromComponent(symbol, source) { const possibleStatements = [ ...source.statements .filter(stmt => Boolean(stmt.name)) .filter(stmt => this.checker.getSymbolAtLocation(stmt.name) === symbol), ...source.statements.filter(stmt => ts.isExpressionStatement(stmt) || ts.isVariableStatement(stmt)), ]; return possibleStatements.reduce((res, statement) => { if (statementIsClassDeclaration(statement) && statement.members.length > 0) { const possibleDefaultProps = statement.members.filter(member => member.name && getPropertyName(member.name) === "defaultProps"); if (possibleDefaultProps.length === 0) { return res; } const defaultProps = possibleDefaultProps[0]; let { initializer } = defaultProps; if (!initializer) { return res; } let { properties } = initializer; while (ts.isIdentifier(initializer)) { const defaultPropsReference = this.checker.getSymbolAtLocation(initializer); if (defaultPropsReference) { const declarations = defaultPropsReference.getDeclarations(); if (declarations) { if (ts.isImportSpecifier(declarations[0])) { const symbol = this.checker.getSymbolAtLocation(declarations[0].name); if (!symbol) { continue; } const aliasedSymbol = this.checker.getAliasedSymbol(symbol); if (aliasedSymbol && aliasedSymbol.declarations && aliasedSymbol.declarations.length > 0) { initializer = aliasedSymbol.declarations[0].initializer; } else { continue; } } else { initializer = declarations[0].initializer; } properties = initializer.properties; } } } let propMap = {}; if (properties) { propMap = this.getPropMap(properties); } return { ...res, ...propMap, }; } if (statementIsStatelessWithDefaultProps(statement)) { let propMap = {}; for (const child of statement.getChildren()) { let { right } = child; if (right && ts.isIdentifier(right)) { const value = source.locals.get(right.escapedText); if (value && value.valueDeclaration && ts.isVariableDeclaration(value.valueDeclaration) && value.valueDeclaration.initializer) { right = value.valueDeclaration.initializer; } } if (right) { const { properties } = right; if (properties) { propMap = this.getPropMap(properties); } } } return { ...res, ...propMap, }; } const functionStatement = this.getFunctionStatement(statement); if (functionStatement && functionStatement.parameters && functionStatement.parameters.length > 0) { const { name } = functionStatement.parameters[0]; if (ts.isObjectBindingPattern(name)) { return { ...res, ...this.getPropMap(name.elements), }; } } return res; }, {}); } extractMembersFromType(type) { const methodSymbols = []; for (const property of type.getProperties()) { if (this.getCallSignature(property)) { methodSymbols.push(property); } } if (type.symbol && type.symbol.members) { for (const [_, member] of type.symbol.members) { methodSymbols.push(member); } } return methodSymbols; } extractPropsFromTypeIfStatefulComponent(type) { const constructSignatures = type.getConstructSignatures(); if (constructSignatures.length > 0) { for (const sig of constructSignatures) { const instanceType = sig.getReturnType(); const props = instanceType.getProperty("props"); if (props) { return props; } } } return null; } extractPropsFromTypeIfStatelessComponent(type) { const callSignatures = type.getCallSignatures(); if (callSignatures.length > 0) { for (const sig of callSignatures) { const params = sig.getParameters(); if (params.length === 0) { continue; } const propsParam = params[0]; if (propsParam.name === "props" || params.length === 1) { return propsParam; } } } return null; } findDocComment(symbol) { const comment = this.getFullJsDocComment(symbol); if (comment.fullComment || comment.tags.default) { return comment; } const rootSymbols = this.checker.getRootSymbols(symbol); const commentsOnRootSymbols = rootSymbols .filter(x => x !== symbol) .map(x => this.getFullJsDocComment(x)) .filter(x => Boolean(x.fullComment) || Boolean(comment.tags.default)); if (commentsOnRootSymbols.length > 0) { return commentsOnRootSymbols[0]; } return defaultJSDoc; } getCallSignature(symbol) { const symbolType = this.checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration); return symbolType.getCallSignatures()[0]; } getComponentInfo(exp, source, componentNameResolver = () => undefined, customComponentTypes = []) { const rootExportName = exp.getName(); if (exp.declarations && exp.declarations.length === 0) { return null; } let rootExp = this.getComponentFromExpression(exp); const declaration = rootExp.valueDeclaration || rootExp.declarations[0]; const type = this.checker.getTypeOfSymbolAtLocation(rootExp, declaration); let commentSource = rootExp; const typeSymbol = type.symbol || type.aliasSymbol; const originalName = rootExp.getName(); const filePath = exp.flags & ts.SymbolFlags.Alias ? this.checker.getAliasedSymbol(exp).declarations?.[0]?.getSourceFile().fileName || source.fileName : source.fileName; if (!rootExp.valueDeclaration) { if (!typeSymbol && (rootExp.flags & ts.SymbolFlags.Alias) !== 0) { commentSource = this.checker.getAliasedSymbol(commentSource); } else if (typeSymbol) { rootExp = typeSymbol; const expName = rootExp.getName(); const defaultComponentTypes = [ "__function", "StatelessComponent", "Stateless", "StyledComponentClass", "StyledComponent", "IStyledComponent", "FunctionComponent", "ForwardRefExoticComponent", "MemoExoticComponent", ]; const supportedComponentTypes = [...defaultComponentTypes, ...customComponentTypes]; commentSource = supportedComponentTypes.includes(expName) ? this.checker.getAliasedSymbol(commentSource) : rootExp; } else { return null; } } else if (type.symbol && (ts.isPropertyAccessExpression(declaration) || ts.isPropertyDeclaration(declaration))) { commentSource = type.symbol; } if (typeSymbol && (typeSymbol.getEscapedName() === "Requireable" || typeSymbol.getEscapedName() === "Validator")) { return null; } const propsType = this.extractPropsFromTypeIfStatelessComponent(type) || this.extractPropsFromTypeIfStatefulComponent(type); const nameSource = originalName === "default" ? rootExp : commentSource; const resolvedComponentName = componentNameResolver(nameSource, source); const { description, tags } = this.findDocComment(commentSource); const exportName = computeComponentExportName(nameSource, source, customComponentTypes, rootExportName); const displayName = resolvedComponentName || tags.visibleName || computeComponentDisplayName(nameSource, source); const methods = this.getMethodsInfo(type); let result = null; if (propsType) { const defaultProps = commentSource.valueDeclaration ? this.extractDefaultPropsFromComponent(commentSource, commentSource.valueDeclaration.getSourceFile()) : {}; const props = this.getPropsInfo(propsType, defaultProps); for (const propName of Object.keys(props)) { const prop = props[propName]; const component = { name: exportName }; if (!this.propFilter(prop, component)) { delete props[propName]; } } result = { description, displayName, exportName, filePath, methods, props, tags, }; } else if (exportName) { result = { description, displayName, exportName, filePath, methods, props: {}, tags, }; } if (result !== null && this.shouldIncludeExpression) { result.expression = rootExp; result.rootExpression = exp; } return result; } getResolvedType({ propType, skipUndefinedInUnion, visitedTypes = new Set(), }) { const typeString = this.checker.typeToString(propType); const raw = typeString; if (visitedTypes.has(typeString)) { return { kind: ResolvedTypeKind.Any, raw }; } const newVisitedTypes = new Set(visitedTypes); newVisitedTypes.add(typeString); if (propType.getCallSignatures().length > 0) { return { kind: ResolvedTypeKind.Function, raw }; } if (/^(ReactNode|ReactElement|Element)<?.*$/i.test(typeString)) { return { kind: ResolvedTypeKind.Slot, raw }; } if (propType.isUnion() && (propType.flags & ts.TypeFlags.Boolean) === 0) { const types = propType.types .filter(type => { if (skipUndefinedInUnion && type.flags & ts.TypeFlags.Undefined) { return false; } return true; }) .map(subType => this.getResolvedType({ propType: subType, visitedTypes: newVisitedTypes })) .filter((type) => type !== null); if (types.length === 1) { return types[0]; } return { kind: ResolvedTypeKind.Union, raw: skipUndefinedInUnion ? raw.replaceAll(" | undefined", "") : raw, types, }; } if (propType.isIntersection()) { const isEverySubTypeObject = propType.types.every(subType => subType.flags & ts.TypeFlags.Object); if (isEverySubTypeObject) { return { kind: ResolvedTypeKind.Object, raw, }; } return { kind: ResolvedTypeKind.Any, raw, }; } if (this.checker.isArrayType(propType)) { const elementType = this.checker.getTypeArguments(propType)[0]; const baseType = this.getResolvedType({ propType: elementType, visitedTypes: newVisitedTypes }); return { ...baseType, raw, isArray: true, }; } if (propType.isStringLiteral()) { return { kind: ResolvedTypeKind.StringLiteral, raw: raw.replaceAll('"', "") }; } if ((propType.flags & ts.TypeFlags.String) !== 0) { return { kind: ResolvedTypeKind.String, raw }; } if (propType.isNumberLiteral()) { return { kind: ResolvedTypeKind.NumberLiteral, raw }; } if ((propType.flags & ts.TypeFlags.Number) !== 0) { return { kind: ResolvedTypeKind.Number, raw }; } if ((propType.flags & ts.TypeFlags.BooleanLiteral) !== 0) { return { kind: ResolvedTypeKind.BooleanLiteral, raw }; } if ((propType.flags & ts.TypeFlags.Boolean) !== 0) { return { kind: ResolvedTypeKind.Boolean, raw }; } if ((propType.flags & ts.TypeFlags.Null) !== 0) { return { kind: ResolvedTypeKind.Null, raw }; } if ((propType.flags & ts.TypeFlags.Undefined) !== 0) { return { kind: ResolvedTypeKind.Undefined, raw }; } if ((propType.flags & ts.TypeFlags.Object) !== 0) { const rawDeclaration = propType.symbol?.declarations?.[0]?.getText(); const isDeclarationFromReact = propType.symbol?.declarations?.[0] ?.getSourceFile() .fileName.includes("@types/react"); return { kind: ResolvedTypeKind.Object, raw: rawDeclaration && !isDeclarationFromReact ? rawDeclaration : raw }; } return { kind: ResolvedTypeKind.Any, raw }; } getDocgenType(propType, isRequired) { if (propType.getConstraint()) { propType = propType.getConstraint(); } let propTypeString = this.checker.typeToString(propType); if (this.shouldRemoveUndefinedFromOptional && !isRequired) { propTypeString = propTypeString.replace(" | undefined", ""); } if (propType.isUnion() && (this.shouldExtractValuesFromUnion || (this.shouldExtractLiteralValuesFromEnum && propType.types.every(type => type.getFlags() & (ts.TypeFlags.StringLiteral | ts.TypeFlags.NumberLiteral | ts.TypeFlags.EnumLiteral | ts.TypeFlags.Undefined))))) { let value = propType.types.map(type => this.getInfoFromUnionType(type)); if (this.shouldRemoveUndefinedFromOptional && !isRequired) { value = value.filter(option => option.value != "undefined"); } if (this.shouldSortUnions) { value.sort((a, b) => a.value.toString().localeCompare(b.value.toString())); } return { name: "enum", raw: propTypeString, value, }; } if (this.shouldRemoveUndefinedFromOptional && !isRequired) { propTypeString = propTypeString.replace(" | undefined", ""); } return { name: propTypeString }; } getFullJsDocComment(symbol) { if (symbol.getDocumentationComment === undefined) { return defaultJSDoc; } let mainComment = ts.displayPartsToString(symbol.getDocumentationComment(this.checker)); if (mainComment) { mainComment = mainComment.replaceAll("\r\n", "\n"); } const tags = symbol.getJsDocTags() || []; const tagComments = []; const tagMap = {}; for (const tag of tags) { const trimmedText = ts.displayPartsToString(tag.text).trim(); const currentValue = tagMap[tag.name]; tagMap[tag.name] = currentValue ? currentValue + "\n" + trimmedText : trimmedText; if (!["default", "type"].includes(tag.name)) { tagComments.push(formatTag(tag)); } } return { description: mainComment, fullComment: (mainComment + "\n" + tagComments.join("\n")).trim(), tags: tagMap, }; } getFunctionStatement(statement) { if (ts.isFunctionDeclaration(statement)) { return statement; } if (ts.isVariableStatement(statement)) { let initializer = statement.declarationList && statement.declarationList.declarations[0].initializer; if (initializer && ts.isCallExpression(initializer)) { const symbol = this.checker.getSymbolAtLocation(initializer.expression); if (!symbol || symbol.getName() !== "forwardRef") return; initializer = initializer.arguments[0]; } if (initializer && (ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer))) { return initializer; } } return undefined; } getLiteralValueFromImportSpecifier(property) { if (ts.isImportSpecifier(property)) { const symbol = this.checker.getSymbolAtLocation(property.name); if (!symbol) { return null; } const aliasedSymbol = this.checker.getAliasedSymbol(symbol); if (aliasedSymbol && aliasedSymbol.declarations && aliasedSymbol.declarations.length > 0) { return this.getLiteralValueFromPropertyAssignment(aliasedSymbol.declarations[0]); } return null; } return null; } getLiteralValueFromPropertyAssignment(property) { let { initializer } = property; if (!initializer && ts.isShorthandPropertyAssignment(property)) { const symbol = this.checker.getShorthandAssignmentValueSymbol(property); const decl = symbol && symbol.valueDeclaration; if (decl && decl.initializer) { initializer = decl.initializer; } } if (!initializer) { return undefined; } switch (initializer.kind) { case ts.SyntaxKind.FalseKeyword: { return this.savePropValueAsString ? "false" : false; } case ts.SyntaxKind.Identifier: { if (initializer.text === "undefined") { return "undefined"; } const symbol = this.checker.getSymbolAtLocation(initializer); if (symbol && symbol.declarations && symbol.declarations.length > 0) { if (ts.isImportSpecifier(symbol.declarations[0])) { return this.getLiteralValueFromImportSpecifier(symbol.declarations[0]); } return this.getLiteralValueFromPropertyAssignment(symbol.declarations[0]); } return null; } case ts.SyntaxKind.NullKeyword: { return this.savePropValueAsString ? "null" : null; } case ts.SyntaxKind.NumericLiteral: { return this.savePropValueAsString ? `${initializer.text}` : Number(initializer.text); } case ts.SyntaxKind.PrefixUnaryExpression: { return this.savePropValueAsString ? initializer.getFullText().trim() : Number(initializer.getFullText()); } case ts.SyntaxKind.StringLiteral: { return initializer.text.trim(); } case ts.SyntaxKind.TrueKeyword: { return this.savePropValueAsString ? "true" : true; } case ts.SyntaxKind.PropertyAccessExpression: { const symbol = this.checker.getSymbolAtLocation(initializer); if (symbol && symbol.declarations && symbol.declarations.length > 0) { const declaration = symbol.declarations[0]; if (ts.isBindingElement(declaration) || ts.isPropertyAssignment(declaration)) { return this.getLiteralValueFromPropertyAssignment(declaration); } } return null; } case ts.SyntaxKind.ObjectLiteralExpression: default: { try { return initializer.getText(); } catch { return null; } } } } getMethodsInfo(type) { const members = this.extractMembersFromType(type); const methods = []; for (const member of members) { if (!this.isTaggedPublic(member)) { continue; } const name = member.getName(); const docblock = this.getFullJsDocComment(member).fullComment; const callSignature = this.getCallSignature(member); const params = this.getParameterInfo(callSignature); const description = ts.displayPartsToString(member.getDocumentationComment(this.checker)); const returnType = this.checker.typeToString(callSignature.getReturnType()); const returnDescription = ts.displayPartsToString(this.getReturnDescription(member)); const modifiers = this.getModifiers(member); methods.push({ description, docblock, modifiers, name, params, returns: returnDescription ? { description: returnDescription, type: returnType, } : null, }); } return methods; } getModifiers(member) { const modifiers = []; if (!member.valueDeclaration) { return modifiers; } const flags = ts.getCombinedModifierFlags(member.valueDeclaration); const isStatic = (flags & ts.ModifierFlags.Static) !== 0; if (isStatic) { modifiers.push("static"); } return modifiers; } getParameterInfo(callSignature) { return callSignature.parameters.map(param => { const paramType = this.checker.getTypeOfSymbolAtLocation(param, param.valueDeclaration); const paramDeclaration = this.checker.symbolToParameterDeclaration(param, undefined, undefined); const isOptionalParam = Boolean(paramDeclaration && paramDeclaration.questionToken); return { description: ts.displayPartsToString(param.getDocumentationComment(this.checker)) || null, name: param.getName() + (isOptionalParam ? "?" : ""), type: { name: this.checker.typeToString(paramType) }, }; }); } getPropMap(properties) { return properties.reduce((acc, property) => { if (ts.isSpreadAssignment(property) || !property.name) { return acc; } const literalValue = this.getLiteralValueFromPropertyAssignment(property); const propertyName = getPropertyName(property.name); if ((typeof literalValue === "string" || typeof literalValue === "number" || typeof literalValue === "boolean" || literalValue === null) && propertyName !== null) { acc[propertyName] = literalValue; } return acc; }, {}); } getPropsInfo(propsObj, defaultProps = {}) { const propsDeclaration = propsObj.valueDeclaration ?? propsObj.getDeclarations()?.[0]; if (!propsDeclaration) { return {}; } const propsType = this.checker.getTypeOfSymbolAtLocation(propsObj, propsDeclaration); const baseProps = propsType.getApparentProperties(); let propertiesOfProps = baseProps; if (propsType.isUnionOrIntersection()) { propertiesOfProps = [ ...(propertiesOfProps = this.checker.getAllPossiblePropertiesOfTypes(propsType.types)), ...baseProps, ]; if (propertiesOfProps.length === 0) { const isUnionType = (type) => (type.flags & ts.TypeFlags.Union) !== 0; const types = isUnionType(propsType) ? propsType.types : [propsType]; const subTypes = this.checker.getAllPossiblePropertiesOfTypes(types.reduce((all, t) => { const typeArray = isUnionType(t) ? t.types : [t]; return [...all, ...typeArray.map(t => t.symbol).filter(s => s !== undefined)]; }, [])); propertiesOfProps = [...subTypes, ...baseProps]; } } const result = {}; for (const prop of propertiesOfProps) { const propName = prop.getName(); const propType = this.checker.getTypeOfSymbolAtLocation(prop, propsDeclaration); const jsDocComment = this.findDocComment(prop); const hasCodeBasedDefault = defaultProps[propName] !== undefined; let defaultValue = null; if (hasCodeBasedDefault) { defaultValue = { value: defaultProps[propName] }; } else if (jsDocComment.tags.default) { defaultValue = { value: jsDocComment.tags.default }; } const parent = getParentType(prop); const parents = getDeclarations(prop); const declarations = prop.declarations || []; const baseProp = baseProps.find(p => p.getName() === propName); const required = !isOptional(prop) && !hasCodeBasedDefault && declarations.every(d => !((ts.isPropertySignature(d) || ts.isPropertyDeclaration(d) || ts.isParameter(d)) && d.questionToken)) && (!baseProp || !isOptional(baseProp)); const type = jsDocComment.tags.type ? { name: jsDocComment.tags.type, } : this.getDocgenType(propType, required); const propTags = this.shouldIncludePropTagMap ? { tags: jsDocComment.tags } : {}; const description = this.shouldIncludePropTagMap ? jsDocComment.description.replaceAll("\r\n", "\n") : jsDocComment.fullComment.replaceAll("\r\n", "\n"); const resolvedType = this.getResolvedType({ propType, skipUndefinedInUnion: !required }); result[propName] = { resolvedType, declarations: parents, defaultValue, description, name: propName, parent, required, type, ...propTags, }; } return result; } getReturnDescription(symbol) { const tags = symbol.getJsDocTags(); const returnTag = tags.find(tag => tag.name === "returns"); if (!returnTag || !Array.isArray(returnTag.text)) { return; } return returnTag.text; } isTaggedPublic(symbol) { const jsDocTags = symbol.getJsDocTags(); return Boolean(jsDocTags.find(tag => tag.name === "public")); } parseExportSymbol(exp, sourceFile) { if (!isReactComponent(exp, sourceFile, this.checker)) { return []; } const componentDocs = []; const doc = this.getComponentInfo(exp, sourceFile); if (doc) { componentDocs.push(doc); } if (!exp.exports) { return componentDocs; } for (const [_, symbol] of exp.exports) { if (symbol.flags & ts.SymbolFlags.Prototype) { continue; } if (!isReactComponent(symbol, sourceFile, this.checker)) { continue; } if (symbol.flags & ts.SymbolFlags.Method) { const signature = this.getCallSignature(symbol); const returnType = this.checker.typeToString(signature.getReturnType()); if (returnType !== "Element") { continue; } } const doc = this.getComponentInfo(symbol, sourceFile); if (doc) { const prefix = exp.escapedName === "default" ? "" : `${exp.escapedName}.`; componentDocs.push({ ...doc, displayName: `${prefix}${symbol.escapedName}`, }); } } return componentDocs; } getComponentFromExpression(exp) { const declaration = exp.valueDeclaration || exp.declarations[0]; const type = this.checker.getTypeOfSymbolAtLocation(exp, declaration); const typeSymbol = type.symbol || type.aliasSymbol; if (!typeSymbol) { return exp; } const symbolName = typeSymbol.getName(); if ((symbolName === "MemoExoticComponent" || symbolName === "ForwardRefExoticComponent") && exp.valueDeclaration && ts.isExportAssignment(exp.valueDeclaration) && ts.isCallExpression(exp.valueDeclaration.expression)) { const component = this.checker.getSymbolAtLocation(exp.valueDeclaration.expression.arguments[0]); if (component) { exp = component; } } return exp; } getInfoFromUnionType(type) { let commentInfo = {}; if (type.getSymbol()) { commentInfo = { ...this.getFullJsDocComment(type.getSymbol()) }; } return { value: this.getValuesFromUnionType(type), ...commentInfo, }; } getValuesFromUnionType(type) { if (type.isStringLiteral()) return `"${type.value}"`; if (type.isNumberLiteral()) return `${type.value}`; return this.checker.typeToString(type); } } function statementIsClassDeclaration(statement) { return Boolean(statement.members); } function statementIsStatelessWithDefaultProps(statement) { const children = statement.getChildren(); for (const child of children) { const { left } = child; if (left) { const { name } = left; if (name && name.escapedText === "defaultProps") { return true; } } } return false; } function getPropertyName(name) { switch (name.kind) { case ts.SyntaxKind.ComputedPropertyName: { return name.getText(); } case ts.SyntaxKind.Identifier: case ts.SyntaxKind.NumericLiteral: case ts.SyntaxKind.StringLiteral: { return name.text; } default: { return null; } } } function formatTag(tag) { let result = "@" + tag.name; if (tag.text) { result += " " + ts.displayPartsToString(tag.text); } return result; } function getTextValueOfClassMember(classDeclaration, memberName) { const classDeclarationMembers = classDeclaration.members || []; const [textValue] = classDeclarationMembers && classDeclarationMembers .filter(member => ts.isPropertyDeclaration(member)) .filter(member => { const name = ts.getNameOfDeclaration(member); return name && name.text === memberName; }) .map(member => { const property = member; return property.initializer && property.initializer.text; }); return textValue || ""; } function getTextValueOfFunctionProperty(_exp, source, propertyName) { const [textValue] = source.statements .filter(statement => ts.isExpressionStatement(statement)) .filter(statement => { const expr = statement.expression; return (expr.left && expr.left.name && expr.left.name.escapedText === propertyName); }) .filter(statement => ts.isStringLiteral(statement.expression.right)) .map(statement => statement.expression.right.text); return textValue || ""; } function computeComponentDisplayName(exp, source) { const statelessDisplayName = getTextValueOfFunctionProperty(exp, source, "displayName"); const statefulDisplayName = exp.valueDeclaration && ts.isClassDeclaration(exp.valueDeclaration) && getTextValueOfClassMember(exp.valueDeclaration, "displayName"); return statelessDisplayName || statefulDisplayName || null; } function computeComponentExportName(rootExport, source, customComponentTypes = [], rootExportName) { const exportName = rootExport.getName(); const defaultComponentTypes = [ "default", "__function", "Stateless", "StyledComponentClass", "StyledComponent", "IStyledComponent", "FunctionComponent", "StatelessComponent", "ForwardRefExoticComponent", "MemoExoticComponent", ]; const supportedComponentTypes = [...defaultComponentTypes, ...customComponentTypes]; if (!defaultComponentTypes.includes(rootExportName)) { return rootExportName; } if (supportedComponentTypes.includes(exportName)) { return getDefaultExportForFile(source); } return exportName; } export function getDefaultExportForFile(source) { const name = path.basename(source.fileName).split(".")[0]; const filename = name === "index" ? path.basename(path.dirname(source.fileName)) : name; const identifier = filename.replaceAll(/^[^A-Z]*/gi, "").replaceAll(/[^A-Z0-9]*/gi, ""); return identifier.length > 0 ? identifier : "DefaultName"; } function isTypeLiteral(node) { return node.kind === ts.SyntaxKind.TypeLiteral; } function getDeclarations(prop) { const declarations = prop.getDeclarations(); if (declarations === undefined || declarations.length === 0) { return undefined; } const parents = []; for (const declaration of declarations) { const { parent } = declaration; if (!isTypeLiteral(parent) && !isInterfaceOrTypeAliasDeclaration(parent)) { continue; } const parentName = "name" in parent ? parent.name.text : "TypeLiteral"; const { fileName } = parent.getSourceFile(); parents.push({ fileName, name: parentName, }); } return parents; } function getParentType(prop) { const declarations = prop.getDeclarations(); if (declarations == null || declarations.length === 0) { return undefined; } const { parent } = declarations[0]; if (!isInterfaceOrTypeAliasDeclaration(parent)) { return undefined; } const parentName = parent.name.text; const { fileName } = parent.getSourceFile(); return { fileName: trimFileName(fileName), name: parentName, }; } function isInterfaceOrTypeAliasDeclaration(node) { return node.kind === ts.SyntaxKind.InterfaceDeclaration || node.kind === ts.SyntaxKind.TypeAliasDeclaration; } //# sourceMappingURL=parser.js.map //# debugId=31412925-e1db-53cd-a40e-7a09aab8dea2