Skip to content

Commit 77ebe50

Browse files
committed
refactor: strict type checks
1 parent 982a7a9 commit 77ebe50

File tree

13 files changed

+83
-66
lines changed

13 files changed

+83
-66
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ jobs:
2424
- run: pnpm install
2525
- run: pnpm lint
2626
if: matrix.os == 'ubuntu-latest'
27+
- run: test:types
28+
if: matrix.os == 'ubuntu-latest'
2729
- run: pnpm build
2830
if: matrix.os == 'ubuntu-latest'
2931
- run: pnpm vitest --coverage

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"lint": "eslint --ext .ts,.js src test && prettier -c src test",
2424
"lint:fix": "eslint --ext .ts,.js src test --fix && prettier -w src test",
2525
"release": "pnpm test && pnpm build && changelogen --release && npm publish && git push --follow-tags",
26-
"test": "pnpm lint && vitest run"
26+
"test": "pnpm lint && pnpm test:types && vitest run",
27+
"test:types": "tsc --noEmit"
2728
},
2829
"dependencies": {
2930
"acorn": "^8.11.3",
@@ -45,4 +46,4 @@
4546
"vitest": "^1.2.2"
4647
},
4748
"packageManager": "pnpm@8.15.1"
48-
}
49+
}

src/_utils.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@ import { builtinModules } from "node:module";
22

33
export const BUILTIN_MODULES = new Set(builtinModules);
44

