Adds the TypeScript transformer

This commit is contained in:
Ron Buckton
2016-02-12 10:49:09 -08:00
parent 49d2d93379
commit f948b14185
12 changed files with 3729 additions and 217 deletions

View File

@@ -42,6 +42,14 @@ var compilerSources = [
"checker.ts",
"factory.ts",
"visitor.ts",
"transformers/destructuring.ts",
"transformers/ts.ts",
"transformers/module/es6.ts",
"transformers/module/system.ts",
"transformers/module/module.ts",
"transformers/jsx.ts",
"transformers/es7.ts",
"transformers/es6.ts",
"transformer.ts",
"sourcemap.ts",
"comments.ts",
@@ -67,6 +75,14 @@ var servicesSources = [
"checker.ts",
"factory.ts",
"visitor.ts",
"transformers/destructuring.ts",
"transformers/ts.ts",
"transformers/module/es6.ts",
"transformers/module/system.ts",
"transformers/module/module.ts",
"transformers/jsx.ts",
"transformers/es7.ts",
"transformers/es6.ts",
"transformer.ts",
"sourcemap.ts",
"comments.ts",

View File

@@ -1838,6 +1838,12 @@ namespace ts {
transformFlags |= TransformFlags.AssertJsx;
break;
case SyntaxKind.ExportKeyword:
// This node is both ES6 and TypeScript syntax.
transformFlags |= TransformFlags.AssertES6 | TransformFlags.TypeScript;
break;
case SyntaxKind.DefaultKeyword:
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.TemplateHead:
case SyntaxKind.TemplateMiddle:

View File

@@ -142,25 +142,44 @@ namespace ts {
return count;
}
export function filter<T>(array: T[], f: (x: T) => boolean): T[] {
export function filter<T, U extends T>(array: T[], f: (x: T, i: number) => x is U): U[];
export function filter<T>(array: T[], f: (x: T, i: number) => boolean): T[];
export function filter<T>(array: T[], f: (x: T, i: number) => boolean): T[] {
let result: T[];
if (array) {
result = [];
for (const item of array) {
if (f(item)) {
result.push(item);
for (let i = 0; i < array.length; i++) {
const v = array[i];
if (f(v, i)) {
result.push(v);
}
}
}
return result;
}
export function map<T, U>(array: T[], f: (x: T) => U): U[] {
export function map<T, U>(array: T[], f: (x: T, i: number) => U): U[] {
let result: U[];
if (array) {
result = [];
for (const v of array) {
result.push(f(v));
for (let i = 0; i < array.length; i++) {
const v = array[i];
result.push(f(v, i));
}
}
return result;
}
export function flatMap<T, U>(array: T[], f: (x: T, i: number) => U[]): U[] {
let result: U[];
if (array) {
result = [];
for (let i = 0; i < array.length; i++) {
const v = array[i];
const ar = f(v, i);
if (ar) {
result = result.concat(ar);
}
}
}
return result;
@@ -212,15 +231,25 @@ namespace ts {
return true;
}
export function firstOrUndefined<T>(array: T[]): T {
return array && array.length > 0
? array[0]
: undefined;
}
export function singleOrUndefined<T>(array: T[]): T {
return array && array.length === 1
? array[0]
: undefined;
}
/**
* Returns the last element of an array if non-empty, undefined otherwise.
*/
export function lastOrUndefined<T>(array: T[]): T {
if (array.length === 0) {
return undefined;
}
return array[array.length - 1];
return array && array.length > 0
? array[array.length - 1]
: undefined;
}
/**

View File

@@ -287,8 +287,12 @@ namespace ts {
_i = 0x10000000, // Use/preference flag for '_i'
}
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile): EmitResult {
return printFiles(resolver, host, targetSourceFile);
}
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
export function legacyEmitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile): EmitResult {
// emit output for the __extends helper function
const extendsHelper = `
var __extends = (this && this.__extends) || function (d, b) {

View File

@@ -6,33 +6,88 @@ namespace ts {
let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
function createNode(kind: SyntaxKind, location?: TextRange): Node {
function createNode(kind: SyntaxKind, location?: TextRange, flags?: NodeFlags): Node {
const ConstructorForKind = kind === SyntaxKind.SourceFile
? (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))
: (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()));
return location
const node = location
? new ConstructorForKind(kind, location.pos, location.end)
: new ConstructorForKind(kind, /*pos*/ -1, /*end*/ -1);
if (flags) {
node.flags = flags;
}
return node;
}
export function createNodeArray<T extends Node>(elements?: T[], pos?: number, end?: number): NodeArray<T> {
const array = <NodeArray<T>>(elements || []);
array.pos = pos;
array.end = end;
export function createNodeArray<T extends Node>(elements?: T[], location?: TextRange): NodeArray<T> {
if (elements) {
if (isNodeArray(elements)) {
return elements;
}
}
else {
elements = [];
}
const array = <NodeArray<T>>elements;
if (location) {
array.pos = location.pos;
array.end = location.end;
}
else {
array.pos = -1;
array.end = -1;
}
array.arrayKind = ArrayKind.NodeArray;
return array;
}
export function createModifiersArray(elements?: Modifier[], pos?: number, end?: number): ModifiersArray {
const array = <ModifiersArray>(elements || []);
array.pos = pos;
array.end = end;
export function createModifiersArray(elements?: Modifier[], location?: TextRange): ModifiersArray {
let flags: NodeFlags;
if (elements) {
if (isModifiersArray(elements)) {
return elements;
}
flags = 0;
for (const modifier of elements) {
flags |= modifierToFlag(modifier.kind);
}
}
else {
elements = [];
flags = 0;
}
const array = <ModifiersArray>elements;
if (location) {
array.pos = location.pos;
array.end = location.end;
}
else {
array.pos = -1;
array.end = -1;
}
array.arrayKind = ArrayKind.ModifiersArray;
array.flags = 0;
array.flags = flags;
return array;
}
function setModifiers(node: Node, modifiers: Modifier[]) {
if (modifiers) {
node.modifiers = createSynthesizedModifiersArray(modifiers);
node.flags |= node.modifiers.flags;
}
else {
node.modifiers = undefined;
}
}
export function createSynthesizedNode(kind: SyntaxKind, startsOnNewLine?: boolean): Node {
const node = <SynthesizedNode>createNode(kind, /*location*/ undefined);
node.startsOnNewLine = startsOnNewLine;
@@ -40,11 +95,11 @@ namespace ts {
}
export function createSynthesizedNodeArray<T extends Node>(elements?: T[]): NodeArray<T> {
return createNodeArray(elements, /*pos*/ -1, /*end*/ -1);
return createNodeArray(elements, /*location*/ undefined);
}
export function createSynthesizedModifiersArray(elements?: Modifier[]): ModifiersArray {
return createModifiersArray(elements, /*pos*/ -1, /*end*/ -1);
return createModifiersArray(elements, /*location*/ undefined);
}
/**
@@ -93,41 +148,28 @@ namespace ts {
return node;
}
export function createReturn(expression?: Expression): ReturnStatement {
const node = <ReturnStatement>createSynthesizedNode(SyntaxKind.ReturnStatement);
node.expression = expression;
return node;
// Literals
export function createLiteral(value: string): StringLiteral;
export function createLiteral(value: number): LiteralExpression;
export function createLiteral(value: string | number | boolean): PrimaryExpression;
export function createLiteral<T extends PrimaryExpression>(value: string | number | boolean): T {
if (typeof value === "number") {
const node = <T & LiteralExpression>createNode(SyntaxKind.NumericLiteral);
node.text = value.toString();
return node;
}
else if (typeof value === "boolean") {
return <T>createNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword);
}
else {
const node = <T & StringLiteral>createNode(SyntaxKind.StringLiteral);
node.text = String(value);
return node;
}
}
export function createStatement(expression: Expression): ExpressionStatement {
const node = <ExpressionStatement>createSynthesizedNode(SyntaxKind.ExpressionStatement);
node.expression = expression;
return node;
}
export function createVariableStatement(declarationList: VariableDeclarationList): VariableStatement {
const node = <VariableStatement>createSynthesizedNode(SyntaxKind.VariableStatement);
node.declarationList = declarationList;
return node;
}
export function createVariableDeclarationList(declarations: VariableDeclaration[]): VariableDeclarationList {
const node = <VariableDeclarationList>createSynthesizedNode(SyntaxKind.VariableDeclarationList);
node.declarations = createNodeArray(declarations);
return node;
}
export function createBlock(statements: Statement[]): Block {
const block = <Block>createSynthesizedNode(SyntaxKind.Block);
block.statements = createNodeArray(statements);
return block;
}
export function createVariableDeclaration(name: BindingPattern | Identifier, initializer?: Expression, location?: TextRange): VariableDeclaration {
const node = <VariableDeclaration>createNode(SyntaxKind.VariableDeclaration, location);
node.name = name;
node.initializer = initializer;
return node;
}
// Identifiers
export function createIdentifier(text: string): Identifier {
const node = <Identifier>createNode(SyntaxKind.Identifier);
@@ -151,33 +193,102 @@ namespace ts {
return name;
}
export function createLiteral(value: string): StringLiteral;
export function createLiteral(value: number): LiteralExpression;
export function createLiteral(value: string | number | boolean): PrimaryExpression;
export function createLiteral<T extends PrimaryExpression>(value: string | number | boolean): T {
if (typeof value === "number") {
const node = <T & LiteralExpression>createNode(SyntaxKind.NumericLiteral);
node.text = value.toString();
return node;
}
else if (typeof value === "boolean") {
return <T>createNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword);
}
else {
const node = <T & StringLiteral>createNode(SyntaxKind.StringLiteral);
node.text = String(value);
return node;
}
// Reserved words
export function createSuper() {
const node = <PrimaryExpression>createNode(SyntaxKind.SuperKeyword);
return node;
}
export function createVoid(expression: UnaryExpression) {
const node = <VoidExpression>createNode(SyntaxKind.VoidExpression);
export function createThis() {
const node = <PrimaryExpression>createNode(SyntaxKind.ThisKeyword);
return node;
}
export function createNull() {
const node = <PrimaryExpression>createNode(SyntaxKind.NullKeyword);
return node;
}
// Names
export function createComputedPropertyName(expression: Expression, location?: TextRange) {
const node = <ComputedPropertyName>createNode(SyntaxKind.ComputedPropertyName, location);
node.expression = expression;
return node;
}
export function createVoidZero() {
return createVoid(createLiteral(0));
// Type members
export function createMethod(modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], body: Block, location?: TextRange) {
const node = <MethodDeclaration>createNode(SyntaxKind.MethodDeclaration, location);
node.decorators = undefined;
setModifiers(node, modifiers);
node.name = coercePropertyName(name);
node.typeParameters = undefined;
node.parameters = createNodeArray(parameters);
node.body = body;
return node;
}
export function createConstructor(parameters: ParameterDeclaration[], body: Block, location?: TextRange) {
const node = <ConstructorDeclaration>createNode(SyntaxKind.Constructor, location);
node.decorators = undefined;
node.modifiers = undefined;
node.typeParameters = undefined;
node.parameters = createSynthesizedNodeArray(parameters);
node.type = undefined;
node.body = body;
return node;
}
export function createGetAccessor(modifiers: Modifier[], name: string | PropertyName, body: Block, location?: TextRange) {
const node = <GetAccessorDeclaration>createNode(SyntaxKind.GetAccessor, location);
node.decorators = undefined;
setModifiers(node, modifiers);
node.name = coercePropertyName(name);
node.typeParameters = undefined;
node.parameters = createNodeArray<ParameterDeclaration>();
node.body = body;
return node;
}
export function createSetAccessor(modifiers: Modifier[], name: string | PropertyName, parameter: ParameterDeclaration, body: Block, location?: TextRange) {
const node = <SetAccessorDeclaration>createNode(SyntaxKind.SetAccessor, location);
node.decorators = undefined;
setModifiers(node, modifiers);
node.name = coercePropertyName(name);
node.typeParameters = undefined;
node.parameters = createNodeArray([parameter]);
node.body = body;
return node;
}
export function createParameter(name: string | Identifier | BindingPattern, initializer?: Expression) {
const node = <ParameterDeclaration>createNode(SyntaxKind.Parameter);
node.decorators = undefined;
node.modifiers = undefined;
node.dotDotDotToken = undefined;
node.name = coerceBindingName(name);
node.questionToken = undefined;
node.type = undefined;
node.initializer = initializer;
return node;
}
// Expression
export function createArrayLiteral(elements?: Expression[]) {
const node = <ArrayLiteralExpression>createNode(SyntaxKind.ArrayLiteralExpression);
node.elements = createNodeArray(elements);
return node;
}
export function createObjectLiteral(properties?: ObjectLiteralElement[]) {
const node = <ObjectLiteralExpression>createNode(SyntaxKind.ObjectLiteralExpression);
node.properties = createNodeArray(properties);
return node;
}
export function createPropertyAccess(expression: Expression, name: string | Identifier, location?: TextRange) {
@@ -195,13 +306,51 @@ namespace ts {
return node;
}
export function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression) {
const node = <ConditionalExpression>createNode(SyntaxKind.ConditionalExpression);
node.condition = condition;
node.questionToken = createSynthesizedNode(SyntaxKind.QualifiedName);
node.whenTrue = whenTrue;
node.colonToken = createSynthesizedNode(SyntaxKind.ColonToken);
node.whenFalse = whenFalse;
export function createCall(expression: Expression, argumentsArray: Expression[], location?: TextRange) {
const node = <CallExpression>createNode(SyntaxKind.CallExpression, location);
node.expression = parenthesizeForAccess(expression);
node.arguments = createNodeArray(argumentsArray);
return node;
}
export function createParen(expression: Expression, location?: TextRange) {
const node = <ParenthesizedExpression>createNode(SyntaxKind.ParenthesizedExpression, location);
node.expression = expression;
return node;
}
export function createFunctionExpression(asteriskToken: Node, name: string | Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange) {
const node = <FunctionExpression>createNode(SyntaxKind.FunctionExpression, location);
node.modifiers = undefined;
node.asteriskToken = asteriskToken;
node.name = coerceIdentifier(name);
node.typeParameters = undefined;
node.parameters = createNodeArray(parameters);
node.type = undefined;
node.body = body;
return node;
}
export function createArrowFunction(parameters: ParameterDeclaration[], body: Expression | Block, location?: TextRange) {
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, location);
node.modifiers = undefined;
node.typeParameters = undefined;
node.parameters = createNodeArray(parameters);
node.type = undefined;
node.equalsGreaterThanToken = createNode(SyntaxKind.EqualsGreaterThanToken);
node.body = body;
return node;
}
export function createTypeOf(expression: Expression) {
const node = <TypeOfExpression>createNode(SyntaxKind.TypeOfExpression);
node.expression = parenthesizeForUnary(expression);
return node;
}
export function createVoid(expression: Expression) {
const node = <VoidExpression>createNode(SyntaxKind.VoidExpression);
node.expression = parenthesizeForUnary(expression);
return node;
}
@@ -213,22 +362,194 @@ namespace ts {
return node;
}
export function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression) {
const node = <ConditionalExpression>createNode(SyntaxKind.ConditionalExpression);
node.condition = condition;
node.questionToken = createSynthesizedNode(SyntaxKind.QualifiedName);
node.whenTrue = whenTrue;
node.colonToken = createSynthesizedNode(SyntaxKind.ColonToken);
node.whenFalse = whenFalse;
return node;
}
export function createYield(expression: Expression, location?: TextRange) {
const node = <YieldExpression>createNode(SyntaxKind.YieldExpression, location);
node.expression = expression;
return node;
}
export function createSpread(expression: Expression) {
const node = <SpreadElementExpression>createNode(SyntaxKind.SpreadElementExpression);
node.expression = expression;
return node;
}
export function createClassExpression(name: Identifier, heritageClauses: HeritageClause[], members: ClassElement[], location?: TextRange) {
const node = <ClassExpression>createNode(SyntaxKind.ClassExpression, location);
node.decorators = undefined;
node.modifiers = undefined;
node.name = name;
node.typeParameters = undefined;
node.heritageClauses = createSynthesizedNodeArray(heritageClauses);
node.members = createSynthesizedNodeArray(members);
return node;
}
export function createExpressionWithTypeArguments(expression: Expression, location?: TextRange) {
const node = <ExpressionWithTypeArguments>createNode(SyntaxKind.ExpressionWithTypeArguments, location);
node.typeArguments = undefined;
node.expression = parenthesizeForAccess(expression);
return node;
}
// Element
export function createBlock(statements: Statement[], location?: TextRange): Block {
const block = <Block>createNode(SyntaxKind.Block, location);
block.statements = createNodeArray(statements);
return block;
}
export function createVariableStatement(modifiers: Modifier[], declarationList: VariableDeclarationList, location?: TextRange): VariableStatement {
const node = <VariableStatement>createNode(SyntaxKind.VariableStatement, location);
node.decorators = undefined;
setModifiers(node, modifiers);
node.declarationList = declarationList;
return node;
}
export function createVariableDeclarationList(declarations: VariableDeclaration[], location?: TextRange, flags?: NodeFlags): VariableDeclarationList {
const node = <VariableDeclarationList>createNode(SyntaxKind.VariableDeclarationList, location, flags);
node.declarations = createNodeArray(declarations);
return node;
}
export function createLetDeclarationList(declarations: VariableDeclaration[], location?: TextRange) {
return createVariableDeclarationList(declarations, location, NodeFlags.Let);
}
export function createConstDeclarationList(declarations: VariableDeclaration[], location?: TextRange) {
return createVariableDeclarationList(declarations, location, NodeFlags.Const);
}
export function createVariableDeclaration(name: string | BindingPattern | Identifier, initializer?: Expression, location?: TextRange): VariableDeclaration {
const node = <VariableDeclaration>createNode(SyntaxKind.VariableDeclaration, location);
node.name = coerceBindingName(name);
node.initializer = initializer;
return node;
}
export function createStatement(expression: Expression, location?: TextRange): ExpressionStatement {
const node = <ExpressionStatement>createNode(SyntaxKind.ExpressionStatement, location);
node.expression = expression;
return node;
}
export function createReturn(expression?: Expression): ReturnStatement {
const node = <ReturnStatement>createSynthesizedNode(SyntaxKind.ReturnStatement);
node.expression = expression;
return node;
}
export function createFunctionDeclaration(modifiers: Modifier[], asteriskToken: Node, name: string | Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange) {
const node = <FunctionDeclaration>createNode(SyntaxKind.FunctionDeclaration, location);
node.decorators = undefined;
setModifiers(node, modifiers);
node.asteriskToken = asteriskToken;
node.name = coerceIdentifier(name);
node.typeParameters = undefined;
node.parameters = createNodeArray(parameters);
node.type = undefined;
node.body = body;
return node;
}
export function createClassDeclaration(modifiers: Modifier[], name: Identifier, heritageClauses: HeritageClause[], members: ClassElement[], location?: TextRange) {
const node = <ClassDeclaration>createNode(SyntaxKind.ClassDeclaration, location);
node.decorators = undefined;
setModifiers(node, modifiers);
node.name = name;
node.typeParameters = undefined;
node.heritageClauses = createSynthesizedNodeArray(heritageClauses);
node.members = createSynthesizedNodeArray(members);
return node;
}
export function createExportDefault(expression: Expression) {
const node = <ExportAssignment>createNode(SyntaxKind.ExportAssignment);
node.isExportEquals = false;
node.expression = expression;
return node;
}
export function createExportDeclaration(exportClause: NamedExports, moduleSpecifier?: Expression) {
const node = <ExportDeclaration>createNode(SyntaxKind.ExportDeclaration);
node.exportClause = exportClause;
node.moduleSpecifier = moduleSpecifier;
return node;
}
export function createNamedExports(elements: ExportSpecifier[]) {
const node = <NamedExports>createNode(SyntaxKind.NamedExports);
node.elements = createNodeArray(elements);
return node;
}
export function createExportSpecifier(name: string | Identifier, propertyName?: string | Identifier) {
const node = <ExportSpecifier>createNode(SyntaxKind.ExportSpecifier);
node.name = coerceIdentifier(name);
node.propertyName = coerceIdentifier(propertyName);
return node;
}
// Clauses
export function createHeritageClause(token: SyntaxKind, types: ExpressionWithTypeArguments[], location?: TextRange) {
const node = <HeritageClause>createNode(SyntaxKind.HeritageClause, location);
node.token = token;
node.types = createSynthesizedNodeArray(types);
return node;
}
// Compound nodes
export function createAssignment(left: Expression, right: Expression, location?: TextRange) {
return createBinary(left, SyntaxKind.EqualsToken, right, location);
}
export function createLogicalAnd(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.AmpersandAmpersandToken, right);
}
export function createLogicalOr(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.BarBarToken, right);
}
export function createStrictEquality(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.EqualsEqualsEqualsToken, right);
}
export function createStrictInequality(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.ExclamationEqualsEqualsToken, right);
}
export function createComma(left: Expression, right: Expression) {
return <Expression>createBinary(left, SyntaxKind.CommaToken, right);
}
export function createCall(expression: Expression, argumentsArray: Expression[], location?: TextRange) {
const node = <CallExpression>createNode(SyntaxKind.CallExpression, location);
node.expression = parenthesizeForAccess(expression);
node.arguments = createNodeArray(argumentsArray);
export function createVoidZero() {
return createVoid(createLiteral(0));
}
export function createMemberAccessForPropertyName(target: Expression, memberName: PropertyName, location?: TextRange): MemberExpression {
return isIdentifier(memberName)
? createPropertyAccess(target, cloneNode(memberName), location)
: createElementAccess(target, cloneNode(isComputedPropertyName(memberName) ? memberName.expression : memberName), location);
}
export function createRestParameter(name: string | Identifier) {
const node = createParameter(name, /*initializer*/ undefined);
node.dotDotDotToken = createSynthesizedNode(SyntaxKind.DotDotDotToken);
return node;
}
@@ -245,16 +566,232 @@ namespace ts {
);
}
export function parenthesizeExpression(expression: Expression) {
const node = <ParenthesizedExpression>createNode(SyntaxKind.ParenthesizedExpression);
node.expression = expression;
return node;
// Helpers
export function createParamHelper(expression: Expression, parameterOffset: number) {
return createCall(
createIdentifier("__param"),
[
createLiteral(parameterOffset),
expression
]
);
}
export function createMetadataHelper(metadataKey: string, metadataValue: Expression, defer?: boolean) {
return createCall(
createIdentifier("__metadata"),
[
createLiteral(metadataKey),
defer
? createArrowFunction([], metadataValue)
: metadataValue
]
);
}
export function createDecorateHelper(decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression) {
const argumentsArray: Expression[] = [];
argumentsArray.push(createArrayLiteral(decoratorExpressions));
argumentsArray.push(target);
if (memberName) {
argumentsArray.push(memberName);
if (descriptor) {
argumentsArray.push(descriptor);
}
}
return createCall(createIdentifier("__decorate"), argumentsArray);
}
export function createAwaiterHelper(hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression, body: Block) {
return createCall(
createIdentifier("__awaiter"),
[
createThis(),
hasLexicalArguments ? createIdentifier("arguments") : createVoidZero(),
promiseConstructor ? createExpressionFromEntityName(promiseConstructor) : createVoidZero(),
createFunctionExpression(
createNode(SyntaxKind.AsteriskToken),
/*name*/ undefined,
[],
body
)
]
);
}
function createObjectCreate(prototype: Expression) {
return createCall(
createPropertyAccess(createIdentifier("Object"), "create"),
[prototype]
);
}
function createGeti(target: LeftHandSideExpression) {
// name => super[name]
return createArrowFunction(
[createParameter("name")],
createElementAccess(
target,
createIdentifier("name")
)
)
}
function createSeti(target: LeftHandSideExpression) {
// (name, value) => super[name] = value
return createArrowFunction(
[
createParameter("name"),
createParameter("value")
],
createAssignment(
createElementAccess(
target,
createIdentifier("name")
),
createIdentifier("value")
)
);
}
export function createAdvancedAsyncSuperHelper() {
// const _super = (function (geti, seti) {
// const cache = Object.create(null);
// return name => cache[name] || (cache[name] = { get value() { return geti(name); }, set value(v) { seti(name, v); } });
// })(name => super[name], (name, value) => super[name] = value);
// const cache = Object.create(null);
const createCache = createVariableStatement(
/*modifiers*/ undefined,
createConstDeclarationList([
createVariableDeclaration(
"cache",
createObjectCreate(createNull())
)
])
);
// get value() { return geti(name); }
const getter = createGetAccessor(
/*modifiers*/ undefined,
"value",
createBlock([
createReturn(
createCall(
createIdentifier("geti"),
[createIdentifier("name")]
)
)
])
);
// set value(v) { seti(name, v); }
const setter = createSetAccessor(
/*modifiers*/ undefined,
"value",
createParameter("v"),
createBlock([
createStatement(
createCall(
createIdentifier("seti"),
[
createIdentifier("name"),
createIdentifier("v")
]
)
)
])
);
// return name => cache[name] || ...
const getOrCreateAccessorsForName = createReturn(
createArrowFunction(
[createParameter("name")],
createLogicalOr(
createElementAccess(
createIdentifier("cache"),
createIdentifier("name")
),
createParen(
createAssignment(
createElementAccess(
createIdentifier("cache"),
createIdentifier("name")
),
createObjectLiteral([
getter,
setter
])
)
)
)
)
);
// const _super = (function (geti, seti) {
// const cache = Object.create(null);
// return name => cache[name] || (cache[name] = { get value() { return geti(name); }, set value(v) { seti(name, v); } });
// })(name => super[name], (name, value) => super[name] = value);
return createVariableStatement(
/*modifiers*/ undefined,
createConstDeclarationList([
createVariableDeclaration(
"_super",
createCall(
createParen(
createFunctionExpression(
/*asteriskToken*/ undefined,
/*name*/ undefined,
[
createParameter("geti"),
createParameter("seti")
],
createBlock([
createCache,
getOrCreateAccessorsForName
])
)
),
[
createGeti(createSuper()),
createSeti(createSuper())
]
)
)
])
);
}
export function createSimpleAsyncSuperHelper() {
return createVariableStatement(
/*modifiers*/ undefined,
createConstDeclarationList([
createVariableDeclaration(
"_super",
createGeti(createSuper())
)
])
);
}
export function inlineExpressions(expressions: Expression[]) {
return reduceLeft(expressions, createComma);
}
export function createExpressionFromEntityName(node: EntityName | Expression): Expression {
return isQualifiedName(node)
? createPropertyAccess(
createExpressionFromEntityName(node.left),
cloneNode(node.right)
)
: cloneNode(node);
}
// Utilities
function coerceIdentifier(value: string | Identifier) {
if (typeof value === "string") {
return createIdentifier(value);
@@ -264,6 +801,24 @@ namespace ts {
}
}
function coerceBindingName(value: string | BindingName) {
if (typeof value === "string") {
return createIdentifier(value);
}
else {
return value;
}
}
function coercePropertyName(value: string | PropertyName) {
if (typeof value === "string") {
return createIdentifier(value);
}
else {
return value;
}
}
function coerceExpression(value: string | number | boolean | Expression): Expression {
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
return createLiteral(value);
@@ -291,7 +846,7 @@ namespace ts {
}
return needsParenthesesForBinary(operand, operator, side)
? parenthesizeExpression(operand)
? createParen(operand)
: operand;
}
@@ -343,6 +898,42 @@ namespace ts {
return <LeftHandSideExpression>expr;
}
return parenthesizeExpression(expr);
return createParen(expr);
}
function parenthesizeForUnary(operand: Expression) {
if (isUnaryExpression(operand)) {
return operand;
}
return createParen(operand);
}
export function startOnNewLine<T extends Node>(node: T): T {
(<SynthesizedNode>node).startsOnNewLine = true;
return node;
}
export function setOriginalNode<T extends Node>(node: T, original: Node): T {
node.original = original;
return node;
}
export function setTextRange<T extends TextRange>(node: T, location: TextRange): T {
if (location) {
node.pos = location.pos;
node.end = location.end;
}
return node;
}
export function setNodeFlags<T extends Node>(node: T, flags: NodeFlags): T {
node.flags = flags;
return node;
}
export function getSynthesizedNode<T extends Node>(node: T): T {
return nodeIsSynthesized(node) ? node : cloneNode(node, /*location*/ undefined, node.flags, /*parent*/ undefined, /*original*/ node);
}
}

View File

@@ -75,6 +75,15 @@ function __export(m) {
}
})`;
const superHelper = `
const _super = name => super[name];`;
const advancedSuperHelper = `
const _super = (function (geti, seti) {
const cache = Object.create(null);
return name => cache[name] || (cache[name] = { get value() { return geti(name); }, set value(v) { seti(name, v); } });
})(name => super[name], (name, value) => super[name] = value);`;
const compilerOptions = host.getCompilerOptions();
const languageVersion = getLanguageVersion(compilerOptions);
const moduleKind = getModuleKind(compilerOptions);
@@ -122,8 +131,12 @@ function __export(m) {
let startLexicalEnvironment: () => void;
let endLexicalEnvironment: () => Statement[];
let getNodeEmitFlags: (node: Node) => NodeEmitFlags;
let isExpressionSubstitutionEnabled: (node: Node) => boolean;
let isEmitNotificationEnabled: (node: Node) => boolean;
let expressionSubstitution: (node: Expression) => Expression;
let identifierSubstitution: (node: Identifier) => Identifier;
let onBeforeEmitNode: (node: Node) => void;
let onAfterEmitNode: (node: Node) => void;
let isUniqueName: (name: string) => boolean;
let temporaryVariables: string[] = [];
let tempFlags: TempFlags;
@@ -177,8 +190,12 @@ function __export(m) {
startLexicalEnvironment = undefined;
endLexicalEnvironment = undefined;
getNodeEmitFlags = undefined;
isExpressionSubstitutionEnabled = undefined;
isEmitNotificationEnabled = undefined;
expressionSubstitution = undefined;
identifierSubstitution = undefined;
onBeforeEmitNode = undefined;
onAfterEmitNode = undefined;
isUniqueName = undefined;
temporaryVariables = undefined;
tempFlags = 0;
@@ -196,8 +213,12 @@ function __export(m) {
startLexicalEnvironment = context.startLexicalEnvironment;
endLexicalEnvironment = context.endLexicalEnvironment;
getNodeEmitFlags = context.getNodeEmitFlags;
isExpressionSubstitutionEnabled = context.isExpressionSubstitutionEnabled;
isEmitNotificationEnabled = context.isEmitNotificationEnabled;
expressionSubstitution = context.expressionSubstitution;
identifierSubstitution = context.identifierSubstitution;
onBeforeEmitNode = context.onBeforeEmitNode;
onAfterEmitNode = context.onAfterEmitNode;
isUniqueName = context.isUniqueName;
return printSourceFile;
}
@@ -213,6 +234,11 @@ function __export(m) {
function emit(node: Node) {
if (node) {
const adviseOnEmit = isEmitNotificationEnabled(node);
if (adviseOnEmit && onBeforeEmitNode) {
onBeforeEmitNode(node);
}
const leadingComments = getLeadingCommentsToEmit(node);
const trailingComments = getTrailingCommentsToEmit(node);
emitLeadingComments(node, leadingComments);
@@ -220,6 +246,10 @@ function __export(m) {
emitWorker(node);
emitEnd(node);
emitTrailingComments(node, trailingComments);
if (adviseOnEmit && onAfterEmitNode) {
onAfterEmitNode(node);
}
}
}
@@ -234,7 +264,11 @@ function __export(m) {
// Identifiers
case SyntaxKind.Identifier:
return emitIdentifier(<Identifier>node, identifierSubstitution);
if (tryEmitSubstitute(node, identifierSubstitution)) {
return;
}
return emitIdentifier(<Identifier>node);
// Reserved words
case SyntaxKind.ConstKeyword:
@@ -486,6 +520,10 @@ function __export(m) {
function emitExpressionWorker(node: Node) {
const kind = node.kind;
if (isExpressionSubstitutionEnabled(node) && tryEmitSubstitute(node, expressionSubstitution)) {
return;
}
switch (kind) {
// Literals
case SyntaxKind.NumericLiteral:
@@ -496,16 +534,15 @@ function __export(m) {
// Identifiers
case SyntaxKind.Identifier:
return emitIdentifier(<Identifier>node, expressionSubstitution);
return emitIdentifier(<Identifier>node);
// Reserved words
case SyntaxKind.FalseKeyword:
case SyntaxKind.NullKeyword:
case SyntaxKind.SuperKeyword:
case SyntaxKind.TrueKeyword:
return writeTokenNode(node);
case SyntaxKind.ThisKeyword:
return emitThisKeyword(<PrimaryExpression>node);
return writeTokenNode(node);
// Expressions
case SyntaxKind.ArrayLiteralExpression:
@@ -597,11 +634,8 @@ function __export(m) {
// Identifiers
//
function emitIdentifier(node: Identifier, substitution: (node: Node) => Node) {
if (tryEmitSubstitute(node, substitution)) {
return;
}
else if (node.text === undefined) {
function emitIdentifier(node: Identifier) {
if (node.text === undefined) {
// Emit a temporary variable name for this node.
const nodeId = getOriginalNodeId(node);
const text = temporaryVariables[nodeId] || (temporaryVariables[nodeId] = makeTempVariableName(tempKindToFlags(node.tempKind)));
@@ -620,15 +654,6 @@ function __export(m) {
}
}
function emitThisKeyword(node: PrimaryExpression) {
if (tryEmitSubstitute(node, expressionSubstitution)) {
return;
}
else {
writeTokenNode(node);
}
}
//
// Names
//
@@ -1051,19 +1076,11 @@ function __export(m) {
}
function emitPostfixUnaryExpression(node: PostfixUnaryExpression) {
if (tryEmitSubstitute(node, expressionSubstitution)) {
return;
}
emitExpression(node.operand);
writeToken(node.operator);
}
function emitBinaryExpression(node: BinaryExpression) {
if (tryEmitSubstitute(node, expressionSubstitution)) {
return;
}
const isCommaOperator = node.operatorToken.kind !== SyntaxKind.CommaToken;
const indentBeforeOperator = needsIndentation(node, node.left, node.operatorToken);
const indentAfterOperator = needsIndentation(node, node.operatorToken, node.right);
@@ -1390,9 +1407,12 @@ function __export(m) {
function emitBlockFunctionBody(parentNode: Node, body: Block) {
// Emit all the prologue directives (like "use strict").
increaseIndent();
const statements = body.statements;
const statementOffset = emitPrologueDirectives(statements, /*startWithNewLine*/ true, /*indented*/ true);
const statementOffset = emitPrologueDirectives(statements, /*startWithNewLine*/ true);
const helpersEmitted = emitHelpers(body);
decreaseIndent();
if (statementOffset === 0 && !helpersEmitted && shouldEmitBlockFunctionBodyOnSingleLine(parentNode, body)) {
emitList(body, statements, ListFormat.SingleLineFunctionBodyStatements);
}
@@ -1688,6 +1708,7 @@ function __export(m) {
function emitHeritageClause(node: HeritageClause) {
emitStart(node);
write(" ");
writeToken(node.token);
write(" ");
emitList(node, node.types, ListFormat.HeritageClauseTypes);
@@ -1783,8 +1804,7 @@ function __export(m) {
}
}
function emitPrologueDirectives(statements: Node[], startWithNewLine?: boolean, indented?: boolean) {
increaseIndentIf(indented);
function emitPrologueDirectives(statements: Node[], startWithNewLine?: boolean) {
for (let i = 0; i < statements.length; i++) {
if (isPrologueDirective(statements[i])) {
if (startWithNewLine || i > 0) {
@@ -1794,24 +1814,32 @@ function __export(m) {
}
else {
// return index of the first non prologue directive
decreaseIndentIf(indented);
return i;
}
}
decreaseIndentIf(indented);
return statements.length;
}
function emitHelpers(node: Node) {
const emitFlags = getNodeEmitFlags(node);
let helpersEmitted = false;
if (emitFlags & NodeEmitFlags.EmitHelpers) {
if (emitFlags & NodeEmitFlags.EmitEmitHelpers) {
helpersEmitted = emitEmitHelpers(currentSourceFile);
}
if (emitFlags & NodeEmitFlags.EmitExportStar) {
emitExportStarHelper();
writeLines(exportStarHelper);
helpersEmitted = true;
}
if (emitFlags & NodeEmitFlags.EmitSuperHelper) {
writeLines(superHelper);
helpersEmitted = true;
}
if (emitFlags & NodeEmitFlags.EmitAdvancedSuperHelper) {
writeLines(advancedSuperHelper);
helpersEmitted = true;
}
@@ -1861,10 +1889,6 @@ function __export(m) {
return helpersEmitted;
}
function emitExportStarHelper() {
writeLines(exportStarHelper);
}
function writeLines(text: string): void {
const lines = text.split(/\r\n|\r|\n/g);
for (let i = 0; i < lines.length; i++) {

View File

@@ -56,6 +56,9 @@ namespace ts {
const nodeEmitFlags: NodeEmitFlags[] = [];
const lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = [];
const lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = [];
const enabledExpressionSubstitutions = new Array<boolean>(SyntaxKind.Count);
const enabledEmitNotifications = new Array<boolean>(SyntaxKind.Count);
let lexicalEnvironmentStackOffset = 0;
let hoistedVariableDeclarations: VariableDeclaration[];
let hoistedFunctionDeclarations: FunctionDeclaration[];
@@ -75,7 +78,11 @@ namespace ts {
hoistVariableDeclaration,
hoistFunctionDeclaration,
startLexicalEnvironment,
endLexicalEnvironment
endLexicalEnvironment,
enableExpressionSubstitution,
isExpressionSubstitutionEnabled,
enableEmitNotification,
isEmitNotificationEnabled,
};
// Chain together and initialize each transformer.
@@ -100,6 +107,23 @@ namespace ts {
return visited;
}
function enableExpressionSubstitution(kind: SyntaxKind) {
enabledExpressionSubstitutions[kind] = true;
}
function isExpressionSubstitutionEnabled(node: Node) {
return enabledExpressionSubstitutions[node.kind];
}
function enableEmitNotification(kind: SyntaxKind) {
enabledEmitNotifications[kind] = true;
}
function isEmitNotificationEnabled(node: Node) {
return enabledEmitNotifications[node.kind]
|| (getNodeEmitFlags(node) & NodeEmitFlags.AdviseOnEmitNode) !== 0;
}
/**
* Gets flags that control emit behavior of a node.
*/
@@ -207,7 +231,7 @@ namespace ts {
case SyntaxKind.ClassExpression:
return generateNameForClassExpression();
default:
return createTempVariable(TempVariableKind.Auto);
return createTempVariable();
}
}
@@ -289,6 +313,7 @@ namespace ts {
if (hoistedVariableDeclarations) {
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(hoistedVariableDeclarations)
)
);

View File

@@ -10,8 +10,14 @@ namespace ts {
* @param needsValue Indicates whether the value from the right-hand-side of the
* destructuring assignment is needed as part of a larger expression.
* @param recordTempVariable A callback used to record new temporary variables.
* @param visitor An optional visitor to use to visit expressions.
*/
export function flattenDestructuringAssignment(node: BinaryExpression, needsValue: boolean, recordTempVariable: (node: Identifier) => void) {
export function flattenDestructuringAssignment(
node: BinaryExpression,
needsValue: boolean,
recordTempVariable: (node: Identifier) => void,
visitor?: (node: Node) => Node) {
let location: TextRange = node;
let value = node.right;
if (isEmptyObjectLiteralOrArrayLiteral(node.left)) {
@@ -31,7 +37,7 @@ namespace ts {
location = node.right;
}
flattenDestructuring(node, value, location, emitAssignment, emitTempVariableAssignment);
flattenDestructuring(node, value, location, emitAssignment, emitTempVariableAssignment, visitor);
if (needsValue) {
expressions.push(value);
@@ -64,11 +70,12 @@ namespace ts {
*
* @param node The ParameterDeclaration to flatten.
* @param value The rhs value for the binding pattern.
* @param visitor An optional visitor to use to visit expressions.
*/
export function flattenParameterDestructuring(node: ParameterDeclaration, value: Expression) {
export function flattenParameterDestructuring(node: ParameterDeclaration, value: Expression, visitor?: (node: Node) => Node) {
const declarations: VariableDeclaration[] = [];
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment);
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, visitor);
return declarations;
@@ -94,11 +101,12 @@ namespace ts {
*
* @param node The VariableDeclaration to flatten.
* @param value An optional rhs value for the binding pattern.
* @param visitor An optional visitor to use to visit expressions.
*/
export function flattenVariableDestructuring(node: VariableDeclaration, value?: Expression) {
export function flattenVariableDestructuring(node: VariableDeclaration, value?: Expression, visitor?: (node: Node) => Node) {
const declarations: VariableDeclaration[] = [];
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment);
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, visitor);
return declarations;
@@ -129,8 +137,15 @@ namespace ts {
*
* @param node The VariableDeclaration to flatten.
* @param recordTempVariable A callback used to record new temporary variables.
* @param nameSubstitution An optional callback used to substitute binding names.
* @param visitor An optional visitor to use to visit expressions.
*/
export function flattenVariableDestructuringToExpression(node: VariableDeclaration, recordTempVariable: (name: Identifier) => void) {
export function flattenVariableDestructuringToExpression(
node: VariableDeclaration,
recordTempVariable: (name: Identifier) => void,
nameSubstitution?: (name: Identifier) => Expression,
visitor?: (node: Node) => Node) {
const pendingAssignments: Expression[] = [];
flattenDestructuring(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment);
@@ -140,6 +155,18 @@ namespace ts {
return expression;
function emitAssignment(name: Identifier, value: Expression, location: TextRange, original: Node) {
const left = nameSubstitution && nameSubstitution(name) || name;
emitPendingAssignment(left, value, location, original);
}
function emitTempVariableAssignment(value: Expression, location: TextRange) {
const name = createTempVariable();
recordTempVariable(name);
emitPendingAssignment(name, value, location, /*original*/ undefined);
return name;
}
function emitPendingAssignment(name: Expression, value: Expression, location: TextRange, original: Node) {
const expression = createAssignment(name, value, location);
if (isSimpleExpression(value)) {
(<SynthesizedNode>expression).disableSourceMap = true;
@@ -147,13 +174,7 @@ namespace ts {
expression.original = original;
pendingAssignments.push(expression);
}
function emitTempVariableAssignment(value: Expression, location: TextRange) {
const name = createTempVariable();
recordTempVariable(name);
emitAssignment(name, value, location, /*original*/ undefined);
return name;
return expression;
}
}
@@ -162,7 +183,12 @@ namespace ts {
value: Expression,
location: TextRange,
emitAssignment: (name: Identifier, value: Expression, location: TextRange, original: Node) => void,
emitTempVariableAssignment: (value: Expression, location: TextRange) => Identifier) {
emitTempVariableAssignment: (value: Expression, location: TextRange) => Identifier,
visitor?: (node: Node) => Node) {
if (value && visitor) {
value = visitNode(value, visitor, isExpression);
}
if (isBinaryExpression(root)) {
emitDestructuringAssignment(root.left, value, location)
}
@@ -174,14 +200,22 @@ namespace ts {
// When emitting target = value use source map node to highlight, including any temporary assignments needed for this
let target: Expression;
if (isShortHandPropertyAssignment(bindingTarget)) {
if (bindingTarget.objectAssignmentInitializer) {
value = createDefaultValueCheck(value, bindingTarget.objectAssignmentInitializer, location);
const initializer = visitor
? visitNode(bindingTarget.objectAssignmentInitializer, visitor, isExpression)
: bindingTarget.objectAssignmentInitializer;
if (initializer) {
value = createDefaultValueCheck(value, initializer, location);
}
target = bindingTarget.name;
}
else if (isBinaryExpression(bindingTarget) && bindingTarget.operatorToken.kind === SyntaxKind.EqualsToken) {
value = createDefaultValueCheck(value, bindingTarget.right, location);
const initializer = visitor
? visitNode(bindingTarget.right, visitor, isExpression)
: bindingTarget.right;
value = createDefaultValueCheck(value, initializer, location);
target = bindingTarget.left;
}
else {
@@ -244,9 +278,10 @@ namespace ts {
function emitBindingElement(target: BindingElement, value: Expression) {
// Any temporary assignments needed to emit target = value should point to target
if (target.initializer) {
const initializer = visitor ? visitNode(target.initializer, visitor, isExpression) : target.initializer;
if (initializer) {
// Combine value and initializer
value = value ? createDefaultValueCheck(value, target.initializer, target) : target.initializer;
value = value ? createDefaultValueCheck(value, initializer, target) : initializer;
}
else if (!value) {
// Use 'void 0' in absence of value and initializer

File diff suppressed because it is too large Load Diff

View File

@@ -1301,7 +1301,7 @@ namespace ts {
export interface EnumMember extends Declaration {
// This does include ComputedPropertyName, but the parser will give an error
// if it parses a ComputedPropertyName in an EnumMember
name: DeclarationName;
name: PropertyName;
initializer?: Expression;
}
@@ -2792,12 +2792,15 @@ namespace ts {
/* @internal */
export const enum NodeEmitFlags {
EmitHelpers = 1 << 0, // Any emit helpers should be written to this node.
EmitExportStar = 1 << 1, // The export * helper should be written to this node.
UMDDefine = 1 << 2, // This node should be replaced with the UMD define helper.
NoLexicalEnvironment = 1 << 3, // A new LexicalEnvironment should *not* be introduced when emitting this node.
SingleLine = 1 << 4, // The contents of this node should be emit on a single line.
MultiLine = 1 << 5, // The contents of this node should be emit on multiple lines.
EmitEmitHelpers = 1 << 0, // Any emit helpers should be written to this node.
EmitExportStar = 1 << 1, // The export * helper should be written to this node.
EmitSuperHelper = 1 << 2, // Emit the basic _super helper for async methods.
EmitAdvancedSuperHelper = 1 << 3, // Emit the advanced _super helper for async methods.
UMDDefine = 1 << 4, // This node should be replaced with the UMD define helper.
NoLexicalEnvironment = 1 << 5, // A new LexicalEnvironment should *not* be introduced when emitting this node.
SingleLine = 1 << 6, // The contents of this node should be emit on a single line.
MultiLine = 1 << 7, // The contents of this node should be emit on multiple lines.
AdviseOnEmitNode = 1 << 8, // The node printer should invoke the onBeforeEmitNode and onAfterEmitNode callbacks when printing this node.
}
/** Additional context provided to `visitEachChild` */
@@ -2821,8 +2824,14 @@ namespace ts {
getGeneratedNameForNode(node: Node): Identifier;
nodeHasGeneratedName(node: Node): boolean;
makeUniqueName(baseName: string): Identifier;
enableExpressionSubstitution(kind: SyntaxKind): void;
isExpressionSubstitutionEnabled(node: Node): boolean;
identifierSubstitution?: (node: Identifier) => Identifier;
expressionSubstitution?: (node: Expression) => Expression;
enableEmitNotification(kind: SyntaxKind): void;
isEmitNotificationEnabled(node: Node): boolean;
onBeforeEmitNode?: (node: Node) => void;
onAfterEmitNode?: (node: Node) => void;
}
/* @internal */

View File

@@ -1018,6 +1018,20 @@ namespace ts {
&& nodeCanBeDecorated(node);
}
export function nodeOrChildIsDecorated(node: Node): boolean {
return nodeIsDecorated(node) || childIsDecorated(node);
}
export function childIsDecorated(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.ClassDeclaration:
return forEach((<ClassDeclaration>node).members, nodeOrChildIsDecorated);
case SyntaxKind.MethodDeclaration:
case SyntaxKind.SetAccessor:
return forEach((<FunctionLikeDeclaration>node).parameters, nodeIsDecorated);
}
}
export function isPartOfExpression(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.SuperKeyword:
@@ -2252,7 +2266,14 @@ namespace ts {
return accessor && accessor.parameters.length > 0 && accessor.parameters[0].type;
}
export function getAllAccessorDeclarations(declarations: NodeArray<Declaration>, accessor: AccessorDeclaration) {
export interface AllAccessorDeclarations {
firstAccessor: AccessorDeclaration;
secondAccessor: AccessorDeclaration;
getAccessor: AccessorDeclaration;
setAccessor: AccessorDeclaration;
}
export function getAllAccessorDeclarations(declarations: NodeArray<Declaration>, accessor: AccessorDeclaration): AllAccessorDeclarations {
let firstAccessor: AccessorDeclaration;
let secondAccessor: AccessorDeclaration;
let getAccessor: AccessorDeclaration;
@@ -2816,7 +2837,6 @@ namespace ts {
|| kind === SyntaxKind.MethodDeclaration
|| kind === SyntaxKind.GetAccessor
|| kind === SyntaxKind.SetAccessor
|| kind === SyntaxKind.MethodSignature
|| kind === SyntaxKind.IndexSignature;
}
@@ -2849,6 +2869,10 @@ namespace ts {
return node.kind === SyntaxKind.BinaryExpression;
}
export function isConditionalExpression(node: Node): node is ConditionalExpression {
return node.kind === SyntaxKind.ConditionalExpression;
}
export function isShortHandPropertyAssignment(node: Node): node is ShorthandPropertyAssignment {
return node.kind === SyntaxKind.ShorthandPropertyAssignment;
}
@@ -3241,8 +3265,12 @@ namespace ts {
return node.kind === SyntaxKind.NodeArrayNode;
}
export function isModifiersArray(array: NodeArray<Node>): array is ModifiersArray {
return array.arrayKind === ArrayKind.ModifiersArray;
export function isNodeArray<T extends Node>(array: T[]): array is NodeArray<T> {
return (<NodeArray<T>>array).arrayKind === ArrayKind.ModifiersArray;
}
export function isModifiersArray(array: Modifier[]): array is ModifiersArray {
return (<ModifiersArray>array).arrayKind === ArrayKind.ModifiersArray;
}
}

View File

@@ -2,6 +2,8 @@
/* @internal */
namespace ts {
export type OneOrMore<T extends Node> = T | NodeArrayNode<T>;
/**
* Describes an edge of a Node, used when traversing a syntax tree.
*/
@@ -472,7 +474,7 @@ namespace ts {
* @param lift A callback to execute to lift a NodeArrayNode into a valid Node.
* @param optional A value indicating whether the Node is optional.
*/
export function visitNode<T extends Node>(node: T, visitor: (node: Node) => Node, test?: (node: Node) => boolean, lift?: (node: NodeArray<Node>) => T, optional?: boolean): T {
export function visitNode<T extends Node>(node: T, visitor: (node: Node) => Node, test?: (node: Node) => boolean, optional?: boolean, lift?: (node: NodeArray<Node>) => T): T {
if (node === undefined) {
return undefined;
}
@@ -490,6 +492,7 @@ namespace ts {
Debug.assert(test === undefined || test(visited), "Wrong node type after visit.");
aggregateTransformFlags(visited);
visited.original = node;
return <T>visited;
}
@@ -500,54 +503,55 @@ namespace ts {
* @param visitor The callback used to visit a Node.
* @param test A node test to execute for each node.
*/
export function visitNodes<T extends Node, TArray extends NodeArray<T>>(nodes: TArray, visitor: (node: Node) => Node, test?: (node: Node) => boolean): TArray {
export function visitNodes<T extends Node, TArray extends NodeArray<T>>(nodes: TArray, visitor: (node: Node) => Node, test?: (node: Node) => boolean, start?: number, count?: number): TArray;
export function visitNodes<T extends Node, U extends Node>(nodes: T[], visitor: (node: T) => U): NodeArray<U>;
export function visitNodes<T extends Node>(nodes: T[], visitor: (node: Node) => Node, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray<T>;
export function visitNodes<T extends Node, TArray extends NodeArray<T>>(nodes: TArray, visitor: (node: Node) => Node, test?: (node: Node) => boolean, start?: number, count?: number): TArray {
if (nodes === undefined) {
return undefined;
}
let updated: NodeArray<T> | ModifiersArray;
for (let i = 0, len = nodes.length; i < len; i++) {
const node = nodes[i];
const len = nodes.length;
start = start !== undefined ? Math.max(start, 0) : 0;
count = count !== undefined ? Math.min(count, len - start) : len - start;
let updated: T[];
if (start > 0 || count < len) {
updated = [];
}
for (let i = 0; i < count; i++) {
const node = nodes[i + start];
if (node === undefined) {
continue;
}
const visited = visitor(node);
const visited = <OneOrMore<T>>visitor(node);
if (updated !== undefined || visited === undefined || visited !== node) {
if (updated === undefined) {
updated = isModifiersArray(nodes)
? createModifiersArray(nodes.slice(0, i), nodes.pos, nodes.end)
: createNodeArray<T>(nodes.slice(0, i), nodes.pos, nodes.end);
updated = nodes.slice(0, i);
}
if (visited === undefined) {
continue;
}
if (isNodeArrayNode<T>(visited)) {
spreadNodeArrayNode(visited, updated, test);
if (visited !== node) {
aggregateTransformFlags(visited);
visited.original = node;
}
else if (visited !== undefined) {
Debug.assert(test === undefined || test(visited), "Wrong node type after visit.");
if (visited !== node) {
aggregateTransformFlags(visited);
}
updated.push(<T>visited);
}
addNode(updated, visited, test);
}
}
if (updated && isModifiersArray(updated)) {
let flags: NodeFlags = 0;
for (const node of updated) {
flags |= modifierToFlag(node.kind);
}
updated.flags = flags;
if (updated) {
return <TArray>(isModifiersArray(nodes)
? createModifiersArray(updated, /*location*/ nodes)
: createNodeArray(updated, /*location*/ nodes));
}
return <TArray>updated || nodes;
return nodes;
}
/**
@@ -606,6 +610,7 @@ namespace ts {
if (updated !== node) {
aggregateTransformFlags(updated);
updated.original = node;
}
return updated;
@@ -621,24 +626,40 @@ namespace ts {
function visitEdge(edge: NodeEdge, value: Node | NodeArray<Node>, visitor: (node: Node) => Node) {
return isArray(value)
? visitNodes(<NodeArray<Node>>value, visitor, edge.test)
: visitNode(<Node>value, visitor, edge.test, edge.lift, edge.optional);
: visitNode(<Node>value, visitor, edge.test, edge.optional, edge.lift);
}
/**
* Spreads a NodeArrayNode into a NodeArray.
* Appends a node to an array.
*
* @param source The source NodeArrayNode.
* @param dest The destination NodeArray.
* @param to The destination array.
* @param from The source Node or NodeArrayNode.
* @param test The node test used to validate each node.
*/
function spreadNodeArrayNode<T extends Node>(source: NodeArrayNode<T>, dest: NodeArray<T>, test: (node: Node) => boolean) {
for (const element of source.nodes) {
if (element === undefined) {
continue;
export function addNode<T extends Node>(to: T[], from: OneOrMore<T>, test?: (node: Node) => boolean) {
if (to && from) {
if (isNodeArrayNode(from)) {
addNodes(to, from.nodes, test);
}
else {
Debug.assert(test === undefined || test(from), "Wrong node type after visit.");
to.push(from);
}
}
}
Debug.assert(test === undefined || test(element), "Wrong node type after visit.");
dest.push(element);
/**
* Appends an array of nodes to an array.
*
* @param to The destination NodeArray.
* @param from The source array of Node or NodeArrayNode.
* @param test The node test used to validate each node.
*/
export function addNodes<T extends Node>(to: T[], from: OneOrMore<T>[], test?: (node: Node) => boolean) {
if (to && from) {
for (const node of from) {
addNode(to, node, test);
}
}
}
@@ -695,14 +716,31 @@ namespace ts {
*/
function mergeFunctionLikeLexicalEnvironment(node: FunctionLikeDeclaration, declarations: Statement[]) {
Debug.assert(node.body !== undefined);
if (node.body.kind === SyntaxKind.Block) {
node.body = <Block>mergeLexicalEnvironment(node.body, declarations, /*nodeIsMutable*/ false);
node.body = mergeConciseBodyLexicalEnvironment(node.body, declarations);
}
export function mergeFunctionBodyLexicalEnvironment(body: FunctionBody, declarations: Statement[], nodeIsMutable?: boolean): FunctionBody {
if (declarations && declarations.length > 0) {
return <Block>mergeLexicalEnvironment(body, declarations, nodeIsMutable);
}
return body;
}
export function mergeConciseBodyLexicalEnvironment(body: ConciseBody, declarations: Statement[], nodeIsMutable?: boolean): ConciseBody {
if (declarations && declarations.length > 0) {
if (isBlock(body)) {
return <Block>mergeLexicalEnvironment(body, declarations, nodeIsMutable);
}
else {
return createBlock([
createReturn(body),
...declarations
]);
}
}
else {
node.body = createBlock([
createReturn(<Expression>node.body),
...declarations
]);
return body;
}
}
@@ -717,7 +755,7 @@ namespace ts {
* Merge generated declarations of a lexical environment into a NodeArray of Statement.
*/
function mergeStatements(statements: NodeArray<Statement>, declarations: Statement[]) {
return createNodeArray(statements.concat(declarations), statements.pos, statements.end);
return createNodeArray(concatenate(statements, declarations), /*location*/ statements);
}
/**