From 03fb3523a9d58f0a344a3592466a262fa8dc1da3 Mon Sep 17 00:00:00 2001 From: Marcin Szczepanski Date: Tue, 24 May 2022 00:12:15 +1000 Subject: [PATCH] Support using packages in imports resolved by the glob resolver (#8097) --- packages/core/integration-tests/test/glob.js | 43 ++++++++ .../integration/glob-package-async/.parcelrc | 4 + .../integration/glob-package-async/index.js | 6 ++ .../node_modules/@scope/pkg/foo/a.js | 1 + .../node_modules/@scope/pkg/foo/b.js | 1 + .../node_modules/@scope/pkg/index.js | 0 .../node_modules/@scope/pkg/package.json | 4 + .../node_modules/pkg/bar/x.js | 1 + .../node_modules/pkg/bar/y.js | 1 + .../node_modules/pkg/index.js | 0 .../node_modules/pkg/package.json | 4 + .../integration/glob-package-async/yarn.lock | 0 .../test/integration/glob-package/.parcelrc | 4 + .../test/integration/glob-package/index.js | 6 ++ .../node_modules/@scope/pkg/foo/a.js | 1 + .../node_modules/@scope/pkg/foo/b.js | 1 + .../node_modules/@scope/pkg/index.js | 0 .../node_modules/@scope/pkg/package.json | 4 + .../glob-package/node_modules/pkg/bar/x.js | 1 + .../glob-package/node_modules/pkg/bar/y.js | 1 + .../glob-package/node_modules/pkg/index.js | 0 .../node_modules/pkg/package.json | 4 + .../test/integration/glob-package/yarn.lock | 0 packages/resolvers/glob/package.json | 1 + packages/resolvers/glob/src/GlobResolver.js | 97 +++++++++++++++---- 25 files changed, 167 insertions(+), 18 deletions(-) create mode 100644 packages/core/integration-tests/test/integration/glob-package-async/.parcelrc create mode 100644 packages/core/integration-tests/test/integration/glob-package-async/index.js create mode 100644 packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/foo/a.js create mode 100644 packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/foo/b.js create mode 100644 packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/index.js create mode 100644 packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/package.json create mode 100644 packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/bar/x.js create mode 100644 packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/bar/y.js create mode 100644 packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/index.js create mode 100644 packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/package.json create mode 100644 packages/core/integration-tests/test/integration/glob-package-async/yarn.lock create mode 100644 packages/core/integration-tests/test/integration/glob-package/.parcelrc create mode 100644 packages/core/integration-tests/test/integration/glob-package/index.js create mode 100644 packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/foo/a.js create mode 100644 packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/foo/b.js create mode 100644 packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/index.js create mode 100644 packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/package.json create mode 100644 packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/bar/x.js create mode 100644 packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/bar/y.js create mode 100644 packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/index.js create mode 100644 packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/package.json create mode 100644 packages/core/integration-tests/test/integration/glob-package/yarn.lock diff --git a/packages/core/integration-tests/test/glob.js b/packages/core/integration-tests/test/glob.js index 5dedf87cb11..15f3fb1bb4d 100644 --- a/packages/core/integration-tests/test/glob.js +++ b/packages/core/integration-tests/test/glob.js @@ -203,4 +203,47 @@ describe('glob', function () { ], }); }); + + it('should require a glob of files from a package', async function () { + let b = await bundle( + path.join(__dirname, '/integration/glob-package/index.js'), + ); + await assertBundles(b, [ + { + name: 'index.js', + assets: ['*.js', '*.js', 'a.js', 'b.js', 'x.js', 'y.js', 'index.js'], + }, + ]); + + let output = await run(b); + assert.equal(typeof output, 'function'); + assert.equal(await output(), 10); + }); + + it('should require a glob of files from a package async', async function () { + let b = await bundle( + path.join(__dirname, '/integration/glob-package-async/index.js'), + ); + await assertBundles(b, [ + { + name: 'index.js', + assets: [ + '*.js', + '*.js', + 'bundle-url.js', + 'cacheLoader.js', + 'index.js', + 'js-loader.js', + ], + }, + {type: 'js', assets: ['a.js']}, + {type: 'js', assets: ['b.js']}, + {type: 'js', assets: ['x.js']}, + {type: 'js', assets: ['y.js']}, + ]); + + let output = await run(b); + assert.equal(typeof output, 'function'); + assert.equal(await output(), 10); + }); }); diff --git a/packages/core/integration-tests/test/integration/glob-package-async/.parcelrc b/packages/core/integration-tests/test/integration/glob-package-async/.parcelrc new file mode 100644 index 00000000000..44d567b5c69 --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package-async/.parcelrc @@ -0,0 +1,4 @@ +{ + "extends": "@parcel/config-default", + "resolvers": ["@parcel/resolver-glob", "..."] +} diff --git a/packages/core/integration-tests/test/integration/glob-package-async/index.js b/packages/core/integration-tests/test/integration/glob-package-async/index.js new file mode 100644 index 00000000000..a8995ba3b2c --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package-async/index.js @@ -0,0 +1,6 @@ +const scoped = import('@scope/pkg/foo/*.js'); +const unscoped = import('pkg/bar/*.js'); + +module.exports = async function () { + return await scoped.a() + await scoped.b() + await unscoped.x() + await unscoped.y(); +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/foo/a.js b/packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/foo/a.js new file mode 100644 index 00000000000..c8bfc30c221 --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/foo/a.js @@ -0,0 +1 @@ +module.exports = 1; \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/foo/b.js b/packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/foo/b.js new file mode 100644 index 00000000000..d6fbb1723e4 --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/foo/b.js @@ -0,0 +1 @@ +module.exports = 2; \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/index.js b/packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/index.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/package.json b/packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/package.json new file mode 100644 index 00000000000..09fcae8572f --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package-async/node_modules/@scope/pkg/package.json @@ -0,0 +1,4 @@ +{ + "name": "@scope/pkg", + "module": "index.js" +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/bar/x.js b/packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/bar/x.js new file mode 100644 index 00000000000..678d19e15e0 --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/bar/x.js @@ -0,0 +1 @@ +module.exports = 3; \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/bar/y.js b/packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/bar/y.js new file mode 100644 index 00000000000..32c87826a5d --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/bar/y.js @@ -0,0 +1 @@ +module.exports = 4; \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/index.js b/packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/index.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/package.json b/packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/package.json new file mode 100644 index 00000000000..5bc2b5b05bd --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package-async/node_modules/pkg/package.json @@ -0,0 +1,4 @@ +{ + "name": "pkg", + "module": "index.js" +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/glob-package-async/yarn.lock b/packages/core/integration-tests/test/integration/glob-package-async/yarn.lock new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/core/integration-tests/test/integration/glob-package/.parcelrc b/packages/core/integration-tests/test/integration/glob-package/.parcelrc new file mode 100644 index 00000000000..44d567b5c69 --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package/.parcelrc @@ -0,0 +1,4 @@ +{ + "extends": "@parcel/config-default", + "resolvers": ["@parcel/resolver-glob", "..."] +} diff --git a/packages/core/integration-tests/test/integration/glob-package/index.js b/packages/core/integration-tests/test/integration/glob-package/index.js new file mode 100644 index 00000000000..015a2cfa275 --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package/index.js @@ -0,0 +1,6 @@ +const scoped = require('@scope/pkg/foo/*.js'); +const unscoped = require('pkg/bar/*.js'); + +module.exports = function () { + return scoped.a + scoped.b + unscoped.x + unscoped.y; +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/foo/a.js b/packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/foo/a.js new file mode 100644 index 00000000000..c8bfc30c221 --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/foo/a.js @@ -0,0 +1 @@ +module.exports = 1; \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/foo/b.js b/packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/foo/b.js new file mode 100644 index 00000000000..d6fbb1723e4 --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/foo/b.js @@ -0,0 +1 @@ +module.exports = 2; \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/index.js b/packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/index.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/package.json b/packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/package.json new file mode 100644 index 00000000000..09fcae8572f --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package/node_modules/@scope/pkg/package.json @@ -0,0 +1,4 @@ +{ + "name": "@scope/pkg", + "module": "index.js" +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/bar/x.js b/packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/bar/x.js new file mode 100644 index 00000000000..678d19e15e0 --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/bar/x.js @@ -0,0 +1 @@ +module.exports = 3; \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/bar/y.js b/packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/bar/y.js new file mode 100644 index 00000000000..32c87826a5d --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/bar/y.js @@ -0,0 +1 @@ +module.exports = 4; \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/index.js b/packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/index.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/package.json b/packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/package.json new file mode 100644 index 00000000000..5bc2b5b05bd --- /dev/null +++ b/packages/core/integration-tests/test/integration/glob-package/node_modules/pkg/package.json @@ -0,0 +1,4 @@ +{ + "name": "pkg", + "module": "index.js" +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/glob-package/yarn.lock b/packages/core/integration-tests/test/integration/glob-package/yarn.lock new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/resolvers/glob/package.json b/packages/resolvers/glob/package.json index 629b8572fb7..06db6649d71 100644 --- a/packages/resolvers/glob/package.json +++ b/packages/resolvers/glob/package.json @@ -21,6 +21,7 @@ }, "dependencies": { "@parcel/diagnostic": "2.5.0", + "@parcel/node-resolver-core": "2.5.0", "@parcel/plugin": "2.5.0", "@parcel/utils": "2.5.0", "nullthrows": "^1.1.1" diff --git a/packages/resolvers/glob/src/GlobResolver.js b/packages/resolvers/glob/src/GlobResolver.js index 1ccf10842ba..cc37739a48e 100644 --- a/packages/resolvers/glob/src/GlobResolver.js +++ b/packages/resolvers/glob/src/GlobResolver.js @@ -10,9 +10,31 @@ import { import path from 'path'; import nullthrows from 'nullthrows'; import ThrowableDiagnostic from '@parcel/diagnostic'; +import NodeResolver from '@parcel/node-resolver-core'; +import invariant from 'assert'; + +function errorToThrowableDiagnostic(error, dependency): ThrowableDiagnostic { + return new ThrowableDiagnostic({ + diagnostic: { + message: error, + codeFrames: dependency.loc + ? [ + { + codeHighlights: [ + { + start: dependency.loc.start, + end: dependency.loc.end, + }, + ], + }, + ] + : undefined, + }, + }); +} export default (new Resolver({ - async resolve({dependency, options, specifier, pipeline}) { + async resolve({dependency, options, specifier, pipeline, logger}) { if (!isGlob(specifier)) { return; } @@ -33,26 +55,65 @@ export default (new Resolver({ } if (error) { - throw new ThrowableDiagnostic({ - diagnostic: { - message: error, - codeFrames: dependency.loc - ? [ - { - codeHighlights: [ - { - start: dependency.loc.start, - end: dependency.loc.end, - }, - ], - }, - ] - : undefined, - }, + throw errorToThrowableDiagnostic(error, dependency); + } + + // if the specifier does not start with /, ~, or . then it's not a path but package-ish - we resolve + // the package first, and then append the rest of the path + if (!/^[/~.]/.test(specifier)) { + // Globs are not paths - so they always use / (see https://github.com/micromatch/micromatch#backslashes) + let splitOn = specifier.indexOf('/'); + if (specifier.charAt(0) === '@') { + splitOn = specifier.indexOf('/', splitOn + 1); + } + + // Since we've already asserted earlier that there is a glob present, it shouldn't be + // possible for there to be only a package here without any other path parts (e.g. `import('pkg')`) + invariant(splitOn !== -1); + + let pkg = specifier.substring(0, splitOn); + let rest = specifier.substring(splitOn + 1); + + // This initialisation code is copied from the DefaultResolver + const resolver = new NodeResolver({ + fs: options.inputFS, + projectRoot: options.projectRoot, + // Extensions are always required in URL dependencies. + extensions: + dependency.specifierType === 'commonjs' || + dependency.specifierType === 'esm' + ? ['ts', 'tsx', 'js', 'jsx', 'json'] + : [], + mainFields: ['source', 'browser', 'module', 'main'], + packageManager: options.shouldAutoInstall + ? options.packageManager + : undefined, + logger, + }); + + const result = await resolver.resolve({ + filename: pkg, + specifierType: dependency.specifierType, + parent: dependency.resolveFrom, + env: dependency.env, + sourcePath: dependency.sourcePath, + loc: dependency.loc, }); + + if (!result || !result.filePath) { + throw errorToThrowableDiagnostic( + `Unable to resolve ${pkg} from ${sourceFile} when evaluating specifier ${specifier}`, + dependency, + ); + } else if (result.diagnostics) { + throw new ThrowableDiagnostic({diagnostic: result.diagnostics}); + } + + specifier = path.resolve(path.dirname(result.filePath), rest); + } else { + specifier = path.resolve(path.dirname(sourceFile), specifier); } - specifier = path.resolve(path.dirname(sourceFile), specifier); let normalized = normalizeSeparators(specifier); let files = await glob(normalized, options.inputFS, { onlyFiles: true,