@simplysm/sd-cli 12.13.13 → 12.13.15

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 (87) hide show
  1. package/dist/entry/sd-cli-electron.js +1 -1
  2. package/dist/entry/sd-cli-electron.js.map +1 -1
  3. package/dist/entry/sd-cli-project.d.ts +2 -0
  4. package/dist/entry/sd-cli-project.js +11 -3
  5. package/dist/entry/sd-cli-project.js.map +1 -1
  6. package/dist/pkg-builders/client/sd-client.build-runner.d.ts +1 -1
  7. package/dist/pkg-builders/client/sd-client.build-runner.js +74 -50
  8. package/dist/pkg-builders/client/sd-client.build-runner.js.map +1 -1
  9. package/dist/pkg-builders/client/sd-ng.bundler.d.ts +2 -0
  10. package/dist/pkg-builders/client/sd-ng.bundler.js +19 -20
  11. package/dist/pkg-builders/client/sd-ng.bundler.js.map +1 -1
  12. package/dist/pkg-builders/client/sd-ng.plugin-creator.d.ts +2 -0
  13. package/dist/pkg-builders/client/sd-ng.plugin-creator.js +94 -33
  14. package/dist/pkg-builders/client/sd-ng.plugin-creator.js.map +1 -1
  15. package/dist/pkg-builders/commons/build-runner.base.d.ts +4 -2
  16. package/dist/pkg-builders/commons/build-runner.base.js +45 -25
  17. package/dist/pkg-builders/commons/build-runner.base.js.map +1 -1
  18. package/dist/pkg-builders/lib/sd-js-lib.build-runner.d.ts +1 -1
  19. package/dist/pkg-builders/lib/sd-js-lib.build-runner.js +14 -4
  20. package/dist/pkg-builders/lib/sd-js-lib.build-runner.js.map +1 -1
  21. package/dist/pkg-builders/lib/sd-ts-lib.build-runner.d.ts +1 -1
  22. package/dist/pkg-builders/lib/sd-ts-lib.build-runner.js +21 -40
  23. package/dist/pkg-builders/lib/sd-ts-lib.build-runner.js.map +1 -1
  24. package/dist/pkg-builders/lib/sd-ts-lib.builder.d.ts +1 -1
  25. package/dist/pkg-builders/lib/sd-ts-lib.builder.js +3 -1
  26. package/dist/pkg-builders/lib/sd-ts-lib.builder.js.map +1 -1
  27. package/dist/pkg-builders/sd-multi.build-runner.js +116 -86
  28. package/dist/pkg-builders/sd-multi.build-runner.js.map +1 -1
  29. package/dist/pkg-builders/server/sd-server.build-runner.d.ts +1 -1
  30. package/dist/pkg-builders/server/sd-server.build-runner.js +9 -5
  31. package/dist/pkg-builders/server/sd-server.build-runner.js.map +1 -1
  32. package/dist/pkg-builders/server/sd-server.bundler.d.ts +2 -0
  33. package/dist/pkg-builders/server/sd-server.bundler.js +3 -1
  34. package/dist/pkg-builders/server/sd-server.bundler.js.map +1 -1
  35. package/dist/pkg-builders/server/sd-server.plugin-creator.d.ts +2 -0
  36. package/dist/pkg-builders/server/sd-server.plugin-creator.js +4 -1
  37. package/dist/pkg-builders/server/sd-server.plugin-creator.js.map +1 -1
  38. package/dist/sd-cli-entry.js +10 -0
  39. package/dist/sd-cli-entry.js.map +1 -1
  40. package/dist/sd-cli.js +8 -6
  41. package/dist/sd-cli.js.map +1 -1
  42. package/dist/ts-compiler/sd-dependency-analyzer.d.ts +8 -1
  43. package/dist/ts-compiler/sd-dependency-analyzer.js +128 -63
  44. package/dist/ts-compiler/sd-dependency-analyzer.js.map +1 -1
  45. package/dist/ts-compiler/sd-dependency-cache.d.ts +0 -34
  46. package/dist/ts-compiler/sd-dependency-cache.js +73 -119
  47. package/dist/ts-compiler/sd-dependency-cache.js.map +1 -1
  48. package/dist/ts-compiler/sd-style-bundler.d.ts +16 -0
  49. package/dist/ts-compiler/sd-style-bundler.js +118 -0
  50. package/dist/ts-compiler/sd-style-bundler.js.map +1 -0
  51. package/dist/ts-compiler/sd-ts-compiler.js +418 -235
  52. package/dist/ts-compiler/sd-ts-compiler.js.map +1 -1
  53. package/dist/types/build-runner.types.d.ts +2 -0
  54. package/dist/types/config.types.d.ts +2 -0
  55. package/dist/types/ts-compiler.types.d.ts +2 -0
  56. package/dist/types/worker.types.d.ts +1 -1
  57. package/dist/workers/build-runner.worker.js +1 -1
  58. package/dist/workers/build-runner.worker.js.map +1 -1
  59. package/dist/workers/server.worker.js +2 -2
  60. package/dist/workers/server.worker.js.map +1 -1
  61. package/package.json +13 -12
  62. package/src/entry/sd-cli-electron.ts +2 -1
  63. package/src/entry/sd-cli-project.ts +13 -3
  64. package/src/pkg-builders/client/sd-client.build-runner.ts +93 -54
  65. package/src/pkg-builders/client/sd-ng.bundler.ts +79 -85
  66. package/src/pkg-builders/client/sd-ng.plugin-creator.ts +119 -39
  67. package/src/pkg-builders/commons/build-runner.base.ts +78 -33
  68. package/src/pkg-builders/lib/sd-js-lib.build-runner.ts +24 -7
  69. package/src/pkg-builders/lib/sd-ts-lib.build-runner.ts +36 -42
  70. package/src/pkg-builders/lib/sd-ts-lib.builder.ts +4 -0
  71. package/src/pkg-builders/sd-multi.build-runner.ts +137 -108
  72. package/src/pkg-builders/server/sd-server.build-runner.ts +10 -4
  73. package/src/pkg-builders/server/sd-server.bundler.ts +5 -1
  74. package/src/pkg-builders/server/sd-server.plugin-creator.ts +10 -5
  75. package/src/sd-cli-entry.ts +10 -0
  76. package/src/sd-cli.ts +8 -6
  77. package/src/ts-compiler/sd-dependency-analyzer.ts +161 -86
  78. package/src/ts-compiler/sd-dependency-cache.ts +118 -99
  79. package/src/ts-compiler/sd-style-bundler.ts +150 -0
  80. package/src/ts-compiler/sd-ts-compiler.ts +559 -296
  81. package/src/types/build-runner.types.ts +2 -0
  82. package/src/types/config.types.ts +3 -0
  83. package/src/types/ts-compiler.types.ts +15 -11
  84. package/src/types/worker.types.ts +7 -10
  85. package/src/workers/build-runner.worker.ts +9 -5
  86. package/src/workers/server.worker.ts +2 -2
  87. package/tests/deps/sd-dependency-cache.spec.ts +1 -1
