Merged some changes from other branches.

This commit is contained in:
Ron Buckton 2016-02-22 15:15:09 -08:00
parent 387b30c296
commit ad64877dee
6 changed files with 155 additions and 61 deletions

View file

@ -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;

View file

@ -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) {

View file

@ -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);

View file

@ -447,6 +447,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)

View file

@ -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) {

View file

@ -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.
@ -528,21 +528,21 @@ 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.
updated = nodes.slice(0, i);
}
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;
@ -571,21 +571,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);
}
}
}
@ -603,9 +610,20 @@ namespace ts {
}
}
if (updated !== node) {
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.
*
@ -626,16 +644,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);
}
/**
@ -645,10 +655,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);
}
}
}