imports-loader
Version:
imports loader module for webpack
287 lines (278 loc) • 10.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getImports = getImports;
exports.renderImports = renderImports;
exports.sourceHasUseStrict = sourceHasUseStrict;
var _path = _interopRequireDefault(require("path"));
var _stripComments = _interopRequireDefault(require("strip-comments"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const matchRelativePath = /^\.\.?[/\\]/;
function isAbsolutePath(str) {
return _path.default.posix.isAbsolute(str) || _path.default.win32.isAbsolute(str);
}
function isRelativePath(str) {
return matchRelativePath.test(str);
}
// TODO simplify for the next major release
function stringifyRequest(loaderContext, request) {
if (typeof loaderContext.utils !== "undefined" && typeof loaderContext.utils.contextify === "function") {
return JSON.stringify(loaderContext.utils.contextify(loaderContext.context, request));
}
const splitted = request.split("!");
const {
context
} = loaderContext;
return JSON.stringify(splitted.map(part => {
// First, separate singlePath from query, because the query might contain paths again
const splittedPart = part.match(/^(.*?)(\?.*)/);
const query = splittedPart ? splittedPart[2] : "";
let singlePath = splittedPart ? splittedPart[1] : part;
if (isAbsolutePath(singlePath) && context) {
singlePath = _path.default.relative(context, singlePath);
if (isAbsolutePath(singlePath)) {
// If singlePath still matches an absolute path, singlePath was on a different drive than context.
// In this case, we leave the path platform-specific without replacing any separators.
// @see https://github.com/webpack/loader-utils/pull/14
return singlePath + query;
}
if (isRelativePath(singlePath) === false) {
// Ensure that the relative path starts at least with ./ otherwise it would be a request into the modules directory (like node_modules).
singlePath = `./${singlePath}`;
}
}
return singlePath.replace(/\\/g, "/") + query;
}).join("!"));
}
function forError(item) {
return typeof item === "string" ? item : `\n${JSON.stringify(item, null, " ")}\n`;
}
function sourceHasUseStrict(source) {
const str = (0, _stripComments.default)(source).trim();
return str.startsWith("'use strict'") || str.startsWith('"use strict"');
}
function splitCommand(command) {
const result = command.split("|").map(item => item.split(" ")).reduce((acc, val) => acc.concat(val), []);
for (const item of result) {
if (!item) {
throw new Error(`Invalid command "${item}" in "${command}" for imports. There must be only one separator: " ", or "|"`);
}
}
return result;
}
function resolveImports(type, item) {
const defaultSyntax = type === "module" ? "default" : "single";
let result;
if (typeof item === "string") {
const noWhitespaceItem = item.trim();
if (noWhitespaceItem.length === 0) {
throw new Error(`Invalid "${item}" value for import`);
}
const splittedItem = splitCommand(noWhitespaceItem);
if (splittedItem.length > 4) {
throw new Error(`Invalid "${item}" value for import`);
}
if (splittedItem.length === 1) {
result = {
syntax: defaultSyntax,
moduleName: splittedItem[0],
name: splittedItem[0],
// eslint-disable-next-line no-undefined
alias: undefined
};
} else {
result = {
syntax: splittedItem[0],
moduleName: splittedItem[1],
name: splittedItem[2],
// eslint-disable-next-line no-undefined
alias: splittedItem[3] ? splittedItem[3] : undefined
};
}
} else {
result = {
syntax: defaultSyntax,
...item
};
}
if (result.syntax === defaultSyntax && typeof result.name === "undefined") {
result.name = result.moduleName;
}
if (["default", "side-effects", "single", "pure"].includes(result.syntax) && typeof result.alias !== "undefined") {
throw new Error(`The "${result.syntax}" syntax does not support "${result.alias}" alias in "${forError(item)}" value`);
}
if (["side-effects", "pure"].includes(result.syntax) && typeof result.name !== "undefined") {
throw new Error(`The "${result.syntax}" syntax does not support "${result.name}" name in "${forError(item)}" value`);
}
if (["default", "namespace", "named", "side-effects"].includes(result.syntax) && type === "commonjs") {
throw new Error(`The "${type}" type does not support the "${result.syntax}" syntax in "${forError(item)}" value`);
}
if (["single", "multiple", "pure"].includes(result.syntax) && type === "module") {
throw new Error(`The "${type}" format does not support the "${result.syntax}" syntax in "${forError(item)}" value`);
}
if (["namespace", "named", "multiple"].includes(result.syntax) && typeof result.name === "undefined") {
throw new Error(`The "${result.syntax}" syntax needs the "name" option in "${forError(item)}" value`);
}
return result;
}
function getIdentifiers(array) {
return array.reduce((accumulator, item) => {
if (typeof item.alias !== "undefined") {
accumulator.push({
type: "alias",
value: item.alias
});
return accumulator;
}
if (typeof item.name !== "undefined") {
accumulator.push({
type: "name",
value: item.name
});
}
return accumulator;
}, []);
}
function duplicateBy(array, key) {
return array.filter((a, aIndex) => array.filter((b, bIndex) => b[key] === a[key] && aIndex !== bIndex).length > 0);
}
function getImports(type, imports) {
let result;
const importItems = typeof imports === "string" && imports.includes(",") ? imports.split(",") : imports;
if (typeof importItems === "string") {
result = [resolveImports(type, importItems)];
} else {
result = [].concat(importItems).map(item => resolveImports(type, item));
}
const identifiers = getIdentifiers(result);
const duplicates = duplicateBy(identifiers, "value");
if (duplicates.length > 0) {
throw new Error(`Duplicate ${duplicates.map(identifier => `"${identifier.value}" (as "${identifier.type}")`).join(", ")} identifiers found in "\n${JSON.stringify(importItems, null, " ")}\n" value`);
}
const sortedResults = Object.create(null);
for (const item of result) {
const {
moduleName
} = item;
if (!sortedResults[moduleName]) {
sortedResults[moduleName] = [];
}
const {
syntax,
name,
alias
} = item;
sortedResults[moduleName].push({
syntax,
name,
alias
});
}
return sortedResults;
}
function renderImports(loaderContext, type, moduleName, imports) {
let code = "";
if (type === "commonjs") {
const pure = imports.filter(({
syntax
}) => syntax === "pure");
// Pure
if (pure.length > 0) {
pure.forEach((_, i) => {
const needNewline = i < pure.length - 1 ? "\n" : "";
code += `require(${stringifyRequest(loaderContext, moduleName)});${needNewline}`;
});
}
const singleImports = imports.filter(({
syntax
}) => syntax === "single");
// Single
if (singleImports.length > 0) {
code += pure.length > 0 ? "\n" : "";
singleImports.forEach((singleImport, i) => {
const {
name
} = singleImport;
const needNewline = i < singleImports.length - 1 ? "\n" : "";
code += `var ${name} = require(${stringifyRequest(loaderContext, moduleName)});${needNewline}`;
});
}
const multipleImports = imports.filter(({
syntax
}) => syntax === "multiple");
// Multiple
if (multipleImports.length > 0) {
code += pure.length > 0 || singleImports.length > 0 ? "\n" : "";
code += `var { `;
multipleImports.forEach((multipleImport, i) => {
const needComma = i > 0 ? ", " : "";
const {
name,
alias
} = multipleImport;
const separator = ": ";
code += alias ? `${needComma}${name}${separator}${alias}` : `${needComma}${name}`;
});
code += ` } = require(${stringifyRequest(loaderContext, moduleName)});`;
}
return code;
}
const sideEffectsImports = imports.filter(({
syntax
}) => syntax === "side-effects");
// Side-effects
if (sideEffectsImports.length > 0) {
sideEffectsImports.forEach((_, i) => {
const needNewline = i < sideEffectsImports.length - 1 ? "\n" : "";
code += `import ${stringifyRequest(loaderContext, moduleName)};${needNewline}`;
});
return code;
}
const defaultImports = imports.filter(({
syntax
}) => syntax === "default");
const namedImports = imports.filter(({
syntax
}) => syntax === "named");
const namespaceImports = imports.filter(({
syntax
}) => syntax === "namespace");
// Default
if (defaultImports.length > 0) {
defaultImports.forEach((defaultImport, i) => {
const {
name
} = defaultImport;
const needNewline = i < defaultImports.length - 1 ? "\n" : "";
code += `import ${name} from ${stringifyRequest(loaderContext, moduleName)};${needNewline}`;
});
}
// Named
if (namedImports.length > 0) {
code += defaultImports.length > 0 ? "\n" : "";
code += "import { ";
namedImports.forEach((namedImport, i) => {
const needComma = i > 0 ? ", " : "";
const {
name,
alias
} = namedImport;
const separator = " as ";
code += alias ? `${needComma}${name}${separator}${alias}` : `${needComma}${name}`;
});
code += ` } from ${stringifyRequest(loaderContext, moduleName)};`;
}
// Namespace
if (namespaceImports.length > 0) {
code += defaultImports.length > 0 || namedImports.length > 0 ? "\n" : "";
namespaceImports.forEach((namespaceImport, i) => {
const {
name
} = namespaceImport;
const needNewline = i < namespaceImports.length - 1 ? "\n" : "";
code += `import * as ${name} from ${stringifyRequest(loaderContext, moduleName)};${needNewline}`;
});
}
return code;
}