fix(ngcc): correctly detect emitted TS helpers in ES5 (#35191)
In ES5 code, TypeScript requires certain helpers (such as `__spreadArrays()`) to be able to support ES2015+ features. These helpers can be either imported from `tslib` (by setting the `importHelpers` TS compiler option to `true`) or emitted inline (by setting the `importHelpers` and `noEmitHelpers` TS compiler options to `false`, which is the default value for both). Ngtsc's `StaticInterpreter` (which is also used during ngcc processing) is able to statically evaluate some of these helpers (currently `__assign()`, `__spread()` and `__spreadArrays()`), as long as `ReflectionHost#getDefinitionOfFunction()` correctly detects the declaration of the helper. For this to happen, the left-hand side of the corresponding call expression (i.e. `__spread(...)` or `tslib.__spread(...)`) must be evaluated as a function declaration for `getDefinitionOfFunction()` to be called with. In the case of imported helpers, the `tslib.__someHelper` expression was resolved to a function declaration of the form `export declare function __someHelper(...args: any[][]): any[];`, which allows `getDefinitionOfFunction()` to correctly map it to a TS helper. In contrast, in the case of emitted helpers (and regardless of the module format: `CommonJS`, `ESNext`, `UMD`, etc.)), the `__someHelper` identifier was resolved to a variable declaration of the form `var __someHelper = (this && this.__someHelper) || function () { ... }`, which upon further evaluation was categorized as a `DynamicValue` (prohibiting further evaluation by the `getDefinitionOfFunction()`). As a result of the above, emitted TypeScript helpers were not evaluated in ES5 code. --- This commit changes the detection of TS helpers to leverage the existing `KnownFn` feature (previously only used for built-in functions). `Esm5ReflectionHost` is changed to always return `KnownDeclaration`s for TS helpers, both imported (`getExportsOfModule()`) as well as emitted (`getDeclarationOfIdentifier()`). Similar changes are made to `CommonJsReflectionHost` and `UmdReflectionHost`. The `KnownDeclaration`s are then mapped to `KnownFn`s in `StaticInterpreter`, allowing it to statically evaluate call expressions involving any kind of TS helpers. Jira issue: https://angular-team.atlassian.net/browse/FW-1689 PR Close #35191
This commit is contained in:

committed by
Miško Hevery

parent
14744f27c5
commit
bd6a39c364
@ -19,7 +19,6 @@ import {DynamicValue} from './dynamic';
|
||||
import {ForeignFunctionResolver} from './interface';
|
||||
import {resolveKnownDeclaration} from './known_declaration';
|
||||
import {EnumValue, KnownFn, ResolvedModule, ResolvedValue, ResolvedValueArray, ResolvedValueMap} from './result';
|
||||
import {evaluateTsHelperInline} from './ts_helpers';
|
||||
|
||||
|
||||
|
||||
@ -333,6 +332,10 @@ export class StaticInterpreter {
|
||||
}
|
||||
|
||||
return new ResolvedModule(declarations, decl => {
|
||||
if (decl.known !== null) {
|
||||
return resolveKnownDeclaration(decl.known);
|
||||
}
|
||||
|
||||
const declContext = {
|
||||
...context, ...joinModuleContext(context, node, decl),
|
||||
};
|
||||
@ -417,12 +420,6 @@ export class StaticInterpreter {
|
||||
return DynamicValue.fromInvalidExpressionType(node.expression, lhs);
|
||||
}
|
||||
|
||||
// If the function corresponds with a tslib helper function, evaluate it with custom logic.
|
||||
if (fn.helper !== null) {
|
||||
const args = this.evaluateFunctionArguments(node, context);
|
||||
return evaluateTsHelperInline(fn.helper, node, args);
|
||||
}
|
||||
|
||||
if (!isFunctionOrMethodReference(lhs)) {
|
||||
return DynamicValue.fromInvalidExpressionType(node.expression, lhs);
|
||||
}
|
||||
|
@ -10,19 +10,31 @@ import {KnownDeclaration} from '../../reflection/src/host';
|
||||
|
||||
import {ObjectAssignBuiltinFn} from './builtin';
|
||||
import {ResolvedValue} from './result';
|
||||
import {AssignHelperFn, SpreadHelperFn} from './ts_helpers';
|
||||
|
||||
/** Resolved value for the JavaScript global `Object` declaration .*/
|
||||
/** Resolved value for the JavaScript global `Object` declaration. */
|
||||
export const jsGlobalObjectValue = new Map([['assign', new ObjectAssignBuiltinFn()]]);
|
||||
|
||||
/** Resolved value for the `__assign()` TypeScript helper declaration. */
|
||||
const assignTsHelperFn = new AssignHelperFn();
|
||||
|
||||
/** Resolved value for the `__spread()` and `__spreadArrays()` TypeScript helper declarations. */
|
||||
const spreadTsHelperFn = new SpreadHelperFn();
|
||||
|
||||
/**
|
||||
* Resolves the specified known declaration to a resolved value. For example,
|
||||
* the known JavaScript global `Object` will resolve to a `Map` that provides the
|
||||
* `assign` method with a builtin function. This enables evaluation of `Object.assign`.
|
||||
* `assign` method with a built-in function. This enables evaluation of `Object.assign`.
|
||||
*/
|
||||
export function resolveKnownDeclaration(decl: KnownDeclaration): ResolvedValue {
|
||||
switch (decl) {
|
||||
case KnownDeclaration.JsGlobalObject:
|
||||
return jsGlobalObjectValue;
|
||||
case KnownDeclaration.TsHelperAssign:
|
||||
return assignTsHelperFn;
|
||||
case KnownDeclaration.TsHelperSpread:
|
||||
case KnownDeclaration.TsHelperSpreadArrays:
|
||||
return spreadTsHelperFn;
|
||||
default:
|
||||
throw new Error(`Cannot resolve known declaration. Received: ${KnownDeclaration[decl]}.`);
|
||||
}
|
||||
|
@ -8,44 +8,30 @@
|
||||
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {TsHelperFn} from '../../reflection';
|
||||
|
||||
import {ObjectAssignBuiltinFn} from './builtin';
|
||||
import {DynamicValue} from './dynamic';
|
||||
import {ResolvedValue, ResolvedValueArray} from './result';
|
||||
import {KnownFn, ResolvedValueArray} from './result';
|
||||
|
||||
|
||||
/**
|
||||
* Instance of the known `Object.assign` built-in function. Used for evaluating
|
||||
* the `__assign` TypeScript helper.
|
||||
*/
|
||||
const objectAssignBuiltinFn = new ObjectAssignBuiltinFn();
|
||||
// Use the same implementation we use for `Object.assign()`. Semantically these functions are the
|
||||
// same, so they can also share the same evaluation code.
|
||||
export class AssignHelperFn extends ObjectAssignBuiltinFn {}
|
||||
|
||||
export function evaluateTsHelperInline(
|
||||
helper: TsHelperFn, node: ts.CallExpression, args: ResolvedValueArray): ResolvedValue {
|
||||
switch (helper) {
|
||||
case TsHelperFn.Assign:
|
||||
// Use the same implementation we use for `Object.assign`. Semantically these
|
||||
// functions are the same, so they can also share the same evaluation code.
|
||||
return objectAssignBuiltinFn.evaluate(node, args);
|
||||
case TsHelperFn.Spread:
|
||||
case TsHelperFn.SpreadArrays:
|
||||
return evaluateTsSpreadHelper(node, args);
|
||||
default:
|
||||
throw new Error(`Cannot evaluate TypeScript helper function: ${TsHelperFn[helper]}`);
|
||||
}
|
||||
}
|
||||
// Used for both `__spread()` and `__spreadArrays()` TypeScript helper functions.
|
||||
export class SpreadHelperFn extends KnownFn {
|
||||
evaluate(node: ts.Node, args: ResolvedValueArray): ResolvedValueArray {
|
||||
const result: ResolvedValueArray = [];
|
||||
|
||||
function evaluateTsSpreadHelper(node: ts.Node, args: ResolvedValueArray): ResolvedValueArray {
|
||||
const result: ResolvedValueArray = [];
|
||||
for (const arg of args) {
|
||||
if (arg instanceof DynamicValue) {
|
||||
result.push(DynamicValue.fromDynamicInput(node, arg));
|
||||
} else if (Array.isArray(arg)) {
|
||||
result.push(...arg);
|
||||
} else {
|
||||
result.push(arg);
|
||||
for (const arg of args) {
|
||||
if (arg instanceof DynamicValue) {
|
||||
result.push(DynamicValue.fromDynamicInput(node, arg));
|
||||
} else if (Array.isArray(arg)) {
|
||||
result.push(...arg);
|
||||
} else {
|
||||
result.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -11,11 +11,11 @@ import {absoluteFrom, getSourceFileOrError} from '../../file_system';
|
||||
import {runInEachFileSystem} from '../../file_system/testing';
|
||||
import {Reference} from '../../imports';
|
||||
import {DependencyTracker} from '../../incremental/api';
|
||||
import {FunctionDefinition, TsHelperFn, TypeScriptReflectionHost} from '../../reflection';
|
||||
import {Declaration, KnownDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
||||
import {getDeclaration, makeProgram} from '../../testing';
|
||||
import {DynamicValue} from '../src/dynamic';
|
||||
import {PartialEvaluator} from '../src/interface';
|
||||
import {EnumValue} from '../src/result';
|
||||
import {EnumValue, ResolvedValue} from '../src/result';
|
||||
|
||||
import {evaluate, firstArgFfr, makeEvaluator, makeExpression, owningModuleOf} from './utils';
|
||||
|
||||
@ -538,69 +538,209 @@ runInEachFileSystem(() => {
|
||||
expect((value.node as ts.CallExpression).expression.getText()).toBe('foo');
|
||||
});
|
||||
|
||||
it('should evaluate TypeScript __spread helper', () => {
|
||||
const {checker, expression} = makeExpression(
|
||||
`
|
||||
import * as tslib from 'tslib';
|
||||
const a = [1];
|
||||
const b = [2, 3];
|
||||
`,
|
||||
'tslib.__spread(a, b)', [
|
||||
{
|
||||
name: _('/node_modules/tslib/index.d.ts'),
|
||||
contents: `
|
||||
export declare function __spread(...args: any[][]): any[];
|
||||
`
|
||||
},
|
||||
]);
|
||||
const reflectionHost = new TsLibAwareReflectionHost(checker);
|
||||
const evaluator = new PartialEvaluator(reflectionHost, checker, null);
|
||||
const value = evaluator.evaluate(expression);
|
||||
expect(value).toEqual([1, 2, 3]);
|
||||
describe('(with imported TypeScript helpers)', () => {
|
||||
// Helpers
|
||||
const evaluateExpression = <T extends ResolvedValue>(code: string, expr: string) => {
|
||||
const {checker, expression} = makeExpression(code, expr, [
|
||||
{
|
||||
name: _('/node_modules/tslib/index.d.ts'),
|
||||
contents: `
|
||||
export declare function __assign(t: any, ...sources: any[]): any;
|
||||
export declare function __spread(...args: any[][]): any[];
|
||||
export declare function __spreadArrays(...args: any[][]): any[];
|
||||
`,
|
||||
},
|
||||
]);
|
||||
|
||||
const reflectionHost = new TsLibAwareReflectionHost(checker);
|
||||
const evaluator = new PartialEvaluator(reflectionHost, checker, null);
|
||||
|
||||
return evaluator.evaluate(expression) as T;
|
||||
};
|
||||
|
||||
it('should evaluate `__assign()` (named import)', () => {
|
||||
const map: Map<string, boolean> = evaluateExpression(
|
||||
`
|
||||
import {__assign} from 'tslib';
|
||||
const a = {a: true};
|
||||
const b = {b: true};
|
||||
`,
|
||||
'__assign(a, b)');
|
||||
|
||||
expect([...map]).toEqual([
|
||||
['a', true],
|
||||
['b', true],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should evaluate `__assign()` (star import)', () => {
|
||||
const map: Map<string, boolean> = evaluateExpression(
|
||||
`
|
||||
import * as tslib from 'tslib';
|
||||
const a = {a: true};
|
||||
const b = {b: true};
|
||||
`,
|
||||
'tslib.__assign(a, b)');
|
||||
|
||||
expect([...map]).toEqual([
|
||||
['a', true],
|
||||
['b', true],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should evaluate `__spread()` (named import)', () => {
|
||||
const arr: number[] = evaluateExpression(
|
||||
`
|
||||
import {__spread} from 'tslib';
|
||||
const a = [1];
|
||||
const b = [2, 3];
|
||||
`,
|
||||
'__spread(a, b)');
|
||||
|
||||
expect(arr).toEqual([1, 2, 3]);
|
||||
});
|
||||
|
||||
it('should evaluate `__spread()` (star import)', () => {
|
||||
const arr: number[] = evaluateExpression(
|
||||
`
|
||||
import * as tslib from 'tslib';
|
||||
const a = [1];
|
||||
const b = [2, 3];
|
||||
`,
|
||||
'tslib.__spread(a, b)');
|
||||
|
||||
expect(arr).toEqual([1, 2, 3]);
|
||||
});
|
||||
|
||||
it('should evaluate `__spreadArrays()` (named import)', () => {
|
||||
const arr: number[] = evaluateExpression(
|
||||
`
|
||||
import {__spreadArrays} from 'tslib';
|
||||
const a = [4];
|
||||
const b = [5, 6];
|
||||
`,
|
||||
'__spreadArrays(a, b)');
|
||||
|
||||
expect(arr).toEqual([4, 5, 6]);
|
||||
});
|
||||
|
||||
it('should evaluate `__spreadArrays()` (star import)', () => {
|
||||
const arr: number[] = evaluateExpression(
|
||||
`
|
||||
import * as tslib from 'tslib';
|
||||
const a = [4];
|
||||
const b = [5, 6];
|
||||
`,
|
||||
'tslib.__spreadArrays(a, b)');
|
||||
|
||||
expect(arr).toEqual([4, 5, 6]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should evaluate TypeScript __spreadArrays helper', () => {
|
||||
const {checker, expression} = makeExpression(
|
||||
`
|
||||
import * as tslib from 'tslib';
|
||||
const a = [1];
|
||||
const b = [2, 3];
|
||||
`,
|
||||
'tslib.__spreadArrays(a, b)', [
|
||||
{
|
||||
name: _('/node_modules/tslib/index.d.ts'),
|
||||
contents: `
|
||||
export declare function __spreadArrays(...args: any[][]): any[];
|
||||
`
|
||||
},
|
||||
]);
|
||||
const reflectionHost = new TsLibAwareReflectionHost(checker);
|
||||
const evaluator = new PartialEvaluator(reflectionHost, checker, null);
|
||||
const value = evaluator.evaluate(expression);
|
||||
expect(value).toEqual([1, 2, 3]);
|
||||
describe('(with emitted TypeScript helpers as functions)', () => {
|
||||
// Helpers
|
||||
const evaluateExpression = <T extends ResolvedValue>(code: string, expr: string) => {
|
||||
const helpers = `
|
||||
function __assign(t, ...sources) { /* ... */ }
|
||||
function __spread(...args) { /* ... */ }
|
||||
function __spreadArrays(...args) { /* ... */ }
|
||||
`;
|
||||
const {checker, expression} = makeExpression(helpers + code, expr);
|
||||
|
||||
const reflectionHost = new TsLibAwareReflectionHost(checker);
|
||||
const evaluator = new PartialEvaluator(reflectionHost, checker, null);
|
||||
|
||||
return evaluator.evaluate(expression) as T;
|
||||
};
|
||||
|
||||
it('should evaluate `__assign()`', () => {
|
||||
const map: Map<string, boolean> = evaluateExpression(
|
||||
`
|
||||
const a = {a: true};
|
||||
const b = {b: true};
|
||||
`,
|
||||
'__assign(a, b)');
|
||||
|
||||
expect([...map]).toEqual([
|
||||
['a', true],
|
||||
['b', true],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should evaluate `__spread()`', () => {
|
||||
const arr: number[] = evaluateExpression(
|
||||
`
|
||||
const a = [1];
|
||||
const b = [2, 3];
|
||||
`,
|
||||
'__spread(a, b)');
|
||||
|
||||
expect(arr).toEqual([1, 2, 3]);
|
||||
});
|
||||
|
||||
it('should evaluate `__spreadArrays()`', () => {
|
||||
const arr: number[] = evaluateExpression(
|
||||
`
|
||||
const a = [4];
|
||||
const b = [5, 6];
|
||||
`,
|
||||
'__spreadArrays(a, b)');
|
||||
|
||||
expect(arr).toEqual([4, 5, 6]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should evaluate TypeScript __assign helper', () => {
|
||||
const {checker, expression} = makeExpression(
|
||||
`
|
||||
import * as tslib from 'tslib';
|
||||
const a = {a: true};
|
||||
const b = {b: true};
|
||||
`,
|
||||
'tslib.__assign(a, b)', [
|
||||
{
|
||||
name: _('/node_modules/tslib/index.d.ts'),
|
||||
contents: `
|
||||
export declare function __assign(...args: object[]): object;
|
||||
`
|
||||
},
|
||||
]);
|
||||
const reflectionHost = new TsLibAwareReflectionHost(checker);
|
||||
const evaluator = new PartialEvaluator(reflectionHost, checker, null);
|
||||
const map = evaluator.evaluate(expression) as Map<string, boolean>;
|
||||
const obj: {[key: string]: boolean} = {};
|
||||
map.forEach((value, key) => obj[key] = value);
|
||||
expect(obj).toEqual({a: true, b: true});
|
||||
describe('(with emitted TypeScript helpers as variables)', () => {
|
||||
// Helpers
|
||||
const evaluateExpression = <T extends ResolvedValue>(code: string, expr: string) => {
|
||||
const helpers = `
|
||||
var __assign = (this && this.__assign) || function (t, ...sources) { /* ... */ }
|
||||
var __spread = (this && this.__spread) || function (...args) { /* ... */ }
|
||||
var __spreadArrays = (this && this.__spreadArrays) || function (...args) { /* ... */ }
|
||||
`;
|
||||
const {checker, expression} = makeExpression(helpers + code, expr);
|
||||
|
||||
const reflectionHost = new TsLibAwareReflectionHost(checker);
|
||||
const evaluator = new PartialEvaluator(reflectionHost, checker, null);
|
||||
|
||||
return evaluator.evaluate(expression) as T;
|
||||
};
|
||||
|
||||
it('should evaluate `__assign()`', () => {
|
||||
const map: Map<string, boolean> = evaluateExpression(
|
||||
`
|
||||
const a = {a: true};
|
||||
const b = {b: true};
|
||||
`,
|
||||
'__assign(a, b)');
|
||||
|
||||
expect([...map]).toEqual([
|
||||
['a', true],
|
||||
['b', true],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should evaluate `__spread()`', () => {
|
||||
const arr: number[] = evaluateExpression(
|
||||
`
|
||||
const a = [1];
|
||||
const b = [2, 3];
|
||||
`,
|
||||
'__spread(a, b)');
|
||||
|
||||
expect(arr).toEqual([1, 2, 3]);
|
||||
});
|
||||
|
||||
it('should evaluate `__spreadArrays()`', () => {
|
||||
const arr: number[] = evaluateExpression(
|
||||
`
|
||||
const a = [4];
|
||||
const b = [5, 6];
|
||||
`,
|
||||
'__spreadArrays(a, b)');
|
||||
|
||||
expect(arr).toEqual([4, 5, 6]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('(visited file tracking)', () => {
|
||||
@ -665,36 +805,52 @@ runInEachFileSystem(() => {
|
||||
});
|
||||
|
||||
/**
|
||||
* Customizes the resolution of functions to recognize functions from tslib. Such functions are
|
||||
* not handled specially in the default TypeScript host, as only ngcc's ES5 host will have special
|
||||
* powers to recognize functions from tslib.
|
||||
* Customizes the resolution of module exports and identifier declarations to recognize known
|
||||
* helper functions from `tslib`. Such functions are not handled specially in the default
|
||||
* TypeScript host, as only ngcc's ES5 hosts will have special powers to recognize such functions.
|
||||
*/
|
||||
class TsLibAwareReflectionHost extends TypeScriptReflectionHost {
|
||||
getDefinitionOfFunction(node: ts.Node): FunctionDefinition|null {
|
||||
if (ts.isFunctionDeclaration(node)) {
|
||||
const helper = getTsHelperFn(node);
|
||||
if (helper !== null) {
|
||||
return {
|
||||
node,
|
||||
body: null, helper,
|
||||
parameters: [],
|
||||
};
|
||||
}
|
||||
getExportsOfModule(node: ts.Node): Map<string, Declaration>|null {
|
||||
const map = super.getExportsOfModule(node);
|
||||
|
||||
if (map !== null) {
|
||||
map.forEach(decl => decl.known = decl.known || (decl.node && getTsHelperFn(decl.node)));
|
||||
}
|
||||
return super.getDefinitionOfFunction(node);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
getDeclarationOfIdentifier(id: ts.Identifier): Declaration|null {
|
||||
const superDeclaration = super.getDeclarationOfIdentifier(id);
|
||||
|
||||
if (superDeclaration === null || superDeclaration.node === null) {
|
||||
return superDeclaration;
|
||||
}
|
||||
|
||||
const tsHelperFn = getTsHelperFn(superDeclaration.node);
|
||||
if (tsHelperFn !== null) {
|
||||
return {
|
||||
known: tsHelperFn,
|
||||
node: id,
|
||||
viaModule: null,
|
||||
};
|
||||
}
|
||||
|
||||
return superDeclaration;
|
||||
}
|
||||
}
|
||||
|
||||
function getTsHelperFn(node: ts.FunctionDeclaration): TsHelperFn|null {
|
||||
const name = node.name !== undefined && ts.isIdentifier(node.name) && node.name.text;
|
||||
function getTsHelperFn(node: ts.Declaration): KnownDeclaration|null {
|
||||
const id = (node as ts.Declaration & {name?: ts.Identifier}).name || null;
|
||||
const name = id && id.text;
|
||||
|
||||
switch (name) {
|
||||
case '__assign':
|
||||
return TsHelperFn.Assign;
|
||||
return KnownDeclaration.TsHelperAssign;
|
||||
case '__spread':
|
||||
return TsHelperFn.Spread;
|
||||
return KnownDeclaration.TsHelperSpread;
|
||||
case '__spreadArrays':
|
||||
return TsHelperFn.SpreadArrays;
|
||||
return KnownDeclaration.TsHelperSpreadArrays;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -316,12 +316,6 @@ export interface FunctionDefinition {
|
||||
*/
|
||||
body: ts.Statement[]|null;
|
||||
|
||||
/**
|
||||
* The type of tslib helper function, if the function is determined to represent a tslib helper
|
||||
* function. Otherwise, this will be null.
|
||||
*/
|
||||
helper: TsHelperFn|null;
|
||||
|
||||
/**
|
||||
* Metadata regarding the function's parameters, including possible default value expressions.
|
||||
*/
|
||||
@ -329,31 +323,28 @@ export interface FunctionDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Possible functions from TypeScript's helper library.
|
||||
*/
|
||||
export enum TsHelperFn {
|
||||
/**
|
||||
* Indicates the `__assign` function.
|
||||
*/
|
||||
Assign,
|
||||
/**
|
||||
* Indicates the `__spread` function.
|
||||
*/
|
||||
Spread,
|
||||
/**
|
||||
* Indicates the `__spreadArrays` function.
|
||||
*/
|
||||
SpreadArrays,
|
||||
}
|
||||
|
||||
/**
|
||||
* Possible declarations which are known.
|
||||
* Possible declarations of known values, such as built-in objects/functions or TypeScript helpers.
|
||||
*/
|
||||
export enum KnownDeclaration {
|
||||
/**
|
||||
* Indicates the JavaScript global `Object` class.
|
||||
*/
|
||||
JsGlobalObject,
|
||||
|
||||
/**
|
||||
* Indicates the `__assign` TypeScript helper function.
|
||||
*/
|
||||
TsHelperAssign,
|
||||
|
||||
/**
|
||||
* Indicates the `__spread` TypeScript helper function.
|
||||
*/
|
||||
TsHelperSpread,
|
||||
|
||||
/**
|
||||
* Indicates the `__spreadArrays` TypeScript helper function.
|
||||
*/
|
||||
TsHelperSpreadArrays,
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,7 +164,6 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
||||
return {
|
||||
node,
|
||||
body: node.body !== undefined ? Array.from(node.body.statements) : null,
|
||||
helper: null,
|
||||
parameters: node.parameters.map(param => {
|
||||
const name = parameterName(param.name);
|
||||
const initializer = param.initializer || null;
|
||||
@ -266,10 +265,8 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
||||
|
||||
/**
|
||||
* Resolve a `ts.Symbol` to its declaration, keeping track of the `viaModule` along the way.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
private getDeclarationOfSymbol(symbol: ts.Symbol, originalId: ts.Identifier|null): Declaration
|
||||
protected getDeclarationOfSymbol(symbol: ts.Symbol, originalId: ts.Identifier|null): Declaration
|
||||
|null {
|
||||
// If the symbol points to a ShorthandPropertyAssignment, resolve it.
|
||||
let valueDeclaration: ts.Declaration|undefined = undefined;
|
||||
|
Reference in New Issue
Block a user