UNPKG

alm

Version:

The best IDE for TypeScript

382 lines (339 loc) 13.4 kB
/** * * * * Various transformers * * * */ /** Imports */ import * as types from "../../../../common/types"; import {getDocumentedTypeLocation} from "../modules/astUtils"; import {getParsedComment} from "../modules/jsDoc"; /** Source File */ export function transformSourceFile(sourceFile: ts.SourceFile): types.DocumentedType { const name = sourceFile.fileName; const icon = ts.isExternalModule(sourceFile) ? types.IconType.Namespace : types.IconType.Global; const comment = getParsedComment(sourceFile, sourceFile); const subItems = getSignificantSubItems(sourceFile, sourceFile); return { name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, sourceFile.pos), }; } /** There are a few root level things we care about. This only recurses on those 🌹 */ function getSignificantSubItems(node: ts.SourceFile | ts.ModuleBlock, sourceFile: ts.SourceFile): types.DocumentedType[] { const subItems: types.DocumentedType[] = []; ts.forEachChild(node, (node) => { if (node.kind == ts.SyntaxKind.ClassDeclaration) { subItems.push(transformClass(node as ts.ClassDeclaration, sourceFile)); } if (node.kind == ts.SyntaxKind.InterfaceDeclaration) { subItems.push(transformInterface(node as ts.InterfaceDeclaration, sourceFile)); } if (node.kind == ts.SyntaxKind.EnumDeclaration) { subItems.push(transformEnum(node as ts.EnumDeclaration, sourceFile)); } if (node.kind == ts.SyntaxKind.VariableStatement) { transformVariableStatement(node as ts.VariableStatement, sourceFile).forEach(variable => subItems.push(variable)); } if (node.kind == ts.SyntaxKind.FunctionDeclaration) { const functionDeclaration = node as ts.FunctionDeclaration; /** If it doesn't have a `block` then its an overload. We don't want to visit it */ if (!functionDeclaration.body) return; subItems.push(transformFunction(functionDeclaration, sourceFile)); } if (node.kind == ts.SyntaxKind.ModuleDeclaration) { subItems.push(transformModule(node as ts.ModuleDeclaration, sourceFile)); } }); return subItems; } /** Class */ function transformClass(node: ts.ClassDeclaration, sourceFile: ts.SourceFile): types.DocumentedType { const name = node.name.text; const comment = getParsedComment(node, sourceFile); const subItems: types.DocumentedType[] = []; let icon = types.IconType.Class; if (node.typeParameters) { icon = types.IconType.ClassGeneric; } ts.forEachChild(node, (node) => { if (node.kind == ts.SyntaxKind.Constructor) { subItems.push(transformClassConstructor(node as ts.ConstructorDeclaration, sourceFile)); } if (node.kind == ts.SyntaxKind.PropertyDeclaration) { subItems.push(transformClassProperty(node as ts.PropertyDeclaration, sourceFile)); } if (node.kind == ts.SyntaxKind.MethodDeclaration) { subItems.push(transformClassMethod(node as ts.MethodDeclaration, sourceFile)); } if (node.kind == ts.SyntaxKind.IndexSignature) { subItems.push(transformClassIndexSignature(node as ts.IndexSignatureDeclaration, sourceFile)); } }); return { name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, node.name.pos), }; } /** Class Constructor */ function transformClassConstructor(node: ts.ConstructorDeclaration, sourceFile: ts.SourceFile): types.DocumentedType { const name = "constructor"; const comment = getParsedComment(node, sourceFile); const subItems: types.DocumentedType[] = []; let icon = types.IconType.ClassConstructor; return { name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, node.pos), }; } /** Class Property */ function transformClassProperty(node: ts.PropertyDeclaration, sourceFile: ts.SourceFile): types.DocumentedType { const name = ts.unescapeLeadingUnderscores(ts.getPropertyNameForPropertyNameNode(node.name)); const comment = getParsedComment(node, sourceFile); const subItems: types.DocumentedType[] = []; let icon = types.IconType.ClassProperty; return { name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, node.pos), }; } /** Class Method */ function transformClassMethod(node: ts.MethodDeclaration, sourceFile: ts.SourceFile): types.DocumentedType { const name = ts.unescapeLeadingUnderscores(ts.getPropertyNameForPropertyNameNode(node.name)); const comment = getParsedComment(node, sourceFile); const subItems: types.DocumentedType[] = []; let icon = types.IconType.ClassMethod; if (node.typeParameters) { icon = types.IconType.ClassMethodGeneric; } return { name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, node.pos), }; } /** Class Index Signature */ function transformClassIndexSignature(node: ts.IndexSignatureDeclaration, sourceFile: ts.SourceFile): types.DocumentedType { const name = "Index Signature"; const comment = '`' + node.getText() + '`' + `\n` + (getParsedComment(node, sourceFile) || ''); const subItems: types.DocumentedType[] = []; let icon = types.IconType.ClassIndexSignature; return { name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, node.pos), }; } /** Interface */ function transformInterface(node: ts.InterfaceDeclaration, sourceFile: ts.SourceFile): types.DocumentedType { const name = node.name.text; const comment = getParsedComment(node, sourceFile); const subItems: types.DocumentedType[] = []; let icon = types.IconType.Interface; if (node.typeParameters) { icon = types.IconType.InterfaceGeneric; } ts.forEachChild(node, (node) => { if (node.kind == ts.SyntaxKind.ConstructSignature) { subItems.push(transformInterfaceConstructor(node as ts.ConstructSignatureDeclaration, sourceFile)); } if (node.kind == ts.SyntaxKind.PropertySignature) { subItems.push(transformInterfaceProperty(node as ts.PropertySignature, sourceFile)); } if (node.kind == ts.SyntaxKind.MethodSignature) { subItems.push(transformInterfaceMethod(node as ts.MethodSignature, sourceFile)); } if (node.kind == ts.SyntaxKind.IndexSignature) { subItems.push(transformInterfaceIndexSignature(node as ts.IndexSignatureDeclaration, sourceFile)); } }); return { name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, node.name.pos), }; } /** Interface Property */ function transformInterfaceProperty(node: ts.PropertySignature, sourceFile: ts.SourceFile): types.DocumentedType { const name = ts.unescapeLeadingUnderscores(ts.getPropertyNameForPropertyNameNode(node.name)); const comment = getParsedComment(node, sourceFile); const subItems: types.DocumentedType[] = []; let icon = types.IconType.InterfaceProperty; return { name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, node.name.pos), }; } /** Interface Constructor */ function transformInterfaceConstructor(node: ts.ConstructSignatureDeclaration, sourceFile: ts.SourceFile): types.DocumentedType { const name = "constructor"; const comment = getParsedComment(node, sourceFile); const subItems: types.DocumentedType[] = []; let icon = types.IconType.InterfaceConstructor; return { name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, node.pos), }; } /** Interface Method */ function transformInterfaceMethod(node: ts.MethodSignature, sourceFile: ts.SourceFile): types.DocumentedType { const name = ts.unescapeLeadingUnderscores(ts.getPropertyNameForPropertyNameNode(node.name)); const comment = getParsedComment(node, sourceFile); const subItems: types.DocumentedType[] = []; let icon = types.IconType.InterfaceMethod; if (node.typeParameters) { icon = types.IconType.InterfaceMethodGeneric; } return { name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, node.name.pos), }; } /** Interface Index Signature */ function transformInterfaceIndexSignature(node: ts.IndexSignatureDeclaration, sourceFile: ts.SourceFile): types.DocumentedType { const name = "Index Signature"; const comment = '`' + node.getText() + '`' + `\n` + (getParsedComment(node, sourceFile) || ''); const subItems: types.DocumentedType[] = []; let icon = types.IconType.InterfaceIndexSignature; return { name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, node.pos), }; } /** Enum */ function transformEnum(node: ts.EnumDeclaration, sourceFile: ts.SourceFile): types.DocumentedType { const name = node.name.text; const comment = getParsedComment(node, sourceFile); const subItems: types.DocumentedType[] = []; let icon = types.IconType.Enum; ts.forEachChild(node, (node) => { if (node.kind == ts.SyntaxKind.EnumMember) { const member = node as ts.EnumMember; subItems.push({ name: member.name.getText(), icon: types.IconType.EnumMember, comment: getParsedComment(node, sourceFile), subItems: [], location: getDocumentedTypeLocation(sourceFile, member.name.pos), }); } }); return { name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, node.name.pos), }; } /** Variable */ function transformVariableStatement(node: ts.VariableStatement, sourceFile: ts.SourceFile): types.DocumentedType[] { const result: types.DocumentedType[] = []; const declarations = node.declarationList.declarations; declarations.forEach(d => { const comment = getParsedComment(d, sourceFile); const subItems: types.DocumentedType[] = []; let icon = types.IconType.Variable; if (d.name.kind === ts.SyntaxKind.ObjectBindingPattern) { /** destructured variable declaration */ const names = d.name as ts.ObjectBindingPattern; names.elements.forEach(bindingElement => { const name = ts.unescapeLeadingUnderscores(ts.getPropertyNameForPropertyNameNode(bindingElement.name)); result.push({ name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, bindingElement.pos), }); }); } else { let name = ts.unescapeLeadingUnderscores(ts.getPropertyNameForPropertyNameNode(d.name)); result.push({ name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, d.pos), }); } }); return result; } /** Function */ function transformFunction(node: ts.FunctionDeclaration, sourceFile: ts.SourceFile): types.DocumentedType { const name = ts.unescapeLeadingUnderscores(ts.getPropertyNameForPropertyNameNode(node.name)); const comment = getParsedComment(node, sourceFile); const subItems: types.DocumentedType[] = []; let icon = types.IconType.Function; if (node.typeParameters) { icon = types.IconType.FunctionGeneric; } return { name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, node.name.pos), }; } /** Module | Namespace */ function transformModule(node: ts.ModuleDeclaration, sourceFile: ts.SourceFile): types.DocumentedType { /** * Namespace chaining basics * a.b.c {} * a > declaration * b > declaration * c > declaration + body * * So if no body then we have to go down to get the name. * Also we the *body* is were we should recurse */ let icon = types.IconType.Namespace; let name = ts.unescapeLeadingUnderscores(ts.getPropertyNameForPropertyNameNode(node.name)); if (node.body.kind === ts.SyntaxKind.ModuleDeclaration) { name = name + '.'; const recurse = transformModule(node.body as ts.ModuleDeclaration, sourceFile); return { name: name + recurse.name, icon, comment: recurse.comment, subItems: recurse.subItems, location: getDocumentedTypeLocation(sourceFile, node.name.pos), } } else { const comment = getParsedComment(node, sourceFile); const subItems: types.DocumentedType[] = getSignificantSubItems(node.body as ts.ModuleBlock, sourceFile); return { name, icon, comment, subItems, location: getDocumentedTypeLocation(sourceFile, node.name.pos) }; } } // TODO: these /** Type */