Skip to content

Commit a4e2916

Browse files
author
Ron S
authored
fix: multiple issue fixes (#61)
* Multiple Issue Fixes - Allow more than one path routing (fixes #60) - Remove implicit extensions from output (fixes #24) - Properly implemented isTypeOnly (fixes #48) - Corrected errors in tests due to TS changing logic for type only star exports - Bonus: Made package zero-dependency * Removed accidental dependency
1 parent 1e75eb0 commit a4e2916

File tree

9 files changed

+73
-32
lines changed

9 files changed

+73
-32
lines changed

package.json

100644100755
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,6 @@
4747
"**/tests/index.ts"
4848
]
4949
},
50-
"dependencies": {
51-
"slash": "^3.0.0"
52-
},
5350
"devDependencies": {
5451
"@types/fs-readdir-recursive": "^1.0.0",
5552
"@types/jest": "^24.0.15",
@@ -59,6 +56,6 @@
5956
"standard-version": "^6.0.1",
6057
"ts-jest": "^24.0.2",
6158
"ttypescript": "^1.5.6",
62-
"typescript": "^3.4.5"
59+
"typescript": "^3.9.7"
6360
}
6461
}

src/index.ts

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
11
import { dirname, relative, resolve, extname } from "path";
22
import ts from "typescript";
3-
import slash from "slash";
43
import { parse } from "url";
54
import { existsSync } from "fs";
65

6+
7+
/* ****************************************************************************************************************** *
8+
* Helpers
9+
* ****************************************************************************************************************** */
10+
11+
export const normalizePath = (p: string) =>
12+
// Is extended length or has non-ascii chars (respectively)
13+
(/^\\\\\?\\/.test(p) || /[^\u0000-\u0080]+/.test(p)) ? p :
14+
// Normalize to forward slash and remove repeating slashes
15+
p.replace(/[\\\/]+/g, '/');
16+
17+
18+
/* ****************************************************************************************************************** *
19+
* Transformer
20+
* ****************************************************************************************************************** */
21+
722
const transformer = (_: ts.Program) => (context: ts.TransformationContext) => (
823
sourceFile: ts.SourceFile
924
) => {
@@ -36,7 +51,7 @@ const transformer = (_: ts.Program) => (context: ts.TransformationContext) => (
3651
.filter(key => paths[key].length)
3752
.map(key => ({
3853
regexp: new RegExp("^" + key.replace("*", "(.*)") + "$"),
39-
path: paths[key][0]
54+
paths: paths[key]
4055
}));
4156

4257
if (!baseUrl || binds.length === 0) {
@@ -66,19 +81,24 @@ const transformer = (_: ts.Program) => (context: ts.TransformationContext) => (
6681
return moduleName;
6782
}
6883

69-
for (const { regexp, path } of binds) {
84+
for (const { regexp, paths } of binds) {
7085
const match = regexp.exec(moduleName);
7186
if (match) {
72-
const out = path.replace(/\*/g, match[1]);
73-
if (isUrl(out)) {
74-
return out;
87+
for (const p of paths) {
88+
const out = p.replace(/\*/g, match[1]);
89+
90+
if (isUrl(out)) return out;
91+
92+
const filepath = resolve(baseUrl, out);
93+
if (!fileExists(`${filepath}/index`) && !fileExists(filepath)) continue;
94+
95+
const resolved = fixupImportPath(relative(sourceDir, filepath));
96+
97+
return isRelative(resolved) ? resolved : `./${resolved}`;
7598
}
76-
const filepath = resolve(baseUrl, out);
77-
if (!fileExists(`${filepath}/index`) && !fileExists(filepath)) continue;
78-
const resolved = slash(relative(sourceDir, filepath));
79-
return isRelative(resolved) ? resolved : `./${resolved}`;
8099
}
81100
}
101+
82102
return undefined;
83103
}
84104

@@ -96,17 +116,6 @@ const transformer = (_: ts.Program) => (context: ts.TransformationContext) => (
96116
node.arguments.length === 1;
97117

98118
function visit(node: ts.Node): ts.VisitResult<ts.Node> {
99-
if (
100-
!isDeclarationFile &&
101-
resolver &&
102-
ts.isExportDeclaration(node) &&
103-
!node.exportClause &&
104-
!compilerOptions.isolatedModules &&
105-
!resolver.moduleExportsSomeValue(node.moduleSpecifier)
106-
) {
107-
return undefined;
108-
}
109-
110119
if (isRequire(node) || isAsyncImport(node)) {
111120
return unpathRequireAndAsyncImport(node);
112121
}
@@ -224,7 +233,7 @@ const transformer = (_: ts.Program) => (context: ts.TransformationContext) => (
224233
ts.isNamedImports
225234
);
226235
return name || namedBindings
227-
? ts.updateImportClause(node, name, namedBindings)
236+
? ts.updateImportClause(node, name, namedBindings, node.isTypeOnly)
228237
: undefined;
229238
}
230239
function visitNamedImportBindings(
@@ -273,7 +282,8 @@ const transformer = (_: ts.Program) => (context: ts.TransformationContext) => (
273282
node.decorators,
274283
node.modifiers,
275284
node.exportClause,
276-
fileLiteral
285+
fileLiteral,
286+
node.isTypeOnly
277287
);
278288
}
279289

@@ -290,7 +300,8 @@ const transformer = (_: ts.Program) => (context: ts.TransformationContext) => (
290300
node.decorators,
291301
node.modifiers,
292302
node.exportClause,
293-
fileLiteral
303+
fileLiteral,
304+
node.isTypeOnly
294305
)
295306
: undefined;
296307
}
@@ -312,6 +323,17 @@ const transformer = (_: ts.Program) => (context: ts.TransformationContext) => (
312323
return resolver.isValueAliasDeclaration(node) ? node : undefined;
313324
}
314325

326+
function fixupImportPath(p:string) {
327+
let res = normalizePath(p);
328+
329+
/* Remove implicit extension */
330+
const ext = extname(res);
331+
if (ext && implicitExtensions.includes(ext.replace(/^\./, '')))
332+
res = res.slice(0, -ext.length);
333+
334+
return res;
335+
}
336+
315337
return ts.visitNode(sourceFile, visit);
316338
};
317339

tests/__fixtures/with-path/core/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import sum = require("@utils/sum");
22
export { sum } from "@utils";
3+
export { g } from "#utils/hello";
4+
export { sum as sum2 } from "#utils/sum";
35
export { NoRuntimecodeHere } from "@utils/types-only";
46
import { subs, NoRuntimecodeHere } from "@utils";
57
import "@circular/b";
@@ -36,4 +38,4 @@ const a = new A("");
3638

3739
testerClass.test(12);
3840
testerConst.test("12");
39-
})();
41+
})();
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const g = 'hello'

