@simplysm/sd-cli 11.1.45 → 11.1.46

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 (48) hide show
  1. package/dist/build-cluster.js +16 -3
  2. package/dist/build-cluster.js.map +1 -1
  3. package/dist/build-tools/SdNgBundler.d.ts +1 -1
  4. package/dist/build-tools/SdNgBundler.js +4 -1
  5. package/dist/build-tools/SdNgBundler.js.map +1 -1
  6. package/dist/build-tools/SdServerBundler.js.map +1 -1
  7. package/dist/build-tools/SdTsCompiler.d.ts +5 -21
  8. package/dist/build-tools/SdTsCompiler.js +211 -188
  9. package/dist/build-tools/SdTsCompiler.js.map +1 -1
  10. package/dist/build-tools2/SdTsCompiler2.d.ts +26 -0
  11. package/dist/build-tools2/SdTsCompiler2.js +280 -0
  12. package/dist/build-tools2/SdTsCompiler2.js.map +1 -0
  13. package/dist/builders/SdCliTsLibBuilder.js +6 -11
  14. package/dist/builders/SdCliTsLibBuilder.js.map +1 -1
  15. package/dist/bundle-plugins/sdNgPlugin.d.ts +3 -3
  16. package/dist/bundle-plugins/sdNgPlugin.js +22 -212
  17. package/dist/bundle-plugins/sdNgPlugin.js.map +1 -1
  18. package/dist/bundle-plugins/sdServerPlugin.d.ts +2 -2
  19. package/dist/bundle-plugins/sdServerPlugin.js +17 -110
  20. package/dist/bundle-plugins/sdServerPlugin.js.map +1 -1
  21. package/dist/commons.d.ts +1 -0
  22. package/dist/entry/SdCliProject.d.ts +1 -0
  23. package/dist/entry/SdCliProject.js +11 -29
  24. package/dist/entry/SdCliProject.js.map +1 -1
  25. package/dist/index.d.ts +1 -0
  26. package/dist/index.js +1 -0
  27. package/dist/index.js.map +1 -1
  28. package/dist/sd-cli.js +7 -1
  29. package/dist/sd-cli.js.map +1 -1
  30. package/dist/server-worker.js.map +1 -1
  31. package/dist/utils/SdCliBuildResultUtil.d.ts +10 -0
  32. package/dist/utils/SdCliBuildResultUtil.js +17 -1
  33. package/dist/utils/SdCliBuildResultUtil.js.map +1 -1
  34. package/package.json +15 -15
  35. package/src/build-cluster.ts +18 -4
  36. package/src/build-tools/SdNgBundler.ts +7 -4
  37. package/src/build-tools/SdServerBundler.ts +2 -2
  38. package/src/build-tools/SdTsCompiler.ts +64 -94
  39. package/src/build-tools2/SdTsCompiler2.ts +427 -0
  40. package/src/builders/SdCliTsLibBuilder.ts +6 -11
  41. package/src/bundle-plugins/sdNgPlugin.ts +26 -320
  42. package/src/bundle-plugins/sdServerPlugin.ts +20 -168
  43. package/src/commons.ts +1 -0
  44. package/src/entry/SdCliProject.ts +12 -30
  45. package/src/index.ts +1 -0
  46. package/src/sd-cli.ts +7 -1
  47. package/src/server-worker.ts +3 -3
  48. package/src/utils/SdCliBuildResultUtil.ts +22 -3
@@ -1,15 +1,12 @@
1
- import path from "path";
2
- import ts from "typescript";
3
1
  import {SdCliBuildResultUtil} from "../utils/SdCliBuildResultUtil";
4
- import {FsUtil, Logger, PathUtil} from "@simplysm/sd-core-node";
5
- import {ISdCliPackageBuildResult, ITsConfig} from "../commons";
6
- import {NgtscProgram, OptimizeFor} from "@angular/compiler-cli";
7
- import {createHash} from "crypto";
8
- import {fileURLToPath, pathToFileURL} from "url";
9
- import * as sass from "sass";
2
+ import {ISdCliPackageBuildResult} from "../commons";
3
+ import {SdTsCompiler2} from "../build-tools2/SdTsCompiler2";
4
+ import ts from "typescript";
5
+ import path from "path";
6
+ import {FsUtil, PathUtil} from "@simplysm/sd-core-node";
10
7
 
