@simplysm/sd-cli 12.9.42 → 12.10.2
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/sd-cli-electron.js +11 -14
- package/dist/entry/sd-cli-electron.js.map +1 -1
- package/dist/entry/sd-cli-postinstall.js +1 -1
- package/dist/entry/sd-cli-postinstall.js.map +1 -1
- package/dist/fix/convert-extends-sd-modal-base-to-interface.d.ts +1 -0
- package/dist/fix/convert-extends-sd-modal-base-to-interface.js +289 -0
- package/dist/fix/convert-extends-sd-modal-base-to-interface.js.map +1 -0
- package/dist/fix/convert-modal-show-params.d.ts +1 -0
- package/dist/fix/convert-modal-show-params.js +32 -0
- package/dist/fix/convert-modal-show-params.js.map +1 -0
- package/dist/fix/convert-sd-angular-symbol-names.js +1 -0
- package/dist/fix/convert-sd-angular-symbol-names.js.map +1 -1
- package/dist/fix/convert-sd-sheet-bindings-inInline-template.js +6 -1
- package/dist/fix/convert-sd-sheet-bindings-inInline-template.js.map +1 -1
- package/dist/fix/core/convert-symbol.js +1 -0
- package/dist/fix/core/convert-symbol.js.map +1 -1
- package/dist/fix/core/remove-named-import.d.ts +1 -0
- package/dist/fix/core/remove-named-import.js +14 -0
- package/dist/fix/core/remove-named-import.js.map +1 -0
- package/dist/fix/core/remove-symbol.d.ts +1 -0
- package/dist/fix/core/remove-symbol.js +76 -0
- package/dist/fix/core/remove-symbol.js.map +1 -0
- package/dist/fix/remove-sd-angular-symbol-names.d.ts +1 -0
- package/dist/fix/remove-sd-angular-symbol-names.js +9 -0
- package/dist/fix/remove-sd-angular-symbol-names.js.map +1 -0
- package/dist/pkg-builders/client/sd-ng.bundler.js +1 -1
- package/dist/pkg-builders/client/sd-ng.bundler.js.map +1 -1
- package/dist/sd-cli-entry.js +12 -14
- package/dist/sd-cli-entry.js.map +1 -1
- package/dist/sd-cli.js +54 -38
- package/dist/sd-cli.js.map +1 -1
- package/package.json +12 -12
- package/src/entry/sd-cli-electron.ts +34 -38
- package/src/entry/sd-cli-postinstall.ts +1 -1
- package/src/fix/convert-extends-sd-modal-base-to-interface.ts +324 -0
- package/src/fix/convert-modal-show-params.ts +41 -0
- package/src/fix/convert-sd-angular-symbol-names.ts +1 -0
- package/src/fix/convert-sd-sheet-bindings-inInline-template.ts +32 -29
- package/src/fix/core/convert-symbol.ts +2 -0
- package/src/fix/core/remove-named-import.ts +14 -0
- package/src/fix/core/remove-symbol.ts +94 -0
- package/src/fix/remove-sd-angular-symbol-names.ts +11 -0
- package/src/pkg-builders/client/sd-ng.bundler.ts +1 -1
- package/src/sd-cli-entry.ts +170 -167
- package/src/sd-cli.ts +66 -44
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { SyntaxKind } from "ts-morph";
|
|
4
|
+
import getTsMorphSourceFiles from "./core/get-ts-morph-source-files";
|
|
5
|
+
import removeNamedImport from "./core/remove-named-import";
|
|
6
|
+
|
|
7
|
+
export function convertExtendsSdModalBaseToInterface() {
|
|
8
|
+
const sourceFiles = getTsMorphSourceFiles();
|
|
9
|
+
|
|
10
|
+
let totalChanged = 0;
|
|
11
|
+
|
|
12
|
+
for (const sourceFile of sourceFiles) {
|
|
13
|
+
let changed = false;
|
|
14
|
+
const relPath = path.basename(sourceFile.getFilePath());
|
|
15
|
+
|
|
16
|
+
const modalClass = sourceFile.getClasses().find((classDecl) => {
|
|
17
|
+
const extendsClause = classDecl
|
|
18
|
+
.getHeritageClauses()
|
|
19
|
+
.find((h) => h.getToken() === SyntaxKind.ExtendsKeyword);
|
|
20
|
+
if (!extendsClause) return false;
|
|
21
|
+
const typeNodes = extendsClause.getTypeNodes();
|
|
22
|
+
return typeNodes.some((typeNode) =>
|
|
23
|
+
/^SdModalBase\s*<[^,>]+,\s*[^>]+\s*>$/.test(typeNode.getText()),
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (!modalClass) continue;
|
|
28
|
+
|
|
29
|
+
const extendsClause = modalClass
|
|
30
|
+
.getHeritageClauses()
|
|
31
|
+
.find((h) => h.getToken() === SyntaxKind.ExtendsKeyword);
|
|
32
|
+
if (!extendsClause) continue;
|
|
33
|
+
const typeNodes = extendsClause.getTypeNodes();
|
|
34
|
+
const match = typeNodes[0]?.getText().match(/^SdModalBase\s*<([^,>]+),\s*([^>]+)\s*>$/);
|
|
35
|
+
if (!match) continue;
|
|
36
|
+
const paramTypeName = match[1].trim();
|
|
37
|
+
const modalOutputTypeText = match[2].trim();
|
|
38
|
+
const paramInterface = sourceFile.getInterface(paramTypeName);
|
|
39
|
+
if (!paramInterface) continue;
|
|
40
|
+
let props = paramInterface.getProperties();
|
|
41
|
+
let paramNames = props.map((p) => p.getName());
|
|
42
|
+
|
|
43
|
+
const onlyISharedData =
|
|
44
|
+
props.length === 0 &&
|
|
45
|
+
paramInterface.getExtends().some(e =>
|
|
46
|
+
e.getText().includes("ISharedDataModalInputParam")
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
if (onlyISharedData) {
|
|
50
|
+
props = [
|
|
51
|
+
{
|
|
52
|
+
getName: () => "selectedItemKeys",
|
|
53
|
+
hasQuestionToken: () => false,
|
|
54
|
+
getTypeNode: () => ({ getText: () => "any[]" })
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
getName: () => "selectMode",
|
|
58
|
+
hasQuestionToken: () => true,
|
|
59
|
+
getTypeNode: () => ({ getText: () => `"single" | "multi"` })
|
|
60
|
+
}
|
|
61
|
+
] as any;
|
|
62
|
+
paramNames = ["selectedItemKeys", "selectMode"];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 1. property/class 필드/close 추가
|
|
66
|
+
let lastPropIdx = 0;
|
|
67
|
+
for (const prop of props) {
|
|
68
|
+
const propName = prop.getName();
|
|
69
|
+
const isOptional = prop.hasQuestionToken();
|
|
70
|
+
const propType = prop.getTypeNode()?.getText() ?? "any";
|
|
71
|
+
const initializer = `input${isOptional ? "" : ".required"}<${propType}>()`;
|
|
72
|
+
if (!modalClass.getProperty(propName)) {
|
|
73
|
+
modalClass.insertProperty(lastPropIdx, { name: propName, initializer });
|
|
74
|
+
lastPropIdx++;
|
|
75
|
+
changed = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!modalClass.getProperty("close")) {
|
|
79
|
+
modalClass.insertProperty(lastPropIdx, { name: "close", initializer: `output<${modalOutputTypeText}>()` });
|
|
80
|
+
changed = true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 2. extends → implements 변환
|
|
84
|
+
let implementsText: string;
|
|
85
|
+
if (modalOutputTypeText === "ISharedDataModalOutputResult") {
|
|
86
|
+
implementsText = "ISdSelectModal";
|
|
87
|
+
} else {
|
|
88
|
+
implementsText = `ISdModal<${modalOutputTypeText}>`;
|
|
89
|
+
}
|
|
90
|
+
if (!modalClass.getImplements().some(i => i.getText() === implementsText)) {
|
|
91
|
+
modalClass.addImplements(implementsText);
|
|
92
|
+
changed = true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 3. super() 삭제(생성자)
|
|
96
|
+
const ctor = modalClass.getConstructors().first();
|
|
97
|
+
if (ctor) {
|
|
98
|
+
ctor.getStatements().forEach((stmt) => {
|
|
99
|
+
if (stmt.getKind() === SyntaxKind.ExpressionStatement) {
|
|
100
|
+
const expr = stmt.asKind(SyntaxKind.ExpressionStatement)?.getExpression();
|
|
101
|
+
if (expr && expr.getKind() === SyntaxKind.CallExpression) {
|
|
102
|
+
const callExpr = expr.asKind(SyntaxKind.CallExpression);
|
|
103
|
+
if (
|
|
104
|
+
callExpr?.getExpression().getText() === "super" &&
|
|
105
|
+
callExpr.getArguments().length === 0
|
|
106
|
+
) {
|
|
107
|
+
stmt.remove();
|
|
108
|
+
changed = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 4. this.open() 전체 삭제(클래스 전체)
|
|
116
|
+
modalClass
|
|
117
|
+
.getDescendantsOfKind(SyntaxKind.CallExpression)
|
|
118
|
+
.filter(
|
|
119
|
+
(expr) =>
|
|
120
|
+
expr.getExpression().getKind() === SyntaxKind.PropertyAccessExpression &&
|
|
121
|
+
expr.getExpression().getText() === "this.open",
|
|
122
|
+
)
|
|
123
|
+
.forEach((expr) => {
|
|
124
|
+
const parentStmt = expr.getFirstAncestorByKind(SyntaxKind.ExpressionStatement);
|
|
125
|
+
if (parentStmt) {
|
|
126
|
+
parentStmt.remove();
|
|
127
|
+
changed = true;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// 5. params().xxx → xxx() 및 this.params().xxx → this.xxx() AST 치환
|
|
132
|
+
modalClass.forEachDescendant((node) => {
|
|
133
|
+
if (node.getKind() === SyntaxKind.PropertyAccessExpression) {
|
|
134
|
+
const propAccess = node.asKind(SyntaxKind.PropertyAccessExpression)!;
|
|
135
|
+
const propName = propAccess.getName();
|
|
136
|
+
if (!paramNames.includes(propName)) return;
|
|
137
|
+
const expr = propAccess.getExpression();
|
|
138
|
+
|
|
139
|
+
// params().xxx
|
|
140
|
+
if (expr.getKind() === SyntaxKind.CallExpression) {
|
|
141
|
+
const callExpr = expr.asKind(SyntaxKind.CallExpression)!;
|
|
142
|
+
const innerExpr = callExpr.getExpression();
|
|
143
|
+
|
|
144
|
+
// a) 단독 params()
|
|
145
|
+
if (innerExpr.getKind() === SyntaxKind.Identifier && innerExpr.getText() === "params") {
|
|
146
|
+
propAccess.replaceWithText(`${propName}()`);
|
|
147
|
+
changed = true;
|
|
148
|
+
}
|
|
149
|
+
// b) this.params()
|
|
150
|
+
else if (innerExpr.getKind() === SyntaxKind.PropertyAccessExpression) {
|
|
151
|
+
const propExpr = innerExpr.asKind(SyntaxKind.PropertyAccessExpression)!;
|
|
152
|
+
if (
|
|
153
|
+
propExpr.getExpression().getKind() === SyntaxKind.ThisKeyword &&
|
|
154
|
+
propExpr.getName() === "params"
|
|
155
|
+
) {
|
|
156
|
+
propAccess.replaceWithText(`this.${propName}()`);
|
|
157
|
+
changed = true;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// 6. this.close(...) → this.close.emit(...)
|
|
165
|
+
modalClass.forEachDescendant((node) => {
|
|
166
|
+
if (node.getKind() === SyntaxKind.CallExpression) {
|
|
167
|
+
const callExpr = node.asKind(SyntaxKind.CallExpression)!;
|
|
168
|
+
const expr = callExpr.getExpression();
|
|
169
|
+
if (
|
|
170
|
+
expr.getKind() === SyntaxKind.PropertyAccessExpression &&
|
|
171
|
+
expr.asKind(SyntaxKind.PropertyAccessExpression)!.getExpression().getKind() ===
|
|
172
|
+
SyntaxKind.ThisKeyword
|
|
173
|
+
) {
|
|
174
|
+
const methodName = expr.asKind(SyntaxKind.PropertyAccessExpression)!.getName();
|
|
175
|
+
if (methodName === "close") {
|
|
176
|
+
expr.asKind(SyntaxKind.PropertyAccessExpression)!.replaceWithText(`this.close.emit`);
|
|
177
|
+
changed = true;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// 7. @Component template: params().xxx → xxx() 치환
|
|
184
|
+
const componentDecorator = modalClass.getDecorator("Component");
|
|
185
|
+
if (componentDecorator) {
|
|
186
|
+
const arg = componentDecorator.getArguments().first();
|
|
187
|
+
if (arg && arg.getKind() === SyntaxKind.ObjectLiteralExpression) {
|
|
188
|
+
const objLit = arg.asKind(SyntaxKind.ObjectLiteralExpression)!;
|
|
189
|
+
const tplProp = objLit.getProperty("template");
|
|
190
|
+
if (
|
|
191
|
+
tplProp &&
|
|
192
|
+
tplProp.getKind() === SyntaxKind.PropertyAssignment &&
|
|
193
|
+
tplProp.asKind(SyntaxKind.PropertyAssignment)!.getInitializer()
|
|
194
|
+
) {
|
|
195
|
+
const propAssign = tplProp.asKind(SyntaxKind.PropertyAssignment)!;
|
|
196
|
+
const init = propAssign.getInitializerOrThrow();
|
|
197
|
+
let tplText = init.getText();
|
|
198
|
+
let tplTextRaw = tplText;
|
|
199
|
+
for (const paramName of paramNames) {
|
|
200
|
+
const paramsPattern = new RegExp(`params\\(\\)\\.${paramName}\\b`, "g");
|
|
201
|
+
tplTextRaw = tplTextRaw.replace(paramsPattern, `${paramName}()`);
|
|
202
|
+
}
|
|
203
|
+
if (tplTextRaw !== tplText) {
|
|
204
|
+
propAssign.setInitializer(tplTextRaw);
|
|
205
|
+
changed = true;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// 8. import 관리
|
|
212
|
+
const sdAngularImport = sourceFile.getImportDeclaration(
|
|
213
|
+
d => d.getModuleSpecifierValue() === "@simplysm/sd-angular"
|
|
214
|
+
);
|
|
215
|
+
if (modalOutputTypeText === "ISharedDataModalOutputResult") {
|
|
216
|
+
// ISdSelectModal 추가
|
|
217
|
+
if (sdAngularImport) {
|
|
218
|
+
const namedImports = sdAngularImport.getNamedImports();
|
|
219
|
+
// ISdSelectModal 없으면 추가
|
|
220
|
+
if (!namedImports.some(n => n.getName() === "ISdSelectModal")) {
|
|
221
|
+
sdAngularImport.addNamedImport("ISdSelectModal");
|
|
222
|
+
}
|
|
223
|
+
// ISdModal 제거
|
|
224
|
+
namedImports
|
|
225
|
+
.filter(n => n.getName() === "ISdModal")
|
|
226
|
+
.forEach(n => n.remove());
|
|
227
|
+
} else {
|
|
228
|
+
sourceFile.addImportDeclaration({
|
|
229
|
+
namedImports: ["ISdSelectModal"],
|
|
230
|
+
moduleSpecifier: "@simplysm/sd-angular"
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
// ISdModal 추가
|
|
235
|
+
if (sdAngularImport) {
|
|
236
|
+
const namedImports = sdAngularImport.getNamedImports();
|
|
237
|
+
// ISdModal 없으면 추가
|
|
238
|
+
if (!namedImports.some(n => n.getName() === "ISdModal")) {
|
|
239
|
+
sdAngularImport.addNamedImport("ISdModal");
|
|
240
|
+
}
|
|
241
|
+
// ISdSelectModal 제거
|
|
242
|
+
namedImports
|
|
243
|
+
.filter(n => n.getName() === "ISdSelectModal")
|
|
244
|
+
.forEach(n => n.remove());
|
|
245
|
+
} else {
|
|
246
|
+
sourceFile.addImportDeclaration({
|
|
247
|
+
namedImports: ["ISdModal"],
|
|
248
|
+
moduleSpecifier: "@simplysm/sd-angular"
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const ngCoreImport = sourceFile.getImportDeclaration(
|
|
254
|
+
(d) => d.getModuleSpecifierValue() === "@angular/core",
|
|
255
|
+
);
|
|
256
|
+
if (ngCoreImport) {
|
|
257
|
+
const imports = ngCoreImport.getNamedImports().map((n) => n.getName());
|
|
258
|
+
if (!imports.includes("input")) {
|
|
259
|
+
ngCoreImport.addNamedImport("input");
|
|
260
|
+
changed = true;
|
|
261
|
+
}
|
|
262
|
+
if (!imports.includes("output")) {
|
|
263
|
+
ngCoreImport.addNamedImport("output");
|
|
264
|
+
changed = true;
|
|
265
|
+
}
|
|
266
|
+
} else {
|
|
267
|
+
sourceFile.addImportDeclaration({
|
|
268
|
+
namedImports: ["input", "output"],
|
|
269
|
+
moduleSpecifier: "@angular/core",
|
|
270
|
+
});
|
|
271
|
+
changed = true;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// 9. $effect([this.params], ...) → $effect([], ...) (생성자)
|
|
275
|
+
if (ctor) {
|
|
276
|
+
ctor.forEachDescendant((node) => {
|
|
277
|
+
if (node.getKind() === SyntaxKind.CallExpression) {
|
|
278
|
+
const callExpr = node.asKind(SyntaxKind.CallExpression)!;
|
|
279
|
+
const expr = callExpr.getExpression();
|
|
280
|
+
if (expr.getKind() === SyntaxKind.Identifier && expr.getText() === "$effect") {
|
|
281
|
+
const args = callExpr.getArguments();
|
|
282
|
+
if (
|
|
283
|
+
args.length >= 1 &&
|
|
284
|
+
args[0].getKind() === SyntaxKind.ArrayLiteralExpression &&
|
|
285
|
+
args[0].asKind(SyntaxKind.ArrayLiteralExpression)!.getElements().length === 1
|
|
286
|
+
) {
|
|
287
|
+
const arrElem = args[0].asKind(SyntaxKind.ArrayLiteralExpression)!.getElements()[0];
|
|
288
|
+
if (
|
|
289
|
+
arrElem.getKind() === SyntaxKind.PropertyAccessExpression &&
|
|
290
|
+
arrElem.getText() === "this.params"
|
|
291
|
+
) {
|
|
292
|
+
args[0].replaceWithText("[]");
|
|
293
|
+
changed = true;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// 10. interface 선언 삭제
|
|
302
|
+
paramInterface.remove();
|
|
303
|
+
|
|
304
|
+
// 11. extends 삭제 (항상 마지막)
|
|
305
|
+
modalClass.removeExtends();
|
|
306
|
+
|
|
307
|
+
// 11. import 삭제
|
|
308
|
+
removeNamedImport(sourceFile, "@simplysm/sd-angular", "SdModalBase");
|
|
309
|
+
removeNamedImport(sourceFile, "@simplysm/sd-angular", "ISharedDataModalInputParam");
|
|
310
|
+
// removeNamedImport(sourceFile, "@simplysm/sd-angular", "ISharedDataModalOutputResult");
|
|
311
|
+
|
|
312
|
+
// 12. 저장 및 간결 로그 출력
|
|
313
|
+
if (changed) {
|
|
314
|
+
sourceFile.saveSync();
|
|
315
|
+
totalChanged++;
|
|
316
|
+
console.log(`[modal-updated] ${relPath} :: 모달기반 변경 완료`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (totalChanged > 0) {
|
|
320
|
+
console.log(`\n[완료] 모달변환 완료 (총 ${totalChanged}개)`);
|
|
321
|
+
} else {
|
|
322
|
+
console.log(`[완료] 변환 대상 없음`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Node, SyntaxKind } from "ts-morph";
|
|
2
|
+
import getTsMorphSourceFiles from "./core/get-ts-morph-source-files";
|
|
3
|
+
|
|
4
|
+
export default function convertShowAsyncCall() {
|
|
5
|
+
const sourceFiles = getTsMorphSourceFiles();
|
|
6
|
+
|
|
7
|
+
for (const sourceFile of sourceFiles) {
|
|
8
|
+
const callExprs = sourceFile
|
|
9
|
+
.getDescendantsOfKind(SyntaxKind.CallExpression)
|
|
10
|
+
.filter((callExpr) => {
|
|
11
|
+
const expr = callExpr.getExpression();
|
|
12
|
+
return (
|
|
13
|
+
Node.isPropertyAccessExpression(expr) &&
|
|
14
|
+
expr.getName() === "showAsync" &&
|
|
15
|
+
expr.getExpression().getText() === "this._sdModal"
|
|
16
|
+
);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
for (const callExpr of callExprs) {
|
|
20
|
+
const args = callExpr.getArguments();
|
|
21
|
+
if (args.length < 2 || args.length > 3) continue;
|
|
22
|
+
|
|
23
|
+
const [typeArg, titleArg, inputsArg] = args;
|
|
24
|
+
|
|
25
|
+
// 반드시 교체 전에 텍스트만 추출
|
|
26
|
+
const typeText = typeArg.getText();
|
|
27
|
+
const titleText = titleArg.getText();
|
|
28
|
+
const inputsText = inputsArg.getText();
|
|
29
|
+
|
|
30
|
+
const props: string[] = [`type: ${typeText}`, `title: ${titleText}`, `inputs: ${inputsText}`];
|
|
31
|
+
|
|
32
|
+
const objectLiteralText = `{
|
|
33
|
+
${props.join(",\n ")}
|
|
34
|
+
}`;
|
|
35
|
+
|
|
36
|
+
callExpr.replaceWithText(`this._sdModal.showAsync(${objectLiteralText})`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
sourceFile.saveSync();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -11,6 +11,7 @@ export default function convertSdAngularSymbolNames() {
|
|
|
11
11
|
"@simplysm/sd-angular#useActivatedRouteManager": "@simplysm/sd-angular#useQueryParamMapSignal",
|
|
12
12
|
"@simplysm/sd-angular#ISdSheetColumnOrderingVM": "@simplysm/sd-angular#ISdSortingDef",
|
|
13
13
|
"@simplysm/sd-angular#ISortingDef": "@simplysm/sd-angular#ISdSortingDef",
|
|
14
|
+
"@simplysm/sd-angular#ISharedDataModalOutputResult": "@simplysm/sd-angular#ISelectModalOutputResult",
|
|
14
15
|
|
|
15
16
|
"@angular/core#signal": "@simplysm/sd-angular#$signal",
|
|
16
17
|
"@angular/core#computed": "@simplysm/sd-angular#$computed",
|
|
@@ -21,50 +21,53 @@ export default function convertSdSheetBindingsSafely() {
|
|
|
21
21
|
if (!initializer) continue;
|
|
22
22
|
|
|
23
23
|
let rawTemplate: string | undefined;
|
|
24
|
-
if (
|
|
25
|
-
SyntaxKind.
|
|
24
|
+
if (
|
|
25
|
+
initializer.isKind(SyntaxKind.NoSubstitutionTemplateLiteral) ||
|
|
26
|
+
initializer.isKind(SyntaxKind.StringLiteral)
|
|
27
|
+
) {
|
|
26
28
|
rawTemplate = initializer.getLiteralText();
|
|
27
|
-
}
|
|
28
|
-
else if (initializer.isKind(SyntaxKind.TemplateExpression)) {
|
|
29
|
+
} else if (initializer.isKind(SyntaxKind.TemplateExpression)) {
|
|
29
30
|
rawTemplate = initializer.getFullText().slice(1, -1);
|
|
30
|
-
}
|
|
31
|
-
else continue;
|
|
31
|
+
} else continue;
|
|
32
32
|
|
|
33
33
|
// 정규식으로 <sd-sheet> 안에서만 바인딩 속성 치환
|
|
34
|
-
let newTemplate = rawTemplate.replace(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
let newTemplate = rawTemplate.replace(/<sd-sheet([\s\S]*?)>/g, (match) =>
|
|
35
|
+
match
|
|
36
|
+
.replace(/\[\(page\)\]/g, "[(currentPage)]")
|
|
37
|
+
.replace(/\[pageLength\]/g, "[totalPageCount]")
|
|
38
|
+
.replace(/\[\(ordering\)\]/g, "[(sorts)]")
|
|
39
|
+
.replace(/\[pageItemCount\]/g, "[itemsPerPage]"),
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
newTemplate = newTemplate.replace(/<sd-pagination([\s\S]*?)>/g, (match) =>
|
|
43
|
+
match
|
|
44
|
+
.replace(/\[\(page\)\]/g, "[(currentPage)]")
|
|
45
|
+
.replace(/\[pageLength\]/g, "[totalPageCount]")
|
|
46
|
+
.replace(/\[displayPageLength\]/g, "[visiblePageCount]"),
|
|
42
47
|
);
|
|
43
48
|
|
|
44
|
-
newTemplate = newTemplate.replace(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
.replace(/\[\(page\)\]/g, "[(currentPage)]")
|
|
49
|
-
.replace(/\[pageLength\]/g, "[totalPageCount]")
|
|
50
|
-
.replace(/\[displayPageLength\]/g, "[visiblePageCount]"),
|
|
49
|
+
newTemplate = newTemplate.replace(/<sd-sheet-column([\s\S]*?)>/g, (match) =>
|
|
50
|
+
match
|
|
51
|
+
.replace(/\[disableOrdering\]/g, "[disableSorting]")
|
|
52
|
+
.replace(/\sdisableOrdering/g, " disableSorting"),
|
|
51
53
|
);
|
|
52
54
|
|
|
53
|
-
newTemplate = newTemplate.replace(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
.replace(/\sdisableOrdering/g, " disableSorting"),
|
|
55
|
+
newTemplate = newTemplate.replace(/<ng-template([\s\S]*?)>/g, (match) =>
|
|
56
|
+
match
|
|
57
|
+
.replace(/target="content"/g, "#content")
|
|
58
|
+
.replace(/target="topbar"/g, "#pageTopbar")
|
|
59
|
+
.replace(/target="bottom"/g, "#modalBottom"),
|
|
59
60
|
);
|
|
60
61
|
|
|
61
62
|
if (rawTemplate !== newTemplate) {
|
|
62
63
|
initializer.replaceWithText("`" + newTemplate + "`");
|
|
63
|
-
console.log(
|
|
64
|
+
console.log(
|
|
65
|
+
`[template-updated] ${sourceFile.getBaseName()} :: 바인딩 속성 안전하게 변경 완료`,
|
|
66
|
+
);
|
|
64
67
|
sourceFile.saveSync();
|
|
65
68
|
}
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
console.log("[완료] 정규식 기반 안전한 sd-sheet 바인딩 속성 변경 완료");
|
|
70
|
-
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export default function removeNamedImport(sourceFile, moduleSpecifier, symbolName) {
|
|
2
|
+
const importDecl = sourceFile.getImportDeclaration(
|
|
3
|
+
(d) => d.getModuleSpecifierValue() === moduleSpecifier,
|
|
4
|
+
);
|
|
5
|
+
if (importDecl == null) return;
|
|
6
|
+
importDecl
|
|
7
|
+
.getNamedImports()
|
|
8
|
+
.filter((n) => n.getName() === symbolName)
|
|
9
|
+
.forEach((n) => n.remove());
|
|
10
|
+
// 만약 named import가 모두 사라지면 import문 자체 삭제
|
|
11
|
+
if (importDecl.getNamedImports().length === 0) {
|
|
12
|
+
importDecl.remove();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import {
|
|
3
|
+
SyntaxKind,
|
|
4
|
+
TypeReferenceNode,
|
|
5
|
+
Identifier,
|
|
6
|
+
ArrayLiteralExpression
|
|
7
|
+
} from "ts-morph";
|
|
8
|
+
import getTsMortphSourceFiles from "./get-ts-morph-source-files";
|
|
9
|
+
|
|
10
|
+
function parseTargets(symbols: string[]) {
|
|
11
|
+
return symbols.map((symbol) => {
|
|
12
|
+
const [importSource, symbolName] = symbol.split("#");
|
|
13
|
+
return { importSource, symbolName };
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default function removeSymbols(symbols: string[]) {
|
|
18
|
+
const targets = parseTargets(symbols);
|
|
19
|
+
const sourceFiles = getTsMortphSourceFiles();
|
|
20
|
+
|
|
21
|
+
for (const sourceFile of sourceFiles) {
|
|
22
|
+
let changed = false;
|
|
23
|
+
|
|
24
|
+
for (const { importSource, symbolName } of targets) {
|
|
25
|
+
// 1. Import 제거
|
|
26
|
+
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
27
|
+
if (importDecl.getModuleSpecifierValue() !== importSource) continue;
|
|
28
|
+
|
|
29
|
+
for (const namedImport of importDecl.getNamedImports()) {
|
|
30
|
+
if (namedImport.getName() === symbolName) {
|
|
31
|
+
console.log(`[import] ${sourceFile.getBaseName()} :: ${importSource} :: removed '${symbolName}'`);
|
|
32
|
+
namedImport.remove();
|
|
33
|
+
changed = true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (importDecl.getNamedImports().length === 0) {
|
|
38
|
+
console.log(`[import] ${sourceFile.getBaseName()} :: removed empty import from '${importSource}'`);
|
|
39
|
+
importDecl.remove();
|
|
40
|
+
changed = true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 2. 타입 참조 제거
|
|
45
|
+
sourceFile.forEachDescendant((node) => {
|
|
46
|
+
if (node.getKind() !== SyntaxKind.TypeReference) return;
|
|
47
|
+
|
|
48
|
+
const typeNode = node as TypeReferenceNode;
|
|
49
|
+
const typeName = typeNode.getTypeName().getText();
|
|
50
|
+
if (typeName !== symbolName) return;
|
|
51
|
+
|
|
52
|
+
const decl = node.getFirstAncestor((a) =>
|
|
53
|
+
a.getKind() === SyntaxKind.VariableStatement ||
|
|
54
|
+
a.getKind() === SyntaxKind.Parameter ||
|
|
55
|
+
a.getKind() === SyntaxKind.PropertyDeclaration
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
if (decl) {
|
|
59
|
+
console.log(`[type] ${sourceFile.getBaseName()} :: removed type usage of '${symbolName}'`);
|
|
60
|
+
|
|
61
|
+
const removable = decl.asKind(SyntaxKind.VariableStatement)
|
|
62
|
+
?? decl.asKind(SyntaxKind.Parameter)
|
|
63
|
+
?? decl.asKind(SyntaxKind.PropertyDeclaration);
|
|
64
|
+
|
|
65
|
+
if (removable) {
|
|
66
|
+
removable.remove();
|
|
67
|
+
changed = true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// 3. ArrayLiteral 내 사용 제거 (예: imports: [SdButtonControl])
|
|
73
|
+
sourceFile.forEachDescendant((node) => {
|
|
74
|
+
if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return;
|
|
75
|
+
|
|
76
|
+
const arr = node as ArrayLiteralExpression;
|
|
77
|
+
const elements = arr.getElements();
|
|
78
|
+
|
|
79
|
+
for (const el of elements) {
|
|
80
|
+
if (el.getKind() === SyntaxKind.Identifier && (el as Identifier).getText() === symbolName) {
|
|
81
|
+
console.log(`[usage] ${sourceFile.getBaseName()} :: removed '${symbolName}' from array`);
|
|
82
|
+
arr.removeElement(el);
|
|
83
|
+
changed = true;
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (changed) {
|
|
91
|
+
sourceFile.saveSync();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
|
|
3
|
+
import removeSymbols from "./core/remove-symbol";
|
|
4
|
+
|
|
5
|
+
export default function removeSdAngularSymbolNames() {
|
|
6
|
+
removeSymbols([
|
|
7
|
+
"@simplysm/sd-angular#TemplateTargetDirective",
|
|
8
|
+
]);
|
|
9
|
+
|
|
10
|
+
console.log("[완료] SdAngular 심볼 삭제 완료");
|
|
11
|
+
}
|
|
@@ -44,7 +44,7 @@ import { INpmConfig } from "../../types/common-configs.types";
|
|
|
44
44
|
import { ISdClientBuilderCordovaConfig } from "../../types/config.types";
|
|
45
45
|
import { ISdCliNgPluginResultCache } from "../../types/build-plugin.types";
|
|
46
46
|
import { ISdBuildMessage } from "../../types/build.types";
|
|
47
|
-
import nodeModule from "
|
|
47
|
+
import nodeModule from "module";
|
|
48
48
|
import { ScopePathSet } from "../commons/scope-path";
|
|
49
49
|
|
|
50
50
|
export class SdNgBundler {
|