Skip to content

Commit 6478365

Browse files
authored
Add js extension for dts only dir (#72)
* feat(add-js-extension): enabled add javascript file extension to directory with type definitions files only * fix(test/dts): fix typecheck error raised by `skipLibCheck: false` * refactor(*): change to better code * feat(case): remove case for handling `.mjs` and `.mts` as typescript compiler requires those extension to be specified * fix(filepath): parse the file path of code for `.js` and `.mjs` case, removed `.js` case for `import`/`export` statement * test(dts): turn off `skipLibCheck` for type definition test and correct export extension in `dts`
1 parent 7fa7468 commit 6478365

25 files changed

+223
-175
lines changed

src/const.ts

+26-29
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,32 @@
1-
const extensionsUtil = () => {
2-
const extensions = {
3-
js: '.js',
4-
mjs: '.mjs',
5-
dts: '.d.ts',
6-
} as const;
7-
8-
const arrayfyExtensions = Object.values(extensions);
9-
10-
return {
11-
extensions,
12-
matchAnyJs: (filePath: string) => {
13-
return Boolean(
14-
arrayfyExtensions
15-
.filter((extension) => {
16-
return extension !== '.d.ts';
17-
})
18-
.find((extension) => {
19-
return filePath.endsWith(extension);
20-
})
21-
);
1+
class ExtensionsUtil {
2+
static readonly extensions = {
3+
javaScript: {
4+
js: '.js',
5+
mjs: '.mjs',
226
},
23-
matchAny: (filePath: string) => {
24-
return Boolean(
25-
arrayfyExtensions.find((extension) => {
26-
return filePath.endsWith(extension);
27-
})
28-
);
7+
typeDefinition: {
8+
dts: '.d.ts',
9+
dmts: '.d.mts',
2910
},
3011
} as const;
31-
};
12+
13+
static readonly matchJs = (filePath: string) => {
14+
const { js, mjs } = this.extensions.javaScript;
15+
16+
return filePath.endsWith(js) || filePath.endsWith(mjs);
17+
};
18+
19+
static readonly matchDts = (filePath: string) => {
20+
const { dts, dmts } = this.extensions.typeDefinition;
21+
22+
return filePath.endsWith(dts) || filePath.endsWith(dmts);
23+
};
24+
25+
static readonly matchEither = (filePath: string) => {
26+
return this.matchJs(filePath) || this.matchDts(filePath);
27+
};
28+
}
3229

3330
const separator = '/';
3431

35-
export { extensionsUtil, separator };
32+
export { ExtensionsUtil, separator };

src/read-write.ts

+11-8
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,32 @@ import path from 'path';
33
import ts from 'typescript';
44
import type { PartialConfig } from './cli-command-parser';
55
import traverseAndUpdateFileWithJSExtension from './traverse-and-update';
6-
import { extensionsUtil, separator } from './const';
6+
import { ExtensionsUtil, separator } from './const';
77
import Log from './log';
88

99
type SourceFile = Awaited<ReturnType<typeof getAllJSAndDTSCodes>[0]>;
1010

1111
type Files = ReadonlyArray<string>;
1212

13-
const getAllJSAndDTSFiles = (dir: string): Files => {
14-
return fs.readdirSync(dir).flatMap((file) => {
13+
const getAllJSAndDTSFiles = (directory: string): Files => {
14+
return fs.readdirSync(directory).flatMap((file) => {
1515
const filePath = path.posix.join(
16-
dir.split(path.sep).join(separator),
16+
directory.split(path.sep).join(separator),
1717
file
1818
);
19+
1920
if (fs.statSync(filePath).isDirectory()) {
2021
return getAllJSAndDTSFiles(filePath);
2122
}
22-
return !extensionsUtil().matchAny(filePath) ? [] : [filePath];
23+
24+
return !ExtensionsUtil.matchEither(filePath) ? [] : [filePath];
2325
});
2426
};
2527

26-
const readCode = (files: string): Promise<string> => {
27-
return new Promise((resolve, reject) => {
28+
const readCode = (files: string) => {
29+
return new Promise<string>((resolve, reject) => {
2830
let fetchData = '';
31+
2932
fs.createReadStream(files)
3033
.on('data', (data) => {
3134
return (fetchData = data.toString());
@@ -62,7 +65,7 @@ export default class File {
6265
include: ReadonlyArray<string>;
6366
}>) => {
6467
// user may import files from `common` into `src`
65-
const files: Files = include.concat(dir).flatMap(getAllJSAndDTSFiles);
68+
const files = include.concat(dir).flatMap(getAllJSAndDTSFiles);
6669

6770
return (await Promise.all(getAllJSAndDTSCodes(files))).flatMap(
6871
traverseAndUpdateFileWithJSExtension(files)

src/traverse-and-update.ts

+106-69
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,47 @@ import fs from 'fs';
22
import path from 'path';
33
import ts from 'typescript';
44
import type { SourceFile, Files } from './read-write';
5-
import { extensionsUtil, separator } from './const';
5+
import { ExtensionsUtil, separator } from './const';
66
import { asString } from './type';
77

8-
const formProperFilePath = ({
9-
filePath,
10-
}: Readonly<{
11-
filePath: string;
12-
}>) => {
13-
return filePath.split(separator).filter(Boolean).join(separator);
8+
const formProperFilePath = (
9+
props: Readonly<{
10+
filePath: string;
11+
}>
12+
) => {
13+
return props.filePath.split(separator).filter(Boolean).join(separator);
1414
};
1515

16-
const checkJavaScriptFileExistByAppend = ({
17-
filePath,
18-
}: Readonly<{
19-
filePath: string;
20-
}>) => {
21-
const { js, mjs } = extensionsUtil().extensions;
22-
if (fs.existsSync(`${filePath}${js}`)) {
23-
return js;
16+
const checkJavaScriptFileExistByAppend = (
17+
props: Readonly<{
18+
filePath: string;
19+
}>
20+
) => {
21+
const { js } = ExtensionsUtil.extensions.javaScript;
22+
23+
const jsFilePath = `${props.filePath}${js}`;
24+
25+
if (fs.existsSync(jsFilePath)) {
26+
return { extension: js, filePath: jsFilePath };
2427
}
25-
if (fs.existsSync(`${filePath}${mjs}`)) {
26-
return mjs;
28+
29+
return false;
30+
};
31+
32+
const checkTypeDefinitionFileExistByAppend = (
33+
props: Readonly<{
34+
filePath: string;
35+
}>
36+
) => {
37+
const { js } = ExtensionsUtil.extensions.javaScript;
38+
const { dts } = ExtensionsUtil.extensions.typeDefinition;
39+
40+
const dtsFilePath = `${props.filePath}${dts}`;
41+
42+
if (fs.existsSync(dtsFilePath)) {
43+
return { extension: js, filePath: dtsFilePath };
2744
}
45+
2846
return false;
2947
};
3048

@@ -36,66 +54,84 @@ const isDirectory = (filePath: string) => {
3654
}
3755
};
3856

39-
const addJSExtension = ({
40-
filePath,
41-
importPath,
42-
}: Readonly<{
43-
filePath: string;
44-
importPath: string;
45-
}>): Readonly<
46-
| {
47-
procedure: 'skip';
48-
}
49-
| {
50-
procedure: 'proceed';
51-
importPath: string;
52-
filePathImported: string;
53-
}
54-
> => {
55-
if (extensionsUtil().matchAnyJs(filePath)) {
56-
return {
57-
procedure: 'skip',
58-
};
59-
}
60-
if (!isDirectory(filePath)) {
61-
const extension = checkJavaScriptFileExistByAppend({
62-
filePath,
57+
const addJSExtensionConditionally = (
58+
props: Readonly<{
59+
filePath: string;
60+
importPath: string;
61+
checkType: 'dts' | 'js';
62+
}>
63+
) => {
64+
const check =
65+
props.checkType === 'js'
66+
? checkJavaScriptFileExistByAppend
67+
: checkTypeDefinitionFileExistByAppend;
68+
69+
const skip = {
70+
procedure: 'skip',
71+
} as const;
72+
73+
if (!isDirectory(props.filePath)) {
74+
const extensionResult = check({
75+
filePath: props.filePath,
6376
});
64-
if (!extension) {
65-
return {
66-
procedure: 'skip',
67-
};
77+
78+
if (!extensionResult) {
79+
return skip;
6880
}
81+
6982
return {
7083
procedure: 'proceed',
84+
absolutePath: extensionResult.filePath,
7185
importPath: formProperFilePath({
72-
filePath: `${importPath}${extension}`,
86+
filePath: `${props.importPath}${extensionResult.extension}`,
7387
}),
74-
filePathImported: formProperFilePath({
75-
filePath: `${filePath}${extension}`,
76-
}),
77-
};
88+
} as const;
7889
}
79-
const extension = checkJavaScriptFileExistByAppend({
80-
filePath: path.posix.join(filePath, 'index'),
90+
91+
const extensionResult = check({
92+
filePath: path.posix.join(props.filePath, 'index'),
8193
});
82-
if (!extension) {
83-
return {
84-
procedure: 'skip',
85-
};
94+
95+
if (!extensionResult) {
96+
return skip;
8697
}
8798

88-
const file = `index${extension}`;
99+
const file = `index${extensionResult.extension}`;
89100

90101
return {
91102
procedure: 'proceed',
103+
absolutePath: extensionResult.filePath,
92104
importPath: formProperFilePath({
93-
filePath: [importPath, separator, file].join(''),
94-
}),
95-
filePathImported: formProperFilePath({
96-
filePath: [filePath, separator, file].join(''),
105+
filePath: [props.importPath, separator, file].join(''),
97106
}),
98-
};
107+
} as const;
108+
};
109+
110+
const addJSExtension = (
111+
props: Readonly<{
112+
filePath: string;
113+
importPath: string;
114+
}>
115+
): ReturnType<typeof addJSExtensionConditionally> => {
116+
if (ExtensionsUtil.matchJs(props.filePath)) {
117+
return {
118+
procedure: 'skip',
119+
};
120+
}
121+
122+
const result = addJSExtensionConditionally({
123+
...props,
124+
checkType: 'js',
125+
});
126+
127+
if (result.procedure === 'proceed') {
128+
return result;
129+
}
130+
131+
return addJSExtensionConditionally({
132+
...props,
133+
checkType: 'dts',
134+
});
99135
};
100136

101137
const traverseAndUpdateFileWithJSExtension = (files: Files) => {
@@ -125,8 +161,6 @@ const traverseAndUpdateFileWithJSExtension = (files: Files) => {
125161
),
126162
});
127163

128-
const separator = '/';
129-
130164
const fileName = formProperFilePath({
131165
filePath: !moduleSpecifier.endsWith(separator)
132166
? moduleSpecifier
@@ -154,10 +188,12 @@ const traverseAndUpdateFileWithJSExtension = (files: Files) => {
154188
switch (result.procedure) {
155189
case 'proceed': {
156190
// if file name not included in list of js file read
157-
const { filePathImported, importPath } = result;
191+
158192
if (
159193
files.find((file) => {
160-
return file.endsWith(filePathImported);
194+
return file.endsWith(
195+
result.absolutePath
196+
);
161197
})
162198
) {
163199
const before = characters
@@ -174,7 +210,7 @@ const traverseAndUpdateFileWithJSExtension = (files: Files) => {
174210
before,
175211
after: before.replace(
176212
moduleSpecifier,
177-
importPath
213+
result.importPath
178214
),
179215
},
180216
];
@@ -184,6 +220,7 @@ const traverseAndUpdateFileWithJSExtension = (files: Files) => {
184220
}
185221
}
186222
}
223+
187224
return [];
188225
});
189226

@@ -192,8 +229,8 @@ const traverseAndUpdateFileWithJSExtension = (files: Files) => {
192229
: [
193230
{
194231
file: sourceFile.fileName,
195-
code: replaceNodes.reduce((prev, { before, after }) => {
196-
return prev.replace(before, after);
232+
code: replaceNodes.reduce((code, node) => {
233+
return code.replace(node.before, node.after);
197234
}, code),
198235
},
199236
];
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './utils/index.js';
2+
export * from './utils/util.mjs';
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
1-
export declare const identity = <T>(_: T) => {
2-
return T;
3-
};
1+
export declare const identity: <T>(_: T) => never;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export declare const utilIdentity: <T>(_: T) => never;
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './utils/index.js';
2+
export * from './utils/util.mjs';
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
// BUG: not working on windows
21
export * from './utils/index.js';
2+
export * from './utils/util.mjs';
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
1-
export declare const identity = <T>(_: T) => {
2-
return T;
3-
};
1+
export declare const identity: <T>(_: T) => never;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export declare const utilIdentity: <T>(_: T) => never;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const utilIdentity = (x) => {
2+
return x;
3+
};

test/process/expected-result/js/main/util.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import index from './index.js';
33
import { index } from './index.js';
44

55
import * as util from './util/index.mjs';
6-
import util from '../util/index.mjs';
7-
import { util } from '../util/index.mjs';
6+
import util from '..//util';
7+
import { util } from '../util/index';
88

99
export * as util from '../util/index.mjs';
10-
export * from '../util/index.mjs';
11-
export { util } from '../util/index.mjs';
10+
export * from '..//util';
11+
export { util } from '../util/index';

0 commit comments

Comments
 (0)