feat(ngcc): support `__spreadArray` helper as used by TypeScript 4.2 (#41201)

In TypeScript 4.2 the `__spread` and `__spreadArrays` helpers were both
replaced by the new helper function `__spreadArray` in
microsoft/TypeScript#41523. These helpers may be used in downleveled
JavaScript bundles that ngcc has to process, so ngcc has the ability to
statically detect these helpers and provide evaluation logic for them.
Because Angular is adopting support for TypeScript 4.2 it becomes
possible for libraries to be compiled by TypeScript 4.2 and thus ngcc
has to add support for the `__spreadArray` helper. The deprecated
`__spread` and `__spreadArrays` helpers are not affected by this change.

Closes #40394

PR Close #41201
This commit is contained in:
JoostK 2021-03-14 00:36:34 +01:00 committed by Jessica Janiuk
parent 6bdad5ef6c
commit 7b1214eca2
9 changed files with 181 additions and 4 deletions

View File

@ -161,6 +161,8 @@ export function getTsHelperFnFromIdentifier(id: ts.Identifier): KnownDeclaration
return KnownDeclaration.TsHelperSpread;
case '__spreadArrays':
return KnownDeclaration.TsHelperSpreadArrays;
case '__spreadArray':
return KnownDeclaration.TsHelperSpreadArray;
default:
return null;
}

View File

