Skip to content

Commit

Permalink
Handle transformed HTML at the root route. (#30)
Browse files Browse the repository at this point in the history
* Add test case for failure to process specifiers in HTML in root route.
* Add code to fix failing tests.
  • Loading branch information
usergenic authored Jul 6, 2020
1 parent 11100a0 commit 7add2c3
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 10 deletions.
4 changes: 2 additions & 2 deletions src/koa-node-resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {parse as parseURL} from 'url';
import {moduleSpecifierTransform, ModuleSpecifierTransformOptions} from './koa-module-specifier-transform';
import {prefixedLogger} from './support/logger';
import {Logger} from './support/logger';
import {noLeadingSlashInURL} from './support/path-utils';
import {noLeadingSlashInURL, resolvePathPreserveTrailingSlash} from './support/path-utils';
import {resolveNodeSpecifier} from './support/resolve-node-specifier';

export {Logger} from './support/logger';
Expand All @@ -40,7 +40,7 @@ export const nodeResolve =
return moduleSpecifierTransform(
(baseURL: string, specifier: string, logger: Logger) =>
resolveNodeSpecifier(
resolvePath(
resolvePathPreserveTrailingSlash(
resolvePath(options.root || '.'),
noLeadingSlashInURL(parseURL(baseURL).pathname || '/')),
specifier,
Expand Down
14 changes: 13 additions & 1 deletion src/support/path-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* subject to an additional IP rights grant found at
* http://polymer.github.io/PATENTS.txt
*/
import {posix, sep as pathSeparator} from 'path';
import {posix, resolve as resolvePath, sep as pathSeparator} from 'path';

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

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

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

export const noTrailingSlashInPath = (path: string): string =>
path.replace(/\/$/, '');

export const noLeadingSlashInURL = (href: string): string =>
href.replace(/^\//, '');

export const relativePathToURL = (from: string, to: string): string =>
ensureLeadingDotInURL(posix.relative(
getBaseURL(forwardSlashesOnlyPlease(from)),
forwardSlashesOnlyPlease(to)));

export const resolvePathPreserveTrailingSlash =
(from: string, to: string): string => {
const resolvedPath = resolvePath(from, to);
return isDirectorySpecifier(to) ? `${resolvedPath}/` : resolvedPath;
};

const isDirectorySpecifier = (specifier: string) => ['', '.', '..'].includes(
specifier.match(/([^\/]*$)/)![0]);
47 changes: 45 additions & 2 deletions src/test/koa-node-resolve.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
* subject to an additional IP rights grant found at
* http://polymer.github.io/PATENTS.txt
*/
import {resolve as resolvePath} from 'path';
import request from 'supertest';
import test from 'tape';

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

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

const fixturesPath = resolvePath(__dirname, '../../test/fixtures/');
const fixturesPath =
resolvePathPreserveTrailingSlash(__dirname, '../../test/fixtures/');

test('nodeResolve middleware transforms resolvable specifiers', async (t) => {
t.plan(4);
Expand Down Expand Up @@ -63,6 +64,48 @@ test('nodeResolve middleware transforms resolvable specifiers', async (t) => {
});
});

test('nodeResolve middleware works even if baseURL has no pathname', async (t) => {
t.plan(4);
const logger = testLogger();
createAndServe(
{
middleware:
[nodeResolve({root: fixturesPath, logger, logLevel: 'debug'})],
routes: {
'/my-module.js': `import * as x from 'x';`,
'/': `
<script type="module">
import * as x from 'x';
</script>
`,
},
},
async (server) => {
t.equal(
squeeze((await request(server).get('/my-module.js')).text),
squeeze(`
import * as x from './node_modules/x/main.js';
`),
'should transform specifiers in JavaScript module');
t.equal(
squeeze((await request(server).get('/')).text),
squeeze(`
<script type="module">
import * as x from './node_modules/x/main.js';
</script>
`),
'should transform specifiers in inline module script');
t.deepEqual(logger.debugs.map((args) => args.join(' ')), [
'[koa-node-resolve] Resolved Node module specifier "x" to "./node_modules/x/main.js"',
'[koa-node-resolve] Resolved Node module specifier "x" to "./node_modules/x/main.js"',
]);
t.deepEqual(logger.infos.map((args) => args.join(' ')), [
'[koa-node-resolve] Transformed 1 module specifier(s) in "/my-module.js"',
'[koa-node-resolve] Transformed 1 module specifier(s) in "/"',
]);
});
});

test('nodeResolve middleware ignores unresolvable specifiers', async (t) => {
t.plan(2);
const logger = testLogger();
Expand Down
44 changes: 44 additions & 0 deletions src/test/path-utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* @license
* Copyright (c) 2020 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at
* http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at
* http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at
* http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at
* http://polymer.github.io/PATENTS.txt
*/
import test from 'tape';

import {dirname, resolvePathPreserveTrailingSlash} from '../support/path-utils';

test('dirname returns portion of path representing directory', (t) => {
t.plan(2);
t.equal(
dirname('/a/b/c'),
'/a/b/',
'should treat lack of trailing slash as file');
t.equal(
dirname('/a/b/c/'),
'/a/b/c/',
'should treat segment before trailing slash as directory name');
});

test('resolvePathPreserveTrailingSlash may return trailing slash', (t) => {
t.plan(3);
t.equal(
resolvePathPreserveTrailingSlash('/a/b', 'c/'),
'/a/b/c/',
'should contain trailing slash when destination has trailing slash');
t.equal(
resolvePathPreserveTrailingSlash('/a/b', 'c'),
'/a/b/c',
'should not contain trailing slash if destination does not have trailing slash');
t.equal(
resolvePathPreserveTrailingSlash('/a/b', ''),
'/a/b/',
'should contain trailing slash if destination is current directory');
});
5 changes: 2 additions & 3 deletions src/test/resolve-node-specifier.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@
* subject to an additional IP rights grant found at
* http://polymer.github.io/PATENTS.txt
*/
import {resolve as resolvePath} from 'path';
import test from 'tape';

import {ensureTrailingSlashInPath} from '../support/path-utils';
import {resolvePathPreserveTrailingSlash} from '../support/path-utils';
import {resolveNodeSpecifier} from '../support/resolve-node-specifier';
import {testLogger} from './test-utils';

const logger = testLogger();
const fixturesPath =
ensureTrailingSlashInPath(resolvePath(__dirname, '../../test/fixtures/'));
resolvePathPreserveTrailingSlash(__dirname, '../../test/fixtures/');
const resolve = (specifier: string): string =>
resolveNodeSpecifier(fixturesPath, specifier, logger);

Expand Down
4 changes: 2 additions & 2 deletions src/test/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ export const createApp = (options: AppOptions): Koa => {
app.use(route.get(key, (ctx) => {
if (key.endsWith('.js')) {
ctx.type = 'js';
}
if (key.endsWith('.html')) {
} else {
// Assume everything else is html.
ctx.type = 'html';
}
// Make our body a stream, like koa static would do, to make sure we
Expand Down

0 comments on commit 7add2c3

Please sign in to comment.