tests/__fixtures/with-path/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"paths": {
99
"path": ["https://external.url/path.js"],
1010
"@*": ["*"],
11+
"#utils/*": [ "./utils/*", "./secondary/*" ],
1112
"*": ["*"]
1213
},
1314

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export * from "@utils/sum";
22
export * from "@utils/subs";
3-
export * from "@utils/types-only";
3+
export { NoRuntimecodeHere } from "@utils/types-only";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const g = 'hello'

tests/index.ts

100644100755
Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { dirname, relative, join } from "path";
2-
import slash = require("slash");
2+
import { normalizePath } from '../src'
33
import read = require("fs-readdir-recursive");
44
import { readFileSync } from "fs";
55

@@ -14,6 +14,9 @@ describe("with-path", () => {
1414
.replace(/"(@.*)"/g, (_, moduleName) => {
1515
return `"${bindModuleToFile(moduleName, sourceDir)}"`;
1616
})
17+
.replace(/"(#utils\/.*)"/g, (_, moduleName) => {
18+
return `"${bindModuleToFile(moduleName, sourceDir)}"`;
19+
})
1720
.replace('"path"', '"https://external.url/path.js"')
1821
.replace('"circular/a"', '"../circular/a"');
1922
const generatedFile = join(
@@ -56,7 +59,13 @@ function bindModuleToFile(moduleName: string, sourceDir: string) {
5659
const match = /@(.*)/.exec(moduleName);
5760
if (match) {
5861
const out = match[1];
59-
const file = slash(relative(sourceDir, out));
62+
const file = normalizePath(relative(sourceDir, out));
6063
return file[0] === "." ? file : `./${file}`;
6164
}
65+
66+
let utilsModule = /^#utils\/(.+)/.exec(moduleName)?.[1];
67+
if (utilsModule) {
68+
const subDir = (utilsModule === 'hello') ? 'secondary' : 'utils';
69+
return normalizePath(relative(sourceDir, join(subDir, utilsModule)));
70+
}
6271
}

tests/tsconfig.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"exclude": [ "__fixtures" ],
3+
"compilerOptions": {
4+
"noEmit": true,
5+
"strict": true,
6+
"esModuleInterop": true
7+
}
8+
}

0 commit comments

Comments
 (0)