11
8
  export class SdTsCompiler {
12
- private readonly _logger = Logger.get(["simplysm", "sd-cli", "SdTsCompiler"]);
9
+ /*private readonly _logger = Logger.get(["simplysm", "sd-cli", "SdTsCompiler"]);
13
10
 
14
11
  private readonly _parsedTsConfig: ts.ParsedCommandLine;
15
12
  private readonly _writeFileCache = new Map<string, string>();
@@ -21,81 +18,33 @@ export class SdTsCompiler {
21
18
  private readonly _isForAngular: boolean;
22
19
  private _ngProgram?: NgtscProgram;
23
20
  private readonly _styleDepsCache = new Map<string, Set<string>>();
24
- private _markedChanges: string[] = [];
21
+ private _markedChanges: string[] = [];*/
22
+
23
+ program?: ts.Program;
24
+
25
+ readonly #compiler: SdTsCompiler2;
25
26
 
26
- public get program(): ts.Program {
27
+ readonly #pkgPath: string;
28
+
29
+ /*public get program(): ts.Program {
27
30
  if (!this._program) {
28
31
  throw new Error("TS 프로그램 NULL");
29
32
  }
30
33
  return this._program;
31
- }
32
-
33
- public constructor(private readonly _opt: {
34
- pkgPath: string,
35
- emit: boolean;
36
- emitDts: boolean;
37
- globalStyle: boolean;
38
- }) {
39
- //-- tsconfig
40
- const tsConfigFilePath = path.resolve(_opt.pkgPath, "tsconfig.json");
41
- const tsConfig = FsUtil.readJson(tsConfigFilePath) as ITsConfig;
42
- this._parsedTsConfig = ts.parseJsonConfigFileContent(
43
- tsConfig,
44
- ts.sys,
45
- _opt.pkgPath,
46
- {
47
- ...tsConfig.angularCompilerOptions ?? {},
48
- ..._opt.emitDts !== undefined ? {declaration: _opt.emitDts} : {}
49
- }
34
+ }*/
35
+
36
+ public constructor(pkgPath: string, dev: boolean) {
37
+ this.#pkgPath = pkgPath;
38
+ this.#compiler = new SdTsCompiler2(
39
+ pkgPath,
40
+ {declaration: true},
41
+ dev,
42
+ path.resolve(pkgPath, "src/styles.scss")
50
43
  );
51
-
52
- //-- vars
53
- this._isForAngular = Boolean(tsConfig.angularCompilerOptions);
54
-
55
- //-- host
56
- this._compilerHost = ts.createIncrementalCompilerHost(this._parsedTsConfig.options);
57
- if (tsConfig.angularCompilerOptions) {
58
- this._compilerHost["readResource"] = (fileName: string) => {
59
- return this._compilerHost.readFile(fileName);
60
- };
61
-
62
- this._compilerHost["transformResource"] = async (data: string, context: {
63
- type: string,
64
- containingFile: string,
65
- resourceFile: any
66
- }) => {
67
- if (context.resourceFile != null || context.type !== "style") {
68
- return null;
69
- }
70
-
71
- try {
72
- const scssResult = await sass.compileStringAsync(data, {
73
- url: new URL((context.containingFile as string) + ".scss"),
74
- importer: {
75
- findFileUrl: (url) => pathToFileURL(url)
76
- },
77
- logger: sass.Logger.silent
78
- });
79
-
80
- const styleContent = scssResult.css.toString();
81
-
82
- const deps = scssResult.loadedUrls.slice(1).map((item) => path.resolve(fileURLToPath(item.href)));
83
- for (const dep of deps) {
84
- const depCache = this._styleDepsCache.getOrCreate(dep, new Set<string>());
85
- depCache.add(path.resolve(context.containingFile));
86
- }
87
- return {content: styleContent};
88
- }
89
- catch (err) {
90
- this._logger.error("scss 파싱 에러", err);
91
- return null;
92
- }
93
- };
94
- }
95
44
  }
96
45
 
97
- public markChanges(changes: string[]): void {
98
- this._markedChanges.push(...changes);
46
+ public markChanges(modifiedFileSet: Set<string>): void {
47
+ this.#compiler.invalidate(modifiedFileSet);
99
48
  }
100
49
 
101
50
  public async buildAsync(): Promise<{
@@ -103,11 +52,36 @@ export class SdTsCompiler {
103
52
  affectedFileSet: Set<string>;
104
53
  results: ISdCliPackageBuildResult[];
105
54
  }> {
106
- const markedChanges = this._markedChanges;
55
+ const buildResult = await this.#compiler.buildAsync();
56
+ this.program = buildResult.program;
57
+
58
+ for (const affectedFilePath of buildResult.affectedFileSet) {
59
+ const emittedFiles = buildResult.emittedFilesCacheMap.get(affectedFilePath) ?? [];
60
+ for (const emittedFile of emittedFiles) {
61
+ if (emittedFile.outRelPath != null) {
62
+ const distPath = path.resolve(this.#pkgPath, "dist", emittedFile.outRelPath);
63
+ if (PathUtil.isChildPath(distPath, path.resolve(this.#pkgPath, "dist"))) {
64
+ await FsUtil.writeFileAsync(distPath, emittedFile.text);
65
+ }
66
+ }
67
+ }
68
+
69
+ const globalStylesheetResult = buildResult.stylesheetResultMap.get(affectedFilePath);
70
+ if (globalStylesheetResult) {
71
+ for (const outputFile of globalStylesheetResult.outputFiles) {
72
+ const distPath = path.resolve(this.#pkgPath, "dist", path.relative(this.#pkgPath, outputFile.path));
73
+ if (PathUtil.isChildPath(distPath, path.resolve(this.#pkgPath, "dist"))) {
74
+ await FsUtil.writeFileAsync(distPath, outputFile.text);
75
+ }
76
+ }
77
+ }
78
+ }
79
+
80
+ /*const markedChanges = this._markedChanges;
107
81
  this._markedChanges = [];
108
82
 
109
83
  const distPath = path.resolve(this._opt.pkgPath, "dist");
110
- const srcFilePaths = await FsUtil.globAsync(path.resolve(this._opt.pkgPath, "src/**/*.{ts,tsx}"));
84
+ const srcFilePaths = await FsUtil.globAsync(path.resolve(this._opt.pkgPath, "src/!**!/!*.{ts,tsx}"));
111
85
  const srcFilePathSet = new Set<string>(srcFilePaths);
112
86
 
113
87
  if (this._isForAngular) {
@@ -139,12 +113,12 @@ export class SdTsCompiler {
139
113
  );
140
114
  }
141
115
  else {
142
- /*this._program = ts.createProgram(
116
+ /!*this._program = ts.createProgram(
143
117
  srcFilePaths,
144
118
  this._parsedTsConfig.options,
145
119
  this._compilerHost,
146
120
  this._program
147
- );*/
121
+ );*!/
148
122
 
149
123
  this._builder = ts.createIncrementalProgram({
150
124
  rootNames: srcFilePaths,
@@ -295,22 +269,18 @@ export class SdTsCompiler {
295
269
 
296
270
  this._logger.debug(`[${path.basename(this._opt.pkgPath)}] 영향받는 파일 ${this._opt.emit ? "EMIT" : "CHECK"} 완료`, affectedFileSet);
297
271
 
298
- const buildResults = diagnostics.map((item) => SdCliBuildResultUtil.convertFromTsDiag(item, this._opt.emit ? "build" : "check"));
272
+ const buildResults = diagnostics.map((item) => SdCliBuildResultUtil.convertFromTsDiag(item, this._opt.emit ? "build" : "check"));*/
299
273
 
300
274
  return {
301
- watchFileSet: new Set([
302
- ...Array.from(this._styleDepsCache.keys()),
303
- ...this._builder.getSourceFiles().map(item => path.normalize(item.fileName))
304
- ]),
305
- affectedFileSet: affectedFileSet,
306
- results: buildResults
275
+ watchFileSet: buildResult.watchFileSet,
276
+ affectedFileSet: buildResult.affectedFileSet,
277
+ results: [
278
+ ...buildResult.typescriptDiagnostics.map((item) => SdCliBuildResultUtil.convertFromTsDiag(item, "build")),
279
+ ...Array.from(buildResult.stylesheetResultMap.values()).mapMany(item => item.errors!)
280
+ .map(err => SdCliBuildResultUtil.convertFromEsbuildResult(err, "build", "error")),
281
+ /*...Array.from(buildResult.stylesheetResultMap.values()).mapMany(item => item.warnings!)
282
+ .map(warn => SdCliBuildResultUtil.convertFromEsbuildResult(warn, "build", "warning"))*/
283
+ ]
307
284
  };
308
285
  }
309
-
310
- private _writeFile(filePath: string, data: string): void {
311
- if (this._writeFileCache.get(filePath) !== data) {
312
- this._compilerHost.writeFile(filePath, data, false);
313
- }
314
- this._writeFileCache.set(filePath, data);
315
- }
316
286
  }
@@ -0,0 +1,427 @@
1
+ import ts, {CompilerOptions} from "typescript";
2
+ import path from "path";
3
+ import {FsUtil, PathUtil} from "@simplysm/sd-core-node";
4
+ import {transformSupportedBrowsersToTargets} from "@angular-devkit/build-angular/src/tools/esbuild/utils";
5
+ import browserslist from "browserslist";
6
+ import {
7
+ ComponentStylesheetBundler
8
+ } from "@angular-devkit/build-angular/src/tools/esbuild/angular/component-stylesheets";
9
+ import {AngularCompilerHost} from "@angular-devkit/build-angular/src/tools/esbuild/angular/angular-host";
10
+ import {StringUtil} from "@simplysm/sd-core-common";
11
+ import esbuild from "esbuild";
12
+ import {NgtscProgram, OptimizeFor} from "@angular/compiler-cli";
13
+ import {createHash} from "crypto";
14
+
15
+ export class SdTsCompiler2 {
16
+ readonly #parsedTsconfig: ts.ParsedCommandLine;
17
+ readonly #isForAngular: boolean;
18
+
19
+ readonly #resourceDependencyCacheMap = new Map<string, Set<string>>();
20
+ readonly #sourceFileCacheMap = new Map<string, ts.SourceFile>();
21
+ readonly #emittedFilesCacheMap = new Map<string, {
22
+ outRelPath?: string;
23
+ text: string;
24
+ }[]>();
25
+
26
+ readonly #stylesheetBundler: ComponentStylesheetBundler | undefined;
27
+ readonly #compilerHost: ts.CompilerHost | AngularCompilerHost;
28
+
29
+ #ngProgram: NgtscProgram | undefined;
30
+ #program: ts.Program | undefined;
31
+ #builder: ts.EmitAndSemanticDiagnosticsBuilderProgram | undefined;
32
+
33
+ readonly #modifiedFileSet = new Set<string>();
34
+
35
+ readonly #watchFileSet = new Set<string>();
36
+ readonly #stylesheetResultMap = new Map<string, IStylesheetResult>();
37
+ readonly #affectedFileSet = new Set<string>();
38
+
39
+ readonly #pkgPath: string;
40
+ readonly #distPath: string;
41
+ readonly #globalStyleFilePath?: string;
42
+
43
+ constructor(pkgPath: string,
44
+ additionalOptions: CompilerOptions,
45
+ isDevMode: boolean,
46
+ globalStyleFilePath?: string) {
47
+ this.#pkgPath = pkgPath;
48
+ this.#globalStyleFilePath = globalStyleFilePath != null ? path.normalize(globalStyleFilePath) : undefined;
49
+
50
+ //-- isForAngular / parsedTsConfig
51
+
52
+ const tsconfigPath = path.resolve(pkgPath, "tsconfig.json");
53
+ const tsconfig = FsUtil.readJson(tsconfigPath);
54
+ this.#isForAngular = Boolean(tsconfig.angularCompilerOptions);
55
+ this.#parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, pkgPath, {
56
+ ...tsconfig.angularCompilerOptions,
57
+ ...additionalOptions
58
+ });
59
+
60
+ this.#distPath = this.#parsedTsconfig.options.outDir ?? path.resolve(pkgPath, "dist");
61
+
62
+ //-- compilerHost
63
+
64
+ this.#compilerHost = ts.createIncrementalCompilerHost(this.#parsedTsconfig.options);
65
+
66
+ const baseGetSourceFile = this.#compilerHost.getSourceFile;
67
+ this.#compilerHost.getSourceFile = (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile, ...args) => {
68
+ if (!shouldCreateNewSourceFile && this.#sourceFileCacheMap.has(path.normalize(fileName))) {
69
+ return this.#sourceFileCacheMap.get(path.normalize(fileName));
70
+ }
71
+
72
+ const sf = baseGetSourceFile.call(
73
+ this.#compilerHost,
74
+ fileName,
75
+ languageVersionOrOptions,
76
+ onError,
77
+ true,
78
+ ...args,
79
+ );
80
+
81
+ if (sf) {
82
+ this.#sourceFileCacheMap.set(path.normalize(fileName), sf);
83
+ }
84
+ else {
85
+ this.#sourceFileCacheMap.delete(path.normalize(fileName));
86
+ }
87
+
88
+ return sf;
89
+ };
90
+
91
+ if (this.#isForAngular) {
92
+ //-- stylesheetBundler
93
+
94
+ const browserTarget = transformSupportedBrowsersToTargets(browserslist("defaults and fully supports es6-module"));
95
+ this.#stylesheetBundler = new ComponentStylesheetBundler(
96
+ {
97
+ workspaceRoot: pkgPath,
98
+ optimization: !isDevMode,
99
+ inlineFonts: true,
100
+ preserveSymlinks: false,
101
+ sourcemap: 'inline', //conf.dev ? 'inline' : false,
102
+ outputNames: {bundles: '[name]', media: 'media/[name]'},
103
+ includePaths: [],
104
+ externalDependencies: [],
105
+ target: browserTarget,
106
+ tailwindConfiguration: undefined,
107
+ cacheOptions: {
108
+ enabled: true,
109
+ path: ".cache/angular",
110
+ basePath: ".cache"
111
+ }
112
+ },
113
+ isDevMode
114
+ );
115
+
116
+ //-- compilerHost
117
+
118
+ (this.#compilerHost as AngularCompilerHost).readResource = (fileName: string) => {
119
+ return this.#compilerHost.readFile(fileName) ?? "";
120
+ };
121
+
122
+ (this.#compilerHost as AngularCompilerHost).transformResource = async (data: string, context: {
123
+ type: string,
124
+ containingFile: string,
125
+ resourceFile: string | null
126
+ }) => {
127
+ if (context.type !== "style") {
128
+ return null;
129
+ }
130
+
131
+ const contents = await this.#bundleStylesheetAsync(data, context.containingFile, context.resourceFile);
132
+
133
+ return StringUtil.isNullOrEmpty(contents) ? null : {content: contents};
134
+ };
135
+
136
+ (this.#compilerHost as AngularCompilerHost).getModifiedResourceFiles = () => {
137
+ return this.#modifiedFileSet;
138
+ };
139
+ }
140
+ }
141
+
142
+ async #bundleStylesheetAsync(data: string, containingFile: string, resourceFile: string | null = null) {
143
+ const stylesheetResult = resourceFile != null
144
+ ? await this.#stylesheetBundler!.bundleFile(resourceFile)
145
+ : await this.#stylesheetBundler!.bundleInline(
146
+ data,
147
+ containingFile,
148
+ "scss",
149
+ );
150
+
151
+ this.#watchFileSet.add(path.normalize(containingFile));
152
+ if (resourceFile != null) {
153
+ this.#watchFileSet.add(path.normalize(resourceFile));
154
+ }
155
+
156
+ if (stylesheetResult.referencedFiles) {
157
+ for (const referencedFile of stylesheetResult.referencedFiles) {
158
+ const referencingMapValSet = this.#resourceDependencyCacheMap.getOrCreate(path.normalize(referencedFile), new Set<string>());
159
+ referencingMapValSet.add(path.normalize(containingFile));
160
+ if (resourceFile != null) {
161
+ referencingMapValSet.add(path.normalize(resourceFile));
162
+ }
163
+ }
164
+
165
+ this.#watchFileSet.adds(...Array.from(stylesheetResult.referencedFiles.values()).map(item => path.normalize(item)));
166
+ }
167
+
168
+ this.#stylesheetResultMap.set(path.normalize(resourceFile ?? containingFile), {
169
+ outputFiles: stylesheetResult.outputFiles ?? [],
170
+ metafile: stylesheetResult.metafile,
171
+ errors: stylesheetResult.errors,
172
+ warnings: stylesheetResult.warnings
173
+ });
174
+
175
+ return stylesheetResult.contents;
176
+ }
177
+
178
+ invalidate(modifiedFileSet: Set<string>) {
179
+ this.#stylesheetBundler?.invalidate(modifiedFileSet);
180
+
181
+ for (const modifiedFile of modifiedFileSet) {
182
+ this.#stylesheetResultMap.delete(path.normalize(modifiedFile));
183
+ this.#sourceFileCacheMap.delete(path.normalize(modifiedFile));
184
+ this.#emittedFilesCacheMap.delete(path.normalize(modifiedFile));
185
+
186
+ if (this.#resourceDependencyCacheMap.has(path.normalize(modifiedFile))) {
187
+ for (const referencingFile of this.#resourceDependencyCacheMap.get(path.normalize(modifiedFile))!) {
188
+ this.#stylesheetResultMap.delete(path.normalize(referencingFile));
189
+ this.#sourceFileCacheMap.delete(path.normalize(referencingFile));
190
+ this.#emittedFilesCacheMap.delete(path.normalize(referencingFile));
191
+ }
192
+ }
193
+ }
194
+
195
+ this.#modifiedFileSet.adds(...modifiedFileSet);
196
+ }
197
+
198
+ async buildAsync(): Promise<ISdTsCompiler2Result> {
199
+ this.#resourceDependencyCacheMap.clear();
200
+ this.#watchFileSet.clear();
201
+ this.#stylesheetResultMap.clear();
202
+ this.#affectedFileSet.clear();
203
+
204
+ if (this.#isForAngular) {
205
+ this.#ngProgram = new NgtscProgram(
206
+ this.#parsedTsconfig.fileNames,
207
+ this.#parsedTsconfig.options,
208
+ this.#compilerHost,
209
+ this.#ngProgram
210
+ );
211
+ this.#program = this.#ngProgram.getTsProgram();
212
+ }
213
+ else {
214
+ // noinspection UnnecessaryLocalVariableJS
215
+ this.#program = ts.createProgram(
216
+ this.#parsedTsconfig.fileNames,
217
+ this.#parsedTsconfig.options,
218
+ this.#compilerHost,
219
+ this.#program
220
+ );
221
+ }
222
+
223
+ const baseGetSourceFiles = this.#program.getSourceFiles;
224
+ this.#program.getSourceFiles = function (...parameters) {
225
+ const files: readonly (ts.SourceFile & { version?: string })[] = baseGetSourceFiles(...parameters);
226
+
227
+ for (const file of files) {
228
+ if (file.version === undefined) {
229
+ file.version = createHash("sha256").update(file.text).digest("hex");
230
+ }
231
+ }
232
+
233
+ return files;
234
+ };
235
+
236
+ this.#builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(
237
+ this.#program,
238
+ this.#compilerHost,
239
+ this.#builder
240
+ );
241
+
242
+ if (this.#ngProgram) {
243
+ await this.#ngProgram.compiler.analyzeAsync();
244
+ }
245
+
246
+ //-- affectedFilePathSet
247
+
248
+ while (true) {
249
+ const result = this.#builder.getSemanticDiagnosticsOfNextAffectedFile(undefined, (sourceFile) => {
250
+ if (
251
+ this.#ngProgram
252
+ && this.#ngProgram.compiler.ignoreForDiagnostics.has(sourceFile)
253
+ && sourceFile.fileName.endsWith('.ngtypecheck.ts')
254
+ ) {
255
+ const originalFilename = sourceFile.fileName.slice(0, -15) + '.ts';
256
+ const originalSourceFile = this.#sourceFileCacheMap.get(originalFilename);
257
+ if (originalSourceFile) {
258
+ this.#affectedFileSet.add(path.normalize(originalSourceFile.fileName));
259
+ }
260
+
261
+ return true;
262
+ }
263
+
264
+ return false;
265
+ });
266
+
267
+ if (!result) {
268
+ break;
269
+ }
270
+
271
+ this.#affectedFileSet.add(path.normalize((result.affected as ts.SourceFile).fileName));
272
+ }
273
+
274
+ // Deps -> refMap
275
+
276
+ this.#builder.getSourceFiles().filter(sf => !this.#ngProgram || !this.#ngProgram.compiler.ignoreForEmit.has(sf))
277
+ .forEach(sf => {
278
+ this.#watchFileSet.add(path.normalize(sf.fileName));
279
+
280
+ if (this.#ngProgram) {
281
+ const deps = this.#ngProgram.compiler.getResourceDependencies(sf);
282
+ for (const dep of deps) {
283
+ const ref = this.#resourceDependencyCacheMap.getOrCreate(path.normalize(dep), new Set<string>());
284
+ ref.add(path.normalize(sf.fileName));
285
+
286
+ this.#watchFileSet.add(path.normalize(dep));
287
+ }
288
+ }
289
+ });
290
+
291
+ //-- diagnostics
292
+
293
+ const diagnostics: ts.Diagnostic[] = [];
294
+
295
+ diagnostics.push(
296
+ ...this.#builder.getConfigFileParsingDiagnostics(),
297
+ ...this.#builder.getOptionsDiagnostics(),
298
+ ...this.#builder.getGlobalDiagnostics()
299
+ );
300
+
301
+ if (this.#ngProgram) {
302
+ diagnostics.push(...this.#ngProgram.compiler.getOptionDiagnostics());
303
+ }
304
+
305
+ for (const affectedFile of this.#affectedFileSet) {
306
+ const affectedSourceFile = this.#sourceFileCacheMap.get(affectedFile);
307
+ if (!affectedSourceFile || (this.#ngProgram && this.#ngProgram.compiler.ignoreForDiagnostics.has(affectedSourceFile))) {
308
+ continue;
309
+ }
310
+
311
+ diagnostics.push(
312
+ ...this.#builder.getSyntacticDiagnostics(affectedSourceFile),
313
+ ...this.#builder.getSemanticDiagnostics(affectedSourceFile)
314
+ );
315
+
316
+ if (this.#ngProgram) {
317
+ if (affectedSourceFile.isDeclarationFile) {
318
+ continue;
319
+ }
320
+
321
+ diagnostics.push(
322
+ ...this.#ngProgram.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram),
323
+ );
324
+ }
325
+ }
326
+
327
+ //-- prepare emit cache
328
+
329
+ while (true) {
330
+ const affectedFileResult = this.#builder.emitNextAffectedFile((fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
331
+ if (!sourceFiles || sourceFiles.length === 0) {
332
+ this.#compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
333
+ return;
334
+ }
335
+
336
+ const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
337
+
338
+ if (this.#ngProgram) {
339
+ if (this.#ngProgram.compiler.ignoreForEmit.has(sourceFile)) {
340
+ return;
341
+ }
342
+ this.#ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
343
+ }
344
+
345
+ const emittedFiles = this.#emittedFilesCacheMap.getOrCreate(path.normalize(sourceFile.fileName), []);
346
+ if (PathUtil.isChildPath(sourceFile.fileName, this.#pkgPath)) {
347
+ let realFilePath = fileName;
348
+ let realText = text;
349
+ if (PathUtil.isChildPath(realFilePath, path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"))) {
350
+ realFilePath = path.resolve(this.#distPath, path.relative(path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"), realFilePath));
351
+
352
+ if (fileName.endsWith(".js.map")) {
353
+ const sourceMapContents = JSON.parse(realText);
354
+ // remove "../../"
355
+ sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6);
356
+ realText = JSON.stringify(sourceMapContents);
357
+ }
358
+ }
359
+
360
+ emittedFiles.push({
361
+ outRelPath: path.relative(this.#distPath, realFilePath),
362
+ text: realText
363
+ });
364
+ }
365
+ else {
366
+ emittedFiles.push({text});
367
+ }
368
+ }, undefined, undefined, this.#ngProgram?.compiler.prepareEmit().transformers);
369
+
370
+ if (!affectedFileResult) {
371
+ break;
372
+ }
373
+
374
+ diagnostics.push(...affectedFileResult.result.diagnostics);
375
+ }
376
+
377
+ //-- global style
378
+ if (
379
+ this.#globalStyleFilePath != null
380
+ && !this.#stylesheetResultMap.has(this.#globalStyleFilePath)
381
+ && FsUtil.exists(this.#globalStyleFilePath)
382
+ ) {
383
+ const data = await FsUtil.readFileAsync(this.#globalStyleFilePath);
384
+ const contents = await this.#bundleStylesheetAsync(data, this.#globalStyleFilePath, this.#globalStyleFilePath);
385
+ const emittedFiles = this.#emittedFilesCacheMap.getOrCreate(path.normalize(this.#globalStyleFilePath), []);
386
+ emittedFiles.push({
387
+ outRelPath: path.relative(path.resolve(this.#pkgPath, "src"), this.#globalStyleFilePath).replace(/\.scss$/, ".css"),
388
+ text: contents
389
+ });
390
+ this.#affectedFileSet.add(this.#globalStyleFilePath);
391
+ }
392
+
393
+ //-- init
394
+
395
+ this.#modifiedFileSet.clear();
396
+
397
+ //-- result
398
+
399
+ return {
400
+ program: this.#program,
401
+ typescriptDiagnostics: diagnostics,
402
+ stylesheetResultMap: this.#stylesheetResultMap,
403
+ emittedFilesCacheMap: this.#emittedFilesCacheMap,
404
+ watchFileSet: this.#watchFileSet,
405
+ affectedFileSet: this.#affectedFileSet
406
+ };
407
+ }
408
+ }
409
+
410
+ export interface ISdTsCompiler2Result {
411
+ program: ts.Program,
412
+ typescriptDiagnostics: ts.Diagnostic[],
413
+ stylesheetResultMap: Map<string, IStylesheetResult>,
414
+ emittedFilesCacheMap: Map<string, {
415
+ outRelPath?: string;
416
+ text: string;
417
+ }[]>,
418
+ watchFileSet: Set<string>,
419
+ affectedFileSet: Set<string>
420
+ }
421
+
422
+ interface IStylesheetResult {
423
+ outputFiles: esbuild.OutputFile[];
424
+ metafile?: esbuild.Metafile;
425
+ errors?: esbuild.PartialMessage[];
426
+ warnings?: esbuild.PartialMessage[];
427
+ }
@@ -35,7 +35,7 @@ export class SdCliTsLibBuilder extends EventEmitter {
35
35
  await SdCliIndexFileGenerator.runAsync(this._pkgPath, this._pkgConf.polyfills);
36
36
  }
37
37
 
38
- const result = await this._runAsync();
38
+ const result = await this._runAsync(false);
39
39
  return {
40
40
  affectedFilePaths: Array.from(result.affectedFileSet),
41
41
  buildResults: result.buildResults
@@ -53,7 +53,7 @@ export class SdCliTsLibBuilder extends EventEmitter {
53
53
  await SdCliIndexFileGenerator.watchAsync(this._pkgPath, this._pkgConf.polyfills);
54
54
  }
55
55
 
56
- const result = await this._runAsync();
56
+ const result = await this._runAsync(true);
57
57
  this.emit("complete", {
58
58
  affectedFilePaths: Array.from(result.affectedFileSet),
59
59
  buildResults: result.buildResults
@@ -64,12 +64,12 @@ export class SdCliTsLibBuilder extends EventEmitter {
64
64
  const watcher = SdFsWatcher
65
65
  .watch(Array.from(result.watchFileSet))
66
66
  .onChange({delay: 100,}, (changeInfos) => {
67
- this._builder!.markChanges(changeInfos.map((item) => item.path));
67
+ this._builder!.markChanges(new Set(changeInfos.map((item) => item.path)));
68
68
 
69
69
  fnQ.runLast(async () => {
70
70
  this.emit("change");
71
71
 
72
- const watchResult = await this._runAsync();
72
+ const watchResult = await this._runAsync(true);
73
73
  this.emit("complete", {
74
74
  affectedFilePaths: Array.from(watchResult.affectedFileSet),
75
75
  buildResults: watchResult.buildResults
@@ -80,18 +80,13 @@ export class SdCliTsLibBuilder extends EventEmitter {
80
80
  });
81
81
  }
82
82
 
83
- private async _runAsync(): Promise<{
83
+ private async _runAsync(dev: boolean): Promise<{
84
84
  watchFileSet: Set<string>;
85
85
  affectedFileSet: Set<string>;
86
86
  buildResults: ISdCliPackageBuildResult[];
87
87
  }> {
88
88
  this._debug(`BUILD & CHECK...`);
89
- this._builder = this._builder ?? new SdTsCompiler({
90
- pkgPath: this._pkgPath,
91
- emit: true,
92
- emitDts: true,
93
- globalStyle: true
94
- });
89
+ this._builder = this._builder ?? new SdTsCompiler(this._pkgPath, dev);
95
90
  const buildResult = await this._builder.buildAsync();
96
91
 
97
92
  this._debug("LINT...");