@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.
Files changed (42) hide show
  1. package/dist/entry/SdCliAiCommand.js +13 -1
  2. package/dist/entry/SdCliCapacitor.d.ts +37 -0
  3. package/dist/entry/SdCliCapacitor.js +390 -0
  4. package/dist/pkg-builders/client/SdClientBuildRunner.d.ts +1 -0
  5. package/dist/pkg-builders/client/SdClientBuildRunner.js +14 -0
  6. package/dist/pkg-builders/client/SdNgBundler.js +3 -1
  7. package/dist/sd-cli-entry.js +18 -44
  8. package/dist/types/config/ISdProjectConfig.d.ts +31 -0
  9. package/package.json +5 -5
  10. package/src/entry/SdCliAiCommand.ts +14 -1
  11. package/src/entry/SdCliCapacitor.ts +560 -0
  12. package/src/pkg-builders/client/SdClientBuildRunner.ts +17 -0
  13. package/src/pkg-builders/client/SdNgBundler.ts +3 -1
  14. package/src/sd-cli-entry.ts +26 -56
  15. package/src/types/config/ISdProjectConfig.ts +34 -0
  16. package/dist/fix/convertPrivateToHash.d.ts +0 -1
  17. package/dist/fix/convertPrivateToHash.js +0 -58
  18. package/dist/fix/convertSdAngularSymbolNames.d.ts +0 -1
  19. package/dist/fix/convertSdAngularSymbolNames.js +0 -22
  20. package/dist/fix/core/convertSymbols.d.ts +0 -1
  21. package/dist/fix/core/convertSymbols.js +0 -101
  22. package/dist/fix/core/getTsMortphSourceFiles.d.ts +0 -1
  23. package/dist/fix/core/getTsMortphSourceFiles.js +0 -7
  24. package/dist/fix/core/removeSymbols.d.ts +0 -1
  25. package/dist/fix/core/removeSymbols.js +0 -76
  26. package/dist/fix/removeSdAngularSymbolNames.d.ts +0 -1
  27. package/dist/fix/removeSdAngularSymbolNames.js +0 -6
  28. package/dist/fix/removeUnusedImports.d.ts +0 -1
  29. package/dist/fix/removeUnusedImports.js +0 -41
  30. package/dist/fix/removeUnusedInjects.d.ts +0 -1
  31. package/dist/fix/removeUnusedInjects.js +0 -37
  32. package/dist/fix/removeUnusedProtectedReadonly.d.ts +0 -1
  33. package/dist/fix/removeUnusedProtectedReadonly.js +0 -57
  34. package/src/fix/convertPrivateToHash.ts +0 -74
  35. package/src/fix/convertSdAngularSymbolNames.ts +0 -27
  36. package/src/fix/core/convertSymbols.ts +0 -135
  37. package/src/fix/core/getTsMortphSourceFiles.ts +0 -9
  38. package/src/fix/core/removeSymbols.ts +0 -102
  39. package/src/fix/removeSdAngularSymbolNames.ts +0 -9
  40. package/src/fix/removeUnusedImports.ts +0 -50
  41. package/src/fix/removeUnusedInjects.ts +0 -50
  42. 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,9 +0,0 @@
1
- import { Project } from "ts-morph";
2
-
3
- export default function getTsMortphSourceFiles() {
4
- const project = new Project({
5
- tsConfigFilePath: "tsconfig.base.json",
6
- });
7
-
8
- return project.getSourceFiles("packages/*/src/**/*.ts");
9
- }
@@ -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,9 +0,0 @@
1
- /* eslint-disable no-console */
2
-
3
- import removeSymbols from "./core/removeSymbols";
4
-
5
- export default function removeSdAngularSymbolNames() {
6
- removeSymbols(["@simplysm/sd-angular#TemplateTargetDirective"]);
7
-
8
- console.log("[완료] SdAngular 심볼 삭제 완료");
9
- }
@@ -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
- }