123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- const {walk} = require("estree-walker");
- const isReference = require("is-reference");
- const {attachScopes, makeLegalIdentifier} = require("@rollup/pluginutils");
- function analyzeImport(node, importBindings, code, getName, globals) {
- const name = node.source.value && getName(node.source.value);
- if (!name) {
- return false;
- }
- globals.add(name);
- for (const spec of node.specifiers) {
- importBindings.set(spec.local.name, makeGlobalName(
- spec.imported ? spec.imported.name : "default",
- name
- ));
- }
- code.remove(node.start, node.end);
- return true;
- }
- function makeGlobalName(prop, name) {
- if (prop === "default") {
- return name;
- }
- return `${name}.${prop}`;
- }
- function writeSpecLocal(code, root, spec, name, tempNames) {
- if (spec.isOverwritten) return;
- // we always need an extra assignment for named export statement
- // https://github.com/eight04/rollup-plugin-external-globals/issues/19
- const localName = `_global_${makeLegalIdentifier(name)}`;
- if (!tempNames.has(localName)) {
- code.appendRight(root.start, `const ${localName} = ${name};\n`);
- tempNames.add(localName);
- }
- if (spec.local.name === localName) {
- return;
- }
- if (spec.local === spec.exported) {
- code.appendRight(spec.local.start, `${localName} as `);
- } else {
- code.overwrite(spec.local.start, spec.local.end, localName);
- }
- spec.isOverwritten = true;
- }
- function writeIdentifier(code, node, parent, name) {
- if (node.name === name || node.isOverwritten) {
- return;
- }
- // 2020/8/14, parent.key and parent.value is no longer the same object. However, the shape is the same.
- if (parent.type === "Property" && parent.key.start === parent.value.start) {
- code.appendLeft(node.end, `: ${name}`);
- parent.key.isOverwritten = true;
- parent.value.isOverwritten = true;
- } else {
- code.overwrite(node.start, node.end, name, {contentOnly: true});
- // FIXME: do we need this?
- node.isOverwritten = true;
- }
- }
- function analyzeExportNamed(node, code, getName, tempNames) {
- if (node.declaration || !node.source || !node.source.value) {
- return false;
- }
- const name = getName(node.source.value);
- if (!name) {
- return false;
- }
- for (const spec of node.specifiers) {
- const globalName = makeGlobalName(spec.local.name, name);
- writeSpecLocal(code, node, spec, globalName, tempNames);
- }
- if (node.specifiers.length) {
- code.overwrite(node.specifiers[node.specifiers.length - 1].end, node.source.end, "}");
- } else {
- code.remove(node.start, node.end);
- }
- return true;
- }
- function writeDynamicImport(code, node, content) {
- code.overwrite(node.start, node.end, content);
- }
- function getDynamicImportSource(node) {
- if (node.type === "ImportExpression") {
- return node.source.value;
- }
- if (node.type === "CallExpression" && node.callee.type === "Import") {
- return node.arguments[0].value;
- }
- }
- function importToGlobals({ast, code, getName, getDynamicWrapper}) {
- let scope = attachScopes(ast, "scope");
- const bindings = new Map;
- const globals = new Set;
- let isTouched = false;
- const tempNames = new Set;
- for (const node of ast.body) {
- if (node.type === "ImportDeclaration") {
- isTouched = analyzeImport(node, bindings, code, getName, globals) || isTouched;
- } else if (node.type === "ExportNamedDeclaration") {
- isTouched = analyzeExportNamed(node, code, getName, tempNames) || isTouched;
- }
- }
-
- let topStatement;
- walk(ast, {
- enter(node, parent) {
- if (parent && parent.type === "Program") {
- topStatement = node;
- }
- if (/^importdec/i.test(node.type)) {
- this.skip();
- return;
- }
- if (node.scope) {
- scope = node.scope;
- }
- if (isReference(node, parent)) {
- if (bindings.has(node.name) && !scope.contains(node.name)) {
- if (parent.type === "ExportSpecifier") {
- writeSpecLocal(code, topStatement, parent, bindings.get(node.name), tempNames);
- } else {
- writeIdentifier(code, node, parent, bindings.get(node.name));
- }
- } else if (globals.has(node.name) && scope.contains(node.name)) {
- writeIdentifier(code, node, parent, `_local_${node.name}`);
- }
- }
- const source = getDynamicImportSource(node);
- const name = source && getName(source);
- const dynamicName = name && getDynamicWrapper(name);
- if (dynamicName) {
- writeDynamicImport(code, node, dynamicName);
- isTouched = true;
- this.skip();
- }
- },
- leave(node) {
- if (node.scope) {
- scope = node.scope.parent;
- }
- }
- });
-
- return isTouched;
- }
- module.exports = importToGlobals;
|