@macrulez/devtoolz 0.1.0
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/LICENSE +21 -0
- package/README.md +262 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +330 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/case-check/core.d.ts +17 -0
- package/dist/commands/case-check/core.js +46 -0
- package/dist/commands/case-check/core.js.map +1 -0
- package/dist/commands/case-check/parse.d.ts +10 -0
- package/dist/commands/case-check/parse.js +52 -0
- package/dist/commands/case-check/parse.js.map +1 -0
- package/dist/commands/case-check/report.d.ts +3 -0
- package/dist/commands/case-check/report.js +38 -0
- package/dist/commands/case-check/report.js.map +1 -0
- package/dist/commands/case-check/resolve-case.d.ts +14 -0
- package/dist/commands/case-check/resolve-case.js +163 -0
- package/dist/commands/case-check/resolve-case.js.map +1 -0
- package/dist/commands/case-check/run.d.ts +31 -0
- package/dist/commands/case-check/run.js +72 -0
- package/dist/commands/case-check/run.js.map +1 -0
- package/dist/commands/case-check/tsconfig-paths.d.ts +19 -0
- package/dist/commands/case-check/tsconfig-paths.js +119 -0
- package/dist/commands/case-check/tsconfig-paths.js.map +1 -0
- package/dist/commands/case-check/vue.d.ts +8 -0
- package/dist/commands/case-check/vue.js +26 -0
- package/dist/commands/case-check/vue.js.map +1 -0
- package/dist/commands/console-strip/core.d.ts +23 -0
- package/dist/commands/console-strip/core.js +104 -0
- package/dist/commands/console-strip/core.js.map +1 -0
- package/dist/commands/console-strip/report.d.ts +3 -0
- package/dist/commands/console-strip/report.js +47 -0
- package/dist/commands/console-strip/report.js.map +1 -0
- package/dist/commands/console-strip/run.d.ts +30 -0
- package/dist/commands/console-strip/run.js +55 -0
- package/dist/commands/console-strip/run.js.map +1 -0
- package/dist/commands/console-strip/vue.d.ts +8 -0
- package/dist/commands/console-strip/vue.js +28 -0
- package/dist/commands/console-strip/vue.js.map +1 -0
- package/dist/commands/dead-exports/core.d.ts +19 -0
- package/dist/commands/dead-exports/core.js +136 -0
- package/dist/commands/dead-exports/core.js.map +1 -0
- package/dist/commands/dead-exports/entry.d.ts +2 -0
- package/dist/commands/dead-exports/entry.js +93 -0
- package/dist/commands/dead-exports/entry.js.map +1 -0
- package/dist/commands/dead-exports/parse.d.ts +30 -0
- package/dist/commands/dead-exports/parse.js +174 -0
- package/dist/commands/dead-exports/parse.js.map +1 -0
- package/dist/commands/dead-exports/report.d.ts +3 -0
- package/dist/commands/dead-exports/report.js +27 -0
- package/dist/commands/dead-exports/report.js.map +1 -0
- package/dist/commands/dead-exports/resolve.d.ts +10 -0
- package/dist/commands/dead-exports/resolve.js +58 -0
- package/dist/commands/dead-exports/resolve.js.map +1 -0
- package/dist/commands/dead-exports/run.d.ts +21 -0
- package/dist/commands/dead-exports/run.js +51 -0
- package/dist/commands/dead-exports/run.js.map +1 -0
- package/dist/commands/dead-exports/workspace.d.ts +14 -0
- package/dist/commands/dead-exports/workspace.js +99 -0
- package/dist/commands/dead-exports/workspace.js.map +1 -0
- package/dist/commands/exports-doctor/core.d.ts +13 -0
- package/dist/commands/exports-doctor/core.js +85 -0
- package/dist/commands/exports-doctor/core.js.map +1 -0
- package/dist/commands/exports-doctor/parse.d.ts +20 -0
- package/dist/commands/exports-doctor/parse.js +80 -0
- package/dist/commands/exports-doctor/parse.js.map +1 -0
- package/dist/commands/exports-doctor/report.d.ts +3 -0
- package/dist/commands/exports-doctor/report.js +36 -0
- package/dist/commands/exports-doctor/report.js.map +1 -0
- package/dist/commands/exports-doctor/resolve-path.d.ts +10 -0
- package/dist/commands/exports-doctor/resolve-path.js +46 -0
- package/dist/commands/exports-doctor/resolve-path.js.map +1 -0
- package/dist/commands/exports-doctor/run.d.ts +13 -0
- package/dist/commands/exports-doctor/run.js +25 -0
- package/dist/commands/exports-doctor/run.js.map +1 -0
- package/dist/commands/readme-check/core.d.ts +22 -0
- package/dist/commands/readme-check/core.js +92 -0
- package/dist/commands/readme-check/core.js.map +1 -0
- package/dist/commands/readme-check/extract.d.ts +9 -0
- package/dist/commands/readme-check/extract.js +48 -0
- package/dist/commands/readme-check/extract.js.map +1 -0
- package/dist/commands/readme-check/lang.d.ts +8 -0
- package/dist/commands/readme-check/lang.js +21 -0
- package/dist/commands/readme-check/lang.js.map +1 -0
- package/dist/commands/readme-check/report.d.ts +3 -0
- package/dist/commands/readme-check/report.js +31 -0
- package/dist/commands/readme-check/report.js.map +1 -0
- package/dist/commands/readme-check/run.d.ts +19 -0
- package/dist/commands/readme-check/run.js +34 -0
- package/dist/commands/readme-check/run.js.map +1 -0
- package/dist/commands/readme-check/tsconfig.d.ts +9 -0
- package/dist/commands/readme-check/tsconfig.js +26 -0
- package/dist/commands/readme-check/tsconfig.js.map +1 -0
- package/dist/commands/readme-check/typecheck.d.ts +31 -0
- package/dist/commands/readme-check/typecheck.js +82 -0
- package/dist/commands/readme-check/typecheck.js.map +1 -0
- package/dist/commands/strip-comments/apply-deletions.d.ts +17 -0
- package/dist/commands/strip-comments/apply-deletions.js +74 -0
- package/dist/commands/strip-comments/apply-deletions.js.map +1 -0
- package/dist/commands/strip-comments/core.d.ts +15 -0
- package/dist/commands/strip-comments/core.js +111 -0
- package/dist/commands/strip-comments/core.js.map +1 -0
- package/dist/commands/strip-comments/report.d.ts +6 -0
- package/dist/commands/strip-comments/report.js +30 -0
- package/dist/commands/strip-comments/report.js.map +1 -0
- package/dist/commands/strip-comments/run.d.ts +28 -0
- package/dist/commands/strip-comments/run.js +50 -0
- package/dist/commands/strip-comments/run.js.map +1 -0
- package/dist/commands/strip-comments/vue.d.ts +6 -0
- package/dist/commands/strip-comments/vue.js +65 -0
- package/dist/commands/strip-comments/vue.js.map +1 -0
- package/dist/format/colors.d.ts +8 -0
- package/dist/format/colors.js +14 -0
- package/dist/format/colors.js.map +1 -0
- package/dist/format/diff-render.d.ts +2 -0
- package/dist/format/diff-render.js +35 -0
- package/dist/format/diff-render.js.map +1 -0
- package/dist/format/file-list.d.ts +14 -0
- package/dist/format/file-list.js +26 -0
- package/dist/format/file-list.js.map +1 -0
- package/dist/format/findings-list.d.ts +14 -0
- package/dist/format/findings-list.js +23 -0
- package/dist/format/findings-list.js.map +1 -0
- package/dist/format/vibes.d.ts +10 -0
- package/dist/format/vibes.js +67 -0
- package/dist/format/vibes.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/diff.d.ts +1 -0
- package/dist/utils/diff.js +13 -0
- package/dist/utils/diff.js.map +1 -0
- package/dist/utils/walk.d.ts +19 -0
- package/dist/utils/walk.js +96 -0
- package/dist/utils/walk.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { findSpecifiers } from './parse.js';
|
|
2
|
+
import { findSpecifiersInVue } from './vue.js';
|
|
3
|
+
import { checkSpecifierCase } from './resolve-case.js';
|
|
4
|
+
import { resolveAlias } from './tsconfig-paths.js';
|
|
5
|
+
export function checkFile(text, file, paths) {
|
|
6
|
+
const occurrences = file.endsWith('.vue')
|
|
7
|
+
? findSpecifiersInVue(text, file)
|
|
8
|
+
: findSpecifiers(text, file);
|
|
9
|
+
const findings = [];
|
|
10
|
+
for (const occ of occurrences) {
|
|
11
|
+
if (occ.specifier.startsWith('.')) {
|
|
12
|
+
const result = checkSpecifierCase(file, occ.specifier);
|
|
13
|
+
if (result) {
|
|
14
|
+
findings.push({
|
|
15
|
+
specifier: occ.specifier,
|
|
16
|
+
correctedSpecifier: result.correctedSpecifier,
|
|
17
|
+
isAlias: false,
|
|
18
|
+
start: occ.start,
|
|
19
|
+
end: occ.end,
|
|
20
|
+
line: occ.line,
|
|
21
|
+
column: occ.column,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (!paths)
|
|
27
|
+
continue;
|
|
28
|
+
const relativeForm = resolveAlias(file, occ.specifier, paths);
|
|
29
|
+
if (!relativeForm)
|
|
30
|
+
continue;
|
|
31
|
+
const result = checkSpecifierCase(file, relativeForm);
|
|
32
|
+
if (result) {
|
|
33
|
+
findings.push({
|
|
34
|
+
specifier: occ.specifier,
|
|
35
|
+
correctedSpecifier: result.correctedSpecifier,
|
|
36
|
+
isAlias: true,
|
|
37
|
+
start: occ.start,
|
|
38
|
+
end: occ.end,
|
|
39
|
+
line: occ.line,
|
|
40
|
+
column: occ.column,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return findings;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../src/commands/case-check/core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAsB,MAAM,qBAAqB,CAAA;AAkBtE,MAAM,UAAU,SAAS,CACvB,IAAY,EACZ,IAAY,EACZ,KAA2B;IAE3B,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QACvC,CAAC,CAAC,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC;QACjC,CAAC,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAC9B,MAAM,QAAQ,GAAuB,EAAE,CAAA;IAEvC,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,IAAI,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAA;YACtD,IAAI,MAAM,EAAE,CAAC;gBACX,QAAQ,CAAC,IAAI,CAAC;oBACZ,SAAS,EAAE,GAAG,CAAC,SAAS;oBACxB,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;oBAC7C,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,GAAG,EAAE,GAAG,CAAC,GAAG;oBACZ,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAA;YACJ,CAAC;YACD,SAAQ;QACV,CAAC;QAED,IAAI,CAAC,KAAK;YAAE,SAAQ;QACpB,MAAM,YAAY,GAAG,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;QAC7D,IAAI,CAAC,YAAY;YAAE,SAAQ;QAC3B,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;QACrD,IAAI,MAAM,EAAE,CAAC;YACX,QAAQ,CAAC,IAAI,CAAC;gBACZ,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;gBAC7C,OAAO,EAAE,IAAI;gBACb,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM;aACnB,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface SpecifierOccurrence {
|
|
2
|
+
specifier: string;
|
|
3
|
+
/** position of the opening quote */
|
|
4
|
+
start: number;
|
|
5
|
+
/** position just past the closing quote */
|
|
6
|
+
end: number;
|
|
7
|
+
line: number;
|
|
8
|
+
column: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function findSpecifiers(text: string, file: string): SpecifierOccurrence[];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Finds every import-like specifier in a file via a real AST walk —
|
|
2
|
+
// `import`/`export ... from`, dynamic `import(...)`, and `require(...)` —
|
|
3
|
+
// each with the exact source position of the string literal itself (not
|
|
4
|
+
// just its decoded text), so a fix can replace precisely that span and
|
|
5
|
+
// keep the original quote character.
|
|
6
|
+
import ts from 'typescript';
|
|
7
|
+
function scriptKindFor(file) {
|
|
8
|
+
return file.endsWith('.tsx')
|
|
9
|
+
? ts.ScriptKind.TSX
|
|
10
|
+
: file.endsWith('.jsx')
|
|
11
|
+
? ts.ScriptKind.JSX
|
|
12
|
+
: ts.ScriptKind.TS;
|
|
13
|
+
}
|
|
14
|
+
function isRequireCall(node) {
|
|
15
|
+
return (ts.isCallExpression(node) &&
|
|
16
|
+
ts.isIdentifier(node.expression) &&
|
|
17
|
+
node.expression.text === 'require');
|
|
18
|
+
}
|
|
19
|
+
function isDynamicImportCall(node) {
|
|
20
|
+
return ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword;
|
|
21
|
+
}
|
|
22
|
+
export function findSpecifiers(text, file) {
|
|
23
|
+
const sf = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true, scriptKindFor(file));
|
|
24
|
+
const found = [];
|
|
25
|
+
function push(node) {
|
|
26
|
+
const start = node.getStart(sf);
|
|
27
|
+
const pos = sf.getLineAndCharacterOfPosition(start);
|
|
28
|
+
found.push({
|
|
29
|
+
specifier: node.text,
|
|
30
|
+
start,
|
|
31
|
+
end: node.getEnd(),
|
|
32
|
+
line: pos.line + 1,
|
|
33
|
+
column: pos.character + 1,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function visit(node) {
|
|
37
|
+
if ((ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&
|
|
38
|
+
node.moduleSpecifier &&
|
|
39
|
+
ts.isStringLiteral(node.moduleSpecifier)) {
|
|
40
|
+
push(node.moduleSpecifier);
|
|
41
|
+
}
|
|
42
|
+
else if ((isRequireCall(node) || isDynamicImportCall(node)) && node.arguments[0]) {
|
|
43
|
+
const arg = node.arguments[0];
|
|
44
|
+
if (ts.isStringLiteral(arg))
|
|
45
|
+
push(arg);
|
|
46
|
+
}
|
|
47
|
+
ts.forEachChild(node, visit);
|
|
48
|
+
}
|
|
49
|
+
visit(sf);
|
|
50
|
+
return found;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../src/commands/case-check/parse.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,0EAA0E;AAC1E,wEAAwE;AACxE,uEAAuE;AACvE,qCAAqC;AAErC,OAAO,EAAE,MAAM,YAAY,CAAA;AAY3B,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC1B,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG;QACnB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YACrB,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG;YACnB,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAA;AACxB,CAAC;AAED,SAAS,aAAa,CAAC,IAAa;IAClC,OAAO,CACL,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;QACzB,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC;QAChC,IAAI,CAAC,UAAU,CAAC,IAAI,KAAK,SAAS,CACnC,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAa;IACxC,OAAO,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,aAAa,CAAA;AAC1F,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,IAAY;IACvD,MAAM,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAA;IAC7F,MAAM,KAAK,GAA0B,EAAE,CAAA;IAEvC,SAAS,IAAI,CAAC,IAAsB;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;QAC/B,MAAM,GAAG,GAAG,EAAE,CAAC,6BAA6B,CAAC,KAAK,CAAC,CAAA;QACnD,KAAK,CAAC,IAAI,CAAC;YACT,SAAS,EAAE,IAAI,CAAC,IAAI;YACpB,KAAK;YACL,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE;YAClB,IAAI,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC;YAClB,MAAM,EAAE,GAAG,CAAC,SAAS,GAAG,CAAC;SAC1B,CAAC,CAAA;IACJ,CAAC;IAED,SAAS,KAAK,CAAC,IAAa;QAC1B,IACE,CAAC,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;YAC9D,IAAI,CAAC,eAAe;YACpB,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,eAAe,CAAC,EACxC,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;QAC5B,CAAC;aAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;YACnF,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;YAC7B,IAAI,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC;gBAAE,IAAI,CAAC,GAAG,CAAC,CAAA;QACxC,CAAC;QACD,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAC9B,CAAC;IACD,KAAK,CAAC,EAAE,CAAC,CAAA;IAET,OAAO,KAAK,CAAA;AACd,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { banner, cleanCelebration } from '../../format/vibes.js';
|
|
2
|
+
import { formatFindingsRows } from '../../format/findings-list.js';
|
|
3
|
+
import { renderDiffForHumans } from '../../format/diff-render.js';
|
|
4
|
+
export function renderCaseCheckReport(report, options = {}) {
|
|
5
|
+
const isClean = report.findings.length === 0;
|
|
6
|
+
if (options.quiet && isClean)
|
|
7
|
+
return '';
|
|
8
|
+
const lines = [];
|
|
9
|
+
if (!options.quiet && !options.plain)
|
|
10
|
+
lines.push(banner(), '');
|
|
11
|
+
lines.push(`Scanned ${report.filesScanned} file${report.filesScanned === 1 ? '' : 's'}.`, '');
|
|
12
|
+
if (isClean) {
|
|
13
|
+
lines.push(cleanCelebration(options));
|
|
14
|
+
return lines.join('\n');
|
|
15
|
+
}
|
|
16
|
+
lines.push(`${report.findings.length} case mismatch${report.findings.length === 1 ? '' : 'es'} found:`);
|
|
17
|
+
lines.push(...formatFindingsRows(report.findings.map((f) => ({
|
|
18
|
+
location: `${f.file}:${f.line}:${f.column}`,
|
|
19
|
+
name: `${f.specifier} → ${f.correctedSpecifier}`,
|
|
20
|
+
tag: f.isAlias ? '(alias, not auto-fixed)' : '',
|
|
21
|
+
})), options));
|
|
22
|
+
if (report.changes.length > 0) {
|
|
23
|
+
lines.push('', report.applied
|
|
24
|
+
? `Fixed ${report.changes.reduce((n, c) => n + c.count, 0)} import(s) in ${report.changes.length} file(s).`
|
|
25
|
+
: `Would fix ${report.changes.reduce((n, c) => n + c.count, 0)} import(s) in ${report.changes.length} file(s) — pass -y to apply.`);
|
|
26
|
+
for (const change of report.changes) {
|
|
27
|
+
if (!change.diff)
|
|
28
|
+
continue;
|
|
29
|
+
const unit = `import${change.count === 1 ? '' : 's'}`;
|
|
30
|
+
lines.push('', renderDiffForHumans(change.file, change.count, unit, change.diff, options));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else if (report.findings.some((f) => !f.isAlias)) {
|
|
34
|
+
lines.push('', '(pass --fix -y to apply, or --fix --diff to preview the fix)');
|
|
35
|
+
}
|
|
36
|
+
return lines.join('\n');
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/commands/case-check/report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAqB,MAAM,uBAAuB,CAAA;AACnF,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAA;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAGjE,MAAM,UAAU,qBAAqB,CAAC,MAAuB,EAAE,UAAwB,EAAE;IACvF,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAA;IAC5C,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO;QAAE,OAAO,EAAE,CAAA;IAEvC,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,CAAA;IAE9D,KAAK,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,YAAY,QAAQ,MAAM,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,CAAA;IAE7F,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAA;QACrC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IAED,KAAK,CAAC,IAAI,CACR,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,iBAAiB,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,SAAS,CAC5F,CAAA;IACD,KAAK,CAAC,IAAI,CACR,GAAG,kBAAkB,CACnB,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1B,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,EAAE;QAC3C,IAAI,EAAE,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,kBAAkB,EAAE;QAChD,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,EAAE;KAChD,CAAC,CAAC,EACH,OAAO,CACR,CACF,CAAA;IAED,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CACR,EAAE,EACF,MAAM,CAAC,OAAO;YACZ,CAAC,CAAC,SAAS,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,iBAAiB,MAAM,CAAC,OAAO,CAAC,MAAM,WAAW;YAC3G,CAAC,CAAC,aAAa,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,iBAAiB,MAAM,CAAC,OAAO,CAAC,MAAM,8BAA8B,CACrI,CAAA;QACD,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACpC,IAAI,CAAC,MAAM,CAAC,IAAI;gBAAE,SAAQ;YAC1B,MAAM,IAAI,GAAG,SAAS,MAAM,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;YACrD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,mBAAmB,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;QAC5F,CAAC;IACH,CAAC;SAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,8DAA8D,CAAC,CAAA;IAChF,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface CaseCheckOutcome {
|
|
2
|
+
/** the specifier with every segment's real on-disk casing substituted in */
|
|
3
|
+
correctedSpecifier: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Returns `{ correctedSpecifier }` if `specifier` (as written in
|
|
7
|
+
* `fromFile`) differs in case from what's really on disk anywhere along
|
|
8
|
+
* its path, or `null` if it's already correct — OR if it doesn't resolve
|
|
9
|
+
* to anything at all (a genuinely broken import is a different problem,
|
|
10
|
+
* not this command's to report). Only relative specifiers (`.`/`..`
|
|
11
|
+
* prefixed) — bare/aliased ones are resolved to a relative-shaped target
|
|
12
|
+
* by the caller first (see tsconfig-paths.ts).
|
|
13
|
+
*/
|
|
14
|
+
export declare function checkSpecifierCase(fromFile: string, specifier: string): CaseCheckOutcome | null;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// Verifies a relative specifier's casing against what's REALLY on disk —
|
|
2
|
+
// via `readdirSync`, never via `existsSync`/`statSync` on the literal
|
|
3
|
+
// path, which Windows/Mac would happily confirm even with the wrong case
|
|
4
|
+
// (case-insensitive filesystems by default) and Linux CI would then fail
|
|
5
|
+
// on for real. This is the whole point of the command: catch it here,
|
|
6
|
+
// not there.
|
|
7
|
+
import { readdirSync } from 'node:fs';
|
|
8
|
+
import { dirname, join, resolve } from 'node:path';
|
|
9
|
+
const CANDIDATE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.vue', '.json'];
|
|
10
|
+
// A NodeNext-style project writes `'./foo.js'` even though the real file
|
|
11
|
+
// on disk is `foo.ts` (devtoolz's own source does this throughout — see
|
|
12
|
+
// resolve.ts in dead-exports for the same convention). Case-checking a
|
|
13
|
+
// literal `.js` specifier against a real `.ts` file needs to know these
|
|
14
|
+
// are the SAME file before it can even get to comparing case, or a
|
|
15
|
+
// perfectly fine NodeNext import looks like a broken one, not a case
|
|
16
|
+
// mismatch. The corrected specifier still keeps the WRITTEN extension
|
|
17
|
+
// (`.js`) — only the base name's case is ever changed, never the
|
|
18
|
+
// extension the codebase's own convention chose to write.
|
|
19
|
+
const NODENEXT_SWAPS = {
|
|
20
|
+
'.js': ['.ts', '.tsx'],
|
|
21
|
+
'.mjs': ['.mts'],
|
|
22
|
+
'.cjs': ['.cts'],
|
|
23
|
+
};
|
|
24
|
+
function extensionOf(name, from = CANDIDATE_EXTENSIONS) {
|
|
25
|
+
return from.find((ext) => name.endsWith(ext)) ?? null;
|
|
26
|
+
}
|
|
27
|
+
function realEntryFor(dir, name) {
|
|
28
|
+
let entries;
|
|
29
|
+
try {
|
|
30
|
+
entries = readdirSync(dir);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
if (entries.includes(name))
|
|
36
|
+
return { name, exact: true };
|
|
37
|
+
const lower = name.toLowerCase();
|
|
38
|
+
const match = entries.find((e) => e.toLowerCase() === lower);
|
|
39
|
+
return match ? { name: match, exact: false } : null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Same idea as `realEntryFor`, but for a specifier segment that already
|
|
43
|
+
* names a file extension (`foo.js`) — also tries every NodeNext-
|
|
44
|
+
* equivalent real extension (`foo.ts`, `foo.tsx`, ...) before giving up,
|
|
45
|
+
* exact match across all candidates first, then case-insensitive.
|
|
46
|
+
* Returns the matched real file's BASE NAME (case-corrected, extension
|
|
47
|
+
* stripped) — the caller re-attaches the ORIGINALLY WRITTEN extension.
|
|
48
|
+
*/
|
|
49
|
+
function realFileBaseFor(dir, nameWithExt, writtenExt) {
|
|
50
|
+
let entries;
|
|
51
|
+
try {
|
|
52
|
+
entries = readdirSync(dir);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const base = nameWithExt.slice(0, nameWithExt.length - writtenExt.length);
|
|
58
|
+
const candidateExts = [writtenExt, ...(NODENEXT_SWAPS[writtenExt] ?? [])];
|
|
59
|
+
for (const ext of candidateExts) {
|
|
60
|
+
const candidate = base + ext;
|
|
61
|
+
if (entries.includes(candidate))
|
|
62
|
+
return { base, exact: true };
|
|
63
|
+
}
|
|
64
|
+
for (const ext of candidateExts) {
|
|
65
|
+
const candidateLower = (base + ext).toLowerCase();
|
|
66
|
+
const match = entries.find((e) => e.toLowerCase() === candidateLower);
|
|
67
|
+
if (match) {
|
|
68
|
+
const matchedExt = extensionOf(match, candidateExts) ?? ext;
|
|
69
|
+
return { base: match.slice(0, match.length - matchedExt.length), exact: false };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Returns `{ correctedSpecifier }` if `specifier` (as written in
|
|
76
|
+
* `fromFile`) differs in case from what's really on disk anywhere along
|
|
77
|
+
* its path, or `null` if it's already correct — OR if it doesn't resolve
|
|
78
|
+
* to anything at all (a genuinely broken import is a different problem,
|
|
79
|
+
* not this command's to report). Only relative specifiers (`.`/`..`
|
|
80
|
+
* prefixed) — bare/aliased ones are resolved to a relative-shaped target
|
|
81
|
+
* by the caller first (see tsconfig-paths.ts).
|
|
82
|
+
*/
|
|
83
|
+
export function checkSpecifierCase(fromFile, specifier) {
|
|
84
|
+
if (!specifier.startsWith('.'))
|
|
85
|
+
return null;
|
|
86
|
+
const baseDir = dirname(fromFile);
|
|
87
|
+
const segments = specifier.split('/');
|
|
88
|
+
const lastSegment = segments[segments.length - 1];
|
|
89
|
+
const hasExplicitExt = CANDIDATE_EXTENSIONS.some((ext) => lastSegment.endsWith(ext));
|
|
90
|
+
let currentDir = baseDir;
|
|
91
|
+
const corrected = [];
|
|
92
|
+
let hasMismatch = false;
|
|
93
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
94
|
+
const seg = segments[i];
|
|
95
|
+
if (seg === '.' || seg === '..' || seg === '') {
|
|
96
|
+
corrected.push(seg);
|
|
97
|
+
currentDir = resolve(currentDir, seg);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const real = realEntryFor(currentDir, seg);
|
|
101
|
+
if (!real)
|
|
102
|
+
return null;
|
|
103
|
+
if (!real.exact)
|
|
104
|
+
hasMismatch = true;
|
|
105
|
+
corrected.push(real.name);
|
|
106
|
+
currentDir = join(currentDir, real.name);
|
|
107
|
+
}
|
|
108
|
+
if (hasExplicitExt) {
|
|
109
|
+
const writtenExt = extensionOf(lastSegment); // hasExplicitExt guarantees a match
|
|
110
|
+
const real = realFileBaseFor(currentDir, lastSegment, writtenExt);
|
|
111
|
+
if (!real)
|
|
112
|
+
return null;
|
|
113
|
+
if (!real.exact)
|
|
114
|
+
hasMismatch = true;
|
|
115
|
+
corrected.push(real.base + writtenExt);
|
|
116
|
+
return hasMismatch ? { correctedSpecifier: corrected.join('/') } : null;
|
|
117
|
+
}
|
|
118
|
+
// No extension in the specifier — try resolving it as a FILE (guessing
|
|
119
|
+
// the extension) before falling back to "it's a directory with an
|
|
120
|
+
// index file inside".
|
|
121
|
+
let entries;
|
|
122
|
+
try {
|
|
123
|
+
entries = readdirSync(currentDir);
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
for (const ext of CANDIDATE_EXTENSIONS) {
|
|
129
|
+
if (entries.includes(lastSegment + ext)) {
|
|
130
|
+
corrected.push(lastSegment);
|
|
131
|
+
return hasMismatch ? { correctedSpecifier: corrected.join('/') } : null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
for (const ext of CANDIDATE_EXTENSIONS) {
|
|
135
|
+
const target = (lastSegment + ext).toLowerCase();
|
|
136
|
+
const match = entries.find((e) => e.toLowerCase() === target);
|
|
137
|
+
if (match) {
|
|
138
|
+
const realBase = match.slice(0, match.length - ext.length);
|
|
139
|
+
corrected.push(realBase);
|
|
140
|
+
return { correctedSpecifier: corrected.join('/') }; // extension case can differ too, but we only ever write the base name back — always worth flagging if the base itself needed a real-case swap
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Not a file — try as a directory containing an index file.
|
|
144
|
+
const realDir = realEntryFor(currentDir, lastSegment);
|
|
145
|
+
if (!realDir)
|
|
146
|
+
return null;
|
|
147
|
+
if (!realDir.exact)
|
|
148
|
+
hasMismatch = true;
|
|
149
|
+
const dirPath = join(currentDir, realDir.name);
|
|
150
|
+
let dirEntries;
|
|
151
|
+
try {
|
|
152
|
+
dirEntries = readdirSync(dirPath);
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
const hasIndex = CANDIDATE_EXTENSIONS.some((ext) => dirEntries.includes(`index${ext}`));
|
|
158
|
+
if (!hasIndex)
|
|
159
|
+
return null; // not actually a resolvable directory import — not this command's problem
|
|
160
|
+
corrected.push(realDir.name);
|
|
161
|
+
return hasMismatch ? { correctedSpecifier: corrected.join('/') } : null;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=resolve-case.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-case.js","sourceRoot":"","sources":["../../../src/commands/case-check/resolve-case.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type CaseCheckFinding } from './core.js';
|
|
2
|
+
export interface CaseCheckRunOptions {
|
|
3
|
+
paths: string[];
|
|
4
|
+
cwd: string;
|
|
5
|
+
extensions?: string[];
|
|
6
|
+
ignoreGlobs?: string[];
|
|
7
|
+
respectGitignore?: boolean;
|
|
8
|
+
/** explicit tsconfig.json path — auto-detected upward from --cwd by default */
|
|
9
|
+
tsconfig?: string;
|
|
10
|
+
/** apply fixes to non-alias findings */
|
|
11
|
+
fix?: boolean;
|
|
12
|
+
dryRun?: boolean;
|
|
13
|
+
yes?: boolean;
|
|
14
|
+
diff?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface CaseCheckFileFinding extends CaseCheckFinding {
|
|
17
|
+
file: string;
|
|
18
|
+
}
|
|
19
|
+
export interface CaseCheckFileChange {
|
|
20
|
+
file: string;
|
|
21
|
+
count: number;
|
|
22
|
+
diff?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface CaseCheckReport {
|
|
25
|
+
filesScanned: number;
|
|
26
|
+
findings: CaseCheckFileFinding[];
|
|
27
|
+
changes: CaseCheckFileChange[];
|
|
28
|
+
applied: boolean;
|
|
29
|
+
exitCode: number;
|
|
30
|
+
}
|
|
31
|
+
export declare function runCaseCheck(options: CaseCheckRunOptions): CaseCheckReport;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { relative, resolve as resolvePath } from 'node:path';
|
|
3
|
+
import { walk } from '../../utils/walk.js';
|
|
4
|
+
import { unifiedDiff } from '../../utils/diff.js';
|
|
5
|
+
import { checkFile } from './core.js';
|
|
6
|
+
import { findTsconfig, loadTsconfigPaths } from './tsconfig-paths.js';
|
|
7
|
+
const DEFAULT_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.cjs', '.mjs', '.vue'];
|
|
8
|
+
function applyFixes(text, findings) {
|
|
9
|
+
const sorted = [...findings].sort((a, b) => a.start - b.start);
|
|
10
|
+
let out = '';
|
|
11
|
+
let cursor = 0;
|
|
12
|
+
for (const f of sorted) {
|
|
13
|
+
const quote = text[f.start] ?? "'";
|
|
14
|
+
out += text.slice(cursor, f.start);
|
|
15
|
+
out += `${quote}${f.correctedSpecifier}${quote}`;
|
|
16
|
+
cursor = f.end;
|
|
17
|
+
}
|
|
18
|
+
out += text.slice(cursor);
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
export function runCaseCheck(options) {
|
|
22
|
+
const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
|
|
23
|
+
const files = walk(options.paths, {
|
|
24
|
+
cwd: options.cwd,
|
|
25
|
+
extensions,
|
|
26
|
+
...(options.ignoreGlobs ? { ignoreGlobs: options.ignoreGlobs } : {}),
|
|
27
|
+
...(options.respectGitignore !== undefined
|
|
28
|
+
? { respectGitignore: options.respectGitignore }
|
|
29
|
+
: {}),
|
|
30
|
+
});
|
|
31
|
+
const tsconfigPath = options.tsconfig
|
|
32
|
+
? resolvePath(options.cwd, options.tsconfig)
|
|
33
|
+
: findTsconfig(options.cwd);
|
|
34
|
+
const paths = tsconfigPath ? loadTsconfigPaths(tsconfigPath) : null;
|
|
35
|
+
const willApply = options.fix === true && options.yes === true && options.dryRun !== true;
|
|
36
|
+
const findings = [];
|
|
37
|
+
const changes = [];
|
|
38
|
+
for (const file of files) {
|
|
39
|
+
const before = readFileSync(file, 'utf8');
|
|
40
|
+
const fileFindings = checkFile(before, file, paths);
|
|
41
|
+
if (fileFindings.length === 0)
|
|
42
|
+
continue;
|
|
43
|
+
const relFile = relative(options.cwd, file).split('\\').join('/');
|
|
44
|
+
for (const f of fileFindings)
|
|
45
|
+
findings.push({ ...f, file: relFile });
|
|
46
|
+
const fixable = fileFindings.filter((f) => !f.isAlias);
|
|
47
|
+
if (options.fix && fixable.length > 0) {
|
|
48
|
+
const after = applyFixes(before, fixable);
|
|
49
|
+
const change = { file: relFile, count: fixable.length };
|
|
50
|
+
if (options.diff)
|
|
51
|
+
change.diff = unifiedDiff(relFile, before, after);
|
|
52
|
+
changes.push(change);
|
|
53
|
+
if (willApply)
|
|
54
|
+
writeFileSync(file, after);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Once fixes are actually applied, only the alias findings (never
|
|
58
|
+
// auto-fixed — see CaseCheckFinding.isAlias) still represent something
|
|
59
|
+
// left for a human to do; everything else just got handled. When
|
|
60
|
+
// nothing was applied (no --fix, dry-run, or missing -y), every finding
|
|
61
|
+
// still counts, same as the other commands' "there's something here"
|
|
62
|
+
// exit-code convention.
|
|
63
|
+
const remaining = willApply ? findings.filter((f) => f.isAlias).length : findings.length;
|
|
64
|
+
return {
|
|
65
|
+
filesScanned: files.length,
|
|
66
|
+
findings,
|
|
67
|
+
changes,
|
|
68
|
+
applied: willApply,
|
|
69
|
+
exitCode: remaining > 0 ? 1 : 0,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/commands/case-check/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface TsconfigPaths {
|
|
2
|
+
baseDir: string;
|
|
3
|
+
/** each entry: the alias pattern's fixed prefix/suffix around its `*`, and its target template */
|
|
4
|
+
patterns: Array<{
|
|
5
|
+
prefix: string;
|
|
6
|
+
suffix: string;
|
|
7
|
+
target: string;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
export declare function loadTsconfigPaths(tsconfigPath: string): TsconfigPaths | null;
|
|
11
|
+
export declare function findTsconfig(startDir: string): string | null;
|
|
12
|
+
/**
|
|
13
|
+
* Resolves an aliased specifier to a `./`/`../`-relative specifier as
|
|
14
|
+
* seen from `fromFile`, or `null` if it doesn't match any configured
|
|
15
|
+
* pattern. The result feeds straight into resolve-case.ts's relative-
|
|
16
|
+
* specifier checker — same function, one caller resolves the alias
|
|
17
|
+
* first.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveAlias(fromFile: string, specifier: string, config: TsconfigPaths): string | null;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// Resolves an aliased specifier (`@/components/Foo`) to a relative-style
|
|
2
|
+
// path (`../components/Foo`, from whichever file is asking) via
|
|
3
|
+
// `compilerOptions.paths`/`baseUrl` — only the common single-`*`-wildcard
|
|
4
|
+
// pattern shape is supported (`{"@/*": ["src/*"]}`), which covers the
|
|
5
|
+
// overwhelming majority of real projects; anything fancier (multiple
|
|
6
|
+
// fallback targets, non-wildcard exact aliases) is left unresolved rather
|
|
7
|
+
// than guessed at.
|
|
8
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
9
|
+
import { dirname, join, relative, resolve } from 'node:path';
|
|
10
|
+
function stripJsonComments(text) {
|
|
11
|
+
// tsconfig.json commonly has // and /* */ comments (JSONC) — a real
|
|
12
|
+
// parser isn't warranted for this narrow use, but plain JSON.parse
|
|
13
|
+
// chokes on them. Strips comments outside of string literals only.
|
|
14
|
+
let out = '';
|
|
15
|
+
let inString = false;
|
|
16
|
+
let i = 0;
|
|
17
|
+
while (i < text.length) {
|
|
18
|
+
const ch = text[i];
|
|
19
|
+
if (inString) {
|
|
20
|
+
out += ch;
|
|
21
|
+
if (ch === '\\') {
|
|
22
|
+
out += text[i + 1] ?? '';
|
|
23
|
+
i += 2;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (ch === '"')
|
|
27
|
+
inString = false;
|
|
28
|
+
i++;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (ch === '"') {
|
|
32
|
+
inString = true;
|
|
33
|
+
out += ch;
|
|
34
|
+
i++;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (ch === '/' && text[i + 1] === '/') {
|
|
38
|
+
while (i < text.length && text[i] !== '\n')
|
|
39
|
+
i++;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (ch === '/' && text[i + 1] === '*') {
|
|
43
|
+
i += 2;
|
|
44
|
+
while (i < text.length && !(text[i] === '*' && text[i + 1] === '/'))
|
|
45
|
+
i++;
|
|
46
|
+
i += 2;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
out += ch;
|
|
50
|
+
i++;
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
export function loadTsconfigPaths(tsconfigPath) {
|
|
55
|
+
let raw;
|
|
56
|
+
try {
|
|
57
|
+
raw = JSON.parse(stripJsonComments(readFileSync(tsconfigPath, 'utf8')));
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
const compilerOptions = raw.compilerOptions;
|
|
63
|
+
const pathsMap = compilerOptions?.paths;
|
|
64
|
+
if (!pathsMap)
|
|
65
|
+
return null;
|
|
66
|
+
const tsconfigDir = dirname(tsconfigPath);
|
|
67
|
+
const baseUrl = typeof compilerOptions?.baseUrl === 'string' ? compilerOptions.baseUrl : '.';
|
|
68
|
+
const baseDir = resolve(tsconfigDir, baseUrl);
|
|
69
|
+
const patterns = [];
|
|
70
|
+
for (const [alias, targets] of Object.entries(pathsMap)) {
|
|
71
|
+
if (!Array.isArray(targets) || typeof targets[0] !== 'string')
|
|
72
|
+
continue;
|
|
73
|
+
const target = targets[0];
|
|
74
|
+
const starIndex = alias.indexOf('*');
|
|
75
|
+
if (starIndex === -1)
|
|
76
|
+
continue; // exact (non-wildcard) alias — out of scope, see file header
|
|
77
|
+
patterns.push({
|
|
78
|
+
prefix: alias.slice(0, starIndex),
|
|
79
|
+
suffix: alias.slice(starIndex + 1),
|
|
80
|
+
target,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return patterns.length > 0 ? { baseDir, patterns } : null;
|
|
84
|
+
}
|
|
85
|
+
export function findTsconfig(startDir) {
|
|
86
|
+
let dir = resolve(startDir);
|
|
87
|
+
for (;;) {
|
|
88
|
+
const candidate = join(dir, 'tsconfig.json');
|
|
89
|
+
if (existsSync(candidate))
|
|
90
|
+
return candidate;
|
|
91
|
+
const parent = dirname(dir);
|
|
92
|
+
if (parent === dir)
|
|
93
|
+
return null;
|
|
94
|
+
dir = parent;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Resolves an aliased specifier to a `./`/`../`-relative specifier as
|
|
99
|
+
* seen from `fromFile`, or `null` if it doesn't match any configured
|
|
100
|
+
* pattern. The result feeds straight into resolve-case.ts's relative-
|
|
101
|
+
* specifier checker — same function, one caller resolves the alias
|
|
102
|
+
* first.
|
|
103
|
+
*/
|
|
104
|
+
export function resolveAlias(fromFile, specifier, config) {
|
|
105
|
+
for (const { prefix, suffix, target } of config.patterns) {
|
|
106
|
+
if (!specifier.startsWith(prefix) || !specifier.endsWith(suffix))
|
|
107
|
+
continue;
|
|
108
|
+
const wildcardValue = specifier.slice(prefix.length, specifier.length - suffix.length);
|
|
109
|
+
if (wildcardValue.includes('*'))
|
|
110
|
+
continue; // ambiguous — more than one wildcard segment matched
|
|
111
|
+
const targetStarIndex = target.indexOf('*');
|
|
112
|
+
const resolvedTargetRel = targetStarIndex === -1 ? target : target.replace('*', wildcardValue);
|
|
113
|
+
const absoluteTarget = resolve(config.baseDir, resolvedTargetRel);
|
|
114
|
+
const rel = relative(dirname(fromFile), absoluteTarget).split('\\').join('/');
|
|
115
|
+
return rel.startsWith('.') ? rel : `./${rel}`;
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=tsconfig-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tsconfig-paths.js","sourceRoot":"","sources":["../../../src/commands/case-check/tsconfig-paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type SpecifierOccurrence } from './parse.js';
|
|
2
|
+
/**
|
|
3
|
+
* Same as `findSpecifiers`, but for a `.vue` file's `<script>` block —
|
|
4
|
+
* positions are offset by the block's real start in the full file, so a
|
|
5
|
+
* fix computed against them still lands correctly when applied to the
|
|
6
|
+
* whole file's text, not just the extracted body.
|
|
7
|
+
*/
|
|
8
|
+
export declare function findSpecifiersInVue(text: string, file: string): SpecifierOccurrence[];
|