diff --git a/packages/commonjs/src/generate-imports.js b/packages/commonjs/src/generate-imports.js index 7aa0c33a7..d624ab25c 100644 --- a/packages/commonjs/src/generate-imports.js +++ b/packages/commonjs/src/generate-imports.js @@ -104,6 +104,7 @@ export function getRequireHandlers() { scope, usesReturnValue, isInsideTryBlock, + isInsideConditional, toBeRemoved ) { requireExpressions.push({ @@ -112,6 +113,7 @@ export function getRequireHandlers() { scope, usesReturnValue, isInsideTryBlock, + isInsideConditional, toBeRemoved }); } @@ -135,7 +137,6 @@ export function getRequireHandlers() { const imports = []; imports.push(`import * as ${helpersName} from "${HELPERS_ID}";`); if (usesRequire) { - // TODO Lukas check where to import it from or change to usesDynamicRequire imports.push( `import { commonjsRequire as ${dynamicRequireName} } from "${DYNAMIC_MODULES_ID}";` ); @@ -155,7 +156,12 @@ export function getRequireHandlers() { const { requireTargets, usesRequireWrapper } = await resolveRequireSourcesAndGetMeta( id, needsRequireWrapper ? IS_WRAPPED_COMMONJS : !isEsModule, - Object.keys(requiresBySource) + Object.keys(requiresBySource).map((source) => { + return { + source, + isConditional: requiresBySource[source].every((require) => require.isInsideConditional) + }; + }) ); processRequireExpressions( imports, diff --git a/packages/commonjs/src/index.js b/packages/commonjs/src/index.js index 45eb23c98..88c362987 100644 --- a/packages/commonjs/src/index.js +++ b/packages/commonjs/src/index.js @@ -38,7 +38,7 @@ export default function commonjs(options = {}) { } = options; const extensions = options.extensions || ['.js']; const filter = createFilter(options.include, options.exclude); - const { strictRequiresFilter, detectCycles } = getStrictRequiresFilter(options); + const { strictRequiresFilter, detectCyclesAndConditional } = getStrictRequiresFilter(options); const getRequireReturnsDefault = typeof requireReturnsDefaultOption === 'function' @@ -63,10 +63,11 @@ export default function commonjs(options = {}) { resolveRequireSourcesAndGetMeta, getWrappedIds, isRequiredId - } = getResolveRequireSourcesAndGetMeta(extensions, detectCycles); + } = getResolveRequireSourcesAndGetMeta(extensions, detectCyclesAndConditional); const dynamicRequireModules = getDynamicRequireModules(options.dynamicRequireTargets); const isDynamicRequireModulesEnabled = dynamicRequireModules.size > 0; - // TODO Lukas do we need the CWD? + // TODO Lukas replace with new dynamicRequireRoot to replace CWD + // TODO Lukas throw if require from outside commondir const commonDir = isDynamicRequireModulesEnabled ? getCommonDir(null, Array.from(dynamicRequireModules.keys()).concat(process.cwd())) : null; diff --git a/packages/commonjs/src/resolve-require-sources.js b/packages/commonjs/src/resolve-require-sources.js index 78f0af4d0..9483d2cd1 100644 --- a/packages/commonjs/src/resolve-require-sources.js +++ b/packages/commonjs/src/resolve-require-sources.js @@ -7,9 +7,10 @@ import { } from './helpers'; import { resolveExtensions } from './resolve-id'; -export function getResolveRequireSourcesAndGetMeta(extensions, detectCycles) { +export function getResolveRequireSourcesAndGetMeta(extensions, detectCyclesAndConditional) { const knownCjsModuleTypes = Object.create(null); const requiredIds = Object.create(null); + const unconditionallyRequiredIds = Object.create(null); const dependentModules = Object.create(null); const getDependentModules = (id) => dependentModules[id] || (dependentModules[id] = Object.create(null)); @@ -20,20 +21,31 @@ export function getResolveRequireSourcesAndGetMeta(extensions, detectCycles) { (id) => knownCjsModuleTypes[id] === IS_WRAPPED_COMMONJS ), isRequiredId: (id) => requiredIds[id], - resolveRequireSourcesAndGetMeta: (rollupContext) => async (id, isParentCommonJS, sources) => { - knownCjsModuleTypes[id] = isParentCommonJS; + resolveRequireSourcesAndGetMeta: (rollupContext) => async ( + parentId, + isParentCommonJS, + sources + ) => { + knownCjsModuleTypes[parentId] = knownCjsModuleTypes[parentId] || isParentCommonJS; + if ( + knownCjsModuleTypes[parentId] && + requiredIds[parentId] && + !unconditionallyRequiredIds[parentId] + ) { + knownCjsModuleTypes[parentId] = IS_WRAPPED_COMMONJS; + } const requireTargets = await Promise.all( - sources.map(async (source) => { + sources.map(async ({ source, isConditional }) => { // Never analyze or proxy internal modules if (source.startsWith('\0')) { return { id: source, allowProxy: false }; } const resolved = - (await rollupContext.resolve(source, id, { + (await rollupContext.resolve(source, parentId, { custom: { 'node-resolve': { isRequire: true } } - })) || resolveExtensions(source, id, extensions); + })) || resolveExtensions(source, parentId, extensions); if (!resolved) { return { id: wrapId(source, EXTERNAL_SUFFIX), allowProxy: false }; } @@ -42,17 +54,25 @@ export function getResolveRequireSourcesAndGetMeta(extensions, detectCycles) { return { id: wrapId(childId, EXTERNAL_SUFFIX), allowProxy: false }; } requiredIds[childId] = true; - const parentDependentModules = getDependentModules(id); + if ( + !( + detectCyclesAndConditional && + (isConditional || knownCjsModuleTypes[parentId] === IS_WRAPPED_COMMONJS) + ) + ) { + unconditionallyRequiredIds[childId] = true; + } + const parentDependentModules = getDependentModules(parentId); const childDependentModules = getDependentModules(childId); - childDependentModules[id] = true; + childDependentModules[parentId] = true; for (const dependentId of Object.keys(parentDependentModules)) { childDependentModules[dependentId] = true; } if (parentDependentModules[childId]) { // If we depend on one of our dependencies, we have a cycle. Then all modules that // we depend on that also depend on the same module are part of a cycle as well. - if (detectCycles && isParentCommonJS) { - knownCjsModuleTypes[id] = IS_WRAPPED_COMMONJS; + if (detectCyclesAndConditional && isParentCommonJS) { + knownCjsModuleTypes[parentId] = IS_WRAPPED_COMMONJS; knownCjsModuleTypes[childId] = IS_WRAPPED_COMMONJS; for (const dependentId of Object.keys(parentDependentModules)) { if (getDependentModules(dependentId)[childId]) { @@ -73,7 +93,7 @@ export function getResolveRequireSourcesAndGetMeta(extensions, detectCycles) { requireTargets: requireTargets.map(({ id: dependencyId, allowProxy }, index) => { const isCommonJS = knownCjsModuleTypes[dependencyId]; return { - source: sources[index], + source: sources[index].source, id: allowProxy ? isCommonJS === IS_WRAPPED_COMMONJS ? wrapId(dependencyId, WRAPPED_SUFFIX) @@ -82,7 +102,7 @@ export function getResolveRequireSourcesAndGetMeta(extensions, detectCycles) { isCommonJS }; }), - usesRequireWrapper: knownCjsModuleTypes[id] === IS_WRAPPED_COMMONJS + usesRequireWrapper: knownCjsModuleTypes[parentId] === IS_WRAPPED_COMMONJS }; } }; diff --git a/packages/commonjs/src/transform-commonjs.js b/packages/commonjs/src/transform-commonjs.js index 7b53b5ab8..5468878ec 100644 --- a/packages/commonjs/src/transform-commonjs.js +++ b/packages/commonjs/src/transform-commonjs.js @@ -71,7 +71,13 @@ export default async function transformCommonjs( let shouldWrap = false; const globals = new Set(); + // A conditionalNode is a node for which execution is not guaranteed. If such a node is a require + // or contains nested requires, those should be handled as function calls unless there is an + // unconditional require elsewhere. + let currentConditionalNodeEnd = null; + const conditionalNodes = new Set(); + // TODO Lukas fix this at last, we are close // TODO technically wrong since globals isn't populated yet, but ¯\_(ツ)_/¯ const helpersName = deconflict([scope], globals, 'commonjsHelpers'); const dynamicRequireName = deconflict([scope], globals, 'commonjsRequire'); @@ -102,6 +108,12 @@ export default async function transformCommonjs( if (currentTryBlockEnd !== null && node.start > currentTryBlockEnd) { currentTryBlockEnd = null; } + if (currentConditionalNodeEnd !== null && node.start > currentConditionalNodeEnd) { + currentConditionalNodeEnd = null; + } + if (currentConditionalNodeEnd === null && conditionalNodes.has(node)) { + currentConditionalNodeEnd = node.end; + } programDepth += 1; if (node.scope) ({ scope } = node); @@ -113,11 +125,6 @@ export default async function transformCommonjs( // eslint-disable-next-line default-case switch (node.type) { - case 'TryStatement': - if (currentTryBlockEnd === null) { - currentTryBlockEnd = node.block.end; - } - return; case 'AssignmentExpression': if (node.left.type === 'MemberExpression') { const flattened = getKeypath(node.left); @@ -227,6 +234,7 @@ export default async function transformCommonjs( scope, usesReturnValue, currentTryBlockEnd !== null, + currentConditionalNodeEnd !== null, parent.type === 'ExpressionStatement' ? parent : node ); } @@ -237,8 +245,26 @@ export default async function transformCommonjs( // skip dead branches if (isFalsy(node.test)) { skippedNodes.add(node.consequent); - } else if (node.alternate && isTruthy(node.test)) { - skippedNodes.add(node.alternate); + } else if (isTruthy(node.test)) { + if (node.alternate) { + skippedNodes.add(node.alternate); + } + } else { + conditionalNodes.add(node.consequent); + if (node.alternate) { + conditionalNodes.add(node.alternate); + } + } + return; + case 'ArrowFunctionExpression': + case 'FunctionDeclaration': + case 'FunctionExpression': + // requires in functions should be conditional unless it is an IIFE + if ( + currentConditionalNodeEnd === null && + !(parent.type === 'CallExpression' && parent.callee === node) + ) { + currentConditionalNodeEnd = node.end; } return; case 'Identifier': { @@ -301,6 +327,22 @@ export default async function transformCommonjs( return; } } + case 'LogicalExpression': + // skip dead branches + if (node.operator === '&&') { + if (isFalsy(node.left)) { + skippedNodes.add(node.right); + } else if (!isTruthy(node.left)) { + conditionalNodes.add(node.right); + } + } else if (node.operator === '||') { + if (isTruthy(node.left)) { + skippedNodes.add(node.right); + } else if (!isFalsy(node.left)) { + conditionalNodes.add(node.right); + } + } + return; case 'MemberExpression': if (!isDynamicRequireModulesEnabled && isModuleRequire(node, scope)) { uses.require = true; @@ -328,6 +370,11 @@ export default async function transformCommonjs( } } return; + case 'TryStatement': + if (currentTryBlockEnd === null) { + currentTryBlockEnd = node.block.end; + } + return; case 'UnaryExpression': // rewrite `typeof module`, `typeof module.exports` and `typeof exports` (https://github.com/rollup/rollup-plugin-commonjs/issues/151) if (node.operator === 'typeof') { diff --git a/packages/commonjs/src/utils.js b/packages/commonjs/src/utils.js index baee15948..35c727a97 100644 --- a/packages/commonjs/src/utils.js +++ b/packages/commonjs/src/utils.js @@ -44,20 +44,20 @@ export function capitalize(name) { export function getStrictRequiresFilter({ strictRequires }) { switch (strictRequires) { case true: - return { strictRequiresFilter: () => true, detectCycles: false }; + return { strictRequiresFilter: () => true, detectCyclesAndConditional: false }; // eslint-disable-next-line no-undefined case undefined: case 'auto': case 'debug': case null: - return { strictRequiresFilter: () => false, detectCycles: true }; + return { strictRequiresFilter: () => false, detectCyclesAndConditional: true }; case false: - return { strictRequiresFilter: () => false, detectCycles: false }; + return { strictRequiresFilter: () => false, detectCyclesAndConditional: false }; default: if (typeof strictRequires === 'string' || Array.isArray(strictRequires)) { return { strictRequiresFilter: createFilter(strictRequires), - detectCycles: false + detectCyclesAndConditional: false }; } throw new Error('Unexpected value for "strictRequires" option.'); diff --git a/packages/commonjs/test/fixtures/function/conditional-require-chain/_config.js b/packages/commonjs/test/fixtures/function/conditional-require-chain/_config.js new file mode 100644 index 000000000..e0666eccc --- /dev/null +++ b/packages/commonjs/test/fixtures/function/conditional-require-chain/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'makes requires in conditionally required modules conditional as well' +}; diff --git a/packages/commonjs/test/fixtures/function/conditional-require-chain/dep.js b/packages/commonjs/test/fixtures/function/conditional-require-chain/dep.js new file mode 100644 index 000000000..3b1998d8e --- /dev/null +++ b/packages/commonjs/test/fixtures/function/conditional-require-chain/dep.js @@ -0,0 +1 @@ +require('./throws.js'); diff --git a/packages/commonjs/test/fixtures/function/conditional-require-chain/main.js b/packages/commonjs/test/fixtures/function/conditional-require-chain/main.js new file mode 100644 index 000000000..1aa85f1c1 --- /dev/null +++ b/packages/commonjs/test/fixtures/function/conditional-require-chain/main.js @@ -0,0 +1,6 @@ +global.false = false; + +if (global.false) { + // eslint-disable-next-line global-require + require('./dep.js'); +} diff --git a/packages/commonjs/test/fixtures/function/conditional-require-chain/throws.js b/packages/commonjs/test/fixtures/function/conditional-require-chain/throws.js new file mode 100644 index 000000000..eb8668af4 --- /dev/null +++ b/packages/commonjs/test/fixtures/function/conditional-require-chain/throws.js @@ -0,0 +1 @@ +throw new Error('This should not be executed'); diff --git a/packages/commonjs/test/fixtures/function/skips-dead-branches/main.js b/packages/commonjs/test/fixtures/function/skips-dead-branches/main.js index 0066d0550..03d934380 100644 --- a/packages/commonjs/test/fixtures/function/skips-dead-branches/main.js +++ b/packages/commonjs/test/fixtures/function/skips-dead-branches/main.js @@ -3,4 +3,9 @@ if ('development' === 'production') { require('./a.js'); } -module.exports = true ? require('./b.js') : require('./c.js'); +exports.conditionalTrue = true ? require('./b.js') : require('./c.js'); +exports.conditionalFalse = false ? require('./c.js') : require('./b.js'); +exports.logicalAnd1 = true && require('./b.js'); +exports.logicalAnd2 = false && require('./c.js'); +exports.logicalOr1 = true || require('./c.js'); +exports.logicalOr2 = false || require('./b.js'); diff --git a/packages/commonjs/test/fixtures/function/strict-requires-detect-conditionals/_config.js b/packages/commonjs/test/fixtures/function/strict-requires-detect-conditionals/_config.js new file mode 100644 index 000000000..d926d0b82 --- /dev/null +++ b/packages/commonjs/test/fixtures/function/strict-requires-detect-conditionals/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'automatically detects requires nested in conditionals' +}; diff --git a/packages/commonjs/test/fixtures/function/strict-requires-detect-conditionals/hoisted.js b/packages/commonjs/test/fixtures/function/strict-requires-detect-conditionals/hoisted.js new file mode 100644 index 000000000..705851f9f --- /dev/null +++ b/packages/commonjs/test/fixtures/function/strict-requires-detect-conditionals/hoisted.js @@ -0,0 +1 @@ +module.exports = 'this should be top-level'; diff --git a/packages/commonjs/test/fixtures/function/strict-requires-detect-conditionals/main.js b/packages/commonjs/test/fixtures/function/strict-requires-detect-conditionals/main.js new file mode 100644 index 000000000..b7fc6ea58 --- /dev/null +++ b/packages/commonjs/test/fixtures/function/strict-requires-detect-conditionals/main.js @@ -0,0 +1,44 @@ +/* eslint-disable global-require */ +global.false = false; +global.true = true; + +if (global.false) { + require('./throws.js'); +} + +if (global.true) { + /* do nothing */ +} else { + require('./throws.js'); +} + +const conditionalFalse = global.false ? require('./throws.js') : null; +const conditionalTrue = global.true ? null : require('./throws.js'); + +const logicalAnd = global.false && require('./throws.js'); +const logicalOr = global.true || require('./throws.js'); + +function requireFunctionDeclaration() { + require('./throws.js'); +} + +const requireFunctionExpression = function () { + require('./throws.js'); +}; + +const requireArrowFunction = () => require('./throws.js'); + +if (global.false) { + requireFunctionDeclaration(); + requireFunctionExpression(); + requireArrowFunction(); +} + +// These should not cause wrapping +t.is( + (function () { + return require('./hoisted.js'); + })(), + 'this should be top-level' +); +t.is((() => require('./hoisted.js'))(), 'this should be top-level'); diff --git a/packages/commonjs/test/fixtures/function/strict-requires-detect-conditionals/throws.js b/packages/commonjs/test/fixtures/function/strict-requires-detect-conditionals/throws.js new file mode 100644 index 000000000..d11e026e6 --- /dev/null +++ b/packages/commonjs/test/fixtures/function/strict-requires-detect-conditionals/throws.js @@ -0,0 +1 @@ +throw new Error('This should never be executed or imported'); diff --git a/packages/commonjs/test/fixtures/function/strict-requires-file-without-module-type/main.js b/packages/commonjs/test/fixtures/function/strict-requires-file-without-module-type/main.js index c10a2ca10..8e5f0208b 100644 --- a/packages/commonjs/test/fixtures/function/strict-requires-file-without-module-type/main.js +++ b/packages/commonjs/test/fixtures/function/strict-requires-file-without-module-type/main.js @@ -1,2 +1,4 @@ +global.null = 0; + // eslint-disable-next-line global-require -t.is(0 && require('./error.js'), 0); +t.is(global.null && require('./error.js'), 0); diff --git a/packages/commonjs/test/form.js b/packages/commonjs/test/form.js index 3dcc25740..270d27ccf 100644 --- a/packages/commonjs/test/form.js +++ b/packages/commonjs/test/form.js @@ -11,6 +11,13 @@ import { commonjs } from './helpers/util'; process.chdir(__dirname); const transformContext = { + error: (base, props) => { + let error = base; + if (!(base instanceof Error)) error = Object.assign(new Error(base.message), base); + if (props) Object.assign(error, props); + throw error; + }, + load: ({ id }) => Promise.resolve({ id, meta: {} }), parse: (input, options) => acorn.parse(input, { ecmaVersion: 9, @@ -20,8 +27,7 @@ const transformContext = { resolve: (source, importer) => Promise.resolve({ id: `${path.resolve(path.dirname(importer), source)}${path.extname(source) ? '' : '.js'}` - }), - load: ({ id }) => Promise.resolve({ id, meta: {} }) + }) }; // Do not run on Windows as we have full path names in the output @@ -59,13 +65,6 @@ if (path.sep === '/') { : [] }; }; - transformContext.error = (base, props) => { - let error = base; - if (!(base instanceof Error)) error = Object.assign(new Error(base.message), base); - if (props) Object.assign(error, props); - throw error; - }; - const input = fs.readFileSync(id, 'utf-8'); let outputFile = `fixtures/form/${dir}/${outputName}`; diff --git a/packages/commonjs/test/snapshots/function.js.md b/packages/commonjs/test/snapshots/function.js.md index 68e51acb0..42d68b8eb 100644 --- a/packages/commonjs/test/snapshots/function.js.md +++ b/packages/commonjs/test/snapshots/function.js.md @@ -4484,16 +4484,32 @@ Generated by [AVA](https://avajs.dev). { 'main.js': `'use strict';␊ ␊ - var multiply = function (a, b) {␊ - return a * b;␊ - };␊ + var multiply;␊ + var hasRequiredMultiply;␊ + ␊ + function requireMultiply () {␊ + if (hasRequiredMultiply) return multiply;␊ + hasRequiredMultiply = 1;␊ + multiply = function (a, b) {␊ + return a * b;␊ + };␊ + return multiply;␊ + }␊ + ␊ + var foo;␊ + var hasRequiredFoo;␊ ␊ - var foo = 1;␊ + function requireFoo () {␊ + if (hasRequiredFoo) return foo;␊ + hasRequiredFoo = 1;␊ + foo = 1;␊ + return foo;␊ + }␊ ␊ /* eslint-disable global-require */␊ ␊ var main = function () {␊ - return multiply(2, foo);␊ + return requireMultiply()(2, requireFoo());␊ };␊ ␊ module.exports = main;␊ @@ -5598,16 +5614,31 @@ Generated by [AVA](https://avajs.dev). { 'main.js': `'use strict';␊ ␊ + Object.defineProperty(exports, '__esModule', { value: true });␊ + ␊ var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};␊ ␊ + var main = {};␊ + ␊ commonjsGlobal.b = 2;␊ var b = 'b';␊ ␊ /* eslint-disable */␊ ␊ - var main = b ;␊ + var conditionalTrue = main.conditionalTrue = b ;␊ + var conditionalFalse = main.conditionalFalse = b;␊ + var logicalAnd1 = main.logicalAnd1 = b;␊ + var logicalAnd2 = main.logicalAnd2 = false ;␊ + var logicalOr1 = main.logicalOr1 = true ;␊ + var logicalOr2 = main.logicalOr2 = b;␊ ␊ - module.exports = main;␊ + exports.conditionalFalse = conditionalFalse;␊ + exports.conditionalTrue = conditionalTrue;␊ + exports["default"] = main;␊ + exports.logicalAnd1 = logicalAnd1;␊ + exports.logicalAnd2 = logicalAnd2;␊ + exports.logicalOr1 = logicalOr1;␊ + exports.logicalOr2 = logicalOr2;␊ `, } @@ -5807,6 +5838,77 @@ Generated by [AVA](https://avajs.dev). `, } +## strict-requires-detect-conditionals + +> Snapshot 1 + + { + 'main.js': `'use strict';␊ + ␊ + var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};␊ + ␊ + var main = {};␊ + ␊ + var throws = {};␊ + ␊ + var hasRequiredThrows;␊ + ␊ + function requireThrows () {␊ + if (hasRequiredThrows) return throws;␊ + hasRequiredThrows = 1;␊ + throw new Error('This should never be executed or imported');␊ + }␊ + ␊ + var hoisted = 'this should be top-level';␊ + ␊ + /* eslint-disable global-require */␊ + ␊ + commonjsGlobal.false = false;␊ + commonjsGlobal.true = true;␊ + ␊ + if (commonjsGlobal.false) {␊ + requireThrows();␊ + }␊ + ␊ + if (commonjsGlobal.true) ; else {␊ + requireThrows();␊ + }␊ + ␊ + commonjsGlobal.false ? requireThrows() : null;␊ + commonjsGlobal.true ? null : requireThrows();␊ + ␊ + commonjsGlobal.false && requireThrows();␊ + commonjsGlobal.true || requireThrows();␊ + ␊ + function requireFunctionDeclaration() {␊ + requireThrows();␊ + }␊ + ␊ + const requireFunctionExpression = function () {␊ + requireThrows();␊ + };␊ + ␊ + const requireArrowFunction = () => requireThrows();␊ + ␊ + if (commonjsGlobal.false) {␊ + requireFunctionDeclaration();␊ + requireFunctionExpression();␊ + requireArrowFunction();␊ + }␊ + ␊ + // These should not cause wrapping␊ + t.is(␊ + (function () {␊ + return hoisted;␊ + })(),␊ + 'this should be top-level'␊ + );␊ + t.is((() => hoisted)(), 'this should be top-level');␊ + ␊ + module.exports = main;␊ + `, + } + ## strict-requires-entry-node-resolve > Snapshot 1 @@ -6052,15 +6154,29 @@ Generated by [AVA](https://avajs.dev). { 'main.js': `'use strict';␊ ␊ + var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};␊ + ␊ var main = {};␊ ␊ + var error = {};␊ + ␊ + var hasRequiredError;␊ + ␊ + function requireError () {␊ + if (hasRequiredError) return error;␊ + hasRequiredError = 1;␊ + throw new Error('FAIL');␊ + }␊ + ␊ var hasRequiredMain;␊ ␊ function requireMain () {␊ if (hasRequiredMain) return main;␊ hasRequiredMain = 1;␊ + commonjsGlobal.null = 0;␊ + ␊ // eslint-disable-next-line global-require␊ - t.is(0 , 0);␊ + t.is(commonjsGlobal.null && requireError(), 0);␊ return main;␊ }␊ ␊ @@ -6962,6 +7078,44 @@ Generated by [AVA](https://avajs.dev). `, } +## try-catch-internal + +> Snapshot 1 + + { + 'main.js': `'use strict';␊ + ␊ + var main = {};␊ + ␊ + var dep = {};␊ + ␊ + dep.foo = 'foo';␊ + ␊ + /* eslint-disable global-require */␊ + ␊ + try {␊ + t.is(dep.foo, 'foo');␊ + } catch (err) {␊ + throw new Error(`Could not require: ${err}`);␊ + }␊ + ␊ + module.exports = main;␊ + `, + } + +## try-catch-remove + +> Snapshot 1 + + { + 'main.js': `'use strict';␊ + ␊ + var main = {};␊ + ␊ + module.exports = main;␊ + `, + } + ## typeof-module-require > Snapshot 1 @@ -7031,39 +7185,44 @@ Generated by [AVA](https://avajs.dev). `, } -## try-catch-internal +## conditional-require-chain > Snapshot 1 { 'main.js': `'use strict';␊ ␊ + var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};␊ + ␊ var main = {};␊ ␊ var dep = {};␊ ␊ - dep.foo = 'foo';␊ + var throws = {};␊ ␊ - /* eslint-disable global-require */␊ + var hasRequiredThrows;␊ ␊ - try {␊ - t.is(dep.foo, 'foo');␊ - } catch (err) {␊ - throw new Error(`Could not require: ${err}`);␊ + function requireThrows () {␊ + if (hasRequiredThrows) return throws;␊ + hasRequiredThrows = 1;␊ + throw new Error('This should not be executed');␊ }␊ ␊ - module.exports = main;␊ - `, - } - -## try-catch-remove - -> Snapshot 1 - - { - 'main.js': `'use strict';␊ + var hasRequiredDep;␊ ␊ - var main = {};␊ + function requireDep () {␊ + if (hasRequiredDep) return dep;␊ + hasRequiredDep = 1;␊ + requireThrows();␊ + return dep;␊ + }␊ + ␊ + commonjsGlobal.false = false;␊ + ␊ + if (commonjsGlobal.false) {␊ + // eslint-disable-next-line global-require␊ + requireDep();␊ + }␊ ␊ module.exports = main;␊ `, diff --git a/packages/commonjs/test/snapshots/function.js.snap b/packages/commonjs/test/snapshots/function.js.snap index 568120c83..f09c75457 100644 Binary files a/packages/commonjs/test/snapshots/function.js.snap and b/packages/commonjs/test/snapshots/function.js.snap differ