@simplysm/sd-cli 12.5.18 → 12.5.20

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 (62) hide show
  1. package/dist/build-tools/SdNgBundler.d.ts +1 -0
  2. package/dist/build-tools/SdNgBundler.js +70 -57
  3. package/dist/build-tools/SdNgBundler.js.map +1 -1
  4. package/dist/build-tools/SdServerBundler.d.ts +1 -0
  5. package/dist/build-tools/SdServerBundler.js +8 -7
  6. package/dist/build-tools/SdServerBundler.js.map +1 -1
  7. package/dist/build-tools/SdTsCompiler.d.ts +1 -0
  8. package/dist/build-tools/SdTsCompiler.js +355 -328
  9. package/dist/build-tools/SdTsCompiler.js.map +1 -1
  10. package/dist/build-tools/SdTsLibBundler.d.ts +1 -1
  11. package/dist/build-tools/SdTsLibBundler.js +2 -1
  12. package/dist/build-tools/SdTsLibBundler.js.map +1 -1
  13. package/dist/builders/SdCliClientBuilder.js +19 -42
  14. package/dist/builders/SdCliClientBuilder.js.map +1 -1
  15. package/dist/builders/SdCliServerBuilder.js +2 -1
  16. package/dist/builders/SdCliServerBuilder.js.map +1 -1
  17. package/dist/builders/SdCliTsLibBuilder.js +4 -2
  18. package/dist/builders/SdCliTsLibBuilder.js.map +1 -1
  19. package/dist/bundle-plugins/sdNgPlugin.d.ts +1 -0
  20. package/dist/bundle-plugins/sdNgPlugin.js +38 -23
  21. package/dist/bundle-plugins/sdNgPlugin.js.map +1 -1
  22. package/dist/bundle-plugins/sdServerPlugin.d.ts +1 -0
  23. package/dist/bundle-plugins/sdServerPlugin.js +1 -0
  24. package/dist/bundle-plugins/sdServerPlugin.js.map +1 -1
  25. package/dist/entry/SdCliProject.js +7 -4
  26. package/dist/entry/SdCliProject.js.map +1 -1
  27. package/dist/index.d.ts +1 -4
  28. package/dist/index.js +1 -4
  29. package/dist/index.js.map +1 -1
  30. package/dist/utils/SdCliPerformanceTime.d.ts +9 -0
  31. package/dist/utils/SdCliPerformanceTime.js +40 -0
  32. package/dist/utils/SdCliPerformanceTime.js.map +1 -0
  33. package/package.json +10 -14
  34. package/src/build-tools/SdNgBundler.ts +82 -68
  35. package/src/build-tools/SdServerBundler.ts +22 -20
  36. package/src/build-tools/SdTsCompiler.ts +341 -358
  37. package/src/build-tools/SdTsLibBundler.ts +2 -1
  38. package/src/builders/SdCliClientBuilder.ts +27 -54
  39. package/src/builders/SdCliServerBuilder.ts +5 -4
  40. package/src/builders/SdCliTsLibBuilder.ts +7 -4
  41. package/src/bundle-plugins/sdNgPlugin.ts +44 -23
  42. package/src/bundle-plugins/sdServerPlugin.ts +2 -0
  43. package/src/entry/SdCliProject.ts +6 -4
  44. package/src/index.ts +1 -4
  45. package/src/utils/SdCliPerformanceTime.ts +42 -0
  46. package/tsconfig.json +1 -1
  47. package/dist/build-tools/SdReactBundler.d.ts +0 -24
  48. package/dist/build-tools/SdReactBundler.js +0 -294
  49. package/dist/build-tools/SdReactBundler.js.map +0 -1
  50. package/dist/build-tools/SdReactBundlerContext.d.ts +0 -14
  51. package/dist/build-tools/SdReactBundlerContext.js +0 -59
  52. package/dist/build-tools/SdReactBundlerContext.js.map +0 -1
  53. package/dist/bundle-plugins/KeysTransformer.d.ts +0 -2
  54. package/dist/bundle-plugins/KeysTransformer.js +0 -61
  55. package/dist/bundle-plugins/KeysTransformer.js.map +0 -1
  56. package/dist/bundle-plugins/sdReactPlugin.d.ts +0 -15
  57. package/dist/bundle-plugins/sdReactPlugin.js +0 -116
  58. package/dist/bundle-plugins/sdReactPlugin.js.map +0 -1
  59. package/src/build-tools/SdReactBundler.ts +0 -370
  60. package/src/build-tools/SdReactBundlerContext.ts +0 -71
  61. package/src/bundle-plugins/KeysTransformer.ts +0 -70
  62. package/src/bundle-plugins/sdReactPlugin.ts +0 -160
@@ -1,16 +1,15 @@
1
- import ts, { CompilerOptions } from "typescript";
1
+ import ts, { CompilerOptions, DiagnosticCategory } from "typescript";
2
2
  import path from "path";
3
3
  import { FsUtil, Logger, PathUtil } from "@simplysm/sd-core-node";
4
4
  import { StringUtil } from "@simplysm/sd-core-common";
5
5
  import esbuild from "esbuild";
6
6
  import { NgtscProgram, OptimizeFor } from "@angular/compiler-cli";
7
- import { createHash } from "crypto";
8
7
  import { ComponentStylesheetBundler } from "@angular/build/src/tools/esbuild/angular/component-stylesheets";
9
8
  import { AngularCompilerHost } from "@angular/build/src/tools/angular/angular-host";
