Skip to content

Commit

Permalink
fix(Resovler): Refactor resolver and module loader to prevent loading…
Browse files Browse the repository at this point in the history
… of URLs and already discovered javascript files (#28)
  • Loading branch information
EntraptaJ committed May 12, 2020
1 parent 74df98a commit cda330e
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 22 deletions.
5 changes: 4 additions & 1 deletion .devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
"SHELL": "/bin/sh"
},

"extensions": ["esbenp.prettier-vscode"],
"extensions": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"],

"remoteUser": "node",

"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached",
"workspaceFolder": "/workspace",

"mounts": [
"source=ts-esnode-modules,target=/workspace/node_modules,type=volume"
],
Expand Down
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"typescript.tsdk": "node_modules/typescript/lib"
}
}
4 changes: 3 additions & 1 deletion Testing/Runner/Utils/runTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ export interface Result {
}

export function runTest(test: Test): Promise<Result> {
const worker = spawnWorker(test.path, {});
const worker = spawnWorker(test.path, {
helloWorld: ['test', 'test2'],
});

return new Promise((resolve, reject) => {
worker.on('exit', (exitCode) => {
Expand Down
4 changes: 1 addition & 3 deletions src/findFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { promises as fs } from 'fs';
import { resolve as resolvePath } from 'path';
import { pathToFileURL, URL } from 'url';

const JS_EXTS = ['.js', '.jsx'];

interface FileRule {
fileName: string;
extensions: string[];
Expand All @@ -24,7 +22,7 @@ async function findFile(
if (directoryEntry.name.includes(fileName)) {
if (directoryEntry.isDirectory()) return true;

for (let extension of [...extensions, ...JS_EXTS]) {
for (let extension of extensions) {
if (directoryFileName === fileName + extension) {
return true;
}
Expand Down
46 changes: 30 additions & 16 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,26 @@
import { createRequire } from 'module';
import { basename, dirname } from 'path';
import ts from 'typescript';
import { fileURLToPath, pathToFileURL, URL, format } from 'url';
import { fileURLToPath, pathToFileURL } from 'url';
import { findFiles } from './findFiles';
import {
ModuleFormat,
ResolveContext,
ResolveResponse,
Source,
TransformContext,
TransformResponse,
ModuleFormat,
} from './types';
import { getTSConfig } from './Utils';

const rootModulePath = `${process.cwd()}/`;
const baseURL = pathToFileURL(rootModulePath).href;

const relativePathRegex = /^\.{0,2}[/]/;
const relativePathRegex = /^\.{1,2}[/]/;

// TODO: Allow customization of extensions
const extensions = ['.ts', '.tsx'];
const extensionsRegex = new RegExp(`\\${extensions.join('$|\\')}$`);
const extensionsRegex = new RegExp(`\\${extensions.join('$|\\')}`);

// Custom resolver to allow `.ts` and `.tsx` extensions, along with finding files if no extension is provided.
export async function resolve(
Expand All @@ -31,8 +31,11 @@ export async function resolve(
): Promise<ResolveResponse> {
const { parentURL = baseURL } = context;

const resolvedUrl = new URL(specifier, parentURL);
const fileName = basename(resolvedUrl.pathname);

// If we can already see a `.ts` or `.tsx` extensions then we can create a File URL
if (extensionsRegex.test(specifier)) {
if (extensionsRegex.test(fileName)) {
// Node.js normally errors on unknown file extensions, so return a URL for
// specifiers ending in the TypeScript file extensions.
return {
Expand All @@ -43,14 +46,14 @@ export async function resolve(
/**
* If no extension is passed and is a relative import then let's try to find a `.ts` or `.tsx` file at the path
*/
if (relativePathRegex.test(specifier) && !specifier.startsWith('file:')) {
const fileURL = new URL(specifier, parentURL);
const filePath = fileURLToPath(fileURL);
if (relativePathRegex.test(specifier)) {
const filePath = fileURLToPath(resolvedUrl);

const file = await findFiles(dirname(filePath), {
fileName: basename(filePath),
fileName,
extensions,
});

return {
url: file.href,
};
Expand All @@ -65,13 +68,19 @@ export async function resolve(
* @param url fileURL given by Node.JS
*/
export async function dynamicInstantiate(url: string) {
// Create a Node.JS Require using the `node_modules` folder as the base URL.
const require = createRequire(
`${url.split('/node_modules/')[0].replace('file://', '')}/node_modules/`,
const moduleUrl = new URL(url);

const [nodeModulesBase, specifier] = moduleUrl.pathname.split(
'node_modules/',
);

const nodeModuleUrl = new URL('node_modules', pathToFileURL(nodeModulesBase));

// Create a Node.JS Require using the `node_modules` folder as the base URL.
const require = createRequire(nodeModuleUrl);

// Import the module file path
let dynModule = require(url.replace(/.*\/node_modules\//, ''));
let dynModule = require(specifier);

/**
* This is needed to allow for default exports in CommonJS modules.
Expand Down Expand Up @@ -105,8 +114,11 @@ export async function getFormat(
let format = formatCache.get(url);
if (format) return { format };

const resolvedUrl = new URL(url);
const fileName = basename(resolvedUrl.pathname);

// If it's a TypeScript extension then force `module` mode.
if (extensionsRegex.test(url)) format = 'module';
if (extensionsRegex.test(fileName)) format = 'module';

if (!format) {
const defaultResolve = defaultGetFormat(url, context, defaultGetFormat) as {
Expand Down Expand Up @@ -136,8 +148,11 @@ export async function transformSource(
context: TransformContext,
defaultTransformSource: Function,
): Promise<TransformResponse> {
const resolvedUrl = new URL(context.url);
const fileName = basename(resolvedUrl.pathname);

// Only transform TypeScript Modules
if (extensionsRegex.test(context.url)) {
if (extensionsRegex.test(fileName)) {
const sourceFilePath = fileURLToPath(context.url);

// Load the closest `tsconfig.json` to the source file
Expand All @@ -149,7 +164,6 @@ export async function transformSource(
reportDiagnostics: true,
});

// TODO: Actually "check" the TypeScript Code.
return {
source: transpiledModule.outputText,
};
Expand Down

0 comments on commit cda330e

Please sign in to comment.