@@ -4,14 +4,14 @@ export class SdDependencyCache {
4
4
  /**
5
5
  * 각 파일이 export한 심볼 집합 (예: export const A → "A")
6
6
  */
7
- private _exportCache = new Map<TNormPath, Set<string>>();
7
+ #exportCache = new Map<TNormPath, Set<string>>();
8
8
 
9
9
  /**
10
10
  * import한 타겟과 그 심볼 정보
11
11
  * - 값이 0이면 전체 import(import * 또는 리소스 import)
12
12
  * - 값이 Set이면 선택적 심볼 import (예: import { A } ...)
13
13
  */
14
- private _importCache = new Map<TNormPath, Map<TNormPath, Set<string> | 0>>();
14
+ #importCache = new Map<TNormPath, Map<TNormPath, Set<string> | 0>>();
15
15
 
16
16
  /**
17
17
  * re-export한 타겟과 그 심볼 정보
@@ -19,7 +19,7 @@ export class SdDependencyCache {
19
19
  * - export { A as B } from ...
20
20
  * - 값이 0이면 전체 reexport(export * from ...)
21
21
  */
22
- private _reexportCache = new Map<
22
+ #reexportCache = new Map<
23
23
  TNormPath,
24
24
  Map<
25
25
  TNormPath,
@@ -36,14 +36,14 @@ export class SdDependencyCache {
36
36
  * - 특정 파일이 어떤 파일에게 의존(참조)되는지
37
37
  * - symbol 기반 추적
38
38
  */
39
- private _revDepCache = new Map<TNormPath, Map<TNormPath, Set<string> | 0>>();
39
+ #revDepCache = new Map<TNormPath, Map<TNormPath, Set<string> | 0>>();
40
40
 
41
41
  /**
42
42
  * 분석이 완료된 파일 경로
43
43
  */
44
- private _collectedCache = new Set<TNormPath>();
44
+ #collectedCache = new Set<TNormPath>();
45
45
 
46
- private _exportSymbolCache = new Map<TNormPath, Set<string>>();
46
+ #exportSymbolCache = new Map<TNormPath, Set<string>>();
47
47
 
48
48
  /**
49
49
  * .d.ts 또는 .js가 입력되었을 때 쌍으로 존재하는 파일 경로를 반환
@@ -62,21 +62,21 @@ export class SdDependencyCache {
62
62
  /**
63
63
  * 전체 추적된 파일 경로를 반환
64
64
  */
65
- getFiles(): Set<TNormPath> {
66
- return new Set<TNormPath>([...this._collectedCache.keys(), ...this._revDepCache.keys()]);
67
- }
65
+ // getFiles(): Set<TNormPath> {
66
+ // return new Set<TNormPath>([...this.#collectedCache.keys(), ...this.revDepCache.keys()]);
67
+ // }
68
68
 
69
69
  /**
70
70
  * 분석이 완료된 파일로 표시
71
71
  */
72
72
  addCollected(fileNPath: TNormPath) {
73
73
  for (const path of this.#getRelatedNPaths(fileNPath)) {
74
- this._collectedCache.add(path);
74
+ this.#collectedCache.add(path);
75
75
  }
76
76
  }
77
77
 
78
78
  hasCollected(fileNPath: TNormPath) {
79
- return this._collectedCache.has(fileNPath);
79
+ return this.#collectedCache.has(fileNPath);
80
80
  }
81
81
 
82
82
  /**
@@ -85,7 +85,7 @@ export class SdDependencyCache {
85
85
  */
86
86
  addExport(fileNPath: TNormPath, exportSymbol: string) {
87
87
  for (const path of this.#getRelatedNPaths(fileNPath)) {
88
- const exportSymbolSet = this._exportCache.getOrCreate(path, new Set());
88
+ const exportSymbolSet = this.#exportCache.getOrCreate(path, new Set());
89
89
  exportSymbolSet.add(exportSymbol);
90
90
  }
91
91
  }
@@ -97,18 +97,18 @@ export class SdDependencyCache {
97
97
  */
98
98
  addImport(fileNPath: TNormPath, targetNPath: TNormPath, targetSymbol: string | 0) {
99
99
  for (const filePath of this.#getRelatedNPaths(fileNPath)) {
100
- for (const targetPath of this.#getRelatedNPaths(targetNPath)) {
101
- const importTargetMap = this._importCache.getOrCreate(filePath, new Map());
100
+ const importTargetMap = this.#importCache.getOrCreate(filePath, new Map());
102
101
 
103
- if (targetSymbol === 0) {
104
- importTargetMap.set(targetPath, 0);
105
- this.#addRevDep(targetPath, filePath, 0);
106
- } else {
102
+ for (const targetPath of this.#getRelatedNPaths(targetNPath)) {
103
+ if (typeof targetSymbol === "string") {
107
104
  const importTargetSymbolSet = importTargetMap.getOrCreate(targetPath, new Set());
108
- if (importTargetSymbolSet === 0) return;
105
+ if (!(importTargetSymbolSet instanceof Set)) continue;
109
106
 
110
107
  importTargetSymbolSet.add(targetSymbol);
111
108
  this.#addRevDep(targetPath, filePath, targetSymbol);
109
+ } else {
110
+ importTargetMap.set(targetPath, targetSymbol);
111
+ this.#addRevDep(targetPath, filePath, targetSymbol);
112
112
  }
113
113
  }
114
114
  }
@@ -129,9 +129,9 @@ export class SdDependencyCache {
129
129
  | 0,
130
130
  ) {
131
131
  for (const filePath of this.#getRelatedNPaths(fileNPath)) {
132
- for (const targetPath of this.#getRelatedNPaths(targetNPath)) {
133
- const reexportTargetMap = this._reexportCache.getOrCreate(filePath, new Map());
132
+ const reexportTargetMap = this.#reexportCache.getOrCreate(filePath, new Map());
134
133
 
134
+ for (const targetPath of this.#getRelatedNPaths(targetNPath)) {
135
135
  if (targetSymbolInfo === 0) {
136
136
  reexportTargetMap.set(targetPath, 0);
137
137
  this.#addRevDep(targetPath, filePath, 0);
@@ -159,15 +159,16 @@ export class SdDependencyCache {
159
159
  */
160
160
  #addRevDep(targetNPath: TNormPath, fileNPath: TNormPath, exportSymbol: string | 0) {
161
161
  for (const targetPath of this.#getRelatedNPaths(targetNPath)) {
162
+ const revDepInfoMap = this.#revDepCache.getOrCreate(targetPath, new Map());
163
+
162
164
  for (const filePath of this.#getRelatedNPaths(fileNPath)) {
163
- const revDepInfoMap = this._revDepCache.getOrCreate(targetPath, new Map());
164
- if (exportSymbol === 0) {
165
- revDepInfoMap.set(filePath, 0);
166
- } else {
165
+ if (typeof exportSymbol === "string") {
167
166
  const exportSymbolSet = revDepInfoMap.getOrCreate(filePath, new Set());
168
- if (exportSymbolSet === 0) return;
167
+ if (!(exportSymbolSet instanceof Set)) continue;
169
168
 
170
169
  exportSymbolSet.add(exportSymbol);
170
+ } else {
171
+ revDepInfoMap.set(filePath, exportSymbol);
171
172
  }
172
173
  }
173
174
  }
@@ -229,6 +230,7 @@ export class SdDependencyCache {
229
230
 
230
231
  return result;
231
232
  }*/
233
+
232
234
  getAffectedFileMap(modifiedNPathSet: Set<TNormPath>): Map<TNormPath, Set<TNormPath>> {
233
235
  const resultMap = new Map<TNormPath, Set<TNormPath>>();
234
236
 
@@ -259,7 +261,7 @@ export class SdDependencyCache {
259
261
 
260
262
  while (queue.length > 0) {
261
263
  const curr = queue.shift()!;
262
- const revDepInfoMap = this._revDepCache.get(curr.fileNPath);
264
+ const revDepInfoMap = this.#revDepCache.get(curr.fileNPath);
263
265
  if (!revDepInfoMap) continue;
264
266
 
265
267
  for (const [revDepFileNPath, revDepInfo] of revDepInfoMap) {
@@ -292,21 +294,30 @@ export class SdDependencyCache {
292
294
  invalidates(fileNPathSet: Set<TNormPath>) {
293
295
  // const affectedFileMap = this.getAffectedFileMap(fileNPathSet);
294
296
 
297
+ const revDepCacheChanged = new Set<TNormPath>();
298
+
295
299
  for (const fileNPath of fileNPathSet) {
296
- this._exportCache.delete(fileNPath);
297
- this._importCache.delete(fileNPath);
298
- this._reexportCache.delete(fileNPath);
299
- this._collectedCache.delete(fileNPath);
300
- this._revDepCache.delete(fileNPath); // 자신이 key인 경우
301
- this._exportSymbolCache.delete(fileNPath);
300
+ this.#exportCache.delete(fileNPath);
301
+ this.#importCache.delete(fileNPath);
302
+ this.#reexportCache.delete(fileNPath);
303
+ this.#exportSymbolCache.delete(fileNPath);
304
+ this.#collectedCache.delete(fileNPath);
305
+
306
+ if (this.#revDepCache.has(fileNPath)) {
307
+ this.#revDepCache.delete(fileNPath); // 자신이 key인 경우
308
+ revDepCacheChanged.add(fileNPath);
309
+ }
302
310
  }
303
311
 
304
- for (const [targetNPath, infoMap] of this._revDepCache) {
312
+ for (const [targetNPath, infoMap] of this.#revDepCache) {
305
313
  for (const fileNPath of fileNPathSet) {
306
- infoMap.delete(fileNPath);
314
+ if (infoMap.has(fileNPath)) {
315
+ infoMap.delete(fileNPath);
316
+ revDepCacheChanged.add(targetNPath);
317
+ }
307
318
  }
308
319
  if (infoMap.size === 0) {
309
- this._revDepCache.delete(targetNPath);
320
+ this.#revDepCache.delete(targetNPath);
310
321
  }
311
322
  }
312
323
  }
@@ -314,8 +325,12 @@ export class SdDependencyCache {
314
325
  /**
315
326
  * reexport된 경우 importSymbol → exportSymbol로 변환
316
327
  */
317
- #convertImportSymbolToExportSymbol(fileNPath: TNormPath, targetNPath: TNormPath, importSymbol: string) {
318
- const symbolInfos = this._reexportCache.get(fileNPath)?.get(targetNPath);
328
+ #convertImportSymbolToExportSymbol(
329
+ fileNPath: TNormPath,
330
+ targetNPath: TNormPath,
331
+ importSymbol: string,
332
+ ) {
333
+ const symbolInfos = this.#reexportCache.get(fileNPath)?.get(targetNPath);
319
334
  if (symbolInfos != null && symbolInfos !== 0 && symbolInfos.length > 0) {
320
335
  const symbolInfo = symbolInfos.single((item) => item.importSymbol === importSymbol);
321
336
  if (symbolInfo) return symbolInfo.exportSymbol;
@@ -327,17 +342,17 @@ export class SdDependencyCache {
327
342
  * 해당 파일에서 export된 모든 심볼 (직접 + 재export 포함)
328
343
  */
329
344
  #getExportSymbols(fileNPath: TNormPath): Set<string> {
330
- if (this._exportSymbolCache.has(fileNPath)) {
331
- return this._exportSymbolCache.get(fileNPath)!;
345
+ if (this.#exportSymbolCache.has(fileNPath)) {
346
+ return this.#exportSymbolCache.get(fileNPath)!;
332
347
  }
333
348
 
334
349
  const result = new Set<string>();
335
350
 
336
351
  for (const path of this.#getRelatedNPaths(fileNPath)) {
337
- const set = this._exportCache.get(path);
352
+ const set = this.#exportCache.get(path);
338
353
  if (set) result.adds(...set);
339
354
 
340
- const map = this._reexportCache.get(path);
355
+ const map = this.#reexportCache.get(path);
341
356
  if (map) {
342
357
  for (const [key, val] of map) {
343
358
  if (val === 0) {
@@ -349,7 +364,7 @@ export class SdDependencyCache {
349
364
  }
350
365
  }
351
366
 
352
- this._exportSymbolCache.set(fileNPath, result);
367
+ this.#exportSymbolCache.set(fileNPath, result);
353
368
  return result;
354
369
  }
355
370
 
@@ -357,62 +372,66 @@ export class SdDependencyCache {
357
372
  * 변경된 파일로부터 영향을 받는 전체 트리를 반환
358
373
  * - 의존 관계를 시각화 및 구조적으로 추적할 수 있도록 트리 형태로 구성
359
374
  */
360
- getAffectedFileTree(modifiedNPathSet: Set<TNormPath>): ISdAffectedFileTreeNode[] {
361
- const visited = new Set<string>();
362
- const nodeMap = new Map<string, ISdAffectedFileTreeNode>();
363
-
364
- const buildTree = (fileNPath: TNormPath, exportSymbol: string | undefined): ISdAffectedFileTreeNode => {
365
- const key = `${fileNPath}#${exportSymbol ?? "*"}`;
366
- if (nodeMap.has(key)) return nodeMap.get(key)!;
367
-
368
- visited.add(key);
369
-
370
- const node: ISdAffectedFileTreeNode = {
371
- fileNPath,
372
- children: [],
373
- };
374
- nodeMap.set(key, node);
375
-
376
- const revDepInfoMap = this._revDepCache.get(fileNPath);
377
- if (!revDepInfoMap) return node;
378
-
379
- for (const [revDepFileNPath, revDepInfo] of revDepInfoMap.entries()) {
380
- const hasImportSymbol = exportSymbol == null || revDepInfo === 0 || revDepInfo.has(exportSymbol);
381
- if (!hasImportSymbol) continue;
382
-
383
- const nextExportSymbol =
384
- exportSymbol != null
385
- ? this.#convertImportSymbolToExportSymbol(revDepFileNPath, fileNPath, exportSymbol)
386
- : undefined;
387
-
388
- const childKey = `${revDepFileNPath}#${nextExportSymbol ?? "*"}`;
389
- if (visited.has(childKey)) continue;
390
-
391
- const childNode = buildTree(revDepFileNPath, nextExportSymbol);
392
- node.children.push(childNode);
393
- }
394
-
395
- return node;
396
- };
397
-
398
- const result: ISdAffectedFileTreeNode[] = [];
399
-
400
- for (const modifiedNPath of modifiedNPathSet) {
401
- for (const path of this.#getRelatedNPaths(modifiedNPath)) {
402
- result.push(buildTree(path, undefined)); // root는 symbol상관없이
403
- /*const exportSymbols = this.#getExportSymbols(path);
404
- if (exportSymbols.size === 0) {
405
- result.push(buildTree(path, undefined));
406
- } else {
407
- for (const symbol of exportSymbols) {
408
- result.push(buildTree(path, symbol));
409
- }
410
- }*/
411
- }
412
- }
413
-
414
- return result;
415
- }
375
+ // getAffectedFileTree(modifiedNPathSet: Set<TNormPath>): ISdAffectedFileTreeNode[] {
376
+ // const visited = new Set<string>();
377
+ // const nodeMap = new Map<string, ISdAffectedFileTreeNode>();
378
+ //
379
+ // const buildTree = (
380
+ // fileNPath: TNormPath,
381
+ // exportSymbol: string | undefined,
382
+ // ): ISdAffectedFileTreeNode => {
383
+ // const key = `${fileNPath}#${exportSymbol ?? "*"}`;
384
+ // if (nodeMap.has(key)) return nodeMap.get(key)!;
385
+ //
386
+ // visited.add(key);
387
+ //
388
+ // const node: ISdAffectedFileTreeNode = {
389
+ // fileNPath,
390
+ // children: [],
391
+ // };
392
+ // nodeMap.set(key, node);
393
+ //
394
+ // const revDepInfoMap = this.revDepCache.get(fileNPath);
395
+ // if (!revDepInfoMap) return node;
396
+ //
397
+ // for (const [revDepFileNPath, revDepInfo] of revDepInfoMap.entries()) {
398
+ // const hasImportSymbol =
399
+ // exportSymbol == null || revDepInfo === 0 || revDepInfo.has(exportSymbol);
400
+ // if (!hasImportSymbol) continue;
401
+ //
402
+ // const nextExportSymbol =
403
+ // exportSymbol != null
404
+ // ? this.#convertImportSymbolToExportSymbol(revDepFileNPath, fileNPath, exportSymbol)
405
+ // : undefined;
406
+ //
407
+ // const childKey = `${revDepFileNPath}#${nextExportSymbol ?? "*"}`;
408
+ // if (visited.has(childKey)) continue;
409
+ //
410
+ // const childNode = buildTree(revDepFileNPath, nextExportSymbol);
411
+ // node.children.push(childNode);
412
+ // }
413
+ //
414
+ // return node;
415
+ // };
416
+ //
417
+ // const result: ISdAffectedFileTreeNode[] = [];
418
+ //
419
+ // for (const modifiedNPath of modifiedNPathSet) {
420
+ // for (const path of this.#getRelatedNPaths(modifiedNPath)) {
421
+ // result.push(buildTree(path, undefined)); // root는 symbol상관없이
422
+ // /*const exportSymbols = this.#getExportSymbols(path);
423
+ // if (exportSymbols.size === 0) {
424
+ // result.push(buildTree(path, undefined));
425
+ // } else {
426
+ // for (const symbol of exportSymbols) {
427
+ // result.push(buildTree(path, symbol));
428
+ // }
429
+ // }*/
430
+ // }
431
+ // }
432
+ //
433
+ // return result;
434
+ // }
416
435
  }
417
436
 
418
437
  export interface ISdAffectedFileTreeNode {
@@ -0,0 +1,150 @@
1
+ import { PathUtils, TNormPath } from "@simplysm/sd-core-node";
2
+ import { TStylesheetBundlingResult } from "../types/ts-compiler.types";
3
+ import { ComponentStylesheetBundler } from "@angular/build/src/tools/esbuild/angular/component-stylesheets";
4
+ import { transformSupportedBrowsersToTargets } from "@angular/build/src/tools/esbuild/utils";
5
+ import browserslist from "browserslist";
6
+ import { ScopePathSet } from "../pkg-builders/commons/scope-path";
7
+
8
+ export class SdStyleBundler {
9
+ #ngStyleBundler: ComponentStylesheetBundler;
10
+ #resultCache = new Map<TNormPath, TStylesheetBundlingResult>();
11
+ #refCache = new Map<TNormPath, Set<TNormPath>>();
12
+ #revRefCache = new Map<TNormPath, Set<TNormPath>>();
13
+
14
+ constructor(
15
+ private readonly _pkgPath: TNormPath,
16
+ private readonly _isDevMode: boolean,
17
+ private readonly _watchScopePathSet: ScopePathSet,
18
+ ) {
19
+ this.#ngStyleBundler = new ComponentStylesheetBundler(
20
+ {
21
+ workspaceRoot: this._pkgPath,
22
+ optimization: !this._isDevMode,
23
+ inlineFonts: true,
24
+ preserveSymlinks: false,
25
+ sourcemap: this._isDevMode ? "inline" : false,
26
+ outputNames: { bundles: "[name]", media: "media/[name]" },
27
+ includePaths: [],
28
+ externalDependencies: [],
29
+ target: transformSupportedBrowsersToTargets(browserslist(["Chrome > 78"])),
30
+ tailwindConfiguration: undefined,
31
+ cacheOptions: {
32
+ enabled: true,
33
+ path: ".cache/angular",
34
+ basePath: ".cache",
35
+ },
36
+ },
37
+ "scss",
38
+ this._isDevMode,
39
+ );
40
+ }
41
+
42
+ getResultCache() {
43
+ return this.#resultCache;
44
+ }
45
+
46
+ async bundleAsync(
47
+ data: string,
48
+ containingFile: TNormPath,
49
+ resourceFile: TNormPath | null = null,
50
+ ): Promise<TStylesheetBundlingResult & { cached: boolean }> {
51
+ // containingFile: 포함된 파일 (.ts 혹은 global style.scss)
52
+ // resourceFile: 외부 리소스 파일 (styleUrls로 입력하지 않고 styles에 직접 입력한 경우 null)
53
+ // referencedFiles: import한 외부 scss 파일 혹은 woff파일등 외부 파일
54
+
55
+ const fileNPath = PathUtils.norm(resourceFile ?? containingFile);
56
+ if (this.#resultCache.has(fileNPath)) {
57
+ return {
58
+ ...this.#resultCache.get(fileNPath)!,
59
+ cached: true,
60
+ };
61
+ }
62
+
63
+ try {
64
+ const result =
65
+ resourceFile != null
66
+ ? await this.#ngStyleBundler.bundleFile(resourceFile)
67
+ : await this.#ngStyleBundler.bundleInline(data, containingFile, "scss");
68
+
69
+ for (const referencedFile of result.referencedFiles ?? []) {
70
+ if (
71
+ !this._watchScopePathSet.inScope(fileNPath) ||
72
+ !this._watchScopePathSet.inScope(PathUtils.norm(referencedFile))
73
+ )
74
+ continue;
75
+
76
+ // 참조하는 파일과 참조된 파일 사이의 의존성 관계 추가
77
+ this.#addReference(fileNPath, PathUtils.norm(referencedFile));
78
+ }
79
+
80
+ this.#resultCache.set(fileNPath, result);
81
+
82
+ return { ...result, cached: false };
83
+ } catch (err) {
84
+ const result = {
85
+ errors: [
86
+ {
87
+ text: `스타일 번들링 실패: ${err.message ?? "알 수 없는 오류"}`,
88
+ location: { file: containingFile },
89
+ },
90
+ ],
91
+ warnings: [],
92
+ };
93
+ this.#resultCache.set(fileNPath, result);
94
+ return { ...result, cached: false };
95
+ }
96
+ }
97
+
98
+ invalidate(modifiedNPathSet: Set<TNormPath>) {
99
+ const affectedFileSet = this.getAffectedFileSet(modifiedNPathSet);
100
+
101
+ this.#ngStyleBundler.invalidate(affectedFileSet);
102
+ for (const fileNPath of affectedFileSet) {
103
+ this.#resultCache.delete(fileNPath);
104
+ }
105
+
106
+ // revRefCache/refCache
107
+ const targetSet = new Set<TNormPath>();
108
+ for (const fileNPath of affectedFileSet) {
109
+ targetSet.adds(...(this.#refCache.get(fileNPath) ?? []));
110
+ }
111
+
112
+ for (const target of [...targetSet]) {
113
+ const source = this.#revRefCache.get(target);
114
+ if (source == null) continue;
115
+
116
+ for (const affectedFile of affectedFileSet) {
117
+ source.delete(affectedFile);
118
+ }
119
+ if (source.size === 0) {
120
+ this.#revRefCache.delete(target);
121
+ }
122
+
123
+ this.#refCache.delete(target);
124
+ }
125
+
126
+ return affectedFileSet;
127
+ }
128
+
129
+ #addReference(fileNPath: TNormPath, referencedFile: TNormPath) {
130
+ this.#refCache.getOrCreate(fileNPath, new Set()).add(referencedFile);
131
+ this.#revRefCache.getOrCreate(referencedFile, new Set()).add(fileNPath);
132
+ }
133
+
134
+ getAffectedFileSet(modifiedNPathSet: Set<TNormPath>) {
135
+ const affectedFileSet = new Set<TNormPath>();
136
+ // 수정파일중 Result에 있는것
137
+ const modifiedResultFiles = Array.from(modifiedNPathSet)
138
+ // .filter((item) => item.endsWith(".scss"))
139
+ .filter((item) => this.#resultCache.has(item));
140
+ affectedFileSet.adds(...modifiedResultFiles);
141
+
142
+ // 수정파일을 사용하는 파일
143
+ const modifiedScssFiles = Array.from(modifiedNPathSet).filter((item) => item.endsWith(".scss"));
144
+ for (const modifiedScss of modifiedScssFiles) {
145
+ affectedFileSet.adds(...(this.#revRefCache.get(modifiedScss) ?? []));
146
+ }
147
+
148
+ return affectedFileSet;
149
+ }
150
+ }