mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-19 10:41:56 -05:00
Use getters to define live export bindings refresh (#35967)
* use getters to define live export bindings * fix scoping in export* helper * Object.defineProperty cannot be used in ES3 target * Accept changed baselines * Use function expression, not arrow function * Update importStarHelper to match export helper in binding-making * Fix whitespace * Adjust whitespace in edited helpers * Use new helper for setting bindings, use unscoped __exportStar helper for exports so helpers get reused more * Accept updated baselines * Use __createBinding for individual reexports when target is es3 * Remove unneeded type assertion * Singeline the helpers * Add check for createBinding helper, accept updated baselines with shortened helper Co-authored-by: Michael Rawlings <mirawlings@ebay.com>
This commit is contained in:
@@ -33450,6 +33450,10 @@ namespace ts {
|
||||
grammarErrorOnFirstToken(node, Diagnostics.An_export_declaration_cannot_have_modifiers);
|
||||
}
|
||||
|
||||
if (node.moduleSpecifier && node.exportClause && isNamedExports(node.exportClause) && length(node.exportClause.elements) && languageVersion === ScriptTarget.ES3) {
|
||||
checkExternalEmitHelpers(node, ExternalEmitHelpers.CreateBinding);
|
||||
}
|
||||
|
||||
if (!node.moduleSpecifier || checkExternalImportOrExportDeclaration(node)) {
|
||||
if (node.exportClause) {
|
||||
// export { x, y }
|
||||
@@ -35661,6 +35665,8 @@ namespace ts {
|
||||
case ExternalEmitHelpers.MakeTemplateObject: return "__makeTemplateObject";
|
||||
case ExternalEmitHelpers.ClassPrivateFieldGet: return "__classPrivateFieldGet";
|
||||
case ExternalEmitHelpers.ClassPrivateFieldSet: return "__classPrivateFieldSet";
|
||||
case ExternalEmitHelpers.CreateBinding: return "__createBinding";
|
||||
case ExternalEmitHelpers.SetModuleDefault: return "__setModuleDefault";
|
||||
default: return Debug.fail("Unrecognized helper");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,6 +412,11 @@ namespace ts {
|
||||
Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the transformation context during initialization.");
|
||||
Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed.");
|
||||
Debug.assert(!helper.scoped, "Cannot request a scoped emit helper.");
|
||||
if (helper.dependencies) {
|
||||
for (const h of helper.dependencies) {
|
||||
requestEmitHelper(h);
|
||||
}
|
||||
}
|
||||
emitHelpers = append(emitHelpers, helper);
|
||||
}
|
||||
|
||||
|
||||
@@ -103,11 +103,6 @@ namespace ts {
|
||||
insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment());
|
||||
|
||||
const updated = updateSourceFileNode(node, setTextRange(createNodeArray(statements), node.statements));
|
||||
if (currentModuleInfo.hasExportStarsToExportValues && !compilerOptions.importHelpers) {
|
||||
// If we have any `export * from ...` declarations
|
||||
// we need to inform the emitter to add the __export helper.
|
||||
addEmitHelper(updated, exportStarHelper);
|
||||
}
|
||||
addEmitHelpers(updated, context.readEmitHelpers());
|
||||
return updated;
|
||||
}
|
||||
@@ -435,11 +430,6 @@ namespace ts {
|
||||
insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment());
|
||||
|
||||
const body = createBlock(statements, /*multiLine*/ true);
|
||||
if (currentModuleInfo.hasExportStarsToExportValues && !compilerOptions.importHelpers) {
|
||||
// If we have any `export * from ...` declarations
|
||||
// we need to inform the emitter to add the __export helper.
|
||||
addEmitHelper(body, exportStarHelper);
|
||||
}
|
||||
if (needUMDDynamicImportHelper) {
|
||||
addEmitHelper(body, dynamicImportUMDHelper);
|
||||
}
|
||||
@@ -1001,20 +991,34 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
for (const specifier of node.exportClause.elements) {
|
||||
const exportedValue = createPropertyAccess(
|
||||
generatedName,
|
||||
specifier.propertyName || specifier.name
|
||||
);
|
||||
statements.push(
|
||||
setOriginalNode(
|
||||
setTextRange(
|
||||
createExpressionStatement(
|
||||
createExportExpression(getExportName(specifier), exportedValue)
|
||||
),
|
||||
specifier),
|
||||
specifier
|
||||
)
|
||||
);
|
||||
if (languageVersion === ScriptTarget.ES3) {
|
||||
statements.push(
|
||||
setOriginalNode(
|
||||
setTextRange(
|
||||
createExpressionStatement(
|
||||
createCreateBindingHelper(context, generatedName, createLiteral(specifier.propertyName || specifier.name), specifier.propertyName ? createLiteral(specifier.name) : undefined)
|
||||
),
|
||||
specifier),
|
||||
specifier
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
const exportedValue = createPropertyAccess(
|
||||
generatedName,
|
||||
specifier.propertyName || specifier.name
|
||||
);
|
||||
statements.push(
|
||||
setOriginalNode(
|
||||
setTextRange(
|
||||
createExpressionStatement(
|
||||
createExportExpression(getExportName(specifier), exportedValue, /* location */ undefined, /* liveBinding */ true)
|
||||
),
|
||||
specifier),
|
||||
specifier
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return singleOrMany(statements);
|
||||
@@ -1343,7 +1347,7 @@ namespace ts {
|
||||
|
||||
case SyntaxKind.NamedImports:
|
||||
for (const importBinding of namedBindings.elements) {
|
||||
statements = appendExportsOfDeclaration(statements, importBinding);
|
||||
statements = appendExportsOfDeclaration(statements, importBinding, /* liveBinding */ true);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1453,12 +1457,12 @@ namespace ts {
|
||||
* appended.
|
||||
* @param decl The declaration to export.
|
||||
*/
|
||||
function appendExportsOfDeclaration(statements: Statement[] | undefined, decl: Declaration): Statement[] | undefined {
|
||||
function appendExportsOfDeclaration(statements: Statement[] | undefined, decl: Declaration, liveBinding?: boolean): Statement[] | undefined {
|
||||
const name = getDeclarationName(decl);
|
||||
const exportSpecifiers = currentModuleInfo.exportSpecifiers.get(idText(name));
|
||||
if (exportSpecifiers) {
|
||||
for (const exportSpecifier of exportSpecifiers) {
|
||||
statements = appendExportStatement(statements, exportSpecifier.name, name, /*location*/ exportSpecifier.name);
|
||||
statements = appendExportStatement(statements, exportSpecifier.name, name, /*location*/ exportSpecifier.name, /* allowComments */ undefined, liveBinding);
|
||||
}
|
||||
}
|
||||
return statements;
|
||||
@@ -1476,8 +1480,8 @@ namespace ts {
|
||||
* @param location The location to use for source maps and comments for the export.
|
||||
* @param allowComments Whether to allow comments on the export.
|
||||
*/
|
||||
function appendExportStatement(statements: Statement[] | undefined, exportName: Identifier, expression: Expression, location?: TextRange, allowComments?: boolean): Statement[] | undefined {
|
||||
statements = append(statements, createExportStatement(exportName, expression, location, allowComments));
|
||||
function appendExportStatement(statements: Statement[] | undefined, exportName: Identifier, expression: Expression, location?: TextRange, allowComments?: boolean, liveBinding?: boolean): Statement[] | undefined {
|
||||
statements = append(statements, createExportStatement(exportName, expression, location, allowComments, liveBinding));
|
||||
return statements;
|
||||
}
|
||||
|
||||
@@ -1518,8 +1522,8 @@ namespace ts {
|
||||
* @param location The location to use for source maps and comments for the export.
|
||||
* @param allowComments An optional value indicating whether to emit comments for the statement.
|
||||
*/
|
||||
function createExportStatement(name: Identifier, value: Expression, location?: TextRange, allowComments?: boolean) {
|
||||
const statement = setTextRange(createExpressionStatement(createExportExpression(name, value)), location);
|
||||
function createExportStatement(name: Identifier, value: Expression, location?: TextRange, allowComments?: boolean, liveBinding?: boolean) {
|
||||
const statement = setTextRange(createExpressionStatement(createExportExpression(name, value, /* location */ undefined, liveBinding)), location);
|
||||
startOnNewLine(statement);
|
||||
if (!allowComments) {
|
||||
setEmitFlags(statement, EmitFlags.NoComments);
|
||||
@@ -1535,9 +1539,31 @@ namespace ts {
|
||||
* @param value The exported value.
|
||||
* @param location The location to use for source maps and comments for the export.
|
||||
*/
|
||||
function createExportExpression(name: Identifier, value: Expression, location?: TextRange) {
|
||||
function createExportExpression(name: Identifier, value: Expression, location?: TextRange, liveBinding?: boolean) {
|
||||
return setTextRange(
|
||||
createAssignment(
|
||||
liveBinding && languageVersion !== ScriptTarget.ES3 ? createCall(
|
||||
createPropertyAccess(
|
||||
createIdentifier("Object"),
|
||||
"defineProperty"
|
||||
),
|
||||
/*typeArguments*/ undefined,
|
||||
[
|
||||
createIdentifier("exports"),
|
||||
createLiteral(name),
|
||||
createObjectLiteral([
|
||||
createPropertyAssignment("enumerable", createLiteral(/*value*/ true)),
|
||||
createPropertyAssignment("get", createFunctionExpression(
|
||||
/*modifiers*/ undefined,
|
||||
/*asteriskToken*/ undefined,
|
||||
/*name*/ undefined,
|
||||
/*typeParameters*/ undefined,
|
||||
/*parameters*/ [],
|
||||
/*type*/ undefined,
|
||||
createBlock([createReturn(value)])
|
||||
))
|
||||
])
|
||||
]
|
||||
) : createAssignment(
|
||||
createPropertyAccess(
|
||||
createIdentifier("exports"),
|
||||
getSynthesizedClone(name)
|
||||
@@ -1813,21 +1839,55 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
// emit output for the __export helper function
|
||||
const exportStarHelper: EmitHelper = {
|
||||
name: "typescript:export-star",
|
||||
scoped: true,
|
||||
export const createBindingHelper: UnscopedEmitHelper = {
|
||||
name: "typescript:commonjscreatebinding",
|
||||
importName: "__createBinding",
|
||||
scoped: false,
|
||||
priority: 1,
|
||||
text: `
|
||||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));`
|
||||
};
|
||||
|
||||
function createCreateBindingHelper(context: TransformationContext, module: Expression, inputName: Expression, outputName: Expression | undefined) {
|
||||
context.requestEmitHelper(createBindingHelper);
|
||||
return createCall(getUnscopedHelperName("__createBinding"), /*typeArguments*/ undefined, [createIdentifier("exports"), module, inputName, ...(outputName ? [outputName] : [])]);
|
||||
}
|
||||
|
||||
export const setModuleDefaultHelper: UnscopedEmitHelper = {
|
||||
name: "typescript:commonjscreatevalue",
|
||||
importName: "__setModuleDefault",
|
||||
scoped: false,
|
||||
priority: 1,
|
||||
text: `
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});`
|
||||
};
|
||||
|
||||
// emit output for the __export helper function
|
||||
const exportStarHelper: UnscopedEmitHelper = {
|
||||
name: "typescript:export-star",
|
||||
importName: "__exportStar",
|
||||
scoped: false,
|
||||
dependencies: [createBindingHelper],
|
||||
priority: 2,
|
||||
text: `
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) __createBinding(exports, m, p);
|
||||
}`
|
||||
};
|
||||
|
||||
function createExportStarHelper(context: TransformationContext, module: Expression) {
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
return compilerOptions.importHelpers
|
||||
? createCall(getUnscopedHelperName("__exportStar"), /*typeArguments*/ undefined, [module, createIdentifier("exports")])
|
||||
: createCall(createIdentifier("__export"), /*typeArguments*/ undefined, [module]);
|
||||
context.requestEmitHelper(exportStarHelper);
|
||||
return createCall(getUnscopedHelperName("__exportStar"), /*typeArguments*/ undefined, [module, createIdentifier("exports")]);
|
||||
}
|
||||
|
||||
// emit helper for dynamic import
|
||||
@@ -1843,12 +1903,14 @@ namespace ts {
|
||||
name: "typescript:commonjsimportstar",
|
||||
importName: "__importStar",
|
||||
scoped: false,
|
||||
dependencies: [createBindingHelper, setModuleDefaultHelper],
|
||||
priority: 2,
|
||||
text: `
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};`
|
||||
};
|
||||
|
||||
@@ -5794,6 +5794,7 @@ namespace ts {
|
||||
readonly scoped: boolean; // Indicates whether the helper MUST be emitted in the current scope.
|
||||
readonly text: string | ((node: EmitHelperUniqueNameCallback) => string); // ES3-compatible raw script text, or a function yielding such a string
|
||||
readonly priority?: number; // Helpers with a higher priority are emitted earlier than other helpers on the node.
|
||||
readonly dependencies?: EmitHelper[]
|
||||
}
|
||||
|
||||
export interface UnscopedEmitHelper extends EmitHelper {
|
||||
@@ -5834,8 +5835,10 @@ namespace ts {
|
||||
MakeTemplateObject = 1 << 17, // __makeTemplateObject (used for constructing template string array objects)
|
||||
ClassPrivateFieldGet = 1 << 18, // __classPrivateFieldGet (used by the class private field transformation)
|
||||
ClassPrivateFieldSet = 1 << 19, // __classPrivateFieldSet (used by the class private field transformation)
|
||||
CreateBinding = 1 << 20, // __createBinding (use by the module transform for exports and namespace imports)
|
||||
SetModuleDefault = 1 << 21, // __setModuleDefault (use by the module transform for default exports)
|
||||
FirstEmitHelper = Extends,
|
||||
LastEmitHelper = ClassPrivateFieldSet,
|
||||
LastEmitHelper = SetModuleDefault,
|
||||
|
||||
// Helpers included by ES2015 for..of
|
||||
ForOfIncludes = Values,
|
||||
|
||||
Reference in New Issue
Block a user