Skip to content

Commit

Permalink
feat(paths): Allow usage of TSConfig Paths (#76)
Browse files Browse the repository at this point in the history
* feat(paths): Allow usage of TSConfig Paths

* fix: Okay apparently GitHub Actions testing doesn't like the optional chaining

* fix?: Fix windows path issue?

* fix?: Fix windows path?

* chore(debugging): Remove debug console.log

* fix(target): Change output target to ES2019 to supoprt Node.JS 13.9+

* lint(index): Fix lint errrors on unused imports
  • Loading branch information
EntraptaJ authored May 26, 2020
1 parent b06c867 commit 6e2f6af
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 10 deletions.
6 changes: 5 additions & 1 deletion .devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
"SHELL": "/bin/sh"
},

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

"remoteUser": "node",

Expand Down
4 changes: 4 additions & 0 deletions Testing/Tests/Paths/package-lock.json

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

12 changes: 12 additions & 0 deletions Testing/Tests/Paths/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "paths",
"type": "module",
"main": "./src/index.ts",
"NODE_OPTIONS": "--harmony-top-level-await",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node --loader ../../../out/dist/index.js --experimental-specifier-resolution=node --experimental-import-meta-resolve --harmony-optional-chaining --harmony-top-level-await src/index.ts"
},
"author": "",
"license": "ISC"
}
6 changes: 6 additions & 0 deletions Testing/Tests/Paths/src/Module/HelloWorld/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Testing/Tests/src/Module/HelloWorld/index.ts
import { add } from '@paths/Utils/Math';

export async function testingSubPath(): Promise<number> {
return add(1, 5);
}
13 changes: 13 additions & 0 deletions Testing/Tests/Paths/src/Utils/Math.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Testing/Tests/Lab/src/Utils/Math.ts

export function add(x: number, y: number): number {
console.debug(`Adding ${x} + ${y}`);

return x + y;
}

export function divide(x: number, y: number): number {
console.debug(`Dividing ${x} / ${y}`);

return x / y;
}
22 changes: 22 additions & 0 deletions Testing/Tests/Paths/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Testing/Tests/Lab/src/index.ts
import { add, divide } from '@paths/Utils/Math';
import { strictEqual } from 'assert';

export async function startApp(): Promise<void> {
console.debug('Starting Application');

const sum = add(1, 1);
strictEqual(sum, 2);

const divideResult = divide(2, 2);
strictEqual(divideResult, 1);

const { testingSubPath } = await import('@paths/Module/HelloWorld');

const addSub = await testingSubPath();
strictEqual(addSub, 6);

console.debug('Done');
}

startApp();
13 changes: 13 additions & 0 deletions Testing/Tests/Paths/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true,
"baseUrl": "./src",

"paths": {
"@paths/*": ["./*"]
}
}
}
1 change: 0 additions & 1 deletion src/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { isAbsolute as isAbsolutePath, dirname as pathDirname } from 'path';
let tsConfigCache: CompilerOptions;

export function getTSConfig(modulePath: string): CompilerOptions {
if (tsConfigCache) return tsConfigCache;
const tsConfigPath = ts.findConfigFile(modulePath, ts.sys.fileExists);

if (!tsConfigPath || !isAbsolutePath(tsConfigPath)) {
Expand Down
41 changes: 34 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
// src/index.ts
import { createRequire } from 'module';
import { basename, dirname } from 'path';
import ts from 'typescript';
import { basename, dirname, resolve as resolvePath } from 'path';
import ts, { CompilerOptions } from 'typescript';
import { fileURLToPath, pathToFileURL } from 'url';
import { findFiles } from './findFiles';
import {
DynamicInstantiateResponse,
GetFormatResponse,
ModuleFormat,
ResolveContext,
ResolveResponse,
Source,
TransformContext,
TransformResponse,
DynamicInstantiateResponse,
GetFormatResponse,
} from './types';
import { getTSConfig } from './Utils';

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

const relativePathRegex = /^\.{1,2}[/]?/;
Expand All @@ -26,13 +26,36 @@ const hasExtensionRegex = /\.\w+$/;
const extensions = ['.ts', '.tsx'];
const extensionsRegex = new RegExp(`\\${extensions.join('|\\')}`);

let TSConfig: CompilerOptions;

// Custom resolver to allow `.ts` and `.tsx` extensions, along with finding files if no extension is provided.
export async function resolve(
specifier: string,
context: ResolveContext,
defaultResolve: Function,
): Promise<ResolveResponse> {
const { parentURL = baseURL } = context;
let { parentURL = baseURL } = context;

let forceRelative = false;
if (TSConfig?.paths) {
for (const tsPath of Object.keys(TSConfig.paths)) {
const tsPathKey = tsPath.replace('/*', '');
if (specifier.startsWith(tsPathKey)) {
const pathSpecifier = TSConfig.paths[tsPath][0].replace(
'/*',
specifier.split(tsPathKey)[1],
);

forceRelative = true;

parentURL = `${
pathToFileURL(resolvePath(baseURL, TSConfig.baseUrl!)).href
}/`;

specifier = pathSpecifier;
}
}
}

const resolvedUrl = new URL(specifier, parentURL);
const fileName = basename(resolvedUrl.pathname);
Expand All @@ -49,7 +72,10 @@ 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) && !hasExtensionRegex.test(fileName)) {
if (
(relativePathRegex.test(specifier) || forceRelative) &&
!hasExtensionRegex.test(fileName)
) {
const filePath = fileURLToPath(resolvedUrl);

const file = await findFiles(dirname(filePath), {
Expand Down Expand Up @@ -161,6 +187,7 @@ export async function transformSource(

// Load the closest `tsconfig.json` to the source file
const tsConfig = getTSConfig(dirname(sourceFilePath));
TSConfig = tsConfig;

// Transpile the source code that Node passed to us.
const transpiledModule = ts.transpileModule(source.toString(), {
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"compilerOptions": {
"target": "ESNext",
"target": "ES2019",
"module": "ESNext",
"moduleResolution": "Node",

"allowSyntheticDefaultImports": true,
"declaration": true,

"strict": true,
"outDir": "out/dist",
Expand Down

0 comments on commit 6e2f6af

Please sign in to comment.