cleaned up assertions and removed flattenNodes.

This commit is contained in:
Ron Buckton 2016-03-10 12:47:10 -08:00
parent 2699bf923b
commit 94018a13e6
10 changed files with 171 additions and 120 deletions

View File

@ -1035,7 +1035,12 @@ namespace ts {
}
export namespace Debug {
const currentAssertionLevel = AssertionLevel.None;
declare var process: any;
declare var require: any;
const currentAssertionLevel = getDevelopmentMode() === "development"
? AssertionLevel.Normal
: AssertionLevel.None;
export function shouldAssert(level: AssertionLevel): boolean {
return currentAssertionLevel >= level;
@ -1055,6 +1060,17 @@ namespace ts {
export function fail(message?: string): void {
Debug.assert(/*expression*/ false, message);
}
function getDevelopmentMode() {
return typeof require !== "undefined"
&& typeof process !== "undefined"
&& !process.browser
&& process.nextTick
&& process.env
&& process.env.NODE_ENV
? String(process.env.NODE_ENV).toLowerCase()
: undefined;
}
}
export function copyListRemovingItem<T>(item: T, list: T[]) {

View File

@ -16,7 +16,7 @@ namespace ts {
node: BinaryExpression,
needsValue: boolean,
recordTempVariable: (node: Identifier) => void,
visitor?: (node: Node) => OneOrMany<Node>) {
visitor?: (node: Node) => VisitResult<Node>) {
if (isEmptyObjectLiteralOrArrayLiteral(node.left)) {
return node.right;
@ -79,7 +79,7 @@ namespace ts {
* @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, visitor?: (node: Node) => OneOrMany<Node>) {
export function flattenParameterDestructuring(node: ParameterDeclaration, value: Expression, visitor?: (node: Node) => VisitResult<Node>) {
const declarations: VariableDeclaration[] = [];
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, visitor);
@ -110,7 +110,7 @@ namespace ts {
* @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, visitor?: (node: Node) => OneOrMany<Node>) {
export function flattenVariableDestructuring(node: VariableDeclaration, value?: Expression, visitor?: (node: Node) => VisitResult<Node>) {
const declarations: VariableDeclaration[] = [];
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, visitor);
@ -151,7 +151,7 @@ namespace ts {
node: VariableDeclaration,
recordTempVariable: (name: Identifier) => void,
nameSubstitution?: (name: Identifier) => Expression,
visitor?: (node: Node) => OneOrMany<Node>) {
visitor?: (node: Node) => VisitResult<Node>) {
const pendingAssignments: Expression[] = [];
@ -191,7 +191,7 @@ namespace ts {
location: TextRange,
emitAssignment: (name: Identifier, value: Expression, location: TextRange, original: Node) => void,
emitTempVariableAssignment: (value: Expression, location: TextRange) => Identifier,
visitor?: (node: Node) => OneOrMany<Node>) {
visitor?: (node: Node) => VisitResult<Node>) {
if (value && visitor) {
value = visitNode(value, visitor, isExpression);
}

View File

@ -55,7 +55,7 @@ namespace ts {
return visitEachChild(node, visitor, context);
}
function visitor(node: Node): OneOrMany<Node> {
function visitor(node: Node): VisitResult<Node> {
const savedContainingNonArrowFunction = containingNonArrowFunction;
const savedCurrentParent = currentParent;
const savedCurrentNode = currentNode;
@ -74,7 +74,7 @@ namespace ts {
return visited;
}
function visitorWorker(node: Node): OneOrMany<Node> {
function visitorWorker(node: Node): VisitResult<Node> {
if (node.transformFlags & TransformFlags.ES6) {
return visitJavaScript(node);
}
@ -86,7 +86,7 @@ namespace ts {
}
}
function visitJavaScript(node: Node): OneOrMany<Node> {
function visitJavaScript(node: Node): VisitResult<Node> {
switch (node.kind) {
case SyntaxKind.ClassDeclaration:
return visitClassDeclaration(<ClassDeclaration>node);
@ -174,9 +174,12 @@ namespace ts {
case SyntaxKind.SourceFile:
return visitSourceFileNode(<SourceFile>node);
default:
Debug.failBadSyntaxKind(node);
return visitEachChild(node, visitor, context);
}
Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`);
}
function onBeforeVisitNode(node: Node) {
@ -695,7 +698,7 @@ namespace ts {
break;
default:
Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`);
Debug.failBadSyntaxKind(node);
break;
}
}
@ -936,7 +939,7 @@ namespace ts {
enableSubstitutionsForBlockScopedBindings();
return setOriginalNode(
createVariableDeclarationList(
flattenNodes(map(node.declarations, visitVariableDeclarationInLetDeclarationList)),
flatten(map(node.declarations, visitVariableDeclarationInLetDeclarationList)),
/*location*/ node
),
node
@ -1043,7 +1046,7 @@ namespace ts {
*
* @param node A VariableDeclaration node.
*/
function visitVariableDeclaration(node: VariableDeclaration): OneOrMany<VariableDeclaration> {
function visitVariableDeclaration(node: VariableDeclaration): VisitResult<VariableDeclaration> {
// If we are here it is because the name contains a binding pattern.
Debug.assert(isBindingPattern(node.name));
@ -1293,7 +1296,7 @@ namespace ts {
break;
default:
Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`);
Debug.failBadSyntaxKind(node);
break;
}
}

View File

@ -12,7 +12,7 @@ namespace ts {
return visitEachChild(node, visitor, context);
}
function visitor(node: Node): OneOrMany<Node> {
function visitor(node: Node): VisitResult<Node> {
if (node.transformFlags & TransformFlags.ES7) {
return visitorWorker(node);
}
@ -24,13 +24,15 @@ namespace ts {
}
}
function visitorWorker(node: Node): OneOrMany<Node> {
function visitorWorker(node: Node): VisitResult<Node> {
switch (node.kind) {
case SyntaxKind.BinaryExpression:
return visitBinaryExpression(<BinaryExpression>node);
}
Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`);
default:
Debug.failBadSyntaxKind(node);
return visitEachChild(node, visitor, context);
}
}
function visitBinaryExpression(node: BinaryExpression): Expression {
@ -90,7 +92,8 @@ namespace ts {
return createMathPow(left, right, /*location*/ node);
}
else {
Debug.fail(`Unexpected operator kind: ${formatSyntaxKind(node.operatorToken.kind)}.`);
Debug.failBadSyntaxKind(node);
return visitEachChild(node, visitor, context);
}
}
}

View File

@ -18,7 +18,7 @@ namespace ts {
return visitEachChild(node, visitor, context);
}
function visitor(node: Node): OneOrMany<Node> {
function visitor(node: Node): VisitResult<Node> {
if (node.transformFlags & TransformFlags.Jsx) {
return visitorWorker(node);
}
@ -30,16 +30,18 @@ namespace ts {
}
}
function visitorWorker(node: Node): OneOrMany<Node> {
function visitorWorker(node: Node): VisitResult<Node> {
switch (node.kind) {
case SyntaxKind.JsxElement:
return visitJsxElement(<JsxElement>node);
case SyntaxKind.JsxSelfClosingElement:
return visitJsxSelfClosingElement(<JsxSelfClosingElement>node);
}
Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`);
default:
Debug.failBadSyntaxKind(node);
return undefined;
}
}
function transformJsxChildToExpression(node: JsxChild): Expression {
@ -55,9 +57,11 @@ namespace ts {
case SyntaxKind.JsxSelfClosingElement:
return visitJsxSelfClosingElement(<JsxSelfClosingElement>node);
}
Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`);
default:
Debug.failBadSyntaxKind(node);
return undefined;
}
}
function visitJsxElement(node: JsxElement) {

View File

@ -123,7 +123,7 @@ namespace ts {
createStatement(
createCall(
define,
flattenNodes([
flatten([
// Add the module name (if provided).
moduleName,
@ -142,7 +142,7 @@ namespace ts {
setNodeEmitFlags(
setMultiLine(
createBlock(
flattenNodes([
flatten([
// Visit each statement of the module body.
...visitNodes(node.statements, visitor, isStatement),
@ -173,7 +173,7 @@ namespace ts {
*
* @param node The node.
*/
function visitor(node: Node): OneOrMany<Node> {
function visitor(node: Node): VisitResult<Node> {
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
return visitImportDeclaration(<ImportDeclaration>node);
@ -208,7 +208,7 @@ namespace ts {
*
* @param node The ImportDeclaration node.
*/
function visitImportDeclaration(node: ImportDeclaration): OneOrMany<Statement> {
function visitImportDeclaration(node: ImportDeclaration): VisitResult<Statement> {
if (contains(externalImports, node)) {
const statements: Statement[] = [];
const namespaceDeclaration = getNamespaceDeclarationNode(node);
@ -287,7 +287,7 @@ namespace ts {
return undefined;
}
function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): OneOrMany<Statement> {
function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult<Statement> {
if (contains(externalImports, node)) {
const statements: Statement[] = [];
if (moduleKind !== ModuleKind.AMD) {
@ -335,7 +335,7 @@ namespace ts {
return undefined;
}
function visitExportDeclaration(node: ExportDeclaration): OneOrMany<Statement> {
function visitExportDeclaration(node: ExportDeclaration): VisitResult<Statement> {
if (contains(externalImports, node)) {
const generatedName = getGeneratedNameForNode(node);
if (node.exportClause) {
@ -391,7 +391,7 @@ namespace ts {
return undefined;
}
function visitExportAssignment(node: ExportAssignment): OneOrMany<Statement> {
function visitExportAssignment(node: ExportAssignment): VisitResult<Statement> {
if (!node.isExportEquals && resolver.isValueAliasDeclaration(node)) {
const statements: Statement[] = [];
addExportDefault(statements, node.expression, /*location*/ node);
@ -470,7 +470,7 @@ namespace ts {
}
}
function visitVariableStatement(node: VariableStatement): OneOrMany<Statement> {
function visitVariableStatement(node: VariableStatement): VisitResult<Statement> {
const variables = getInitializedVariables(node.declarationList);
if (variables.length === 0) {
// elide statement if there are no initialized variables
@ -502,7 +502,7 @@ namespace ts {
}
}
function visitFunctionDeclaration(node: FunctionDeclaration): OneOrMany<Statement> {
function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult<Statement> {
const statements: Statement[] = [];
if (node.name) {
if (hasModifier(node, ModifierFlags.Export)) {
@ -543,7 +543,7 @@ namespace ts {
return statements;
}
function visitClassDeclaration(node: ClassDeclaration): OneOrMany<Statement> {
function visitClassDeclaration(node: ClassDeclaration): VisitResult<Statement> {
const statements: Statement[] = [];
if (node.name) {
if (hasModifier(node, ModifierFlags.Export)) {

View File

@ -408,7 +408,7 @@ namespace ts {
return createArrayLiteral(setters);
}
function visitSourceElement(node: Node): OneOrMany<Node> {
function visitSourceElement(node: Node): VisitResult<Node> {
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
return visitImportDeclaration(<ImportDeclaration>node);
@ -427,7 +427,7 @@ namespace ts {
}
}
function visitNestedNode(node: Node): OneOrMany<Node> {
function visitNestedNode(node: Node): VisitResult<Node> {
switch (node.kind) {
case SyntaxKind.VariableStatement:
return visitVariableStatement(<VariableStatement>node);
@ -502,7 +502,7 @@ namespace ts {
return undefined;
}
function visitExportDeclaration(node: ExportDeclaration): OneOrMany<Statement> {
function visitExportDeclaration(node: ExportDeclaration): VisitResult<Statement> {
if (!node.moduleSpecifier) {
const statements: Statement[] = [];
addNodes(statements, map(node.exportClause.elements, visitExportSpecifier));
@ -541,7 +541,7 @@ namespace ts {
*
* @param node The variable statement to visit.
*/
function visitVariableStatement(node: VariableStatement): OneOrMany<Statement> {
function visitVariableStatement(node: VariableStatement): VisitResult<Statement> {
const isExported = hasModifier(node, ModifierFlags.Export);
const expressions: Expression[] = [];
for (const variable of node.declarationList.declarations) {
@ -616,7 +616,7 @@ namespace ts {
*
* @param node The class declaration to visit.
*/
function visitClassDeclaration(node: ClassDeclaration): OneOrMany<Statement> {
function visitClassDeclaration(node: ClassDeclaration): VisitResult<Statement> {
// Hoist the name of the class declaration to the outer module body function.
const name = getDeclarationName(node);
hoistVariableDeclaration(name);

View File

@ -92,7 +92,7 @@ namespace ts {
*
* @param node The node to visit.
*/
function visitWithStack(node: Node, visitor: (node: Node) => OneOrMany<Node>): OneOrMany<Node> {
function visitWithStack(node: Node, visitor: (node: Node) => VisitResult<Node>): VisitResult<Node> {
// Save state
const savedCurrentNamespace = currentNamespace;
const savedCurrentScope = currentScope;
@ -118,7 +118,7 @@ namespace ts {
*
* @param node The node to visit.
*/
function visitor(node: Node): OneOrMany<Node> {
function visitor(node: Node): VisitResult<Node> {
return visitWithStack(node, visitorWorker);
}
@ -127,7 +127,7 @@ namespace ts {
*
* @param node The node to visit.
*/
function visitorWorker(node: Node): OneOrMany<Node> {
function visitorWorker(node: Node): VisitResult<Node> {
if (node.transformFlags & TransformFlags.TypeScript) {
// This node is explicitly marked as TypeScript, so we should transform the node.
return visitTypeScript(node);
@ -145,7 +145,7 @@ namespace ts {
*
* @param node The node to visit.
*/
function namespaceElementVisitor(node: Node): OneOrMany<Node> {
function namespaceElementVisitor(node: Node): VisitResult<Node> {
return visitWithStack(node, namespaceElementVisitorWorker);
}
@ -154,7 +154,7 @@ namespace ts {
*
* @param node The node to visit.
*/
function namespaceElementVisitorWorker(node: Node): OneOrMany<Node> {
function namespaceElementVisitorWorker(node: Node): VisitResult<Node> {
if (node.transformFlags & TransformFlags.TypeScript || isExported(node)) {
// This node is explicitly marked as TypeScript, or is exported at the namespace
// level, so we should transform the node.
@ -173,7 +173,7 @@ namespace ts {
*
* @param node The node to visit.
*/
function classElementVisitor(node: Node): OneOrMany<Node> {
function classElementVisitor(node: Node): VisitResult<Node> {
return visitWithStack(node, classElementVisitorWorker);
}
@ -182,7 +182,7 @@ namespace ts {
*
* @param node The node to visit.
*/
function classElementVisitorWorker(node: Node): OneOrMany<Node> {
function classElementVisitorWorker(node: Node): VisitResult<Node> {
switch (node.kind) {
case SyntaxKind.Constructor:
// TypeScript constructors are transformed in `transformClassDeclaration`.
@ -202,8 +202,8 @@ namespace ts {
return node;
default:
Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`);
break;
Debug.failBadSyntaxKind(node);
return undefined;
}
}
@ -212,7 +212,7 @@ namespace ts {
*
* @param node The node to visit.
*/
function visitTypeScript(node: Node): OneOrMany<Node> {
function visitTypeScript(node: Node): VisitResult<Node> {
if (hasModifier(node, ModifierFlags.Ambient)) {
// TypeScript ambient declarations are elided.
return undefined;
@ -373,8 +373,8 @@ namespace ts {
return visitImportEqualsDeclaration(<ImportEqualsDeclaration>node);
default:
Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`);
break;
Debug.failBadSyntaxKind(node);
return undefined;
}
}
@ -408,7 +408,7 @@ namespace ts {
*
* @param node The node to transform.
*/
function visitClassDeclaration(node: ClassDeclaration): OneOrMany<Statement> {
function visitClassDeclaration(node: ClassDeclaration): VisitResult<Statement> {
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
const hasExtendsClause = getClassExtendsHeritageClauseElement(node) !== undefined;
@ -1553,7 +1553,7 @@ namespace ts {
break;
default:
Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`);
Debug.failBadSyntaxKind(node);
break;
}
@ -1855,7 +1855,7 @@ namespace ts {
*
* @param node The function node.
*/
function visitFunctionDeclaration(node: FunctionDeclaration): OneOrMany<Statement> {
function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult<Statement> {
if (shouldElideFunctionLikeDeclaration(node)) {
return undefined;
}
@ -2150,7 +2150,7 @@ namespace ts {
*
* @param node The enum declaration node.
*/
function visitEnumDeclaration(node: EnumDeclaration): OneOrMany<Statement> {
function visitEnumDeclaration(node: EnumDeclaration): VisitResult<Statement> {
if (shouldElideEnumDeclaration(node)) {
return undefined;
}
@ -2362,7 +2362,7 @@ namespace ts {
*
* @param node The module declaration node.
*/
function visitModuleDeclaration(node: ModuleDeclaration): OneOrMany<Statement> {
function visitModuleDeclaration(node: ModuleDeclaration): VisitResult<Statement> {
if (shouldElideModuleDeclaration(node)) {
return undefined;
}
@ -2481,7 +2481,7 @@ namespace ts {
*
* @param node The import equals declaration node.
*/
function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): OneOrMany<Statement> {
function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult<Statement> {
Debug.assert(!isExternalModuleImportEqualsDeclaration(node));
if (shouldElideImportEqualsDeclaration(node)) {
return undefined;

View File

@ -2735,6 +2735,8 @@ namespace ts {
/* @internal */
export const enum TransformFlags {
None = 0,
// Facts
// - Flags used to indicate that a node or subtree contains syntax that requires transformation.
TypeScript = 1 << 0,

View File

@ -3,7 +3,7 @@
/* @internal */
namespace ts {
export type OneOrMany<T extends Node> = T | T[];
export type VisitResult<T extends Node> = T | T[];
/**
* Describes an edge of a Node, used when traversing a syntax tree.
@ -448,7 +448,7 @@ namespace ts {
* @param f The callback function
* @param initial The initial value to supply to the reduction.
*/
export function reduceEachChild<T>(node: Node, f: (memo: T, node: Node) => T, initial: T) {
export function reduceEachChild<T>(node: Node, f: (memo: T, node: Node) => T, initial: T): T {
if (node === undefined) {
return undefined;
}
@ -478,7 +478,7 @@ namespace ts {
* @param optional An optional value indicating whether the Node is itself optional.
* @param lift An optional callback to execute to lift a NodeArrayNode into a valid Node.
*/
export function visitNode<T extends Node>(node: T, visitor: (node: Node) => OneOrMany<Node>, test: (node: Node) => boolean, optional?: boolean, lift?: (node: NodeArray<Node>) => T): T {
export function visitNode<T extends Node>(node: T, visitor: (node: Node) => VisitResult<Node>, test: (node: Node) => boolean, optional?: boolean, lift?: (node: NodeArray<Node>) => T): T {
return <T>visitNodeWorker(node, visitor, test, optional, lift, /*parenthesize*/ undefined, /*parentNode*/ undefined);
}
@ -493,24 +493,26 @@ namespace ts {
* @param parenthesize A callback used to parenthesize the node if needed.
* @param parentNode A parentNode for the node.
*/
function visitNodeWorker(node: Node, visitor: (node: Node) => OneOrMany<Node>, test: (node: Node) => boolean, optional: boolean, lift: (node: NodeArray<Node>) => Node, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node): Node {
function visitNodeWorker(node: Node, visitor: (node: Node) => VisitResult<Node>, test: (node: Node) => boolean, optional: boolean, lift: (node: Node[]) => Node, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node): Node {
if (node === undefined) {
return undefined;
}
let visited = visitor(node);
const visited = visitor(node);
if (visited === node) {
return node;
}
let visitedNode: Node;
if (visited === undefined) {
Debug.assert(optional, "Node not optional.");
if (!optional) {
Debug.failNotOptional();
}
return undefined;
}
let visitedNode: Node;
if (isArray(visited)) {
visitedNode = (lift || extractSingleNode)(<NodeArray<Node>>visited);
else if (isArray(visited)) {
visitedNode = (lift || extractSingleNode)(visited);
}
else {
visitedNode = visited;
@ -520,7 +522,7 @@ namespace ts {
visitedNode = parenthesize(visitedNode, parentNode);
}
Debug.assert(test === undefined || test(visitedNode), "Wrong node type after visit.", () => `Node ${formatSyntaxKind(visitedNode.kind)} did not pass test ${(<any>test).name}.`);
Debug.assertNode(visitedNode, test);
aggregateTransformFlags(visitedNode);
return visitedNode;
}
@ -534,7 +536,7 @@ namespace ts {
* @param start An optional value indicating the starting offset at which to start visiting.
* @param count An optional value indicating the maximum number of nodes to visit.
*/
export function visitNodes<T extends Node, TArray extends NodeArray<T>>(nodes: TArray, visitor: (node: Node) => OneOrMany<Node>, test: (node: Node) => boolean, start?: number, count?: number): TArray {
export function visitNodes<T extends Node, TArray extends NodeArray<T>>(nodes: TArray, visitor: (node: Node) => VisitResult<Node>, test: (node: Node) => boolean, start?: number, count?: number): TArray {
return <TArray>visitNodesWorker(nodes, visitor, test, /*parenthesize*/ undefined, /*parentNode*/ undefined, start, count);
}
@ -547,12 +549,12 @@ namespace ts {
* @param start An optional value indicating the starting offset at which to start visiting.
* @param count An optional value indicating the maximum number of nodes to visit.
*/
function visitNodesWorker(nodes: NodeArray<Node>, visitor: (node: Node) => OneOrMany<Node>, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, start: number, count: number): NodeArray<Node> {
function visitNodesWorker(nodes: NodeArray<Node>, visitor: (node: Node) => VisitResult<Node>, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, start: number, count: number): NodeArray<Node> {
if (nodes === undefined) {
return undefined;
}
let updated: Node[];
let updated: NodeArray<Node>;
// Ensure start and count have valid values
const length = nodes.length;
@ -564,9 +566,12 @@ namespace ts {
count = length - start;
}
// If we are not visiting all of the original nodes, we must always create a new array.
if (start > 0 || count < length) {
updated = [];
// If we are not visiting all of the original nodes, we must always create a new array.
// Since this is a fragment of a node array, we do not copy over the previous location
// and will only copy over `hasTrailingComma` if we are including the last element.
updated = createNodeArray<Node>([], /*location*/ undefined,
/*hasTrailingComma*/ nodes.hasTrailingComma && start + count === length);
}
// Visit each original node.
@ -576,18 +581,14 @@ namespace ts {
if (updated !== undefined || visited === undefined || visited !== node) {
if (updated === undefined) {
// Ensure we have a copy of `nodes`, up to the current index.
updated = nodes.slice(0, i);
updated = createNodeArray(nodes.slice(0, i), /*location*/ nodes, nodes.hasTrailingComma);
}
addNodeWorker(updated, visited, /*addOnNewLine*/ undefined, test, parenthesize, parentNode, /*isVisiting*/ visited !== node);
}
}
if (updated !== undefined) {
return createNodeArray(updated, nodes, nodes.hasTrailingComma);
}
return nodes;
return updated || nodes;
}
/**
@ -597,8 +598,8 @@ namespace ts {
* @param visitor The callback used to visit each child.
* @param context A lexical environment context for the visitor.
*/
export function visitEachChild<T extends Node>(node: T, visitor: (node: Node) => OneOrMany<Node>, context: LexicalEnvironment): T;
export function visitEachChild<T extends Node>(node: T & Map<any>, visitor: (node: Node) => OneOrMany<Node>, context: LexicalEnvironment): T {
export function visitEachChild<T extends Node>(node: T, visitor: (node: Node) => VisitResult<Node>, context: LexicalEnvironment): T;
export function visitEachChild<T extends Node>(node: T & Map<any>, visitor: (node: Node) => VisitResult<Node>, context: LexicalEnvironment): T {
if (node === undefined) {
return undefined;
}
@ -657,33 +658,13 @@ namespace ts {
return updated;
}
/**
* Flattens an array of nodes that could contain NodeArrayNodes.
*/
export function flattenNodes<T extends Node>(nodes: OneOrMany<T>[]): T[] {
let result: T[];
if (nodes) {
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if (result || node === undefined || isArray(node)) {
if (!result) {
result = <T[]>nodes.slice(0, i);
}
addNode(result, node);
}
}
}
return result || <T[]>nodes;
}
/**
* Appends a node to an array.
*
* @param to The destination array.
* @param from The source Node or NodeArrayNode.
*/
export function addNode<T extends Node>(to: T[], from: OneOrMany<T>, startOnNewLine?: boolean) {
export function addNode<T extends Node>(to: T[], from: VisitResult<T>, startOnNewLine?: boolean): void {
addNodeWorker(to, from, startOnNewLine, /*test*/ undefined, /*parenthesize*/ undefined, /*parentNode*/ undefined, /*isVisiting*/ false);
}
@ -693,18 +674,21 @@ namespace ts {
* @param to The destination NodeArray.
* @param from The source array of Node or NodeArrayNode.
*/
export function addNodes<T extends Node>(to: T[], from: OneOrMany<T>[], startOnNewLine?: boolean) {
export function addNodes<T extends Node>(to: T[], from: VisitResult<T>[], startOnNewLine?: boolean): void {
addNodesWorker(to, from, startOnNewLine, /*test*/ undefined, /*parenthesize*/ undefined, /*parentNode*/ undefined, /*isVisiting*/ false);
}
function addNodeWorker(to: Node[], from: OneOrMany<Node>, startOnNewLine: boolean, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, isVisiting: boolean) {
function addNodeWorker(to: Node[], from: VisitResult<Node>, startOnNewLine: boolean, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, isVisiting: boolean): void {
if (to && from) {
if (isArray(from)) {
addNodesWorker(to, from, startOnNewLine, test, parenthesize, parentNode, isVisiting);
}
else {
const node = parenthesize !== undefined ? parenthesize(from, parentNode) : from;
Debug.assert(test === undefined || test(node), "Wrong node type after visit.", () => `Node ${formatSyntaxKind(node.kind)} did not pass test ${(<any>test).name}.`);
const node = parenthesize !== undefined
? parenthesize(from, parentNode)
: from;
Debug.assertNode(node, test);
if (startOnNewLine) {
node.startsOnNewLine = true;
@ -719,7 +703,7 @@ namespace ts {
}
}
function addNodesWorker(to: Node[], from: OneOrMany<Node>[], startOnNewLine: boolean, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, isVisiting: boolean) {
function addNodesWorker(to: Node[], from: VisitResult<Node>[], startOnNewLine: boolean, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, isVisiting: boolean): void {
if (to && from) {
for (const node of from) {
addNodeWorker(to, node, startOnNewLine, test, parenthesize, parentNode, isVisiting);
@ -760,7 +744,7 @@ namespace ts {
* @param node The SourceFile node.
* @param declarations The generated lexical declarations.
*/
export function mergeSourceFileLexicalEnvironment(node: SourceFile, declarations: Statement[]) {
export function mergeSourceFileLexicalEnvironment(node: SourceFile, declarations: Statement[]): SourceFile {
if (declarations !== undefined && declarations.length) {
const mutableNode = getMutableClone(node);
mutableNode.statements = mergeStatements(mutableNode.statements, declarations);
@ -776,7 +760,7 @@ namespace ts {
* @param node The ModuleDeclaration node.
* @param declarations The generated lexical declarations.
*/
export function mergeModuleDeclarationLexicalEnvironment(node: ModuleDeclaration, declarations: Statement[]) {
export function mergeModuleDeclarationLexicalEnvironment(node: ModuleDeclaration, declarations: Statement[]): ModuleDeclaration {
Debug.assert(node.body.kind === SyntaxKind.ModuleBlock);
if (declarations !== undefined && declarations.length) {
const mutableNode = getMutableClone(node);
@ -793,7 +777,7 @@ namespace ts {
* @param node The function-like node.
* @param declarations The generated lexical declarations.
*/
function mergeFunctionLikeLexicalEnvironment(node: FunctionLikeDeclaration, declarations: Statement[]) {
function mergeFunctionLikeLexicalEnvironment(node: FunctionLikeDeclaration, declarations: Statement[]): FunctionLikeDeclaration {
Debug.assert(node.body !== undefined);
if (declarations !== undefined && declarations.length) {
const mutableNode = getMutableClone(node);
@ -810,7 +794,7 @@ namespace ts {
* @param node The ConciseBody of an arrow function.
* @param declarations The lexical declarations to merge.
*/
export function mergeFunctionBodyLexicalEnvironment(body: FunctionBody, declarations: Statement[]) {
export function mergeFunctionBodyLexicalEnvironment(body: FunctionBody, declarations: Statement[]): FunctionBody {
if (declarations !== undefined && declarations.length > 0) {
return mergeBlockLexicalEnvironment(body, declarations);
}
@ -824,7 +808,7 @@ namespace ts {
* @param node The ConciseBody of an arrow function.
* @param declarations The lexical declarations to merge.
*/
export function mergeConciseBodyLexicalEnvironment(body: ConciseBody, declarations: Statement[]) {
export function mergeConciseBodyLexicalEnvironment(body: ConciseBody, declarations: Statement[]): ConciseBody {
if (declarations !== undefined && declarations.length > 0) {
if (isBlock(body)) {
return mergeBlockLexicalEnvironment(body, declarations);
@ -846,7 +830,7 @@ namespace ts {
* @param node The block into which to merge lexical declarations.
* @param declarations The lexical declarations to merge.
*/
function mergeBlockLexicalEnvironment<T extends Block>(node: T, declarations: Statement[]) {
function mergeBlockLexicalEnvironment<T extends Block>(node: T, declarations: Statement[]): T {
const mutableNode = getMutableClone(node);
mutableNode.statements = mergeStatements(node.statements, declarations);
return mutableNode;
@ -858,7 +842,7 @@ namespace ts {
* @param statements The node array to concatentate with the supplied lexical declarations.
* @param declarations The lexical declarations to merge.
*/
function mergeStatements(statements: NodeArray<Statement>, declarations: Statement[]) {
function mergeStatements(statements: NodeArray<Statement>, declarations: Statement[]): NodeArray<Statement> {
return createNodeArray(concatenate(statements, declarations), /*location*/ statements);
}
@ -867,7 +851,7 @@ namespace ts {
*
* @param nodes The NodeArray.
*/
export function liftToBlock(nodes: NodeArray<Node>) {
export function liftToBlock(nodes: Node[]): Block {
Debug.assert(every(nodes, isStatement), "Cannot lift nodes to a Block.");
return createBlock(<NodeArray<Statement>>nodes);
}
@ -877,9 +861,9 @@ namespace ts {
*
* @param nodes The NodeArray.
*/
function extractSingleNode(nodes: NodeArray<Node>) {
function extractSingleNode(nodes: Node[]): Node {
Debug.assert(nodes.length <= 1, "Too many nodes written to output.");
return nodes.length > 0 ? nodes[0] : undefined;
return singleOrUndefined(nodes);
}
/**
@ -916,11 +900,11 @@ namespace ts {
// We do not transform ambient declarations or types, so there is no need to
// recursively aggregate transform flags.
if (hasModifier(node, ModifierFlags.Ambient) || isTypeNode(node)) {
return <TransformFlags>0;
return TransformFlags.None;
}
// Aggregate the transform flags of each child.
return reduceEachChild<TransformFlags>(node, aggregateTransformFlagsForChildNode, 0);
return reduceEachChild(node, aggregateTransformFlagsForChildNode, TransformFlags.None);
}
/**
@ -930,4 +914,43 @@ namespace ts {
function aggregateTransformFlagsForChildNode(transformFlags: TransformFlags, child: Node): TransformFlags {
return transformFlags | aggregateTransformFlagsForNode(child);
}
export namespace Debug {
export function failNotOptional(message?: string) {
if (shouldAssert(AssertionLevel.Normal)) {
Debug.assert(false, message || "Node not optional.");
}
}
export function failBadSyntaxKind(node: Node, message?: string) {
if (shouldAssert(AssertionLevel.Normal)) {
Debug.assert(false,
message || "Unexpected node.",
() => `Node ${formatSyntaxKind(node.kind)} was unexpected.`);
}
}
export function assertNode<T extends Node>(node: Node, test: (node: Node) => boolean, message?: string): void {
if (shouldAssert(AssertionLevel.Normal)) {
Debug.assert(
test === undefined || test(node),
message || "Unexpected node.",
() => `Node ${formatSyntaxKind(node.kind)} did not pass test '${getFunctionName(test)}'.`);
};
}
function getFunctionName(func: Function) {
if (typeof func !== "function") {
return "";
}
else if (func.hasOwnProperty("name")) {
return (<any>func).name;
}
else {
const text = Function.prototype.toString.call(func);
const match = /^function\s+([\w\$]+)\s*\(/.exec(text);
return match ? match[1] : "";
}
}
}
}