@simplysm/sd-cli 12.8.20 → 12.8.22
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/entry/sd-cli-cordova.d.ts +30 -0
- package/dist/entry/sd-cli-cordova.js +307 -246
- package/dist/entry/sd-cli-cordova.js.map +1 -1
- package/dist/entry/sd-cli-project.d.ts +1 -1
- package/dist/entry/sd-cli-project.js +8 -9
- package/dist/entry/sd-cli-project.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/pkg-builders/client/sd-ng.bundler.d.ts +15 -1
- package/dist/pkg-builders/client/sd-ng.bundler.js +60 -70
- package/dist/pkg-builders/client/sd-ng.bundler.js.map +1 -1
- package/dist/pkg-builders/client/sd-ng.plugin-creator.js +49 -29
- package/dist/pkg-builders/client/sd-ng.plugin-creator.js.map +1 -1
- package/dist/pkg-builders/lib/sd-ts-lib.builder.js +7 -4
- package/dist/pkg-builders/lib/sd-ts-lib.builder.js.map +1 -1
- package/dist/pkg-builders/server/sd-server.bundler.js +11 -10
- package/dist/pkg-builders/server/sd-server.bundler.js.map +1 -1
- package/dist/ts-compiler/sd-ts-compiler.d.ts +25 -2
- package/dist/ts-compiler/sd-ts-compiler.js +306 -575
- package/dist/ts-compiler/sd-ts-compiler.js.map +1 -1
- package/dist/ts-compiler/sd-ts-dependency-analyzer.d.ts +6 -0
- package/dist/ts-compiler/sd-ts-dependency-analyzer.js +141 -0
- package/dist/ts-compiler/sd-ts-dependency-analyzer.js.map +1 -0
- package/dist/types/ts-compiler.types.d.ts +12 -7
- package/dist/types/worker.types.d.ts +13 -0
- package/dist/utils/sd-cli-performance-time.js +1 -1
- package/package.json +6 -8
- package/src/entry/sd-cli-cordova.ts +393 -280
- package/src/entry/sd-cli-project.ts +11 -23
- package/src/index.ts +1 -0
- package/src/pkg-builders/client/sd-ng.bundler.ts +67 -69
- package/src/pkg-builders/client/sd-ng.plugin-creator.ts +47 -27
- package/src/pkg-builders/lib/sd-ts-lib.builder.ts +14 -7
- package/src/pkg-builders/server/sd-server.bundler.ts +22 -12
- package/src/ts-compiler/sd-ts-compiler.ts +379 -704
- package/src/ts-compiler/sd-ts-dependency-analyzer.ts +185 -0
- package/src/types/ts-compiler.types.ts +11 -6
- package/src/types/worker.types.ts +7 -6
- package/src/utils/sd-cli-performance-time.ts +1 -1
|
@@ -11,76 +11,31 @@ import { SdCliPerformanceTimer } from "../utils/sd-cli-performance-time";
|
|
|
11
11
|
import { SdCliConvertMessageUtils } from "../utils/sd-cli-convert-message.utils";
|
|
12
12
|
import { createWorkerTransformer, } from "@angular/build/src/tools/angular/transformers/web-worker-transformer";
|
|
13
13
|
import { ESLint } from "eslint";
|
|
14
|
+
import { SdTsDependencyAnalyzer } from "./sd-ts-dependency-analyzer";
|
|
14
15
|
export class SdTsCompiler {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
#affectedFileSet = new Set();
|
|
29
|
-
#watchFileSet = new Set();
|
|
30
|
-
#stylesheetBundlingResultMap = new Map();
|
|
31
|
-
#pkgPath;
|
|
32
|
-
#distPath;
|
|
33
|
-
#globalStyleFilePath;
|
|
34
|
-
#watchScopePaths;
|
|
35
|
-
#isForBundle;
|
|
36
|
-
// readonly #lintWorker = new SdWorker<TSdLintWorkerType>(import.meta.resolve("../workers/lint-worker"));
|
|
37
|
-
#perf;
|
|
38
|
-
// #processWebWorker?: (workerFile: string, containingFile: string) => string;
|
|
39
|
-
constructor(opt) {
|
|
40
|
-
this.#pkgPath = opt.pkgPath;
|
|
41
|
-
this.#globalStyleFilePath = opt.globalStyleFilePath;
|
|
42
|
-
this.#isForBundle = opt.isForBundle;
|
|
43
|
-
this.#watchScopePaths = opt.watchScopePaths;
|
|
44
|
-
// this.#processWebWorker = opt.processWebWorker;
|
|
45
|
-
this.#debug("초기화...");
|
|
46
|
-
//-- isForAngular / parsedTsConfig
|
|
47
|
-
const tsconfigPath = path.resolve(opt.pkgPath, "tsconfig.json");
|
|
16
|
+
constructor(_opt) {
|
|
17
|
+
this._opt = _opt;
|
|
18
|
+
this._logger = SdLogger.get(["simplysm", "sd-cli", "SdTsCompiler"]);
|
|
19
|
+
this._allDepCacheMap = new Map();
|
|
20
|
+
this._revDepCacheMap = new Map();
|
|
21
|
+
this._sourceFileCacheMap = new Map();
|
|
22
|
+
this._emittedFilesCacheMap = new Map();
|
|
23
|
+
this._modifiedFileSet = new Set();
|
|
24
|
+
this._affectedFileSet = new Set();
|
|
25
|
+
this._watchFileSet = new Set();
|
|
26
|
+
this._stylesheetBundlingResultMap = new Map();
|
|
27
|
+
this._debug("초기화 중...");
|
|
28
|
+
const tsconfigPath = path.resolve(this._opt.pkgPath, "tsconfig.json");
|
|
48
29
|
const tsconfig = FsUtils.readJson(tsconfigPath);
|
|
49
|
-
this
|
|
50
|
-
|
|
51
|
-
...tsconfig.angularCompilerOptions,
|
|
52
|
-
...opt.additionalOptions,
|
|
53
|
-
});
|
|
54
|
-
this.#distPath = PathUtils.norm(this.#parsedTsconfig.options.outDir ?? path.resolve(opt.pkgPath, "dist"));
|
|
55
|
-
//-- compilerHost
|
|
56
|
-
this.#compilerHost = ts.createCompilerHost(this.#parsedTsconfig.options);
|
|
57
|
-
const baseGetSourceFile = this.#compilerHost.getSourceFile;
|
|
58
|
-
this.#compilerHost.getSourceFile = (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile, ...args) => {
|
|
59
|
-
if (!shouldCreateNewSourceFile && this.#sourceFileCacheMap.has(PathUtils.norm(fileName))) {
|
|
60
|
-
return this.#sourceFileCacheMap.get(PathUtils.norm(fileName));
|
|
61
|
-
}
|
|
62
|
-
const sf = baseGetSourceFile.call(this.#compilerHost, fileName, languageVersionOrOptions, onError, true, ...args);
|
|
63
|
-
if (sf) {
|
|
64
|
-
this.#sourceFileCacheMap.set(PathUtils.norm(fileName), sf);
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
this.#sourceFileCacheMap.delete(PathUtils.norm(fileName));
|
|
68
|
-
}
|
|
69
|
-
return sf;
|
|
70
|
-
};
|
|
71
|
-
const baseReadFile = this.#compilerHost.readFile;
|
|
72
|
-
this.#compilerHost.readFile = (fileName) => {
|
|
73
|
-
this.#watchFileSet.add(PathUtils.norm(fileName));
|
|
74
|
-
return baseReadFile.call(this.#compilerHost, fileName);
|
|
75
|
-
};
|
|
76
|
-
if (this.#isForAngular) {
|
|
30
|
+
this._isForAngular = Boolean(tsconfig.angularCompilerOptions);
|
|
31
|
+
if (this._isForAngular) {
|
|
77
32
|
//-- stylesheetBundler
|
|
78
|
-
this
|
|
79
|
-
workspaceRoot:
|
|
80
|
-
optimization: !
|
|
33
|
+
this._stylesheetBundler = new ComponentStylesheetBundler({
|
|
34
|
+
workspaceRoot: this._opt.pkgPath,
|
|
35
|
+
optimization: !this._opt.isDevMode,
|
|
81
36
|
inlineFonts: true,
|
|
82
37
|
preserveSymlinks: false,
|
|
83
|
-
sourcemap:
|
|
38
|
+
sourcemap: this._opt.isDevMode ? "inline" : false,
|
|
84
39
|
outputNames: { bundles: "[name]", media: "media/[name]" },
|
|
85
40
|
includePaths: [],
|
|
86
41
|
externalDependencies: [],
|
|
@@ -94,53 +49,116 @@ export class SdTsCompiler {
|
|
|
94
49
|
path: ".cache/angular",
|
|
95
50
|
basePath: ".cache",
|
|
96
51
|
},
|
|
97
|
-
}, "scss",
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
52
|
+
}, "scss", this._opt.isDevMode);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
_parseTsConfig() {
|
|
56
|
+
const config = this._loadTsConfig();
|
|
57
|
+
const compilerHost = this._createCompilerHost(config.options);
|
|
58
|
+
return {
|
|
59
|
+
...config,
|
|
60
|
+
compilerHost,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
_loadTsConfig() {
|
|
64
|
+
const tsconfigPath = path.resolve(this._opt.pkgPath, "tsconfig.json");
|
|
65
|
+
const tsconfig = FsUtils.readJson(tsconfigPath);
|
|
66
|
+
const parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this._opt.pkgPath, {
|
|
67
|
+
...tsconfig.angularCompilerOptions,
|
|
68
|
+
...this._opt.additionalOptions,
|
|
69
|
+
});
|
|
70
|
+
const distPath = PathUtils.norm(parsedTsconfig.options.outDir ?? path.resolve(this._opt.pkgPath, "dist"));
|
|
71
|
+
return {
|
|
72
|
+
fileNames: parsedTsconfig.fileNames,
|
|
73
|
+
options: parsedTsconfig.options,
|
|
74
|
+
distPath: distPath,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
_createCompilerHost(compilerOptions) {
|
|
78
|
+
const compilerHost = ts.createCompilerHost(compilerOptions);
|
|
79
|
+
const baseGetSourceFile = compilerHost.getSourceFile;
|
|
80
|
+
compilerHost.getSourceFile = (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile, ...args) => {
|
|
81
|
+
const fileNPath = PathUtils.norm(fileName);
|
|
82
|
+
if (!shouldCreateNewSourceFile && this._sourceFileCacheMap.has(fileNPath)) {
|
|
83
|
+
return this._sourceFileCacheMap.get(fileNPath);
|
|
84
|
+
}
|
|
85
|
+
const sf = baseGetSourceFile.call(compilerHost, fileName, languageVersionOrOptions, onError, true, ...args);
|
|
86
|
+
if (sf) {
|
|
87
|
+
this._sourceFileCacheMap.set(fileNPath, sf);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
this._sourceFileCacheMap.delete(fileNPath);
|
|
91
|
+
}
|
|
92
|
+
return sf;
|
|
93
|
+
};
|
|
94
|
+
const baseReadFile = compilerHost.readFile;
|
|
95
|
+
compilerHost.readFile = (fileName) => {
|
|
96
|
+
this._watchFileSet.add(PathUtils.norm(fileName));
|
|
97
|
+
return baseReadFile.call(compilerHost, fileName);
|
|
98
|
+
};
|
|
99
|
+
if (this._isForAngular) {
|
|
100
|
+
compilerHost.readResource = (fileName) => {
|
|
101
|
+
return compilerHost.readFile(fileName) ?? "";
|
|
101
102
|
};
|
|
102
|
-
|
|
103
|
+
compilerHost.transformResource = async (data, context) => {
|
|
103
104
|
if (context.type !== "style") {
|
|
104
105
|
return null;
|
|
105
106
|
}
|
|
106
|
-
const
|
|
107
|
-
return StringUtils.isNullOrEmpty(contents)
|
|
107
|
+
const stylesheetBundlingResult = await this._bundleStylesheetAsync(data, PathUtils.norm(context.containingFile), context.resourceFile != null ? PathUtils.norm(context.resourceFile) : undefined);
|
|
108
|
+
return StringUtils.isNullOrEmpty(stylesheetBundlingResult.contents)
|
|
109
|
+
? null
|
|
110
|
+
: { content: stylesheetBundlingResult.contents };
|
|
108
111
|
};
|
|
109
|
-
|
|
110
|
-
return new Set(Array.from(this
|
|
112
|
+
compilerHost.getModifiedResourceFiles = () => {
|
|
113
|
+
return new Set(Array.from(this._modifiedFileSet).map((item) => PathUtils.posix(item)));
|
|
111
114
|
};
|
|
112
115
|
}
|
|
116
|
+
return compilerHost;
|
|
113
117
|
}
|
|
114
|
-
async
|
|
118
|
+
async _bundleStylesheetAsync(data, containingFile, resourceFile = null) {
|
|
115
119
|
// containingFile: 포함된 파일 (.ts)
|
|
116
120
|
// resourceFile: 외부 리소스 파일 (styleUrls로 입력하지 않고 styles에 직접 입력한 경우 null)
|
|
117
121
|
// referencedFiles: import한 외부 scss 파일 혹은 woff파일등 외부 파일
|
|
118
122
|
// this.#debug(`bundle stylesheet...(${containingFile}, ${resourceFile})`);
|
|
119
|
-
return await this
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
123
|
+
return await this._perf.run("스타일 번들링", async () => {
|
|
124
|
+
const fileNPath = PathUtils.norm(resourceFile ?? containingFile);
|
|
125
|
+
if (this._stylesheetBundlingResultMap.has(fileNPath)) {
|
|
126
|
+
return this._stylesheetBundlingResultMap.get(fileNPath);
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
const result = resourceFile != null
|
|
130
|
+
? await this._stylesheetBundler.bundleFile(resourceFile)
|
|
131
|
+
: await this._stylesheetBundler.bundleInline(data, containingFile, "scss");
|
|
132
|
+
if (result.referencedFiles) {
|
|
133
|
+
for (const referencedFile of result.referencedFiles) {
|
|
134
|
+
const depCacheSet = this._revDepCacheMap.getOrCreate(PathUtils.norm(referencedFile), new Set());
|
|
135
|
+
depCacheSet.add(fileNPath);
|
|
136
|
+
}
|
|
137
|
+
this._watchFileSet.adds(...Array.from(result.referencedFiles.values())
|
|
138
|
+
.map((item) => PathUtils.norm(item)));
|
|
127
139
|
}
|
|
128
|
-
this
|
|
129
|
-
|
|
140
|
+
this._stylesheetBundlingResultMap.set(fileNPath, result);
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
const result = {
|
|
145
|
+
errors: [
|
|
146
|
+
{
|
|
147
|
+
text: `스타일 번들링 실패: ${err.message ?? "알 수 없는 오류"}`,
|
|
148
|
+
location: { file: containingFile },
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
warnings: [],
|
|
152
|
+
};
|
|
153
|
+
this._stylesheetBundlingResultMap.set(fileNPath, result);
|
|
154
|
+
return result;
|
|
130
155
|
}
|
|
131
|
-
this.#stylesheetBundlingResultMap.set(PathUtils.norm(resourceFile ?? containingFile), {
|
|
132
|
-
outputFiles: stylesheetResult.errors == null ? stylesheetResult.outputFiles : undefined,
|
|
133
|
-
metafile: stylesheetResult.errors == null ? stylesheetResult.metafile : undefined,
|
|
134
|
-
errors: stylesheetResult.errors,
|
|
135
|
-
warnings: stylesheetResult.warnings,
|
|
136
|
-
});
|
|
137
|
-
return stylesheetResult.contents;
|
|
138
156
|
});
|
|
139
157
|
}
|
|
140
158
|
async compileAsync(modifiedFileSet) {
|
|
141
|
-
this
|
|
142
|
-
this
|
|
143
|
-
this
|
|
159
|
+
this._perf = new SdCliPerformanceTimer("esbuild compile");
|
|
160
|
+
this._modifiedFileSet = new Set(modifiedFileSet);
|
|
161
|
+
this._affectedFileSet = new Set();
|
|
144
162
|
/*for (const mod of modifiedFileSet) {
|
|
145
163
|
const workerImporters = this.#workerRevDependencyCacheMap.get(mod);
|
|
146
164
|
if (workerImporters) {
|
|
@@ -149,146 +167,156 @@ export class SdTsCompiler {
|
|
|
149
167
|
this.#modifiedFileSet.add(mod);
|
|
150
168
|
}
|
|
151
169
|
}*/
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
|
|
170
|
+
const tsconf = this._parseTsConfig();
|
|
171
|
+
const prepareResult = await this._prepareAsync(tsconf);
|
|
172
|
+
const [buildResult, lintResults] = await Promise.all([
|
|
173
|
+
this._buildAsync(tsconf),
|
|
174
|
+
this._lintAsync(),
|
|
175
|
+
]);
|
|
176
|
+
this._debug(`빌드 완료됨`, this._perf.toString());
|
|
177
|
+
this._debug(`영향 받은 파일: ${this._affectedFileSet.size}개`);
|
|
178
|
+
this._debug(`감시 중인 파일: ${this._watchFileSet.size}개`);
|
|
155
179
|
return {
|
|
156
180
|
messages: [
|
|
157
181
|
...prepareResult.messages,
|
|
158
182
|
...SdCliConvertMessageUtils.convertToBuildMessagesFromTsDiag(buildResult.diagnostics),
|
|
159
183
|
...SdCliConvertMessageUtils.convertToBuildMessagesFromEslint(lintResults),
|
|
160
184
|
],
|
|
161
|
-
watchFileSet: this
|
|
162
|
-
affectedFileSet: this
|
|
163
|
-
stylesheetBundlingResultMap: this
|
|
164
|
-
emittedFilesCacheMap: this
|
|
185
|
+
watchFileSet: this._watchFileSet,
|
|
186
|
+
affectedFileSet: this._affectedFileSet,
|
|
187
|
+
stylesheetBundlingResultMap: this._stylesheetBundlingResultMap,
|
|
188
|
+
emittedFilesCacheMap: this._emittedFilesCacheMap,
|
|
165
189
|
emitFileSet: buildResult.emitFileSet,
|
|
166
190
|
};
|
|
167
191
|
}
|
|
168
|
-
async
|
|
169
|
-
if (this
|
|
170
|
-
this
|
|
171
|
-
this
|
|
172
|
-
for (const modifiedFile of this
|
|
173
|
-
this
|
|
174
|
-
this
|
|
175
|
-
|
|
192
|
+
async _prepareAsync(tsconf) {
|
|
193
|
+
if (this._modifiedFileSet.size !== 0) {
|
|
194
|
+
this._debug(`영향 받은 파일 추적 중... (구 의존성)`);
|
|
195
|
+
this._perf.run("영향 받은 파일 추적", () => {
|
|
196
|
+
for (const modifiedFile of this._modifiedFileSet) {
|
|
197
|
+
this._affectedFileSet.add(modifiedFile);
|
|
198
|
+
this._affectedFileSet.adds(...(this._revDepCacheMap.get(modifiedFile) ?? []));
|
|
199
|
+
// .d.ts → .js 대응
|
|
200
|
+
if (modifiedFile.endsWith(".d.ts")) {
|
|
201
|
+
const jsEquivalent = PathUtils.norm(modifiedFile.replace(/\.d\.ts$/, ".js"));
|
|
202
|
+
this._affectedFileSet.add(jsEquivalent);
|
|
203
|
+
}
|
|
176
204
|
}
|
|
177
205
|
});
|
|
178
|
-
this
|
|
179
|
-
this
|
|
180
|
-
this
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
206
|
+
this._debug(`캐시 무효화 및 초기화 중...`);
|
|
207
|
+
this._perf.run("캐시 무효화 및 초기화", () => {
|
|
208
|
+
this._stylesheetBundler?.invalidate(this._affectedFileSet);
|
|
209
|
+
const toDeleteSet = new Set();
|
|
210
|
+
// 초기: 명시적으로 수정된 파일들
|
|
211
|
+
for (const file of this._affectedFileSet) {
|
|
212
|
+
toDeleteSet.add(file);
|
|
213
|
+
// 역방향으로 영향을 받는 파일들도 포함
|
|
214
|
+
const dependents = this._revDepCacheMap.get(file);
|
|
215
|
+
if (dependents) {
|
|
216
|
+
for (const dep of dependents) {
|
|
217
|
+
toDeleteSet.add(dep);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
for (const toDeleteFile of toDeleteSet) {
|
|
222
|
+
this._emittedFilesCacheMap.delete(toDeleteFile);
|
|
223
|
+
this._sourceFileCacheMap.delete(toDeleteFile);
|
|
224
|
+
this._stylesheetBundlingResultMap.delete(toDeleteFile);
|
|
225
|
+
this._watchFileSet.delete(toDeleteFile);
|
|
226
|
+
this._allDepCacheMap.delete(toDeleteFile);
|
|
227
|
+
this._revDepCacheMap.delete(toDeleteFile);
|
|
228
|
+
}
|
|
229
|
+
for (const [key, deps] of this._revDepCacheMap) {
|
|
230
|
+
for (const file of toDeleteSet) {
|
|
231
|
+
deps.delete(file);
|
|
232
|
+
}
|
|
233
|
+
if (deps.size === 0) {
|
|
234
|
+
this._revDepCacheMap.delete(key);
|
|
235
|
+
}
|
|
186
236
|
}
|
|
187
|
-
this.#revDependencyCacheMap.clear();
|
|
188
|
-
this.#resourceDependencyCacheMap.clear();
|
|
189
237
|
});
|
|
190
238
|
}
|
|
191
|
-
this
|
|
192
|
-
this
|
|
193
|
-
if (this
|
|
194
|
-
this
|
|
195
|
-
this
|
|
239
|
+
this._debug(`ts.Program 생성 중...`);
|
|
240
|
+
this._perf.run("ts.Program 생성", () => {
|
|
241
|
+
if (this._isForAngular) {
|
|
242
|
+
this._ngProgram = new NgtscProgram(tsconf.fileNames, tsconf.options, tsconf.compilerHost, this._ngProgram);
|
|
243
|
+
this._program = this._ngProgram.getTsProgram();
|
|
196
244
|
}
|
|
197
245
|
else {
|
|
198
|
-
this
|
|
246
|
+
this._program = ts.createProgram(tsconf.fileNames, tsconf.options, tsconf.compilerHost, this._program);
|
|
199
247
|
}
|
|
200
248
|
});
|
|
201
|
-
if (this
|
|
202
|
-
await this
|
|
203
|
-
await this
|
|
249
|
+
if (this._ngProgram) {
|
|
250
|
+
await this._perf.run("Angular 템플릿 분석", async () => {
|
|
251
|
+
await this._ngProgram.compiler.analyzeAsync();
|
|
204
252
|
});
|
|
205
253
|
}
|
|
206
|
-
|
|
207
|
-
if (sf.fileName.endsWith(".ngtypecheck.ts")) {
|
|
208
|
-
const orgFileName = sf.fileName.slice(0, -15) + ".ts";
|
|
209
|
-
return this.#program.getSourceFile(orgFileName);
|
|
210
|
-
}
|
|
211
|
-
return sf;
|
|
212
|
-
};
|
|
213
|
-
const sourceFileSet = new Set(this.#program.getSourceFiles()
|
|
214
|
-
.map((sf) => getOrgSourceFile(sf))
|
|
215
|
-
.filterExists());
|
|
216
|
-
this.#debug(`get new deps...`);
|
|
254
|
+
this._debug(`새 의존성 분석 중...`);
|
|
217
255
|
const messages = [];
|
|
218
|
-
this
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const refs = this.#findDeps(sf);
|
|
225
|
-
messages.push(...refs.filter((item) => "severity" in item));
|
|
226
|
-
depMap.set(PathUtils.norm(sf.fileName), refs
|
|
227
|
-
.filter((item) => "fileName" in item)
|
|
228
|
-
.filter((item) => this.#watchScopePaths.some((scopePath) => PathUtils.isChildPath(item.fileName, scopePath))));
|
|
229
|
-
}
|
|
230
|
-
const allDepMap = new Map();
|
|
231
|
-
const getAllDeps = (fileName, prevSet) => {
|
|
232
|
-
if (allDepMap.has(fileName)) {
|
|
233
|
-
return allDepMap.get(fileName);
|
|
234
|
-
}
|
|
235
|
-
const result = new Set();
|
|
236
|
-
const deps = depMap.get(fileName) ?? [];
|
|
237
|
-
result.adds(...deps.map((item) => item.fileName));
|
|
256
|
+
this._perf.run("새 의존성 분석", () => {
|
|
257
|
+
const analysed = SdTsDependencyAnalyzer.analyze(this._program, tsconf.compilerHost, this._opt.watchScopePaths, this._allDepCacheMap);
|
|
258
|
+
messages.push(...analysed);
|
|
259
|
+
for (const fileNPath of this._allDepCacheMap.keys()) {
|
|
260
|
+
// const filePath = PathUtils.norm(sf.fileName);
|
|
261
|
+
const deps = this._allDepCacheMap.get(fileNPath);
|
|
238
262
|
for (const dep of deps) {
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
for (const targetRefItem of targetDeps.filter((item) => item.exportName != null)) {
|
|
242
|
-
if (prevSet?.has(targetRefItem.fileName))
|
|
243
|
-
continue;
|
|
244
|
-
result.add(targetRefItem.fileName);
|
|
245
|
-
result.adds(...getAllDeps(targetRefItem.fileName, new Set(prevSet).adds(...result)));
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
else {
|
|
249
|
-
for (const targetRefItem of targetDeps.filter((item) => item.exportName
|
|
250
|
-
=== dep.importName)) {
|
|
251
|
-
if (prevSet?.has(targetRefItem.fileName))
|
|
252
|
-
continue;
|
|
253
|
-
result.add(targetRefItem.fileName);
|
|
254
|
-
result.adds(...getAllDeps(targetRefItem.fileName, new Set(prevSet).adds(...result)));
|
|
255
|
-
}
|
|
256
|
-
}
|
|
263
|
+
const depCache = this._revDepCacheMap.getOrCreate(dep, new Set());
|
|
264
|
+
depCache.add(fileNPath);
|
|
257
265
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
const deps = getAllDeps(PathUtils.norm(sf.fileName));
|
|
262
|
-
allDepMap.set(PathUtils.norm(sf.fileName), deps);
|
|
263
|
-
for (const dep of getAllDeps(PathUtils.norm(sf.fileName))) {
|
|
264
|
-
const depCache = this.#revDependencyCacheMap.getOrCreate(dep, new Set());
|
|
265
|
-
depCache.add(PathUtils.norm(sf.fileName));
|
|
266
|
-
}
|
|
267
|
-
if (this.#ngProgram) {
|
|
268
|
-
if (this.#ngProgram.compiler.ignoreForEmit.has(sf)) {
|
|
266
|
+
if (this._ngProgram) {
|
|
267
|
+
const sf = this._program.getSourceFile(fileNPath);
|
|
268
|
+
if (this._ngProgram.compiler.ignoreForEmit.has(sf)) {
|
|
269
269
|
continue;
|
|
270
270
|
}
|
|
271
|
-
for (const dep of this
|
|
272
|
-
const ref = this
|
|
273
|
-
ref.add(
|
|
271
|
+
for (const dep of this._ngProgram.compiler.getResourceDependencies(sf)) {
|
|
272
|
+
const ref = this._revDepCacheMap.getOrCreate(PathUtils.norm(dep), new Set());
|
|
273
|
+
ref.add(fileNPath);
|
|
274
274
|
}
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
277
|
});
|
|
278
|
-
if (this
|
|
279
|
-
this
|
|
280
|
-
this
|
|
281
|
-
for (const
|
|
282
|
-
if (!this
|
|
278
|
+
if (this._modifiedFileSet.size === 0) {
|
|
279
|
+
this._debug(`영향 받은 파일 추가 중... (새 의존성)`);
|
|
280
|
+
this._perf.run("영향 받은 파일 추가 중 (새 의존성)", () => {
|
|
281
|
+
for (const fileNPath of this._allDepCacheMap.keys()) {
|
|
282
|
+
if (!this._opt.watchScopePaths.some((scopePath) => PathUtils.isChildPath(fileNPath, scopePath))) {
|
|
283
283
|
continue;
|
|
284
284
|
}
|
|
285
|
-
this
|
|
285
|
+
this._affectedFileSet.add(fileNPath);
|
|
286
286
|
}
|
|
287
287
|
});
|
|
288
288
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
289
|
+
/**
|
|
290
|
+
* AI가 넣으라고해서 넣었지만 이유는 잘 모르겠음.
|
|
291
|
+
* AI측의 설명은 아래와 같음:
|
|
292
|
+
*
|
|
293
|
+
* 변경된 파일이 .d.ts일 경우, 타입 정보만을 가져다 쓰는 다수의 .ts 파일들이
|
|
294
|
+
* 직접적으로 import하고 있어도 revDepMap에는 기록되지 않을 수 있음.
|
|
295
|
+
*
|
|
296
|
+
* 따라서 .d.ts 파일을 참조하는 모든 파일을 allDepCacheMap에서 역추적하여
|
|
297
|
+
* 간접 영향 파일들을 정확하게 affectedFileSet에 포함시켜야 함.
|
|
298
|
+
*
|
|
299
|
+
* 이 블록은 정확도 보완을 위한 보증 로직이며, 특히 초기 빌드 또는 watch 시 의존성 누락을 방지함.
|
|
300
|
+
*/
|
|
301
|
+
for (const modifiedFile of this._modifiedFileSet) {
|
|
302
|
+
// 신규 추가된 파일이 누락되지 않도록 추가하라고 하여 넣음
|
|
303
|
+
if (!this._revDepCacheMap.has(modifiedFile) &&
|
|
304
|
+
!this._allDepCacheMap.has(modifiedFile) &&
|
|
305
|
+
this._program.getSourceFile(modifiedFile)) {
|
|
306
|
+
this._affectedFileSet.add(modifiedFile);
|
|
307
|
+
}
|
|
308
|
+
// AI가 넣으라 한부분에 대한 설명은 여기서부터임
|
|
309
|
+
if (!modifiedFile.endsWith(".d.ts"))
|
|
310
|
+
continue;
|
|
311
|
+
for (const [importer, deps] of this._allDepCacheMap) {
|
|
312
|
+
if (deps.has(modifiedFile)) {
|
|
313
|
+
this._affectedFileSet.add(importer);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
for (const dep of this._revDepCacheMap.keys()) {
|
|
318
|
+
if (this._modifiedFileSet.has(dep)) {
|
|
319
|
+
this._affectedFileSet.adds(...Array.from(this._revDepCacheMap.get(dep)).mapMany((item) => [
|
|
292
320
|
item,
|
|
293
321
|
// .d.ts면 .js파일도 affected에 추가
|
|
294
322
|
item.endsWith(".d.ts") ? PathUtils.norm(item.replace(/\.d\.ts$/, ".js")) : undefined,
|
|
@@ -296,29 +324,17 @@ export class SdTsCompiler {
|
|
|
296
324
|
}
|
|
297
325
|
// dep이 emit된적이 없으면 affected에 추가해야함.
|
|
298
326
|
// dep파일이 추가된후 기존 파일에서 import하면 dep파일이 affected에 포함이 안되는 현상 때문
|
|
299
|
-
if (!this
|
|
300
|
-
this
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
if (this.#ngProgram) {
|
|
304
|
-
for (const dep of this.#resourceDependencyCacheMap.keys()) {
|
|
305
|
-
if (this.#modifiedFileSet.has(dep)) {
|
|
306
|
-
this.#affectedFileSet.adds(...this.#resourceDependencyCacheMap.get(dep));
|
|
307
|
-
}
|
|
308
|
-
// dep이 emit된적이 없으면 affected에 추가해야함.
|
|
309
|
-
// dep파일이 추가된후 기존 파일에서 import하면 dep파일이 affected에 포함이 안되는 현상 때문
|
|
310
|
-
if (!this.#emittedFilesCacheMap.has(dep)) {
|
|
311
|
-
this.#affectedFileSet.add(dep);
|
|
312
|
-
}
|
|
327
|
+
if (!this._emittedFilesCacheMap.has(dep)) {
|
|
328
|
+
this._affectedFileSet.add(dep);
|
|
313
329
|
}
|
|
314
330
|
}
|
|
315
331
|
return {
|
|
316
332
|
messages,
|
|
317
333
|
};
|
|
318
334
|
}
|
|
319
|
-
async
|
|
320
|
-
const lintFilePaths = Array.from(this
|
|
321
|
-
.filter((item) => PathUtils.isChildPath(item, this
|
|
335
|
+
async _lintAsync() {
|
|
336
|
+
const lintFilePaths = Array.from(this._affectedFileSet)
|
|
337
|
+
.filter((item) => PathUtils.isChildPath(item, this._opt.pkgPath))
|
|
322
338
|
.filter((item) => ((!item.endsWith(".d.ts") && item.endsWith(".ts")) ||
|
|
323
339
|
item.endsWith(".js")))
|
|
324
340
|
.filter((item) => FsUtils.exists(item));
|
|
@@ -326,14 +342,14 @@ export class SdTsCompiler {
|
|
|
326
342
|
return [];
|
|
327
343
|
}
|
|
328
344
|
const linter = new ESLint({
|
|
329
|
-
cwd: this
|
|
345
|
+
cwd: this._opt.pkgPath,
|
|
330
346
|
cache: false,
|
|
331
347
|
overrideConfig: {
|
|
332
348
|
languageOptions: {
|
|
333
349
|
parserOptions: {
|
|
334
350
|
// parser: tseslint.parser,
|
|
335
351
|
project: null,
|
|
336
|
-
programs: [this
|
|
352
|
+
programs: [this._program],
|
|
337
353
|
},
|
|
338
354
|
},
|
|
339
355
|
},
|
|
@@ -346,206 +362,88 @@ export class SdTsCompiler {
|
|
|
346
362
|
// },
|
|
347
363
|
// ]);
|
|
348
364
|
}
|
|
349
|
-
async
|
|
365
|
+
async _buildAsync(tsconf) {
|
|
350
366
|
const emitFileSet = new Set();
|
|
351
367
|
const diagnostics = [];
|
|
352
|
-
this
|
|
353
|
-
this
|
|
354
|
-
diagnostics.push(...this
|
|
355
|
-
if (this
|
|
356
|
-
diagnostics.push(...this
|
|
368
|
+
this._debug(`프로그램 진단 수집 중...`);
|
|
369
|
+
this._perf.run("프로그램 진단 수집", () => {
|
|
370
|
+
diagnostics.push(...this._program.getConfigFileParsingDiagnostics(), ...this._program.getOptionsDiagnostics(), ...this._program.getGlobalDiagnostics());
|
|
371
|
+
if (this._ngProgram) {
|
|
372
|
+
diagnostics.push(...this._ngProgram.compiler.getOptionDiagnostics());
|
|
357
373
|
}
|
|
358
374
|
});
|
|
359
|
-
this
|
|
360
|
-
for (const affectedFile of this
|
|
361
|
-
if (!PathUtils.isChildPath(affectedFile, this
|
|
375
|
+
this._debug(`개별 파일 진단 수집 중...`);
|
|
376
|
+
for (const affectedFile of this._affectedFileSet) {
|
|
377
|
+
if (!PathUtils.isChildPath(affectedFile, this._opt.pkgPath))
|
|
362
378
|
continue;
|
|
363
|
-
|
|
364
|
-
const affectedSourceFile = this.#program.getSourceFile(affectedFile);
|
|
379
|
+
const affectedSourceFile = this._program.getSourceFile(affectedFile);
|
|
365
380
|
if (!affectedSourceFile ||
|
|
366
|
-
(this
|
|
381
|
+
(this._ngProgram && this._ngProgram.compiler.ignoreForDiagnostics.has(affectedSourceFile))) {
|
|
367
382
|
continue;
|
|
368
383
|
}
|
|
369
384
|
// this.#debug(`get diagnostics of file ${affectedFile}...`);
|
|
370
|
-
this
|
|
371
|
-
diagnostics.push(...this
|
|
385
|
+
this._perf.run("개별 파일 진단 수집", () => {
|
|
386
|
+
diagnostics.push(...this._program.getSyntacticDiagnostics(affectedSourceFile), ...this._program.getSemanticDiagnostics(affectedSourceFile));
|
|
372
387
|
});
|
|
373
|
-
if (this
|
|
374
|
-
this
|
|
375
|
-
if (affectedSourceFile.isDeclarationFile)
|
|
388
|
+
if (this._ngProgram) {
|
|
389
|
+
this._perf.run("개별 파일 진단 수집(Angular)", () => {
|
|
390
|
+
if (affectedSourceFile.isDeclarationFile)
|
|
376
391
|
return;
|
|
377
|
-
|
|
378
|
-
diagnostics.push(...this.#ngProgram.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram));
|
|
392
|
+
diagnostics.push(...this._ngProgram.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram));
|
|
379
393
|
});
|
|
380
394
|
}
|
|
381
395
|
}
|
|
382
|
-
this
|
|
383
|
-
this
|
|
396
|
+
this._perf.run("파일 출력 (emit)", () => {
|
|
397
|
+
this._debug(`파일 출력 준비 중...`);
|
|
384
398
|
let transformers = {};
|
|
385
|
-
if (this
|
|
399
|
+
if (this._ngProgram) {
|
|
386
400
|
transformers = {
|
|
387
401
|
...transformers,
|
|
388
|
-
...this
|
|
402
|
+
...this._ngProgram.compiler.prepareEmit().transformers,
|
|
389
403
|
};
|
|
390
|
-
(transformers.before ??= []).push(replaceBootstrap(() => this
|
|
404
|
+
(transformers.before ??= []).push(replaceBootstrap(() => this._program.getTypeChecker()));
|
|
391
405
|
(transformers.before ??= []).push(createWorkerTransformer((file, importer) => {
|
|
392
406
|
const fullPath = path.resolve(path.dirname(importer), file);
|
|
393
|
-
const relPath = path.relative(path.resolve(this
|
|
407
|
+
const relPath = path.relative(path.resolve(this._opt.pkgPath, "src"), fullPath);
|
|
394
408
|
return relPath.replace(/\.ts$/, "").replaceAll("\\", "/") + ".js";
|
|
395
409
|
}));
|
|
396
410
|
}
|
|
397
|
-
|
|
398
|
-
/*const fixImportTransformer: ts.TransformerFactory<ts.SourceFile> = (context) => {
|
|
399
|
-
return (sf) => {
|
|
400
|
-
const shouldAppendJs = (importText: string): string | undefined => {
|
|
401
|
-
const resolved = ts.resolveModuleName(
|
|
402
|
-
importText,
|
|
403
|
-
sf.fileName,
|
|
404
|
-
this.#program!.getCompilerOptions(),
|
|
405
|
-
ts.sys,
|
|
406
|
-
);
|
|
407
|
-
|
|
408
|
-
const resolvedInfo = resolved.resolvedModule;
|
|
409
|
-
if (!resolvedInfo) return undefined;
|
|
410
|
-
|
|
411
|
-
const resolvedFileName = resolvedInfo.resolvedFileName;
|
|
412
|
-
|
|
413
|
-
// ① .ts / .tsx / .js / .jsx 만 대상
|
|
414
|
-
if (!/\.(d\.ts|ts|tsx|js|jsx)$/i.test(resolvedFileName)) return undefined;
|
|
415
|
-
|
|
416
|
-
// ② 사용자가 .js, .mjs, .json 등 명시한 경우 무시
|
|
417
|
-
if (/\.[mc]?js$|\.json$/i.test(importText)) return undefined;
|
|
418
|
-
|
|
419
|
-
// 3. import 경로의 마지막 부분이 파일명(확장자 제외)과 같으면 → .js 붙여야 함
|
|
420
|
-
const importLastName = importText.split("/").pop();
|
|
421
|
-
const resolvedFileNameOnly = path.basename(resolvedFileName)
|
|
422
|
-
.replace(/\.(d\.ts|ts|tsx|js|jsx)$/, "");
|
|
423
|
-
|
|
424
|
-
if (importLastName === resolvedFileNameOnly) {
|
|
425
|
-
return importText + ".js";
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// 4. 그렇지 않으면 → index.ts 같은 루트 패키지 import → .js 붙이지 않음
|
|
429
|
-
return undefined;
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
const visitor: ts.Visitor = (node): ts.Node => {
|
|
433
|
-
// import { x } from "./foo"
|
|
434
|
-
if (
|
|
435
|
-
ts.isImportDeclaration(node) &&
|
|
436
|
-
ts.isStringLiteral(node.moduleSpecifier)
|
|
437
|
-
) {
|
|
438
|
-
const newPath = shouldAppendJs(node.moduleSpecifier.text);
|
|
439
|
-
if (newPath != null) {
|
|
440
|
-
return ts.factory.updateImportDeclaration(
|
|
441
|
-
node,
|
|
442
|
-
node.modifiers,
|
|
443
|
-
node.importClause,
|
|
444
|
-
ts.factory.createStringLiteral(newPath),
|
|
445
|
-
undefined,
|
|
446
|
-
);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// export * from "./bar"
|
|
451
|
-
if (
|
|
452
|
-
ts.isExportDeclaration(node) &&
|
|
453
|
-
node.moduleSpecifier &&
|
|
454
|
-
ts.isStringLiteral(node.moduleSpecifier)
|
|
455
|
-
) {
|
|
456
|
-
const newPath = shouldAppendJs(node.moduleSpecifier.text);
|
|
457
|
-
if (newPath != null) {
|
|
458
|
-
return ts.factory.updateExportDeclaration(
|
|
459
|
-
node,
|
|
460
|
-
node.modifiers,
|
|
461
|
-
node.isTypeOnly,
|
|
462
|
-
node.exportClause,
|
|
463
|
-
ts.factory.createStringLiteral(newPath),
|
|
464
|
-
undefined,
|
|
465
|
-
);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// dynamic import("./baz")
|
|
470
|
-
if (
|
|
471
|
-
ts.isCallExpression(node) &&
|
|
472
|
-
node.expression.kind === ts.SyntaxKind.ImportKeyword &&
|
|
473
|
-
node.arguments.length === 1 &&
|
|
474
|
-
ts.isStringLiteral(node.arguments[0])
|
|
475
|
-
) {
|
|
476
|
-
const newPath = shouldAppendJs(node.arguments[0].text);
|
|
477
|
-
if (newPath != null) {
|
|
478
|
-
return ts.factory.updateCallExpression(
|
|
479
|
-
node,
|
|
480
|
-
node.expression,
|
|
481
|
-
undefined,
|
|
482
|
-
[ts.factory.createStringLiteral(newPath)],
|
|
483
|
-
);
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
return ts.visitEachChild(node, visitor, context);
|
|
488
|
-
};
|
|
489
|
-
|
|
490
|
-
return ts.visitNode(sf, visitor) as ts.SourceFile;
|
|
491
|
-
};
|
|
492
|
-
};
|
|
493
|
-
(transformers.before ??= []).push(fixImportTransformer);*/
|
|
494
|
-
this.#debug(`emit for files...`);
|
|
411
|
+
this._debug(`파일 출력 중...`);
|
|
495
412
|
// affected에 새로 추가된 파일은 포함되지 않는 현상이 있어 sourceFileSet으로 바꿈
|
|
496
413
|
// 비교해보니, 딱히 getSourceFiles라서 더 느려지는것 같지는 않음
|
|
497
414
|
// 그래도 affected로 다시 테스트 (조금이라도 더 빠르게)
|
|
498
|
-
for (const affectedFile of this
|
|
499
|
-
if (this
|
|
415
|
+
for (const affectedFile of this._affectedFileSet) {
|
|
416
|
+
if (this._emittedFilesCacheMap.has(affectedFile))
|
|
500
417
|
continue;
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
if (!sf) {
|
|
418
|
+
const sf = this._program.getSourceFile(affectedFile);
|
|
419
|
+
if (!sf || sf.isDeclarationFile)
|
|
504
420
|
continue;
|
|
505
|
-
|
|
506
|
-
if (sf.isDeclarationFile) {
|
|
421
|
+
if (this._ngProgram?.compiler.ignoreForEmit.has(sf))
|
|
507
422
|
continue;
|
|
508
|
-
|
|
509
|
-
if (this.#ngProgram?.compiler.ignoreForEmit.has(sf)) {
|
|
423
|
+
if (this._ngProgram?.compiler.incrementalCompilation.safeToSkipEmit(sf))
|
|
510
424
|
continue;
|
|
511
|
-
|
|
512
|
-
|
|
425
|
+
// 번들이 아닌 외부패키지는 보통 emit안해도 됨
|
|
426
|
+
// but esbuild를 통해 bundle로 묶어야 하는놈들은 모든 output이 있어야 함.
|
|
427
|
+
if (!this._opt.isForBundle && !PathUtils.isChildPath(sf.fileName, this._opt.pkgPath)) {
|
|
513
428
|
continue;
|
|
514
429
|
}
|
|
515
|
-
|
|
516
|
-
if (!this.#isForBundle) {
|
|
517
|
-
if (!PathUtils.isChildPath(sf.fileName, this.#pkgPath)) {
|
|
518
|
-
continue;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
this.#program.emit(sf, (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
|
|
430
|
+
this._program.emit(sf, (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
|
|
522
431
|
if (!sourceFiles || sourceFiles.length === 0) {
|
|
523
|
-
|
|
432
|
+
tsconf.compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
|
|
524
433
|
return;
|
|
525
434
|
}
|
|
526
435
|
const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
|
|
527
|
-
if (this
|
|
528
|
-
if (this
|
|
436
|
+
if (this._ngProgram) {
|
|
437
|
+
if (this._ngProgram.compiler.ignoreForEmit.has(sourceFile))
|
|
529
438
|
return;
|
|
530
|
-
|
|
531
|
-
this.#ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
|
|
439
|
+
this._ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
|
|
532
440
|
}
|
|
533
|
-
const emitFileInfoCaches = this
|
|
534
|
-
if (PathUtils.isChildPath(sourceFile.fileName, this
|
|
535
|
-
|
|
536
|
-
let realText = text;
|
|
537
|
-
if (PathUtils.isChildPath(realFilePath, path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"))) {
|
|
538
|
-
realFilePath = PathUtils.norm(this.#distPath, path.relative(path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"), realFilePath));
|
|
539
|
-
if (fileName.endsWith(".js.map")) {
|
|
540
|
-
const sourceMapContents = JSON.parse(realText);
|
|
541
|
-
// remove "../../"
|
|
542
|
-
sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6);
|
|
543
|
-
realText = JSON.stringify(sourceMapContents);
|
|
544
|
-
}
|
|
545
|
-
}
|
|
441
|
+
const emitFileInfoCaches = this._emittedFilesCacheMap.getOrCreate(PathUtils.norm(sourceFile.fileName), []);
|
|
442
|
+
if (PathUtils.isChildPath(sourceFile.fileName, this._opt.pkgPath)) {
|
|
443
|
+
const real = this._convertOutputToReal(fileName, tsconf.distPath, text);
|
|
546
444
|
emitFileInfoCaches.push({
|
|
547
|
-
outAbsPath:
|
|
548
|
-
text:
|
|
445
|
+
outAbsPath: real.filePath,
|
|
446
|
+
text: real.text,
|
|
549
447
|
});
|
|
550
448
|
}
|
|
551
449
|
else {
|
|
@@ -556,20 +454,20 @@ export class SdTsCompiler {
|
|
|
556
454
|
}
|
|
557
455
|
});
|
|
558
456
|
//-- global style
|
|
559
|
-
if (this
|
|
560
|
-
FsUtils.exists(this
|
|
561
|
-
!this
|
|
562
|
-
this
|
|
563
|
-
await this
|
|
564
|
-
const data = FsUtils.readFile(this
|
|
565
|
-
const
|
|
566
|
-
const emitFileInfos = this
|
|
457
|
+
if (this._opt.globalStyleFilePath != null &&
|
|
458
|
+
FsUtils.exists(this._opt.globalStyleFilePath) &&
|
|
459
|
+
!this._emittedFilesCacheMap.has(this._opt.globalStyleFilePath)) {
|
|
460
|
+
this._debug(`전역 스타일 번들링 중...`);
|
|
461
|
+
await this._perf.run("전역 스타일 번들링", async () => {
|
|
462
|
+
const data = FsUtils.readFile(this._opt.globalStyleFilePath);
|
|
463
|
+
const stylesheetBundlingResult = await this._bundleStylesheetAsync(data, this._opt.globalStyleFilePath, this._opt.globalStyleFilePath);
|
|
464
|
+
const emitFileInfos = this._emittedFilesCacheMap.getOrCreate(this._opt.globalStyleFilePath, []);
|
|
567
465
|
emitFileInfos.push({
|
|
568
|
-
outAbsPath: PathUtils.norm(this
|
|
466
|
+
outAbsPath: PathUtils.norm(this._opt.pkgPath, path.relative(path.resolve(this._opt.pkgPath, "src"), this._opt.globalStyleFilePath)
|
|
569
467
|
.replace(/\.scss$/, ".css")),
|
|
570
|
-
text: contents,
|
|
468
|
+
text: stylesheetBundlingResult.contents ?? "",
|
|
571
469
|
});
|
|
572
|
-
emitFileSet.add(this
|
|
470
|
+
emitFileSet.add(this._opt.globalStyleFilePath);
|
|
573
471
|
});
|
|
574
472
|
}
|
|
575
473
|
return {
|
|
@@ -577,190 +475,23 @@ export class SdTsCompiler {
|
|
|
577
475
|
diagnostics,
|
|
578
476
|
};
|
|
579
477
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
if (
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
|
|
592
|
-
deps.push({
|
|
593
|
-
filePath: PathUtils.norm(sf.fileName),
|
|
594
|
-
line: pos.line,
|
|
595
|
-
char: pos.character,
|
|
596
|
-
code: undefined,
|
|
597
|
-
severity: "error",
|
|
598
|
-
message: "export moduleSymbol not found",
|
|
599
|
-
type: "deps",
|
|
600
|
-
});
|
|
601
|
-
return;
|
|
602
|
-
}
|
|
603
|
-
const decls = moduleSymbol.getDeclarations();
|
|
604
|
-
if (!decls) {
|
|
605
|
-
const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
|
|
606
|
-
deps.push({
|
|
607
|
-
filePath: PathUtils.norm(sf.fileName),
|
|
608
|
-
line: pos.line,
|
|
609
|
-
char: pos.character,
|
|
610
|
-
code: undefined,
|
|
611
|
-
severity: "error",
|
|
612
|
-
message: "export decls not found",
|
|
613
|
-
type: "deps",
|
|
614
|
-
});
|
|
615
|
-
return;
|
|
616
|
-
}
|
|
617
|
-
const namedBindings = node.exportClause;
|
|
618
|
-
if (namedBindings && ts.isNamedExports(namedBindings)) {
|
|
619
|
-
for (const el of namedBindings.elements) {
|
|
620
|
-
for (const decl of decls) {
|
|
621
|
-
deps.push({
|
|
622
|
-
fileName: PathUtils.norm(decl.getSourceFile().fileName),
|
|
623
|
-
importName: el.name.text,
|
|
624
|
-
exportName: el.propertyName?.text ?? el.name.text,
|
|
625
|
-
});
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
else {
|
|
630
|
-
if (!moduleSymbol.exports) {
|
|
631
|
-
const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
|
|
632
|
-
deps.push({
|
|
633
|
-
filePath: PathUtils.norm(sf.fileName),
|
|
634
|
-
line: pos.line,
|
|
635
|
-
char: pos.character,
|
|
636
|
-
code: undefined,
|
|
637
|
-
severity: "error",
|
|
638
|
-
message: "moduleSymbol exports not found",
|
|
639
|
-
type: "deps",
|
|
640
|
-
});
|
|
641
|
-
return;
|
|
642
|
-
}
|
|
643
|
-
for (const decl of decls) {
|
|
644
|
-
for (const key of moduleSymbol.exports.keys()) {
|
|
645
|
-
deps.push({
|
|
646
|
-
fileName: PathUtils.norm(decl.getSourceFile().fileName),
|
|
647
|
-
importName: key.toString(),
|
|
648
|
-
exportName: key.toString(),
|
|
649
|
-
});
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
}
|
|
478
|
+
_convertOutputToReal(filePath, distPath, text) {
|
|
479
|
+
let realFilePath = PathUtils.norm(filePath);
|
|
480
|
+
let realText = text;
|
|
481
|
+
const srcRelBasePath = path.resolve(distPath, path.basename(this._opt.pkgPath), "src");
|
|
482
|
+
if (PathUtils.isChildPath(realFilePath, srcRelBasePath)) {
|
|
483
|
+
realFilePath = PathUtils.norm(distPath, path.relative(srcRelBasePath, realFilePath));
|
|
484
|
+
// source map 위치 정확히 찾아가기
|
|
485
|
+
if (filePath.endsWith(".js.map")) {
|
|
486
|
+
const sourceMapContents = JSON.parse(realText);
|
|
487
|
+
sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6); // remove "../../"
|
|
488
|
+
realText = JSON.stringify(sourceMapContents);
|
|
654
489
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
deps.push({
|
|
661
|
-
fileName: PathUtils.norm(path.resolve(path.dirname(sf.fileName), node.moduleSpecifier.text + ".ts")),
|
|
662
|
-
importName: "*",
|
|
663
|
-
});
|
|
664
|
-
// const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
|
|
665
|
-
// deps.push({
|
|
666
|
-
// filePath: PathUtil.norm(sf.fileName),
|
|
667
|
-
// line: pos.line,
|
|
668
|
-
// char: pos.character,
|
|
669
|
-
// code: undefined,
|
|
670
|
-
// severity: "error",
|
|
671
|
-
// message: `import moduleSymbol not found (${node.moduleSpecifier.text})`,
|
|
672
|
-
// type: "deps",
|
|
673
|
-
// });
|
|
674
|
-
// return;
|
|
675
|
-
}
|
|
676
|
-
/*else {
|
|
677
|
-
throw new NeverEntryError(`import moduleSymbol: ${sf.fileName} ${node.moduleSpecifier["text"]}`);
|
|
678
|
-
}*/
|
|
679
|
-
}
|
|
680
|
-
else {
|
|
681
|
-
const decls = moduleSymbol.getDeclarations();
|
|
682
|
-
if (!decls) {
|
|
683
|
-
const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
|
|
684
|
-
deps.push({
|
|
685
|
-
filePath: PathUtils.norm(sf.fileName),
|
|
686
|
-
line: pos.line,
|
|
687
|
-
char: pos.character,
|
|
688
|
-
code: undefined,
|
|
689
|
-
severity: "error",
|
|
690
|
-
message: `import decls not found (${moduleSymbol.name})`,
|
|
691
|
-
type: "deps",
|
|
692
|
-
});
|
|
693
|
-
return;
|
|
694
|
-
}
|
|
695
|
-
const namedBindings = node.importClause?.namedBindings;
|
|
696
|
-
if (namedBindings && ts.isNamedImports(namedBindings)) {
|
|
697
|
-
for (const el of namedBindings.elements) {
|
|
698
|
-
for (const decl of decls) {
|
|
699
|
-
deps.push({
|
|
700
|
-
fileName: PathUtils.norm(decl.getSourceFile().fileName),
|
|
701
|
-
importName: el.name.text,
|
|
702
|
-
});
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
else {
|
|
707
|
-
for (const decl of decls) {
|
|
708
|
-
deps.push({
|
|
709
|
-
fileName: PathUtils.norm(decl.getSourceFile().fileName),
|
|
710
|
-
importName: "*",
|
|
711
|
-
});
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
|
|
717
|
-
if (ts.isStringLiteral(node.arguments[0]) && node.arguments[0].text.startsWith("./")) {
|
|
718
|
-
const moduleSymbol = tc.getSymbolAtLocation(node.arguments[0]);
|
|
719
|
-
if (!moduleSymbol) {
|
|
720
|
-
deps.push({
|
|
721
|
-
fileName: PathUtils.norm(path.resolve(path.dirname(sf.fileName), node.arguments[0].text + ".ts")),
|
|
722
|
-
importName: "*",
|
|
723
|
-
});
|
|
724
|
-
// const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
|
|
725
|
-
// deps.push({
|
|
726
|
-
// filePath: PathUtil.norm(sf.fileName),
|
|
727
|
-
// line: pos.line,
|
|
728
|
-
// char: pos.character,
|
|
729
|
-
// code: undefined,
|
|
730
|
-
// severity: "error",
|
|
731
|
-
// message: `import() moduleSymbol not found (${node.arguments[0].text})`,
|
|
732
|
-
// type: "deps",
|
|
733
|
-
// });
|
|
734
|
-
// return;
|
|
735
|
-
}
|
|
736
|
-
else {
|
|
737
|
-
const decls = moduleSymbol.getDeclarations();
|
|
738
|
-
if (!decls) {
|
|
739
|
-
const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
|
|
740
|
-
deps.push({
|
|
741
|
-
filePath: PathUtils.norm(sf.fileName),
|
|
742
|
-
line: pos.line,
|
|
743
|
-
char: pos.character,
|
|
744
|
-
code: undefined,
|
|
745
|
-
severity: "error",
|
|
746
|
-
message: `import() decls not found (${node.arguments[0].text})`,
|
|
747
|
-
type: "deps",
|
|
748
|
-
});
|
|
749
|
-
return;
|
|
750
|
-
}
|
|
751
|
-
for (const decl of decls) {
|
|
752
|
-
deps.push({
|
|
753
|
-
fileName: PathUtils.norm(decl.getSourceFile().fileName),
|
|
754
|
-
importName: "*",
|
|
755
|
-
});
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
node.forEachChild(visit);
|
|
761
|
-
};
|
|
762
|
-
sf.forEachChild(visit);
|
|
763
|
-
return deps;
|
|
490
|
+
}
|
|
491
|
+
return { filePath: realFilePath, text: realText };
|
|
492
|
+
}
|
|
493
|
+
_debug(...msg) {
|
|
494
|
+
this._logger.debug(`[${path.basename(this._opt.pkgPath)}]`, ...msg);
|
|
764
495
|
}
|
|
765
496
|
}
|
|
766
497
|
//# sourceMappingURL=sd-ts-compiler.js.map
|