5-
export function normalizeSlash(string_) {
6-
return string_.replace(/\\/g, "/");
5+
export function normalizeSlash(path: string): string {
6+
return path.replace(/\\/g, "/");
77
}
88

9-
export function isObject(value) {
9+
export function isObject(value: unknown): boolean {
1010
return value !== null && typeof value === "object";
1111
}
1212

13-
export function matchAll(regex, string, addition) {
13+
export function matchAll(regex: RegExp, string: string, addition: any) {
1414
const matches = [];
1515
for (const match of string.matchAll(regex)) {
1616
matches.push({
1717
...addition,
1818
...match.groups,
1919
code: match[0],
2020
start: match.index,
21-
end: match.index + match[0].length,
21+
end: (match.index || 0) + match[0].length,
2222
});
2323
}
2424
return matches;

src/analyze.ts

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,13 @@ export function parseStaticImport(
122122
): ParsedStaticImport {
123123
const cleanedImports = clearImports(matched.imports);
124124

125-
const namedImports = {};
126-
for (const namedImport of cleanedImports
127-
.match(/{([^}]*)}/)?.[1]
128-
?.split(",") || []) {
129-
const [, source = namedImport.trim(), importName = source] =
130-
namedImport.match(/^\s*(\S*) as (\S*)\s*$/) || [];
131-
if (source && !TYPE_RE.test(source)) {
125+
const namedImports: Record<string, string> = {};
126+
const _matches = cleanedImports.match(/{([^}]*)}/)?.[1]?.split(",") || [];
127+
for (const namedImport of _matches) {
128+
const _match = namedImport.match(/^\s*(\S*) as (\S*)\s*$/);
129+
const source = _match?.[1] || namedImport.trim();
130+
const importName = _match?.[2] || source;
131+
if (!TYPE_RE.test(source)) {
132132
namedImports[source] = importName;
133133
}
134134
}
@@ -151,16 +151,14 @@ export function parseTypeImport(
151151

152152
const cleanedImports = clearImports(matched.imports);
153153

154-
const namedImports = {};
155-
for (const namedImport of cleanedImports
156-
.match(/{([^}]*)}/)?.[1]
157-
?.split(",") || []) {
158-
const [, source = namedImport.trim(), importName = source] = (() => {
159-
return /\s+as\s+/.test(namedImport)
160-
? namedImport.match(/^\s*type\s+(\S*) as (\S*)\s*$/) || []
161-
: namedImport.match(/^\s*type\s+(\S*)\s*$/) || [];
162-
})();
163-
154+
const namedImports: Record<string, string> = {};
155+
const _matches = cleanedImports.match(/{([^}]*)}/)?.[1]?.split(",") || [];
156+
for (const namedImport of _matches) {
157+
const _match = /\s+as\s+/.test(namedImport)
158+
? namedImport.match(/^\s*type\s+(\S*) as (\S*)\s*$/)
159+
: namedImport.match(/^\s*type\s+(\S*)\s*$/);
160+
const source = _match?.[1] || namedImport.trim();
161+
const importName = _match?.[2] || source;
164162
if (source && TYPE_RE.test(namedImport)) {
165163
namedImports[source] = importName;
166164
}
@@ -326,7 +324,7 @@ function normalizeExports(exports: (ESMExport & { declaration?: string })[]) {
326324
if (!exp.names && exp.name) {
327325
exp.names = [exp.name];
328326
}
329-
if (exp.type === "declaration") {
327+
if (exp.type === "declaration" && exp.declaration) {
330328
exp.declarationType = exp.declaration.replace(
331329
/^declare\s*/,
332330
"",
@@ -368,14 +366,15 @@ export async function resolveModuleExportNames(
368366

369367
// Recursive * exports
370368
for (const exp of exports) {
371-
if (exp.type === "star") {
372-
const subExports = await resolveModuleExportNames(exp.specifier, {
373-
...options,
374-
url,
375-
});
376-
for (const subExport of subExports) {
377-
exportNames.add(subExport);
378-
}
369+
if (exp.type !== "star" || !exp.specifier) {
370+
continue;
371+
}
372+
const subExports = await resolveModuleExportNames(exp.specifier, {
373+
...options,
374+
url,
375+
});
376+
for (const subExport of subExports) {
377+
exportNames.add(subExport);
379378
}
380379
}
381380

src/cjs.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,19 @@ export function createCommonJS(url: string): CommonjsContext {
1616
const __dirname = dirname(__filename);
1717

1818
// Lazy require
19-
let _nativeRequire;
20-
const getNativeRequire = () =>
21-
_nativeRequire || (_nativeRequire = createRequire(url));
22-
function require(id) {
19+
let _nativeRequire: typeof require;
20+
const getNativeRequire = () => {
21+
if (!_nativeRequire) {
22+
_nativeRequire = createRequire(url);
23+
}
24+
return _nativeRequire;
25+
};
26+
function require(id: string): any {
2327
return getNativeRequire()(id);
2428
}
25-
require.resolve = (id, options) => getNativeRequire().resolve(id, options);
26-
29+
require.resolve = function requireResolve(id: string, options: any): string {
30+
return getNativeRequire().resolve(id, options);
31+
};
2732
return {
2833
__filename,
2934
__dirname,

src/eval.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export async function evalModule(
3535

3636
export function transformModule(
3737
code: string,
38-
options?: EvaluateOptions,
38+
options: EvaluateOptions = {},
3939
): Promise<string> {
4040
// Convert JSON to module
4141
if (options.url && options.url.endsWith(".json")) {

src/resolve.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ function _tryModuleResolve(
2828
): URL | undefined {
2929
try {
3030
return moduleResolve(id, url, conditions);
31-
} catch (error) {
32-
if (!NOT_FOUND_ERRORS.has(error.code)) {
31+
} catch (error: any) {
32+
if (!NOT_FOUND_ERRORS.has(error?.code)) {
3333
throw error;
3434
}
3535
}
@@ -66,8 +66,8 @@ function _resolve(id: string | URL, options: ResolveOptions = {}): string {
6666
if (stat.isFile()) {
6767
return pathToFileURL(id);
6868
}
69-
} catch (error) {
70-
if (error.code !== "ENOENT") {
69+
} catch (error: any) {
70+
if (error?.code !== "ENOENT") {
7171
throw error;
7272
}
7373
}
@@ -80,10 +80,10 @@ function _resolve(id: string | URL, options: ResolveOptions = {}): string {
8080

8181
// Search paths
8282
const _urls: URL[] = (
83-
Array.isArray(options.url) ? options.url : [options.url]
83+
(Array.isArray(options.url) ? options.url : [options.url]) as URL[]
8484
)
8585
.filter(Boolean)
86-
.map((url) => new URL(normalizeid(url!.toString())));
86+
.map((url) => new URL(normalizeid(url.toString())));
8787
if (_urls.length === 0) {
8888
_urls.push(new URL(pathToFileURL(process.cwd())));
8989
}
@@ -226,21 +226,21 @@ function _findSubpath(subpath: string, exports: PackageJson["exports"]) {
226226
subpath = subpath.startsWith("/") ? `.${subpath}` : `./${subpath}`;
227227
}
228228

229-
if (subpath in exports) {
229+
if (subpath in (exports || {})) {
230230
return subpath;
231231
}
232232

233233
return _flattenExports(exports).find((p) => p.fsPath === subpath)?.subpath;
234234
}
235235

236236
function _flattenExports(
237-
exports: Exclude<PackageJson["exports"], string>,
237+
exports: Exclude<PackageJson["exports"], string> = {},
238238
parentSubpath = "./",
239239
): { subpath: string; fsPath: string; condition?: string }[] {
240240
return Object.entries(exports).flatMap(([key, value]) => {
241241
const [subpath, condition] = key.startsWith(".")
242242
? [key.slice(1), undefined]
243-
: [undefined, key];
243+
: ["", key];
244244
const _subPath = joinURL(parentSubpath, subpath);
245245
// eslint-disable-next-line unicorn/prefer-ternary
246246
if (typeof value === "string") {

src/syntax.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export async function isValidNodeImport(
8080
const options = { ...validNodeImportDefaults, ..._options };
8181

8282
const proto = getProtocol(id);
83-
if (proto && !options.allowedProtocols.includes(proto)) {
83+
if (proto && !options.allowedProtocols?.includes(proto)) {
8484
return false;
8585
}
8686

src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,5 @@ const ProtocolRegex = /^(?<proto>.{2,}?):.+$/;
7171

7272
export function getProtocol(id: string): string | undefined {
7373
const proto = id.match(ProtocolRegex);
74-
return proto ? proto.groups.proto : undefined;
74+
return proto ? proto.groups?.proto : undefined;
7575
}

test.mjs

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)