diff --git a/__fixtures__/tsconfig.json b/__fixtures__/tsconfig.json new file mode 100644 index 00000000..9df43c15 --- /dev/null +++ b/__fixtures__/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../tsconfig" +} diff --git a/__fixtures__/tsconfig.json.d.mts b/__fixtures__/tsconfig.json.d.mts new file mode 100644 index 00000000..14a8b381 --- /dev/null +++ b/__fixtures__/tsconfig.json.d.mts @@ -0,0 +1,10 @@ +import type { TSConfig as Tsconfig } from '@flex-development/tsconfig-utils' + +/** + * TypeScript configuration. + * + * @const {Tsconfig} tsconfig + */ +declare const tsconfig: Tsconfig + +export default tsconfig diff --git a/package.json b/package.json index 47ac7d03..14a69b8a 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,10 @@ }, "imports": { "#build/*": "./build/*.mts", + "#fixtures/tsconfig*.json": { + "types": "./__fixtures__/tsconfig.json.d.mts", + "default": "./__fixtures__/tsconfig*.json" + }, "#fixtures/*": "./__fixtures__/*.mts", "#interfaces/*": { "mlly": "./src/interfaces/*.mts", diff --git a/src/internal/invalid-subpath.mts b/src/internal/invalid-subpath.mts index a27d9e32..2aa0819c 100644 --- a/src/internal/invalid-subpath.mts +++ b/src/internal/invalid-subpath.mts @@ -10,7 +10,6 @@ import { } from '@flex-development/errnode' import type { ModuleId } from '@flex-development/mlly' import { fileURLToPath } from '@flex-development/pathe' -import { ok } from 'devlop' /** * Create an {@linkcode ERR_INVALID_MODULE_SPECIFIER} error for an invalid @@ -41,8 +40,6 @@ function invalidSubpath( isImports?: boolean | null | undefined, parent?: ModuleId | null | undefined ): ErrInvalidModuleSpecifier { - ok(patternMatch, 'expected `patternMatch`') - return new ERR_INVALID_MODULE_SPECIFIER( subpath.replace(chars.asterisk, () => patternMatch), `request is not a valid match in pattern "${subpath}" for the ` + diff --git a/src/lib/__snapshots__/pattern-match.snap b/src/lib/__snapshots__/pattern-match.snap index 1791416d..be975c89 100644 --- a/src/lib/__snapshots__/pattern-match.snap +++ b/src/lib/__snapshots__/pattern-match.snap @@ -1,20 +1,27 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`unit:lib/patternMatch > should return \`PatternMatch\` if subpath pattern match is found (0) 1`] = ` +[ + "#fixtures/tsconfig*.json", + "", +] +`; + +exports[`unit:lib/patternMatch > should return \`PatternMatch\` if subpath pattern match is found (1) 1`] = ` [ "#lib/*", "pattern-match", ] `; -exports[`unit:lib/patternMatch > should return \`PatternMatch\` if subpath pattern match is found (1) 1`] = ` +exports[`unit:lib/patternMatch > should return \`PatternMatch\` if subpath pattern match is found (2) 1`] = ` [ "./lib/*.js", "a", ] `; -exports[`unit:lib/patternMatch > should return \`PatternMatch\` if subpath pattern match is found (2) 1`] = ` +exports[`unit:lib/patternMatch > should return \`PatternMatch\` if subpath pattern match is found (3) 1`] = ` [ "./package.json", null, diff --git a/src/lib/__snapshots__/resolver.snap b/src/lib/__snapshots__/resolver.snap index 44d61eac..49fbd634 100644 --- a/src/lib/__snapshots__/resolver.snap +++ b/src/lib/__snapshots__/resolver.snap @@ -2,50 +2,52 @@ exports[`unit:lib/resolver > legacyMainResolve > should throw if main entry point is not found 1`] = `Cannot find package '\${process.cwd()}/__fixtures__/node_modules/@flex-development/mlly/' imported from \${process.cwd()}/__fixtures__/parent.mts`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (0) 1`] = `"node:fs/promises"`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (0) 1`] = `file://\${process.cwd()}/__fixtures__/tsconfig.json`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (1) 1`] = `file://\${process.cwd()}/src/internal/fs.browser.mts`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (1) 1`] = `"node:fs/promises"`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (2) 1`] = `"node:path/posix"`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (2) 1`] = `file://\${process.cwd()}/src/internal/fs.browser.mts`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (3) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/subpath-imports/internal/path/windows.browser.mjs`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (3) 1`] = `"node:path/posix"`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (4) 1`] = `file://\${process.cwd()}/src/lib/resolver.mts`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (4) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/subpath-imports/internal/path/windows.browser.mjs`; exports[`unit:lib/resolver > moduleResolve > should return resolved URL (5) 1`] = `file://\${process.cwd()}/src/lib/resolver.mts`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (6) 1`] = `file://\${process.cwd()}/node_modules/@flex-development/mkbuild/dist/index.mjs`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (6) 1`] = `file://\${process.cwd()}/src/lib/resolver.mts`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (7) 1`] = `"node:fs"`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (7) 1`] = `file://\${process.cwd()}/node_modules/@flex-development/mkbuild/dist/index.mjs`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (8) 1`] = `"node:fs/promises"`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (8) 1`] = `"node:fs"`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (9) 1`] = `"node:url"`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (9) 1`] = `"node:fs/promises"`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (10) 1`] = `file://\${process.cwd()}/node_modules/vitest/dist/index.js`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (10) 1`] = `"node:url"`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (11) 1`] = `file://\${process.cwd()}/src/lib/index.mts`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (11) 1`] = `file://\${process.cwd()}/node_modules/vitest/dist/index.js`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (12) 1`] = `file://\${process.cwd()}/node_modules/@flex-development/errnode/dist/index.mjs`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (12) 1`] = `file://\${process.cwd()}/src/lib/index.mts`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (13) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/exports-sugar/index.mjs`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (13) 1`] = `file://\${process.cwd()}/node_modules/@flex-development/errnode/dist/index.mjs`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (14) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/exports-sugar-a/index.mjs`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (14) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/exports-sugar/index.mjs`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (15) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/legacy-main-1/a.js`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (15) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/exports-sugar-a/index.mjs`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (16) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/legacy-main-1/index.js`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (16) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/legacy-main-1/a.js`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (17) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/legacy-main-2/index.json`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (17) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/legacy-main-1/index.js`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (18) 1`] = `file://\${process.cwd()}/package.json`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (18) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/legacy-main-2/index.json`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (19) 1`] = `file://\${process.cwd()}/src/index.mts`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (19) 1`] = `file://\${process.cwd()}/package.json`; -exports[`unit:lib/resolver > moduleResolve > should return resolved URL (20) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/subpath-exports/lib/a.js`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (20) 1`] = `file://\${process.cwd()}/src/index.mts`; exports[`unit:lib/resolver > moduleResolve > should return resolved URL (21) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/subpath-exports/lib/a.js`; +exports[`unit:lib/resolver > moduleResolve > should return resolved URL (22) 1`] = `file://\${process.cwd()}/__fixtures__/node_modules/subpath-exports/lib/a.js`; + exports[`unit:lib/resolver > moduleResolve > should throw if \`specifier\` contains encoded separators 1`] = `Invalid module '/lib%2futils.mjs' must not include encoded "/" or "\\" characters imported from \${process.cwd()}/src/lib/__tests__/resolver.spec.mts`; exports[`unit:lib/resolver > moduleResolve > should throw if \`specifier\` resolves to a directory 1`] = `Directory import '\${process.cwd()}/src/' is not supported resolving ES modules imported from \${process.cwd()}/src/lib/__tests__/resolver.spec.mts`; diff --git a/src/lib/__tests__/pattern-match.spec.mts b/src/lib/__tests__/pattern-match.spec.mts index 7e4417f1..26f11c35 100644 --- a/src/lib/__tests__/pattern-match.spec.mts +++ b/src/lib/__tests__/pattern-match.spec.mts @@ -9,6 +9,7 @@ import pkg from '@flex-development/mlly/package.json' describe('unit:lib/patternMatch', () => { it.each>([ + ['#fixtures/tsconfig.json', pkg.imports], ['#lib/pattern-match', pkg.imports], ['./lib/a.js', subpathExports.exports], ['./package.json', pkg.exports] diff --git a/src/lib/__tests__/resolver.spec.mts b/src/lib/__tests__/resolver.spec.mts index 3671fc67..729c271b 100644 --- a/src/lib/__tests__/resolver.spec.mts +++ b/src/lib/__tests__/resolver.spec.mts @@ -56,6 +56,7 @@ describe('unit:lib/resolver', () => { describe('moduleResolve', () => { it.each>([ + ['#fixtures/tsconfig.json', import.meta.url], ['#internal/fs', import.meta.url, fixtureConditions], ['#internal/fs', import.meta.url, ['browser', ...fixtureConditions]], [ @@ -94,11 +95,16 @@ describe('unit:lib/resolver', () => { fs ) => { // Arrange - const expected: URL = baseline.moduleResolve( - specifier, - new URL(parent), - new Set(conditions ?? defaultConditions) - ) + let expected: URL | null = null + + // `import-meta-resolve` does not support empty pattern matches. + if (specifier !== '#fixtures/tsconfig.json') { + expected = baseline.moduleResolve( + specifier, + new URL(parent), + new Set(conditions ?? defaultConditions) + ) + } // Act const result = await testSubject.moduleResolve( @@ -111,7 +117,7 @@ describe('unit:lib/resolver', () => { ) // Expect - expect(result).to.eql(expected) + expect(result).to.eql(expected ?? result) expect(result).toMatchSnapshot() }) diff --git a/src/lib/pattern-match.mts b/src/lib/pattern-match.mts index 1bdfd3e2..8f6e53ac 100644 --- a/src/lib/pattern-match.mts +++ b/src/lib/pattern-match.mts @@ -86,7 +86,10 @@ function patternMatch( !patternTrailer.length || ( matchKey.endsWith(patternTrailer) && - matchKey.length >= expansionKey.length + ( + matchKey.length >= expansionKey.length || + matchKey === patternBase + patternTrailer + ) ) ) { return [ diff --git a/src/lib/resolver.mts b/src/lib/resolver.mts index 43e700e7..14c3b8e0 100644 --- a/src/lib/resolver.mts +++ b/src/lib/resolver.mts @@ -973,8 +973,8 @@ async function packageTargetResolve( } // replace `chars.asterisk` in `resolved` with `patternMatch` - if (patternMatch) { - if (checkInvalidSegments(patternMatch)) { + if (typeof patternMatch === 'string') { + if (patternMatch && checkInvalidSegments(patternMatch)) { throw invalidSubpath( subpath, patternMatch,