@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.
- package/dist/build-cluster.js +16 -3
- package/dist/build-cluster.js.map +1 -1
- package/dist/build-tools/SdNgBundler.d.ts +1 -1
- package/dist/build-tools/SdNgBundler.js +4 -1
- package/dist/build-tools/SdNgBundler.js.map +1 -1
- package/dist/build-tools/SdServerBundler.js.map +1 -1
- package/dist/build-tools/SdTsCompiler.d.ts +5 -21
- package/dist/build-tools/SdTsCompiler.js +211 -188
- package/dist/build-tools/SdTsCompiler.js.map +1 -1
- package/dist/build-tools2/SdTsCompiler2.d.ts +26 -0
- package/dist/build-tools2/SdTsCompiler2.js +280 -0
- package/dist/build-tools2/SdTsCompiler2.js.map +1 -0
- package/dist/builders/SdCliTsLibBuilder.js +6 -11
- package/dist/builders/SdCliTsLibBuilder.js.map +1 -1
- package/dist/bundle-plugins/sdNgPlugin.d.ts +3 -3
- package/dist/bundle-plugins/sdNgPlugin.js +22 -212
- package/dist/bundle-plugins/sdNgPlugin.js.map +1 -1
- package/dist/bundle-plugins/sdServerPlugin.d.ts +2 -2
- package/dist/bundle-plugins/sdServerPlugin.js +17 -110
- package/dist/bundle-plugins/sdServerPlugin.js.map +1 -1
- package/dist/commons.d.ts +1 -0
- package/dist/entry/SdCliProject.d.ts +1 -0
- package/dist/entry/SdCliProject.js +11 -29
- package/dist/entry/SdCliProject.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/sd-cli.js +7 -1
- package/dist/sd-cli.js.map +1 -1
- package/dist/server-worker.js.map +1 -1
- package/dist/utils/SdCliBuildResultUtil.d.ts +10 -0
- package/dist/utils/SdCliBuildResultUtil.js +17 -1
- package/dist/utils/SdCliBuildResultUtil.js.map +1 -1
- package/package.json +15 -15
- package/src/build-cluster.ts +18 -4
- package/src/build-tools/SdNgBundler.ts +7 -4
- package/src/build-tools/SdServerBundler.ts +2 -2
- package/src/build-tools/SdTsCompiler.ts +64 -94
- package/src/build-tools2/SdTsCompiler2.ts +427 -0
- package/src/builders/SdCliTsLibBuilder.ts +6 -11
- package/src/bundle-plugins/sdNgPlugin.ts +26 -320
- package/src/bundle-plugins/sdServerPlugin.ts +20 -168
- package/src/commons.ts +1 -0
- package/src/entry/SdCliProject.ts +12 -30
- package/src/index.ts +1 -0
- package/src/sd-cli.ts +7 -1
- package/src/server-worker.ts +3 -3
- 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 {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
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
|
-
|
|
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(
|
|
34
|
-
pkgPath
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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(
|
|
98
|
-
this.
|
|
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
|
|
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
|
|
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
|
-
|
|
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:
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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...");
|