gatsby
Version:
Blazing fast modern site generator for React
188 lines (176 loc) • 8.39 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.resolveModuleExports = resolveModuleExports;
var fs = _interopRequireWildcard(require("fs-extra"));
var t = _interopRequireWildcard(require("@babel/types"));
var _traverse = _interopRequireDefault(require("@babel/traverse"));
var _codeFrame = require("@babel/code-frame");
var _reporter = _interopRequireDefault(require("gatsby-cli/lib/reporter"));
var _babelParseToAst = require("../utils/babel-parse-to-ast");
var _testImportError = require("../utils/test-import-error");
var _moduleResolver = require("../utils/module-resolver");
var _resolveJsFilePath = require("./resolve-js-file-path");
var _preferDefault = require("./prefer-default");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
const staticallyAnalyzeExports = (modulePath, resolver = _moduleResolver.resolveModule) => {
let absPath;
const exportNames = [];
try {
absPath = resolver(modulePath);
} catch (err) {
return exportNames; // doesn't exist
}
const code = fs.readFileSync(absPath, `utf8`); // get file contents
let ast;
try {
ast = (0, _babelParseToAst.babelParseToAst)(code, absPath);
} catch (err) {
if (err instanceof SyntaxError) {
// Pretty print syntax errors
const codeFrame = (0, _codeFrame.codeFrameColumns)(code, {
start: err.loc
}, {
highlightCode: true
});
_reporter.default.panic(`Syntax error in "${absPath}":\n${err.message}\n${codeFrame}`);
} else {
// if it's not syntax error, just throw it
throw err;
}
}
let isCommonJS = false;
let isES6 = false;
// extract names of exports from file
(0, _traverse.default)(ast, {
// Check if the file is using ES6 imports
ImportDeclaration: function ImportDeclaration() {
isES6 = true;
},
ExportNamedDeclaration: function ExportNamedDeclaration(astPath) {
var _declaration$declarat, _declaration$id;
const declaration = astPath.node.declaration;
// get foo from `export const foo = bar`
if ((declaration === null || declaration === void 0 ? void 0 : declaration.type) === `VariableDeclaration` && ((_declaration$declarat = declaration.declarations[0]) === null || _declaration$declarat === void 0 ? void 0 : _declaration$declarat.id.type) === `Identifier`) {
isES6 = true;
exportNames.push(declaration.declarations[0].id.name);
}
// get foo from `export function foo()`
if ((declaration === null || declaration === void 0 ? void 0 : declaration.type) === `FunctionDeclaration` && ((_declaration$id = declaration.id) === null || _declaration$id === void 0 ? void 0 : _declaration$id.type) === `Identifier`) {
isES6 = true;
exportNames.push(declaration.id.name);
}
},
// get foo from `export { foo } from 'bar'`
// get foo from `export { foo }`
ExportSpecifier: function ExportSpecifier(astPath) {
var _astPath$node;
isES6 = true;
const exp = astPath === null || astPath === void 0 ? void 0 : (_astPath$node = astPath.node) === null || _astPath$node === void 0 ? void 0 : _astPath$node.exported;
if (!exp) {
return;
}
if (exp.type === `Identifier`) {
const exportName = exp.name;
if (exportName) {
exportNames.push(exportName);
}
}
},
// export default () => {}
// export default function() {}
// export default function foo() {}
// const foo = () => {}; export default foo
ExportDefaultDeclaration: function ExportDefaultDeclaration(astPath) {
const declaration = astPath.node.declaration;
if (!t.isIdentifier(declaration) && !t.isArrowFunctionExpression(declaration) && !t.isFunctionDeclaration(declaration)) {
return;
}
let name = ``;
if (t.isIdentifier(declaration)) {
name = declaration.name;
} else if (t.isFunctionDeclaration(declaration) && declaration.id) {
name = declaration.id.name;
}
const exportName = `export default${name ? ` ${name}` : ``}`;
isES6 = true;
exportNames.push(exportName);
},
AssignmentExpression: function AssignmentExpression(astPath) {
const nodeLeft = astPath.node.left;
if (!t.isMemberExpression(nodeLeft)) {
return;
}
// ignore marker property `__esModule`
if (t.isIdentifier(nodeLeft.property) && nodeLeft.property.name === `__esModule`) {
return;
}
// get foo from `exports.foo = bar`
if (t.isIdentifier(nodeLeft.object) && nodeLeft.object.name === `exports`) {
isCommonJS = true;
exportNames.push(nodeLeft.property.name);
}
// get foo from `module.exports.foo = bar`
if (t.isMemberExpression(nodeLeft.object)) {
const exp = nodeLeft.object;
if (t.isIdentifier(exp.object) && t.isIdentifier(exp.property) && exp.object.name === `module` && exp.property.name === `exports`) {
isCommonJS = true;
exportNames.push(nodeLeft.property.name);
}
}
}
});
if (isES6 && isCommonJS && process.env.NODE_ENV !== `test`) {
_reporter.default.panic(`This plugin file is using both CommonJS and ES6 module systems together which we don't support.
You'll need to edit the file to use just one or the other.
plugin: ${modulePath}.js
This didn't cause a problem in Gatsby v1 so you might want to review the migration doc for this:
https://gatsby.dev/no-mixed-modules
`);
}
return exportNames;
};
/**
* Given a path to a module, return an array of the module's exports.
*
* It can run in two modes:
* 1. `analysis` mode gets exports via static analysis by traversing the file's AST with babel
* 2. `import` mode gets exports by directly importing the module and accessing its properties
*
* At the time of writing, analysis mode is used for files that can be jsx (e.g. gatsby-browser, gatsby-ssr)
* and import mode is used for files that can be js or mjs.
*
* Returns [] for invalid paths and modules without exports.
*/
async function resolveModuleExports(modulePath, {
mode = `analysis`,
resolver = _moduleResolver.resolveModule,
rootDir = process.cwd()
} = {}) {
if (mode === `import`) {
try {
const moduleFilePath = await (0, _resolveJsFilePath.resolveJSFilepath)({
rootDir,
filePath: modulePath
});
if (!moduleFilePath) {
return [];
}
const rawImportedModule = await import((0, _resolveJsFilePath.maybeAddFileProtocol)(moduleFilePath));
// If the module is cjs, the properties we care about are nested under a top-level `default` property
const importedModule = (0, _preferDefault.preferDefault)(rawImportedModule);
return Object.keys(importedModule).filter(exportName => exportName !== `__esModule`);
} catch (error) {
if (!(0, _testImportError.testImportError)(modulePath, error)) {
// if module exists, but requiring it cause errors,
// show the error to the user and terminate build
_reporter.default.panic(`Error in "${modulePath}":`, error);
}
}
} else {
return staticallyAnalyzeExports(modulePath, resolver);
}
return [];
}
//# sourceMappingURL=resolve-module-exports.js.map
;