@simplysm/sd-cli 12.15.67 → 12.15.69
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/dist/entry/SdCliAiCommand.js +13 -1
- package/dist/entry/SdCliCapacitor.d.ts +37 -0
- package/dist/entry/SdCliCapacitor.js +390 -0
- package/dist/pkg-builders/client/SdClientBuildRunner.d.ts +1 -0
- package/dist/pkg-builders/client/SdClientBuildRunner.js +14 -0
- package/dist/pkg-builders/client/SdNgBundler.js +3 -1
- package/dist/sd-cli-entry.js +18 -44
- package/dist/types/config/ISdProjectConfig.d.ts +31 -0
- package/package.json +5 -5
- package/src/entry/SdCliAiCommand.ts +14 -1
- package/src/entry/SdCliCapacitor.ts +560 -0
- package/src/pkg-builders/client/SdClientBuildRunner.ts +17 -0
- package/src/pkg-builders/client/SdNgBundler.ts +3 -1
- package/src/sd-cli-entry.ts +26 -56
- package/src/types/config/ISdProjectConfig.ts +34 -0
- package/dist/fix/convertPrivateToHash.d.ts +0 -1
- package/dist/fix/convertPrivateToHash.js +0 -58
- package/dist/fix/convertSdAngularSymbolNames.d.ts +0 -1
- package/dist/fix/convertSdAngularSymbolNames.js +0 -22
- package/dist/fix/core/convertSymbols.d.ts +0 -1
- package/dist/fix/core/convertSymbols.js +0 -101
- package/dist/fix/core/getTsMortphSourceFiles.d.ts +0 -1
- package/dist/fix/core/getTsMortphSourceFiles.js +0 -7
- package/dist/fix/core/removeSymbols.d.ts +0 -1
- package/dist/fix/core/removeSymbols.js +0 -76
- package/dist/fix/removeSdAngularSymbolNames.d.ts +0 -1
- package/dist/fix/removeSdAngularSymbolNames.js +0 -6
- package/dist/fix/removeUnusedImports.d.ts +0 -1
- package/dist/fix/removeUnusedImports.js +0 -41
- package/dist/fix/removeUnusedInjects.d.ts +0 -1
- package/dist/fix/removeUnusedInjects.js +0 -37
- package/dist/fix/removeUnusedProtectedReadonly.d.ts +0 -1
- package/dist/fix/removeUnusedProtectedReadonly.js +0 -57
- package/src/fix/convertPrivateToHash.ts +0 -74
- package/src/fix/convertSdAngularSymbolNames.ts +0 -27
- package/src/fix/core/convertSymbols.ts +0 -135
- package/src/fix/core/getTsMortphSourceFiles.ts +0 -9
- package/src/fix/core/removeSymbols.ts +0 -102
- package/src/fix/removeSdAngularSymbolNames.ts +0 -9
- package/src/fix/removeUnusedImports.ts +0 -50
- package/src/fix/removeUnusedInjects.ts +0 -50
- package/src/fix/removeUnusedProtectedReadonly.ts +0 -69
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
|
|
3
|
-
import { Node, SyntaxKind } from "ts-morph";
|
|
4
|
-
import getTsMortphSourceFiles from "./core/getTsMortphSourceFiles";
|
|
5
|
-
|
|
6
|
-
export default function convertPrivateToHash() {
|
|
7
|
-
const sourceFiles = getTsMortphSourceFiles();
|
|
8
|
-
|
|
9
|
-
for (const sourceFile of sourceFiles) {
|
|
10
|
-
let changed = false;
|
|
11
|
-
|
|
12
|
-
for (const classDecl of sourceFile.getClasses()) {
|
|
13
|
-
const renameMap = new Map<string, string>();
|
|
14
|
-
|
|
15
|
-
// 1. 선언부에서 private을 #으로 바꾸고 이름 매핑 저장
|
|
16
|
-
for (const member of classDecl.getMembers()) {
|
|
17
|
-
if (
|
|
18
|
-
Node.isPropertyDeclaration(member) ||
|
|
19
|
-
Node.isMethodDeclaration(member) ||
|
|
20
|
-
Node.isGetAccessorDeclaration(member) ||
|
|
21
|
-
Node.isSetAccessorDeclaration(member)
|
|
22
|
-
) {
|
|
23
|
-
if (member.hasModifier(SyntaxKind.PrivateKeyword)) {
|
|
24
|
-
const nameNode = member.getNameNode();
|
|
25
|
-
if (typeof nameNode.getText !== "function") continue;
|
|
26
|
-
|
|
27
|
-
const oldName = nameNode.getText();
|
|
28
|
-
const newName = oldName.startsWith("_") ? `#${oldName.slice(1)}` : `#${oldName}`;
|
|
29
|
-
|
|
30
|
-
nameNode.replaceWithText(newName);
|
|
31
|
-
member.toggleModifier("private", false);
|
|
32
|
-
renameMap.set(oldName, newName);
|
|
33
|
-
|
|
34
|
-
const kind = Node.isMethodDeclaration(member)
|
|
35
|
-
? "method"
|
|
36
|
-
: Node.isGetAccessorDeclaration(member) || Node.isSetAccessorDeclaration(member)
|
|
37
|
-
? "accessor"
|
|
38
|
-
: "field";
|
|
39
|
-
|
|
40
|
-
console.log(
|
|
41
|
-
`[private-${kind}] ${sourceFile.getBaseName()} :: private ${oldName} → ${newName}`,
|
|
42
|
-
);
|
|
43
|
-
changed = true;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (renameMap.size === 0) continue;
|
|
49
|
-
|
|
50
|
-
// 2. this.xxx 접근 표현식 전환
|
|
51
|
-
classDecl.forEachDescendant((node) => {
|
|
52
|
-
const propAccess = node.asKind(SyntaxKind.PropertyAccessExpression);
|
|
53
|
-
if (propAccess) {
|
|
54
|
-
const expr = propAccess.getExpression();
|
|
55
|
-
const name = propAccess.getName();
|
|
56
|
-
|
|
57
|
-
if (expr.getText() === "this" && renameMap.has(name)) {
|
|
58
|
-
const newName = renameMap.get(name)!;
|
|
59
|
-
propAccess.replaceWithText(`this.${newName}`);
|
|
60
|
-
console.log(`[ref] ${sourceFile.getBaseName()} :: this.${name} → this.${newName}`);
|
|
61
|
-
changed = true;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (changed) {
|
|
68
|
-
sourceFile.saveSync();
|
|
69
|
-
console.log(`[save] ${sourceFile.getFilePath()}`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
console.log("[완료] private → ECMAScript # 멤버 변환 완료");
|
|
74
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
import convertSymbols from "./core/convertSymbols";
|
|
3
|
-
|
|
4
|
-
export default function convertSdAngularSymbolNames() {
|
|
5
|
-
convertSymbols({
|
|
6
|
-
"@simplysm/sd-angular#useBgTheme": "@simplysm/sd-angular#setupBgTheme",
|
|
7
|
-
"@simplysm/sd-angular#canDeactivate": "@simplysm/sd-angular#setupCanDeactivate",
|
|
8
|
-
"@simplysm/sd-angular#useRipple": "@simplysm/sd-angular#setupRipple",
|
|
9
|
-
"@simplysm/sd-angular#useCumulateSelectedKeys":
|
|
10
|
-
"@simplysm/sd-angular#setupCumulateSelectedKeys",
|
|
11
|
-
"@simplysm/sd-angular#injectQueryParamMap$": "@simplysm/sd-angular#useQueryParamMapSignal",
|
|
12
|
-
"@simplysm/sd-angular#useActivatedRouteManager": "@simplysm/sd-angular#useQueryParamMapSignal",
|
|
13
|
-
"@simplysm/sd-angular#ISdSheetColumnOrderingVM": "@simplysm/sd-angular#ISdSortingDef",
|
|
14
|
-
"@simplysm/sd-angular#ISortingDef": "@simplysm/sd-angular#ISdSortingDef",
|
|
15
|
-
"@simplysm/sd-angular#ISharedDataModalOutputResult":
|
|
16
|
-
"@simplysm/sd-angular#ISelectModalOutputResult",
|
|
17
|
-
|
|
18
|
-
"@angular/core#signal": "@simplysm/sd-angular#$signal",
|
|
19
|
-
"@angular/core#computed": "@simplysm/sd-angular#$computed",
|
|
20
|
-
"@angular/core#effect": "@simplysm/sd-angular#$effect",
|
|
21
|
-
"@angular/core#afterRenderEffect": "@simplysm/sd-angular#$afterRenderEffect",
|
|
22
|
-
"@angular/core#afterRenderComputed": "@simplysm/sd-angular#$afterRenderComputed",
|
|
23
|
-
"@angular/core#resource": "@simplysm/sd-angular#$resource",
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
console.log("[완료] SdAngular 심볼 이름 변환 완료");
|
|
27
|
-
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
|
|
3
|
-
import { Identifier, SyntaxKind } from "ts-morph";
|
|
4
|
-
import getTsMortphSourceFiles from "./getTsMortphSourceFiles";
|
|
5
|
-
|
|
6
|
-
interface SymbolReplacement {
|
|
7
|
-
oldModule: string;
|
|
8
|
-
oldName: string;
|
|
9
|
-
newModule: string;
|
|
10
|
-
newName: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function parseReplacements(input: Record<string, string>): SymbolReplacement[] {
|
|
14
|
-
return Object.entries(input).map(([oldKey, newValue]) => {
|
|
15
|
-
const [oldModule, oldName] = oldKey.split("#");
|
|
16
|
-
const [newModule, newName] = newValue.split("#");
|
|
17
|
-
return { oldModule, oldName, newModule, newName };
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function getSourceFileModule(filePath: string): string {
|
|
22
|
-
const match = filePath.match(/packages[\\/](.*?)[\\/]src[\\/]/);
|
|
23
|
-
return `@simplysm/${match![1]}`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export default function convertSymbols(raw: Record<string, string>) {
|
|
27
|
-
const replacements = parseReplacements(raw);
|
|
28
|
-
const sourceFiles = getTsMortphSourceFiles();
|
|
29
|
-
|
|
30
|
-
for (const sourceFile of sourceFiles) {
|
|
31
|
-
const sourceFileModule = getSourceFileModule(sourceFile.getFilePath());
|
|
32
|
-
|
|
33
|
-
let changed = false;
|
|
34
|
-
|
|
35
|
-
const usedReplacements = new Set<string>(); // 실제 사용된 newModule#newName 추적
|
|
36
|
-
const existingImportMap: Map<string, Set<string>> = new Map();
|
|
37
|
-
|
|
38
|
-
// 1. 참조 치환 (Identifier)
|
|
39
|
-
sourceFile.forEachDescendant((node) => {
|
|
40
|
-
if (node.getKind() !== SyntaxKind.Identifier) return;
|
|
41
|
-
if (node.getFirstAncestorByKind(SyntaxKind.ImportSpecifier)) return;
|
|
42
|
-
|
|
43
|
-
const identifier = node as Identifier;
|
|
44
|
-
const name = identifier.getText();
|
|
45
|
-
|
|
46
|
-
const symbol = identifier.getSymbol();
|
|
47
|
-
if (!symbol) return;
|
|
48
|
-
|
|
49
|
-
const declarations = symbol.getDeclarations();
|
|
50
|
-
if (declarations.length === 0) return;
|
|
51
|
-
|
|
52
|
-
const importDecl = declarations[0].getFirstAncestorByKind(SyntaxKind.ImportDeclaration);
|
|
53
|
-
if (!importDecl) return;
|
|
54
|
-
|
|
55
|
-
const importModule = importDecl.getModuleSpecifierValue();
|
|
56
|
-
|
|
57
|
-
const match = replacements.find((r) => r.oldModule === importModule && r.oldName === name);
|
|
58
|
-
if (!match || match.oldModule === sourceFileModule || match.newModule === sourceFileModule)
|
|
59
|
-
return;
|
|
60
|
-
|
|
61
|
-
identifier.replaceWithText(match.newName);
|
|
62
|
-
usedReplacements.add(`${match.newModule}#${match.newName}`);
|
|
63
|
-
changed = true;
|
|
64
|
-
console.log(
|
|
65
|
-
`[ref] ${sourceFile.getBaseName()} :: ${importModule} :: ${name} → ${match.newName}`,
|
|
66
|
-
);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// 2. import 교체
|
|
70
|
-
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
71
|
-
const specifier = importDecl.getModuleSpecifierValue();
|
|
72
|
-
const namedImports = importDecl.getNamedImports();
|
|
73
|
-
|
|
74
|
-
for (const ni of namedImports) {
|
|
75
|
-
const oldName = ni.getName();
|
|
76
|
-
|
|
77
|
-
const match = replacements.find((r) => r.oldModule === specifier && r.oldName === oldName);
|
|
78
|
-
if (
|
|
79
|
-
!match ||
|
|
80
|
-
match.oldModule === sourceFileModule ||
|
|
81
|
-
match.newModule === sourceFileModule
|
|
82
|
-
) {
|
|
83
|
-
// 기존 import 유지 기록
|
|
84
|
-
if (!existingImportMap.has(specifier)) {
|
|
85
|
-
existingImportMap.set(specifier, new Set());
|
|
86
|
-
}
|
|
87
|
-
existingImportMap.get(specifier)!.add(oldName);
|
|
88
|
-
} else {
|
|
89
|
-
ni.remove();
|
|
90
|
-
|
|
91
|
-
// 만약 모듈이 동일하다면 즉시 대체
|
|
92
|
-
if (match.oldModule === match.newModule) {
|
|
93
|
-
importDecl.addNamedImport(match.newName);
|
|
94
|
-
} else {
|
|
95
|
-
// 새로 import할 목록에 기록
|
|
96
|
-
usedReplacements.add(`${match.newModule}#${match.newName}`);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
changed = true;
|
|
100
|
-
console.log(
|
|
101
|
-
`[import] ${sourceFile.getBaseName()} :: ${specifier} :: ${oldName} → ${match.newName}`,
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// 3. 필요 시 새 import 추가
|
|
108
|
-
for (const key of usedReplacements) {
|
|
109
|
-
const [newModule, newName] = key.split("#");
|
|
110
|
-
|
|
111
|
-
const already = existingImportMap.get(newModule)?.has(newName);
|
|
112
|
-
const existsInFile = sourceFile
|
|
113
|
-
.getImportDeclarations()
|
|
114
|
-
.some(
|
|
115
|
-
(decl) =>
|
|
116
|
-
decl.getModuleSpecifierValue() === newModule &&
|
|
117
|
-
decl.getNamedImports().some((ni) => ni.getName() === newName),
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
if (already || existsInFile) continue;
|
|
121
|
-
|
|
122
|
-
sourceFile.addImportDeclaration({
|
|
123
|
-
moduleSpecifier: newModule,
|
|
124
|
-
namedImports: [newName],
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
changed = true;
|
|
128
|
-
console.log(`[new-import] ${sourceFile.getBaseName()} :: ${newModule} :: ${newName}`);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (changed) {
|
|
132
|
-
sourceFile.saveSync();
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
import { ArrayLiteralExpression, Identifier, SyntaxKind, TypeReferenceNode } from "ts-morph";
|
|
3
|
-
import getTsMortphSourceFiles from "./getTsMortphSourceFiles";
|
|
4
|
-
|
|
5
|
-
function parseTargets(symbols: string[]) {
|
|
6
|
-
return symbols.map((symbol) => {
|
|
7
|
-
const [importSource, symbolName] = symbol.split("#");
|
|
8
|
-
return { importSource, symbolName };
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export default function removeSymbols(symbols: string[]) {
|
|
13
|
-
const targets = parseTargets(symbols);
|
|
14
|
-
const sourceFiles = getTsMortphSourceFiles();
|
|
15
|
-
|
|
16
|
-
for (const sourceFile of sourceFiles) {
|
|
17
|
-
let changed = false;
|
|
18
|
-
|
|
19
|
-
for (const { importSource, symbolName } of targets) {
|
|
20
|
-
// 1. Import 제거
|
|
21
|
-
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
22
|
-
if (importDecl.getModuleSpecifierValue() !== importSource) continue;
|
|
23
|
-
|
|
24
|
-
for (const namedImport of importDecl.getNamedImports()) {
|
|
25
|
-
if (namedImport.getName() === symbolName) {
|
|
26
|
-
console.log(
|
|
27
|
-
`[import] ${sourceFile.getBaseName()} :: ${importSource} :: removed '${symbolName}'`,
|
|
28
|
-
);
|
|
29
|
-
namedImport.remove();
|
|
30
|
-
changed = true;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (importDecl.getNamedImports().length === 0) {
|
|
35
|
-
console.log(
|
|
36
|
-
`[import] ${sourceFile.getBaseName()} :: removed empty import from '${importSource}'`,
|
|
37
|
-
);
|
|
38
|
-
importDecl.remove();
|
|
39
|
-
changed = true;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// 2. 타입 참조 제거
|
|
44
|
-
sourceFile.forEachDescendant((node) => {
|
|
45
|
-
if (node.getKind() !== SyntaxKind.TypeReference) return;
|
|
46
|
-
|
|
47
|
-
const typeNode = node as TypeReferenceNode;
|
|
48
|
-
const typeName = typeNode.getTypeName().getText();
|
|
49
|
-
if (typeName !== symbolName) return;
|
|
50
|
-
|
|
51
|
-
const decl = node.getFirstAncestor(
|
|
52
|
-
(a) =>
|
|
53
|
-
a.getKind() === SyntaxKind.VariableStatement ||
|
|
54
|
-
a.getKind() === SyntaxKind.Parameter ||
|
|
55
|
-
a.getKind() === SyntaxKind.PropertyDeclaration,
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
if (decl) {
|
|
59
|
-
console.log(
|
|
60
|
-
`[type] ${sourceFile.getBaseName()} :: removed type usage of '${symbolName}'`,
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
const removable =
|
|
64
|
-
decl.asKind(SyntaxKind.VariableStatement) ??
|
|
65
|
-
decl.asKind(SyntaxKind.Parameter) ??
|
|
66
|
-
decl.asKind(SyntaxKind.PropertyDeclaration);
|
|
67
|
-
|
|
68
|
-
if (removable) {
|
|
69
|
-
removable.remove();
|
|
70
|
-
changed = true;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// 3. ArrayLiteral 내 사용 제거 (예: imports: [SdButtonControl])
|
|
76
|
-
sourceFile.forEachDescendant((node) => {
|
|
77
|
-
if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return;
|
|
78
|
-
|
|
79
|
-
const arr = node as ArrayLiteralExpression;
|
|
80
|
-
const elements = arr.getElements();
|
|
81
|
-
|
|
82
|
-
for (const el of elements) {
|
|
83
|
-
if (
|
|
84
|
-
el.getKind() === SyntaxKind.Identifier &&
|
|
85
|
-
(el as Identifier).getText() === symbolName
|
|
86
|
-
) {
|
|
87
|
-
console.log(
|
|
88
|
-
`[usage] ${sourceFile.getBaseName()} :: removed '${symbolName}' from array`,
|
|
89
|
-
);
|
|
90
|
-
arr.removeElement(el);
|
|
91
|
-
changed = true;
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (changed) {
|
|
99
|
-
sourceFile.saveSync();
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
import { SyntaxKind } from "ts-morph";
|
|
3
|
-
import getTsMorphSourceFiles from "./core/getTsMortphSourceFiles";
|
|
4
|
-
|
|
5
|
-
export function removeUnusedImports() {
|
|
6
|
-
const sourceFiles = getTsMorphSourceFiles();
|
|
7
|
-
let totalChanged = 0;
|
|
8
|
-
|
|
9
|
-
for (const sourceFile of sourceFiles) {
|
|
10
|
-
let changed = false;
|
|
11
|
-
|
|
12
|
-
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
13
|
-
// ⚠️ 사이드이펙트 import는 유지
|
|
14
|
-
if (importDecl.getNamedImports().length === 0) {
|
|
15
|
-
continue;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// ⚙️ Named import 제거
|
|
19
|
-
for (const namedImport of importDecl.getNamedImports()) {
|
|
20
|
-
const name = namedImport.getName();
|
|
21
|
-
const used = sourceFile
|
|
22
|
-
.getDescendantsOfKind(SyntaxKind.Identifier)
|
|
23
|
-
.some((id) => id.getText() === name && id !== namedImport.getNameNode());
|
|
24
|
-
if (!used) {
|
|
25
|
-
namedImport.remove();
|
|
26
|
-
changed = true;
|
|
27
|
-
console.log(`[정리됨] ${sourceFile.getBaseName()} → 미사용 import: ${name}`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// 모든 import가 제거된 경우 전체 import 선언 제거
|
|
32
|
-
if (importDecl.getNamedImports().length === 0) {
|
|
33
|
-
importDecl.remove();
|
|
34
|
-
changed = true;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (changed) {
|
|
39
|
-
sourceFile.saveSync();
|
|
40
|
-
totalChanged++;
|
|
41
|
-
console.log(`[updated] ${sourceFile.getBaseName()} :: import 정리 완료`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
console.log(
|
|
46
|
-
totalChanged > 0
|
|
47
|
-
? `\n[완료] 미사용 import 정리 완료 (총 ${totalChanged}개)`
|
|
48
|
-
: `[완료] 정리 대상 없음`,
|
|
49
|
-
);
|
|
50
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
import { SyntaxKind } from "ts-morph";
|
|
3
|
-
import getTsMorphSourceFiles from "./core/getTsMortphSourceFiles";
|
|
4
|
-
|
|
5
|
-
export function removeUnusedInjects() {
|
|
6
|
-
const sourceFiles = getTsMorphSourceFiles();
|
|
7
|
-
let totalChanged = 0;
|
|
8
|
-
|
|
9
|
-
for (const sourceFile of sourceFiles) {
|
|
10
|
-
let changed = false;
|
|
11
|
-
|
|
12
|
-
for (const cls of sourceFile.getClasses()) {
|
|
13
|
-
const injectVars = cls
|
|
14
|
-
.getInstanceProperties()
|
|
15
|
-
.filter(
|
|
16
|
-
(p) =>
|
|
17
|
-
p.isKind(SyntaxKind.PropertyDeclaration) &&
|
|
18
|
-
p.getInitializer()?.isKind(SyntaxKind.CallExpression) &&
|
|
19
|
-
p.getInitializer()!.getText().startsWith("inject("),
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
for (const propDecl of injectVars) {
|
|
23
|
-
const name = propDecl.getName();
|
|
24
|
-
|
|
25
|
-
// 클래스 전체에서 해당 변수명이 참조되고 있는지 확인
|
|
26
|
-
const references = cls
|
|
27
|
-
.getDescendants()
|
|
28
|
-
.filter((desc) => desc.getText() === name && desc !== propDecl.getNameNode());
|
|
29
|
-
|
|
30
|
-
if (references.length === 0) {
|
|
31
|
-
propDecl.remove();
|
|
32
|
-
changed = true;
|
|
33
|
-
console.log(`[정리됨] ${sourceFile.getBaseName()} → 미사용 inject: ${name}`);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (changed) {
|
|
39
|
-
sourceFile.saveSync();
|
|
40
|
-
totalChanged++;
|
|
41
|
-
console.log(`[updated] ${sourceFile.getBaseName()} :: inject 정리 완료`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
console.log(
|
|
46
|
-
totalChanged > 0
|
|
47
|
-
? `\n[완료] 미사용 inject 정리 완료 (총 ${totalChanged}개)`
|
|
48
|
-
: `[완료] 정리 대상 없음`,
|
|
49
|
-
);
|
|
50
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
import { SyntaxKind } from "ts-morph";
|
|
3
|
-
import getTsMortphSourceFiles from "./core/getTsMortphSourceFiles";
|
|
4
|
-
|
|
5
|
-
export default function removeUnusedProtectedReadonly() {
|
|
6
|
-
const sourceFiles = getTsMortphSourceFiles();
|
|
7
|
-
|
|
8
|
-
for (const sourceFile of sourceFiles) {
|
|
9
|
-
const classes = sourceFile.getClasses();
|
|
10
|
-
|
|
11
|
-
for (const cls of classes) {
|
|
12
|
-
// @Component 데코레이터가 있는 클래스만 대상
|
|
13
|
-
const componentDecorator = cls.getDecorator("Component");
|
|
14
|
-
if (!componentDecorator) continue;
|
|
15
|
-
|
|
16
|
-
// 템플릿 문자열 추출
|
|
17
|
-
const templateArg = componentDecorator
|
|
18
|
-
.getArguments()
|
|
19
|
-
.find((arg) => arg.getKind() === SyntaxKind.ObjectLiteralExpression);
|
|
20
|
-
|
|
21
|
-
if (!templateArg || !templateArg.asKind(SyntaxKind.ObjectLiteralExpression)) continue;
|
|
22
|
-
|
|
23
|
-
const templateProp = templateArg
|
|
24
|
-
.asKindOrThrow(SyntaxKind.ObjectLiteralExpression)
|
|
25
|
-
.getProperty("template");
|
|
26
|
-
|
|
27
|
-
if (!templateProp || !templateProp.asKind(SyntaxKind.PropertyAssignment)) continue;
|
|
28
|
-
|
|
29
|
-
const initializer =
|
|
30
|
-
templateProp
|
|
31
|
-
.asKindOrThrow(SyntaxKind.PropertyAssignment)
|
|
32
|
-
.getInitializerIfKind(SyntaxKind.NoSubstitutionTemplateLiteral) ??
|
|
33
|
-
templateProp
|
|
34
|
-
.asKindOrThrow(SyntaxKind.PropertyAssignment)
|
|
35
|
-
.getInitializerIfKind(SyntaxKind.TemplateExpression) ??
|
|
36
|
-
templateProp
|
|
37
|
-
.asKindOrThrow(SyntaxKind.PropertyAssignment)
|
|
38
|
-
.getInitializerIfKind(SyntaxKind.StringLiteral);
|
|
39
|
-
|
|
40
|
-
const templateText = initializer?.getText().slice(1, -1); // `...` 또는 '...' 제거
|
|
41
|
-
if (templateText == null) continue;
|
|
42
|
-
|
|
43
|
-
// protected readonly 필드 중 템플릿에서 사용되지 않은 것 삭제
|
|
44
|
-
const protectedReadonlyFields = cls
|
|
45
|
-
.getProperties()
|
|
46
|
-
.filter((prop) => prop.getScope() === "protected" && prop.isReadonly() && !prop.isStatic());
|
|
47
|
-
|
|
48
|
-
for (const field of protectedReadonlyFields) {
|
|
49
|
-
const name = field.getName();
|
|
50
|
-
|
|
51
|
-
const usedInTemplate =
|
|
52
|
-
templateText.includes(name) || new RegExp(`\\b${name}\\b`).test(templateText);
|
|
53
|
-
|
|
54
|
-
const identifiers = cls.getDescendantsOfKind(SyntaxKind.Identifier);
|
|
55
|
-
const usedInClass = identifiers.some((id) => {
|
|
56
|
-
if (id.getText() !== name) return false;
|
|
57
|
-
return id !== field.getNameNode();
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
if (!usedInTemplate && !usedInClass) {
|
|
61
|
-
console.log(`🧹 Removing unused field: ${name} in ${sourceFile.getBaseName()}`);
|
|
62
|
-
field.remove();
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
sourceFile.saveSync();
|
|
68
|
-
}
|
|
69
|
-
}
|