@simplysm/sd-cli 7.0.248 → 7.0.266

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 (138) hide show
  1. package/README.md +95 -0
  2. package/assets/client-files/assets/icons/icon-128x128.png +0 -0
  3. package/assets/client-files/assets/icons/icon-144x144.png +0 -0
  4. package/assets/client-files/assets/icons/icon-152x152.png +0 -0
  5. package/assets/client-files/assets/icons/icon-192x192.png +0 -0
  6. package/assets/client-files/assets/icons/icon-384x384.png +0 -0
  7. package/assets/client-files/assets/icons/icon-512x512.png +0 -0
  8. package/assets/client-files/assets/icons/icon-72x72.png +0 -0
  9. package/assets/client-files/assets/icons/icon-96x96.png +0 -0
  10. package/assets/client-files/favicon.ico +0 -0
  11. package/dist/bin/sd-cli.mjs +212 -15
  12. package/dist/build-tool/SdCliCordova.mjs +3 -3
  13. package/dist/build-tool/SdCliElectron.mjs +3 -2
  14. package/dist/build-tool/SdCliIndexFileGenerator.mjs +2 -3
  15. package/dist/builder/SdCliClientBuilder.d.ts +2 -0
  16. package/dist/builder/SdCliClientBuilder.mjs +55 -18
  17. package/dist/builder/SdCliServerBuilder.d.ts +2 -0
  18. package/dist/builder/SdCliServerBuilder.mjs +27 -13
  19. package/dist/builder/SdCliTsLibBuilder.mjs +18 -12
  20. package/dist/commons.d.ts +6 -1
  21. package/dist/entry-points/SdCliPrepare.mjs +34 -34
  22. package/dist/entry-points/SdCliProjectGenerator.d.ts +44 -0
  23. package/dist/entry-points/SdCliProjectGenerator.mjs +320 -0
  24. package/dist/entry-points/SdCliWorkspace.d.ts +6 -6
  25. package/dist/entry-points/SdCliWorkspace.mjs +61 -107
  26. package/dist/entry-points/file/base/fc_package_eslintrc.d.ts +3 -0
  27. package/dist/entry-points/file/base/fc_package_eslintrc.mjs +31 -0
  28. package/dist/entry-points/file/base/fc_package_npmconfig.d.ts +9 -0
  29. package/dist/entry-points/file/base/fc_package_npmconfig.mjs +32 -0
  30. package/dist/entry-points/file/base/fc_package_tsconfig.d.ts +5 -0
  31. package/dist/entry-points/file/base/fc_package_tsconfig.mjs +13 -0
  32. package/dist/entry-points/file/client/fc_package_AppModule.d.ts +1 -0
  33. package/dist/entry-points/file/client/fc_package_AppModule.mjs +37 -0
  34. package/dist/entry-points/file/client/fc_package_AppPage.d.ts +1 -0
  35. package/dist/entry-points/file/client/fc_package_AppPage.mjs +14 -0
  36. package/dist/entry-points/file/client/fc_package_Page.d.ts +4 -0
  37. package/dist/entry-points/file/client/fc_package_Page.mjs +19 -0
  38. package/dist/entry-points/file/client/fc_package_client_main.d.ts +1 -0
  39. package/dist/entry-points/file/client/fc_package_client_main.mjs +19 -0
  40. package/dist/entry-points/file/client/fc_package_index.d.ts +3 -0
  41. package/dist/entry-points/file/client/fc_package_index.mjs +88 -0
  42. package/dist/entry-points/file/client/fc_package_manifest.d.ts +5 -0
  43. package/dist/entry-points/file/client/fc_package_manifest.mjs +54 -0
  44. package/dist/entry-points/file/client/fc_package_polyfills.d.ts +1 -0
  45. package/dist/entry-points/file/client/fc_package_polyfills.mjs +11 -0
  46. package/dist/entry-points/file/client/fc_package_styles.d.ts +1 -0
  47. package/dist/entry-points/file/client/fc_package_styles.mjs +7 -0
  48. package/dist/entry-points/file/db/fc_package_DbContext.d.ts +3 -0
  49. package/dist/entry-points/file/db/fc_package_DbContext.mjs +14 -0
  50. package/dist/entry-points/file/db/fc_package_DbModel.d.ts +4 -0
  51. package/dist/entry-points/file/db/fc_package_DbModel.mjs +12 -0
  52. package/dist/entry-points/file/project/fc_project_editor_config.d.ts +1 -0
  53. package/dist/entry-points/file/project/fc_project_editor_config.mjs +22 -0
  54. package/dist/entry-points/file/project/fc_project_eslintrc.d.ts +1 -0
  55. package/dist/entry-points/file/project/fc_project_eslintrc.mjs +30 -0
  56. package/dist/entry-points/file/project/fc_project_gitattributes.d.ts +1 -0
  57. package/dist/entry-points/file/project/fc_project_gitattributes.mjs +6 -0
  58. package/dist/entry-points/file/project/fc_project_gitignore.d.ts +1 -0
  59. package/dist/entry-points/file/project/fc_project_gitignore.mjs +17 -0
  60. package/dist/entry-points/file/project/fc_project_npmconfig.d.ts +7 -0
  61. package/dist/entry-points/file/project/fc_project_npmconfig.mjs +35 -0
  62. package/dist/entry-points/file/project/fc_project_readme.d.ts +3 -0
  63. package/dist/entry-points/file/project/fc_project_readme.mjs +13 -0
  64. package/dist/entry-points/file/project/fc_project_simplysm.d.ts +1 -0
  65. package/dist/entry-points/file/project/fc_project_simplysm.mjs +2 -0
  66. package/dist/entry-points/file/project/fc_project_tsconfig.d.ts +1 -0
  67. package/dist/entry-points/file/project/fc_project_tsconfig.mjs +26 -0
  68. package/dist/entry-points/file/server/fc_package_server_main.d.ts +4 -0
  69. package/dist/entry-points/file/server/fc_package_server_main.mjs +60 -0
  70. package/dist/index.d.ts +23 -0
  71. package/dist/index.mjs +24 -1
  72. package/dist/ng-tools/SdCliNgModuleGenerator.mjs +35 -36
  73. package/dist/packages/SdCliPackage.d.ts +1 -0
  74. package/dist/packages/SdCliPackage.mjs +69 -63
  75. package/dist/utils/SdCliBuildResultUtil.mjs +2 -2
  76. package/docs/client-add-page.md +8 -0
  77. package/docs/client-router.md +85 -0
  78. package/docs/client-sw.md +101 -0
  79. package/docs/conf-orm.md +81 -0
  80. package/docs/conf-usage.md +5 -0
  81. package/docs/lib-local-update.md +50 -0
  82. package/docs/lib-ts-paths.md +25 -0
  83. package/package.json +10 -8
  84. package/src/SdCliBuildResultError.ts +9 -9
  85. package/src/bin/sd-cli.ts +244 -15
  86. package/src/build-tool/SdCliCacheCompilerHost.ts +77 -77
  87. package/src/build-tool/SdCliCordova.ts +2 -2
  88. package/src/build-tool/SdCliElectron.ts +2 -1
  89. package/src/build-tool/SdCliGithubApi.ts +110 -110
  90. package/src/build-tool/SdCliIndexFileGenerator.ts +79 -80
  91. package/src/build-tool/SdCliNgCacheCompilerHost.ts +58 -58
  92. package/src/build-tool/SdCliPackageLinter.ts +74 -74
  93. package/src/builder/SdCliClientBuilder.ts +71 -20
  94. package/src/builder/SdCliJsLibBuilder.ts +70 -70
  95. package/src/builder/SdCliServerBuilder.ts +34 -14
  96. package/src/builder/SdCliTsLibBuilder.ts +450 -445
  97. package/src/commons.ts +6 -1
  98. package/src/entry-points/SdCliFileCrypto.ts +87 -87
  99. package/src/entry-points/SdCliPrepare.ts +55 -55
  100. package/src/entry-points/SdCliProjectGenerator.ts +395 -0
  101. package/src/entry-points/SdCliWorkspace.ts +74 -122
  102. package/src/entry-points/file/base/fc_package_eslintrc.ts +30 -0
  103. package/src/entry-points/file/base/fc_package_npmconfig.ts +43 -0
  104. package/src/entry-points/file/base/fc_package_tsconfig.ts +12 -0
  105. package/src/entry-points/file/client/fc_package_AppModule.ts +36 -0
  106. package/src/entry-points/file/client/fc_package_AppPage.ts +13 -0
  107. package/src/entry-points/file/client/fc_package_Page.ts +19 -0
  108. package/src/entry-points/file/client/fc_package_client_main.ts +18 -0
  109. package/src/entry-points/file/client/fc_package_index.ts +87 -0
  110. package/src/entry-points/file/client/fc_package_manifest.ts +53 -0
  111. package/src/entry-points/file/client/fc_package_polyfills.ts +10 -0
  112. package/src/entry-points/file/client/fc_package_styles.ts +6 -0
  113. package/src/entry-points/file/db/fc_package_DbContext.ts +14 -0
  114. package/src/entry-points/file/db/fc_package_DbModel.ts +11 -0
  115. package/src/entry-points/file/project/fc_project_editor_config.ts +21 -0
  116. package/src/entry-points/file/project/fc_project_eslintrc.ts +29 -0
  117. package/src/entry-points/file/project/fc_project_gitattributes.ts +5 -0
  118. package/src/entry-points/file/project/fc_project_gitignore.ts +16 -0
  119. package/src/entry-points/file/project/fc_project_npmconfig.ts +34 -0
  120. package/src/entry-points/file/project/fc_project_readme.ts +12 -0
  121. package/src/entry-points/file/project/fc_project_simplysm.ts +1 -0
  122. package/src/entry-points/file/project/fc_project_tsconfig.ts +25 -0
  123. package/src/entry-points/file/server/fc_package_server_main.ts +62 -0
  124. package/src/index.ts +55 -32
  125. package/src/ng-tools/SdCliNgModuleGenerator.ts +639 -640
  126. package/src/ng-tools/babel/SdCliBbFileMetadata.ts +568 -568
  127. package/src/ng-tools/babel/SdCliBbRootMetadata.ts +239 -239
  128. package/src/ng-tools/babel/SdCliBbUtil.ts +15 -15
  129. package/src/ng-tools/babel/TSdCliBbNgMetadata.ts +234 -234
  130. package/src/ng-tools/babel/TSdCliBbTypeMetadata.ts +177 -177
  131. package/src/ng-tools/commons.ts +3 -3
  132. package/src/ng-tools/typescript/SdCliTsFileMetadata.ts +384 -384
  133. package/src/ng-tools/typescript/SdCliTsRootMetadata.ts +32 -32
  134. package/src/ng-tools/typescript/SdCliTsUtil.ts +29 -29
  135. package/src/packages/SdCliPackage.ts +76 -59
  136. package/src/utils/SdCliBuildResultUtil.ts +76 -76
  137. package/src/utils/SdCliConfigUtil.ts +94 -94
  138. package/src/utils/SdCliNpmConfigUtil.ts +16 -16