10
9
  import { transformSupportedBrowsersToTargets } from "@angular/build/src/tools/esbuild/utils";
11
10
  import browserslist from "browserslist";
12
- import transformKeys from "@simplysm/ts-transformer-keys/transformer";
13
11
  import { replaceBootstrap } from "@angular/build/src/tools/angular/transformers/jit-bootstrap-transformer";
12
+ import { SdCliPerformanceTimer } from "../utils/SdCliPerformanceTime";
14
13
 
15
14
  export class SdTsCompiler {
16
15
  readonly #logger = Logger.get(["simplysm", "sd-cli", "SdTsCompiler"]);
@@ -18,7 +17,7 @@ export class SdTsCompiler {
18
17
  readonly #parsedTsconfig: ts.ParsedCommandLine;
19
18
  readonly #isForAngular: boolean;
20
19
 
21
- // readonly #revDependencyCacheMap = new Map<string, Set<string>>();
20
+ readonly #revDependencyCacheMap = new Map<string, Set<string>>();
22
21
  readonly #resourceDependencyCacheMap = new Map<string, Set<string>>();
23
22
  readonly #sourceFileCacheMap = new Map<string, ts.SourceFile>();
24
23
  readonly #emittedFilesCacheMap = new Map<
@@ -34,7 +33,6 @@ export class SdTsCompiler {
34
33
 
35
34
  #ngProgram: NgtscProgram | undefined;
36
35
  #program: ts.Program | undefined;
37
- #builder: ts.EmitAndSemanticDiagnosticsBuilderProgram | undefined;
38
36
 
39
37
  readonly #modifiedFileSet = new Set<string>();
40
38
 
@@ -44,6 +42,7 @@ export class SdTsCompiler {
44
42
  readonly #pkgPath: string;
45
43
  readonly #distPath: string;
46
44
  readonly #globalStyleFilePath?: string;
45
+ readonly #watchScopePaths: string[];
47
46
 
48
47
  readonly #isForBundle: boolean;
49
48
 
@@ -52,11 +51,13 @@ export class SdTsCompiler {
52
51
  additionalOptions: CompilerOptions;
53
52
  isForBundle: boolean;
54
53
  isDevMode: boolean;
54
+ watchScopePaths: string[];
55
55
  globalStyleFilePath?: string;
56
56
  }) {
57
57
  this.#pkgPath = opt.pkgPath;
58
58
  this.#globalStyleFilePath = opt.globalStyleFilePath != null ? path.normalize(opt.globalStyleFilePath) : undefined;
59
59
  this.#isForBundle = opt.isForBundle;
60
+ this.#watchScopePaths = opt.watchScopePaths;
60
61
 
61
62
  this.#debug("초기화...");
62
63
 
@@ -197,65 +198,64 @@ export class SdTsCompiler {
197
198
  }
198
199
 
199
200
  invalidate(modifiedFileSet: Set<string>) {
200
- for (const modifiedFile of Array.from(modifiedFileSet).map((item) => path.normalize(item))) {
201
- this.#modifiedFileSet.add(modifiedFile);
202
- this.#modifiedFileSet.adds(...(this.#resourceDependencyCacheMap.get(modifiedFile) ?? []));
203
- }
201
+ this.#modifiedFileSet.adds(...Array.from(modifiedFileSet).map((item) => path.normalize(item)));
204
202
  }
205
203
 
206
204
  async buildAsync(): Promise<ISdTsCompilerResult> {
207
- const affectedSourceFileSet = new Set<ts.SourceFile>();
205
+ let perf = new SdCliPerformanceTimer("esbuild");
206
+
207
+ const affectedFileSet = new Set<string>();
208
208
  const emitFileSet = new Set<string>();
209
209
 
210
210
  this.#debug(`get affected (old deps & old res deps)...`);
211
211
 
212
- for (const modifiedFile of this.#modifiedFileSet) {
213
- // affectedFileSet.add(modifiedFile);
214
- // affectedFileSet.adds(...(this.#revDependencyCacheMap.get(modifiedFile) ?? []));
215
- // affectedFileSet.adds(...(this.#resourceDependencyCacheMap.get(modifiedFile) ?? []));
212
+ perf.run("get affected", () => {
213
+ for (const modifiedFile of this.#modifiedFileSet) {
214
+ affectedFileSet.add(modifiedFile);
215
+ affectedFileSet.adds(...(this.#revDependencyCacheMap.get(modifiedFile) ?? []));
216
+ affectedFileSet.adds(...(this.#resourceDependencyCacheMap.get(modifiedFile) ?? []));
216
217
 
217
- this.#emittedFilesCacheMap.delete(path.normalize(modifiedFile));
218
- this.#sourceFileCacheMap.delete(path.normalize(modifiedFile));
219
- this.#stylesheetBundlingResultMap.delete(path.normalize(modifiedFile));
220
- this.#watchFileSet.delete(path.normalize(modifiedFile));
221
- }
222
- this.#stylesheetBundler?.invalidate(this.#modifiedFileSet);
218
+ this.#emittedFilesCacheMap.delete(path.normalize(modifiedFile));
219
+ }
220
+ });
223
221
 
224
- // this.#debug(`invalidate & clear cache...`);
222
+ this.#debug(`invalidate & clear cache...`);
225
223
 
226
- // this.#stylesheetBundler?.invalidate(affectedFileSet);
224
+ perf.run("invalidate & clear cache", () => {
225
+ this.#stylesheetBundler?.invalidate(this.#modifiedFileSet);
227
226
 
228
- // for (const affectedFile of affectedFileSet) {
229
- // this.#sourceFileCacheMap.delete(path.normalize(affectedFile));
230
- // this.#stylesheetBundlingResultMap.delete(path.normalize(affectedFile));
231
- // this.#watchFileSet.delete(path.normalize(affectedFile));
232
- // }
227
+ for (const affectedFile of affectedFileSet) {
228
+ this.#sourceFileCacheMap.delete(path.normalize(affectedFile));
229
+ this.#stylesheetBundlingResultMap.delete(path.normalize(affectedFile));
230
+ this.#watchFileSet.delete(path.normalize(affectedFile));
231
+ }
233
232
 
234
- // this.#revDependencyCacheMap.clear();
235
- this.#resourceDependencyCacheMap.clear();
233
+ this.#revDependencyCacheMap.clear();
234
+ this.#resourceDependencyCacheMap.clear();
235
+ });
236
236
 
237
237
  this.#debug(`create program...`);
238
238
 
239
- if (this.#isForAngular) {
240
- this.#ngProgram = new NgtscProgram(
241
- this.#parsedTsconfig.fileNames,
242
- this.#parsedTsconfig.options,
243
- this.#compilerHost,
244
- this.#ngProgram,
245
- );
246
- this.#program = this.#ngProgram.getTsProgram();
247
- } else {
248
- this.#program = ts.createProgram(
249
- this.#parsedTsconfig.fileNames,
250
- this.#parsedTsconfig.options,
251
- this.#compilerHost,
252
- this.#program,
253
- );
254
- }
255
-
256
- this.#debug(`create builder...`);
239
+ perf.run("create program", () => {
240
+ if (this.#isForAngular) {
241
+ this.#ngProgram = new NgtscProgram(
242
+ this.#parsedTsconfig.fileNames,
243
+ this.#parsedTsconfig.options,
244
+ this.#compilerHost,
245
+ this.#ngProgram,
246
+ );
247
+ this.#program = this.#ngProgram.getTsProgram();
248
+ } else {
249
+ this.#program = ts.createProgram(
250
+ this.#parsedTsconfig.fileNames,
251
+ this.#parsedTsconfig.options,
252
+ this.#compilerHost,
253
+ this.#program,
254
+ );
255
+ }
256
+ });
257
257
 
258
- const baseGetSourceFiles = this.#program.getSourceFiles;
258
+ /*const baseGetSourceFiles = this.#program.getSourceFiles;
259
259
  this.#program.getSourceFiles = function (...parameters) {
260
260
  const files: readonly (ts.SourceFile & { version?: string })[] = baseGetSourceFiles(...parameters);
261
261
 
@@ -266,12 +266,12 @@ export class SdTsCompiler {
266
266
  }
267
267
 
268
268
  return files;
269
- };
270
-
271
- this.#builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(this.#program, this.#compilerHost, this.#builder);
269
+ };*/
272
270
 
273
271
  if (this.#ngProgram) {
274
- await this.#ngProgram.compiler.analyzeAsync();
272
+ await perf.run("ng analyze", async () => {
273
+ await this.#ngProgram!.compiler.analyzeAsync();
274
+ });
275
275
  }
276
276
 
277
277
  const getOrgSourceFile = (sf: ts.SourceFile) => {
@@ -285,340 +285,281 @@ export class SdTsCompiler {
285
285
 
286
286
  this.#debug(`get affected (new deps)...`);
287
287
 
288
- // const sourceFileSet = new Set(
289
- // this.#program
290
- // .getSourceFiles()
291
- // .map((sf) => getOrgSourceFile(sf))
292
- // .filterExists(),
293
- // );
294
-
295
- // const depMap = new Map<
296
- // string,
297
- // {
298
- // fileName: string;
299
- // importName: string;
300
- // exportName?: string;
301
- // }[]
302
- // >();
303
- // for (const sf of sourceFileSet) {
304
- // const refs = this.#findDeps(sf);
305
- // depMap.set(path.normalize(sf.fileName), refs);
306
- // }
307
- //
308
- // const allDepMap = new Map<string, Set<string>>();
309
- // const getAllDeps = (fileName: string, prevSet?: Set<string>) => {
310
- // if (allDepMap.has(fileName)) {
311
- // return allDepMap.get(fileName)!;
312
- // }
313
- //
314
- // const result = new Set<string>();
315
- //
316
- // const deps = depMap.get(fileName) ?? [];
317
- // result.adds(...deps.map((item) => item.fileName));
318
- //
319
- // for (const dep of deps) {
320
- // const targetDeps = depMap.get(dep.fileName) ?? [];
321
- //
322
- // if (dep.importName === "*") {
323
- // for (const targetRefItem of targetDeps.filter((item) => item.exportName != null)) {
324
- // if (prevSet?.has(targetRefItem.fileName)) continue;
325
- //
326
- // result.add(targetRefItem.fileName);
327
- // result.adds(...getAllDeps(targetRefItem.fileName, new Set<string>(prevSet).adds(...result)));
328
- // }
329
- // } else {
330
- // for (const targetRefItem of targetDeps.filter((item) => item.exportName === dep.importName)) {
331
- // if (prevSet?.has(targetRefItem.fileName)) continue;
332
- //
333
- // result.add(targetRefItem.fileName);
334
- // result.adds(...getAllDeps(targetRefItem.fileName, new Set<string>(prevSet).adds(...result)));
335
- // }
336
- // }
337
- // }
338
- //
339
- // return result;
340
- // };
341
-
342
- // for (const sf of sourceFileSet) {
343
- // const deps = getAllDeps(path.normalize(sf.fileName));
344
- // allDepMap.set(path.normalize(sf.fileName), deps);
345
- //
346
- // for (const dep of getAllDeps(path.normalize(sf.fileName))) {
347
- // const depCache = this.#revDependencyCacheMap.getOrCreate(path.normalize(dep), new Set<string>());
348
- // depCache.add(path.normalize(sf.fileName));
349
- // if (this.#modifiedFileSet.has(path.normalize(dep))) {
350
- // affectedFileSet.add(path.normalize(sf.fileName));
351
- // }
352
- // }
353
- //
354
- // if (this.#ngProgram) {
355
- // if (this.#ngProgram.compiler.ignoreForEmit.has(sf)) {
356
- // continue;
357
- // }
358
- //
359
- // for (const dep of this.#ngProgram.compiler.getResourceDependencies(sf)) {
360
- // const ref = this.#resourceDependencyCacheMap.getOrCreate(path.normalize(dep), new Set<string>());
361
- // ref.add(path.normalize(sf.fileName));
362
- // if (this.#modifiedFileSet.has(path.normalize(dep))) {
363
- // affectedFileSet.add(path.normalize(sf.fileName));
364
- // }
365
- // }
366
- // }
367
- // }
368
-
369
- // if (affectedFileSet.size === 0) {
370
- // this.#debug(`get affected (init)...`);
371
- //
372
- // for (const sf of this.#program.getSourceFiles()) {
373
- // const orgSf = getOrgSourceFile(sf);
374
- // if (!orgSf) continue;
375
- //
376
- // affectedFileSet.add(path.normalize(orgSf.fileName));
377
- // }
378
- // }
288
+ const diagnostics: ts.Diagnostic[] = [];
379
289
 
380
- this.#debug(`get diagnostics...`);
290
+ perf.run("get affected (deps)", () => {
291
+ const sourceFileSet = new Set(
292
+ this.#program!.getSourceFiles()
293
+ .map((sf) => getOrgSourceFile(sf))
294
+ .filterExists(),
295
+ );
381
296
 
382
- const diagnostics: ts.Diagnostic[] = [];
297
+ const depMap = new Map<
298
+ string,
299
+ {
300
+ fileName: string;
301
+ importName: string;
302
+ exportName?: string;
303
+ }[]
304
+ >();
305
+ for (const sf of sourceFileSet) {
306
+ if (!PathUtil.isChildPath(sf.fileName, this.#pkgPath)) {
307
+ continue;
308
+ }
383
309
 
384
- diagnostics.push(
385
- ...this.#builder.getConfigFileParsingDiagnostics(),
386
- ...this.#builder.getOptionsDiagnostics(),
387
- ...this.#builder.getGlobalDiagnostics(),
388
- );
310
+ const refs = this.#findDeps(sf);
311
+ diagnostics.push(...refs.filter((item) => "category" in item));
312
+ depMap.set(
313
+ path.normalize(sf.fileName),
314
+ refs
315
+ .filter((item) => "fileName" in item)
316
+ .filter((item) =>
317
+ this.#watchScopePaths.some((scopePath) => PathUtil.isChildPath(item.fileName, scopePath)),
318
+ ),
319
+ );
320
+ }
389
321
 
390
- /*diagnostics.push(
391
- ...this.#program.getConfigFileParsingDiagnostics(),
392
- ...this.#program.getOptionsDiagnostics(),
393
- ...this.#program.getGlobalDiagnostics(),
394
- );*/
322
+ const allDepMap = new Map<string, Set<string>>();
323
+ const getAllDeps = (fileName: string, prevSet?: Set<string>) => {
324
+ if (allDepMap.has(fileName)) {
325
+ return allDepMap.get(fileName)!;
326
+ }
395
327
 
396
- if (this.#ngProgram) {
397
- diagnostics.push(...this.#ngProgram.compiler.getOptionDiagnostics());
398
- }
328
+ const result = new Set<string>();
399
329
 
400
- this.#debug(`get diagnostics of files...`);
330
+ const deps = depMap.get(fileName) ?? [];
331
+ result.adds(...deps.map((item) => item.fileName));
401
332
 
402
- while (true) {
403
- const affectedFileResult = this.#builder.getSemanticDiagnosticsOfNextAffectedFile(undefined, (sf) => {
404
- if (
405
- this.#ngProgram &&
406
- this.#ngProgram.compiler.ignoreForDiagnostics.has(sf) &&
407
- sf.fileName.endsWith(".ngtypecheck.ts")
408
- ) {
409
- const orgSourceFile = getOrgSourceFile(sf);
410
- if (orgSourceFile) {
411
- affectedSourceFileSet.add(orgSourceFile);
333
+ for (const dep of deps) {
334
+ const targetDeps = depMap.get(dep.fileName) ?? [];
335
+
336
+ if (dep.importName === "*") {
337
+ for (const targetRefItem of targetDeps.filter((item) => item.exportName != null)) {
338
+ if (prevSet?.has(targetRefItem.fileName)) continue;
339
+
340
+ result.add(targetRefItem.fileName);
341
+ result.adds(...getAllDeps(targetRefItem.fileName, new Set<string>(prevSet).adds(...result)));
342
+ }
343
+ } else {
344
+ for (const targetRefItem of targetDeps.filter((item) => item.exportName === dep.importName)) {
345
+ if (prevSet?.has(targetRefItem.fileName)) continue;
346
+
347
+ result.add(targetRefItem.fileName);
348
+ result.adds(...getAllDeps(targetRefItem.fileName, new Set<string>(prevSet).adds(...result)));
349
+ }
412
350
  }
413
- return true;
414
351
  }
415
- return false;
416
- });
417
- if (!affectedFileResult) break;
418
352
 
419
- const affectedSourceFile = affectedFileResult.affected as ts.SourceFile;
353
+ return result;
354
+ };
420
355
 
421
- affectedSourceFileSet.add(affectedSourceFile);
422
- }
356
+ for (const sf of sourceFileSet) {
357
+ const deps = getAllDeps(path.normalize(sf.fileName));
358
+ allDepMap.set(path.normalize(sf.fileName), deps);
423
359
 
424
- for (const affectedSourceFile of affectedSourceFileSet) {
425
- this.#debug(`get diagnostics of file [${affectedSourceFile.fileName}]`);
360
+ for (const dep of getAllDeps(path.normalize(sf.fileName))) {
361
+ const depCache = this.#revDependencyCacheMap.getOrCreate(path.normalize(dep), new Set<string>());
362
+ depCache.add(path.normalize(sf.fileName));
363
+ if (this.#modifiedFileSet.has(path.normalize(dep))) {
364
+ affectedFileSet.add(path.normalize(sf.fileName));
365
+ }
366
+ }
426
367
 
427
- diagnostics.push(
428
- ...this.#program.getSyntacticDiagnostics(affectedSourceFile),
429
- ...this.#program.getSemanticDiagnostics(affectedSourceFile),
430
- );
368
+ if (this.#ngProgram) {
369
+ if (this.#ngProgram.compiler.ignoreForEmit.has(sf)) {
370
+ continue;
371
+ }
431
372
 
432
- if (this.#ngProgram) {
433
- if (affectedSourceFile.isDeclarationFile) {
434
- continue;
373
+ for (const dep of this.#ngProgram.compiler.getResourceDependencies(sf)) {
374
+ const ref = this.#resourceDependencyCacheMap.getOrCreate(path.normalize(dep), new Set<string>());
375
+ ref.add(path.normalize(sf.fileName));
376
+ if (this.#modifiedFileSet.has(path.normalize(dep))) {
377
+ affectedFileSet.add(path.normalize(sf.fileName));
378
+ }
379
+ }
435
380
  }
436
-
437
- diagnostics.push(
438
- ...this.#ngProgram.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram),
439
- );
440
381
  }
441
- }
382
+ });
442
383
 
443
- /*
444
- for (const affectedFile of affectedFileSet) {
445
- if (!PathUtil.isChildPath(affectedFile, this.#pkgPath)) {
446
- continue;
447
- }
384
+ if (affectedFileSet.size === 0) {
385
+ this.#debug(`get affected (init)...`);
448
386
 
449
- this.#debug(`get diagnostics of file [${affectedFile}]`);
387
+ perf.run("get affected (init)", () => {
388
+ for (const sf of this.#program!.getSourceFiles()) {
389
+ if (!this.#watchScopePaths.some((scopePath) => PathUtil.isChildPath(sf.fileName, scopePath))) {
390
+ continue;
391
+ }
450
392
 
451
- const affectedSourceFile = this.#program.getSourceFile(affectedFile);
452
- if (
453
- !affectedSourceFile ||
454
- (this.#ngProgram && this.#ngProgram.compiler.ignoreForDiagnostics.has(affectedSourceFile))
455
- ) {
456
- continue;
457
- }
393
+ const orgSf = getOrgSourceFile(sf);
394
+ if (!orgSf) continue;
458
395
 
396
+ affectedFileSet.add(path.normalize(orgSf.fileName));
397
+ }
398
+ });
399
+ }
400
+
401
+ this.#debug(`get diagnostics...`);
402
+
403
+ perf.run("get program diagnostics", () => {
459
404
  diagnostics.push(
460
- ...this.#program.getSyntacticDiagnostics(affectedSourceFile),
461
- ...this.#program.getSemanticDiagnostics(affectedSourceFile),
405
+ ...this.#program!.getConfigFileParsingDiagnostics(),
406
+ ...this.#program!.getOptionsDiagnostics(),
407
+ ...this.#program!.getGlobalDiagnostics(),
462
408
  );
463
409
 
464
410
  if (this.#ngProgram) {
465
- if (affectedSourceFile.isDeclarationFile) {
466
- continue;
467
- }
468
-
469
- diagnostics.push(
470
- ...this.#ngProgram.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram),
471
- );
411
+ diagnostics.push(...this.#ngProgram.compiler.getOptionDiagnostics());
472
412
  }
473
- }*/
413
+ });
414
+
415
+ this.#debug(`get diagnostics of files...`);
474
416
 
475
- this.#debug(`prepare emit...`);
417
+ perf.run("get file diagnostics", () => {
418
+ for (const affectedFile of affectedFileSet) {
419
+ if (!PathUtil.isChildPath(affectedFile, this.#pkgPath)) {
420
+ continue;
421
+ }
476
422
 
477
- let transformers: ts.CustomTransformers = {};
423
+ const affectedSourceFile = this.#program!.getSourceFile(affectedFile);
478
424
 
479
- if (this.#ngProgram) {
480
- transformers = {
481
- ...transformers,
482
- ...this.#ngProgram.compiler.prepareEmit().transformers,
483
- };
484
- (transformers.before ??= []).push(replaceBootstrap(() => this.#program!.getTypeChecker()));
485
- }
486
- (transformers.before ??= []).push(transformKeys(this.#program));
425
+ if (
426
+ !affectedSourceFile ||
427
+ (this.#ngProgram && this.#ngProgram.compiler.ignoreForDiagnostics.has(affectedSourceFile))
428
+ ) {
429
+ continue;
430
+ }
487
431
 
488
- this.#debug(`prepare emit files...`);
432
+ // this.#debug(`get diagnostics of file ${affectedFile}...`);
489
433
 
490
- while (
491
- this.#builder.emitNextAffectedFile(
492
- (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
493
- if (!sourceFiles || sourceFiles.length === 0) {
494
- this.#compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
495
- return;
496
- }
434
+ diagnostics.push(
435
+ ...this.#program!.getSyntacticDiagnostics(affectedSourceFile),
436
+ ...this.#program!.getSemanticDiagnostics(affectedSourceFile),
437
+ );
497
438
 
498
- const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
499
- if (this.#ngProgram) {
500
- if (this.#ngProgram.compiler.ignoreForEmit.has(sourceFile)) {
439
+ if (this.#ngProgram) {
440
+ perf.run("get file diagnostics: ng", () => {
441
+ if (affectedSourceFile.isDeclarationFile) {
501
442
  return;
502
443
  }
503
- this.#ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
504
- }
505
444
 
506
- const emitFileInfoCaches = this.#emittedFilesCacheMap.getOrCreate(path.normalize(sourceFile.fileName), []);
507
- if (PathUtil.isChildPath(sourceFile.fileName, this.#pkgPath)) {
508
- let realFilePath = fileName;
509
- let realText = text;
510
- if (PathUtil.isChildPath(realFilePath, path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"))) {
511
- realFilePath = path.resolve(
512
- this.#distPath,
513
- path.relative(path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"), realFilePath),
514
- );
515
-
516
- if (fileName.endsWith(".js.map")) {
517
- const sourceMapContents = JSON.parse(realText);
518
- // remove "../../"
519
- sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6);
520
- realText = JSON.stringify(sourceMapContents);
521
- }
522
- }
445
+ diagnostics.push(
446
+ ...this.#ngProgram!.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram),
447
+ );
448
+ });
449
+ }
450
+ }
451
+ });
523
452
 
524
- emitFileInfoCaches.push({
525
- outAbsPath: realFilePath,
526
- text: realText,
527
- });
528
- } else {
529
- emitFileInfoCaches.push({ text });
530
- }
453
+ perf.run("emit", () => {
454
+ this.#debug(`prepare emit...`);
531
455
 
532
- emitFileSet.add(path.normalize(sourceFile.fileName));
533
- },
534
- undefined,
535
- undefined,
536
- transformers,
537
- )
538
- ) {}
539
-
540
- // affected에 새로 추가된 파일은 포함되지 않는 현상이 있어 getSourceFiles로 바꿈
541
- // 비교해보니, 딱히 getSourceFiles라서 더 느려지는것 같지는 않음
542
- /*for (const affectedFile of affectedFileSet) {
543
- if (this.#emittedFilesCacheMap.has(affectedFile)) {
544
- continue;
456
+ let transformers: ts.CustomTransformers = {};
457
+
458
+ if (this.#ngProgram) {
459
+ transformers = {
460
+ ...transformers,
461
+ ...this.#ngProgram.compiler.prepareEmit().transformers,
462
+ };
463
+ (transformers.before ??= []).push(replaceBootstrap(() => this.#program!.getTypeChecker()));
545
464
  }
465
+ // (transformers.before ??= []).push(transformKeys(this.#program));
546
466
 
547
- const sf = this.#program.getSourceFile(affectedFile);
548
- if (!sf) {
549
- continue;
550
- }*/
467
+ this.#debug(`emit for files...`);
551
468
 
552
- /*for (const sf of sourceFileSet) {
553
- if (this.#emittedFilesCacheMap.has(path.normalize(sf.fileName))) {
554
- continue;
555
- }
469
+ // affected에 새로 추가된 파일은 포함되지 않는 현상이 있어 getSourceFiles로 바꿈
470
+ // 비교해보니, 딱히 getSourceFiles라서 더 느려지는것 같지는 않음
471
+ // 그래도 affected로 다시 테스트
472
+ for (const affectedFile of affectedFileSet) {
473
+ if (this.#emittedFilesCacheMap.has(affectedFile)) {
474
+ continue;
475
+ }
556
476
 
557
- if (sf.isDeclarationFile) {
558
- continue;
559
- }
477
+ const sf = this.#program!.getSourceFile(affectedFile);
478
+ if (!sf) {
479
+ continue;
480
+ }
560
481
 
561
- if (this.#ngProgram?.compiler.ignoreForEmit.has(sf)) {
562
- continue;
563
- }
482
+ // for (const sf of sourceFileSet) {
483
+ /*if (this.#emittedFilesCacheMap.has(path.normalize(sf.fileName))) {
484
+ continue;
485
+ }*/
564
486
 
565
- // esbuild를 통해 bundle로 묶어야 하는놈들은 모든 output이 있어야 함.
566
- if (!this.#isForBundle) {
567
- if (!PathUtil.isChildPath(sf.fileName, this.#pkgPath)) {
487
+ if (sf.isDeclarationFile) {
568
488
  continue;
569
489
  }
570
- }
571
490
 
572
- this.#debug(`emit for`, sf.fileName);
573
- this.#program.emit(
574
- sf,
575
- (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
576
- if (!sourceFiles || sourceFiles.length === 0) {
577
- this.#compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
578
- return;
491
+ if (this.#ngProgram?.compiler.ignoreForEmit.has(sf)) {
492
+ continue;
493
+ }
494
+
495
+ if (
496
+ this.#ngProgram?.compiler.incrementalCompilation.safeToSkipEmit(sf) &&
497
+ !affectedFileSet.has(path.normalize(sf.fileName))
498
+ ) {
499
+ continue;
500
+ }
501
+
502
+ // esbuild를 통해 bundle로 묶어야 하는놈들은 모든 output이 있어야 함.
503
+ if (!this.#isForBundle) {
504
+ if (!PathUtil.isChildPath(sf.fileName, this.#pkgPath)) {
505
+ continue;
579
506
  }
507
+ }
580
508
 
581
- const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
582
- if (this.#ngProgram) {
583
- if (this.#ngProgram.compiler.ignoreForEmit.has(sourceFile)) {
509
+ // this.#debug(`emit for`, sf.fileName);
510
+ this.#program!.emit(
511
+ sf,
512
+ (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
513
+ if (!sourceFiles || sourceFiles.length === 0) {
514
+ this.#compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
584
515
  return;
585
516
  }
586
- this.#ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
587
- }
588
517
 
589
- const emitFileInfoCaches = this.#emittedFilesCacheMap.getOrCreate(path.normalize(sourceFile.fileName), []);
590
- if (PathUtil.isChildPath(sourceFile.fileName, this.#pkgPath)) {
591
- let realFilePath = fileName;
592
- let realText = text;
593
- if (PathUtil.isChildPath(realFilePath, path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"))) {
594
- realFilePath = path.resolve(
595
- this.#distPath,
596
- path.relative(path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"), realFilePath),
597
- );
598
-
599
- if (fileName.endsWith(".js.map")) {
600
- const sourceMapContents = JSON.parse(realText);
601
- // remove "../../"
602
- sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6);
603
- realText = JSON.stringify(sourceMapContents);
518
+ const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
519
+ if (this.#ngProgram) {
520
+ if (this.#ngProgram.compiler.ignoreForEmit.has(sourceFile)) {
521
+ return;
604
522
  }
523
+ this.#ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
605
524
  }
606
525
 
607
- emitFileInfoCaches.push({
608
- outAbsPath: realFilePath,
609
- text: realText,
610
- });
611
- } else {
612
- emitFileInfoCaches.push({ text });
613
- }
526
+ const emitFileInfoCaches = this.#emittedFilesCacheMap.getOrCreate(path.normalize(sourceFile.fileName), []);
527
+
528
+ if (PathUtil.isChildPath(sourceFile.fileName, this.#pkgPath)) {
529
+ let realFilePath = fileName;
530
+ let realText = text;
531
+ if (
532
+ PathUtil.isChildPath(realFilePath, path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"))
533
+ ) {
534
+ realFilePath = path.resolve(
535
+ this.#distPath,
536
+ path.relative(path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"), realFilePath),
537
+ );
538
+
539
+ if (fileName.endsWith(".js.map")) {
540
+ const sourceMapContents = JSON.parse(realText);
541
+ // remove "../../"
542
+ sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6);
543
+ realText = JSON.stringify(sourceMapContents);
544
+ }
545
+ }
614
546
 
615
- emitFileSet.add(path.normalize(sourceFile.fileName));
616
- },
617
- undefined,
618
- undefined,
619
- transformers,
620
- );
621
- }*/
547
+ emitFileInfoCaches.push({
548
+ outAbsPath: realFilePath,
549
+ text: realText,
550
+ });
551
+ } else {
552
+ emitFileInfoCaches.push({ text });
553
+ }
554
+
555
+ emitFileSet.add(path.normalize(sourceFile.fileName));
556
+ },
557
+ undefined,
558
+ undefined,
559
+ transformers,
560
+ );
561
+ }
562
+ });
622
563
 
623
564
  //-- global style
624
565
  if (
@@ -628,30 +569,31 @@ export class SdTsCompiler {
628
569
  ) {
629
570
  this.#debug(`bundle global style...`);
630
571
 
631
- const data = await FsUtil.readFileAsync(this.#globalStyleFilePath);
632
- const contents = await this.#bundleStylesheetAsync(data, this.#globalStyleFilePath, this.#globalStyleFilePath);
633
- const emitFileInfos = this.#emittedFilesCacheMap.getOrCreate(this.#globalStyleFilePath, []);
634
- emitFileInfos.push({
635
- outAbsPath: path.resolve(
636
- this.#pkgPath,
637
- path.relative(path.resolve(this.#pkgPath, "src"), this.#globalStyleFilePath).replace(/\.scss$/, ".css"),
638
- ),
639
- text: contents,
572
+ await perf.run("bundle global style", async () => {
573
+ const data = await FsUtil.readFileAsync(this.#globalStyleFilePath!);
574
+ const contents = await this.#bundleStylesheetAsync(data, this.#globalStyleFilePath!, this.#globalStyleFilePath);
575
+ const emitFileInfos = this.#emittedFilesCacheMap.getOrCreate(this.#globalStyleFilePath!, []);
576
+ emitFileInfos.push({
577
+ outAbsPath: path.resolve(
578
+ this.#pkgPath,
579
+ path.relative(path.resolve(this.#pkgPath, "src"), this.#globalStyleFilePath!).replace(/\.scss$/, ".css"),
580
+ ),
581
+ text: contents,
582
+ });
583
+ emitFileSet.add(this.#globalStyleFilePath!);
640
584
  });
641
- emitFileSet.add(this.#globalStyleFilePath);
642
585
  }
643
586
 
644
587
  //-- init
645
588
 
646
589
  this.#modifiedFileSet.clear();
647
590
 
648
- const affectedFileSet = new Set(Array.from(affectedSourceFileSet).map((item) => path.normalize(item.fileName)));
649
- this.#debug(`build completed`, affectedFileSet, diagnostics.length);
591
+ this.#debug(`build completed`, perf.toString());
650
592
 
651
593
  //-- result
652
594
 
653
595
  return {
654
- program: this.#program,
596
+ program: this.#program!,
655
597
  typescriptDiagnostics: diagnostics,
656
598
  stylesheetBundlingResultMap: this.#stylesheetBundlingResultMap,
657
599
  emittedFilesCacheMap: this.#emittedFilesCacheMap,
@@ -665,12 +607,15 @@ export class SdTsCompiler {
665
607
  this.#logger.debug(`[${path.basename(this.#pkgPath)}]`, ...msg);
666
608
  }
667
609
 
668
- /*#findDeps(sf: ts.SourceFile) {
669
- const deps: {
670
- fileName: string;
671
- importName: string;
672
- exportName?: string;
673
- }[] = [];
610
+ #findDeps(sf: ts.SourceFile) {
611
+ const deps: (
612
+ | {
613
+ fileName: string;
614
+ importName: string;
615
+ exportName?: string;
616
+ }
617
+ | ts.Diagnostic
618
+ )[] = [];
674
619
 
675
620
  const tc = this.#program!.getTypeChecker();
676
621
 
@@ -678,10 +623,30 @@ export class SdTsCompiler {
678
623
  if (ts.isExportDeclaration(node)) {
679
624
  if (node.moduleSpecifier) {
680
625
  const moduleSymbol = tc.getSymbolAtLocation(node.moduleSpecifier);
681
- if (!moduleSymbol) throw new NeverEntryError(`export moduleSymbol: ${sf.fileName}`);
626
+ if (!moduleSymbol) {
627
+ deps.push({
628
+ category: DiagnosticCategory.Error,
629
+ code: -1,
630
+ file: sf,
631
+ start: node.getStart(),
632
+ length: node.getEnd() - node.getStart(),
633
+ messageText: `export moduleSymbol not found`,
634
+ });
635
+ return;
636
+ }
682
637
 
683
638
  const decls = moduleSymbol.getDeclarations();
684
- if (!decls) throw new NeverEntryError(`export decls: ${sf.fileName}`);
639
+ if (!decls) {
640
+ deps.push({
641
+ category: DiagnosticCategory.Error,
642
+ code: -1,
643
+ file: sf,
644
+ start: node.getStart(),
645
+ length: node.getEnd() - node.getStart(),
646
+ messageText: `export decls not found`,
647
+ });
648
+ return;
649
+ }
685
650
 
686
651
  const namedBindings = node.exportClause;
687
652
  if (namedBindings && ts.isNamedExports(namedBindings)) {
@@ -696,7 +661,15 @@ export class SdTsCompiler {
696
661
  }
697
662
  } else {
698
663
  if (!moduleSymbol.exports) {
699
- throw new NeverEntryError("1234");
664
+ deps.push({
665
+ category: DiagnosticCategory.Error,
666
+ code: -1,
667
+ file: sf,
668
+ start: node.getStart(),
669
+ length: node.getEnd() - node.getStart(),
670
+ messageText: `moduleSymbol exports not found`,
671
+ });
672
+ return;
700
673
  }
701
674
 
702
675
  for (const decl of decls) {
@@ -719,12 +692,22 @@ export class SdTsCompiler {
719
692
  importName: "*",
720
693
  });
721
694
  }
722
- /!*else {
695
+ /*else {
723
696
  throw new NeverEntryError(`import moduleSymbol: ${sf.fileName} ${node.moduleSpecifier["text"]}`);
724
- }*!/
697
+ }*/
725
698
  } else {
726
699
  const decls = moduleSymbol.getDeclarations();
727
- if (!decls) throw new NeverEntryError(`import decls: ${sf.fileName}`);
700
+ if (!decls) {
701
+ deps.push({
702
+ category: DiagnosticCategory.Error,
703
+ code: -1,
704
+ file: sf,
705
+ start: node.getStart(),
706
+ length: node.getEnd() - node.getStart(),
707
+ messageText: `import decls not found`,
708
+ });
709
+ return;
710
+ }
728
711
 
729
712
  const namedBindings = node.importClause?.namedBindings;
730
713
  if (namedBindings && ts.isNamedImports(namedBindings)) {
@@ -749,7 +732,7 @@ export class SdTsCompiler {
749
732
  });
750
733
 
751
734
  return deps;
752
- }*/
735
+ }
753
736
  }
754
737
 
755
738
  export interface ISdTsCompilerResult {