@ -1999,10 +1999,12 @@ exports.MissingClass2 = MissingClass2;
function __assign(t, ...sources) { /* ... */ }
function __spread(...args) { /* ... */ }
function __spreadArrays(...args) { /* ... */ }
function __spreadArray(to, from) { /* ... */ }
var a = __assign({foo: 'bar'}, {baz: 'qux'});
var b = __spread(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray(['foo', 'bar'], ['baz', 'qux']);
`,
};
loadTestFiles([file]);
@ -2018,6 +2020,7 @@ exports.MissingClass2 = MissingClass2;
testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize suffixed TypeScript helpers (as function declarations)', () => {
@ -2027,10 +2030,12 @@ exports.MissingClass2 = MissingClass2;
function __assign$1(t, ...sources) { /* ... */ }
function __spread$2(...args) { /* ... */ }
function __spreadArrays$3(...args) { /* ... */ }
function __spreadArray$3(to, from) { /* ... */ }
var a = __assign$1({foo: 'bar'}, {baz: 'qux'});
var b = __spread$2(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray$3(['foo', 'bar'], ['baz', 'qux']);
`,
};
loadTestFiles([file]);
@ -2046,6 +2051,7 @@ exports.MissingClass2 = MissingClass2;
testForHelper('a', '__assign$1', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize TypeScript helpers (as variable declarations)', () => {
@ -2055,10 +2061,12 @@ exports.MissingClass2 = MissingClass2;
var __assign = (this && this.__assign) || function (t, ...sources) { /* ... */ }
var __spread = (this && this.__spread) || function (...args) { /* ... */ }
var __spreadArrays = (this && this.__spreadArrays) || function (...args) { /* ... */ }
var __spreadArray = (this && this.__spreadArray) || function (to, from) { /* ... */ }
var a = __assign({foo: 'bar'}, {baz: 'qux'});
var b = __spread(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray(['foo', 'bar'], ['baz', 'qux']);
`,
};
loadTestFiles([file]);
@ -2074,6 +2082,7 @@ exports.MissingClass2 = MissingClass2;
testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize suffixed TypeScript helpers (as variable declarations)', () => {
@ -2083,10 +2092,12 @@ exports.MissingClass2 = MissingClass2;
var __assign$1 = (this && this.__assign$1) || function (t, ...sources) { /* ... */ }
var __spread$2 = (this && this.__spread$2) || function (...args) { /* ... */ }
var __spreadArrays$3 = (this && this.__spreadArrays$3) || function (...args) { /* ... */ }
var __spreadArray$3 = (this && this.__spreadArray$3) || function (to, from) { /* ... */ }
var a = __assign$1({foo: 'bar'}, {baz: 'qux'});
var b = __spread$2(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray$3(['foo', 'bar'], ['baz', 'qux']);
`,
};
loadTestFiles([file]);
@ -2102,6 +2113,7 @@ exports.MissingClass2 = MissingClass2;
testForHelper('a', '__assign$1', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize imported TypeScript helpers', () => {
@ -2114,6 +2126,7 @@ exports.MissingClass2 = MissingClass2;
var a = tslib_1.__assign({foo: 'bar'}, {baz: 'qux'});
var b = tslib_1.__spread(['foo', 'bar'], ['baz', 'qux']);
var c = tslib_1.__spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = tslib_1.__spreadArray(['foo', 'bar'], ['baz', 'qux']);
`,
},
{
@ -2122,6 +2135,7 @@ exports.MissingClass2 = MissingClass2;
export declare function __assign(t: any, ...sources: any[]): any;
export declare function __spread(...args: any[][]): any[];
export declare function __spreadArrays(...args: any[][]): any[];
export declare function __spreadArray(to: any[], from: any[]): any[];
`,
},
];
@ -2140,6 +2154,7 @@ exports.MissingClass2 = MissingClass2;
testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign, 'tslib');
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread, 'tslib');
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays, 'tslib');
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray, 'tslib');
});
it('should recognize undeclared, unimported TypeScript helpers (by name)', () => {
@ -2149,6 +2164,7 @@ exports.MissingClass2 = MissingClass2;
var a = __assign({foo: 'bar'}, {baz: 'qux'});
var b = __spread(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray(['foo', 'bar'], ['baz', 'qux']);
`,
};
loadTestFiles([file]);
@ -2174,6 +2190,7 @@ exports.MissingClass2 = MissingClass2;
testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize suffixed, undeclared, unimported TypeScript helpers (by name)', () => {
@ -2183,6 +2200,7 @@ exports.MissingClass2 = MissingClass2;
var a = __assign$1({foo: 'bar'}, {baz: 'qux'});
var b = __spread$2(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray$3(['foo', 'bar'], ['baz', 'qux']);
`,
};
loadTestFiles([file]);
@ -2208,6 +2226,7 @@ exports.MissingClass2 = MissingClass2;
testForHelper('a', '__assign$1', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize enum declarations with string values', () => {
@ -2441,6 +2460,7 @@ exports.MissingClass2 = MissingClass2;
export declare function __assign(t: any, ...sources: any[]): any;
export declare function __spread(...args: any[][]): any[];
export declare function __spreadArrays(...args: any[][]): any[];
export declare function __spreadArray(to: any[], from: any[]): any[];
export declare function __unknownHelper(...args: any[]): any;
`,
};
@ -2456,6 +2476,7 @@ exports.MissingClass2 = MissingClass2;
['__assign', KnownDeclaration.TsHelperAssign],
['__spread', KnownDeclaration.TsHelperSpread],
['__spreadArrays', KnownDeclaration.TsHelperSpreadArrays],
['__spreadArray', KnownDeclaration.TsHelperSpreadArray],
['__unknownHelper', null],
]);
});

View File

@ -2059,10 +2059,12 @@ runInEachFileSystem(() => {
function __assign(t, ...sources) { /* ... */ }
function __spread(...args) { /* ... */ }
function __spreadArrays(...args) { /* ... */ }
function __spreadArray(to, from) { /* ... */ }
var a = __assign({foo: 'bar'}, {baz: 'qux'});
var b = __spread(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray(['foo', 'bar'], ['baz', 'qux']);
`,
};
loadTestFiles([file]);
@ -2077,6 +2079,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize suffixed TypeScript helpers (as function declarations)', () => {
@ -2086,10 +2089,12 @@ runInEachFileSystem(() => {
function __assign$1(t, ...sources) { /* ... */ }
function __spread$2(...args) { /* ... */ }
function __spreadArrays$3(...args) { /* ... */ }
function __spreadArray$3(to, from) { /* ... */ }
var a = __assign$1({foo: 'bar'}, {baz: 'qux'});
var b = __spread$2(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray$3(['foo', 'bar'], ['baz', 'qux']);
`,
};
loadTestFiles([file]);
@ -2104,6 +2109,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign$1', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize TypeScript helpers (as variable declarations)', () => {
@ -2113,11 +2119,13 @@ runInEachFileSystem(() => {
var __assign = (this && this.__assign) || function (t, ...sources) { /* ... */ }
var __spread = (this && this.__spread) || function (...args) { /* ... */ }
var __spreadArrays = (this && this.__spreadArrays) || function (...args) { /* ... */ }
var __spreadArray = (this && this.__spreadArray) || function (to, from) { /* ... */ }
var a = __assign({foo: 'bar'}, {baz: 'qux'});
var b = __spread(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']);
`,
var d = __spreadArray(['foo', 'bar'], ['baz', 'qux']);
`,
};
loadTestFiles([file]);
const bundle = makeTestBundleProgram(file.name);
@ -2131,6 +2139,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize suffixed TypeScript helpers (as variable declarations)', () => {
@ -2140,10 +2149,12 @@ runInEachFileSystem(() => {
var __assign$1 = (this && this.__assign$1) || function (t, ...sources) { /* ... */ }
var __spread$2 = (this && this.__spread$2) || function (...args) { /* ... */ }
var __spreadArrays$3 = (this && this.__spreadArrays$3) || function (...args) { /* ... */ }
var __spreadArray$3 = (this && this.__spreadArray$3) || function (to, from) { /* ... */ }
var a = __assign$1({foo: 'bar'}, {baz: 'qux'});
var b = __spread$2(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray$3(['foo', 'bar'], ['baz', 'qux']);
`,
};
loadTestFiles([file]);
@ -2158,6 +2169,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign$1', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize imported TypeScript helpers (named imports)', () => {
@ -2165,11 +2177,12 @@ runInEachFileSystem(() => {
{
name: _('/test.js'),
contents: `
import {__assign, __spread, __spreadArrays} from 'tslib';
import {__assign, __spread, __spreadArrays, __spreadArray} from 'tslib';
var a = __assign({foo: 'bar'}, {baz: 'qux'});
var b = __spread(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray(['foo', 'bar'], ['baz', 'qux']);
`,
},
{
@ -2178,6 +2191,7 @@ runInEachFileSystem(() => {
export declare function __assign(t: any, ...sources: any[]): any;
export declare function __spread(...args: any[][]): any[];
export declare function __spreadArrays(...args: any[][]): any[];
export declare function __spreadArray(to: any[], from: any[]): any[];
`,
},
];
@ -2195,6 +2209,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign, 'tslib');
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread, 'tslib');
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays, 'tslib');
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray, 'tslib');
});
it('should recognize imported TypeScript helpers (star import)', () => {
@ -2207,6 +2222,7 @@ runInEachFileSystem(() => {
var a = tslib_1.__assign({foo: 'bar'}, {baz: 'qux'});
var b = tslib_1.__spread(['foo', 'bar'], ['baz', 'qux']);
var c = tslib_1.__spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = tslib_1.__spreadArray(['foo', 'bar'], ['baz', 'qux']);
`,
},
{
@ -2215,6 +2231,7 @@ runInEachFileSystem(() => {
export declare function __assign(t: any, ...sources: any[]): any;
export declare function __spread(...args: any[][]): any[];
export declare function __spreadArrays(...args: any[][]): any[];
export declare function __spreadArray(to: any[], from: any[]): any[];
`,
},
];
@ -2232,6 +2249,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign, 'tslib');
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread, 'tslib');
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays, 'tslib');
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray, 'tslib');
});
it('should recognize undeclared, unimported TypeScript helpers (by name)', () => {
@ -2241,6 +2259,7 @@ runInEachFileSystem(() => {
var a = __assign({foo: 'bar'}, {baz: 'qux'});
var b = __spread(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray(['foo', 'bar'], ['baz', 'qux']);
`,
};
loadTestFiles([file]);
@ -2263,6 +2282,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize suffixed, undeclared, unimported TypeScript helpers (by name)', () => {
@ -2272,6 +2292,7 @@ runInEachFileSystem(() => {
var a = __assign$1({foo: 'bar'}, {baz: 'qux'});
var b = __spread$2(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray$3(['foo', 'bar'], ['baz', 'qux']);
`,
};
loadTestFiles([file]);
@ -2294,6 +2315,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign$1', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize enum declarations with string values', () => {
@ -2456,6 +2478,7 @@ runInEachFileSystem(() => {
export declare function __assign(t: any, ...sources: any[]): any;
export declare function __spread(...args: any[][]): any[];
export declare function __spreadArrays(...args: any[][]): any[];
export declare function __spreadArray(to: any[], from: any[]): any[];
export declare function __unknownHelper(...args: any[]): any;
`,
};
@ -2470,6 +2493,7 @@ runInEachFileSystem(() => {
['__assign', KnownDeclaration.TsHelperAssign],
['__spread', KnownDeclaration.TsHelperSpread],
['__spreadArrays', KnownDeclaration.TsHelperSpreadArrays],
['__spreadArray', KnownDeclaration.TsHelperSpreadArray],
['__unknownHelper', null],
]);
});

View File

@ -2331,10 +2331,12 @@ runInEachFileSystem(() => {
function __assign(t, ...sources) { /* ... */ }
function __spread(...args) { /* ... */ }
function __spreadArrays(...args) { /* ... */ }
function __spreadArray(to, from) { /* ... */ }
var a = __assign({foo: 'bar'}, {baz: 'qux'});
var b = __spread(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray(['foo', 'bar'], ['baz', 'qux']);
})));
`,
};
@ -2349,6 +2351,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize suffixed TypeScript helpers (as function declarations)', () => {
@ -2363,10 +2366,12 @@ runInEachFileSystem(() => {
function __assign$1(t, ...sources) { /* ... */ }
function __spread$2(...args) { /* ... */ }
function __spreadArrays$3(...args) { /* ... */ }
function __spreadArray$3(to, from) { /* ... */ }
var a = __assign$1({foo: 'bar'}, {baz: 'qux'});
var b = __spread$2(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray$3(['foo', 'bar'], ['baz', 'qux']);
})));
`,
};
@ -2381,6 +2386,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign$1', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize TypeScript helpers (as variable declarations)', () => {
@ -2395,10 +2401,12 @@ runInEachFileSystem(() => {
var __assign = (this && this.__assign) || function (t, ...sources) { /* ... */ }
var __spread = (this && this.__spread) || function (...args) { /* ... */ }
var __spreadArrays = (this && this.__spreadArrays) || function (...args) { /* ... */ }
var __spreadArray = (this && this.__spreadArray) || function (to, from) { /* ... */ }
var a = __assign({foo: 'bar'}, {baz: 'qux'});
var b = __spread(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray(['foo', 'bar'], ['baz', 'qux']);
})));
`,
};
@ -2413,6 +2421,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize suffixed TypeScript helpers (as variable declarations)', () => {
@ -2427,10 +2436,12 @@ runInEachFileSystem(() => {
var __assign$1 = (this && this.__assign$1) || function (t, ...sources) { /* ... */ }
var __spread$2 = (this && this.__spread$2) || function (...args) { /* ... */ }
var __spreadArrays$3 = (this && this.__spreadArrays$3) || function (...args) { /* ... */ }
var __spreadArray$3 = (this && this.__spreadArray$3) || function (to, from) { /* ... */ }
var a = __assign$1({foo: 'bar'}, {baz: 'qux'});
var b = __spread$2(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray$3(['foo', 'bar'], ['baz', 'qux']);
})));
`,
};
@ -2445,6 +2456,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign$1', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize imported TypeScript helpers', () => {
@ -2460,6 +2472,7 @@ runInEachFileSystem(() => {
var a = tslib_1.__assign({foo: 'bar'}, {baz: 'qux'});
var b = tslib_1.__spread(['foo', 'bar'], ['baz', 'qux']);
var c = tslib_1.__spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = tslib_1.__spreadArray(['foo', 'bar'], ['baz', 'qux']);
})));
`,
},
@ -2469,6 +2482,7 @@ runInEachFileSystem(() => {
export declare function __assign(t: any, ...sources: any[]): any;
export declare function __spread(...args: any[][]): any[];
export declare function __spreadArrays(...args: any[][]): any[];
export declare function __spreadArray(to: any[], from: any[]): any[];
`,
},
];
@ -2487,6 +2501,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign, 'tslib');
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread, 'tslib');
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays, 'tslib');
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray, 'tslib');
});
it('should recognize undeclared, unimported TypeScript helpers (by name)', () => {
@ -2501,6 +2516,7 @@ runInEachFileSystem(() => {
var a = __assign({foo: 'bar'}, {baz: 'qux'});
var b = __spread(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray(['foo', 'bar'], ['baz', 'qux']);
})));
`,
};
@ -2527,6 +2543,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize suffixed, undeclared, unimported TypeScript helpers (by name)', () => {
@ -2541,6 +2558,7 @@ runInEachFileSystem(() => {
var a = __assign$1({foo: 'bar'}, {baz: 'qux'});
var b = __spread$2(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray$3(['foo', 'bar'], ['baz', 'qux']);
})));
`,
};
@ -2567,6 +2585,7 @@ runInEachFileSystem(() => {
testForHelper('a', '__assign$1', KnownDeclaration.TsHelperAssign);
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize enum declarations with string values', () => {
@ -2841,6 +2860,7 @@ runInEachFileSystem(() => {
export declare function __assign(t: any, ...sources: any[]): any;
export declare function __spread(...args: any[][]): any[];
export declare function __spreadArrays(...args: any[][]): any[];
export declare function __spreadArray(to: any[], from: any[]): any[];
export declare function __unknownHelper(...args: any[]): any;
`,
};
@ -2855,6 +2875,7 @@ runInEachFileSystem(() => {
['__assign', KnownDeclaration.TsHelperAssign],
['__spread', KnownDeclaration.TsHelperSpread],
['__spreadArrays', KnownDeclaration.TsHelperSpreadArrays],
['__spreadArray', KnownDeclaration.TsHelperSpreadArray],
['__unknownHelper', null],
]);
});

View File

@ -108,6 +108,22 @@ describe('getTsHelperFnFromDeclaration()', () => {
expect(getTsHelperFnFromDeclaration(decl2)).toBe(KnownDeclaration.TsHelperSpreadArrays);
});
it('should recognize the `__spreadArray` helper as function declaration', () => {
const decl1 = createFunctionDeclaration('__spreadArray');
const decl2 = createFunctionDeclaration('__spreadArray$42');
expect(getTsHelperFnFromDeclaration(decl1)).toBe(KnownDeclaration.TsHelperSpreadArray);
expect(getTsHelperFnFromDeclaration(decl2)).toBe(KnownDeclaration.TsHelperSpreadArray);
});
it('should recognize the `__spreadArray` helper as variable declaration', () => {
const decl1 = createVariableDeclaration('__spreadArray');
const decl2 = createVariableDeclaration('__spreadArray$42');
expect(getTsHelperFnFromDeclaration(decl1)).toBe(KnownDeclaration.TsHelperSpreadArray);
expect(getTsHelperFnFromDeclaration(decl2)).toBe(KnownDeclaration.TsHelperSpreadArray);
});
it('should return null for unrecognized helpers', () => {
const decl1 = createFunctionDeclaration('__foo');
const decl2 = createVariableDeclaration('spread');
@ -158,6 +174,14 @@ describe('getTsHelperFnFromIdentifier()', () => {
expect(getTsHelperFnFromIdentifier(id2)).toBe(KnownDeclaration.TsHelperSpreadArrays);
});
it('should recognize the `__spreadArray` helper', () => {
const id1 = ts.createIdentifier('__spreadArray');
const id2 = ts.createIdentifier('__spreadArray$42');
expect(getTsHelperFnFromIdentifier(id1)).toBe(KnownDeclaration.TsHelperSpreadArray);
expect(getTsHelperFnFromIdentifier(id2)).toBe(KnownDeclaration.TsHelperSpreadArray);
});
it('should return null for unrecognized helpers', () => {
const id1 = ts.createIdentifier('__foo');
const id2 = ts.createIdentifier('spread');

View File

@ -10,7 +10,7 @@ import {KnownDeclaration} from '../../reflection/src/host';
import {ObjectAssignBuiltinFn} from './builtin';
import {ResolvedValue} from './result';
import {AssignHelperFn, SpreadHelperFn} from './ts_helpers';
import {AssignHelperFn, SpreadArrayHelperFn, SpreadHelperFn} from './ts_helpers';
/** Resolved value for the JavaScript global `Object` declaration. */
export const jsGlobalObjectValue = new Map([['assign', new ObjectAssignBuiltinFn()]]);
@ -21,6 +21,9 @@ const assignTsHelperFn = new AssignHelperFn();
/** Resolved value for the `__spread()` and `__spreadArrays()` TypeScript helper declarations. */
const spreadTsHelperFn = new SpreadHelperFn();
/** Resolved value for the `__spreadArray()` TypeScript helper declarations. */
const spreadArrayTsHelperFn = new SpreadArrayHelperFn();
/**
* Resolves the specified known declaration to a resolved value. For example,
* the known JavaScript global `Object` will resolve to a `Map` that provides the
@ -35,6 +38,8 @@ export function resolveKnownDeclaration(decl: KnownDeclaration): ResolvedValue {
case KnownDeclaration.TsHelperSpread:
case KnownDeclaration.TsHelperSpreadArrays:
return spreadTsHelperFn;
case KnownDeclaration.TsHelperSpreadArray:
return spreadArrayTsHelperFn;
default:
throw new Error(`Cannot resolve known declaration. Received: ${KnownDeclaration[decl]}.`);
}

View File

@ -10,7 +10,7 @@ import * as ts from 'typescript';
import {ObjectAssignBuiltinFn} from './builtin';
import {DynamicValue} from './dynamic';
import {KnownFn, ResolvedValueArray} from './result';
import {KnownFn, ResolvedValue, ResolvedValueArray} from './result';
// Use the same implementation we use for `Object.assign()`. Semantically these functions are the
@ -35,3 +35,27 @@ export class SpreadHelperFn extends KnownFn {
return result;
}
}
// Used for `__spreadArray` TypeScript helper function.
export class SpreadArrayHelperFn extends KnownFn {
evaluate(node: ts.Node, args: ResolvedValueArray): ResolvedValue {
if (args.length !== 2) {
return DynamicValue.fromUnknown(node);
}
const [to, from] = args;
if (to instanceof DynamicValue) {
return DynamicValue.fromDynamicInput(node, to);
} else if (from instanceof DynamicValue) {
return DynamicValue.fromDynamicInput(node, from);
}
if (!Array.isArray(to)) {
return DynamicValue.fromInvalidExpressionType(node, to);
} else if (!Array.isArray(from)) {
return DynamicValue.fromInvalidExpressionType(node, from);
}
return to.concat(from);
}
}

View File

@ -646,6 +646,7 @@ runInEachFileSystem(() => {
export declare function __assign(t: any, ...sources: any[]): any;
export declare function __spread(...args: any[][]): any[];
export declare function __spreadArrays(...args: any[][]): any[];
export declare function __spreadArray(to: any[], from: any[]): any[];
`,
},
]);
@ -733,6 +734,30 @@ runInEachFileSystem(() => {
expect(arr).toEqual([4, 5, 6]);
});
it('should evaluate `__spreadArray()` (named import)', () => {
const arr: number[] = evaluateExpression(
`
import {__spreadArray} from 'tslib';
const a = [4];
const b = [5, 6];
`,
'__spreadArray(a, b)');
expect(arr).toEqual([4, 5, 6]);
});
it('should evaluate `__spreadArray()` (star import)', () => {
const arr: number[] = evaluateExpression(
`
import * as tslib from 'tslib';
const a = [4];
const b = [5, 6];
`,
'tslib.__spreadArray(a, b)');
expect(arr).toEqual([4, 5, 6]);
});
});
describe('(with emitted TypeScript helpers as functions)', () => {
@ -742,6 +767,7 @@ runInEachFileSystem(() => {
function __assign(t, ...sources) { /* ... */ }
function __spread(...args) { /* ... */ }
function __spreadArrays(...args) { /* ... */ }
function __spreadArray(to, from) { /* ... */ }
`;
const {checker, expression} = makeExpression(helpers + code, expr);
@ -786,6 +812,17 @@ runInEachFileSystem(() => {
expect(arr).toEqual([4, 5, 6]);
});
it('should evaluate `__spreadArray()`', () => {
const arr: number[] = evaluateExpression(
`
const a = [4];
const b = [5, 6];
`,
'__spreadArray(a, b)');
expect(arr).toEqual([4, 5, 6]);
});
});
describe('(with emitted TypeScript helpers as variables)', () => {
@ -795,6 +832,7 @@ runInEachFileSystem(() => {
var __assign = (this && this.__assign) || function (t, ...sources) { /* ... */ }
var __spread = (this && this.__spread) || function (...args) { /* ... */ }
var __spreadArrays = (this && this.__spreadArrays) || function (...args) { /* ... */ }
var __spreadArray = (this && this.__spreadArray) || function (to, from) { /* ... */ }
`;
const {checker, expression} = makeExpression(helpers + code, expr);
@ -839,6 +877,17 @@ runInEachFileSystem(() => {
expect(arr).toEqual([4, 5, 6]);
});
it('should evaluate `__spreadArray()`', () => {
const arr: number[] = evaluateExpression(
`
const a = [4];
const b = [5, 6];
`,
'__spreadArray(a, b)');
expect(arr).toEqual([4, 5, 6]);
});
});
describe('(visited file tracking)', () => {
@ -980,6 +1029,8 @@ runInEachFileSystem(() => {
return KnownDeclaration.TsHelperSpread;
case '__spreadArrays':
return KnownDeclaration.TsHelperSpreadArrays;
case '__spreadArray':
return KnownDeclaration.TsHelperSpreadArray;
default:
return null;
}

View File

@ -474,6 +474,11 @@ export enum KnownDeclaration {
* Indicates the `__spreadArrays` TypeScript helper function.
*/
TsHelperSpreadArrays,
/**
* Indicates the `__spreadArray` TypeScript helper function.
*/
TsHelperSpreadArray,
}
/**