@simplysm/sd-cli 12.8.21 → 12.9.1

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 (96) hide show
  1. package/dist/entry/sd-cli-ai-command.js +2 -1
  2. package/dist/entry/sd-cli-ai-command.js.map +1 -1
  3. package/dist/entry/sd-cli-cordova.d.ts +1 -1
  4. package/dist/entry/sd-cli-cordova.js +10 -9
  5. package/dist/entry/sd-cli-cordova.js.map +1 -1
  6. package/dist/entry/sd-cli-electron.d.ts +6 -6
  7. package/dist/entry/sd-cli-electron.js +15 -9
  8. package/dist/entry/sd-cli-electron.js.map +1 -1
  9. package/dist/entry/sd-cli-local-update.d.ts +5 -5
  10. package/dist/entry/sd-cli-local-update.js +8 -12
  11. package/dist/entry/sd-cli-local-update.js.map +1 -1
  12. package/dist/entry/sd-cli-project.d.ts +11 -11
  13. package/dist/entry/sd-cli-project.js +11 -14
  14. package/dist/entry/sd-cli-project.js.map +1 -1
  15. package/dist/entry/utils/loadProjConfAsync.d.ts +5 -0
  16. package/dist/entry/utils/loadProjConfAsync.js +8 -0
  17. package/dist/entry/utils/loadProjConfAsync.js.map +1 -0
  18. package/dist/pkg-builders/client/sd-client.build-runner.js +1 -1
  19. package/dist/pkg-builders/client/sd-client.build-runner.js.map +1 -1
  20. package/dist/pkg-builders/client/sd-ng.bundler-context.d.ts +6 -5
  21. package/dist/pkg-builders/client/sd-ng.bundler-context.js +6 -6
  22. package/dist/pkg-builders/client/sd-ng.bundler-context.js.map +1 -1
  23. package/dist/pkg-builders/client/sd-ng.bundler.d.ts +13 -13
  24. package/dist/pkg-builders/client/sd-ng.bundler.js +1 -1
  25. package/dist/pkg-builders/client/sd-ng.bundler.js.map +1 -1
  26. package/dist/pkg-builders/client/sd-ng.plugin-creator.js +4 -88
  27. package/dist/pkg-builders/client/sd-ng.plugin-creator.js.map +1 -1
  28. package/dist/pkg-builders/lib/sd-js-lib.build-runner.js.map +1 -1
  29. package/dist/pkg-builders/lib/sd-ts-lib.build-runner.d.ts +1 -1
  30. package/dist/pkg-builders/lib/sd-ts-lib.build-runner.js.map +1 -1
  31. package/dist/pkg-builders/lib/sd-ts-lib.builder.js.map +1 -1
  32. package/dist/pkg-builders/sd-multi.build-runner.d.ts +4 -0
  33. package/dist/pkg-builders/sd-multi.build-runner.js +33 -25
  34. package/dist/pkg-builders/sd-multi.build-runner.js.map +1 -1
  35. package/dist/pkg-builders/server/sd-server.build-runner.js.map +1 -1
  36. package/dist/pkg-builders/server/sd-server.bundler.d.ts +6 -2
  37. package/dist/pkg-builders/server/sd-server.bundler.js +24 -24
  38. package/dist/pkg-builders/server/sd-server.bundler.js.map +1 -1
  39. package/dist/sd-cli/vitest.config.d.ts +2 -0
  40. package/dist/sd-cli/vitest.config.js +15 -0
  41. package/dist/sd-cli/vitest.config.js.map +1 -0
  42. package/dist/sd-cli.js +7 -36
  43. package/dist/sd-cli.js.map +1 -1
  44. package/dist/ts-compiler/sd-dependency-analyzer.d.ts +8 -0
  45. package/dist/ts-compiler/sd-dependency-analyzer.js +244 -0
  46. package/dist/ts-compiler/sd-dependency-analyzer.js.map +1 -0
  47. package/dist/ts-compiler/sd-dependency-cache.d.ts +27 -0
  48. package/dist/ts-compiler/sd-dependency-cache.js +232 -0
  49. package/dist/ts-compiler/sd-dependency-cache.js.map +1 -0
  50. package/dist/ts-compiler/sd-ts-compiler.d.ts +7 -9
  51. package/dist/ts-compiler/sd-ts-compiler.js +101 -188
  52. package/dist/ts-compiler/sd-ts-compiler.js.map +1 -1
  53. package/dist/types/worker.types.d.ts +19 -0
  54. package/dist/utils/sd-cli-performance-time.d.ts +2 -1
  55. package/dist/utils/sd-cli-performance-time.js +9 -9
  56. package/dist/utils/sd-cli-performance-time.js.map +1 -1
  57. package/dist/workers/style-bundler.worker.d.ts +1 -0
  58. package/dist/workers/style-bundler.worker.js +56 -0
  59. package/dist/workers/style-bundler.worker.js.map +1 -0
  60. package/package.json +11 -11
  61. package/src/entry/sd-cli-ai-command.ts +2 -1
  62. package/src/entry/sd-cli-cordova.ts +20 -20
  63. package/src/entry/sd-cli-electron.ts +54 -23
  64. package/src/entry/sd-cli-local-update.ts +14 -29
  65. package/src/entry/sd-cli-project.ts +24 -41
  66. package/src/entry/utils/loadProjConfAsync.ts +12 -0
  67. package/src/pkg-builders/client/sd-client.build-runner.ts +7 -7
  68. package/src/pkg-builders/client/sd-ng.bundler-context.ts +15 -12
  69. package/src/pkg-builders/client/sd-ng.bundler.ts +17 -20
  70. package/src/pkg-builders/client/sd-ng.plugin-creator.ts +5 -94
  71. package/src/pkg-builders/lib/sd-js-lib.build-runner.ts +6 -6
  72. package/src/pkg-builders/lib/sd-ts-lib.build-runner.ts +7 -7
  73. package/src/pkg-builders/lib/sd-ts-lib.builder.ts +1 -1
  74. package/src/pkg-builders/sd-multi.build-runner.ts +54 -39
  75. package/src/pkg-builders/server/sd-server.build-runner.ts +6 -6
  76. package/src/pkg-builders/server/sd-server.bundler.ts +43 -35
  77. package/src/sd-cli.ts +7 -36
  78. package/src/ts-compiler/sd-dependency-analyzer.ts +312 -0
  79. package/src/ts-compiler/sd-dependency-cache.ts +328 -0
  80. package/src/ts-compiler/sd-ts-compiler.ts +161 -256
  81. package/src/types/worker.types.ts +17 -0
  82. package/src/utils/sd-cli-performance-time.ts +9 -9
  83. package/src/workers/style-bundler.worker.ts +70 -0
  84. package/tests/deps/sd-dependency-analyzer.spec.ts +272 -0
  85. package/tests/deps/sd-dependency-cache.spec.ts +144 -0
  86. package/tsconfig.json +1 -1
  87. package/tsconfig.test.json +8 -0
  88. package/vitest.config.ts +15 -0
  89. package/dist/index.d.ts +0 -34
  90. package/dist/index.js +0 -35
  91. package/dist/index.js.map +0 -1
  92. package/dist/ts-compiler/sd-ts-dependency-analyzer.d.ts +0 -10
  93. package/dist/ts-compiler/sd-ts-dependency-analyzer.js +0 -140
  94. package/dist/ts-compiler/sd-ts-dependency-analyzer.js.map +0 -1
  95. package/src/index.ts +0 -34
  96. package/src/ts-compiler/sd-ts-dependency-analyzer.ts +0 -176
