alm
Version:
The best IDE for TypeScript
382 lines (339 loc) • 13.4 kB
text/typescript
/**
*
*
*
* 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 */