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

This commit complements the support for the `__spreadArray` helper that
was added in microsoft/TypeScript#41523. The prior helpers `__spread`
and `__spreadArrays` used the `__read` helper internally, but the helper
is now emitted as an argument to `__spreadArray` so ngcc now needs to
support evaluating it statically. The real implementation of `__read`
reads an iterable into an array, but for ngcc's static evaluation
support it is sufficient to only deal with arrays as is. Additionally,
the optional `n` parameter is not supported as that is only emitted for
array destructuring syntax, which ngcc does not have to support.

PR Close #41201
This commit is contained in:
JoostK 2021-03-14 14:53:18 +01:00 committed by Jessica Janiuk
parent 7b1214eca2
commit 66e9970691
8 changed files with 148 additions and 2 deletions

View File

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

View File

@ -2000,11 +2000,13 @@ exports.MissingClass2 = MissingClass2;
function __spread(...args) { /* ... */ }
function __spreadArrays(...args) { /* ... */ }
function __spreadArray(to, from) { /* ... */ }
function __read(o) { /* ... */ }
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']);
var e = __read(['foo', 'bar']);
`,
};
loadTestFiles([file]);
@ -2021,6 +2023,7 @@ exports.MissingClass2 = MissingClass2;
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read', KnownDeclaration.TsHelperRead);
});
it('should recognize suffixed TypeScript helpers (as function declarations)', () => {
@ -2031,11 +2034,13 @@ exports.MissingClass2 = MissingClass2;
function __spread$2(...args) { /* ... */ }
function __spreadArrays$3(...args) { /* ... */ }
function __spreadArray$3(to, from) { /* ... */ }
function __read$3(o) { /* ... */ }
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']);
var e = __read$3(['foo', 'bar']);
`,
};
loadTestFiles([file]);
@ -2052,6 +2057,7 @@ exports.MissingClass2 = MissingClass2;
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read$3', KnownDeclaration.TsHelperRead);
});
it('should recognize TypeScript helpers (as variable declarations)', () => {
@ -2062,11 +2068,13 @@ exports.MissingClass2 = MissingClass2;
var __spread = (this && this.__spread) || function (...args) { /* ... */ }
var __spreadArrays = (this && this.__spreadArrays) || function (...args) { /* ... */ }
var __spreadArray = (this && this.__spreadArray) || function (to, from) { /* ... */ }
var __read = (this && this.__read) || function (o) { /* ... */ }
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']);
var e = __read(['foo', 'bar']);
`,
};
loadTestFiles([file]);
@ -2083,6 +2091,7 @@ exports.MissingClass2 = MissingClass2;
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read', KnownDeclaration.TsHelperRead);
});
it('should recognize suffixed TypeScript helpers (as variable declarations)', () => {
@ -2093,11 +2102,13 @@ exports.MissingClass2 = MissingClass2;
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 __read$3 = (this && this.__read$3) || function (o) { /* ... */ }
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']);
var e = __read$3(['foo', 'bar']);
`,
};
loadTestFiles([file]);
@ -2114,6 +2125,7 @@ exports.MissingClass2 = MissingClass2;
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read$3', KnownDeclaration.TsHelperRead);
});
it('should recognize imported TypeScript helpers', () => {
@ -2127,6 +2139,7 @@ exports.MissingClass2 = MissingClass2;
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']);
var e = tslib_1.__read(['foo', 'bar']);
`,
},
{
@ -2136,6 +2149,7 @@ exports.MissingClass2 = MissingClass2;
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 __read(o: any, n?: number): any[];
`,
},
];
@ -2155,6 +2169,7 @@ exports.MissingClass2 = MissingClass2;
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread, 'tslib');
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays, 'tslib');
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray, 'tslib');
testForHelper('e', '__read', KnownDeclaration.TsHelperRead, 'tslib');
});
it('should recognize undeclared, unimported TypeScript helpers (by name)', () => {
@ -2165,6 +2180,7 @@ exports.MissingClass2 = MissingClass2;
var b = __spread(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray(['foo', 'bar'], ['baz', 'qux']);
var e = __read(['foo', 'bar']);
`,
};
loadTestFiles([file]);
@ -2191,6 +2207,7 @@ exports.MissingClass2 = MissingClass2;
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read', KnownDeclaration.TsHelperRead);
});
it('should recognize suffixed, undeclared, unimported TypeScript helpers (by name)', () => {
@ -2201,6 +2218,7 @@ exports.MissingClass2 = MissingClass2;
var b = __spread$2(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray$3(['foo', 'bar'], ['baz', 'qux']);
var e = __read$3(['foo', 'bar']);
`,
};
loadTestFiles([file]);
@ -2227,6 +2245,7 @@ exports.MissingClass2 = MissingClass2;
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read$3', KnownDeclaration.TsHelperRead);
});
it('should recognize enum declarations with string values', () => {
@ -2461,6 +2480,7 @@ exports.MissingClass2 = MissingClass2;
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 __read(o: any, n?: number): any[];
export declare function __unknownHelper(...args: any[]): any;
`,
};
@ -2477,6 +2497,7 @@ exports.MissingClass2 = MissingClass2;
['__spread', KnownDeclaration.TsHelperSpread],
['__spreadArrays', KnownDeclaration.TsHelperSpreadArrays],
['__spreadArray', KnownDeclaration.TsHelperSpreadArray],
['__read', KnownDeclaration.TsHelperRead],
['__unknownHelper', null],
]);
});

View File

@ -2060,11 +2060,13 @@ runInEachFileSystem(() => {
function __spread(...args) { /* ... */ }
function __spreadArrays(...args) { /* ... */ }
function __spreadArray(to, from) { /* ... */ }
function __read(o) { /* ... */ }
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']);
var e = __read(['foo', 'bar']);
`,
};
loadTestFiles([file]);
@ -2080,6 +2082,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read', KnownDeclaration.TsHelperRead);
});
it('should recognize suffixed TypeScript helpers (as function declarations)', () => {
@ -2090,11 +2093,13 @@ runInEachFileSystem(() => {
function __spread$2(...args) { /* ... */ }
function __spreadArrays$3(...args) { /* ... */ }
function __spreadArray$3(to, from) { /* ... */ }
function __read$3(o) { /* ... */ }
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']);
var e = __read$3(['foo', 'bar']);
`,
};
loadTestFiles([file]);
@ -2110,6 +2115,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read$3', KnownDeclaration.TsHelperRead);
});
it('should recognize TypeScript helpers (as variable declarations)', () => {
@ -2120,11 +2126,13 @@ runInEachFileSystem(() => {
var __spread = (this && this.__spread) || function (...args) { /* ... */ }
var __spreadArrays = (this && this.__spreadArrays) || function (...args) { /* ... */ }
var __spreadArray = (this && this.__spreadArray) || function (to, from) { /* ... */ }
var __read = (this && this._read) || function (o) { /* ... */ }
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']);
var e = __read(['foo', 'bar']);
`,
};
loadTestFiles([file]);
@ -2140,6 +2148,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read', KnownDeclaration.TsHelperRead);
});
it('should recognize suffixed TypeScript helpers (as variable declarations)', () => {
@ -2150,11 +2159,13 @@ runInEachFileSystem(() => {
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 __read$3 = (this && this.__read$3) || function (o) { /* ... */ }
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']);
var e = __read$3(['foo', 'bar']);
`,
};
loadTestFiles([file]);
@ -2170,6 +2181,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read$3', KnownDeclaration.TsHelperRead);
});
it('should recognize imported TypeScript helpers (named imports)', () => {
@ -2177,12 +2189,13 @@ runInEachFileSystem(() => {
{
name: _('/test.js'),
contents: `
import {__assign, __spread, __spreadArrays, __spreadArray} from 'tslib';
import {__assign, __spread, __spreadArrays, __spreadArray, __read} 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']);
var e = __read(['foo', 'bar']);
`,
},
{
@ -2192,6 +2205,7 @@ runInEachFileSystem(() => {
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 __read(o: any, n?: number): any[];
`,
},
];
@ -2210,6 +2224,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread, 'tslib');
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays, 'tslib');
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray, 'tslib');
testForHelper('e', '__read', KnownDeclaration.TsHelperRead, 'tslib');
});
it('should recognize imported TypeScript helpers (star import)', () => {
@ -2223,6 +2238,7 @@ runInEachFileSystem(() => {
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']);
var e = tslib_1.__read(['foo', 'bar']);
`,
},
{
@ -2232,6 +2248,7 @@ runInEachFileSystem(() => {
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 __read(o: any, n?: number): any[];
`,
},
];
@ -2250,6 +2267,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread, 'tslib');
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays, 'tslib');
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray, 'tslib');
testForHelper('e', '__read', KnownDeclaration.TsHelperRead, 'tslib');
});
it('should recognize undeclared, unimported TypeScript helpers (by name)', () => {
@ -2260,6 +2278,7 @@ runInEachFileSystem(() => {
var b = __spread(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray(['foo', 'bar'], ['baz', 'qux']);
var e = __read(['foo', 'bar']);
`,
};
loadTestFiles([file]);
@ -2283,6 +2302,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read', KnownDeclaration.TsHelperRead);
});
it('should recognize suffixed, undeclared, unimported TypeScript helpers (by name)', () => {
@ -2293,6 +2313,7 @@ runInEachFileSystem(() => {
var b = __spread$2(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray$3(['foo', 'bar'], ['baz', 'qux']);
var e = __read$3(['foo', 'bar']);
`,
};
loadTestFiles([file]);
@ -2316,6 +2337,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read', KnownDeclaration.TsHelperRead);
});
it('should recognize enum declarations with string values', () => {
@ -2479,6 +2501,7 @@ runInEachFileSystem(() => {
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 __read(o: any, n?: number): any[];
export declare function __unknownHelper(...args: any[]): any;
`,
};
@ -2494,6 +2517,7 @@ runInEachFileSystem(() => {
['__spread', KnownDeclaration.TsHelperSpread],
['__spreadArrays', KnownDeclaration.TsHelperSpreadArrays],
['__spreadArray', KnownDeclaration.TsHelperSpreadArray],
['__read', KnownDeclaration.TsHelperRead],
['__unknownHelper', null],
]);
});

View File

@ -2332,11 +2332,13 @@ runInEachFileSystem(() => {
function __spread(...args) { /* ... */ }
function __spreadArrays(...args) { /* ... */ }
function __spreadArray(to, from) { /* ... */ }
function __read(o) { /* ... */ }
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']);
var e = __read(['foo', 'bar']);
})));
`,
};
@ -2352,6 +2354,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read', KnownDeclaration.TsHelperRead);
});
it('should recognize suffixed TypeScript helpers (as function declarations)', () => {
@ -2367,11 +2370,13 @@ runInEachFileSystem(() => {
function __spread$2(...args) { /* ... */ }
function __spreadArrays$3(...args) { /* ... */ }
function __spreadArray$3(to, from) { /* ... */ }
function __read$3(o) { /* ... */ }
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']);
var e = __read$3(['foo', 'bar']);
})));
`,
};
@ -2387,6 +2392,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read$3', KnownDeclaration.TsHelperRead);
});
it('should recognize TypeScript helpers (as variable declarations)', () => {
@ -2402,11 +2408,13 @@ runInEachFileSystem(() => {
var __spread = (this && this.__spread) || function (...args) { /* ... */ }
var __spreadArrays = (this && this.__spreadArrays) || function (...args) { /* ... */ }
var __spreadArray = (this && this.__spreadArray) || function (to, from) { /* ... */ }
var __read = (this && this.__read) || function (o) { /* ... */ }
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']);
var e = __read(['foo', 'bar']);
})));
`,
};
@ -2422,6 +2430,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read', KnownDeclaration.TsHelperRead);
});
it('should recognize suffixed TypeScript helpers (as variable declarations)', () => {
@ -2437,11 +2446,13 @@ runInEachFileSystem(() => {
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 __read$3 = (this && this.__read$3) || function (o) { /* ... */ }
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']);
var e = __read$3(['foo', 'bar']);
})));
`,
};
@ -2457,6 +2468,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read$3', KnownDeclaration.TsHelperRead);
});
it('should recognize imported TypeScript helpers', () => {
@ -2473,6 +2485,7 @@ runInEachFileSystem(() => {
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']);
var e = tslib_1.__read(['foo', 'bar']);
})));
`,
},
@ -2483,6 +2496,7 @@ runInEachFileSystem(() => {
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 __read(o: any, n?: number): any[];
`,
},
];
@ -2502,6 +2516,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread, 'tslib');
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays, 'tslib');
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray, 'tslib');
testForHelper('e', '__read', KnownDeclaration.TsHelperRead, 'tslib');
});
it('should recognize undeclared, unimported TypeScript helpers (by name)', () => {
@ -2517,6 +2532,7 @@ runInEachFileSystem(() => {
var b = __spread(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray(['foo', 'bar'], ['baz', 'qux']);
var e = __read(['foo', 'bar']);
})));
`,
};
@ -2544,6 +2560,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read', KnownDeclaration.TsHelperRead);
});
it('should recognize suffixed, undeclared, unimported TypeScript helpers (by name)', () => {
@ -2559,6 +2576,7 @@ runInEachFileSystem(() => {
var b = __spread$2(['foo', 'bar'], ['baz', 'qux']);
var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']);
var d = __spreadArray$3(['foo', 'bar'], ['baz', 'qux']);
var e = __read$3(['foo', 'bar']);
})));
`,
};
@ -2586,6 +2604,7 @@ runInEachFileSystem(() => {
testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread);
testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays);
testForHelper('d', '__spreadArray$3', KnownDeclaration.TsHelperSpreadArray);
testForHelper('e', '__read$3', KnownDeclaration.TsHelperRead);
});
it('should recognize enum declarations with string values', () => {
@ -2861,6 +2880,7 @@ runInEachFileSystem(() => {
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 __read(o: any, n?: number): any[];
export declare function __unknownHelper(...args: any[]): any;
`,
};
@ -2876,6 +2896,7 @@ runInEachFileSystem(() => {
['__spread', KnownDeclaration.TsHelperSpread],
['__spreadArrays', KnownDeclaration.TsHelperSpreadArrays],
['__spreadArray', KnownDeclaration.TsHelperSpreadArray],
['__read', KnownDeclaration.TsHelperRead],
['__unknownHelper', null],
]);
});