@@ -1,18 +1,18 @@
1
1
  export class SdCliPerformanceTimer {
2
- #startingMap = new Map<string, number>();
3
- #resultMap = new Map<string, number>();
2
+ private _startingMap = new Map<string, number>();
3
+ private _resultMap = new Map<string, number>();
4
4
 
5
5
  constructor(private _name: string) {}
6
6
 
7
7
  start(name: string) {
8
- this.#startingMap.set(name, new Date().getTime());
8
+ this._startingMap.set(name, new Date().getTime());
9
9
  }
10
10
 
11
11
  end(name: string) {
12
- const val = this.#startingMap.get(name);
12
+ const val = this._startingMap.get(name);
13
13
  if (val == null) throw new Error();
14
- this.#resultMap.set(name, new Date().getTime() - val);
15
- this.#startingMap.delete(name);
14
+ this._resultMap.set(name, new Date().getTime() - val);
15
+ this._startingMap.delete(name);
16
16
  }
17
17
 
18
18
  run<R>(name: string, fn: () => R): R {
@@ -21,20 +21,20 @@ export class SdCliPerformanceTimer {
21
21
  if (res instanceof Promise) {
22
22
  return res.then((realRes) => {
23
23
  const duration = new Date().getTime() - startTime;
24
- this.#resultMap.update(name, (v) => (v ?? 0) + duration);
24
+ this._resultMap.update(name, (v) => (v ?? 0) + duration);
25
25
  return realRes;
26
26
  }) as R;
27
27
  }
28
28
 
29
29
  const duration = new Date().getTime() - startTime;
30
- this.#resultMap.update(name, (v) => (v ?? 0) + duration);
30
+ this._resultMap.update(name, (v) => (v ?? 0) + duration);
31
31
  return res;
32
32
  }
33
33
 
34
34
  toString() {
35
35
  return `${this._name} 성능 보고서
36
36
  ------------------------------------
37
- ${Array.from(this.#resultMap.entries())
37
+ ${Array.from(this._resultMap.entries())
38
38
  .map((en) => `${en[0]}: ${en[1].toLocaleString()}ms`)
39
39
  .join("\n")}
40
40
  ------------------------------------`;
@@ -0,0 +1,70 @@
1
+ import { createSdWorker, SdLogger, SdLoggerSeverity, TNormPath } from "@simplysm/sd-core-node";
2
+ import { TStyleBundlerWorkerType } from "../types/worker.types";
3
+ import { EventEmitter } from "events";
4
+ import {
5
+ ComponentStylesheetBundler,
6
+ } from "@angular/build/src/tools/esbuild/angular/component-stylesheets";
7
+ import { transformSupportedBrowsersToTargets } from "@angular/build/src/tools/esbuild/utils";
8
+ import browserslist from "browserslist";
9
+
10
+ Error.stackTraceLimit = Infinity;
11
+ EventEmitter.defaultMaxListeners = 0;
12
+
13
+ if (process.env["SD_DEBUG"] != null) {
14
+ SdLogger.setConfig({
15
+ console: {
16
+ level: SdLoggerSeverity.debug,
17
+ },
18
+ });
19
+ }
20
+ else {
21
+ SdLogger.setConfig({
22
+ dot: true,
23
+ });
24
+ }
25
+
26
+ let stylesheetBundler: ComponentStylesheetBundler;
27
+
28
+ createSdWorker<TStyleBundlerWorkerType>({
29
+ prepare(rootPath: string, dev: boolean) {
30
+ //-- stylesheetBundler
31
+ stylesheetBundler = new ComponentStylesheetBundler(
32
+ {
33
+ workspaceRoot: rootPath,
34
+ optimization: !dev,
35
+ inlineFonts: true,
36
+ preserveSymlinks: false,
37
+ sourcemap: dev ? "inline" : false,
38
+ outputNames: { bundles: "[name]", media: "media/[name]" },
39
+ includePaths: [],
40
+ // sass:
41
+ externalDependencies: [],
42
+ target: transformSupportedBrowsersToTargets(browserslist(["Chrome > 78"])),
43
+ tailwindConfiguration: undefined,
44
+ postcssConfiguration: {
45
+ plugins: [["css-has-pseudo"]],
46
+ },
47
+ // publicPath:
48
+ cacheOptions: {
49
+ enabled: true,
50
+ path: ".cache/angular",
51
+ basePath: ".cache",
52
+ },
53
+ },
54
+ "scss",
55
+ dev,
56
+ );
57
+ },
58
+ async bundle(
59
+ data: string,
60
+ containingFile: TNormPath,
61
+ resourceFile: TNormPath | null = null,
62
+ ) {
63
+ return resourceFile != null
64
+ ? await stylesheetBundler!.bundleFile(resourceFile)
65
+ : await stylesheetBundler!.bundleInline(data, containingFile, "scss");
66
+ },
67
+ invalidate(fileNPathSet: Set<TNormPath>) {
68
+ stylesheetBundler.invalidate(fileNPathSet);
69
+ },
70
+ });
@@ -0,0 +1,272 @@
1
+ import { beforeEach, describe, expect, it } from "vitest";
2
+ import * as ts from "typescript";
3
+ import { PathUtils, TNormPath } from "@simplysm/sd-core-node/src";
4
+ import { SdDependencyCache } from "../../src/ts-compiler/sd-dependency-cache";
5
+ import { SdDependencyAnalyzer } from "../../src/ts-compiler/sd-dependency-analyzer";
6
+
7
+ function createMockProgram(sources: Record<string, string>) {
8
+ const fileNames = Object.keys(sources);
9
+ const compilerHost = ts.createCompilerHost({});
10
+ compilerHost.readFile = (fileName: string) => sources[fileName] ?? "";
11
+ compilerHost.fileExists = (fileName: string) => fileName in sources;
12
+ compilerHost.getSourceFile = (fileName, languageVersion) => {
13
+ const sourceText = sources[fileName];
14
+ if (!sourceText) return undefined;
15
+ return ts.createSourceFile(fileName, sourceText, languageVersion);
16
+ };
17
+ const program = ts.createProgram(fileNames, {}, compilerHost);
18
+ return { program, compilerHost };
19
+ }
20
+
21
+ function norm(path: string): TNormPath {
22
+ return PathUtils.norm(path);
23
+ }
24
+
25
+ describe("DependencyAnalyzer", () => {
26
+ const scope = PathUtils.norm("/");
27
+ let depCache: SdDependencyCache;
28
+
29
+ beforeEach(() => {
30
+ depCache = new SdDependencyCache();
31
+ });
32
+
33
+ it("1레벨 의존성 추적", () => {
34
+ const files = {
35
+ "/a.ts": `export const A = 1;`,
36
+ "/b.ts": `import { A } from "./a";`,
37
+ };
38
+
39
+ const { program, compilerHost } = createMockProgram(files);
40
+ SdDependencyAnalyzer.analyze(program, compilerHost, [scope], depCache);
41
+
42
+ const result = depCache.getAffectedFileSet(new Set([norm("/a.ts")]));
43
+ expect(result).toEqual(new Set([
44
+ norm("/a.ts"),
45
+ norm("/b.ts"),
46
+ ]));
47
+ });
48
+
49
+ it("2레벨 의존성 추적", () => {
50
+ const files = {
51
+ "/a.ts": `export const A = 1;`,
52
+ "/b.ts": `export * from "./a";`,
53
+ "/c.ts": `import { A } from "./b";`,
54
+ };
55
+
56
+ const { program, compilerHost } = createMockProgram(files);
57
+ SdDependencyAnalyzer.analyze(program, compilerHost, [scope], depCache);
58
+
59
+ {
60
+ const result = depCache.getAffectedFileSet(new Set([norm("/a.ts")]));
61
+ expect(result).toEqual(new Set([
62
+ norm("/a.ts"),
63
+ norm("/b.ts"), // a파일이 사라지거나 하면 b가 오류를 뱉어야 하므로
64
+ norm("/c.ts"),
65
+ ]));
66
+ }
67
+
68
+ {
69
+ const result = depCache.getAffectedFileSet(new Set([norm("/b.ts")]));
70
+ expect(result).toEqual(new Set([
71
+ norm("/b.ts"),
72
+ norm("/c.ts"),
73
+ ]));
74
+ }
75
+ });
76
+
77
+ it("2레벨 Rename 의존성 추적", () => {
78
+ const files = {
79
+ "/a.ts": `export const A = 1;`,
80
+ "/b.ts": `export { A as B } from "./a";`,
81
+ "/c.ts": `import { B } from "./b";`,
82
+ };
83
+
84
+ const { program, compilerHost } = createMockProgram(files);
85
+ SdDependencyAnalyzer.analyze(program, compilerHost, [scope], depCache);
86
+
87
+ {
88
+ const result = depCache.getAffectedFileSet(new Set([norm("/a.ts")]));
89
+ expect(result).toEqual(new Set([
90
+ norm("/a.ts"),
91
+ norm("/b.ts"), // a파일이 사라지거나 하면 b가 오류를 뱉어야 하므로
92
+ norm("/c.ts"),
93
+ ]));
94
+ }
95
+
96
+ {
97
+ const result = depCache.getAffectedFileSet(new Set([norm("/b.ts")]));
98
+ expect(result).toEqual(new Set([
99
+ norm("/b.ts"),
100
+ norm("/c.ts"),
101
+ ]));
102
+ }
103
+ });
104
+
105
+ it("2레벨 선택적 의존성 추적", () => {
106
+ const files = {
107
+ "/a.ts": `export const A = 1;`,
108
+ "/a_1.ts": `export const A_1 = 1;`,
109
+ "/b.ts": `export * from "./a"; export * from "./a_1";`,
110
+ "/c.ts": `import { A } from "./b";`,
111
+ };
112
+
113
+ const { program, compilerHost } = createMockProgram(files);
114
+ SdDependencyAnalyzer.analyze(program, compilerHost, [scope], depCache);
115
+
116
+ {
117
+ const result = depCache.getAffectedFileSet(new Set([norm("/a.ts")]));
118
+ expect(result).toEqual(new Set([
119
+ norm("/a.ts"),
120
+ norm("/b.ts"),
121
+ norm("/c.ts"),
122
+ ]));
123
+ }
124
+
125
+ {
126
+ const result = depCache.getAffectedFileSet(new Set([norm("/a_1.ts")]));
127
+ expect(result).toEqual(new Set([
128
+ norm("/a_1.ts"),
129
+ norm("/b.ts"),
130
+ ]));
131
+ }
132
+ });
133
+
134
+
135
+ it("A.b.c와같은 간접 의존성 추적", () => {
136
+ const files = {
137
+ "/a.ts": `
138
+ import { B } from "./b";
139
+ export class A {
140
+ b: B = new B();
141
+ }
142
+ `,
143
+ "/b.ts": `
144
+ export class B {
145
+ c: string = "hello";
146
+ }
147
+ `,
148
+ "/c.ts": `
149
+ import { A } from "./a";
150
+
151
+ function doSomething() {
152
+ // A.b.c 속성 접근을 통해 B에 간접 의존
153
+ console.log(new A().b.c);
154
+ }
155
+ `,
156
+ };
157
+
158
+ const { program, compilerHost } = createMockProgram(files);
159
+ SdDependencyAnalyzer.analyze(program, compilerHost, [scope], depCache);
160
+
161
+ // B가 변경되면 A와 C 모두 영향 받는지 확인
162
+ const result = depCache.getAffectedFileSet(new Set([norm("/b.ts")]));
163
+ expect(result).toEqual(new Set([
164
+ norm("/a.ts"),
165
+ norm("/b.ts"),
166
+ norm("/c.ts"),
167
+ ]));
168
+ });
169
+
170
+ it("A['b'].c와같은 Element 간접 의존성 추적", () => {
171
+ const files = {
172
+ "/a.ts": `
173
+ import { B } from "./b";
174
+ export class A {
175
+ b: B = new B();
176
+ }
177
+ `,
178
+ "/b.ts": `
179
+ export class B {
180
+ c: string = "hello";
181
+ }
182
+ `,
183
+ "/c.ts": `
184
+ import { A } from "./a";
185
+
186
+ function doSomething() {
187
+ // A['b'].c 속성 접근을 통해 B에 간접 의존
188
+ console.log(new A()['b'].c);
189
+ }
190
+ `,
191
+ };
192
+
193
+ const { program, compilerHost } = createMockProgram(files);
194
+ SdDependencyAnalyzer.analyze(program, compilerHost, [scope], depCache);
195
+
196
+ // B가 변경되면 A와 C 모두 영향 받는지 확인
197
+ const result = depCache.getAffectedFileSet(new Set([norm("/b.ts")]));
198
+ expect(result).toEqual(new Set([
199
+ norm("/a.ts"),
200
+ norm("/b.ts"),
201
+ norm("/c.ts"),
202
+ ]));
203
+ });
204
+
205
+ it("타입만 사용하는 경우에도 의존성으로 추적된다", () => {
206
+ const files = {
207
+ "/a.ts": `export interface IA { value: string; }`,
208
+ "/b.ts": `import { IA } from "./a"; const val: IA = { value: "hi" };`,
209
+ };
210
+
211
+ const { program, compilerHost } = createMockProgram(files);
212
+ SdDependencyAnalyzer.analyze(program, compilerHost, [scope], depCache);
213
+
214
+ const result = depCache.getAffectedFileSet(new Set([norm("/a.ts")]));
215
+ expect(result).toEqual(new Set([
216
+ norm("/a.ts"),
217
+ norm("/b.ts"),
218
+ ]));
219
+ });
220
+
221
+ it("함수 반환 타입을 통한 간접 의존성도 추적된다", () => {
222
+ const files = {
223
+ "/a.ts": `export class A { value = 1; }`,
224
+ "/b.ts": `import { A } from "./a"; export function getA(): A { return new A(); }`,
225
+ "/c.ts": `import { getA } from "./b"; console.log(getA().value);`,
226
+ };
227
+
228
+ const { program, compilerHost } = createMockProgram(files);
229
+ SdDependencyAnalyzer.analyze(program, compilerHost, [scope], depCache);
230
+
231
+ const result = depCache.getAffectedFileSet(new Set([norm("/a.ts")]));
232
+ expect(result).toEqual(new Set([
233
+ norm("/a.ts"),
234
+ norm("/b.ts"),
235
+ norm("/c.ts"),
236
+ ]));
237
+ });
238
+
239
+ it("optional chaining으로 접근해도 의존성은 추적된다", () => {
240
+ const files = {
241
+ "/a.ts": `export class A { b?: { c: number }; }`,
242
+ "/b.ts": `import { A } from "./a"; const a = new A(); console.log(a.b?.c);`,
243
+ };
244
+
245
+ const { program, compilerHost } = createMockProgram(files);
246
+ SdDependencyAnalyzer.analyze(program, compilerHost, [scope], depCache);
247
+
248
+ const result = depCache.getAffectedFileSet(new Set([norm("/a.ts")]));
249
+ expect(result).toEqual(new Set([
250
+ norm("/a.ts"),
251
+ norm("/b.ts"),
252
+ ]));
253
+ });
254
+
255
+ it("invalidates()는 영향 받은 모든 파일을 캐시에서 제거한다", () => {
256
+ const files = {
257
+ "/a.ts": `export const A = 1;`,
258
+ "/b.ts": `import { A } from "./a";`,
259
+ "/c.ts": `import { A } from "./a";`,
260
+ };
261
+
262
+ const { program, compilerHost } = createMockProgram(files);
263
+ SdDependencyAnalyzer.analyze(program, compilerHost, [scope], depCache);
264
+
265
+ // invalidate 처리
266
+ depCache.invalidates(new Set([norm("/a.ts")]));
267
+
268
+ const affected = depCache.getAffectedFileSet(new Set([norm("/a.ts")]));
269
+ // 분석 안된 상태이므로, a만 남아야 함
270
+ expect(affected).toEqual(new Set([norm("/a.ts")]));
271
+ });
272
+ });
@@ -0,0 +1,144 @@
1
+ import "@simplysm/sd-core-common";
2
+ import { PathUtils } from "@simplysm/sd-core-node";
3
+ import { beforeEach, describe, expect, it } from "vitest";
4
+ import {
5
+ ISdAffectedFileTreeNode,
6
+ SdDependencyCache,
7
+ } from "../../src/ts-compiler/sd-dependency-cache";
8
+
9
+ describe("SdDependencyCache", () => {
10
+ const a = PathUtils.norm("/a.ts");
11
+ const b = PathUtils.norm("/b.ts");
12
+ const c = PathUtils.norm("/c.ts");
13
+ const html = PathUtils.norm("/comp.html");
14
+ const style = PathUtils.norm("/style.scss");
15
+
16
+ let depCache: SdDependencyCache;
17
+
18
+ beforeEach(() => {
19
+ depCache = new SdDependencyCache();
20
+ });
21
+
22
+ it("export * from 구문으로 재export된 심볼이 정확히 전파된다", () => {
23
+ // a.ts → export const A
24
+ depCache.addExport(a, "A");
25
+
26
+ // b.ts → export * from './a.ts'
27
+ depCache.addReexport(b, a, 0);
28
+
29
+ // c.ts → import { A } from './b.ts'
30
+ depCache.addImport(c, b, "A");
31
+
32
+ const result = depCache.getAffectedFileSet(new Set([a]));
33
+ expect(result).toEqual(new Set([a, b, c]));
34
+ });
35
+
36
+ it("export { A as B } from 구문으로 이름이 바뀐 심볼도 추적된다", () => {
37
+ // a.ts → export const A
38
+ depCache.addExport(a, "A");
39
+
40
+ // b.ts → export { A as B } from './a.ts'
41
+ depCache.addReexport(b, a, {
42
+ importSymbol: "A",
43
+ exportSymbol: "B",
44
+ });
45
+
46
+ // c.ts → import { B } from './b.ts'
47
+ depCache.addImport(c, b, "B");
48
+
49
+ const result = depCache.getAffectedFileSet(new Set([a]));
50
+ expect(result).toEqual(new Set([a, b, c]));
51
+ });
52
+
53
+ it("import { X } 구문은 정확히 사용한 심볼만 추적한다", () => {
54
+ // b.ts → export const Foo
55
+ depCache.addExport(b, "Foo");
56
+
57
+ // a.ts → import { Foo } from './b.ts'
58
+ depCache.addImport(a, b, "Foo");
59
+
60
+ const result = depCache.getAffectedFileSet(new Set([b]));
61
+ expect(result).toEqual(new Set([b, a]));
62
+ });
63
+
64
+ it("import * (namespace import)은 모든 export의 영향을 받는다", () => {
65
+ // b.ts → export const Bar
66
+ depCache.addExport(b, "Bar");
67
+
68
+ // a.ts → import * as B from './b.ts'
69
+ depCache.addImport(a, b, 0);
70
+
71
+ const result = depCache.getAffectedFileSet(new Set([b]));
72
+ expect(result).toEqual(new Set([b, a]));
73
+ });
74
+
75
+ it("심볼이 일치하지 않으면 영향이 전파되지 않는다", () => {
76
+ // b.ts → export const Foo
77
+ depCache.addExport(b, "Foo");
78
+
79
+ // a.ts → import { NotFoo } from './b.ts'
80
+ depCache.addImport(a, b, "NotFoo");
81
+
82
+ const result = depCache.getAffectedFileSet(new Set([b]));
83
+ expect(result).toEqual(new Set([b])); // a.ts는 영향 없음
84
+ });
85
+
86
+ it("리소스 의존은 역의존만 추적되고 심볼 전파는 없다", () => {
87
+ // a.ts → templateUrl: "comp.html"
88
+ depCache.addImport(a, html, 0);
89
+
90
+ const result = depCache.getAffectedFileSet(new Set([html]));
91
+ expect(result).toEqual(new Set([html, a])); // 단순 역참조만 전파
92
+ });
93
+
94
+ it("reexport 후 재import된 경로의 역의존도 정확히 추적된다", () => {
95
+ depCache.addExport(a, "X");
96
+ depCache.addReexport(b, a, { importSymbol: "X", exportSymbol: "Y" });
97
+ depCache.addImport(c, b, "Y");
98
+
99
+ const result = depCache.getAffectedFileSet(new Set([a]));
100
+ expect(result).toEqual(new Set([a, b, c]));
101
+ });
102
+
103
+ it("invalidates()는 캐시에서 모든 관련 정보를 제거한다", () => {
104
+ depCache.addExport(a, "X");
105
+ depCache.addImport(b, a, "X");
106
+
107
+ depCache.invalidates(new Set([a]));
108
+
109
+ // 내부 캐시 확인
110
+ expect(depCache["_exportCache"].has(a)).toBe(false);
111
+ expect(depCache["_revDepCache"].get(a)?.has(b)).toBeFalsy(); // unefined
112
+ });
113
+
114
+ it("getAffectedFileTree()는 영향도를 트리 형태로 표현한다", () => {
115
+ // a.ts → export A
116
+ depCache.addExport(a, "A");
117
+
118
+ // b.ts → export { A as B } from './a.ts'
119
+ depCache.addReexport(b, a, {
120
+ importSymbol: "A",
121
+ exportSymbol: "B",
122
+ });
123
+
124
+ // c.ts → import { B } from './b.ts'
125
+ depCache.addImport(c, b, "B");
126
+
127
+ const trees = depCache.getAffectedFileTree(new Set([a]));
128
+
129
+ expect(trees.length).toBeGreaterThan(0);
130
+ const aNode = trees.find(t => t.fileNPath === a)!;
131
+ expect(aNode.children.some(c1 => c1.fileNPath === b)).toBeTruthy();
132
+ const bNode = aNode.children.find(c1 => c1.fileNPath === b)!;
133
+ expect(bNode.children.some(c2 => c2.fileNPath === c)).toBeTruthy();
134
+
135
+ const printTree = (node: ISdAffectedFileTreeNode, indent = "") => {
136
+ console.log(indent + node.fileNPath);
137
+ for (const child of node.children) {
138
+ printTree(child, indent + " ");
139
+ }
140
+ };
141
+
142
+ console.log(printTree(trees[0]));
143
+ });
144
+ });
package/tsconfig.json CHANGED
@@ -4,5 +4,5 @@
4
4
  "lib": ["ES2021"],
5
5
  "outDir": "./dist"
6
6
  },
7
- "exclude": ["dist", "node_modules"]
7
+ "exclude": ["dist", "node_modules", "tests"]
8
8
  }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "lib": ["ES2021"],
5
+ "outDir": "./dist"
6
+ },
7
+ "exclude": ["dist", "node_modules"]
8
+ }
@@ -0,0 +1,15 @@
1
+ import { defineConfig } from "vitest/config";
2
+ import tsconfigPaths from "vite-tsconfig-paths";
3
+
4
+ export default defineConfig({
5
+ plugins: [
6
+ tsconfigPaths({
7
+ projects: ["../../tsconfig.base.json"],
8
+ }),
9
+ ],
10
+ test: {
11
+ globals: true,
12
+ environment: "node",
13
+ include: ["tests/**/*.spec.ts"],
14
+ },
15
+ });
package/dist/index.d.ts DELETED
@@ -1,34 +0,0 @@
1
- export * from "./entry/sd-cli-ai-command";
2
- export * from "./entry/sd-cli-cordova";
3
- export * from "./entry/sd-cli-electron";
4
- export * from "./entry/sd-cli-local-update";
5
- export * from "./entry/sd-cli-postinstall";
6
- export * from "./entry/sd-cli-project";
7
- export * from "./pkg-builders/client/sd-cli-ng-routes.file-generator";
8
- export * from "./pkg-builders/client/sd-client.build-runner";
9
- export * from "./pkg-builders/client/sd-ng.bundler-context";
10
- export * from "./pkg-builders/client/sd-ng.bundler";
11
- export * from "./pkg-builders/client/sd-ng.plugin-creator";
12
- export * from "./pkg-builders/lib/sd-cli-db-context.file-generator";
13
- export * from "./pkg-builders/lib/sd-cli-index.file-generator";
14
- export * from "./pkg-builders/lib/sd-js-lib.build-runner";
15
- export * from "./pkg-builders/lib/sd-ts-lib.build-runner";
16
- export * from "./pkg-builders/lib/sd-ts-lib.builder";
17
- export * from "./pkg-builders/sd-multi.build-runner";
18
- export * from "./pkg-builders/server/sd-server.build-runner";
19
- export * from "./pkg-builders/server/sd-server.bundler";
20
- export * from "./pkg-builders/server/sd-server.plugin-creator";
21
- import "./sd-cli";
22
- export * from "./ts-compiler/sd-ts-compiler";
23
- export * from "./ts-compiler/sd-ts-dependency-analyzer";
24
- export * from "./types/build-plugin.types";
25
- export * from "./types/build-runner.types";
26
- export * from "./types/build.types";
27
- export * from "./types/common-configs.types";
28
- export * from "./types/config.types";
29
- export * from "./types/ts-compiler.types";
30
- export * from "./types/worker.types";
31
- export * from "./utils/sd-cli-convert-message.utils";
32
- export * from "./utils/sd-cli-performance-time";
33
- import "./workers/build-runner.worker";
34
- import "./workers/server.worker";
package/dist/index.js DELETED
@@ -1,35 +0,0 @@
1
- export * from "./entry/sd-cli-ai-command";
2
- export * from "./entry/sd-cli-cordova";
3
- export * from "./entry/sd-cli-electron";
4
- export * from "./entry/sd-cli-local-update";
5
- export * from "./entry/sd-cli-postinstall";
6
- export * from "./entry/sd-cli-project";
7
- export * from "./pkg-builders/client/sd-cli-ng-routes.file-generator";
8
- export * from "./pkg-builders/client/sd-client.build-runner";
9
- export * from "./pkg-builders/client/sd-ng.bundler-context";
10
- export * from "./pkg-builders/client/sd-ng.bundler";
11
- export * from "./pkg-builders/client/sd-ng.plugin-creator";
12
- export * from "./pkg-builders/lib/sd-cli-db-context.file-generator";
13
- export * from "./pkg-builders/lib/sd-cli-index.file-generator";
14
- export * from "./pkg-builders/lib/sd-js-lib.build-runner";
15
- export * from "./pkg-builders/lib/sd-ts-lib.build-runner";
16
- export * from "./pkg-builders/lib/sd-ts-lib.builder";
17
- export * from "./pkg-builders/sd-multi.build-runner";
18
- export * from "./pkg-builders/server/sd-server.build-runner";
19
- export * from "./pkg-builders/server/sd-server.bundler";
20
- export * from "./pkg-builders/server/sd-server.plugin-creator";
21
- import "./sd-cli";
22
- export * from "./ts-compiler/sd-ts-compiler";
23
- export * from "./ts-compiler/sd-ts-dependency-analyzer";
24
- export * from "./types/build-plugin.types";
25
- export * from "./types/build-runner.types";
26
- export * from "./types/build.types";
27
- export * from "./types/common-configs.types";
28
- export * from "./types/config.types";
29
- export * from "./types/ts-compiler.types";
30
- export * from "./types/worker.types";
31
- export * from "./utils/sd-cli-convert-message.utils";
32
- export * from "./utils/sd-cli-performance-time";
33
- import "./workers/build-runner.worker";
34
- import "./workers/server.worker";
35
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,uDAAuD,CAAC;AACtE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,6CAA6C,CAAC;AAC5D,cAAc,qCAAqC,CAAC;AACpD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,qDAAqD,CAAC;AACpE,cAAc,gDAAgD,CAAC;AAC/D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,sCAAsC,CAAC;AACrD,cAAc,sCAAsC,CAAC;AACrD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,yCAAyC,CAAC;AACxD,cAAc,gDAAgD,CAAC;AAC/D,OAAO,UAAU,CAAC;AAClB,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yCAAyC,CAAC;AACxD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sCAAsC,CAAC;AACrD,cAAc,iCAAiC,CAAC;AAChD,OAAO,+BAA+B,CAAC;AACvC,OAAO,yBAAyB,CAAC"}
@@ -1,10 +0,0 @@
1
- import * as ts from "typescript";
2
- import { TNormPath } from "@simplysm/sd-core-node";
3
- import { ISdBuildMessage } from "../types/build.types";
4
- export declare class SdTsDependencyAnalyzer {
5
- static analyze(program: ts.Program, compilerHost: ts.CompilerHost, scopePaths: TNormPath[]): {
6
- allDepMap: Map<TNormPath, Set<TNormPath>>;
7
- sourceFileSet: Set<ts.SourceFile>;
8
- messages: ISdBuildMessage[];
9
- };
10
- }