From aeaaf2e0697c6ab35c446d63856a642dd1282460 Mon Sep 17 00:00:00 2001 From: Mohamed Akram Date: Wed, 29 May 2024 22:18:49 +0400 Subject: [PATCH] fix: handling of default and star exports Fixes #77 Co-authored-by: Tim Fish --- hook.js | 190 ++++-------------- lib/get-esm-exports.js | 29 +-- lib/get-exports.js | 25 +-- package.json | 4 + test/fixtures/default-class.mjs | 3 - test/fixtures/duplicate-a.mjs | 4 + test/fixtures/duplicate-b.mjs | 1 + test/fixtures/duplicate.mjs | 5 + .../default-call-expression-renamed.mjs | 2 + .../export-types/default-call-expression.mjs | 1 + test/fixtures/got-alike.mjs | 6 - test/fixtures/snake_case.mjs | 2 - test/get-esm-exports/v20-get-esm-exports.js | 2 +- test/hook/default-export.mjs | 8 + test/hook/duplicate-exports.mjs | 19 ++ test/hook/v14-date-fns.mjs | 10 + test/hook/v14-react-email-components.mjs | 16 ++ test/hook/v16-got.mjs | 16 ++ test/hook/v18.19-openai.mjs | 10 + test/hook/v18.19-static-import-gotalike.mjs | 17 +- 20 files changed, 153 insertions(+), 217 deletions(-) delete mode 100644 test/fixtures/default-class.mjs create mode 100644 test/fixtures/duplicate-a.mjs create mode 100644 test/fixtures/duplicate-b.mjs create mode 100644 test/fixtures/duplicate.mjs create mode 100644 test/fixtures/export-types/default-call-expression-renamed.mjs create mode 100644 test/fixtures/export-types/default-call-expression.mjs delete mode 100644 test/fixtures/snake_case.mjs create mode 100644 test/hook/duplicate-exports.mjs create mode 100644 test/hook/v14-date-fns.mjs create mode 100644 test/hook/v14-react-email-components.mjs create mode 100644 test/hook/v16-got.mjs create mode 100644 test/hook/v18.19-openai.mjs diff --git a/hook.js b/hook.js index 9da900a..750640b 100644 --- a/hook.js +++ b/hook.js @@ -2,7 +2,6 @@ // // This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc. -const { randomBytes } = require('crypto') const { URL } = require('url') const specifiers = new Map() const isWin = process.platform === 'win32' @@ -20,7 +19,7 @@ let getExports if (NODE_MAJOR >= 20 || (NODE_MAJOR === 18 && NODE_MINOR >= 19)) { getExports = require('./lib/get-exports.js') } else { - getExports = ({ url }) => import(url).then(Object.keys) + getExports = (url) => import(url).then(Object.keys) } function hasIitm (url) { @@ -117,70 +116,37 @@ function isBareSpecifier (specifier) { } /** - * @typedef {object} ProcessedModule - * @property {string[]} imports A set of ESM import lines to be added to the - * shimmed module source. - * @property {string[]} namespaces A set of identifiers representing the - * modules in `imports`, e.g. for `import * as foo from 'bar'`, "foo" will be - * present in this array. - * @property {Map} setters The shimmed setters for all the - * exports from the module and any transitive export all modules. The key is - * used to deduplicate conflicting exports, assigning a priority to `default` - * exports. - */ - -/** - * Processes a module's exports and builds a set of new import statements, - * namespace names, and setter blocks. If an export all export if encountered, - * the target exports will be hoisted to the current module via a generated - * namespace. + * Processes a module's exports and builds a set of setter blocks. * * @param {object} params * @param {string} params.srcUrl The full URL to the module to process. * @param {object} params.context Provided by the loaders API. - * @param {Function} params.parentGetSource Provides the source code for the - * parent module. - * @param {string} [params.ns='namespace'] A string identifier that will be - * used as the namespace for the identifiers exported by the module. - * @param {string} [params.defaultAs='default'] The name to give the default - * identifier exported by the module (if one exists). This is really only - * useful in a recursive situation where a transitive module's default export - * needs to be renamed to the name of the module. + * @param {Function} params.parentGetSource Provides the source code for the parent module. + * @param {bool} params.excludeDefault Exclude the default export. * - * @returns {Promise} + * @returns {Promise>} The shimmed setters for all the exports + * from the module and any transitive export all modules. */ -async function processModule ({ - srcUrl, - context, - parentGetSource, - parentResolve, - ns = 'namespace', - defaultAs = 'default' -}) { - const exportNames = await getExports({ - url: srcUrl, - context, - parentLoad: parentGetSource, - defaultAs - }) - const imports = [`import * as ${ns} from ${JSON.stringify(srcUrl)}`] - const namespaces = [ns] - - // As we iterate found module exports we will add setter code blocks - // to this map that will eventually be inserted into the shim module's - // source code. We utilize a map in order to prevent duplicate exports. - // As a consequence of default renaming, it is possible that a file named - // `foo.mjs` which has `export function foo() {}` and `export default foo` - // exports will result in the "foo" export being defined twice in our shim. - // The map allows us to avoid this situation at the cost of losing the - // named export in favor of the default export. +async function processModule ({ srcUrl, context, parentGetSource, parentResolve, excludeDefault }) { + const exportNames = await getExports(srcUrl, context, parentGetSource) + const duplicates = new Set() const setters = new Map() + const addSetter = (name, setter) => { + // When doing an `import *` duplicates become undefined, so do the same + if (setters.has(name)) { + duplicates.add(name) + setters.delete(name) + } else if (!duplicates.has(name)) { + setters.set(name, setter) + } + } + for (const n of exportNames) { + if (n === 'default' && excludeDefault) continue + if (isStarExportLine(n) === true) { const [, modFile] = n.split('* from ') - const normalizedModName = normalizeModName(modFile) - const modName = Buffer.from(modFile, 'hex') + Date.now() + randomBytes(4).toString('hex') let modUrl if (isBareSpecifier(modFile)) { @@ -191,70 +157,28 @@ async function processModule ({ modUrl = new URL(modFile, srcUrl).href } - const data = await processModule({ + const setters = await processModule({ srcUrl: modUrl, context, parentGetSource, - parentResolve, - ns: `$${modName}`, - defaultAs: normalizedModName + excludeDefault: true }) - Array.prototype.push.apply(imports, data.imports) - Array.prototype.push.apply(namespaces, data.namespaces) - for (const [k, v] of data.setters.entries()) { - setters.set(k, v) + for (const [name, setter] of setters.entries()) { + addSetter(name, setter) } - - continue - } - - const matches = /^rename (.+) as (.+)$/.exec(n) - if (matches !== null) { - // Transitive modules that export a default identifier need to have - // that identifier renamed to the name of module. And our shim setter - // needs to utilize that new name while being initialized from the - // corresponding origin namespace. - const renamedExport = matches[2] - setters.set(`$${renamedExport}${ns}`, ` - let $${renamedExport} = ${ns}.default - export { $${renamedExport} as ${renamedExport} } - set.${renamedExport} = (v) => { - $${renamedExport} = v + } else { + addSetter(n, ` + let $${n} = _.${n} + export { $${n} as ${n} } + set.${n} = (v) => { + $${n} = v return true } `) - continue } - - setters.set(`$${n}` + ns, ` - let $${n} = ${ns}.${n} - export { $${n} as ${n} } - set.${n} = (v) => { - $${n} = v - return true - } - `) } - return { imports, namespaces, setters } -} - -/** - * Given a module name, e.g. 'foo-bar' or './foo-bar.js', normalize it to a - * string that is a valid JavaScript identifier, e.g. `fooBar`. Normalization - * means converting kebab-case to camelCase while removing any path tokens and - * file extensions. - * - * @param {string} name The module name to normalize. - * - * @returns {string} The normalized identifier. - */ -function normalizeModName (name) { - return name - .split('/') - .pop() - .replace(/(.+)\.(?:js|mjs)$/, '$1') - .replaceAll(/(-.)/g, x => x[1].toUpperCase()) + return setters } function addIitm (url) { @@ -312,61 +236,25 @@ function createHook (meta) { async function getSource (url, context, parentGetSource) { if (hasIitm(url)) { const realUrl = deleteIitm(url) - const { imports, namespaces, setters: mapSetters } = await processModule({ + const setters = await processModule({ srcUrl: realUrl, context, parentGetSource, parentResolve: cachedResolve }) - const setters = Array.from(mapSetters.values()) - - // When we encounter modules that re-export all identifiers from other - // modules, it is possible that the transitive modules export a default - // identifier. Due to us having to merge all transitive modules into a - // single common namespace, we need to recognize these default exports - // and remap them to a name based on the module name. This prevents us - // from overriding the top-level module's (the one actually being imported - // by some source code) default export when we merge the namespaces. - const renamedDefaults = setters - .map(s => { - const matches = /let \$(.+) = (\$.+)\.default/.exec(s) - if (matches === null) return undefined - return `_['${matches[1]}'] = ${matches[2]}.default` - }) - .filter(s => s) - - // The for loops are how we merge namespaces into a common namespace that - // can be proxied. We can't use a simple `Object.assign` style merging - // because transitive modules can export a default identifier that would - // override the desired default identifier. So we need to do manual - // merging with some logic around default identifiers. - // - // Additionally, we need to make sure any renamed default exports in - // transitive dependencies are added to the common namespace. This is - // accomplished through the `renamedDefaults` array. return { source: ` import { register } from '${iitmURL}' -${imports.join('\n')} +import * as namespace from ${JSON.stringify(realUrl)} -const namespaces = [${namespaces.join(', ')}] // Mimic a Module object (https://tc39.es/ecma262/#sec-module-namespace-objects). -const _ = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } }) +const _ = Object.assign( + Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } }), + namespace +) const set = {} -const primary = namespaces.shift() -for (const [k, v] of Object.entries(primary)) { - _[k] = v -} -for (const ns of namespaces) { - for (const [k, v] of Object.entries(ns)) { - if (k === 'default') continue - _[k] = v - } -} - -${setters.join('\n')} -${renamedDefaults.join('\n')} +${Array.from(setters.values()).join('\n')} register(${JSON.stringify(realUrl)}, _, set, ${JSON.stringify(specifiers.get(realUrl))}) ` diff --git a/lib/get-esm-exports.js b/lib/get-esm-exports.js index 1749b48..9c88ac8 100644 --- a/lib/get-esm-exports.js +++ b/lib/get-esm-exports.js @@ -18,30 +18,21 @@ function warn (txt) { * Utilizes an AST parser to interpret ESM source code and build a list of * exported identifiers. In the baseline case, the list of identifiers will be * the simple identifier names as written in the source code of the module. - * However, there are some special cases: + * However, there is a special case: * - * 1. When an `export * from './foo.js'` line is encountered it is rewritten + * When an `export * from './foo.js'` line is encountered it is rewritten * as `* from ./foo.js`. This allows the interpreting code to recognize a * transitive export and recursively parse the indicated module. The returned * identifier list will have "* from ./foo.js" as an item. * - * 2. When `defaultAs` has a value other than 'default', the export line will - * be rewritten as `rename as `. This rename string - * will be an item in the returned identifier list. - * * @param {object} params * @param {string} params.moduleSource The source code of the module to parse * and interpret. - * @param {string} [defaultAs='default'] When anything other than 'default' any - * `export default` lines will be rewritten utilizing the value provided. For - * example, if a module 'foo-bar.js' has the line `export default foo` and the - * value of this parameter is 'baz', then the export will be rewritten to - * `rename foo as baz`. * * @returns {string[]} The identifiers exported by the module along with any * custom directives. */ -function getEsmExports ({ moduleSource, defaultAs = 'default' }) { +function getEsmExports (moduleSource) { const exportedNames = new Set() const tree = parser.parse(moduleSource, acornOpts) for (const node of tree.body) { @@ -56,19 +47,7 @@ function getEsmExports ({ moduleSource, defaultAs = 'default' }) { break case 'ExportDefaultDeclaration': { - if (defaultAs === 'default') { - exportedNames.add('default') - break - } - - if (node.declaration.type.toLowerCase() === 'identifier') { - // e.g. `export default foo` - exportedNames.add(`rename ${node.declaration.name} as ${defaultAs}`) - } else { - // e.g. `export function foo () {} - exportedNames.add(`rename ${node.declaration.id.name} as ${defaultAs}`) - } - + exportedNames.add('default') break } diff --git a/lib/get-exports.js b/lib/get-exports.js index 59ea5cc..7616e6c 100644 --- a/lib/get-exports.js +++ b/lib/get-exports.js @@ -20,13 +20,13 @@ async function getFullCjsExports (url, context, parentLoad, source) { const ex = getCjsExports(source) const full = Array.from(new Set([ ...addDefault(ex.exports), - ...(await Promise.all(ex.reexports.map(re => getExports(({ - url: (/^(..?($|\/|\\))/).test(re) + ...(await Promise.all(ex.reexports.map(re => getExports( + (/^(..?($|\/|\\))/).test(re) ? pathToFileURL(require.resolve(fileURLToPath(new URL(re, url)))).toString() : pathToFileURL(require.resolve(re)).toString(), context, parentLoad - }))))).flat() + )))).flat() ])) urlsBeingProcessed.delete(url) @@ -38,25 +38,18 @@ async function getFullCjsExports (url, context, parentLoad, source) { * source code for said module from the loader API, and parses the result * for the entities exported from that module. * - * @param {object} params - * @param {string} params.url A file URL string pointing to the module that + * @param {string} url A file URL string pointing to the module that * we should get the exports of. - * @param {object} params.context Context object as provided by the `load` + * @param {object} context Context object as provided by the `load` * hook from the loaders API. - * @param {Function} params.parentLoad Next hook function in the loaders API + * @param {Function} parentLoad Next hook function in the loaders API * hook chain. - * @param {string} [defaultAs='default'] When anything other than 'default', - * will trigger remapping of default exports in ESM source files to the - * provided name. For example, if a submodule has `export default foo` and - * 'myFoo' is provided for this parameter, the export line will be rewritten - * to `rename foo as myFoo`. This is key to being able to support - * `export * from 'something'` exports. * * @returns {Promise} An array of identifiers exported by the module. * Please see {@link getEsmExports} for caveats on special identifiers that may * be included in the result set. */ -async function getExports ({ url, context, parentLoad, defaultAs = 'default' }) { +async function getExports (url, context, parentLoad) { // `parentLoad` gives us the possibility of getting the source // from an upstream loader. This doesn't always work though, // so later on we fall back to reading it from disk. @@ -77,7 +70,7 @@ async function getExports ({ url, context, parentLoad, defaultAs = 'default' }) } if (format === 'module') { - return getEsmExports({ moduleSource: source, defaultAs }) + return getEsmExports(source) } if (format === 'commonjs') { return getFullCjsExports(url, context, parentLoad, source) @@ -85,7 +78,7 @@ async function getExports ({ url, context, parentLoad, defaultAs = 'default' }) // At this point our `format` is either undefined or not known by us. Fall // back to parsing as ESM/CJS. - const esmExports = getEsmExports({ moduleSource: source, defaultAs }) + const esmExports = getEsmExports(source) if (!esmExports.length) { // TODO(bengl) it's might be possible to get here if somehow the format // isn't set at first and yet we have an ESM module with no exports. diff --git a/package.json b/package.json index 2daef3d..2b6ede2 100644 --- a/package.json +++ b/package.json @@ -36,15 +36,19 @@ "@babel/core": "^7.23.7", "@babel/eslint-parser": "^7.23.3", "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@react-email/components": "^0.0.19", "@types/node": "^18.0.6", "c8": "^7.8.0", + "date-fns": "^3.6.0", "eslint": "^8.55.0", "eslint-config-standard": "^17.1.0", "eslint-plugin-import": "^2.29.0", "eslint-plugin-n": "^16.4.0", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^6.1.1", + "got": "^14.3.0", "imhotap": "^2.1.0", + "openai": "^4.47.2", "ts-node": "^10.9.1", "typescript": "^4.7.4" }, diff --git a/test/fixtures/default-class.mjs b/test/fixtures/default-class.mjs deleted file mode 100644 index 6c3d0f8..0000000 --- a/test/fixtures/default-class.mjs +++ /dev/null @@ -1,3 +0,0 @@ -export default class DefaultClass { - value = 'DefaultClass' -} diff --git a/test/fixtures/duplicate-a.mjs b/test/fixtures/duplicate-a.mjs new file mode 100644 index 0000000..8cd09a5 --- /dev/null +++ b/test/fixtures/duplicate-a.mjs @@ -0,0 +1,4 @@ +export const foo = 'a' +export default function () { + return 'c' +} diff --git a/test/fixtures/duplicate-b.mjs b/test/fixtures/duplicate-b.mjs new file mode 100644 index 0000000..a41341d --- /dev/null +++ b/test/fixtures/duplicate-b.mjs @@ -0,0 +1 @@ +export const foo = 'a' diff --git a/test/fixtures/duplicate.mjs b/test/fixtures/duplicate.mjs new file mode 100644 index 0000000..0ff4f03 --- /dev/null +++ b/test/fixtures/duplicate.mjs @@ -0,0 +1,5 @@ +export * from './duplicate-a.mjs' +export * from './duplicate-b.mjs' + +const foo = 'foo' +export default foo diff --git a/test/fixtures/export-types/default-call-expression-renamed.mjs b/test/fixtures/export-types/default-call-expression-renamed.mjs new file mode 100644 index 0000000..a4b9565 --- /dev/null +++ b/test/fixtures/export-types/default-call-expression-renamed.mjs @@ -0,0 +1,2 @@ +export * from './default-call-expression.mjs' +export { default as somethingElse } from './default-call-expression.mjs' diff --git a/test/fixtures/export-types/default-call-expression.mjs b/test/fixtures/export-types/default-call-expression.mjs new file mode 100644 index 0000000..0740895 --- /dev/null +++ b/test/fixtures/export-types/default-call-expression.mjs @@ -0,0 +1 @@ +export default parseInt('1') diff --git a/test/fixtures/got-alike.mjs b/test/fixtures/got-alike.mjs index 68a719a..dd94f62 100644 --- a/test/fixtures/got-alike.mjs +++ b/test/fixtures/got-alike.mjs @@ -1,7 +1,3 @@ -// The purpose of this fixture is to replicate a situation where we may -// end up exporting `default` twice: first from this script itself and second -// via the `export * from` line. -// // This replicates the way the in-the-wild `got` module does things: // https://github.com/sindresorhus/got/blob/3822412/source/index.ts @@ -12,6 +8,4 @@ class got { export default got export { got } export * from './something.mjs' -export * from './default-class.mjs' -export * from './snake_case.mjs' export { default as renamedDefaultExport } from './lib/baz.mjs' diff --git a/test/fixtures/snake_case.mjs b/test/fixtures/snake_case.mjs deleted file mode 100644 index 003c28d..0000000 --- a/test/fixtures/snake_case.mjs +++ /dev/null @@ -1,2 +0,0 @@ -const snakeCase = 'snake_case' -export default snakeCase diff --git a/test/get-esm-exports/v20-get-esm-exports.js b/test/get-esm-exports/v20-get-esm-exports.js index ad003cd..0d03214 100644 --- a/test/get-esm-exports/v20-get-esm-exports.js +++ b/test/get-esm-exports/v20-get-esm-exports.js @@ -15,7 +15,7 @@ fixture.split('\n').forEach(line => { if (expectedNames[0] === '') { expectedNames.length = 0 } - const names = getEsmExports({ moduleSource: mod }) + const names = getEsmExports(mod) assert.deepEqual(expectedNames, names) console.log(`${mod}\n ✅ contains exports: ${testStr}`) }) diff --git a/test/hook/default-export.mjs b/test/hook/default-export.mjs index 56ed78a..ae873d5 100644 --- a/test/hook/default-export.mjs +++ b/test/hook/default-export.mjs @@ -12,6 +12,8 @@ import gfn from '../fixtures/export-types/default-generator.mjs' import afn from '../fixtures/export-types/default-function-anon.mjs' import acn from '../fixtures/export-types/default-class-anon.mjs' import agfn from '../fixtures/export-types/default-generator-anon.mjs' +import callEx from '../fixtures/export-types/default-call-expression.mjs' +import { somethingElse } from '../fixtures/export-types/default-call-expression-renamed.mjs' import defaultImportExport from '../fixtures/export-types/import-default-export.mjs' import varDefaultExport from '../fixtures/export-types/variable-default-export.mjs' import { strictEqual } from 'assert' @@ -61,6 +63,10 @@ Hook((exports, name) => { exports.default = function () { return orig4() + 1 } + } else if (name.match(/default-call-expression\.m?js/)) { + exports.default += 1 + } else if (name.match(/default-call-expression-renamed\.m?js/)) { + exports.somethingElse += 1 } }) @@ -76,3 +82,5 @@ strictEqual(new acn().getFoo(), 2) strictEqual(agfn().next().value, 2) strictEqual(n, 2) strictEqual(s, 'dogdawg') +strictEqual(callEx, 2) +strictEqual(somethingElse, 2) diff --git a/test/hook/duplicate-exports.mjs b/test/hook/duplicate-exports.mjs new file mode 100644 index 0000000..2011602 --- /dev/null +++ b/test/hook/duplicate-exports.mjs @@ -0,0 +1,19 @@ +import * as lib from '../fixtures/duplicate.mjs' +import { notEqual, strictEqual } from 'assert' +import Hook from '../../index.js' + +Hook((exports, name) => { + if (name.match(/duplicate\.mjs/)) { + // foo should not be exported because there are duplicate exports + strictEqual(exports.foo, undefined) + // default should be exported + strictEqual(exports.default, 'foo') + } +}) + +notEqual(lib, undefined) + +// foo should not be exported because there are duplicate exports +strictEqual(lib.foo, undefined) +// default should be exported +strictEqual(lib.default, 'foo') diff --git a/test/hook/v14-date-fns.mjs b/test/hook/v14-date-fns.mjs new file mode 100644 index 0000000..27f75a7 --- /dev/null +++ b/test/hook/v14-date-fns.mjs @@ -0,0 +1,10 @@ +import { format, parse } from 'date-fns' +import Hook from '../../index.js' + +Hook((exports, name) => { + if (name === 'date-fns') { + // + } +}) + +console.assert(format, parse) diff --git a/test/hook/v14-react-email-components.mjs b/test/hook/v14-react-email-components.mjs new file mode 100644 index 0000000..56d99d7 --- /dev/null +++ b/test/hook/v14-react-email-components.mjs @@ -0,0 +1,16 @@ +import * as lib from '@react-email/components' +import { Heading } from '@react-email/components' +import Hook from '../../index.js' +import { strictEqual } from 'assert' + +Hook((exports, name) => { + if (name.match(/@react-email\/components/)) { + exports.Heading = function wrappedHeading () { + return 'heading-wrapped' + } + } +}) + +strictEqual(typeof lib.Button, 'function') +strictEqual(lib.Heading(), 'heading-wrapped') +strictEqual(Heading(), 'heading-wrapped') diff --git a/test/hook/v16-got.mjs b/test/hook/v16-got.mjs new file mode 100644 index 0000000..2ec0ce6 --- /dev/null +++ b/test/hook/v16-got.mjs @@ -0,0 +1,16 @@ +import got, { Options } from 'got' +import { strictEqual } from 'assert' +import Hook from '../../index.js' + +Hook((exports, name) => { + if (name === 'got' && 'Options' in exports) { + exports.Options = 'nothing' + } +}) + +strictEqual(typeof got, 'function') +strictEqual(typeof got.post, 'function') +strictEqual(typeof got.stream, 'function') +strictEqual(typeof got.extend, 'function') + +strictEqual(Options, 'nothing') diff --git a/test/hook/v18.19-openai.mjs b/test/hook/v18.19-openai.mjs new file mode 100644 index 0000000..9e0dcb6 --- /dev/null +++ b/test/hook/v18.19-openai.mjs @@ -0,0 +1,10 @@ +import OpenAI from 'openai' +import Hook from '../../index.js' + +Hook((exports, name) => { + if (name === 'openai') { + console.assert(name, exports) + } +}) + +console.assert(OpenAI) diff --git a/test/hook/v18.19-static-import-gotalike.mjs b/test/hook/v18.19-static-import-gotalike.mjs index c6ec006..906cf59 100644 --- a/test/hook/v18.19-static-import-gotalike.mjs +++ b/test/hook/v18.19-static-import-gotalike.mjs @@ -3,10 +3,8 @@ import Hook from '../../index.js' Hook((exports, name) => { if (/got-alike\.mjs/.test(name) === false) return - const bar = exports.something - exports.something = function barWrapped () { - return bar() + '-wrapped' - } + const foo = exports.foo + exports.foo = foo + '-wrapped' const renamedDefaultExport = exports.renamedDefaultExport exports.renamedDefaultExport = function bazWrapped () { @@ -15,21 +13,14 @@ Hook((exports, name) => { }) /* eslint-disable import/no-named-default */ -/* eslint-disable camelcase */ import { default as Got, - something, - defaultClass as DefaultClass, - snake_case, + foo, renamedDefaultExport } from '../fixtures/got-alike.mjs' -strictEqual(something(), '42-wrapped') +strictEqual(foo, '42-wrapped') const got = new Got() strictEqual(got.foo, 'foo') -const dc = new DefaultClass() -strictEqual(dc.value, 'DefaultClass') - -strictEqual(snake_case, 'snake_case') strictEqual(renamedDefaultExport(), 'baz-wrapped')