@@ -1,445 +1,450 @@
1
- import { INpmConfig, ISdCliLibPackageConfig, ISdCliPackageBuildResult } from "../commons";
2
- import { EventEmitter } from "events";
3
- import ts from "typescript";
4
- import { FsUtil, Logger, PathUtil, SdFsWatcher } from "@simplysm/sd-core-node";
5
- import path from "path";
6
- import { createHash } from "crypto";
7
- import { SdCliBuildResultUtil } from "../utils/SdCliBuildResultUtil";
8
- import { NgtscProgram } from "@angular/compiler-cli";
9
- import sass from "sass";
10
- import { SdCliPackageLinter } from "../build-tool/SdCliPackageLinter";
11
- import { SdCliCacheCompilerHost } from "../build-tool/SdCliCacheCompilerHost";
12
- import { SdCliNgCacheCompilerHost } from "../build-tool/SdCliNgCacheCompilerHost";
13
- import { NgCompiler } from "@angular/compiler-cli/src/ngtsc/core";
14
- import { SdCliNpmConfigUtil } from "../utils/SdCliNpmConfigUtil";
15
- import { SdCliNgModuleGenerator } from "../ng-tools/SdCliNgModuleGenerator";
16
- import { SdCliIndexFileGenerator } from "../build-tool/SdCliIndexFileGenerator";
17
-
18
- export class SdCliTsLibBuilder extends EventEmitter {
19
- private readonly _logger: Logger;
20
-
21
- private _moduleResolutionCache?: ts.ModuleResolutionCache;
22
-
23
- private readonly _linter: SdCliPackageLinter;
24
-
25
- private readonly _fileCache = new Map<string, IFileCache>();
26
- private readonly _writeFileCache = new Map<string, string>();
27
-
28
- private readonly _indexFileGenerator?: SdCliIndexFileGenerator;
29
-
30
- private _program?: ts.Program;
31
- private _ngProgram?: NgtscProgram;
32
- private _builder?: ts.EmitAndSemanticDiagnosticsBuilderProgram;
33
- private readonly _ngModuleGenerator?: SdCliNgModuleGenerator;
34
-
35
- private readonly _tsconfigFilePath: string;
36
- private readonly _parsedTsconfig: ts.ParsedCommandLine;
37
- private readonly _npmConfigMap = new Map<string, INpmConfig>();
38
-
39
- private readonly _isAngular: boolean;
40
- private readonly _hasAngularRoute: boolean;
41
-
42
- public constructor(private readonly _rootPath: string,
43
- private readonly _config: ISdCliLibPackageConfig,
44
- private readonly _workspaceRootPath: string) {
45
- super();
46
- const npmConfig = this._getNpmConfig(this._rootPath)!;
47
-
48
- // linter
49
- this._linter = new SdCliPackageLinter(this._rootPath);
50
-
51
- // logger
52
- this._logger = Logger.get(["simplysm", "sd-cli", this.constructor.name, npmConfig.name]);
53
-
54
- // isAngular
55
- this._isAngular = SdCliNpmConfigUtil.getDependencies(npmConfig).defaults.includes("@angular/core");
56
- this._hasAngularRoute = SdCliNpmConfigUtil.getDependencies(npmConfig).defaults.includes("@angular/router");
57
-
58
- // tsconfig
59
- this._tsconfigFilePath = path.resolve(this._rootPath, "tsconfig-build.json");
60
- const tsconfig = FsUtil.readJson(this._tsconfigFilePath);
61
- this._parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this._rootPath, this._isAngular ? tsconfig.angularCompilerOptions : undefined);
62
-
63
- if (this._isAngular) {
64
- // NgModule 생성기 초기화
65
- this._ngModuleGenerator = new SdCliNgModuleGenerator(this._rootPath, [
66
- "controls",
67
- "directives",
68
- "guards",
69
- "modals",
70
- "providers",
71
- "app",
72
- "pages",
73
- "print-templates",
74
- "toasts",
75
- "AppPage"
76
- ], this._hasAngularRoute ? {
77
- glob: "**/*Page.ts",
78
- fileEndsWith: "Page",
79
- rootClassName: "AppPage"
80
- } : undefined);
81
- }
82
-
83
- // index 생성기 초기화
84
- if (this._config.autoIndex) {
85
- this._indexFileGenerator = new SdCliIndexFileGenerator(this._rootPath, this._config.autoIndex);
86
- }
87
- }
88
-
89
- public override on(event: "change", listener: () => void): this;
90
- public override on(event: "complete", listener: (results: ISdCliPackageBuildResult[]) => void): this;
91
- public override on(event: string | symbol, listener: (...args: any[]) => void): this {
92
- return super.on(event, listener);
93
- }
94
-
95
- public async watchAsync(): Promise<void> {
96
- this.emit("change");
97
-
98
- this._logger.debug("dist 폴더 삭제...");
99
- await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
100
-
101
- if (this._ngModuleGenerator) {
102
- this._logger.debug("NgModule 생성...");
103
- await this._ngModuleGenerator.runAsync();
104
- }
105
-
106
- if (this._indexFileGenerator) {
107
- this._logger.debug("index.js 생성 및 index.js용 변경감지 시작...");
108
- await this._indexFileGenerator.runAsync();
109
- await this._indexFileGenerator.watchAsync();
110
- }
111
-
112
- this._logger.debug("프로그램 로딩...");
113
- const buildPack = this._createSdBuildPack(this._parsedTsconfig);
114
-
115
- this._logger.debug("변경감지 구성...");
116
- const relatedPaths = await this.getAllRelatedPathsAsync();
117
- const watcher = SdFsWatcher.watch(relatedPaths);
118
- watcher.onChange({}, async (changedInfos) => {
119
- const changeFilePaths = changedInfos.filter((item) => ["add", "change", "unlink"].includes(item.event)).map((item) => item.path);
120
- if (changeFilePaths.length === 0) return;
121
-
122
- this._logger.debug("파일 변경 감지", changeFilePaths);
123
- this.emit("change");
124
-
125
- this._logger.debug("변경된 파일의 캐쉬 삭제...");
126
- for (const changeFilePath of changeFilePaths) {
127
- const fileCache = this._fileCache.get(PathUtil.posix(changeFilePath));
128
- if (fileCache) {
129
- if (fileCache.importerSet) {
130
- for (const importer of fileCache.importerSet.values()) {
131
- this._fileCache.delete(importer);
132
- }
133
- }
134
-
135
- this._fileCache.delete(PathUtil.posix(changeFilePath));
136
- }
137
- }
138
-
139
- if (this._ngModuleGenerator) {
140
- this._logger.debug("NgModule 생성...");
141
- this._ngModuleGenerator.removeCaches(changeFilePaths);
142
- await this._ngModuleGenerator.runAsync();
143
- }
144
-
145
- const watchBuildResults: ISdCliPackageBuildResult[] = [];
146
-
147
- this._logger.debug("프로그램 로딩...");
148
- const watchBuildPack = this._createSdBuildPack(this._parsedTsconfig);
149
-
150
- this._logger.debug("빌드...");
151
- watchBuildResults.push(...await this._runBuilderAsync(watchBuildPack.builder, watchBuildPack.ngCompiler));
152
-
153
- this._logger.debug("린트...");
154
- const lintFilePaths = [
155
- ...watchBuildPack.affectedSourceFiles.map((item) => item.fileName),
156
- ...changedInfos.filter((item) => ["add", "change"].includes(item.event)).map((item) => item.path)
157
- ];
158
- if (lintFilePaths.length > 0) {
159
- watchBuildResults.push(...await this._linter.lintAsync(lintFilePaths, watchBuildPack.program));
160
- }
161
-
162
- this._logger.debug("변경감지 대상목록 재구성...");
163
- const watchRelatedPaths = await this.getAllRelatedPathsAsync();
164
- watcher.add(watchRelatedPaths);
165
-
166
- this.emit("complete", watchBuildResults);
167
- });
168
-
169
- this._logger.debug("빌드...");
170
- const buildResults = await this._runBuilderAsync(buildPack.builder, buildPack.ngCompiler);
171
-
172
- this._logger.debug("린트...");
173
- buildResults.push(...await this._linter.lintAsync(relatedPaths, buildPack.program));
174
-
175
- this._logger.debug("변경감지 대상목록 재구성...");
176
- const watchRelatedPaths = await this.getAllRelatedPathsAsync();
177
- watcher.add(watchRelatedPaths);
178
-
179
- this.emit("complete", buildResults);
180
- }
181
-
182
- public async buildAsync(): Promise<ISdCliPackageBuildResult[]> {
183
- this._logger.debug("dist 폴더 삭제...");
184
- await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
185
-
186
- if (this._ngModuleGenerator) {
187
- this._logger.debug("NgModule 생성...");
188
- await this._ngModuleGenerator.runAsync();
189
- }
190
-
191
- if (this._indexFileGenerator) {
192
- this._logger.debug("index.js 생성...");
193
- await this._indexFileGenerator.runAsync();
194
- }
195
-
196
- this._logger.debug("프로그램 로딩...");
197
- const buildPack = this._createSdBuildPack(this._parsedTsconfig);
198
-
199
- this._logger.debug("빌드...");
200
- const buildResults = await this._runBuilderAsync(buildPack.builder, buildPack.ngCompiler);
201
-
202
- this._logger.debug("린트...");
203
- const relatedPaths = await this.getAllRelatedPathsAsync();
204
- buildResults.push(...await this._linter.lintAsync(relatedPaths, buildPack.program));
205
-
206
- return buildResults;
207
- }
208
-
209
- private async getAllRelatedPathsAsync(): Promise<string[]> {
210
- const workspaceNpmConfig = this._getNpmConfig(this._workspaceRootPath)!;
211
- const workspaceName = workspaceNpmConfig.name;
212
-
213
- const fileCachePaths = Array.from(this._fileCache.keys())
214
- .filter((filePath) => {
215
- const workspaceRegex = new RegExp(`node_modules[\\\\/]@${workspaceName}[\\\\/]`);
216
- return !filePath.includes("node_modules")
217
- || (/node_modules[\\/]@simplysm[\\/]/).test(filePath)
218
- || workspaceRegex.test(filePath);
219
- });
220
- const mySourceGlobPath = path.resolve(this._rootPath, "**", "+(*.js|*.cjs|*.mjs|*.ts|*.scss)");
221
- const mySourceFilePaths = await FsUtil.globAsync(mySourceGlobPath, {
222
- ignore: [
223
- "**/node_modules/**",
224
- "**/dist/**",
225
- "**/.*/**"
226
- ]
227
- });
228
-
229
- return [...fileCachePaths, ...mySourceFilePaths, path.resolve(this._rootPath, ".eslintrc.cjs")].distinct();
230
- }
231
-
232
- private async _runBuilderAsync(builder: ts.EmitAndSemanticDiagnosticsBuilderProgram, ngCompiler?: NgCompiler): Promise<ISdCliPackageBuildResult[]> {
233
- try {
234
- const results: ISdCliPackageBuildResult[] = [];
235
-
236
- const diagnostics: ts.Diagnostic[] = [];
237
-
238
- if (ngCompiler) {
239
- diagnostics.push(...ngCompiler.getOptionDiagnostics());
240
- }
241
-
242
- diagnostics.push(
243
- ...builder.getOptionsDiagnostics(),
244
- ...builder.getGlobalDiagnostics()
245
- );
246
-
247
- if (ngCompiler) {
248
- await ngCompiler.analyzeAsync();
249
- }
250
-
251
- for (const sourceFile of builder.getSourceFiles()) {
252
- if (ngCompiler?.ignoreForDiagnostics.has(sourceFile)) continue;
253
-
254
- diagnostics.push(
255
- ...builder.getSyntacticDiagnostics(sourceFile),
256
- ...builder.getSemanticDiagnostics(sourceFile)
257
- );
258
-
259
- if (
260
- ngCompiler &&
261
- !sourceFile.isDeclarationFile &&
262
- !ngCompiler.ignoreForEmit.has(sourceFile) &&
263
- !ngCompiler.incrementalDriver.safeToSkipEmit(sourceFile)
264
- ) {
265
- diagnostics.push(
266
- ...ngCompiler.getDiagnosticsForFile(sourceFile, 1)
267
- );
268
- }
269
- }
270
-
271
- results.push(
272
- ...diagnostics
273
- .filter((item) => [ts.DiagnosticCategory.Error, ts.DiagnosticCategory.Warning].includes(item.category))
274
- .map((item) => SdCliBuildResultUtil.convertFromTsDiag(item))
275
- .filterExists()
276
- );
277
-
278
- if (results.some((item) => item.severity === "error")) {
279
- return results;
280
- }
281
-
282
- const transformers = ngCompiler?.prepareEmit().transformers;
283
- for (const sourceFile of builder.getSourceFiles()) {
284
- if (ngCompiler?.ignoreForEmit.has(sourceFile)) continue;
285
- builder.emit(sourceFile, undefined, undefined, undefined, transformers);
286
- }
287
-
288
- return results;
289
- }
290
- catch (err) {
291
- if (err instanceof sass.Exception) {
292
- const matches = (/^(.*\.sd\.scss) ([0-9]*):([0-9]*)/).exec(err.sassStack)!;
293
- const filePath = path.resolve(matches[1].replace(/\.sd\.scss/, "").replace(/^\.:/, item => item.toUpperCase()));
294
- const scssLine = matches[2];
295
- const scssChar = matches[3];
296
- const message = err.sassMessage;
297
-
298
- return [{
299
- filePath,
300
- line: undefined,
301
- char: undefined,
302
- code: undefined,
303
- severity: "error",
304
- message: `스타일(${scssLine}:${scssChar}): ${message}\n${err.message}`
305
- }];
306
- }
307
-
308
- return [{
309
- filePath: undefined,
310
- line: undefined,
311
- char: undefined,
312
- code: undefined,
313
- severity: "error",
314
- message: err.stack
315
- }];
316
- }
317
- }
318
-
319
- private _createSdBuildPack(parsedTsconfig: ts.ParsedCommandLine): ISdBuildPack {
320
- const compilerHost = this._createCacheCompilerHost(parsedTsconfig);
321
- const { program, ngCompiler } = this._createProgram(parsedTsconfig, compilerHost);
322
-
323
- this._builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(
324
- program,
325
- compilerHost,
326
- this._builder
327
- );
328
-
329
- const affectedSourceFileSet: Set<ts.SourceFile> = new Set<ts.SourceFile>();
330
- while (true) {
331
- const result = this._builder.getSemanticDiagnosticsOfNextAffectedFile(undefined, (sourceFile) => {
332
- // this._logger.debug(sourceFile.fileName + " SYNTAX 로딩...");
333
- if (ngCompiler?.ignoreForDiagnostics.has(sourceFile) && sourceFile.fileName.endsWith(".ngtypecheck.ts")) {
334
- const orgFileName = sourceFile.fileName.slice(0, -15) + ".ts";
335
- const orgSourceFile = this._builder!.getSourceFile(orgFileName);
336
- if (orgSourceFile) {
337
- affectedSourceFileSet.add(orgSourceFile);
338
- }
339
-
340
- return true;
341
- }
342
-
343
- return false;
344
- });
345
- if (!result) break;
346
-
347
- // this._logger.debug((result.affected as ts.SourceFile).fileName + " SYNTAX 로딩");
348
- affectedSourceFileSet.add(result.affected as ts.SourceFile);
349
- }
350
-
351
- return {
352
- program,
353
- ngCompiler,
354
- builder: this._builder,
355
- affectedSourceFiles: Array.from(affectedSourceFileSet.values())
356
- };
357
- }
358
-
359
- private _createProgram(parsedTsconfig: ts.ParsedCommandLine, compilerHost: ts.CompilerHost): { program: ts.Program; ngCompiler?: NgCompiler } {
360
- if (this._isAngular) {
361
- this._ngProgram = new NgtscProgram(
362
- parsedTsconfig.fileNames,
363
- parsedTsconfig.options,
364
- compilerHost,
365
- this._ngProgram
366
- );
367
- this._program = this._ngProgram.getTsProgram();
368
-
369
- this._configProgramSourceFileVersions(this._program);
370
- return {
371
- program: this._program,
372
- ngCompiler: this._ngProgram.compiler
373
- };
374
- }
375
- else {
376
- this._program = ts.createProgram(
377
- parsedTsconfig.fileNames,
378
- parsedTsconfig.options,
379
- compilerHost,
380
- this._program
381
- );
382
-
383
- this._configProgramSourceFileVersions(this._program);
384
-
385
- return { program: this._program };
386
- }
387
- }
388
-
389
- private _configProgramSourceFileVersions(program: ts.Program): void {
390
- const baseGetSourceFiles = program.getSourceFiles;
391
- program.getSourceFiles = function (...parameters) {
392
- const files: readonly (ts.SourceFile & { version?: string })[] = baseGetSourceFiles(...parameters);
393
-
394
- for (const file of files) {
395
- if (file.version === undefined) {
396
- file.version = createHash("sha256").update(file.text).digest("hex");
397
- }
398
- }
399
-
400
- return files;
401
- };
402
- }
403
-
404
- private _createCacheCompilerHost(parsedTsconfig: ts.ParsedCommandLine): ts.CompilerHost {
405
- if (!this._moduleResolutionCache) {
406
- this._moduleResolutionCache = ts.createModuleResolutionCache(this._rootPath, (s) => s, parsedTsconfig.options);
407
- }
408
-
409
- const compilerHost = SdCliCacheCompilerHost.create(
410
- parsedTsconfig,
411
- this._moduleResolutionCache,
412
- this._fileCache,
413
- this._writeFileCache
414
- );
415
-
416
- if (this._isAngular) {
417
- return SdCliNgCacheCompilerHost.wrap(compilerHost, this._fileCache);
418
- }
419
- else {
420
- return compilerHost;
421
- }
422
- }
423
-
424
- private _getNpmConfig(pkgPath: string): INpmConfig | undefined {
425
- if (!this._npmConfigMap.has(pkgPath)) {
426
- this._npmConfigMap.set(pkgPath, FsUtil.readJson(path.resolve(pkgPath, "package.json")));
427
- }
428
- return this._npmConfigMap.get(pkgPath);
429
- }
430
- }
431
-
432
- interface IFileCache {
433
- exists?: boolean;
434
- sourceFile?: ts.SourceFile;
435
- content?: string;
436
- styleContent?: string;
437
- importerSet?: Set<string>;
438
- }
439
-
440
- interface ISdBuildPack {
441
- program: ts.Program;
442
- ngCompiler?: NgCompiler;
443
- builder: ts.EmitAndSemanticDiagnosticsBuilderProgram;
444
- affectedSourceFiles: ts.SourceFile[];
445
- }
1
+ import { INpmConfig, ISdCliLibPackageConfig, ISdCliPackageBuildResult } from "../commons";
2
+ import { EventEmitter } from "events";
3
+ import ts from "typescript";
4
+ import { FsUtil, Logger, PathUtil, SdFsWatcher } from "@simplysm/sd-core-node";
5
+ import path from "path";
6
+ import { createHash } from "crypto";
7
+ import { SdCliBuildResultUtil } from "../utils/SdCliBuildResultUtil";
8
+ import { NgtscProgram } from "@angular/compiler-cli";
9
+ import sass from "sass";
10
+ import { SdCliPackageLinter } from "../build-tool/SdCliPackageLinter";
11
+ import { SdCliCacheCompilerHost } from "../build-tool/SdCliCacheCompilerHost";
12
+ import { SdCliNgCacheCompilerHost } from "../build-tool/SdCliNgCacheCompilerHost";
13
+ import { NgCompiler } from "@angular/compiler-cli/src/ngtsc/core";
14
+ import { SdCliNpmConfigUtil } from "../utils/SdCliNpmConfigUtil";
15
+ import { SdCliNgModuleGenerator } from "../ng-tools/SdCliNgModuleGenerator";
16
+ import { SdCliIndexFileGenerator } from "../build-tool/SdCliIndexFileGenerator";
17
+
18
+ export class SdCliTsLibBuilder extends EventEmitter {
19
+ private readonly _logger: Logger;
20
+
21
+ private _moduleResolutionCache?: ts.ModuleResolutionCache;
22
+
23
+ private readonly _linter: SdCliPackageLinter;
24
+
25
+ private readonly _fileCache = new Map<string, IFileCache>();
26
+ private readonly _writeFileCache = new Map<string, string>();
27
+
28
+ private readonly _indexFileGenerator?: SdCliIndexFileGenerator;
29
+
30
+ private _program?: ts.Program;
31
+ private _ngProgram?: NgtscProgram;
32
+ private _builder?: ts.EmitAndSemanticDiagnosticsBuilderProgram;
33
+ private readonly _ngModuleGenerator?: SdCliNgModuleGenerator;
34
+
35
+ private readonly _tsconfigFilePath: string;
36
+ private readonly _parsedTsconfig: ts.ParsedCommandLine;
37
+ private readonly _npmConfigMap = new Map<string, INpmConfig>();
38
+
39
+ private readonly _isAngular: boolean;
40
+ private readonly _hasAngularRoute: boolean;
41
+
42
+ public constructor(private readonly _rootPath: string,
43
+ private readonly _config: ISdCliLibPackageConfig,
44
+ private readonly _workspaceRootPath: string) {
45
+ super();
46
+ const npmConfig = this._getNpmConfig(this._rootPath)!;
47
+
48
+ // linter
49
+ this._linter = new SdCliPackageLinter(this._rootPath);
50
+
51
+ // logger
52
+ this._logger = Logger.get(["simplysm", "sd-cli", this.constructor.name, npmConfig.name]);
53
+
54
+ // isAngular
55
+ this._isAngular = SdCliNpmConfigUtil.getDependencies(npmConfig).defaults.includes("@angular/core");
56
+ this._hasAngularRoute = SdCliNpmConfigUtil.getDependencies(npmConfig).defaults.includes("@angular/router");
57
+
58
+ // tsconfig
59
+ this._tsconfigFilePath = path.resolve(this._rootPath, "tsconfig-build.json");
60
+ const tsconfig = FsUtil.readJson(this._tsconfigFilePath);
61
+ this._parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this._rootPath, this._isAngular ? tsconfig.angularCompilerOptions : undefined);
62
+
63
+ if (this._isAngular) {
64
+ // NgModule 생성기 초기화
65
+ this._ngModuleGenerator = new SdCliNgModuleGenerator(this._rootPath, [
66
+ "controls",
67
+ "directives",
68
+ "guards",
69
+ "modals",
70
+ "providers",
71
+ "app",
72
+ "pages",
73
+ "print-templates",
74
+ "toasts",
75
+ "AppPage"
76
+ ], this._hasAngularRoute ? {
77
+ glob: "**/*Page.ts",
78
+ fileEndsWith: "Page",
79
+ rootClassName: "AppPage"
80
+ } : undefined);
81
+ }
82
+
83
+ // index 생성기 초기화
84
+ if (this._config.autoIndex) {
85
+ this._indexFileGenerator = new SdCliIndexFileGenerator(this._rootPath, this._config.autoIndex);
86
+ }
87
+ }
88
+
89
+ public override on(event: "change", listener: () => void): this;
90
+ public override on(event: "complete", listener: (results: ISdCliPackageBuildResult[]) => void): this;
91
+ public override on(event: string | symbol, listener: (...args: any[]) => void): this {
92
+ return super.on(event, listener);
93
+ }
94
+
95
+ public async watchAsync(): Promise<void> {
96
+ this.emit("change");
97
+
98
+ this._logger.debug("dist 폴더 삭제...");
99
+ await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
100
+
101
+ if (this._ngModuleGenerator) {
102
+ this._logger.debug("NgModule 생성...");
103
+ await this._ngModuleGenerator.runAsync();
104
+ }
105
+
106
+ if (this._indexFileGenerator) {
107
+ this._logger.debug("index.js 생성 및 index.js용 변경감지 시작...");
108
+ await this._indexFileGenerator.runAsync();
109
+ await this._indexFileGenerator.watchAsync();
110
+ }
111
+
112
+ this._logger.debug("프로그램 로딩...");
113
+ const buildPack = this._createSdBuildPack(this._parsedTsconfig);
114
+
115
+ this._logger.debug("변경감지 구성...");
116
+ const relatedPaths = await this.getAllRelatedPathsAsync();
117
+ const watcher = SdFsWatcher.watch(relatedPaths);
118
+ watcher.onChange({}, async (changedInfos) => {
119
+ const changeFilePaths = changedInfos.filter((item) => ["add", "change", "unlink"].includes(item.event)).map((item) => item.path);
120
+ if (changeFilePaths.length === 0) return;
121
+
122
+ this._logger.debug("파일 변경 감지", changeFilePaths);
123
+ this.emit("change");
124
+
125
+ this._logger.debug("변경된 파일의 캐쉬 삭제...");
126
+ for (const changeFilePath of changeFilePaths) {
127
+ const fileCache = this._fileCache.get(PathUtil.posix(changeFilePath));
128
+ if (fileCache) {
129
+ if (fileCache.importerSet) {
130
+ for (const importer of fileCache.importerSet.values()) {
131
+ this._fileCache.delete(importer);
132
+ }
133
+ }
134
+
135
+ this._fileCache.delete(PathUtil.posix(changeFilePath));
136
+ }
137
+ }
138
+
139
+ if (this._ngModuleGenerator) {
140
+ this._logger.debug("NgModule 생성...");
141
+ this._ngModuleGenerator.removeCaches(changeFilePaths);
142
+ await this._ngModuleGenerator.runAsync();
143
+ }
144
+
145
+ const watchBuildResults: ISdCliPackageBuildResult[] = [];
146
+
147
+ this._logger.debug("프로그램 로딩...");
148
+ const watchBuildPack = this._createSdBuildPack(this._parsedTsconfig);
149
+
150
+ const promises: Promise<ISdCliPackageBuildResult[]>[] = [];
151
+
152
+ // 빌드
153
+ promises.push(this._runBuilderAsync(watchBuildPack.builder, watchBuildPack.ngCompiler));
154
+ // watchBuildResults.push(...await this._runBuilderAsync(watchBuildPack.builder, watchBuildPack.ngCompiler));
155
+
156
+ // 린트
157
+ const lintFilePaths = [
158
+ ...watchBuildPack.affectedSourceFiles.map((item) => item.fileName),
159
+ ...changedInfos.filter((item) => ["add", "change"].includes(item.event)).map((item) => item.path)
160
+ ];
161
+ if (lintFilePaths.length > 0) {
162
+ promises.push(this._linter.lintAsync(lintFilePaths, watchBuildPack.program));
163
+ // watchBuildResults.push(...await this._linter.lintAsync(lintFilePaths, watchBuildPack.program));
164
+ }
165
+
166
+ this._logger.debug("빌드...");
167
+ watchBuildResults.push(...(await Promise.all(promises)).mapMany());
168
+
169
+ this._logger.debug("변경감지 대상목록 재구성...");
170
+ const watchRelatedPaths = await this.getAllRelatedPathsAsync();
171
+ watcher.add(watchRelatedPaths);
172
+
173
+ this.emit("complete", watchBuildResults);
174
+ });
175
+
176
+ this._logger.debug("빌드...");
177
+ const buildResults = (await Promise.all([
178
+ this._runBuilderAsync(buildPack.builder, buildPack.ngCompiler),
179
+ this._linter.lintAsync(relatedPaths, buildPack.program)
180
+ ].filterExists())).mapMany();
181
+
182
+ this._logger.debug("변경감지 대상목록 재구성...");
183
+ const watchRelatedPaths = await this.getAllRelatedPathsAsync();
184
+ watcher.add(watchRelatedPaths);
185
+
186
+ this.emit("complete", buildResults);
187
+ }
188
+
189
+ public async buildAsync(): Promise<ISdCliPackageBuildResult[]> {
190
+ this._logger.debug("dist 폴더 삭제...");
191
+ await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
192
+
193
+ if (this._ngModuleGenerator) {
194
+ this._logger.debug("NgModule 생성...");
195
+ await this._ngModuleGenerator.runAsync();
196
+ }
197
+
198
+ if (this._indexFileGenerator) {
199
+ this._logger.debug("index.js 생성...");
200
+ await this._indexFileGenerator.runAsync();
201
+ }
202
+
203
+ this._logger.debug("프로그램 로딩...");
204
+ const buildPack = this._createSdBuildPack(this._parsedTsconfig);
205
+
206
+ this._logger.debug("빌드...");
207
+ const relatedPaths = await this.getAllRelatedPathsAsync();
208
+ return (await Promise.all([
209
+ this._runBuilderAsync(buildPack.builder, buildPack.ngCompiler),
210
+ this._linter.lintAsync(relatedPaths, buildPack.program)
211
+ ].filterExists())).mapMany();
212
+ }
213
+
214
+ private async getAllRelatedPathsAsync(): Promise<string[]> {
215
+ const workspaceNpmConfig = this._getNpmConfig(this._workspaceRootPath)!;
216
+ const workspaceName = workspaceNpmConfig.name;
217
+
218
+ const fileCachePaths = Array.from(this._fileCache.keys())
219
+ .filter((filePath) => {
220
+ const workspaceRegex = new RegExp(`node_modules[\\\\/]@${workspaceName}[\\\\/]`);
221
+ return !filePath.includes("node_modules")
222
+ || (/node_modules[\\/]@simplysm[\\/]/).test(filePath)
223
+ || workspaceRegex.test(filePath);
224
+ });
225
+ const mySourceGlobPath = path.resolve(this._rootPath, "**", "+(*.js|*.cjs|*.mjs|*.ts|*.scss)");
226
+ const mySourceFilePaths = await FsUtil.globAsync(mySourceGlobPath, {
227
+ ignore: [
228
+ "**/node_modules/**",
229
+ "**/dist/**",
230
+ "**/.*/**"
231
+ ]
232
+ });
233
+
234
+ return [...fileCachePaths, ...mySourceFilePaths, path.resolve(this._rootPath, ".eslintrc.cjs")].distinct();
235
+ }
236
+
237
+ private async _runBuilderAsync(builder: ts.EmitAndSemanticDiagnosticsBuilderProgram, ngCompiler?: NgCompiler): Promise<ISdCliPackageBuildResult[]> {
238
+ try {
239
+ const results: ISdCliPackageBuildResult[] = [];
240
+
241
+ const diagnostics: ts.Diagnostic[] = [];
242
+
243
+ if (ngCompiler) {
244
+ diagnostics.push(...ngCompiler.getOptionDiagnostics());
245
+ }
246
+
247
+ diagnostics.push(
248
+ ...builder.getOptionsDiagnostics(),
249
+ ...builder.getGlobalDiagnostics()
250
+ );
251
+
252
+ if (ngCompiler) {
253
+ await ngCompiler.analyzeAsync();
254
+ }
255
+
256
+ for (const sourceFile of builder.getSourceFiles()) {
257
+ if (ngCompiler?.ignoreForDiagnostics.has(sourceFile)) continue;
258
+
259
+ diagnostics.push(
260
+ ...builder.getSyntacticDiagnostics(sourceFile),
261
+ ...builder.getSemanticDiagnostics(sourceFile)
262
+ );
263
+
264
+ if (
265
+ ngCompiler &&
266
+ !sourceFile.isDeclarationFile &&
267
+ !ngCompiler.ignoreForEmit.has(sourceFile) &&
268
+ !ngCompiler.incrementalDriver.safeToSkipEmit(sourceFile)
269
+ ) {
270
+ diagnostics.push(
271
+ ...ngCompiler.getDiagnosticsForFile(sourceFile, 1)
272
+ );
273
+ }
274
+ }
275
+
276
+ results.push(
277
+ ...diagnostics
278
+ .filter((item) => [ts.DiagnosticCategory.Error, ts.DiagnosticCategory.Warning].includes(item.category))
279
+ .map((item) => SdCliBuildResultUtil.convertFromTsDiag(item))
280
+ .filterExists()
281
+ );
282
+
283
+ if (results.some((item) => item.severity === "error")) {
284
+ return results;
285
+ }
286
+
287
+ const transformers = ngCompiler?.prepareEmit().transformers;
288
+ for (const sourceFile of builder.getSourceFiles()) {
289
+ if (ngCompiler?.ignoreForEmit.has(sourceFile)) continue;
290
+ builder.emit(sourceFile, undefined, undefined, undefined, transformers);
291
+ }
292
+
293
+ return results;
294
+ }
295
+ catch (err) {
296
+ if (err instanceof sass.Exception) {
297
+ const matches = (/^(.*\.sd\.scss) ([0-9]*):([0-9]*)/).exec(err.sassStack)!;
298
+ const filePath = path.resolve(matches[1].replace(/\.sd\.scss/, "").replace(/^\.:/, item => item.toUpperCase()));
299
+ const scssLine = matches[2];
300
+ const scssChar = matches[3];
301
+ const message = err.sassMessage;
302
+
303
+ return [{
304
+ filePath,
305
+ line: undefined,
306
+ char: undefined,
307
+ code: undefined,
308
+ severity: "error",
309
+ message: `스타일(${scssLine}:${scssChar}): ${message}\n${err.message}`
310
+ }];
311
+ }
312
+
313
+ return [{
314
+ filePath: undefined,
315
+ line: undefined,
316
+ char: undefined,
317
+ code: undefined,
318
+ severity: "error",
319
+ message: err.stack
320
+ }];
321
+ }
322
+ }
323
+
324
+ private _createSdBuildPack(parsedTsconfig: ts.ParsedCommandLine): ISdBuildPack {
325
+ const compilerHost = this._createCacheCompilerHost(parsedTsconfig);
326
+ const { program, ngCompiler } = this._createProgram(parsedTsconfig, compilerHost);
327
+
328
+ this._builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(
329
+ program,
330
+ compilerHost,
331
+ this._builder
332
+ );
333
+
334
+ const affectedSourceFileSet: Set<ts.SourceFile> = new Set<ts.SourceFile>();
335
+ while (true) {
336
+ const result = this._builder.getSemanticDiagnosticsOfNextAffectedFile(undefined, (sourceFile) => {
337
+ // this._logger.debug(sourceFile.fileName + " SYNTAX 로딩...");
338
+ if (ngCompiler?.ignoreForDiagnostics.has(sourceFile) && sourceFile.fileName.endsWith(".ngtypecheck.ts")) {
339
+ const orgFileName = sourceFile.fileName.slice(0, -15) + ".ts";
340
+ const orgSourceFile = this._builder!.getSourceFile(orgFileName);
341
+ if (orgSourceFile) {
342
+ affectedSourceFileSet.add(orgSourceFile);
343
+ }
344
+
345
+ return true;
346
+ }
347
+
348
+ return false;
349
+ });
350
+ if (!result) break;
351
+
352
+ // this._logger.debug((result.affected as ts.SourceFile).fileName + " SYNTAX 로딩");
353
+ affectedSourceFileSet.add(result.affected as ts.SourceFile);
354
+ }
355
+
356
+ return {
357
+ program,
358
+ ngCompiler,
359
+ builder: this._builder,
360
+ affectedSourceFiles: Array.from(affectedSourceFileSet.values())
361
+ };
362
+ }
363
+
364
+ private _createProgram(parsedTsconfig: ts.ParsedCommandLine, compilerHost: ts.CompilerHost): { program: ts.Program; ngCompiler?: NgCompiler } {
365
+ if (this._isAngular) {
366
+ this._ngProgram = new NgtscProgram(
367
+ parsedTsconfig.fileNames,
368
+ parsedTsconfig.options,
369
+ compilerHost,
370
+ this._ngProgram
371
+ );
372
+ this._program = this._ngProgram.getTsProgram();
373
+
374
+ this._configProgramSourceFileVersions(this._program);
375
+ return {
376
+ program: this._program,
377
+ ngCompiler: this._ngProgram.compiler
378
+ };
379
+ }
380
+ else {
381
+ this._program = ts.createProgram(
382
+ parsedTsconfig.fileNames,
383
+ parsedTsconfig.options,
384
+ compilerHost,
385
+ this._program
386
+ );
387
+
388
+ this._configProgramSourceFileVersions(this._program);
389
+
390
+ return { program: this._program };
391
+ }
392
+ }
393
+
394
+ private _configProgramSourceFileVersions(program: ts.Program): void {
395
+ const baseGetSourceFiles = program.getSourceFiles;
396
+ program.getSourceFiles = function (...parameters) {
397
+ const files: readonly (ts.SourceFile & { version?: string })[] = baseGetSourceFiles(...parameters);
398
+
399
+ for (const file of files) {
400
+ if (file.version === undefined) {
401
+ file.version = createHash("sha256").update(file.text).digest("hex");
402
+ }
403
+ }
404
+
405
+ return files;
406
+ };
407
+ }
408
+
409
+ private _createCacheCompilerHost(parsedTsconfig: ts.ParsedCommandLine): ts.CompilerHost {
410
+ if (!this._moduleResolutionCache) {
411
+ this._moduleResolutionCache = ts.createModuleResolutionCache(this._rootPath, (s) => s, parsedTsconfig.options);
412
+ }
413
+
414
+ const compilerHost = SdCliCacheCompilerHost.create(
415
+ parsedTsconfig,
416
+ this._moduleResolutionCache,
417
+ this._fileCache,
418
+ this._writeFileCache
419
+ );
420
+
421
+ if (this._isAngular) {
422
+ return SdCliNgCacheCompilerHost.wrap(compilerHost, this._fileCache);
423
+ }
424
+ else {
425
+ return compilerHost;
426
+ }
427
+ }
428
+
429
+ private _getNpmConfig(pkgPath: string): INpmConfig | undefined {
430
+ if (!this._npmConfigMap.has(pkgPath)) {
431
+ this._npmConfigMap.set(pkgPath, FsUtil.readJson(path.resolve(pkgPath, "package.json")));
432
+ }
433
+ return this._npmConfigMap.get(pkgPath);
434
+ }
435
+ }
436
+
437
+ interface IFileCache {
438
+ exists?: boolean;
439
+ sourceFile?: ts.SourceFile;
440
+ content?: string;
441
+ styleContent?: string;
442
+ importerSet?: Set<string>;
443
+ }
444
+
445
+ interface ISdBuildPack {
446
+ program: ts.Program;
447
+ ngCompiler?: NgCompiler;
448
+ builder: ts.EmitAndSemanticDiagnosticsBuilderProgram;
449
+ affectedSourceFiles: ts.SourceFile[];
450
+ }