View File

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

View File

@ -59,3 +59,24 @@ export class SpreadArrayHelperFn extends KnownFn {
return to.concat(from);
}
}
// Used for `__read` TypeScript helper function.
export class ReadHelperFn extends KnownFn {
evaluate(node: ts.Node, args: ResolvedValueArray): ResolvedValue {
if (args.length !== 1) {
// The `__read` helper accepts a second argument `n` but that case is not supported.
return DynamicValue.fromUnknown(node);
}
const [value] = args;
if (value instanceof DynamicValue) {
return DynamicValue.fromDynamicInput(node, value);
}
if (!Array.isArray(value)) {
return DynamicValue.fromInvalidExpressionType(node, value);
}
return value;
}
}

View File

@ -647,6 +647,7 @@ runInEachFileSystem(() => {
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 __read(o: any, n?: number): any[];
`,
},
]);
@ -758,6 +759,28 @@ runInEachFileSystem(() => {
expect(arr).toEqual([4, 5, 6]);
});
it('should evaluate `__read()` (named import)', () => {
const arr: number[] = evaluateExpression(
`
import {__read} from 'tslib';
const a = [5, 6];
`,
'__read(a)');
expect(arr).toEqual([5, 6]);
});
it('should evaluate `__read()` (star import)', () => {
const arr: number[] = evaluateExpression(
`
import * as tslib from 'tslib';
const a = [5, 6];
`,
'tslib.__read(a)');
expect(arr).toEqual([5, 6]);
});
});
describe('(with emitted TypeScript helpers as functions)', () => {
@ -768,6 +791,7 @@ runInEachFileSystem(() => {
function __spread(...args) { /* ... */ }
function __spreadArrays(...args) { /* ... */ }
function __spreadArray(to, from) { /* ... */ }
function __read(o) { /* ... */ }
`;
const {checker, expression} = makeExpression(helpers + code, expr);
@ -823,6 +847,16 @@ runInEachFileSystem(() => {
expect(arr).toEqual([4, 5, 6]);
});
it('should evaluate `__read()`', () => {
const arr: number[] = evaluateExpression(
`
const a = [5, 6];
`,
'__read(a)');
expect(arr).toEqual([5, 6]);
});
});
describe('(with emitted TypeScript helpers as variables)', () => {
@ -833,6 +867,7 @@ runInEachFileSystem(() => {
var __spread = (this && this.__spread) || function (...args) { /* ... */ }
var __spreadArrays = (this && this.__spreadArrays) || function (...args) { /* ... */ }
var __spreadArray = (this && this.__spreadArray) || function (to, from) { /* ... */ }
var __read = (this && this.__read) || function (o) { /* ... */ }
`;
const {checker, expression} = makeExpression(helpers + code, expr);
@ -888,6 +923,16 @@ runInEachFileSystem(() => {
expect(arr).toEqual([4, 5, 6]);
});
it('should evaluate `__read()`', () => {
const arr: number[] = evaluateExpression(
`
const a = [5, 6];
`,
'__read(a)');
expect(arr).toEqual([5, 6]);
});
});
describe('(visited file tracking)', () => {
@ -1031,6 +1076,8 @@ runInEachFileSystem(() => {
return KnownDeclaration.TsHelperSpreadArrays;
case '__spreadArray':
return KnownDeclaration.TsHelperSpreadArray;
case '__read':
return KnownDeclaration.TsHelperRead;
default:
return null;
}

View File

@ -479,6 +479,11 @@ export enum KnownDeclaration {
* Indicates the `__spreadArray` TypeScript helper function.
*/
TsHelperSpreadArray,
/**
* Indicates the `__read` TypeScript helper function.
*/
TsHelperRead,
}
/**