From 61a7e80fe8012fd31930af1536048d6d9b888f00 Mon Sep 17 00:00:00 2001 From: Bryan Forbes Date: Thu, 2 Mar 2017 12:07:02 -0600 Subject: [PATCH 1/2] Simplify the converter --- src/lib/converter/components.ts | 49 ------ src/lib/converter/converter.ts | 149 ++++++++++-------- src/lib/converter/index.ts | 2 - src/lib/converter/nodes/accessor.ts | 7 +- src/lib/converter/nodes/alias.ts | 9 +- src/lib/converter/nodes/block.ts | 31 +--- src/lib/converter/nodes/class.ts | 13 +- src/lib/converter/nodes/constructor.ts | 9 +- src/lib/converter/nodes/enum.ts | 7 +- src/lib/converter/nodes/export.ts | 7 +- src/lib/converter/nodes/function.ts | 7 +- src/lib/converter/nodes/index.ts | 2 + src/lib/converter/nodes/interface.ts | 11 +- src/lib/converter/nodes/literal-object.ts | 9 +- src/lib/converter/nodes/literal-type.ts | 9 +- src/lib/converter/nodes/module.ts | 9 +- src/lib/converter/nodes/node.ts | 22 +++ src/lib/converter/nodes/signature-call.ts | 7 +- src/lib/converter/nodes/signature-index.ts | 7 +- src/lib/converter/nodes/variable-statement.ts | 11 +- src/lib/converter/nodes/variable.ts | 17 +- src/lib/converter/types/alias.ts | 5 +- src/lib/converter/types/array.ts | 7 +- src/lib/converter/types/binding-array.ts | 7 +- src/lib/converter/types/binding-object.ts | 7 +- src/lib/converter/types/enum.ts | 5 +- src/lib/converter/types/index.ts | 2 + src/lib/converter/types/intrinsic.ts | 5 +- src/lib/converter/types/reference.ts | 11 +- src/lib/converter/types/string-literal.ts | 5 +- src/lib/converter/types/tuple.ts | 9 +- src/lib/converter/types/type-parameter.ts | 5 +- src/lib/converter/types/type.ts | 55 +++++++ src/lib/converter/types/union.ts | 9 +- src/lib/converter/types/unknown.ts | 5 +- tsconfig.json | 7 +- 36 files changed, 269 insertions(+), 269 deletions(-) create mode 100644 src/lib/converter/nodes/node.ts create mode 100644 src/lib/converter/types/type.ts diff --git a/src/lib/converter/components.ts b/src/lib/converter/components.ts index 68f21a29c..39e038dce 100644 --- a/src/lib/converter/components.ts +++ b/src/lib/converter/components.ts @@ -1,55 +1,6 @@ -import * as ts from 'typescript'; - import {Component, AbstractComponent} from '../utils/component'; -import {Reflection} from '../models/reflections/abstract'; -import {Type} from '../models/types/abstract'; -import {Context} from './context'; import {Converter} from './converter'; export {Component}; export abstract class ConverterComponent extends AbstractComponent { } - -export abstract class ConverterNodeComponent extends ConverterComponent { - /** - * List of supported TypeScript syntax kinds. - */ - supports: ts.SyntaxKind[]; - - abstract convert(context: Context, node: T): Reflection; -} - -export abstract class ConverterTypeComponent extends ConverterComponent { - /** - * The priority this converter should be executed with. - * A higher priority means the converter will be applied earlier. - */ - priority = 0; -} - -export interface TypeConverter - extends ConverterTypeComponent, TypeTypeConverter, TypeNodeConverter {} - -export interface TypeTypeConverter extends ConverterTypeComponent { - /** - * Test whether this converter can handle the given TypeScript type. - */ - supportsType(context: Context, type: T): boolean; - - /** - * Convert the given type to its type reflection. - */ - convertType(context: Context, type: T): Type; -} - -export interface TypeNodeConverter extends ConverterTypeComponent { - /** - * Test whether this converter can handle the given TypeScript node. - */ - supportsNode(context: Context, node: N, type: T): boolean; - - /** - * Convert the given type node to its type reflection. - */ - convertNode(context: Context, node: N, type: T): Type; -} diff --git a/src/lib/converter/converter.ts b/src/lib/converter/converter.ts index 847a6ce0d..bfb595511 100644 --- a/src/lib/converter/converter.ts +++ b/src/lib/converter/converter.ts @@ -1,16 +1,18 @@ import * as ts from 'typescript'; import * as _ts from '../ts-internal'; -import * as _ from 'lodash'; import {Application} from '../application'; import {ParameterType} from '../utils/options/declaration'; import {Reflection, Type, ProjectReflection} from '../models/index'; import {Context} from './context'; -import {ConverterComponent, ConverterNodeComponent, ConverterTypeComponent, TypeTypeConverter, TypeNodeConverter} from './components'; +import {ConverterComponent} from './components'; import {CompilerHost} from './utils/compiler-host'; -import {Component, Option, ChildableComponent, ComponentClass} from '../utils/component'; +import {Component, Option, ChildableComponent} from '../utils/component'; import {normalizePath} from '../utils/fs'; +import * as nodes from './nodes'; +import * as types from './types'; + /** * Result structure of the [[Converter.convert]] method. */ @@ -26,6 +28,10 @@ export interface ConverterResult { project: ProjectReflection; } +export enum SourceFileMode { + File, Modules +} + /** * Compiles source files using TypeScript and converts compiler symbols to reflections. */ @@ -74,13 +80,23 @@ export class Converter extends ChildableComponent}; + @Option({ + name: 'mode', + help: "Specifies the output mode the project is used to be compiled with: 'file' or 'modules'", + type: ParameterType.Map, + map: { + 'file': SourceFileMode.File, + 'modules': SourceFileMode.Modules + }, + defaultValue: SourceFileMode.Modules + }) + mode: SourceFileMode; - private typeNodeConverters: TypeNodeConverter[]; + private compilerHost: CompilerHost; - private typeTypeConverters: TypeTypeConverter[]; + private nodeConverters: Map; + private typeNodeConverters: types.NodeTypeConverter[]; + private typeTypeConverters: types.TypeTypeConverter[]; /** * General events @@ -171,6 +187,40 @@ export class Converter extends ChildableComponent): ConverterComponent { - const component = super.addComponent(name, componentClass); - if (component instanceof ConverterNodeComponent) { - this.addNodeConverter(component); - } else if (component instanceof ConverterTypeComponent) { - this.addTypeConverter(|TypeNodeConverter> component); - } - - return component; - } - - private addNodeConverter(converter: ConverterNodeComponent) { - for (let supports of converter.supports) { - this.nodeConverters[supports] = converter; - } - } - private addTypeConverter(converter: TypeTypeConverter|TypeNodeConverter) { - if ('supportsNode' in converter && 'convertNode' in converter) { - this.typeNodeConverters.push(> converter); - this.typeNodeConverters.sort((a, b) => (b.priority || 0) - (a.priority || 0)); + this.nodeConverters = new Map(); + for (let ctor of Converter.nodeConverterClasses) { + this.addNodeConverter(ctor); } - if ('supportsType' in converter && 'convertType' in converter) { - this.typeTypeConverters.push(> converter); - this.typeTypeConverters.sort((a, b) => (b.priority || 0) - (a.priority || 0)); + this.typeTypeConverters = []; + this.typeNodeConverters = []; + for (let ctor of Converter.typeConverterClasses) { + this.addTypeConverter(ctor); } + this.typeNodeConverters.sort((a, b) => b.priority - a.priority); + this.typeTypeConverters.sort((a, b) => b.priority - a.priority); } - removeComponent(name: string): ConverterComponent { - const component = super.removeComponent(name); - if (component instanceof ConverterNodeComponent) { - this.removeNodeConverter(component); - } else if (component instanceof ConverterTypeComponent) { - this.removeTypeConverter(component); + private addNodeConverter(componentClass: nodes.NodeConverterConstructor) { + const converter = new componentClass(this); + for (let kind of componentClass.supports) { + this.nodeConverters.set(kind, converter); } - - return component; } - private removeNodeConverter(converter: ConverterNodeComponent) { - const converters = this.nodeConverters; - const keys = _.keys(this.nodeConverters); - for (let key of keys) { - if (converters[key] === converter) { - delete converters[key]; - } - } - } + private addTypeConverter(converterClass: types.TypeConverterConstructor) { + const converter = new converterClass(this); - private removeTypeConverter(converter: ConverterTypeComponent) { - let index = this.typeNodeConverters.indexOf( converter); - if (index !== -1) { - this.typeTypeConverters.splice(index, 1); + if (types.isNodeTypeConverter(converter)) { + this.typeNodeConverters.push(converter); } - index = this.typeNodeConverters.indexOf( converter); - if (index !== -1) { - this.typeNodeConverters.splice(index, 1); + if (types.isTypeTypeConverter(converter)) { + this.typeTypeConverters.push(converter); } } - removeAllComponents() { - super.removeAllComponents(); - - this.nodeConverters = {}; - this.typeTypeConverters = []; - this.typeNodeConverters = []; - } - /** * Compile the given source files and create a project reflection for them. * @@ -300,8 +309,8 @@ export class Converter extends ChildableComponent { +export class AccessorConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.GetAccessor, ts.SyntaxKind.SetAccessor ]; diff --git a/src/lib/converter/nodes/alias.ts b/src/lib/converter/nodes/alias.ts index cf42b5adc..dfe1488d3 100644 --- a/src/lib/converter/nodes/alias.ts +++ b/src/lib/converter/nodes/alias.ts @@ -3,14 +3,13 @@ import * as ts from 'typescript'; import {Reflection, ReflectionKind} from '../../models/index'; import {createDeclaration} from '../factories/index'; import {Context} from '../context'; -import {Component, ConverterNodeComponent} from '../components'; +import {NodeConverter} from './node'; -@Component({name: 'node:alias'}) -export class AliasConverter extends ConverterNodeComponent { +export class AliasConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.TypeAliasDeclaration ]; @@ -25,7 +24,7 @@ export class AliasConverter extends ConverterNodeComponent { - alias.type = this.owner.convertType(context, node.type, context.getTypeAtLocation(node.type)); + alias.type = this.converter.convertType(context, node.type, context.getTypeAtLocation(node.type)); }); return alias; diff --git a/src/lib/converter/nodes/block.ts b/src/lib/converter/nodes/block.ts index 6c35a0ef0..45094ff26 100644 --- a/src/lib/converter/nodes/block.ts +++ b/src/lib/converter/nodes/block.ts @@ -3,9 +3,8 @@ import * as ts from 'typescript'; import {Reflection, ReflectionKind, ReflectionFlag} from '../../models/index'; import {createDeclaration} from '../factories/index'; import {Context} from '../context'; -import {Component, ConverterNodeComponent} from '../components'; -import {Option} from '../../utils/component'; -import {ParameterType} from '../../utils/options/declaration'; +import {NodeConverter} from './node'; +import {SourceFileMode} from '../converter'; const prefered: ts.SyntaxKind[] = [ ts.SyntaxKind.ClassDeclaration, @@ -13,28 +12,12 @@ const prefered: ts.SyntaxKind[] = [ ts.SyntaxKind.EnumDeclaration ]; -export enum SourceFileMode { - File, Modules -} - -@Component({name: 'node:block'}) -export class BlockConverter extends ConverterNodeComponent { - @Option({ - name: 'mode', - help: "Specifies the output mode the project is used to be compiled with: 'file' or 'modules'", - type: ParameterType.Map, - map: { - 'file': SourceFileMode.File, - 'modules': SourceFileMode.Modules - }, - defaultValue: SourceFileMode.Modules - }) - mode: number; +export class BlockConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.Block, ts.SyntaxKind.ModuleBlock, ts.SyntaxKind.SourceFile @@ -68,7 +51,7 @@ export class BlockConverter extends ConverterNodeComponent { - if (this.mode === SourceFileMode.Modules) { + if (this.converter.mode === SourceFileMode.Modules) { result = createDeclaration(context, node, ReflectionKind.ExternalModule, node.fileName); context.withScope(result, () => { this.convertStatements(context, node); @@ -88,14 +71,14 @@ export class BlockConverter extends ConverterNodeComponent { if (prefered.indexOf(statement.kind) !== -1) { - this.owner.convertNode(context, statement); + this.converter.convertNode(context, statement); } else { statements.push(statement); } }); statements.forEach((statement) => { - this.owner.convertNode(context, statement); + this.converter.convertNode(context, statement); }); } } diff --git a/src/lib/converter/nodes/class.ts b/src/lib/converter/nodes/class.ts index 5feda6dcc..bc4bef245 100644 --- a/src/lib/converter/nodes/class.ts +++ b/src/lib/converter/nodes/class.ts @@ -4,14 +4,13 @@ import * as _ts from '../../ts-internal'; import {Reflection, ReflectionKind, DeclarationReflection} from '../../models/index'; import {createDeclaration} from '../factories/index'; import {Context} from '../context'; -import {Component, ConverterNodeComponent} from '../components'; +import {NodeConverter} from './node'; -@Component({name: 'node:class'}) -export class ClassConverter extends ConverterNodeComponent { +export class ClassConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.ClassExpression, ts.SyntaxKind.ClassDeclaration ]; @@ -39,7 +38,7 @@ export class ClassConverter extends ConverterNodeComponent const exclude = context.converter.excludePrivate ? privateMember : false; if (!exclude) { - this.owner.convertNode(context, member); + this.converter.convertNode(context, member); } }); } @@ -51,7 +50,7 @@ export class ClassConverter extends ConverterNodeComponent if (!reflection.extendedTypes) { reflection.extendedTypes = []; } - reflection.extendedTypes.push(this.owner.convertType(context, baseType, type)); + reflection.extendedTypes.push(this.converter.convertType(context, baseType, type)); } if (type && type.symbol) { @@ -68,7 +67,7 @@ export class ClassConverter extends ConverterNodeComponent reflection.implementedTypes = []; } - reflection.implementedTypes.push(this.owner.convertType(context, implementedType)); + reflection.implementedTypes.push(this.converter.convertType(context, implementedType)); }); } }); diff --git a/src/lib/converter/nodes/constructor.ts b/src/lib/converter/nodes/constructor.ts index 8ca1dcf1b..919335931 100644 --- a/src/lib/converter/nodes/constructor.ts +++ b/src/lib/converter/nodes/constructor.ts @@ -4,14 +4,13 @@ import {Reflection, ReflectionKind, ReflectionFlag, ReferenceType, Comment} from import {createDeclaration, createSignature, createComment} from '../factories/index'; import {Context} from '../context'; import {Converter} from '../converter'; -import {Component, ConverterNodeComponent} from '../components'; +import {NodeConverter} from './node'; -@Component({name: 'node:constructor'}) -export class ConstructorConverter extends ConverterNodeComponent { +export class ConstructorConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.Constructor, ts.SyntaxKind.ConstructSignature ]; @@ -75,7 +74,7 @@ export class ConstructorConverter extends ConverterNodeComponent { +export class EnumConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.EnumDeclaration ]; diff --git a/src/lib/converter/nodes/export.ts b/src/lib/converter/nodes/export.ts index 3e52cb2e7..f18de1d50 100644 --- a/src/lib/converter/nodes/export.ts +++ b/src/lib/converter/nodes/export.ts @@ -2,14 +2,13 @@ import * as ts from 'typescript'; import {Reflection, ReflectionFlag, DeclarationReflection} from '../../models/index'; import {Context} from '../context'; -import {Component, ConverterNodeComponent} from '../components'; +import {NodeConverter} from './node'; -@Component({name: 'node:export'}) -export class ExportConverter extends ConverterNodeComponent { +export class ExportConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.ExportAssignment ]; diff --git a/src/lib/converter/nodes/function.ts b/src/lib/converter/nodes/function.ts index 5d165ff67..d6802b22d 100644 --- a/src/lib/converter/nodes/function.ts +++ b/src/lib/converter/nodes/function.ts @@ -4,14 +4,13 @@ import {Reflection, ReflectionKind} from '../../models/index'; import {createDeclaration, createSignature} from '../factories/index'; import {Context} from '../context'; import {Converter} from '../converter'; -import {Component, ConverterNodeComponent} from '../components'; +import {NodeConverter} from './node'; -@Component({name: 'node:function'}) -export class FunctionConverter extends ConverterNodeComponent { +export class FunctionConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.MethodSignature, ts.SyntaxKind.MethodDeclaration, ts.SyntaxKind.FunctionDeclaration diff --git a/src/lib/converter/nodes/index.ts b/src/lib/converter/nodes/index.ts index a4c50e83c..388ebc6fd 100644 --- a/src/lib/converter/nodes/index.ts +++ b/src/lib/converter/nodes/index.ts @@ -1,3 +1,5 @@ +export * from './node'; + export {AccessorConverter} from './accessor'; export {AliasConverter} from './alias'; export {BlockConverter} from './block'; diff --git a/src/lib/converter/nodes/interface.ts b/src/lib/converter/nodes/interface.ts index 589c86ab8..7f51ad35c 100644 --- a/src/lib/converter/nodes/interface.ts +++ b/src/lib/converter/nodes/interface.ts @@ -4,14 +4,13 @@ import * as _ts from '../../ts-internal'; import {Reflection, ReflectionKind, DeclarationReflection} from '../../models/index'; import {createDeclaration} from '../factories/index'; import {Context} from '../context'; -import {Component, ConverterNodeComponent} from '../components'; +import {NodeConverter} from './node'; -@Component({name: 'node:interface'}) -export class InterfaceConverter extends ConverterNodeComponent { +export class InterfaceConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.InterfaceDeclaration ]; @@ -33,7 +32,7 @@ export class InterfaceConverter extends ConverterNodeComponent { if (node.members) { node.members.forEach((member, isInherit) => { - this.owner.convertNode(context, member); + this.converter.convertNode(context, member); }); } @@ -45,7 +44,7 @@ export class InterfaceConverter extends ConverterNodeComponent { +export class ObjectLiteralConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.ObjectLiteralExpression ]; @@ -23,7 +22,7 @@ export class ObjectLiteralConverter extends ConverterNodeComponent { - this.owner.convertNode(context, node); + this.converter.convertNode(context, node); }); } diff --git a/src/lib/converter/nodes/literal-type.ts b/src/lib/converter/nodes/literal-type.ts index 1ad390b5d..afe2545a0 100644 --- a/src/lib/converter/nodes/literal-type.ts +++ b/src/lib/converter/nodes/literal-type.ts @@ -2,14 +2,13 @@ import * as ts from 'typescript'; import {Reflection} from '../../models/index'; import {Context} from '../context'; -import {Component, ConverterNodeComponent} from '../components'; +import {NodeConverter} from './node'; -@Component({name: 'node:literal-type'}) -export class TypeLiteralConverter extends ConverterNodeComponent { +export class TypeLiteralConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.TypeLiteral ]; @@ -23,7 +22,7 @@ export class TypeLiteralConverter extends ConverterNodeComponent { - this.owner.convertNode(context, node); + this.converter.convertNode(context, node); }); } diff --git a/src/lib/converter/nodes/module.ts b/src/lib/converter/nodes/module.ts index e916716bf..21af2e440 100644 --- a/src/lib/converter/nodes/module.ts +++ b/src/lib/converter/nodes/module.ts @@ -3,14 +3,13 @@ import * as ts from 'typescript'; import {Reflection, ReflectionKind, ReflectionFlag, ProjectReflection} from '../../models/index'; import {createDeclaration} from '../factories/index'; import {Context} from '../context'; -import {Component, ConverterNodeComponent} from '../components'; +import {NodeConverter} from './node'; -@Component({name: 'node:module'}) -export class ModuleConverter extends ConverterNodeComponent { +export class ModuleConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.ModuleDeclaration ]; @@ -32,7 +31,7 @@ export class ModuleConverter extends ConverterNodeComponent { +export class SignatureConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.CallSignature, ts.SyntaxKind.FunctionType, ts.SyntaxKind.FunctionExpression, diff --git a/src/lib/converter/nodes/signature-index.ts b/src/lib/converter/nodes/signature-index.ts index d041349c4..c05b5eb5e 100644 --- a/src/lib/converter/nodes/signature-index.ts +++ b/src/lib/converter/nodes/signature-index.ts @@ -3,14 +3,13 @@ import * as ts from 'typescript'; import {Reflection, ReflectionKind, DeclarationReflection} from '../../models/index'; import {createSignature} from '../factories/index'; import {Context} from '../context'; -import {Component, ConverterNodeComponent} from '../components'; +import {NodeConverter} from './node'; -@Component({name: 'node:signature-index'}) -export class IndexSignatureConverter extends ConverterNodeComponent { +export class IndexSignatureConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.IndexSignature ]; diff --git a/src/lib/converter/nodes/variable-statement.ts b/src/lib/converter/nodes/variable-statement.ts index 757ba2968..8ee48b226 100644 --- a/src/lib/converter/nodes/variable-statement.ts +++ b/src/lib/converter/nodes/variable-statement.ts @@ -3,14 +3,13 @@ import * as _ts from '../../ts-internal'; import {Reflection} from '../../models/index'; import {Context} from '../context'; -import {Component, ConverterNodeComponent} from '../components'; +import {NodeConverter} from './node'; -@Component({name: 'node:variable-statement'}) -export class VariableStatementConverter extends ConverterNodeComponent { +export class VariableStatementConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.VariableStatement ]; @@ -27,7 +26,7 @@ export class VariableStatementConverter extends ConverterNodeComponent variableDeclaration.name); } else { - this.owner.convertNode(context, variableDeclaration); + this.converter.convertNode(context, variableDeclaration); } }); } @@ -43,7 +42,7 @@ export class VariableStatementConverter extends ConverterNodeComponent { - this.owner.convertNode(context, element); + this.converter.convertNode(context, element); if (_ts.isBindingPattern(element.name)) { this.convertBindingPattern(context, element.name); diff --git a/src/lib/converter/nodes/variable.ts b/src/lib/converter/nodes/variable.ts index 4c5e7f6fb..1b2ade4bf 100644 --- a/src/lib/converter/nodes/variable.ts +++ b/src/lib/converter/nodes/variable.ts @@ -4,15 +4,14 @@ import * as _ts from '../../ts-internal'; import {Reflection, ReflectionKind, IntrinsicType} from '../../models/index'; import {createDeclaration, createComment} from '../factories/index'; import {Context} from '../context'; -import {Component, ConverterNodeComponent} from '../components'; +import {NodeConverter} from './node'; import {convertDefaultValue} from '../index'; -@Component({name: 'node:variable'}) -export class VariableConverter extends ConverterNodeComponent { +export class VariableConverter extends NodeConverter { /** * List of supported TypeScript syntax kinds. */ - supports: ts.SyntaxKind[] = [ + static supports: ts.SyntaxKind[] = [ ts.SyntaxKind.PropertySignature, ts.SyntaxKind.PropertyDeclaration, ts.SyntaxKind.PropertyAssignment, @@ -40,7 +39,7 @@ export class VariableConverter extends ConverterNodeComponent node.initializer)) { variable.kind = ReflectionKind.ObjectLiteral; variable.type = new IntrinsicType('object'); - this.owner.convertNode(context, node.initializer); + this.converter.convertNode(context, node.initializer); } break; default: @@ -83,9 +82,9 @@ export class VariableConverter extends ConverterNodeComponent { +export class AliasConverter extends TypeConverter implements NodeTypeConverter { /** * The priority this converter should be executed with. * A higher priority means the converter will be applied earlier. diff --git a/src/lib/converter/types/array.ts b/src/lib/converter/types/array.ts index 2b87e4023..59b839c86 100644 --- a/src/lib/converter/types/array.ts +++ b/src/lib/converter/types/array.ts @@ -1,11 +1,10 @@ import * as ts from 'typescript'; import {Type, IntrinsicType} from '../../models/index'; -import {Component, ConverterTypeComponent, TypeNodeConverter} from '../components'; +import {TypeConverter, NodeTypeConverter} from './type'; import {Context} from '../context'; -@Component({name: 'type:array'}) -export class ArrayConverter extends ConverterTypeComponent implements TypeNodeConverter { +export class ArrayConverter extends TypeConverter implements NodeTypeConverter { /** * Test whether this converter can handle the given TypeScript node. */ @@ -27,7 +26,7 @@ export class ArrayConverter extends ConverterTypeComponent implements TypeNodeCo * @returns The type reflection representing the given array type node. */ convertNode(context: Context, node: ts.ArrayTypeNode): Type { - let result = this.owner.convertType(context, node.elementType); + let result = this.converter.convertType(context, node.elementType); if (result) { result.isArray = true; diff --git a/src/lib/converter/types/binding-array.ts b/src/lib/converter/types/binding-array.ts index f865ab475..2173a98a5 100644 --- a/src/lib/converter/types/binding-array.ts +++ b/src/lib/converter/types/binding-array.ts @@ -1,11 +1,10 @@ import * as ts from 'typescript'; import {Type, TupleType} from '../../models/index'; -import {Component, ConverterTypeComponent, TypeNodeConverter} from '../components'; +import {TypeConverter, NodeTypeConverter} from './type'; import {Context} from '../context'; -@Component({name: 'type:binding-array'}) -export class BindingArrayConverter extends ConverterTypeComponent implements TypeNodeConverter { +export class BindingArrayConverter extends TypeConverter implements NodeTypeConverter { /** * Test whether this converter can handle the given TypeScript node. */ @@ -24,7 +23,7 @@ export class BindingArrayConverter extends ConverterTypeComponent implements Typ const types: Type[] = []; (node.elements as ts.BindingElement[]).forEach((element) => { - types.push(this.owner.convertType(context, element)); + types.push(this.converter.convertType(context, element)); }); return new TupleType(types); diff --git a/src/lib/converter/types/binding-object.ts b/src/lib/converter/types/binding-object.ts index 4c99b3533..6d506f84d 100644 --- a/src/lib/converter/types/binding-object.ts +++ b/src/lib/converter/types/binding-object.ts @@ -1,12 +1,11 @@ import * as ts from 'typescript'; import {Type, ReflectionKind, DeclarationReflection, ReflectionType} from '../../models/index'; -import {Component, ConverterTypeComponent, TypeNodeConverter} from '../components'; +import {TypeConverter, NodeTypeConverter} from './type'; import {Context} from '../context'; import {Converter} from '../converter'; -@Component({name: 'type:binding-object'}) -export class BindingObjectConverter extends ConverterTypeComponent implements TypeNodeConverter { +export class BindingObjectConverter extends TypeConverter implements NodeTypeConverter { /** * Test whether this converter can handle the given TypeScript node. */ @@ -31,7 +30,7 @@ export class BindingObjectConverter extends ConverterTypeComponent implements Ty context.trigger(Converter.EVENT_CREATE_DECLARATION, declaration, node); context.withScope(declaration, () => { (node.elements as ts.BindingElement[]).forEach((element) => { - this.owner.convertNode(context, element); + this.converter.convertNode(context, element); }); }); diff --git a/src/lib/converter/types/enum.ts b/src/lib/converter/types/enum.ts index 5f4e84f06..79ad81972 100644 --- a/src/lib/converter/types/enum.ts +++ b/src/lib/converter/types/enum.ts @@ -2,11 +2,10 @@ import * as ts from 'typescript'; import {Type} from '../../models/index'; import {createReferenceType} from '../factories/index'; -import {Component, ConverterTypeComponent, TypeTypeConverter} from '../components'; +import {TypeConverter, TypeTypeConverter} from './type'; import {Context} from '../context'; -@Component({name: 'type:enum'}) -export class EnumConverter extends ConverterTypeComponent implements TypeTypeConverter { +export class EnumConverter extends TypeConverter implements TypeTypeConverter { /** * Test whether this converter can handle the given TypeScript type. */ diff --git a/src/lib/converter/types/index.ts b/src/lib/converter/types/index.ts index ede95d9c6..1956912a5 100644 --- a/src/lib/converter/types/index.ts +++ b/src/lib/converter/types/index.ts @@ -1,3 +1,5 @@ +export * from './type'; + export {AliasConverter} from './alias'; export {ArrayConverter} from './array'; export {BindingArrayConverter} from './binding-array'; diff --git a/src/lib/converter/types/intrinsic.ts b/src/lib/converter/types/intrinsic.ts index 152d8000e..f0445e385 100644 --- a/src/lib/converter/types/intrinsic.ts +++ b/src/lib/converter/types/intrinsic.ts @@ -1,7 +1,7 @@ import * as ts from 'typescript'; import {IntrinsicType} from '../../models/index'; -import {Component, ConverterTypeComponent, TypeTypeConverter} from '../components'; +import {TypeConverter, TypeTypeConverter} from './type'; import {Context} from '../context'; // TypeScript has an @internal enum set for the intrinsic types: @@ -13,8 +13,7 @@ if (IntrinsicTypeFlags === undefined) { throw new Error('Internal TypeScript API missing: TypeFlags.Intrinsic'); } -@Component({name: 'type:intrinsic'}) -export class IntrinsicConverter extends ConverterTypeComponent implements TypeTypeConverter { +export class IntrinsicConverter extends TypeConverter implements TypeTypeConverter { /** * Test whether this converter can handle the given TypeScript type. */ diff --git a/src/lib/converter/types/reference.ts b/src/lib/converter/types/reference.ts index c8906f7f8..0530fd7d5 100644 --- a/src/lib/converter/types/reference.ts +++ b/src/lib/converter/types/reference.ts @@ -3,12 +3,11 @@ import * as ts from 'typescript'; import {Type, IntrinsicType, ReflectionType} from '../../models/types/index'; import {ReflectionKind, DeclarationReflection} from '../../models/reflections/index'; import {createReferenceType} from '../factories/index'; -import {Component, ConverterTypeComponent, TypeNodeConverter} from '../components'; +import {TypeConverter, NodeTypeConverter, TypeTypeConverter} from './type'; import {Context} from '../context'; import {Converter} from '../converter'; -@Component({name: 'type:reference'}) -export class ReferenceConverter extends ConverterTypeComponent implements TypeNodeConverter { +export class ReferenceConverter extends TypeConverter implements NodeTypeConverter, TypeTypeConverter { /** * The priority this converter should be executed with. * A higher priority means the converter will be applied earlier. @@ -53,7 +52,7 @@ export class ReferenceConverter extends ConverterTypeComponent implements TypeNo const result = createReferenceType(context, type.symbol); if (node.typeArguments) { - result.typeArguments = node.typeArguments.map((n) => this.owner.convertType(context, n)); + result.typeArguments = node.typeArguments.map((n) => this.converter.convertType(context, n)); } return result; @@ -82,7 +81,7 @@ export class ReferenceConverter extends ConverterTypeComponent implements TypeNo const result = createReferenceType(context, type.symbol); if (type.typeArguments) { - result.typeArguments = type.typeArguments.map((t) => this.owner.convertType(context, null, t)); + result.typeArguments = type.typeArguments.map((t) => this.converter.convertType(context, null, t)); } return result; @@ -131,7 +130,7 @@ export class ReferenceConverter extends ConverterTypeComponent implements TypeNo context.trigger(Converter.EVENT_CREATE_DECLARATION, declaration, node); context.withScope(declaration, () => { symbol.declarations.forEach((node) => { - this.owner.convertNode(context, node); + this.converter.convertNode(context, node); }); }); diff --git a/src/lib/converter/types/string-literal.ts b/src/lib/converter/types/string-literal.ts index 4a18c4dfe..60c80b946 100644 --- a/src/lib/converter/types/string-literal.ts +++ b/src/lib/converter/types/string-literal.ts @@ -1,11 +1,10 @@ import * as ts from 'typescript'; import {Type, StringLiteralType} from '../../models/types/index'; -import {Component, ConverterTypeComponent, TypeConverter} from '../components'; +import {TypeConverter, NodeTypeConverter, TypeTypeConverter} from './type'; import {Context} from '../context'; -@Component({name: 'type:string-literal'}) -export class StringLiteralConverter extends ConverterTypeComponent implements TypeConverter { +export class StringLiteralConverter extends TypeConverter implements NodeTypeConverter, TypeTypeConverter { /** * Test whether this converter can handle the given TypeScript node. */ diff --git a/src/lib/converter/types/tuple.ts b/src/lib/converter/types/tuple.ts index 034bbc9b2..eefe484f0 100644 --- a/src/lib/converter/types/tuple.ts +++ b/src/lib/converter/types/tuple.ts @@ -1,11 +1,10 @@ import * as ts from 'typescript'; import {Type, TupleType} from '../../models/types/index'; -import {Component, ConverterTypeComponent, TypeConverter} from '../components'; +import {TypeConverter, NodeTypeConverter, TypeTypeConverter} from './type'; import {Context} from '../context'; -@Component({name: 'type:tuple'}) -export class TupleConverter extends ConverterTypeComponent implements TypeConverter { +export class TupleConverter extends TypeConverter implements NodeTypeConverter, TypeTypeConverter { /** * Test whether this converter can handle the given TypeScript node. */ @@ -36,7 +35,7 @@ export class TupleConverter extends ConverterTypeComponent implements TypeConver convertNode(context: Context, node: ts.TupleTypeNode): TupleType { let elements: Type[]; if (node.elementTypes) { - elements = node.elementTypes.map((n) => this.owner.convertType(context, n)); + elements = node.elementTypes.map((n) => this.converter.convertType(context, n)); } else { elements = []; } @@ -60,7 +59,7 @@ export class TupleConverter extends ConverterTypeComponent implements TypeConver convertType(context: Context, type: ts.TypeReference): TupleType { let elements: Type[]; if (type.typeArguments) { - elements = type.typeArguments.map((t) => this.owner.convertType(context, null, t)); + elements = type.typeArguments.map((t) => this.converter.convertType(context, null, t)); } else { elements = []; } diff --git a/src/lib/converter/types/type-parameter.ts b/src/lib/converter/types/type-parameter.ts index 40ce72141..08c11dd28 100644 --- a/src/lib/converter/types/type-parameter.ts +++ b/src/lib/converter/types/type-parameter.ts @@ -2,11 +2,10 @@ import * as ts from 'typescript'; import * as _ts from '../../ts-internal'; import {Type, TypeParameterType} from '../../models/types/index'; -import {Component, ConverterTypeComponent, TypeNodeConverter} from '../components'; +import {TypeConverter, NodeTypeConverter} from './type'; import {Context} from '../context'; -@Component({name: 'type:type-parameter'}) -export class TypeParameterConverter extends ConverterTypeComponent implements TypeNodeConverter { +export class TypeParameterConverter extends TypeConverter implements NodeTypeConverter { /** * The priority this converter should be executed with. * A higher priority means the converter will be applied earlier. diff --git a/src/lib/converter/types/type.ts b/src/lib/converter/types/type.ts new file mode 100644 index 000000000..aebf7c04f --- /dev/null +++ b/src/lib/converter/types/type.ts @@ -0,0 +1,55 @@ +import * as ts from 'typescript'; + +import {Type} from '../../models/types/abstract'; +import {Context} from '../context'; +import {Converter} from '../converter'; + +export type TypeConverterConstructor = new (converter: Converter) => TypeConverter; + +export abstract class TypeConverter { + /** + * The priority this converter should be executed with. + * A higher priority means the converter will be applied earlier. + */ + priority = 0; + + protected converter: Converter; + + constructor(converter: Converter) { + this.converter = converter; + } +} + +export interface NodeTypeConverter extends TypeConverter { + /** + * Test whether this converter can handle the given TypeScript node. + */ + supportsNode(context: Context, node: ts.Node, type: ts.Type): boolean; + + /** + * Convert the given type node to its type reflection. + */ + convertNode(context: Context, node: ts.Node, type: ts.Type): Type; +} + +export function isNodeTypeConverter(object: any): object is NodeTypeConverter { + return object instanceof TypeConverter && ('supportsNode' in object) && + ('convertNode' in object); +} + +export interface TypeTypeConverter extends TypeConverter { + /** + * Test whether this converter can handle the given TypeScript type. + */ + supportsType(context: Context, type: ts.Type): boolean; + + /** + * Convert the given type to its type reflection. + */ + convertType(context: Context, type: ts.Type): Type; +} + +export function isTypeTypeConverter(object: any): object is TypeTypeConverter { + return object instanceof TypeConverter && ('supportsType' in object) && + ('convertType' in object); +} diff --git a/src/lib/converter/types/union.ts b/src/lib/converter/types/union.ts index bdef3b666..5438fa69d 100644 --- a/src/lib/converter/types/union.ts +++ b/src/lib/converter/types/union.ts @@ -1,11 +1,10 @@ import * as ts from 'typescript'; import {Type, UnionType} from '../../models/types/index'; -import {Component, ConverterTypeComponent, TypeConverter} from '../components'; +import {TypeConverter, NodeTypeConverter, TypeTypeConverter} from './type'; import {Context} from '../context'; -@Component({name: 'type:union'}) -export class UnionConverter extends ConverterTypeComponent implements TypeConverter { +export class UnionConverter extends TypeConverter implements NodeTypeConverter, TypeTypeConverter { /** * Test whether this converter can handle the given TypeScript node. */ @@ -36,7 +35,7 @@ export class UnionConverter extends ConverterTypeComponent implements TypeConver convertNode(context: Context, node: ts.UnionTypeNode): UnionType { let types: Type[] = []; if (node.types) { - types = node.types.map((n) => this.owner.convertType(context, n)); + types = node.types.map((n) => this.converter.convertType(context, n)); } else { types = []; } @@ -60,7 +59,7 @@ export class UnionConverter extends ConverterTypeComponent implements TypeConver convertType(context: Context, type: ts.UnionType): UnionType { let types: Type[]; if (type && type.types) { - types = type.types.map((t) => this.owner.convertType(context, null, t)); + types = type.types.map((t) => this.converter.convertType(context, null, t)); } else { types = []; } diff --git a/src/lib/converter/types/unknown.ts b/src/lib/converter/types/unknown.ts index daee0ce3f..e1eda9342 100644 --- a/src/lib/converter/types/unknown.ts +++ b/src/lib/converter/types/unknown.ts @@ -1,11 +1,10 @@ import * as ts from 'typescript'; import {Type, UnknownType} from '../../models/types/index'; -import {Component, ConverterTypeComponent, TypeTypeConverter} from '../components'; +import {TypeConverter, TypeTypeConverter} from './type'; import {Context} from '../context'; -@Component({name: 'type:unknown'}) -export class UnknownConverter extends ConverterTypeComponent implements TypeTypeConverter { +export class UnknownConverter extends TypeConverter implements TypeTypeConverter { /** * The priority this converter should be executed with. * A higher priority means the converter will be applied earlier. diff --git a/tsconfig.json b/tsconfig.json index 386e61abd..35212a83a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,12 @@ "inlineSources": true, // Required for debugging NPM published package. "outDir": "dist/", "rootDir": "src/", - "experimentalDecorators": true + "experimentalDecorators": true, + "lib": [ + "dom", + "es5", + "es2015.collection" + ] }, "include": [ "src/**/*.ts" From fbb32df59171965c1345118c600b9cd229e385ae Mon Sep 17 00:00:00 2001 From: Bryan Forbes Date: Thu, 2 Mar 2017 17:06:50 -0600 Subject: [PATCH 2/2] More converter cleanup --- src/lib/application.ts | 81 ++++++++- src/lib/converter/components.ts | 6 - src/lib/converter/context.ts | 18 +- src/lib/converter/converter.ts | 166 ++++++++++-------- src/lib/converter/factories/declaration.ts | 2 +- src/lib/converter/index.ts | 4 +- src/lib/converter/nodes/block.ts | 2 +- src/lib/converter/nodes/class.ts | 2 +- src/lib/converter/nodes/constructor.ts | 2 +- src/lib/converter/plugins/CommentPlugin.ts | 7 +- src/lib/converter/plugins/DecoratorPlugin.ts | 7 +- .../converter/plugins/DeepCommentPlugin.ts | 7 +- .../converter/plugins/DynamicModulePlugin.ts | 7 +- src/lib/converter/plugins/GitHubPlugin.ts | 7 +- src/lib/converter/plugins/GroupPlugin.ts | 7 +- src/lib/converter/plugins/ImplementsPlugin.ts | 7 +- src/lib/converter/plugins/PackagePlugin.ts | 16 +- src/lib/converter/plugins/Plugin.ts | 17 ++ src/lib/converter/plugins/SourcePlugin.ts | 7 +- src/lib/converter/plugins/TypePlugin.ts | 7 +- src/lib/converter/plugins/index.ts | 2 + src/lib/converter/utils/compiler-host.ts | 158 ----------------- 22 files changed, 236 insertions(+), 303 deletions(-) delete mode 100644 src/lib/converter/components.ts create mode 100644 src/lib/converter/plugins/Plugin.ts delete mode 100644 src/lib/converter/utils/compiler-host.ts diff --git a/src/lib/application.ts b/src/lib/application.ts index ee09f0aee..acfe39e0f 100644 --- a/src/lib/application.ts +++ b/src/lib/application.ts @@ -11,7 +11,7 @@ import * as FS from 'fs'; import * as typescript from 'typescript'; import {Minimatch, IMinimatch} from 'minimatch'; -import {Converter} from './converter/index'; +import {Converter, SourceFileMode} from './converter/index'; import {Renderer} from './output/renderer'; import {ProjectReflection} from './models/index'; import {Logger, ConsoleLogger, CallbackLogger, PluginHost, writeFile} from './utils/index'; @@ -77,6 +77,67 @@ export class Application extends ChildableComponent { } diff --git a/src/lib/converter/context.ts b/src/lib/converter/context.ts index 38e0b1bbd..c555347e2 100644 --- a/src/lib/converter/context.ts +++ b/src/lib/converter/context.ts @@ -1,7 +1,7 @@ import * as ts from 'typescript'; import {Minimatch, IMinimatch} from 'minimatch'; -import {Logger} from '../utils/loggers'; +// import {Logger} from '../utils/loggers'; import {Reflection, ProjectReflection, ContainerReflection, Type} from '../models/index'; import {createTypeParameter} from './factories/type-parameter'; import {Converter} from './converter'; @@ -109,12 +109,12 @@ export class Context { this.program = program; this.visitStack = []; - const project = new ProjectReflection(converter.name); + const project = new ProjectReflection(converter.options.name); this.project = project; this.scope = project; - if (converter.externalPattern) { - this.externalPattern = new Minimatch(converter.externalPattern); + if (converter.options.externalPattern) { + this.externalPattern = new Minimatch(converter.options.externalPattern); } } @@ -122,7 +122,7 @@ export class Context { * Return the compiler options. */ getCompilerOptions(): ts.CompilerOptions { - return this.converter.application.options.getCompilerOptions(); + return this.converter.options.compilerOptions; } /** @@ -154,9 +154,9 @@ export class Context { * * @returns The current logger instance. */ - getLogger(): Logger { + /*getLogger(): Logger { return this.converter.application.logger; - } + }*/ /** * Return the symbol id of the given symbol. @@ -222,7 +222,7 @@ export class Context { isExternal = isExternal || externalPattern.match(node.fileName); } - if (isExternal && this.converter.excludeExternals) { + if (isExternal && this.converter.options.excludeExternals) { return; } @@ -230,7 +230,7 @@ export class Context { if (isDeclaration) { const lib = this.converter.getDefaultLib(); const isLib = node.fileName.substr(-lib.length) === lib; - if (!this.converter.includeDeclarations || isLib) { + if (!this.converter.options.includeDeclarations || isLib) { return; } } diff --git a/src/lib/converter/converter.ts b/src/lib/converter/converter.ts index bfb595511..ccb5022d9 100644 --- a/src/lib/converter/converter.ts +++ b/src/lib/converter/converter.ts @@ -1,17 +1,15 @@ import * as ts from 'typescript'; import * as _ts from '../ts-internal'; +import * as path from 'path'; -import {Application} from '../application'; -import {ParameterType} from '../utils/options/declaration'; +import {EventDispatcher} from '../utils/events'; import {Reflection, Type, ProjectReflection} from '../models/index'; import {Context} from './context'; -import {ConverterComponent} from './components'; -import {CompilerHost} from './utils/compiler-host'; -import {Component, Option, ChildableComponent} from '../utils/component'; import {normalizePath} from '../utils/fs'; import * as nodes from './nodes'; import * as types from './types'; +import * as plugins from './plugins'; /** * Result structure of the [[Converter.convert]] method. @@ -32,71 +30,80 @@ export enum SourceFileMode { File, Modules } +export interface ConverterOptions { + compilerOptions: ts.CompilerOptions; + + name?: string; + externalPattern?: string; + includeDeclarations?: boolean; + excludeExternals?: boolean; + excludeNotExported?: boolean; + excludePrivate?: boolean; + mode?: SourceFileMode; + readme?: string; +} + +function createCompilerHost(converter: Converter): ts.CompilerHost { + return { + getSourceFile(filename: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile { + let text: string; + try { + text = ts.sys.readFile(filename, converter.options.compilerOptions.charset); + } catch (e) { + if (onError) { + onError(e.number === ERROR_UNSUPPORTED_FILE_ENCODING ? 'Unsupported file encoding' : e.message); + } + text = ''; + } + + return text !== undefined ? ts.createSourceFile(filename, text, languageVersion) : undefined; + }, + + getDefaultLibFileName(options: ts.CompilerOptions): string { + const lib = converter.getDefaultLib(); + const dir = _ts.getDirectoryPath(normalizePath(require.resolve('typescript'))); + return path.join(dir, lib); + }, + + getCurrentDirectory(this: ts.CompilerHost): string { + const currentDirectory = ts.sys.getCurrentDirectory(); + this.getCurrentDirectory = () => currentDirectory; + return currentDirectory; + }, + + useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames, + + getDirectories: ts.sys.getDirectories, + fileExists: ts.sys.fileExists, + directoryExists: ts.sys.directoryExists, + readFile: ts.sys.readFile, + getCanonicalFileName: ts.sys.useCaseSensitiveFileNames ? + (fileName: string) => fileName : + (fileName: string) => fileName.toLowerCase() + , + getNewLine: () => ts.sys.newLine, + + writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) { } + }; +} + +/** + * Return code of ts.sys.readFile when the file encoding is unsupported. + */ +const ERROR_UNSUPPORTED_FILE_ENCODING = -2147024809; + /** * Compiles source files using TypeScript and converts compiler symbols to reflections. */ -@Component({name: 'converter', internal: true, childClass: ConverterComponent}) -export class Converter extends ChildableComponent { - /** - * The human readable name of the project. Used within the templates to set the title of the document. - */ - @Option({ - name: 'name', - help: 'Set the name of the project that will be used in the header of the template.' - }) - name: string; - - @Option({ - name: 'externalPattern', - help: 'Define a pattern for files that should be considered being external.' - }) - externalPattern: string; - - @Option({ - name: 'includeDeclarations', - help: 'Turn on parsing of .d.ts declaration files.', - type: ParameterType.Boolean - }) - includeDeclarations: boolean; - - @Option({ - name: 'excludeExternals', - help: 'Prevent externally resolved TypeScript files from being documented.', - type: ParameterType.Boolean - }) - excludeExternals: boolean; - - @Option({ - name: 'excludeNotExported', - help: 'Prevent symbols that are not exported from being documented.', - type: ParameterType.Boolean - }) - excludeNotExported: boolean; - - @Option({ - name: 'excludePrivate', - help: 'Ignores private variables and methods', - type: ParameterType.Boolean - }) - excludePrivate: boolean; - - @Option({ - name: 'mode', - help: "Specifies the output mode the project is used to be compiled with: 'file' or 'modules'", - type: ParameterType.Map, - map: { - 'file': SourceFileMode.File, - 'modules': SourceFileMode.Modules - }, - defaultValue: SourceFileMode.Modules - }) - mode: SourceFileMode; +export class Converter extends EventDispatcher { + options: ConverterOptions; - private compilerHost: CompilerHost; + private compilerHost: ts.CompilerHost; private nodeConverters: Map; private typeNodeConverters: types.NodeTypeConverter[]; private typeTypeConverters: types.TypeTypeConverter[]; + private plugins: plugins.Plugin[]; /** * General events @@ -221,14 +228,24 @@ export class Converter extends ChildableComponent b.priority - a.priority); this.typeTypeConverters.sort((a, b) => b.priority - a.priority); + + this.plugins = []; + for (let ctor of Converter.pluginClasses) { + this.plugins.push(new ctor(this)); + } } private addNodeConverter(componentClass: nodes.NodeConverterConstructor) { @@ -273,7 +295,7 @@ export class Converter extends ChildableComponent { - if (this.converter.mode === SourceFileMode.Modules) { + if (this.converter.options.mode === SourceFileMode.Modules) { result = createDeclaration(context, node, ReflectionKind.ExternalModule, node.fileName); context.withScope(result, () => { this.convertStatements(context, node); diff --git a/src/lib/converter/nodes/class.ts b/src/lib/converter/nodes/class.ts index bc4bef245..9616ebf1f 100644 --- a/src/lib/converter/nodes/class.ts +++ b/src/lib/converter/nodes/class.ts @@ -35,7 +35,7 @@ export class ClassConverter extends NodeConverter { node.members.forEach((member) => { const modifiers = ts.getCombinedModifierFlags(member); const privateMember = (modifiers & ts.ModifierFlags.Private) > 0; - const exclude = context.converter.excludePrivate ? privateMember : false; + const exclude = context.converter.options.excludePrivate ? privateMember : false; if (!exclude) { this.converter.convertNode(context, member); diff --git a/src/lib/converter/nodes/constructor.ts b/src/lib/converter/nodes/constructor.ts index 919335931..dc9c14389 100644 --- a/src/lib/converter/nodes/constructor.ts +++ b/src/lib/converter/nodes/constructor.ts @@ -64,7 +64,7 @@ export class ConstructorConverter extends NodeConverter { } const privateParameter = modifiers & ts.ModifierFlags.Private; - if (privateParameter && context.converter.excludePrivate) { + if (privateParameter && context.converter.options.excludePrivate) { return; } diff --git a/src/lib/converter/plugins/CommentPlugin.ts b/src/lib/converter/plugins/CommentPlugin.ts index 21857ad4f..bba9a9406 100644 --- a/src/lib/converter/plugins/CommentPlugin.ts +++ b/src/lib/converter/plugins/CommentPlugin.ts @@ -5,7 +5,7 @@ import {IntrinsicType} from '../../models/types/index'; import {Reflection, ReflectionFlag, ReflectionKind, TraverseProperty, TypeParameterReflection, DeclarationReflection, ProjectReflection, SignatureReflection, ParameterReflection} from '../../models/reflections/index'; -import {Component, ConverterComponent} from '../components'; +import {Plugin} from './Plugin'; import {parseComment, getRawComment} from '../factories/comment'; import {Converter} from '../converter'; import {Context} from '../context'; @@ -34,8 +34,7 @@ interface ModuleComment { * A handler that parses javadoc comments and attaches [[Models.Comment]] instances to * the generated reflections. */ -@Component({name: 'comment'}) -export class CommentPlugin extends ConverterComponent { +export class CommentPlugin extends Plugin { /** * List of discovered module comments. */ @@ -50,7 +49,7 @@ export class CommentPlugin extends ConverterComponent { * Create a new CommentPlugin instance. */ initialize() { - this.listenTo(this.owner, { + this.listenTo(this.converter, { [Converter.EVENT_BEGIN]: this.onBegin, [Converter.EVENT_CREATE_DECLARATION]: this.onDeclaration, [Converter.EVENT_CREATE_SIGNATURE]: this.onDeclaration, diff --git a/src/lib/converter/plugins/DecoratorPlugin.ts b/src/lib/converter/plugins/DecoratorPlugin.ts index 47445d90c..c4383ffc4 100644 --- a/src/lib/converter/plugins/DecoratorPlugin.ts +++ b/src/lib/converter/plugins/DecoratorPlugin.ts @@ -3,22 +3,21 @@ import * as _ts from '../../ts-internal'; import {ReferenceType} from '../../models/types/index'; import {Reflection, Decorator} from '../../models/reflections/index'; -import {Component, ConverterComponent} from '../components'; +import {Plugin} from './Plugin'; import {Converter} from '../converter'; import {Context} from '../context'; /** * A plugin that detects decorators. */ -@Component({name: 'decorator'}) -export class DecoratorPlugin extends ConverterComponent { +export class DecoratorPlugin extends Plugin { private usages: {[symbolID: number]: ReferenceType[]}; /** * Create a new ImplementsPlugin instance. */ initialize() { - this.listenTo(this.owner, { + this.listenTo(this.converter, { [Converter.EVENT_BEGIN]: this.onBegin, [Converter.EVENT_CREATE_DECLARATION]: this.onDeclaration, [Converter.EVENT_CREATE_PARAMETER]: this.onDeclaration, diff --git a/src/lib/converter/plugins/DeepCommentPlugin.ts b/src/lib/converter/plugins/DeepCommentPlugin.ts index 0e19356d7..32ec0554e 100644 --- a/src/lib/converter/plugins/DeepCommentPlugin.ts +++ b/src/lib/converter/plugins/DeepCommentPlugin.ts @@ -1,19 +1,18 @@ import {Reflection, SignatureReflection, ProjectReflection, TypeParameterReflection} from '../../models/reflections/index'; import {Comment, CommentTag} from '../../models/comments/index'; -import {Component, ConverterComponent} from '../components'; +import {Plugin} from './Plugin'; import {Converter} from '../converter'; import {Context} from '../context'; /** * A handler that moves comments with dot syntax to their target. */ -@Component({name: 'deep-comment'}) -export class DeepCommentPlugin extends ConverterComponent { +export class DeepCommentPlugin extends Plugin { /** * Create a new CommentHandler instance. */ initialize() { - this.listenTo(this.owner, Converter.EVENT_RESOLVE_BEGIN, this.onBeginResolve, 512); + this.listenTo(this.converter, Converter.EVENT_RESOLVE_BEGIN, this.onBeginResolve, 512); } /** diff --git a/src/lib/converter/plugins/DynamicModulePlugin.ts b/src/lib/converter/plugins/DynamicModulePlugin.ts index cd851be65..3d85c52c1 100644 --- a/src/lib/converter/plugins/DynamicModulePlugin.ts +++ b/src/lib/converter/plugins/DynamicModulePlugin.ts @@ -2,7 +2,7 @@ import * as ts from 'typescript'; import * as Path from 'path'; import {Reflection, ReflectionKind} from '../../models/reflections/abstract'; -import {Component, ConverterComponent} from '../components'; +import {Plugin} from './Plugin'; import {BasePath} from '../utils/base-path'; import {Converter} from '../converter'; import {Context} from '../context'; @@ -11,8 +11,7 @@ import {Context} from '../context'; * A handler that truncates the names of dynamic modules to not include the * project's base path. */ -@Component({name: 'dynamic-module'}) -export class DynamicModulePlugin extends ConverterComponent { +export class DynamicModulePlugin extends Plugin { /** * Helper class for determining the base path. */ @@ -27,7 +26,7 @@ export class DynamicModulePlugin extends ConverterComponent { * Create a new DynamicModuleHandler instance. */ initialize() { - this.listenTo(this.owner, { + this.listenTo(this.converter, { [Converter.EVENT_BEGIN]: this.onBegin, [Converter.EVENT_CREATE_DECLARATION]: this.onDeclaration, [Converter.EVENT_RESOLVE_BEGIN]: this.onBeginResolve diff --git a/src/lib/converter/plugins/GitHubPlugin.ts b/src/lib/converter/plugins/GitHubPlugin.ts index fea3565a3..f6d781409 100644 --- a/src/lib/converter/plugins/GitHubPlugin.ts +++ b/src/lib/converter/plugins/GitHubPlugin.ts @@ -2,7 +2,7 @@ import * as ShellJS from 'shelljs'; import * as Path from 'path'; import {SourceReference} from '../../models/sources/file'; -import {Component, ConverterComponent} from '../components'; +import {Plugin} from './Plugin'; import {BasePath} from '../utils/base-path'; import {Converter} from '../converter'; import {Context} from '../context'; @@ -146,8 +146,7 @@ class Repository { * A handler that watches for repositories with GitHub origin and links * their source files to the related GitHub pages. */ -@Component({name: 'git-hub'}) -export class GitHubPlugin extends ConverterComponent { +export class GitHubPlugin extends Plugin { /** * List of known repositories. */ @@ -166,7 +165,7 @@ export class GitHubPlugin extends ConverterComponent { initialize() { ShellJS.config.silent = true; if (ShellJS.which('git')) { - this.listenTo(this.owner, Converter.EVENT_RESOLVE_END, this.onEndResolve); + this.listenTo(this.converter, Converter.EVENT_RESOLVE_END, this.onEndResolve); } } diff --git a/src/lib/converter/plugins/GroupPlugin.ts b/src/lib/converter/plugins/GroupPlugin.ts index 845b04ed6..0a12c1c62 100644 --- a/src/lib/converter/plugins/GroupPlugin.ts +++ b/src/lib/converter/plugins/GroupPlugin.ts @@ -1,7 +1,7 @@ import {Reflection, ReflectionKind, ContainerReflection, DeclarationReflection} from '../../models/reflections/index'; import {ReflectionGroup} from '../../models/ReflectionGroup'; import {SourceDirectory} from '../../models/sources/directory'; -import {Component, ConverterComponent} from '../components'; +import {Plugin} from './Plugin'; import {Converter} from '../converter'; import {Context} from '../context'; @@ -10,8 +10,7 @@ import {Context} from '../context'; * * The handler sets the ´groups´ property of all reflections. */ -@Component({name: 'group'}) -export class GroupPlugin extends ConverterComponent { +export class GroupPlugin extends Plugin { /** * Define the sort order of reflections. */ @@ -71,7 +70,7 @@ export class GroupPlugin extends ConverterComponent { * Create a new GroupPlugin instance. */ initialize() { - this.listenTo(this.owner, { + this.listenTo(this.converter, { [Converter.EVENT_RESOLVE]: this.onResolve, [Converter.EVENT_RESOLVE_END]: this.onEndResolve }); diff --git a/src/lib/converter/plugins/ImplementsPlugin.ts b/src/lib/converter/plugins/ImplementsPlugin.ts index 39f2a134c..96e72e7d6 100644 --- a/src/lib/converter/plugins/ImplementsPlugin.ts +++ b/src/lib/converter/plugins/ImplementsPlugin.ts @@ -1,6 +1,6 @@ import {Reflection, ReflectionKind, DeclarationReflection, SignatureReflection} from '../../models/reflections/index'; import {Type, ReferenceType} from '../../models/types/index'; -import {Component, ConverterComponent} from '../components'; +import {Plugin} from './Plugin'; import {Converter} from '../converter'; import {Context} from '../context'; @@ -8,13 +8,12 @@ import {Context} from '../context'; * A plugin that detects interface implementations of functions and * properties on classes and links them. */ -@Component({name: 'implements'}) -export class ImplementsPlugin extends ConverterComponent { +export class ImplementsPlugin extends Plugin { /** * Create a new ImplementsPlugin instance. */ initialize() { - this.listenTo(this.owner, Converter.EVENT_RESOLVE, this.onResolve, -10); + this.listenTo(this.converter, Converter.EVENT_RESOLVE, this.onResolve, -10); } /** diff --git a/src/lib/converter/plugins/PackagePlugin.ts b/src/lib/converter/plugins/PackagePlugin.ts index dfc2890b5..edb018153 100644 --- a/src/lib/converter/plugins/PackagePlugin.ts +++ b/src/lib/converter/plugins/PackagePlugin.ts @@ -3,10 +3,9 @@ import * as FS from 'fs'; import * as ts from 'typescript'; import {Reflection} from '../../models/reflections/abstract'; -import {Component, ConverterComponent} from '../components'; +import {Plugin} from './Plugin'; import {Converter} from '../converter'; import {Context} from '../context'; -import {Option} from '../../utils/component'; /** * A handler that tries to find the package.json and readme.md files of the @@ -16,14 +15,7 @@ import {Option} from '../../utils/component'; * and records the nearest package info files it can find. Within the resolve files, the * contents of the found files will be read and appended to the ProjectReflection. */ -@Component({name: 'package'}) -export class PackagePlugin extends ConverterComponent { - @Option({ - name: 'readme', - help: 'Path to the readme file that should be displayed on the index page. Pass `none` to disable the index page and start the documentation on the globals page.' - }) - readme: string; - +export class PackagePlugin extends Plugin { /** * The file name of the found readme.md file. */ @@ -48,7 +40,7 @@ export class PackagePlugin extends ConverterComponent { * Create a new PackageHandler instance. */ initialize() { - this.listenTo(this.owner, { + this.listenTo(this.converter, { [Converter.EVENT_BEGIN]: this.onBegin, [Converter.EVENT_FILE_BEGIN]: this.onBeginDocument, [Converter.EVENT_RESOLVE_BEGIN]: this.onBeginResolve @@ -65,7 +57,7 @@ export class PackagePlugin extends ConverterComponent { this.packageFile = null; this.visited = []; - let readme = this.readme; + let readme = this.converter.options.readme; this.noReadmeFile = (readme === 'none'); if (!this.noReadmeFile && readme) { readme = Path.resolve(readme); diff --git a/src/lib/converter/plugins/Plugin.ts b/src/lib/converter/plugins/Plugin.ts new file mode 100644 index 000000000..4bbea395e --- /dev/null +++ b/src/lib/converter/plugins/Plugin.ts @@ -0,0 +1,17 @@ +import {Converter} from '../converter'; +import {EventDispatcher} from '../../utils/events'; + +export type PluginConstructor = new (converter: Converter) => Plugin; + +export abstract class Plugin extends EventDispatcher { + protected converter: Converter; + + constructor(converter: Converter) { + super(); + this.converter = converter; + + this.initialize(); + } + + abstract initialize(): void; +} diff --git a/src/lib/converter/plugins/SourcePlugin.ts b/src/lib/converter/plugins/SourcePlugin.ts index 2766c3f80..6411a9f6b 100644 --- a/src/lib/converter/plugins/SourcePlugin.ts +++ b/src/lib/converter/plugins/SourcePlugin.ts @@ -4,7 +4,7 @@ import * as _ts from '../../ts-internal'; import {Reflection, ProjectReflection, DeclarationReflection} from '../../models/reflections/index'; import {SourceDirectory, SourceFile} from '../../models/sources/index'; -import {Component, ConverterComponent} from '../components'; +import {Plugin} from './Plugin'; import {BasePath} from '../utils/base-path'; import {Converter} from '../converter'; import {Context} from '../context'; @@ -12,8 +12,7 @@ import {Context} from '../context'; /** * A handler that attaches source file information to reflections. */ -@Component({name: 'source'}) -export class SourcePlugin extends ConverterComponent { +export class SourcePlugin extends Plugin { /** * Helper for resolving the base path of all source files. */ @@ -28,7 +27,7 @@ export class SourcePlugin extends ConverterComponent { * Create a new SourceHandler instance. */ initialize() { - this.listenTo(this.owner, { + this.listenTo(this.converter, { [Converter.EVENT_BEGIN]: this.onBegin, [Converter.EVENT_FILE_BEGIN]: this.onBeginDocument, [Converter.EVENT_CREATE_DECLARATION]: this.onDeclaration, diff --git a/src/lib/converter/plugins/TypePlugin.ts b/src/lib/converter/plugins/TypePlugin.ts index a0026b881..82f835724 100644 --- a/src/lib/converter/plugins/TypePlugin.ts +++ b/src/lib/converter/plugins/TypePlugin.ts @@ -1,21 +1,20 @@ import {Reflection, ReflectionKind, Decorator, DeclarationReflection, DeclarationHierarchy} from '../../models/reflections/index'; import {Type, ReferenceType, TupleType, UnionType} from '../../models/types/index'; -import {Component, ConverterComponent} from '../components'; +import {Plugin} from './Plugin'; import {Converter} from '../converter'; import {Context} from '../context'; /** * A handler that converts all instances of [[LateResolvingType]] to their renderable equivalents. */ -@Component({name: 'type'}) -export class TypePlugin extends ConverterComponent { +export class TypePlugin extends Plugin { reflections: DeclarationReflection[] = []; /** * Create a new TypeHandler instance. */ initialize() { - this.listenTo(this.owner, { + this.listenTo(this.converter, { [Converter.EVENT_RESOLVE]: this.onResolve, [Converter.EVENT_RESOLVE_END]: this.onResolveEnd }); diff --git a/src/lib/converter/plugins/index.ts b/src/lib/converter/plugins/index.ts index 579376394..329fc0bd9 100644 --- a/src/lib/converter/plugins/index.ts +++ b/src/lib/converter/plugins/index.ts @@ -1,3 +1,5 @@ +export * from './Plugin'; + export {CommentPlugin} from './CommentPlugin'; export {DecoratorPlugin} from './DecoratorPlugin'; export {DeepCommentPlugin} from './DeepCommentPlugin'; diff --git a/src/lib/converter/utils/compiler-host.ts b/src/lib/converter/utils/compiler-host.ts deleted file mode 100644 index 7b3b9c669..000000000 --- a/src/lib/converter/utils/compiler-host.ts +++ /dev/null @@ -1,158 +0,0 @@ -import * as ts from 'typescript'; -import * as _ts from '../../ts-internal'; -import * as Path from 'path'; - -import {ConverterComponent} from '../components'; -import {normalizePath} from '../../utils/fs'; - -/** - * Return code of ts.sys.readFile when the file encoding is unsupported. - */ -const ERROR_UNSUPPORTED_FILE_ENCODING = -2147024809; - -/** - * CompilerHost implementation - */ -export class CompilerHost extends ConverterComponent implements ts.CompilerHost { - - /** - * The full path of the current directory. Result cache of [[getCurrentDirectory]]. - */ - private currentDirectory: string; - - /** - * Return an instance of ts.SourceFile representing the given file. - * - * Implementation of ts.CompilerHost.getSourceFile() - * - * @param filename The path and name of the file that should be loaded. - * @param languageVersion The script target the file should be interpreted with. - * @param onError A callback that will be invoked if an error occurs. - * @returns An instance of ts.SourceFile representing the given file. - */ - getSourceFile(filename: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile { - let text: string; - try { - text = ts.sys.readFile(filename, this.application.options.getCompilerOptions().charset); - } catch (e) { - if (onError) { - onError(e.number === ERROR_UNSUPPORTED_FILE_ENCODING ? 'Unsupported file encoding' : e.message); - } - text = ''; - } - - return text !== undefined ? ts.createSourceFile(filename, text, languageVersion) : undefined; - } - - /** - * Return the full path of the default library that should be used. - * - * Implementation of ts.CompilerHost.getDefaultLibFilename() - * - * @returns The full path of the default library. - */ - getDefaultLibFileName(options: ts.CompilerOptions): string { - const lib = this.owner.getDefaultLib(); - const path = _ts.getDirectoryPath(normalizePath(require.resolve('typescript'))); - return Path.join(path, lib); - } - - getDirectories(path: string): string[] { - return ts.sys.getDirectories(path); - } - - /** - * Return the full path of the current directory. - * - * Implementation of ts.CompilerHost.getCurrentDirectory() - * - * @returns The full path of the current directory. - */ - getCurrentDirectory(): string { - return this.currentDirectory || (this.currentDirectory = ts.sys.getCurrentDirectory()); - } - - /** - * Return whether file names are case sensitive on the current platform or not. - * - * Implementation of ts.CompilerHost.useCaseSensitiveFileNames() - * - * @returns TRUE if file names are case sensitive on the current platform, FALSE otherwise. - */ - useCaseSensitiveFileNames(): boolean { - return ts.sys.useCaseSensitiveFileNames; - } - - /** - * Check whether the given file exists. - * - * Implementation of ts.CompilerHost.fileExists(fileName) - * - * @param fileName - * @returns {boolean} - */ - fileExists(fileName: string): boolean { - return ts.sys.fileExists(fileName); - } - - /** - * Check whether the given directory exists. - * - * Implementation of ts.CompilerHost.directoryExists(directoryName) - * - * @param directoryName - * @returns {boolean} - */ - directoryExists(directoryName: string): boolean { - return ts.sys.directoryExists(directoryName); - } - - /** - * Return the contents of the given file. - * - * Implementation of ts.CompilerHost.readFile(fileName) - * - * @param fileName - * @returns {string} - */ - readFile(fileName: string): string { - return ts.sys.readFile(fileName); - } - - /** - * Return the canonical file name of the given file. - * - * Implementation of ts.CompilerHost.getCanonicalFileName() - * - * @param fileName The file name whose canonical variant should be resolved. - * @returns The canonical file name of the given file. - */ - getCanonicalFileName(fileName: string): string { - return ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(); - } - - /** - * Return the new line char sequence of the current platform. - * - * Implementation of ts.CompilerHost.getNewLine() - * - * @returns The new line char sequence of the current platform. - */ - getNewLine(): string { - return ts.sys.newLine; - } - - /** - * Write a compiled javascript file to disc. - * - * As TypeDoc will not emit compiled javascript files this is a null operation. - * - * Implementation of ts.CompilerHost.writeFile() - * - * @param fileName The name of the file that should be written. - * @param data The contents of the file. - * @param writeByteOrderMark Whether the UTF-8 BOM should be written or not. - * @param onError A callback that will be invoked if an error occurs. - */ - writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) { } -}