Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Resovler): Refactor resolver and module loader to prevent loading… #28

Merged
merged 1 commit into from
Mar 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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