fix(ngcc): support defineProperty()
re-exports in CommonJS and UMD (#36989)
In TypeScript 3.9 some re-export syntaxes have changed to be getter functions (created by calls to `Object.defineProperty()`) rather than simple property accessors. This commit adds support into the CommonJS and UMD reflection hosts for this style of re-export syntax. PR Close #36989
This commit is contained in:

committed by
Kara Erickson

parent
d268d2ad85
commit
91092f668e
@ -45,6 +45,20 @@ export interface WildcardReexportStatement extends ts.ExpressionStatement {
|
||||
expression: ts.CallExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* A CommonJS or UMD re-export statement using an `Object.defineProperty()` call.
|
||||
* For example:
|
||||
*
|
||||
* ```
|
||||
* Object.defineProperty(exports, "<exported-id>",
|
||||
* { enumerable: true, get: function () { return <imported-id>; } });
|
||||
* ```
|
||||
*/
|
||||
export interface DefinePropertyReexportStatement extends ts.ExpressionStatement {
|
||||
expression: ts.CallExpression&
|
||||
{arguments: [ts.Identifier, ts.StringLiteral, ts.ObjectLiteralExpression]};
|
||||
}
|
||||
|
||||
export interface RequireCall extends ts.CallExpression {
|
||||
arguments: ts.CallExpression['arguments']&[ts.StringLiteral];
|
||||
}
|
||||
@ -133,6 +147,69 @@ export function isWildcardReexportStatement(stmt: ts.Statement): stmt is Wildcar
|
||||
return stmt.expression.arguments.length > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the statement is a re-export of the form:
|
||||
*
|
||||
* ```
|
||||
* Object.defineProperty(exports, "<export-name>",
|
||||
* { enumerable: true, get: function () { return <import-name>; } });
|
||||
* ```
|
||||
*/
|
||||
export function isDefinePropertyReexportStatement(stmt: ts.Statement):
|
||||
stmt is DefinePropertyReexportStatement {
|
||||
if (!ts.isExpressionStatement(stmt) || !ts.isCallExpression(stmt.expression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for Object.defineProperty
|
||||
if (!ts.isPropertyAccessExpression(stmt.expression.expression) ||
|
||||
!ts.isIdentifier(stmt.expression.expression.expression) ||
|
||||
stmt.expression.expression.expression.text !== 'Object' ||
|
||||
!ts.isIdentifier(stmt.expression.expression.name) ||
|
||||
stmt.expression.expression.name.text !== 'defineProperty') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const args = stmt.expression.arguments;
|
||||
if (args.length !== 3) {
|
||||
return false;
|
||||
}
|
||||
const exportsObject = args[0];
|
||||
if (!ts.isIdentifier(exportsObject) || exportsObject.text !== 'exports') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const propertyKey = args[1];
|
||||
if (!ts.isStringLiteral(propertyKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const propertyDescriptor = args[2];
|
||||
if (!ts.isObjectLiteralExpression(propertyDescriptor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (propertyDescriptor.properties.some(
|
||||
prop => prop.name !== undefined && ts.isIdentifier(prop.name) && prop.name.text === 'get'));
|
||||
}
|
||||
|
||||
export function extractGetterFnExpression(statement: DefinePropertyReexportStatement):
|
||||
ts.Expression|null {
|
||||
const args = statement.expression.arguments;
|
||||
const getterFn = args[2].properties.find(
|
||||
prop => prop.name !== undefined && ts.isIdentifier(prop.name) && prop.name.text === 'get');
|
||||
if (getterFn === undefined || !ts.isPropertyAssignment(getterFn) ||
|
||||
!ts.isFunctionExpression(getterFn.initializer)) {
|
||||
return null;
|
||||
}
|
||||
const returnStatement = getterFn.initializer.body.statements[0];
|
||||
if (!ts.isReturnStatement(returnStatement) || returnStatement.expression === undefined) {
|
||||
return null;
|
||||
}
|
||||
return returnStatement.expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the specified `ts.Node` represents a `require()` call, i.e. an call expression of
|
||||
* the form: `require('<foo>')`
|
||||
@ -142,3 +219,7 @@ export function isRequireCall(node: ts.Node): node is RequireCall {
|
||||
node.expression.text === 'require' && node.arguments.length === 1 &&
|
||||
ts.isStringLiteral(node.arguments[0]);
|
||||
}
|
||||
|
||||
export function isExternalImport(path: string): boolean {
|
||||
return !/^\.\.?(\/|$)/.test(path);
|
||||
}
|
Reference in New Issue
Block a user