Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

Commit 7add2c3

Browse files
authored
Handle transformed HTML at the root route. (#30)
* Add test case for failure to process specifiers in HTML in root route. * Add code to fix failing tests.
1 parent 11100a0 commit 7add2c3

File tree

6 files changed

+108
-10
lines changed

6 files changed

+108
-10
lines changed

src/koa-node-resolve.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {parse as parseURL} from 'url';
1818
import {moduleSpecifierTransform, ModuleSpecifierTransformOptions} from './koa-module-specifier-transform';
1919
import {prefixedLogger} from './support/logger';
2020
import {Logger} from './support/logger';
21-
import {noLeadingSlashInURL} from './support/path-utils';
21+
import {noLeadingSlashInURL, resolvePathPreserveTrailingSlash} from './support/path-utils';
2222
import {resolveNodeSpecifier} from './support/resolve-node-specifier';
2323

2424
export {Logger} from './support/logger';
@@ -40,7 +40,7 @@ export const nodeResolve =
4040
return moduleSpecifierTransform(
4141
(baseURL: string, specifier: string, logger: Logger) =>
4242
resolveNodeSpecifier(
43-
resolvePath(
43+
resolvePathPreserveTrailingSlash(
4444
resolvePath(options.root || '.'),
4545
noLeadingSlashInURL(parseURL(baseURL).pathname || '/')),
4646
specifier,

src/support/path-utils.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* subject to an additional IP rights grant found at
1212
* http://polymer.github.io/PATENTS.txt
1313
*/
14-
import {posix, sep as pathSeparator} from 'path';
14+
import {posix, resolve as resolvePath, sep as pathSeparator} from 'path';
1515

1616
const filenameRegex = process.platform === 'win32' ? /[^\\]+$/ : /[^\/]+$/;
1717

@@ -35,10 +35,22 @@ export const forwardSlashesOnlyPlease = (path: string): string =>
3535

3636
export const getBaseURL = (href: string): string => href.replace(/[^\/]+$/, '');
3737

38+
export const noTrailingSlashInPath = (path: string): string =>
39+
path.replace(/\/$/, '');
40+
3841
export const noLeadingSlashInURL = (href: string): string =>
3942
href.replace(/^\//, '');
4043

4144
export const relativePathToURL = (from: string, to: string): string =>
4245
ensureLeadingDotInURL(posix.relative(
4346
getBaseURL(forwardSlashesOnlyPlease(from)),
4447
forwardSlashesOnlyPlease(to)));
48+
49+
export const resolvePathPreserveTrailingSlash =
50+
(from: string, to: string): string => {
51+
const resolvedPath = resolvePath(from, to);
52+
return isDirectorySpecifier(to) ? `${resolvedPath}/` : resolvedPath;
53+
};
54+
55+
const isDirectorySpecifier = (specifier: string) => ['', '.', '..'].includes(
56+
specifier.match(/([^\/]*$)/)![0]);

src/test/koa-node-resolve.test.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@
1111
* subject to an additional IP rights grant found at
1212
* http://polymer.github.io/PATENTS.txt
1313
*/
14-
import {resolve as resolvePath} from 'path';
1514
import request from 'supertest';
1615
import test from 'tape';
1716

1817
import {nodeResolve} from '../koa-node-resolve';
18+
import {resolvePathPreserveTrailingSlash} from '../support/path-utils';
1919

2020
import {createAndServe, squeeze, testLogger} from './test-utils';
2121

22-
const fixturesPath = resolvePath(__dirname, '../../test/fixtures/');
22+
const fixturesPath =
23+
resolvePathPreserveTrailingSlash(__dirname, '../../test/fixtures/');
2324

2425
test('nodeResolve middleware transforms resolvable specifiers', async (t) => {
2526
t.plan(4);
@@ -63,6 +64,48 @@ test('nodeResolve middleware transforms resolvable specifiers', async (t) => {
6364
});
6465
});
6566

67+
test('nodeResolve middleware works even if baseURL has no pathname', async (t) => {
68+
t.plan(4);
69+
const logger = testLogger();
70+
createAndServe(
71+
{
72+
middleware:
73+
[nodeResolve({root: fixturesPath, logger, logLevel: 'debug'})],
74+
routes: {
75+
'/my-module.js': `import * as x from 'x';`,
76+
'/': `
77+
<script type="module">
78+
import * as x from 'x';
79+
</script>
80+
`,
81+
},
82+
},
83+
async (server) => {
84+
t.equal(
85+
squeeze((await request(server).get('/my-module.js')).text),
86+
squeeze(`
87+
import * as x from './node_modules/x/main.js';
88+
`),
89+
'should transform specifiers in JavaScript module');
90+
t.equal(
91+
squeeze((await request(server).get('/')).text),
92+
squeeze(`
93+
<script type="module">
94+
import * as x from './node_modules/x/main.js';
95+
</script>
96+
`),
97+
'should transform specifiers in inline module script');
98+
t.deepEqual(logger.debugs.map((args) => args.join(' ')), [
99+
'[koa-node-resolve] Resolved Node module specifier "x" to "./node_modules/x/main.js"',
100+
'[koa-node-resolve] Resolved Node module specifier "x" to "./node_modules/x/main.js"',
101+
]);
102+
t.deepEqual(logger.infos.map((args) => args.join(' ')), [
103+
'[koa-node-resolve] Transformed 1 module specifier(s) in "/my-module.js"',
104+
'[koa-node-resolve] Transformed 1 module specifier(s) in "/"',
105+
]);
106+
});
107+
});
108+
66109
test('nodeResolve middleware ignores unresolvable specifiers', async (t) => {
67110
t.plan(2);
68111
const logger = testLogger();

src/test/path-utils.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* @license
3+
* Copyright (c) 2020 The Polymer Project Authors. All rights reserved.
4+
* This code may only be used under the BSD style license found at
5+
* http://polymer.github.io/LICENSE.txt
6+
* The complete set of authors may be found at
7+
* http://polymer.github.io/AUTHORS.txt
8+
* The complete set of contributors may be found at
9+
* http://polymer.github.io/CONTRIBUTORS.txt
10+
* Code distributed by Google as part of the polymer project is also
11+
* subject to an additional IP rights grant found at
12+
* http://polymer.github.io/PATENTS.txt
13+
*/
14+
import test from 'tape';
15+
16+
import {dirname, resolvePathPreserveTrailingSlash} from '../support/path-utils';
17+
18+
test('dirname returns portion of path representing directory', (t) => {
19+
t.plan(2);
20+
t.equal(
21+
dirname('/a/b/c'),
22+
'/a/b/',
23+
'should treat lack of trailing slash as file');
24+
t.equal(
25+
dirname('/a/b/c/'),
26+
'/a/b/c/',
27+
'should treat segment before trailing slash as directory name');
28+
});
29+
30+
test('resolvePathPreserveTrailingSlash may return trailing slash', (t) => {
31+
t.plan(3);
32+
t.equal(
33+
resolvePathPreserveTrailingSlash('/a/b', 'c/'),
34+
'/a/b/c/',
35+
'should contain trailing slash when destination has trailing slash');
36+
t.equal(
37+
resolvePathPreserveTrailingSlash('/a/b', 'c'),
38+
'/a/b/c',
39+
'should not contain trailing slash if destination does not have trailing slash');
40+
t.equal(
41+
resolvePathPreserveTrailingSlash('/a/b', ''),
42+
'/a/b/',
43+
'should contain trailing slash if destination is current directory');
44+
});

src/test/resolve-node-specifier.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,15 @@
1111
* subject to an additional IP rights grant found at
1212
* http://polymer.github.io/PATENTS.txt
1313
*/
14-
import {resolve as resolvePath} from 'path';
1514
import test from 'tape';
1615

17-
import {ensureTrailingSlashInPath} from '../support/path-utils';
16+
import {resolvePathPreserveTrailingSlash} from '../support/path-utils';
1817
import {resolveNodeSpecifier} from '../support/resolve-node-specifier';
1918
import {testLogger} from './test-utils';
2019

2120
const logger = testLogger();
2221
const fixturesPath =
23-
ensureTrailingSlashInPath(resolvePath(__dirname, '../../test/fixtures/'));
22+
resolvePathPreserveTrailingSlash(__dirname, '../../test/fixtures/');
2423
const resolve = (specifier: string): string =>
2524
resolveNodeSpecifier(fixturesPath, specifier, logger);
2625

src/test/test-utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ export const createApp = (options: AppOptions): Koa => {
3737
app.use(route.get(key, (ctx) => {
3838
if (key.endsWith('.js')) {
3939
ctx.type = 'js';
40-
}
41-
if (key.endsWith('.html')) {
40+
} else {
41+
// Assume everything else is html.
4242
ctx.type = 'html';
4343
}
4444
// Make our body a stream, like koa static would do, to make sure we

0 commit comments

Comments
 (0)