@reliverse/dler 1.6.3 → 1.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -1
- package/bin/app/agg/cmd.d.ts +0 -6
- package/bin/app/agg/cmd.js +6 -12
- package/bin/app/check/cmd.d.ts +16 -2
- package/bin/app/check/cmd.js +477 -25
- package/bin/app/cmds.d.ts +34 -35
- package/bin/app/deps/cmd.d.ts +21 -4
- package/bin/app/deps/cmd.js +31 -9
- package/bin/app/deps/impl/deps-types.d.ts +5 -0
- package/bin/app/deps/impl/wrapper.d.ts +2 -0
- package/bin/app/deps/impl/wrapper.js +57 -0
- package/bin/app/inject/cmd.d.ts +0 -1
- package/bin/app/inject/cmd.js +1 -2
- package/bin/app/libs/cmd.d.ts +0 -1
- package/bin/app/libs/cmd.js +0 -1
- package/bin/app/migrate/cmd.d.ts +0 -1
- package/bin/app/migrate/cmd.js +1 -2
- package/bin/app/relifso/cmd.d.ts +0 -1
- package/bin/app/relifso/cmd.js +1 -2
- package/bin/app/relifso/init/cmd.d.ts +0 -7
- package/bin/app/relifso/init/cmd.js +4 -11
- package/bin/app/relifso/rename/cmd.d.ts +0 -7
- package/bin/app/relifso/rename/cmd.js +5 -12
- package/bin/app/rempts/cmd/cmd.d.ts +0 -2
- package/bin/app/rempts/cmd/cmd.js +0 -2
- package/bin/app/rempts/cmdsTs/cmd.d.ts +0 -1
- package/bin/app/rempts/cmdsTs/cmd.js +0 -1
- package/bin/app/spell/cmd.d.ts +0 -2
- package/bin/app/spell/cmd.js +2 -4
- package/bin/init/info.js +1 -1
- package/bin/libs/sdk/sdk-impl/constants.d.ts +1 -0
- package/bin/libs/sdk/sdk-impl/constants.js +13 -0
- package/bin/libs/sdk/sdk-types.d.ts +31 -1
- package/package.json +2 -2
package/bin/app/check/cmd.js
CHANGED
|
@@ -1,44 +1,496 @@
|
|
|
1
|
+
import { getFileImportsExports, extname, join } from "@reliverse/pathkit";
|
|
2
|
+
import fs from "@reliverse/relifso";
|
|
1
3
|
import { relinka } from "@reliverse/relinka";
|
|
2
4
|
import {
|
|
3
5
|
defineCommand,
|
|
4
|
-
defineArgs,
|
|
5
6
|
selectPrompt,
|
|
6
|
-
multiselectPrompt
|
|
7
|
+
multiselectPrompt,
|
|
8
|
+
confirmPrompt,
|
|
9
|
+
defineArgs
|
|
7
10
|
} from "@reliverse/rempts";
|
|
11
|
+
import { readTSConfig } from "pkg-types";
|
|
12
|
+
import { checkMissingDependencies } from "../deps/impl/wrapper.js";
|
|
13
|
+
import { IGNORE_PATTERNS } from "../../libs/sdk/sdk-impl/constants.js";
|
|
14
|
+
const ALLOWED_FILE_EXTENSIONS = {
|
|
15
|
+
src: ["", ".ts", ".css", ".json"],
|
|
16
|
+
// ✅ .ts files allowed in src
|
|
17
|
+
"dist-npm": ["", ".js", ".css", ".json"],
|
|
18
|
+
// ❌ no .ts files in npm dist
|
|
19
|
+
"dist-jsr": ["", ".ts", ".css", ".json"],
|
|
20
|
+
// ✅ .ts files allowed in jsr dist
|
|
21
|
+
"dist-libs/npm": ["", ".js", ".css", ".json"],
|
|
22
|
+
// ❌ no .ts files in npm libs
|
|
23
|
+
"dist-libs/jsr": ["", ".ts", ".css", ".json"]
|
|
24
|
+
// ✅ .ts files allowed in jsr libs
|
|
25
|
+
};
|
|
26
|
+
const STRICT_FILE_EXTENSIONS = {
|
|
27
|
+
src: [".ts", ".css", ".json"],
|
|
28
|
+
// ✅ .ts files required in src
|
|
29
|
+
"dist-npm": [".js", ".css", ".json"],
|
|
30
|
+
// ❌ no .ts files in npm dist
|
|
31
|
+
"dist-jsr": [".ts", ".css", ".json"],
|
|
32
|
+
// ✅ .ts files required in jsr dist
|
|
33
|
+
"dist-libs/npm": [".js", ".css", ".json"],
|
|
34
|
+
// ❌ no .ts files in npm libs
|
|
35
|
+
"dist-libs/jsr": [".ts", ".css", ".json"]
|
|
36
|
+
// ✅ .ts files required in jsr libs
|
|
37
|
+
};
|
|
38
|
+
const ALLOWED_IMPORT_EXTENSIONS = {
|
|
39
|
+
src: ["", ".js", ".css", ".json"],
|
|
40
|
+
// ❌ no .ts imports (use .js)
|
|
41
|
+
"dist-npm": ["", ".js", ".css", ".json"],
|
|
42
|
+
// ❌ no .ts imports
|
|
43
|
+
"dist-jsr": ["", ".ts", ".css", ".json"],
|
|
44
|
+
// ✅ .ts imports allowed
|
|
45
|
+
"dist-libs/npm": ["", ".js", ".css", ".json"],
|
|
46
|
+
// ❌ no .ts imports
|
|
47
|
+
"dist-libs/jsr": ["", ".ts", ".css", ".json"]
|
|
48
|
+
// ✅ .ts imports allowed
|
|
49
|
+
};
|
|
50
|
+
const STRICT_IMPORT_EXTENSIONS = {
|
|
51
|
+
src: [".js", ".css", ".json"],
|
|
52
|
+
// ❌ no .ts imports, no empty
|
|
53
|
+
"dist-npm": [".js", ".css", ".json"],
|
|
54
|
+
// ❌ no .ts imports
|
|
55
|
+
"dist-jsr": [".ts", ".css", ".json"],
|
|
56
|
+
// ✅ .ts imports required
|
|
57
|
+
"dist-libs/npm": [".js", ".css", ".json"],
|
|
58
|
+
// ❌ no .ts imports
|
|
59
|
+
"dist-libs/jsr": [".ts", ".css", ".json"]
|
|
60
|
+
// ✅ .ts imports required
|
|
61
|
+
};
|
|
62
|
+
async function validateDirectory(dir) {
|
|
63
|
+
try {
|
|
64
|
+
const stat = await fs.stat(dir);
|
|
65
|
+
return stat.isDirectory();
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function shouldIgnoreFile(filePath) {
|
|
71
|
+
const pathSegments = filePath.split("/");
|
|
72
|
+
return IGNORE_PATTERNS.some(
|
|
73
|
+
(pattern) => pathSegments.some((segment) => segment.includes(pattern))
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
async function getAllFiles(dir, onProgress) {
|
|
77
|
+
const results = [];
|
|
78
|
+
let fileCount = 0;
|
|
79
|
+
async function searchDirectory(directory) {
|
|
80
|
+
try {
|
|
81
|
+
const files = await fs.readdir(directory);
|
|
82
|
+
for (const file of files) {
|
|
83
|
+
const fullPath = join(directory, file);
|
|
84
|
+
if (shouldIgnoreFile(fullPath)) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const stat = await fs.stat(fullPath);
|
|
89
|
+
if (stat.isDirectory()) {
|
|
90
|
+
if (file === "templates") continue;
|
|
91
|
+
await searchDirectory(fullPath);
|
|
92
|
+
} else {
|
|
93
|
+
results.push(fullPath);
|
|
94
|
+
fileCount++;
|
|
95
|
+
onProgress?.(fileCount, fileCount, fullPath);
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
relinka("warn", `skipping inaccessible file: ${fullPath}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
relinka("warn", `skipping inaccessible directory: ${directory}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (!await validateDirectory(dir)) {
|
|
106
|
+
throw new Error(`directory "${dir}" does not exist or is not accessible`);
|
|
107
|
+
}
|
|
108
|
+
await searchDirectory(dir);
|
|
109
|
+
return results;
|
|
110
|
+
}
|
|
111
|
+
async function validateModuleResolution() {
|
|
112
|
+
try {
|
|
113
|
+
const tsconfig = await readTSConfig();
|
|
114
|
+
const moduleResolution = tsconfig?.compilerOptions?.moduleResolution;
|
|
115
|
+
if (!moduleResolution) {
|
|
116
|
+
throw new Error("moduleResolution is not specified in tsconfig.json");
|
|
117
|
+
}
|
|
118
|
+
if (moduleResolution !== "bundler" && moduleResolution !== "nodenext") {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`unsupported moduleResolution: ${moduleResolution}. Only "bundler" and "nodenext" are supported`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
return moduleResolution;
|
|
124
|
+
} catch (error) {
|
|
125
|
+
throw new Error(
|
|
126
|
+
`failed to read tsconfig.json: ${error instanceof Error ? error.message : "unknown error"}`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function getAllowedFileExtensions(directory, strict, moduleResolution) {
|
|
131
|
+
if (!strict) {
|
|
132
|
+
return ALLOWED_FILE_EXTENSIONS[directory];
|
|
133
|
+
}
|
|
134
|
+
if (moduleResolution === "bundler") {
|
|
135
|
+
return STRICT_FILE_EXTENSIONS[directory];
|
|
136
|
+
}
|
|
137
|
+
return STRICT_FILE_EXTENSIONS[directory];
|
|
138
|
+
}
|
|
139
|
+
function getAllowedImportExtensions(directory, strict) {
|
|
140
|
+
if (strict) {
|
|
141
|
+
return STRICT_IMPORT_EXTENSIONS[directory];
|
|
142
|
+
}
|
|
143
|
+
return ALLOWED_IMPORT_EXTENSIONS[directory];
|
|
144
|
+
}
|
|
145
|
+
export async function checkFileExtensions(options) {
|
|
146
|
+
const startTime = Date.now();
|
|
147
|
+
const issues = [];
|
|
148
|
+
const { directory, strict, moduleResolution, onProgress } = options;
|
|
149
|
+
const allowedExts = getAllowedFileExtensions(
|
|
150
|
+
directory,
|
|
151
|
+
strict,
|
|
152
|
+
moduleResolution
|
|
153
|
+
);
|
|
154
|
+
try {
|
|
155
|
+
const files = await getAllFiles(directory, onProgress);
|
|
156
|
+
const batchSize = 50;
|
|
157
|
+
const batches = [];
|
|
158
|
+
for (let i = 0; i < files.length; i += batchSize) {
|
|
159
|
+
batches.push(files.slice(i, i + batchSize));
|
|
160
|
+
}
|
|
161
|
+
for (const [batchIndex, batch] of batches.entries()) {
|
|
162
|
+
const batchPromises = batch.map(async (file, fileIndex) => {
|
|
163
|
+
const globalIndex = batchIndex * batchSize + fileIndex;
|
|
164
|
+
onProgress?.(globalIndex + 1, files.length, file);
|
|
165
|
+
const ext = extname(file);
|
|
166
|
+
if (!allowedExts.includes(ext)) {
|
|
167
|
+
let message = `file has disallowed extension "${ext}" (allowed: ${allowedExts.join(", ")})`;
|
|
168
|
+
if (ext === ".ts" && (directory === "dist-npm" || directory === "dist-libs/npm")) {
|
|
169
|
+
message = `typescript file found in javascript environment: ${file} (should be compiled to .js)`;
|
|
170
|
+
} else if (ext === ".js" && (directory === "src" || directory === "dist-jsr" || directory === "dist-libs/jsr")) {
|
|
171
|
+
message = `javascript file found in typescript environment: ${file} (should be .ts)`;
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
file,
|
|
175
|
+
message,
|
|
176
|
+
type: "file-extension"
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
});
|
|
181
|
+
const batchResults = await Promise.all(batchPromises);
|
|
182
|
+
issues.push(...batchResults.filter(Boolean));
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
success: issues.length === 0,
|
|
186
|
+
issues,
|
|
187
|
+
stats: {
|
|
188
|
+
filesChecked: files.length,
|
|
189
|
+
importsChecked: 0,
|
|
190
|
+
timeElapsed: Date.now() - startTime
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
} catch (error) {
|
|
194
|
+
throw new Error(
|
|
195
|
+
`failed to check file extensions: ${error instanceof Error ? error.message : "unknown error"}`
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
export async function checkPathExtensions(options) {
|
|
200
|
+
const startTime = Date.now();
|
|
201
|
+
const issues = [];
|
|
202
|
+
const { directory, strict, onProgress } = options;
|
|
203
|
+
const allowedExts = getAllowedImportExtensions(directory, strict);
|
|
204
|
+
try {
|
|
205
|
+
const files = await getAllFiles(directory);
|
|
206
|
+
let totalImports = 0;
|
|
207
|
+
const importableFiles = files.filter((file) => {
|
|
208
|
+
const ext = extname(file);
|
|
209
|
+
return [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"].includes(ext);
|
|
210
|
+
});
|
|
211
|
+
const batchSize = 20;
|
|
212
|
+
const batches = [];
|
|
213
|
+
for (let i = 0; i < importableFiles.length; i += batchSize) {
|
|
214
|
+
batches.push(importableFiles.slice(i, i + batchSize));
|
|
215
|
+
}
|
|
216
|
+
for (const [batchIndex, batch] of batches.entries()) {
|
|
217
|
+
const batchPromises = batch.map(async (file, fileIndex) => {
|
|
218
|
+
const globalIndex = batchIndex * batchSize + fileIndex;
|
|
219
|
+
onProgress?.(globalIndex + 1, importableFiles.length, file);
|
|
220
|
+
try {
|
|
221
|
+
const content = await fs.readFile(file, "utf-8");
|
|
222
|
+
const imports = getFileImportsExports(content, {
|
|
223
|
+
kind: "import",
|
|
224
|
+
pathTypes: ["relative", "alias"]
|
|
225
|
+
});
|
|
226
|
+
totalImports += imports.length;
|
|
227
|
+
const fileIssues = [];
|
|
228
|
+
for (const imp of imports) {
|
|
229
|
+
if (!imp.source) continue;
|
|
230
|
+
const ext = extname(imp.source);
|
|
231
|
+
if (!allowedExts.includes(ext)) {
|
|
232
|
+
const isTypeScriptImport = ext === ".ts";
|
|
233
|
+
const isJsEnvironment = directory === "src" || directory === "dist-npm" || directory === "dist-libs/npm";
|
|
234
|
+
let message;
|
|
235
|
+
if (isTypeScriptImport && isJsEnvironment) {
|
|
236
|
+
message = `import uses .ts extension in javascript environment: ${imp.source} (use .js extension instead)`;
|
|
237
|
+
} else {
|
|
238
|
+
message = `import has disallowed extension "${ext}": ${imp.source} (allowed: ${allowedExts.join(", ")})`;
|
|
239
|
+
}
|
|
240
|
+
fileIssues.push({
|
|
241
|
+
file,
|
|
242
|
+
message,
|
|
243
|
+
type: "path-extension",
|
|
244
|
+
line: getLineNumber(content, imp.start),
|
|
245
|
+
source: imp.source
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return { issues: fileIssues, importCount: imports.length };
|
|
250
|
+
} catch {
|
|
251
|
+
relinka("warn", `skipping unreadable file: ${file}`);
|
|
252
|
+
return { issues: [], importCount: 0 };
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
const batchResults = await Promise.all(batchPromises);
|
|
256
|
+
for (const result of batchResults) {
|
|
257
|
+
issues.push(...result.issues);
|
|
258
|
+
totalImports += result.importCount;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
success: issues.length === 0,
|
|
263
|
+
issues,
|
|
264
|
+
stats: {
|
|
265
|
+
filesChecked: importableFiles.length,
|
|
266
|
+
importsChecked: totalImports,
|
|
267
|
+
timeElapsed: Date.now() - startTime
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
} catch (error) {
|
|
271
|
+
throw new Error(
|
|
272
|
+
`failed to check path extensions: ${error instanceof Error ? error.message : "unknown error"}`
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function getLineNumber(content, position) {
|
|
277
|
+
return content.slice(0, position).split("\n").length;
|
|
278
|
+
}
|
|
279
|
+
function displayResults(checkType, directory, result) {
|
|
280
|
+
const { success, issues, stats } = result;
|
|
281
|
+
if (success) {
|
|
282
|
+
relinka("success", `\u2713 ${checkType} check passed for ${directory}`);
|
|
283
|
+
relinka(
|
|
284
|
+
"info",
|
|
285
|
+
` files checked: ${stats.filesChecked}, imports: ${stats.importsChecked}, time: ${stats.timeElapsed}ms`
|
|
286
|
+
);
|
|
287
|
+
} else {
|
|
288
|
+
relinka(
|
|
289
|
+
"error",
|
|
290
|
+
`\u2717 ${checkType} check failed for ${directory} (${issues.length} issues)`
|
|
291
|
+
);
|
|
292
|
+
const fileIssues = issues.filter((i) => i.type === "file-extension");
|
|
293
|
+
const pathIssues = issues.filter((i) => i.type === "path-extension");
|
|
294
|
+
const missingDepIssues = issues.filter(
|
|
295
|
+
(i) => i.type === "missing-dependency"
|
|
296
|
+
);
|
|
297
|
+
const builtinIssues = issues.filter((i) => i.type === "builtin-module");
|
|
298
|
+
if (fileIssues.length > 0) {
|
|
299
|
+
relinka("error", ` file extension issues (${fileIssues.length}):`);
|
|
300
|
+
for (const issue of fileIssues.slice(0, 10)) {
|
|
301
|
+
relinka("error", ` ${issue.file}: ${issue.message}`);
|
|
302
|
+
}
|
|
303
|
+
if (fileIssues.length > 10) {
|
|
304
|
+
relinka("error", ` ... and ${fileIssues.length - 10} more`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (pathIssues.length > 0) {
|
|
308
|
+
relinka("error", ` import extension issues (${pathIssues.length}):`);
|
|
309
|
+
for (const issue of pathIssues.slice(0, 10)) {
|
|
310
|
+
relinka("error", ` ${issue.file}:${issue.line}: ${issue.message}`);
|
|
311
|
+
}
|
|
312
|
+
if (pathIssues.length > 10) {
|
|
313
|
+
relinka("error", ` ... and ${pathIssues.length - 10} more`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (missingDepIssues.length > 0) {
|
|
317
|
+
relinka("error", ` missing dependencies (${missingDepIssues.length}):`);
|
|
318
|
+
for (const issue of missingDepIssues.slice(0, 10)) {
|
|
319
|
+
relinka("error", ` ${issue.message}`);
|
|
320
|
+
}
|
|
321
|
+
if (missingDepIssues.length > 10) {
|
|
322
|
+
relinka("error", ` ... and ${missingDepIssues.length - 10} more`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (builtinIssues.length > 0) {
|
|
326
|
+
relinka("warn", ` builtin modules used (${builtinIssues.length}):`);
|
|
327
|
+
for (const issue of builtinIssues.slice(0, 10)) {
|
|
328
|
+
relinka("warn", ` ${issue.message}`);
|
|
329
|
+
}
|
|
330
|
+
if (builtinIssues.length > 10) {
|
|
331
|
+
relinka("warn", ` ... and ${builtinIssues.length - 10} more`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
relinka(
|
|
335
|
+
"info",
|
|
336
|
+
` stats: ${stats.filesChecked} files, ${stats.importsChecked} imports, ${stats.timeElapsed}ms`
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
8
340
|
export default defineCommand({
|
|
9
341
|
meta: {
|
|
10
342
|
name: "check",
|
|
11
343
|
version: "1.0.0",
|
|
12
|
-
description: "
|
|
344
|
+
description: "check your codebase source and dists for any issues."
|
|
13
345
|
},
|
|
14
346
|
args: defineArgs({
|
|
15
|
-
|
|
347
|
+
directory: {
|
|
348
|
+
type: "string",
|
|
349
|
+
description: "directory to check (src, dist-npm, dist-jsr, dist-libs/npm, dist-libs/jsr, or all)"
|
|
350
|
+
},
|
|
351
|
+
checks: {
|
|
16
352
|
type: "string",
|
|
17
|
-
|
|
18
|
-
|
|
353
|
+
description: "comma-separated list of checks to run (missing-dependencies,file-extensions,path-extensions)"
|
|
354
|
+
},
|
|
355
|
+
strict: {
|
|
356
|
+
type: "boolean",
|
|
357
|
+
description: "enable strict mode (requires explicit extensions)"
|
|
358
|
+
},
|
|
359
|
+
json: {
|
|
360
|
+
type: "boolean",
|
|
361
|
+
description: "output results in JSON format"
|
|
19
362
|
}
|
|
20
363
|
}),
|
|
21
364
|
async run({ args }) {
|
|
22
365
|
relinka(
|
|
23
366
|
"info",
|
|
24
|
-
"
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
367
|
+
"this command checks your codebase for extension and dependency issues."
|
|
368
|
+
);
|
|
369
|
+
relinka(
|
|
370
|
+
"info",
|
|
371
|
+
"\u{1F4C1} file rules: .ts files allowed in src/jsr dirs, .js files in npm dirs"
|
|
372
|
+
);
|
|
373
|
+
relinka(
|
|
374
|
+
"info",
|
|
375
|
+
"\u{1F4E6} import rules: use .js imports in src/npm dirs, .ts imports in jsr dirs"
|
|
376
|
+
);
|
|
377
|
+
let moduleResolution;
|
|
378
|
+
try {
|
|
379
|
+
moduleResolution = await validateModuleResolution();
|
|
380
|
+
relinka("info", `using moduleResolution: ${moduleResolution}`);
|
|
381
|
+
} catch (error) {
|
|
382
|
+
relinka(
|
|
383
|
+
"error",
|
|
384
|
+
error instanceof Error ? error.message : "unknown error"
|
|
385
|
+
);
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
let dir;
|
|
389
|
+
let checks;
|
|
390
|
+
let strict;
|
|
391
|
+
if (args.directory) {
|
|
392
|
+
dir = args.directory;
|
|
393
|
+
} else {
|
|
394
|
+
dir = await selectPrompt({
|
|
395
|
+
title: "select a directory to check",
|
|
396
|
+
options: [
|
|
397
|
+
{ label: "all directories", value: "all" },
|
|
398
|
+
{ label: "src (typescript source)", value: "src" },
|
|
399
|
+
{ label: "dist-npm (compiled js)", value: "dist-npm" },
|
|
400
|
+
{ label: "dist-jsr (typescript)", value: "dist-jsr" },
|
|
401
|
+
{ label: "dist-libs/npm (compiled js)", value: "dist-libs/npm" },
|
|
402
|
+
{ label: "dist-libs/jsr (typescript)", value: "dist-libs/jsr" }
|
|
403
|
+
]
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
if (args.checks) {
|
|
407
|
+
checks = args.checks.split(",");
|
|
408
|
+
} else {
|
|
409
|
+
checks = await multiselectPrompt({
|
|
410
|
+
title: "select checks to run",
|
|
411
|
+
options: [
|
|
412
|
+
{ label: "missing dependencies", value: "missing-dependencies" },
|
|
413
|
+
{
|
|
414
|
+
label: "file extensions (.ts/.js files)",
|
|
415
|
+
value: "file-extensions"
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
label: "import path extensions (.ts/.js imports)",
|
|
419
|
+
value: "path-extensions"
|
|
420
|
+
}
|
|
421
|
+
]
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
if (args.strict !== void 0) {
|
|
425
|
+
strict = args.strict;
|
|
426
|
+
} else {
|
|
427
|
+
strict = await confirmPrompt({
|
|
428
|
+
title: "activate strict mode?",
|
|
429
|
+
content: "strict mode requires explicit extensions (no empty extensions). files: .ts in src/jsr dirs, .js in npm dirs. imports: .js in src/npm dirs, .ts in jsr dirs. templates folder is always exempt."
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
if (checks.length === 0) {
|
|
433
|
+
relinka("warn", "no checks selected, exiting...");
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
const directories = dir === "all" ? [
|
|
437
|
+
"src",
|
|
438
|
+
"dist-npm",
|
|
439
|
+
"dist-jsr",
|
|
440
|
+
"dist-libs/npm",
|
|
441
|
+
"dist-libs/jsr"
|
|
442
|
+
] : [dir];
|
|
443
|
+
for (const directory of directories) {
|
|
444
|
+
relinka("info", `
|
|
445
|
+
checking directory: ${directory}`);
|
|
446
|
+
const onProgress = (current, total) => {
|
|
447
|
+
if (current % 10 === 0 || current === total) {
|
|
448
|
+
process.stdout.write(`\r progress: ${current}/${total} files...`);
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
try {
|
|
452
|
+
if (checks.includes("missing-dependencies")) {
|
|
453
|
+
process.stdout.write(" checking missing dependencies...\n");
|
|
454
|
+
const result = await checkMissingDependencies({
|
|
455
|
+
directory,
|
|
456
|
+
strict: false,
|
|
457
|
+
// not used for deps check
|
|
458
|
+
moduleResolution,
|
|
459
|
+
// not used for deps check
|
|
460
|
+
onProgress
|
|
461
|
+
});
|
|
462
|
+
process.stdout.write("\r");
|
|
463
|
+
displayResults("missing dependencies", directory, result);
|
|
464
|
+
}
|
|
465
|
+
if (checks.includes("file-extensions")) {
|
|
466
|
+
process.stdout.write(" checking file extensions...\n");
|
|
467
|
+
const result = await checkFileExtensions({
|
|
468
|
+
directory,
|
|
469
|
+
strict,
|
|
470
|
+
moduleResolution,
|
|
471
|
+
onProgress
|
|
472
|
+
});
|
|
473
|
+
process.stdout.write("\r");
|
|
474
|
+
displayResults("file extensions", directory, result);
|
|
475
|
+
}
|
|
476
|
+
if (checks.includes("path-extensions")) {
|
|
477
|
+
process.stdout.write(" checking import path extensions...\n");
|
|
478
|
+
const result = await checkPathExtensions({
|
|
479
|
+
directory,
|
|
480
|
+
strict,
|
|
481
|
+
moduleResolution,
|
|
482
|
+
onProgress
|
|
483
|
+
});
|
|
484
|
+
process.stdout.write("\r");
|
|
485
|
+
displayResults("path extensions", directory, result);
|
|
486
|
+
}
|
|
487
|
+
} catch (error) {
|
|
488
|
+
relinka(
|
|
489
|
+
"error",
|
|
490
|
+
`failed to check ${directory}: ${error instanceof Error ? error.message : "unknown error"}`
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
relinka("success", "all checks completed!");
|
|
43
495
|
}
|
|
44
496
|
});
|