From 9a590dbbe5d6f03e6b06c91d144d91a952645f37 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Thu, 2 Apr 2015 15:22:53 -0700 Subject: [PATCH] PR feedback --- src/compiler/checker.ts | 61 +++++++------ src/compiler/emitter.ts | 185 +++++++++++++++++++++------------------- 2 files changed, 132 insertions(+), 114 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8c41d97c7bf..0ff961ea5b8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8747,6 +8747,9 @@ module ts { /** Checks a type reference node as an expression. */ function checkTypeNodeAsExpression(node: TypeNode | LiteralExpression) { + // When we are emitting type metadata for decorators, we need to try to check the type + // as if it were an expression so that we can emit the type in a value position when we + // serialize the type metadata. if (node && node.kind === SyntaxKind.TypeReference) { let type = getTypeFromTypeNodeOrHeritageClauseElement(node); let shouldCheckIfUnknownType = type === unknownType && compilerOptions.separateCompilation; @@ -8785,29 +8788,35 @@ module ts { function checkDecorators(node: Node): void { if (!node.decorators) { return; - } + } - switch (node.kind) { - case SyntaxKind.ClassDeclaration: - var constructor = getFirstConstructorWithBody(node); - if (constructor) { - checkParameterTypeAnnotationsAsExpressions(constructor); - } - break; + // skip this check for nodes that cannot have decorators. These should have already had an error reported by + // checkGrammarDecorators. + if (!nodeCanBeDecorated(node)) { + return; + } - case SyntaxKind.MethodDeclaration: - checkParameterTypeAnnotationsAsExpressions(node); - // fall-through + if (compilerOptions.emitDecoratorMetadata) { + // we only need to perform these checks if we are emitting serialized type metadata for the target of a decorator. + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + var constructor = getFirstConstructorWithBody(node); + if (constructor) { + checkParameterTypeAnnotationsAsExpressions(constructor); + } + break; - case SyntaxKind.SetAccessor: - case SyntaxKind.GetAccessor: - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.Parameter: - checkTypeAnnotationAsExpression(node); - break; + case SyntaxKind.MethodDeclaration: + checkParameterTypeAnnotationsAsExpressions(node); + // fall-through - default: - return; + case SyntaxKind.SetAccessor: + case SyntaxKind.GetAccessor: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.Parameter: + checkTypeAnnotationAsExpression(node); + break; + } } emitDecorate = true; @@ -11510,7 +11519,7 @@ module ts { return undefined; } - /** Serializes an EntityName (with substitutions) to an appropriate JS constructor value. Used by the `@type`, `@paramtypes`, and `@returntype` decorators. */ + /** Serializes an EntityName (with substitutions) to an appropriate JS constructor value. Used by the __metadata decorator. */ function serializeEntityName(node: EntityName, getGeneratedNameForNode: (Node: Node) => string, fallbackPath?: string[]): string { if (node.kind === SyntaxKind.Identifier) { var substitution = getExpressionNameSubstitution(node, getGeneratedNameForNode); @@ -11531,7 +11540,7 @@ module ts { } } - /** Serializes a TypeReferenceNode to an appropriate JS constructor value. Used by the `@type`, `@paramtypes`, and `@returntype` decorators. */ + /** Serializes a TypeReferenceNode to an appropriate JS constructor value. Used by the __metadata decorator. */ function serializeTypeReferenceNode(node: TypeReferenceNode, getGeneratedNameForNode: (Node: Node) => string): string | string[] { // serialization of a TypeReferenceNode uses the following rules: // @@ -11578,7 +11587,7 @@ module ts { return "Object"; } - /** Serializes a TypeNode to an appropriate JS constructor value. Used by the `@type`, `@paramtypes`, and `@returntype` decorators. */ + /** Serializes a TypeNode to an appropriate JS constructor value. Used by the __metadata decorator. */ function serializeTypeNode(node: TypeNode | LiteralExpression, getGeneratedNameForNode: (Node: Node) => string): string | string[] { // serialization of a TypeNode uses the following rules: // @@ -11623,11 +11632,11 @@ module ts { return "Object"; } - /** Serializes the type of a declaration to an appropriate JS constructor value. Used by the `@type` and `@paramtypes` decorators. */ + /** Serializes the type of a declaration to an appropriate JS constructor value. Used by the __metadata decorator for a class member. */ function serializeTypeOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): string | string[] { // serialization of the type of a declaration uses the following rules: // - // * The serialized type of a ClassDeclaration is the class name (see serializeEntityName). + // * The serialized type of a ClassDeclaration is "Function" // * The serialized type of a ParameterDeclaration is the serialized type of its type annotation. // * The serialized type of a PropertyDeclaration is the serialized type of its type annotation. // * The serialized type of an AccessorDeclaration is the serialized type of the return type annotation of its getter or parameter type annotation of its setter. @@ -11648,7 +11657,7 @@ module ts { return "void 0"; } - /** Serializes the parameter types of a function or the constructor of a class. Used by the `@paramtypes` decorator. */ + /** Serializes the parameter types of a function or the constructor of a class. Used by the __metadata decorator for a method or set accessor. */ function serializeParameterTypesOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): (string | string[])[] { // serialization of parameter types uses the following rules: // @@ -11695,7 +11704,7 @@ module ts { return emptyArray; } - /** Serializes the return type of function. Used by the `@returntype` decorator. */ + /** Serializes the return type of function. Used by the __metadata decorator for a method. */ function serializeReturnTypeOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): string | string[] { if (node && isFunctionLike(node)) { return serializeTypeNode((node).type, getGeneratedNameForNode); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index c50d7459493..cae95ed0f9a 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -796,27 +796,34 @@ var __param = this.__param || function(index, decorator) { return function (targ } } - function emitList(nodes: Node[], start: number, count: number, multiLine: boolean, trailingComma: boolean) { + function emitList(nodes: TNode[], start: number, count: number, multiLine: boolean, trailingComma: boolean, leadingComma?: boolean, noTrailingNewLine?: boolean, emitNode?: (node: TNode) => void): number { + if (!emitNode) { + emitNode = emit; + } + for (let i = 0; i < count; i++) { if (multiLine) { - if (i) { + if (i || leadingComma) { write(","); } writeLine(); } else { - if (i) { + if (i || leadingComma) { write(", "); } } - emit(nodes[start + i]); + emitNode(nodes[start + i]); + leadingComma = true; } if (trailingComma) { write(","); } - if (multiLine) { + if (multiLine && !noTrailingNewLine) { writeLine(); } + + return count; } function emitCommaList(nodes: Node[]) { @@ -3752,10 +3759,15 @@ var __param = this.__param || function(index, decorator) { return function (targ increaseIndent(); writeLine(); - let writeComma = false; - writeComma = emitDecoratorArray(decorators, writeComma); - writeComma = emitDecoratorsOfParameters(constructor, writeComma); - emitSerializedTypeMetadata(node, writeComma); + let decoratorCount = decorators ? decorators.length : 0; + let argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true, decorator => { + emitStart(decorator); + emit(decorator.expression); + emitEnd(decorator); + }); + + argumentsWritten += emitDecoratorsOfParameters(constructor, /*leadingComma*/ argumentsWritten > 0); + emitSerializedTypeMetadata(node, /*leadingComma*/ argumentsWritten >= 0); decreaseIndent(); writeLine(); @@ -3861,10 +3873,15 @@ var __param = this.__param || function(index, decorator) { return function (targ increaseIndent(); writeLine(); - let writeComma = false; - writeComma = emitDecoratorArray(decorators, writeComma); - writeComma = emitDecoratorsOfParameters(functionLikeMember, writeComma); - emitSerializedTypeMetadata(member, writeComma); + let decoratorCount = decorators ? decorators.length : 0; + let argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true, decorator => { + emitStart(decorator); + emit(decorator.expression); + emitEnd(decorator); + }); + + argumentsWritten += emitDecoratorsOfParameters(functionLikeMember, argumentsWritten > 0); + emitSerializedTypeMetadata(member, argumentsWritten > 0); decreaseIndent(); writeLine(); @@ -3892,45 +3909,32 @@ var __param = this.__param || function(index, decorator) { return function (targ } } - function emitDecoratorsOfParameters(node: FunctionLikeDeclaration, writeComma: boolean): boolean { + function emitDecoratorsOfParameters(node: FunctionLikeDeclaration, leadingComma: boolean): number { + let argumentsWritten = 0; if (node) { let parameterIndex = 0; for (let parameter of node.parameters) { if (nodeIsDecorated(parameter)) { - writeComma = emitDecoratorArray(parameter.decorators, writeComma, `__param(${parameterIndex}, `, ")"); + let decorators = parameter.decorators; + argumentsWritten += emitList(decorators, 0, decorators.length, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ leadingComma, /*noTrailingNewLine*/ true, decorator => { + emitStart(decorator); + write(`__param(${parameterIndex}, `); + emit(decorator.expression); + write(")"); + emitEnd(decorator); + }); + leadingComma = true; } ++parameterIndex; } } - return writeComma; - } - - function emitDecoratorArray(decorators: NodeArray, writeComma: boolean, prefix?: string, postfix?: string): boolean { - if (decorators) { - let decoratorCount = decorators ? decorators.length : 0; - for (let i = 0; i < decoratorCount; i++) { - if (writeComma) { - write(","); - } - writeLine(); - - let decorator = decorators[i]; - emitStart(decorator); - write(prefix); - emit(decorator.expression); - write(postfix); - emitEnd(decorator); - writeComma = true; - } - } - return writeComma; + return argumentsWritten; } function shouldEmitTypeMetadata(node: Declaration): boolean { - if (!compilerOptions.emitDecoratorMetadata) { - return false; - } - + // This method determines whether to emit the "design:type" metadata based on the node's kind. + // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata + // compiler option is set. switch (node.kind) { case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: @@ -3943,10 +3947,9 @@ var __param = this.__param || function(index, decorator) { return function (targ } function shouldEmitReturnTypeMetadata(node: Declaration): boolean { - if (!compilerOptions.emitDecoratorMetadata) { - return false; - } - + // This method determines whether to emit the "design:returntype" metadata based on the node's kind. + // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata + // compiler option is set. switch (node.kind) { case SyntaxKind.MethodDeclaration: return true; @@ -3955,10 +3958,9 @@ var __param = this.__param || function(index, decorator) { return function (targ } function shouldEmitParamTypesMetadata(node: Declaration): boolean { - if (!compilerOptions.emitDecoratorMetadata) { - return false; - } - + // This method determines whether to emit the "design:paramtypes" metadata based on the node's kind. + // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata + // compiler option is set. switch (node.kind) { case SyntaxKind.ClassDeclaration: case SyntaxKind.MethodDeclaration: @@ -3968,50 +3970,57 @@ var __param = this.__param || function(index, decorator) { return function (targ return false; } - function emitSerializedTypeMetadata(node: Declaration, writeComma: boolean): void { - if (shouldEmitTypeMetadata(node)) { - var serializedType = resolver.serializeTypeOfNode(node, getGeneratedNameForNode); - if (serializedType) { - if (writeComma) { - write(", "); - } - writeLine(); - write("__metadata('design:type', "); - emitSerializedType(node, serializedType); - write(")"); - writeComma = true; - } - } - if (shouldEmitParamTypesMetadata(node)) { - var serializedTypes = resolver.serializeParameterTypesOfNode(node, getGeneratedNameForNode); - if (serializedTypes) { - if (writeComma) { - write(", "); - } - writeLine(); - write("__metadata('design:paramtypes', ["); - for (var i = 0; i < serializedTypes.length; ++i) { - if (i > 0) { + function emitSerializedTypeMetadata(node: Declaration, writeComma: boolean): number { + // This method emits the serialized type metadata for a decorator target. + // The caller should have already tested whether the node has decorators. + let argumentsWritten = 0; + if (compilerOptions.emitDecoratorMetadata) { + if (shouldEmitTypeMetadata(node)) { + var serializedType = resolver.serializeTypeOfNode(node, getGeneratedNameForNode); + if (serializedType) { + if (writeComma) { write(", "); } - emitSerializedType(node, serializedTypes[i]); + writeLine(); + write("__metadata('design:type', "); + emitSerializedType(node, serializedType); + write(")"); + argumentsWritten++; + } + } + if (shouldEmitParamTypesMetadata(node)) { + var serializedTypes = resolver.serializeParameterTypesOfNode(node, getGeneratedNameForNode); + if (serializedTypes) { + if (writeComma || argumentsWritten) { + write(", "); + } + writeLine(); + write("__metadata('design:paramtypes', ["); + for (var i = 0; i < serializedTypes.length; ++i) { + if (i > 0) { + write(", "); + } + emitSerializedType(node, serializedTypes[i]); + } + write("])"); + argumentsWritten++; + } + } + if (shouldEmitReturnTypeMetadata(node)) { + var serializedType = resolver.serializeReturnTypeOfNode(node, getGeneratedNameForNode); + if (serializedType) { + if (writeComma || argumentsWritten) { + write(", "); + } + writeLine(); + write("__metadata('design:returntype', "); + emitSerializedType(node, serializedType); + write(")"); + argumentsWritten++; } - write("])"); - writeComma = true; - } - } - if (shouldEmitReturnTypeMetadata(node)) { - var serializedType = resolver.serializeReturnTypeOfNode(node, getGeneratedNameForNode); - if (serializedType) { - if (writeComma) { - write(", "); - } - writeLine(); - write("__metadata('design:returntype', "); - emitSerializedType(node, serializedType); - write(")"); } } + return argumentsWritten; } function serializeTypeNameSegment(location: Node, path: string[], index: number): string {