Merge branch 'transforms-visitor' into transforms-flags
This commit is contained in:
commit
ab8e83e930
6 changed files with 152 additions and 61 deletions
|
@ -130,11 +130,12 @@ namespace ts {
|
|||
return -1;
|
||||
}
|
||||
|
||||
export function countWhere<T>(array: T[], predicate: (x: T) => boolean): number {
|
||||
export function countWhere<T>(array: T[], predicate: (x: T, i: number) => boolean): number {
|
||||
let count = 0;
|
||||
if (array) {
|
||||
for (const v of array) {
|
||||
if (predicate(v)) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const v = array[i];
|
||||
if (predicate(v, i)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
@ -142,25 +143,49 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps an array. If the mapped value is an array, it is spread into the result.
|
||||
*/
|
||||
export function flatMap<T, U>(array: T[], f: (x: T, i: number) => U | 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) {
|
||||
// We cast to <U> here to leverage the behavior of Array#concat
|
||||
// which will append a single value here.
|
||||
result = result.concat(<U[]>ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -170,7 +195,7 @@ namespace ts {
|
|||
if (!array2 || !array2.length) return array1;
|
||||
if (!array1 || !array1.length) return array2;
|
||||
|
||||
return array1.concat(array2);
|
||||
return [...array1, ...array2];
|
||||
}
|
||||
|
||||
export function deduplicate<T>(array: T[]): T[] {
|
||||
|
@ -186,6 +211,27 @@ namespace ts {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compacts an array, removing any falsey elements.
|
||||
*/
|
||||
export function compact<T>(array: T[]): T[] {
|
||||
let result: T[];
|
||||
if (array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const v = array[i];
|
||||
if (result || !v) {
|
||||
if (!result) {
|
||||
result = array.slice(0, i);
|
||||
}
|
||||
if (v) {
|
||||
result.push(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result || array;
|
||||
}
|
||||
|
||||
export function sum(array: any[], prop: string): number {
|
||||
let result = 0;
|
||||
for (const v of array) {
|
||||
|
@ -212,15 +258,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -252,9 +308,9 @@ namespace ts {
|
|||
return ~low;
|
||||
}
|
||||
|
||||
export function reduceLeft<T, U>(array: T[], f: (memo: U, value: T) => U, initial: U): U;
|
||||
export function reduceLeft<T>(array: T[], f: (memo: T, value: T) => T): T;
|
||||
export function reduceLeft<T>(array: T[], f: (memo: T, value: T) => T, initial?: T): T {
|
||||
export function reduceLeft<T, U>(array: T[], f: (memo: U, value: T, i: number) => U, initial: U): U;
|
||||
export function reduceLeft<T>(array: T[], f: (memo: T, value: T, i: number) => T): T;
|
||||
export function reduceLeft<T>(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T): T {
|
||||
if (array) {
|
||||
const count = array.length;
|
||||
if (count > 0) {
|
||||
|
@ -268,7 +324,7 @@ namespace ts {
|
|||
result = initial;
|
||||
}
|
||||
while (pos < count) {
|
||||
result = f(result, array[pos]);
|
||||
result = f(result, array[pos], pos);
|
||||
pos++;
|
||||
}
|
||||
return result;
|
||||
|
@ -277,9 +333,9 @@ namespace ts {
|
|||
return initial;
|
||||
}
|
||||
|
||||
export function reduceRight<T, U>(array: T[], f: (memo: U, value: T) => U, initial: U): U;
|
||||
export function reduceRight<T>(array: T[], f: (memo: T, value: T) => T): T;
|
||||
export function reduceRight<T>(array: T[], f: (memo: T, value: T) => T, initial?: T): T {
|
||||
export function reduceRight<T, U>(array: T[], f: (memo: U, value: T, i: number) => U, initial: U): U;
|
||||
export function reduceRight<T>(array: T[], f: (memo: T, value: T, i: number) => T): T;
|
||||
export function reduceRight<T>(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T): T {
|
||||
if (array) {
|
||||
let pos = array.length - 1;
|
||||
if (pos >= 0) {
|
||||
|
@ -292,7 +348,7 @@ namespace ts {
|
|||
result = initial;
|
||||
}
|
||||
while (pos >= 0) {
|
||||
result = f(result, array[pos]);
|
||||
result = f(result, array[pos], pos);
|
||||
pos--;
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -2728,7 +2728,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||
}
|
||||
|
||||
function synthesizedNodeStartsOnNewLine(node: Node) {
|
||||
return nodeIsSynthesized(node) && (<SynthesizedNode>node).startsOnNewLine;
|
||||
return nodeIsSynthesized(node) && node.startsOnNewLine;
|
||||
}
|
||||
|
||||
function emitConditionalExpression(node: ConditionalExpression) {
|
||||
|
|
|
@ -22,8 +22,8 @@ namespace ts {
|
|||
return node;
|
||||
}
|
||||
|
||||
export function createNodeArray<T extends Node>(elements?: T[], location?: TextRange): NodeArray<T> {
|
||||
if (elements !== undefined) {
|
||||
export function createNodeArray<T extends Node>(elements?: T[], location?: TextRange, hasTrailingComma?: boolean): NodeArray<T> {
|
||||
if (elements) {
|
||||
if (isNodeArray(elements)) {
|
||||
return elements;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
const array = <NodeArray<T>>elements;
|
||||
if (location !== undefined) {
|
||||
if (location) {
|
||||
array.pos = location.pos;
|
||||
array.end = location.end;
|
||||
}
|
||||
|
@ -42,13 +42,17 @@ namespace ts {
|
|||
array.end = -1;
|
||||
}
|
||||
|
||||
if (hasTrailingComma) {
|
||||
array.hasTrailingComma = true;
|
||||
}
|
||||
|
||||
array.arrayKind = ArrayKind.NodeArray;
|
||||
return array;
|
||||
}
|
||||
|
||||
export function createModifiersArray(elements?: Modifier[], location?: TextRange): ModifiersArray {
|
||||
let flags: NodeFlags;
|
||||
if (elements !== undefined) {
|
||||
if (elements) {
|
||||
if (isModifiersArray(elements)) {
|
||||
return elements;
|
||||
}
|
||||
|
@ -64,7 +68,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
const array = <ModifiersArray>elements;
|
||||
if (location !== undefined) {
|
||||
if (location) {
|
||||
array.pos = location.pos;
|
||||
array.end = location.end;
|
||||
}
|
||||
|
@ -79,7 +83,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
export function setModifiers<T extends Node>(node: T, modifiers: Modifier[]) {
|
||||
if (modifiers !== undefined) {
|
||||
if (modifiers) {
|
||||
const array = createModifiersArray(modifiers);
|
||||
node.modifiers = array;
|
||||
node.flags |= array.flags;
|
||||
|
@ -92,7 +96,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
export function createSynthesizedNode(kind: SyntaxKind, startsOnNewLine?: boolean): Node {
|
||||
const node = <SynthesizedNode>createNode(kind, /*location*/ undefined);
|
||||
const node = createNode(kind, /*location*/ undefined);
|
||||
node.startsOnNewLine = startsOnNewLine;
|
||||
return node;
|
||||
}
|
||||
|
@ -145,6 +149,15 @@ namespace ts {
|
|||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shallow, memberwise clone of a node for mutation.
|
||||
*
|
||||
* @param node The node to clone.
|
||||
*/
|
||||
export function getMutableNode<T extends Node>(node: T): T {
|
||||
return cloneNode<T>(node, node, node.flags, node.parent, node);
|
||||
}
|
||||
|
||||
export function createNodeArrayNode<T extends Node>(elements: T[]): NodeArrayNode<T> {
|
||||
const node = <NodeArrayNode<T>>createSynthesizedNode(SyntaxKind.NodeArrayNode);
|
||||
node.nodes = createNodeArray(elements);
|
||||
|
|
|
@ -449,6 +449,7 @@ namespace ts {
|
|||
/* @internal */ id?: number; // Unique id (used to look up NodeLinks)
|
||||
parent?: Node; // Parent node (initialized by binding)
|
||||
/* @internal */ original?: Node; // The original node if this is an updated node.
|
||||
/* @internal */ startsOnNewLine?: boolean; // Whether a synthesized node should start on a new line (used by transforms).
|
||||
/* @internal */ jsDocComment?: JSDocComment; // JSDoc for the node, if it has any. Only for .js files.
|
||||
/* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding)
|
||||
/* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding)
|
||||
|
|
|
@ -8,12 +8,6 @@ namespace ts {
|
|||
isNoDefaultLib?: boolean;
|
||||
}
|
||||
|
||||
export interface SynthesizedNode extends Node {
|
||||
leadingCommentRanges?: CommentRange[];
|
||||
trailingCommentRanges?: CommentRange[];
|
||||
startsOnNewLine: boolean;
|
||||
}
|
||||
|
||||
export function getDeclarationOfKind(symbol: Symbol, kind: SyntaxKind): Declaration {
|
||||
const declarations = symbol.declarations;
|
||||
if (declarations) {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export type OneOrMore<T extends Node> = T | NodeArrayNode<T>;
|
||||
export type OneOrMany<T extends Node> = T | NodeArrayNode<T>;
|
||||
|
||||
/**
|
||||
* Describes an edge of a Node, used when traversing a syntax tree.
|
||||
|
@ -529,7 +529,7 @@ namespace ts {
|
|||
// Visit each original node.
|
||||
for (let i = 0; i < count; i++) {
|
||||
const node = nodes[i + start];
|
||||
const visited = node && <OneOrMore<T>>visitor(node);
|
||||
const visited = node && <OneOrMany<T>>visitor(node);
|
||||
if (updated !== undefined || visited === undefined || visited !== node) {
|
||||
if (updated === undefined) {
|
||||
// Ensure we have a copy of `nodes`, up to the current index.
|
||||
|
@ -540,14 +540,14 @@ namespace ts {
|
|||
aggregateTransformFlags(visited);
|
||||
}
|
||||
|
||||
addNode(updated, visited, test);
|
||||
addNodeWorker(updated, visited, /*addOnNewLine*/ undefined, test);
|
||||
}
|
||||
}
|
||||
|
||||
if (updated !== undefined) {
|
||||
return <TArray>(isModifiersArray(nodes)
|
||||
? createModifiersArray(updated, nodes)
|
||||
: createNodeArray(updated, nodes));
|
||||
: createNodeArray(updated, nodes, nodes.hasTrailingComma));
|
||||
}
|
||||
|
||||
return nodes;
|
||||
|
@ -576,21 +576,28 @@ namespace ts {
|
|||
|
||||
const edgeTraversalPath = nodeEdgeTraversalMap[node.kind];
|
||||
if (edgeTraversalPath) {
|
||||
let modifiers: NodeFlags;
|
||||
for (const edge of edgeTraversalPath) {
|
||||
const value = <Node | NodeArray<Node>>node[edge.name];
|
||||
if (value !== undefined) {
|
||||
const visited = visitEdge(edge, value, visitor);
|
||||
if (visited && isArray(visited) && isModifiersArray(visited)) {
|
||||
modifiers = visited.flags;
|
||||
}
|
||||
|
||||
if (updated !== undefined || visited !== value) {
|
||||
if (updated === undefined) {
|
||||
updated = cloneNode(node, /*location*/ node, node.flags & ~NodeFlags.Modifier, /*parent*/ undefined, /*original*/ node);
|
||||
updated = getMutableNode(node);
|
||||
updated.flags &= ~NodeFlags.Modifier;
|
||||
}
|
||||
|
||||
if (visited && isArray(visited) && isModifiersArray(visited)) {
|
||||
updated[edge.name] = visited;
|
||||
updated.flags |= visited.flags;
|
||||
if (modifiers) {
|
||||
updated.flags |= modifiers;
|
||||
modifiers = undefined;
|
||||
}
|
||||
else {
|
||||
updated[edge.name] = visited;
|
||||
|
||||
if (visited !== value) {
|
||||
setEdgeValue(updated, edge, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -610,11 +617,19 @@ namespace ts {
|
|||
|
||||
if (updated !== node) {
|
||||
aggregateTransformFlags(updated);
|
||||
updated.original = node;
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of an edge, adjusting the value as necessary for cases such as expression precedence.
|
||||
*/
|
||||
function setEdgeValue(parentNode: Node & Map<any>, edge: NodeEdge, value: Node | NodeArray<Node>) {
|
||||
parentNode[edge.name] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a node edge.
|
||||
*
|
||||
|
@ -635,16 +650,8 @@ namespace ts {
|
|||
* @param from The source Node or NodeArrayNode.
|
||||
* @param test The node test used to validate each node.
|
||||
*/
|
||||
export function addNode<T extends Node>(to: T[], from: OneOrMore<T>, test?: (node: Node) => boolean) {
|
||||
if (to !== undefined && from !== undefined) {
|
||||
if (isNodeArrayNode(from)) {
|
||||
addNodes(to, from.nodes, test);
|
||||
}
|
||||
else {
|
||||
Debug.assert(test === undefined || test(from), "Wrong node type after visit.");
|
||||
to.push(from);
|
||||
}
|
||||
}
|
||||
export function addNode<T extends Node>(to: T[], from: OneOrMany<T>, startOnNewLine?: boolean) {
|
||||
addNodeWorker(to, from, startOnNewLine, /*test*/ undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -654,10 +661,30 @@ namespace ts {
|
|||
* @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 !== undefined && from !== undefined) {
|
||||
export function addNodes<T extends Node>(to: T[], from: OneOrMany<T>[], startOnNewLine?: boolean) {
|
||||
addNodesWorker(to, from, startOnNewLine, /*test*/ undefined);
|
||||
}
|
||||
|
||||
function addNodeWorker<T extends Node>(to: T[], from: OneOrMany<T>, startOnNewLine: boolean, test: (node: Node) => boolean) {
|
||||
if (to && from) {
|
||||
if (isNodeArrayNode(from)) {
|
||||
addNodesWorker(to, from.nodes, startOnNewLine, test);
|
||||
}
|
||||
else {
|
||||
Debug.assert(test === undefined || test(from), "Wrong node type after visit.");
|
||||
if (startOnNewLine) {
|
||||
from.startsOnNewLine = true;
|
||||
}
|
||||
|
||||
to.push(from);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addNodesWorker<T extends Node>(to: T[], from: OneOrMany<T>[], startOnNewLine: boolean, test: (node: Node) => boolean) {
|
||||
if (to && from) {
|
||||
for (const node of from) {
|
||||
addNode(to, node, test);
|
||||
addNodeWorker(to, node, startOnNewLine, test);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue