Skip to content
This repository has been archived by the owner on Oct 18, 2023. It is now read-only.

Commit

Permalink
fix: support query in specifier (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
privatenumber authored Sep 17, 2023
1 parent a237b20 commit dcf4dd9
Show file tree
Hide file tree
Showing 11 changed files with 112 additions and 17 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"prepack": "pnpm build && clean-pkg-json"
},
"dependencies": {
"@esbuild-kit/core-utils": "^3.3.0",
"@esbuild-kit/core-utils": "^3.3.2",
"get-tsconfig": "^4.7.0"
},
"devDependencies": {
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions src/loaders-deprecated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
tsExtensionsPattern,
getFormatFromFileUrl,
fileProtocol,
isJsonPattern,
type MaybePromise,
type NodeError,
} from './utils.js';
Expand All @@ -32,7 +33,7 @@ const _getFormat: getFormat = async function (
context,
defaultGetFormat,
) {
if (url.endsWith('.json')) {
if (isJsonPattern.test(url)) {
return { format: 'module' };
}

Expand Down Expand Up @@ -80,7 +81,7 @@ const _transformSource: transformSource = async function (
}

if (
url.endsWith('.json')
isJsonPattern.test(url)
|| tsExtensionsPattern.test(url)
) {
const transformed = await transform(
Expand Down
15 changes: 10 additions & 5 deletions src/loaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ import {
tsconfigPathsMatcher,
fileMatcher,
tsExtensionsPattern,
isJsonPattern,
getFormatFromFileUrl,
fileProtocol,
type MaybePromise,
type NodeError,
} from './utils.js';

const isDirectoryPattern = /\/(?:$|\?)/;

type NextResolve = (
specifier: string,
context?: ResolveHookContext,
Expand Down Expand Up @@ -75,11 +78,12 @@ async function tryExtensions(
context: ResolveHookContext,
defaultResolve: NextResolve,
) {
const [specifierWithoutQuery, query] = specifier.split('?');
let throwError: Error | undefined;
for (const extension of extensions) {
try {
return await resolve(
specifier + extension,
specifierWithoutQuery + extension + (query ? `?${query}` : ''),
context,
defaultResolve,
true,
Expand All @@ -105,11 +109,12 @@ async function tryDirectory(
context: ResolveHookContext,
defaultResolve: NextResolve,
) {
const isExplicitDirectory = specifier.endsWith('/');
const isExplicitDirectory = isDirectoryPattern.test(specifier);
const appendIndex = isExplicitDirectory ? 'index' : '/index';
const [specifierWithoutQuery, query] = specifier.split('?');

try {
return await tryExtensions(specifier + appendIndex, context, defaultResolve);
return await tryExtensions(specifierWithoutQuery + appendIndex + (query ? `?${query}` : ''), context, defaultResolve);
} catch (_error) {
if (!isExplicitDirectory) {
try {
Expand Down Expand Up @@ -145,7 +150,7 @@ export const resolve: resolve = async function (
}

// If directory, can be index.js, index.ts, etc.
if (specifier.endsWith('/')) {
if (isDirectoryPattern.test(specifier)) {
return await tryDirectory(specifier, context, defaultResolve);
}

Expand Down Expand Up @@ -243,7 +248,7 @@ export const load: LoadHook = async function (
});
}

if (url.endsWith('.json')) {
if (isJsonPattern.test(url)) {
if (!context.importAssertions) {
context.importAssertions = {};
}
Expand Down
4 changes: 3 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ export const tsconfigPathsMatcher = tsconfig && createPathsMatcher(tsconfig);

export const fileProtocol = 'file://';

export const tsExtensionsPattern = /\.([cm]?ts|[tj]sx)$/;
export const tsExtensionsPattern = /\.([cm]?ts|[tj]sx)($|\?)/;

export const isJsonPattern = /\.json(?:$|\?)/;

const getFormatFromExtension = (fileUrl: string): ModuleFormat | undefined => {
const extension = path.extname(fileUrl);
Expand Down
13 changes: 13 additions & 0 deletions tests/specs/javascript/esm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import semver from 'semver';
import type { NodeApis } from '../../utils/node-with-loader.js';
import nodeSupports from '../../utils/node-supports.js';
import { assertNotFound } from '../../utils/assertions.js';
import { query } from '../../utils/query.js';

export default testSuite(async ({ describe }, node: NodeApis) => {
describe('Load ESM', ({ describe }) => {
Expand Down Expand Up @@ -36,6 +37,12 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});

test('Import with query', async () => {
const nodeProcess = await node.import(importPath + query);
assertResults(nodeProcess);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});

test('TypeScript Import', async () => {
const nodeProcess = await node.import(importPath, { typescript: true });
assertResults(nodeProcess);
Expand Down Expand Up @@ -101,6 +108,12 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
assertResults(nodeProcess);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});

test('Import with query', async () => {
const nodeProcess = await node.import(importPath + query);
assertResults(nodeProcess);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});
});

describe('extensionless', ({ test }) => {
Expand Down
21 changes: 17 additions & 4 deletions tests/specs/json.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { testSuite, expect } from 'manten';
import { createFixture } from 'fs-fixture';
import type { NodeApis } from '../utils/node-with-loader.js';
import { query } from '../utils/query.js';

const jsonFixture = {
'package.json': JSON.stringify({
Expand Down Expand Up @@ -28,6 +29,11 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
const nodeProcess = await node.importFile(fixture.path, './index.json');
expect(nodeProcess.stdout).toMatch('default: { loaded: \'json\' }');
});

test('Import with query', async () => {
const nodeProcess = await node.importFile(fixture.path, `./index.json${query}`);
expect(nodeProcess.stdout).toMatch('default: { loaded: \'json\' }');
});
});

describe('extensionless', ({ test }) => {
Expand All @@ -41,14 +47,16 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
const nodeProcess = await node.importFile(fixture.path, './index');
expect(nodeProcess.stdout).toMatch('default: { loaded: \'json\' }');
});

test('Import with query', async () => {
const nodeProcess = await node.importFile(fixture.path, `./index${query}`);
expect(nodeProcess.stdout).toMatch('default: { loaded: \'json\' }');
});
});

describe('directory', ({ test }) => {
test('Load', async ({ onTestFail }) => {
test('Load', async () => {
const nodeProcess = await node.loadFile(fixture.path, '.');
onTestFail(() => {
console.log(nodeProcess);
});
expect(nodeProcess.exitCode).toBe(0);
expect(nodeProcess.stdout).toBe('');
});
Expand All @@ -57,6 +65,11 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
const nodeProcess = await node.importFile(fixture.path, '.');
expect(nodeProcess.stdout).toMatch('default: { loaded: \'json\' }');
});

test('Import with query', async () => {
const nodeProcess = await node.importFile(fixture.path, `./${query}`);
expect(nodeProcess.stdout).toMatch('default: { loaded: \'json\' }');
});
});

describe('ambiguous path', async ({ describe, onFinish }) => {
Expand Down
23 changes: 23 additions & 0 deletions tests/specs/typescript/mts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import semver from 'semver';
import type { NodeApis } from '../../utils/node-with-loader.js';
import nodeSupports from '../../utils/node-supports.js';
import { assertNotFound } from '../../utils/assertions.js';
import { query } from '../../utils/query.js';

export default testSuite(async ({ describe }, node: NodeApis) => {
describe('.mts extension', ({ describe }) => {
Expand Down Expand Up @@ -33,6 +34,12 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
assertResults(nodeProcess.stdout);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});

test('Import with query', async () => {
const nodeProcess = await node.import(importPath + query);
assertResults(nodeProcess.stdout);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});
});

describe('full path via .mjs', ({ test }) => {
Expand All @@ -48,6 +55,12 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
assertResults(nodeProcess.stdout);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});

test('Import with query', async () => {
const nodeProcess = await node.import(importPath + query, { typescript: true });
assertResults(nodeProcess.stdout);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});
});

describe('extensionless - should not work', ({ test }) => {
Expand All @@ -62,6 +75,11 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
const nodeProcess = await node.import(importPath);
assertNotFound(nodeProcess.stderr, importPath);
});

test('Import with query', async () => {
const nodeProcess = await node.import(importPath + query);
assertNotFound(nodeProcess.stderr, importPath);
});
});

describe('directory - should not work', ({ test }) => {
Expand All @@ -76,6 +94,11 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
const nodeProcess = await node.import(importPath);
assertNotFound(nodeProcess.stderr, importPath);
});

test('Import with query', async () => {
const nodeProcess = await node.import(importPath + query);
assertNotFound(nodeProcess.stderr, importPath);
});
});
});
});
36 changes: 36 additions & 0 deletions tests/specs/typescript/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import semver from 'semver';
import type { NodeApis } from '../../utils/node-with-loader.js';
import nodeSupports from '../../utils/node-supports.js';
import { assertNotFound } from '../../utils/assertions.js';
import { query } from '../../utils/query.js';

export default testSuite(async ({ describe }, node: NodeApis) => {
describe('.ts extension', ({ describe }) => {
Expand Down Expand Up @@ -58,6 +59,12 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
assertResults(nodeProcess.stdout);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});

test('Import with query', async () => {
const nodeProcess = await node.import(importPath + query, { typescript: true });
assertResults(nodeProcess.stdout);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});
});

describe('extensionless', ({ test }) => {
Expand All @@ -73,6 +80,12 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
assertResults(nodeProcess.stdout);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});

test('Import with query', async () => {
const nodeProcess = await node.import(importPath + query, { typescript: true });
assertResults(nodeProcess.stdout);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});
});

describe('extensionless with subextension', ({ test }) => {
Expand All @@ -88,6 +101,12 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
assertResults(nodeProcess.stdout, 'ts-ext-ts/index.tsx.ts');
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});

test('Import with query', async () => {
const nodeProcess = await node.import(importPath + query);
assertResults(nodeProcess.stdout, 'ts-ext-ts/index.tsx.ts');
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});
});

describe('directory', ({ test }) => {
Expand All @@ -103,6 +122,12 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
assertResults(nodeProcess.stdout);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});

test('Import with query', async () => {
const nodeProcess = await node.import(importPath + query);
assertResults(nodeProcess.stdout);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});
});

describe('empty directory should fallback to file', ({ test }) => {
Expand All @@ -118,6 +143,12 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
assertResults(nodeProcess.stdout);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});

test('Import with query', async () => {
const nodeProcess = await node.import(importPath + query);
assertResults(nodeProcess.stdout);
expect(nodeProcess.stdout).toMatch('{"default":1234}');
});
});

describe('empty but explicit directory should not fallback to file', ({ test }) => {
Expand All @@ -127,6 +158,11 @@ export default testSuite(async ({ describe }, node: NodeApis) => {
const nodeProcess = await node.import(importPath);
assertNotFound(nodeProcess.stderr, importPath);
});

test('Import with query', async () => {
const nodeProcess = await node.import(importPath + query);
assertNotFound(nodeProcess.stderr, importPath);
});
});
});
});
1 change: 1 addition & 0 deletions tests/utils/node-with-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const nodeWithLoader = (
nodePath: options.nodePath,
cwd: options.cwd,
reject: false,
all: true,
},
);

Expand Down
1 change: 1 addition & 0 deletions tests/utils/query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const query = '?query=123';

0 comments on commit dcf4dd9

Please sign in to comment.