@supernovaio/cli
Version:
Supernova.io Command Line Interface
911 lines (909 loc) • 38.4 kB
JavaScript
!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