@simplysm/sd-cli 14.0.47 → 14.0.49
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/README.md +782 -0
- package/dist/angular/ngtsc-build-core.js +2 -2
- package/dist/angular/ngtsc-build-core.js.map +1 -1
- package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
- package/dist/angular/vite-angular-plugin.js +3 -2
- package/dist/angular/vite-angular-plugin.js.map +1 -1
- package/dist/capacitor/capacitor-android.js +2 -2
- package/dist/capacitor/capacitor-android.js.map +1 -1
- package/dist/capacitor/capacitor-build.d.ts.map +1 -1
- package/dist/capacitor/capacitor-build.js +2 -1
- package/dist/capacitor/capacitor-build.js.map +1 -1
- package/dist/capacitor/capacitor-icon.d.ts.map +1 -1
- package/dist/capacitor/capacitor-icon.js +2 -1
- package/dist/capacitor/capacitor-icon.js.map +1 -1
- package/dist/capacitor/capacitor-npm-config.d.ts.map +1 -1
- package/dist/capacitor/capacitor-npm-config.js +2 -1
- package/dist/capacitor/capacitor-npm-config.js.map +1 -1
- package/dist/capacitor/capacitor.d.ts.map +1 -1
- package/dist/capacitor/capacitor.js +2 -1
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/commands/device.js +2 -2
- package/dist/commands/device.js.map +1 -1
- package/dist/commands/replace-deps.js +2 -2
- package/dist/commands/replace-deps.js.map +1 -1
- package/dist/deps/replace-deps/collect-deps.js +2 -2
- package/dist/deps/replace-deps/collect-deps.js.map +1 -1
- package/dist/deps/replace-deps/replace-deps.d.ts.map +1 -1
- package/dist/deps/replace-deps/replace-deps.js +108 -81
- package/dist/deps/replace-deps/replace-deps.js.map +1 -1
- package/dist/deps/server-externals/server-production-files.js +2 -2
- package/dist/deps/server-externals/server-production-files.js.map +1 -1
- package/dist/electron/electron.d.ts.map +1 -1
- package/dist/electron/electron.js +2 -1
- package/dist/electron/electron.js.map +1 -1
- package/dist/engines/BaseEngine.d.ts.map +1 -1
- package/dist/engines/BaseEngine.js +2 -2
- package/dist/engines/BaseEngine.js.map +1 -1
- package/dist/engines/EsbuildClientEngine.d.ts.map +1 -1
- package/dist/engines/EsbuildClientEngine.js +2 -2
- package/dist/engines/EsbuildClientEngine.js.map +1 -1
- package/dist/engines/NgtscEngine.js +2 -2
- package/dist/engines/NgtscEngine.js.map +1 -1
- package/dist/engines/ServerEsbuildEngine.js +2 -2
- package/dist/engines/ServerEsbuildEngine.js.map +1 -1
- package/dist/engines/TscEngine.js +2 -2
- package/dist/engines/TscEngine.js.map +1 -1
- package/dist/engines/engine-factory.d.ts.map +1 -1
- package/dist/engines/engine-factory.js +2 -2
- package/dist/engines/engine-factory.js.map +1 -1
- package/dist/esbuild/esbuild-angular-compiler-plugin.d.ts.map +1 -1
- package/dist/esbuild/esbuild-angular-compiler-plugin.js +46 -18
- package/dist/esbuild/esbuild-angular-compiler-plugin.js.map +1 -1
- package/dist/esbuild/esbuild-config.js +2 -2
- package/dist/esbuild/esbuild-config.js.map +1 -1
- package/dist/lint/lint-with-program.js +2 -2
- package/dist/lint/lint-with-program.js.map +1 -1
- package/dist/runtime/lazy-logger.d.ts +14 -0
- package/dist/runtime/lazy-logger.d.ts.map +1 -0
- package/dist/runtime/lazy-logger.js +23 -0
- package/dist/runtime/lazy-logger.js.map +1 -0
- package/dist/sd-cli-entry.js +2 -2
- package/dist/sd-cli-entry.js.map +1 -1
- package/dist/sd-cli.js +2 -2
- package/dist/sd-cli.js.map +1 -1
- package/dist/ts-compiler/SdTsCompiler.d.ts +11 -0
- package/dist/ts-compiler/SdTsCompiler.d.ts.map +1 -1
- package/dist/ts-compiler/SdTsCompiler.js +223 -116
- package/dist/ts-compiler/SdTsCompiler.js.map +1 -1
- package/dist/typecheck/typecheck-non-package.js +2 -2
- package/dist/typecheck/typecheck-non-package.js.map +1 -1
- package/dist/typecheck/typecheck-serialization.d.ts +31 -9
- package/dist/typecheck/typecheck-serialization.d.ts.map +1 -1
- package/dist/typecheck/typecheck-serialization.js +62 -22
- package/dist/typecheck/typecheck-serialization.js.map +1 -1
- package/dist/utils/output-utils.js +2 -2
- package/dist/utils/output-utils.js.map +1 -1
- package/dist/utils/package-classify.js +2 -2
- package/dist/utils/package-classify.js.map +1 -1
- package/dist/utils/package-utils.js +2 -2
- package/dist/utils/package-utils.js.map +1 -1
- package/dist/utils/sd-config.js +2 -2
- package/dist/utils/sd-config.js.map +1 -1
- package/dist/utils/tsconfig.d.ts.map +1 -1
- package/dist/utils/tsconfig.js +3 -5
- package/dist/utils/tsconfig.js.map +1 -1
- package/package.json +5 -5
- package/src/angular/ngtsc-build-core.ts +3 -3
- package/src/angular/vite-angular-plugin.ts +3 -2
- package/src/capacitor/capacitor-android.ts +2 -2
- package/src/capacitor/capacitor-build.ts +2 -1
- package/src/capacitor/capacitor-icon.ts +2 -1
- package/src/capacitor/capacitor-npm-config.ts +2 -1
- package/src/capacitor/capacitor.ts +2 -1
- package/src/commands/device.ts +2 -2
- package/src/commands/replace-deps.ts +2 -2
- package/src/deps/replace-deps/collect-deps.ts +2 -2
- package/src/deps/replace-deps/replace-deps.ts +119 -85
- package/src/deps/server-externals/server-production-files.ts +2 -2
- package/src/electron/electron.ts +2 -1
- package/src/engines/BaseEngine.ts +2 -2
- package/src/engines/EsbuildClientEngine.ts +2 -2
- package/src/engines/NgtscEngine.ts +2 -2
- package/src/engines/ServerEsbuildEngine.ts +2 -2
- package/src/engines/TscEngine.ts +2 -2
- package/src/engines/engine-factory.ts +2 -2
- package/src/esbuild/esbuild-angular-compiler-plugin.ts +60 -19
- package/src/esbuild/esbuild-config.ts +2 -2
- package/src/lint/lint-with-program.ts +2 -2
- package/src/runtime/lazy-logger.ts +23 -0
- package/src/sd-cli-entry.ts +2 -2
- package/src/sd-cli.ts +2 -2
- package/src/ts-compiler/SdTsCompiler.ts +280 -138
- package/src/typecheck/typecheck-non-package.ts +2 -2
- package/src/typecheck/typecheck-serialization.ts +100 -26
- package/src/utils/output-utils.ts +2 -2
- package/src/utils/package-classify.ts +2 -2
- package/src/utils/package-utils.ts +2 -2
- package/src/utils/sd-config.ts +2 -2
- package/src/utils/tsconfig.ts +3 -4
- package/tests/angular/angular-compiler-hmr-removal.verify.md +12 -12
- package/tests/angular/onbuild-lint-removal.verify.md +4 -4
- package/tests/angular/vite-angular-plugin-sdtscompiler.verify.md +9 -9
- package/tests/angular/vite-angular-plugin-vitest.verify.md +16 -16
- package/tests/capacitor/capacitor-android-exports.verify.md +7 -7
- package/tests/commands/publish-npm-local-split.verify.md +5 -5
- package/tests/commands/publish-responsibility-split.verify.md +9 -9
- package/tests/commands/publish-set.verify.md +3 -3
- package/tests/commands/publish-storage-split.verify.md +4 -4
- package/tests/commands/slice3-severity-cleanup.verify.md +8 -8
- package/tests/deps/deps-directory-separation.verify.md +11 -11
- package/tests/deps/replace-deps/replace-deps-perf.verify.md +6 -6
- package/tests/deps/server-externals/mise-toml-parse-intent.verify.md +8 -8
- package/tests/electron/electron-symlink-cleanup.verify.md +4 -4
- package/tests/engines/engine-duplicate-output-removal.verify.md +6 -6
- package/tests/engines/engine-typecheck-selection.verify.md +4 -4
- package/tests/engines/esbuild-client-engine.verify.md +11 -11
- package/tests/engines/normalize-result.verify.md +5 -5
- package/tests/engines/vite-dependency-cleanup.verify.md +11 -11
- package/tests/esbuild/esbuild-angular-compiler-plugin-hmr.verify.md +10 -10
- package/tests/esbuild/esbuild-angular-compiler-plugin-onload.verify.md +17 -17
- package/tests/esbuild/esbuild-angular-compiler-plugin-onstart-extraction.verify.md +12 -12
- package/tests/esbuild/esbuild-angular-compiler-plugin-sdtscompiler.verify.md +11 -11
- package/tests/esbuild/esbuild-angular-compiler-plugin-stylesheet.verify.md +13 -13
- package/tests/esbuild/esbuild-angular-compiler-plugin-worker.verify.md +32 -32
- package/tests/esbuild/esbuild-angular-compiler-plugin.verify.md +9 -9
- package/tests/esbuild/esbuild-postcss-plugin-chunking.verify.md +3 -3
- package/tests/esbuild/esbuild-tsc-plugin-imports.verify.md +9 -9
- package/tests/esbuild/esbuild-worker-plugin-node.verify.md +7 -7
- package/tests/esbuild/esbuild-worker-plugin.spec.ts +8 -0
- package/tests/esbuild/esbuild-worker-plugin.verify.md +3 -3
- package/tests/orchestrators/dist-delete-watcher.verify.md +6 -6
- package/tests/orchestrators/orchestrator-baseenv.verify.md +6 -6
- package/tests/orchestrators/orchestrator-diagnostic-formatting.verify.md +6 -6
- package/tests/orchestrators/orchestrator-initializemode-signature.verify.md +5 -5
- package/tests/orchestrators/slice1-stdout-to-consola.verify.md +6 -6
- package/tests/sd-cli-catch-all.verify.md +3 -3
- package/tests/sd-cli-log-tag.verify.md +7 -7
- package/tests/ts-compiler/SdTsCompiler-affected-files.verify.md +4 -4
- package/tests/ts-compiler/SdTsCompiler-diagnostics.verify.md +8 -8
- package/tests/ts-compiler/SdTsCompiler-emit.verify.md +5 -5
- package/tests/ts-compiler/SdTsCompiler.verify.md +20 -20
- package/tests/ts-compiler/scss-lint-integration.verify.md +10 -10
- package/tests/utils/copy-public-outdir.verify.md +4 -4
- package/tests/utils/dev-http-server.verify.md +4 -4
- package/tests/utils/engine-watch-events.verify.md +8 -8
- package/tests/utils/esbuild-client-config-integration.verify.md +5 -5
- package/tests/utils/esbuild-client-config-postcss.verify.md +2 -2
- package/tests/utils/esbuild-client-config.verify.md +16 -16
- package/tests/utils/esbuild-index-html.verify.md +6 -6
- package/tests/utils/esbuild-pwa.verify.md +5 -5
- package/tests/utils/esbuild-scss-plugin.verify.md +4 -4
- package/tests/utils/hmr-service.verify.md +10 -10
- package/tests/utils/lint-core-import-paths.verify.md +6 -6
- package/tests/utils/replace-deps-split.verify.md +11 -11
- package/tests/utils/replace-deps-watch.acc.spec.ts +85 -0
- package/tests/utils/replace-deps-watch.spec.ts +198 -1
- package/tests/utils/replace-deps-watch.verify.md +5 -5
- package/tests/utils/server-production-files-import-paths.verify.md +10 -10
- package/tests/utils/vite-config-cleanup.verify.md +3 -3
- package/tests/workers/build-watch-paths-library.verify.md +6 -6
- package/tests/workers/build-watch-paths-ngtsc-server.verify.md +8 -8
- package/tests/workers/client-worker-browser-support.verify.md +3 -3
- package/tests/workers/client-worker-cleanup.verify.md +4 -4
- package/tests/workers/client-worker-initial-build-error.verify.md +3 -3
- package/tests/workers/client-worker-initial-build-warnings.verify.md +3 -3
- package/tests/workers/client-worker-mtime-incremental.verify.md +6 -6
- package/tests/workers/client-worker-onend-sync.verify.md +3 -3
- package/tests/workers/client-worker-refactor.verify.md +18 -18
- package/tests/workers/client-worker-ts-cache-invalidation.verify.md +8 -8
- package/tests/workers/dev-port-file.verify.md +3 -3
- package/tests/workers/ngtsc-build-rootnames-refresh.verify.md +4 -4
- package/tests/workers/server-build-context-dispose.verify.md +4 -4
- package/tests/workers/server-build-worker-plugin.verify.md +5 -5
- package/tests/workers/server-build-worker-refactoring.verify.md +10 -10
- package/tests/workers/server-esbuild-context-integration.verify.md +6 -6
- package/tests/workers/server-esbuild-context-tsc.verify.md +3 -3
- package/dist/sd-cli/tests/angular/fixtures/packages/basic-app/tests/test.fixture.d.ts +0 -3
- package/dist/sd-cli/tests/angular/fixtures/packages/basic-app/tests/test.fixture.d.ts.map +0 -1
- package/dist/sd-cli/tests/angular/fixtures/packages/basic-app/tests/test.fixture.js +0 -9
- package/dist/sd-cli/tests/angular/fixtures/packages/basic-app/tests/test.fixture.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import { createHash } from "crypto";
|
|
3
3
|
import ts from "typescript";
|
|
4
|
-
import { consola } from "consola";
|
|
4
|
+
import { consola, type ConsolaInstance } from "consola";
|
|
5
5
|
import { pathx } from "@simplysm/core-node";
|
|
6
6
|
import type { ISdTsCompilerOptions, ISdTsCompilerEmitOptions } from "./sd-ts-compiler-options";
|
|
7
7
|
import type { ISdTsCompilerResult } from "./sd-ts-compiler-result";
|
|
@@ -28,8 +28,6 @@ import {
|
|
|
28
28
|
} from "../angular/ngtsc-build-core";
|
|
29
29
|
import { LintWithProgramRunner, type LintWithProgramResult } from "../lint/lint-with-program";
|
|
30
30
|
|
|
31
|
-
const logger = consola.withTag("sd:cli:SdTsCompiler");
|
|
32
|
-
|
|
33
31
|
type NgCompiler = NgtscProgram["compiler"];
|
|
34
32
|
|
|
35
33
|
function hasTemplateExtension(file: string): boolean {
|
|
@@ -80,10 +78,32 @@ export class SdTsCompiler {
|
|
|
80
78
|
// ── Lint (lazy init, 인스턴스 재사용) ──
|
|
81
79
|
private _lintRunner?: LintWithProgramRunner;
|
|
82
80
|
|
|
81
|
+
// ── 크래시 디버깅용 컨텍스트 (compileAsync 내 단계/파일 진입 시 갱신) ──
|
|
82
|
+
private _crashContext?: { stage: string; file?: string };
|
|
83
|
+
|
|
84
|
+
// ── Logger ──
|
|
85
|
+
// NOTE: 모듈 레벨이 아닌 인스턴스 레벨에서 생성해야 한다.
|
|
86
|
+
// consola.withTag는 호출 시점의 consola.level/reporters를 스냅샷 복사하므로,
|
|
87
|
+
// setupConsola 이전(모듈 import 시점)에 만들면 debug 레벨이 반영되지 않는다.
|
|
88
|
+
private readonly _logger: ConsolaInstance = consola.withTag("sd:cli:SdTsCompiler");
|
|
89
|
+
|
|
83
90
|
constructor(options: ISdTsCompilerOptions) {
|
|
84
91
|
this._options = options;
|
|
85
92
|
}
|
|
86
93
|
|
|
94
|
+
private _setCrashContext(stage: string, file?: string): void {
|
|
95
|
+
this._crashContext = { stage, file };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private _formatCrashContext(): string {
|
|
99
|
+
const ctx = this._crashContext;
|
|
100
|
+
if (ctx == null) return "unknown";
|
|
101
|
+
if (ctx.file != null) {
|
|
102
|
+
return `${ctx.stage} [${path.relative(this._options.cwd, ctx.file)}]`;
|
|
103
|
+
}
|
|
104
|
+
return ctx.stage;
|
|
105
|
+
}
|
|
106
|
+
|
|
87
107
|
private _getScssLoadPaths(): string[] {
|
|
88
108
|
const { pkgDir, cwd } = this._options;
|
|
89
109
|
return [path.join(pkgDir, "scss"), path.join(cwd, "node_modules")];
|
|
@@ -121,11 +141,20 @@ export class SdTsCompiler {
|
|
|
121
141
|
modifiedFiles?: ReadonlySet<string>,
|
|
122
142
|
emitOptions?: ISdTsCompilerEmitOptions,
|
|
123
143
|
): Promise<ISdTsCompilerResult> {
|
|
124
|
-
const { pkgDir } = this._options;
|
|
144
|
+
const { pkgDir, cwd } = this._options;
|
|
125
145
|
const pkgName = path.basename(pkgDir);
|
|
146
|
+
this._crashContext = undefined;
|
|
126
147
|
|
|
127
148
|
// 1. 증분: sourceFileCache 무효화 + packageJsonCache 클리어
|
|
128
149
|
if (modifiedFiles != null && modifiedFiles.size > 0) {
|
|
150
|
+
const sampleFiles = [...modifiedFiles]
|
|
151
|
+
.slice(0, 10)
|
|
152
|
+
.map((f) => path.relative(cwd, f))
|
|
153
|
+
.join(", ");
|
|
154
|
+
this._logger.debug(
|
|
155
|
+
`[${pkgName}] modifiedFiles (${modifiedFiles.size}개)${modifiedFiles.size > 10 ? " [상위 10개]" : ""}: ${sampleFiles}`,
|
|
156
|
+
);
|
|
157
|
+
|
|
129
158
|
if (this._sourceFileCache != null) {
|
|
130
159
|
this._sourceFileCache.invalidate(modifiedFiles);
|
|
131
160
|
}
|
|
@@ -149,12 +178,12 @@ export class SdTsCompiler {
|
|
|
149
178
|
? (parsed.raw.angularCompilerOptions as Record<string, unknown>)
|
|
150
179
|
: undefined;
|
|
151
180
|
|
|
152
|
-
|
|
181
|
+
this._logger.debug(`[${pkgName}] isForAngular: ${isForAngular}`);
|
|
153
182
|
|
|
154
183
|
// 3. rootNames 필터링
|
|
155
184
|
const rootNames = this._filterRootNames(parsed);
|
|
156
185
|
|
|
157
|
-
|
|
186
|
+
this._logger.debug(`[${pkgName}] rootNames: ${rootNames.length}개`);
|
|
158
187
|
|
|
159
188
|
// 4. compilerOptions 구성
|
|
160
189
|
const compilerOptions = this._buildCompilerOptions(
|
|
@@ -181,9 +210,10 @@ export class SdTsCompiler {
|
|
|
181
210
|
// 7. compiler host 생성
|
|
182
211
|
const host = this._createHost(compilerOptions, isForAngular, effectiveTransformStylesheet);
|
|
183
212
|
|
|
184
|
-
// 8. program 생성
|
|
213
|
+
// 8. program 생성 (체커 미진입 구간 — try 밖)
|
|
185
214
|
let program: ts.Program;
|
|
186
215
|
let builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram;
|
|
216
|
+
let angularProgram: NgtscProgram | undefined;
|
|
187
217
|
|
|
188
218
|
if (isForAngular) {
|
|
189
219
|
// Angular: sourceFileCache 확보
|
|
@@ -193,8 +223,8 @@ export class SdTsCompiler {
|
|
|
193
223
|
augmentHostWithCaching(host, this._sourceFileCache);
|
|
194
224
|
|
|
195
225
|
// NgtscProgram 생성
|
|
196
|
-
|
|
197
|
-
|
|
226
|
+
this._logger.debug(`[${pkgName}] NgtscProgram 생성 중...`);
|
|
227
|
+
angularProgram = new NgtscProgram(
|
|
198
228
|
rootNames,
|
|
199
229
|
compilerOptions,
|
|
200
230
|
host,
|
|
@@ -210,13 +240,6 @@ export class SdTsCompiler {
|
|
|
210
240
|
this._builderProgram,
|
|
211
241
|
);
|
|
212
242
|
program = tsProgram;
|
|
213
|
-
|
|
214
|
-
// 7. Angular analyzeAsync
|
|
215
|
-
logger.debug(`[${pkgName}] AOT analyzeAsync 시작`);
|
|
216
|
-
await angularProgram.compiler.analyzeAsync();
|
|
217
|
-
logger.debug(`[${pkgName}] AOT analyzeAsync 완료`);
|
|
218
|
-
|
|
219
|
-
this._ngtscProgram = angularProgram;
|
|
220
243
|
} else {
|
|
221
244
|
// Non-Angular: BuilderProgram 직접 생성
|
|
222
245
|
builderProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram(
|
|
@@ -228,84 +251,218 @@ export class SdTsCompiler {
|
|
|
228
251
|
program = builderProgram.getProgram();
|
|
229
252
|
}
|
|
230
253
|
|
|
231
|
-
//
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
this.
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
affectedFiles = result.affectedPaths;
|
|
241
|
-
} else {
|
|
242
|
-
affectedFiles = this._findAffectedFilesForTsc(builderProgram);
|
|
243
|
-
}
|
|
254
|
+
// 9. 위험 구간 (체커 진입 — TsCompiler 내부 크래시 단일 catch)
|
|
255
|
+
try {
|
|
256
|
+
if (isForAngular) {
|
|
257
|
+
this._setCrashContext("analyzeAsync");
|
|
258
|
+
this._logger.debug(`[${pkgName}] AOT analyzeAsync 시작`);
|
|
259
|
+
await angularProgram!.compiler.analyzeAsync();
|
|
260
|
+
this._logger.debug(`[${pkgName}] AOT analyzeAsync 완료`);
|
|
261
|
+
this._ngtscProgram = angularProgram;
|
|
262
|
+
}
|
|
244
263
|
|
|
245
|
-
|
|
264
|
+
// 9-1. affected files 추적
|
|
265
|
+
this._setCrashContext("findAffectedFiles");
|
|
266
|
+
let affectedFiles: ReadonlySet<string> | undefined;
|
|
267
|
+
if (isForAngular) {
|
|
268
|
+
const result = this._findAffectedFilesForAngular(
|
|
269
|
+
builderProgram,
|
|
270
|
+
this._ngtscProgram!.compiler,
|
|
271
|
+
this._sourceFileCache,
|
|
272
|
+
);
|
|
273
|
+
this._affectedSourceFiles = result.affectedSourceFiles;
|
|
274
|
+
affectedFiles = result.affectedPaths;
|
|
275
|
+
} else {
|
|
276
|
+
affectedFiles = this._findAffectedFilesForTsc(builderProgram);
|
|
277
|
+
}
|
|
246
278
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
279
|
+
if (affectedFiles != null) {
|
|
280
|
+
const sample = [...affectedFiles]
|
|
281
|
+
.slice(0, 10)
|
|
282
|
+
.map((f) => path.relative(cwd, f))
|
|
283
|
+
.join(", ");
|
|
284
|
+
this._logger.debug(
|
|
285
|
+
`[${pkgName}] affected files (${affectedFiles.size}개)${affectedFiles.size > 10 ? " [상위 10개]" : ""}: ${sample}`,
|
|
286
|
+
);
|
|
287
|
+
} else {
|
|
288
|
+
this._logger.debug(`[${pkgName}] affected files: 전체 (global change)`);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// 9-2. emit 처리
|
|
292
|
+
this._setCrashContext("emit");
|
|
293
|
+
let emitResults: EmitResult[] | undefined;
|
|
294
|
+
if (isForAngular) {
|
|
295
|
+
emitResults = this._emitAngular(
|
|
296
|
+
this._ngtscProgram!,
|
|
297
|
+
builderProgram,
|
|
298
|
+
this._affectedSourceFiles,
|
|
299
|
+
emitOptions,
|
|
300
|
+
);
|
|
301
|
+
} else {
|
|
302
|
+
this._emitTsc(builderProgram);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// 9-3. 진단 수집
|
|
306
|
+
this._setCrashContext("collectDiagnostics");
|
|
307
|
+
const rawDiagnostics = isForAngular
|
|
308
|
+
? this._collectDiagnosticsForAngular(
|
|
309
|
+
this._ngtscProgram!,
|
|
310
|
+
builderProgram,
|
|
311
|
+
this._affectedSourceFiles,
|
|
312
|
+
)
|
|
313
|
+
: this._collectDiagnosticsForTsc(builderProgram);
|
|
314
|
+
const diagResult = this._finalizeDiagnostics(rawDiagnostics);
|
|
315
|
+
|
|
316
|
+
// 9-4. 글로벌 SCSS + lint 병렬 실행
|
|
317
|
+
this._setCrashContext("lintAndGlobalScss");
|
|
318
|
+
const [, lintResult] = await Promise.all([
|
|
319
|
+
// globalScss
|
|
320
|
+
this._options.globalScss === true
|
|
321
|
+
? Promise.resolve().then(() => {
|
|
322
|
+
const loadPaths = this._getScssLoadPaths();
|
|
323
|
+
const globalScssErrors = compileGlobalScss(pkgDir, loadPaths);
|
|
324
|
+
this._scssErrors.push(...globalScssErrors);
|
|
325
|
+
})
|
|
326
|
+
: Promise.resolve(),
|
|
327
|
+
// lint
|
|
328
|
+
this._options.lint === true
|
|
329
|
+
? this._runLint(program, affectedFiles)
|
|
330
|
+
: Promise.resolve(undefined),
|
|
331
|
+
]);
|
|
332
|
+
|
|
333
|
+
// 9-5. 상태 저장
|
|
334
|
+
this._builderProgram = builderProgram;
|
|
335
|
+
this._crashContext = undefined;
|
|
336
|
+
|
|
337
|
+
this._logger.debug(`[${pkgName}] compileAsync 완료`);
|
|
338
|
+
|
|
339
|
+
return {
|
|
340
|
+
program,
|
|
252
341
|
builderProgram,
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
342
|
+
isForAngular,
|
|
343
|
+
affectedFiles,
|
|
344
|
+
diagnostics: diagResult.diagnostics,
|
|
345
|
+
errorCount: diagResult.errorCount,
|
|
346
|
+
warningCount: diagResult.warningCount,
|
|
347
|
+
errors: diagResult.errors,
|
|
348
|
+
ngtscProgram: this._ngtscProgram,
|
|
349
|
+
emitResults,
|
|
350
|
+
lint: lintResult,
|
|
351
|
+
scssErrors: [...this._scssErrors],
|
|
352
|
+
scssDependencies: new Map(this._scssDependencies),
|
|
353
|
+
};
|
|
354
|
+
} catch (e) {
|
|
355
|
+
// TsCompiler 내부 크래시 (TS 5.9 overload 버그 등) — 단일 에러 진단으로 degrade
|
|
356
|
+
const contextLabel = this._formatCrashContext();
|
|
357
|
+
const rawMsg = e instanceof Error ? (e.stack ?? e.message) : String(e);
|
|
358
|
+
this._logger.debug(`[${pkgName}] crash @${contextLabel}: ${rawMsg}`);
|
|
359
|
+
|
|
360
|
+
// per-file 프로브: affected 파일 각각을 개별 try-catch로 재체크하여 재현 파일 특정
|
|
361
|
+
const probeReport = isForAngular
|
|
362
|
+
? this._probeCrashPerFileAngular(
|
|
363
|
+
this._ngtscProgram,
|
|
364
|
+
builderProgram,
|
|
365
|
+
this._affectedSourceFiles,
|
|
366
|
+
)
|
|
367
|
+
: this._probeCrashPerFileTsc(builderProgram, this._affectedSourceFiles);
|
|
368
|
+
|
|
369
|
+
const parts: string[] = [
|
|
370
|
+
`TsCompiler 내부 크래시 @${contextLabel}`,
|
|
371
|
+
"",
|
|
372
|
+
rawMsg,
|
|
373
|
+
];
|
|
374
|
+
if (probeReport.length > 0) {
|
|
375
|
+
parts.push("", "크래시 재현 파일 (per-file 프로브):", ...probeReport);
|
|
376
|
+
}
|
|
377
|
+
const message = parts.join("\n");
|
|
259
378
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
379
|
+
const crashDiag: SerializedDiagnostic = {
|
|
380
|
+
category: ts.DiagnosticCategory.Error,
|
|
381
|
+
code: 0,
|
|
382
|
+
messageText: message,
|
|
383
|
+
};
|
|
384
|
+
return {
|
|
385
|
+
program,
|
|
265
386
|
builderProgram,
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
387
|
+
isForAngular,
|
|
388
|
+
affectedFiles: undefined,
|
|
389
|
+
diagnostics: [crashDiag],
|
|
390
|
+
errorCount: 1,
|
|
391
|
+
warningCount: 0,
|
|
392
|
+
errors: [message],
|
|
393
|
+
ngtscProgram: this._ngtscProgram,
|
|
394
|
+
emitResults: undefined,
|
|
395
|
+
lint: undefined,
|
|
396
|
+
scssErrors: [...this._scssErrors],
|
|
397
|
+
scssDependencies: new Map(this._scssDependencies),
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* 크래시 발생 후, affected sourceFile을 개별 try-catch로 재검사하여 원인 파일을 특정한다.
|
|
404
|
+
* Angular: `getDiagnosticsForFile(sf, SingleFile)` + `builderProgram.getSemanticDiagnostics(sf)` 개별 호출.
|
|
405
|
+
* 각 파일별로 크래시 재현 여부를 기록. 프로브 자체 크래시는 흡수한다.
|
|
406
|
+
*/
|
|
407
|
+
private _probeCrashPerFileAngular(
|
|
408
|
+
ngtscProgram: NgtscProgram | undefined,
|
|
409
|
+
builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram,
|
|
410
|
+
affectedSourceFiles: ReadonlySet<ts.SourceFile>,
|
|
411
|
+
): string[] {
|
|
412
|
+
const report: string[] = [];
|
|
413
|
+
const angularCompiler = ngtscProgram?.compiler;
|
|
414
|
+
const { cwd } = this._options;
|
|
415
|
+
|
|
416
|
+
for (const sf of affectedSourceFiles) {
|
|
417
|
+
if (angularCompiler?.ignoreForDiagnostics.has(sf) === true) continue;
|
|
418
|
+
|
|
419
|
+
const rel = path.relative(cwd, sf.fileName);
|
|
420
|
+
|
|
421
|
+
try {
|
|
422
|
+
builderProgram.getSemanticDiagnostics(sf);
|
|
423
|
+
} catch (e) {
|
|
424
|
+
report.push(
|
|
425
|
+
` - ${rel} [getSemanticDiagnostics]: ${e instanceof Error ? e.message : String(e)}`,
|
|
426
|
+
);
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (angularCompiler != null && !sf.isDeclarationFile) {
|
|
431
|
+
try {
|
|
432
|
+
angularCompiler.getDiagnosticsForFile(sf, OptimizeFor.SingleFile);
|
|
433
|
+
} catch (e) {
|
|
434
|
+
report.push(
|
|
435
|
+
` - ${rel} [getDiagnosticsForFile]: ${e instanceof Error ? e.message : String(e)}`,
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
270
439
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
// 11. 글로벌 SCSS + lint 병렬 실행
|
|
274
|
-
const [, lintResult] = await Promise.all([
|
|
275
|
-
// globalScss
|
|
276
|
-
this._options.globalScss === true
|
|
277
|
-
? Promise.resolve().then(() => {
|
|
278
|
-
const loadPaths = this._getScssLoadPaths();
|
|
279
|
-
const globalScssErrors = compileGlobalScss(pkgDir, loadPaths);
|
|
280
|
-
this._scssErrors.push(...globalScssErrors);
|
|
281
|
-
})
|
|
282
|
-
: Promise.resolve(),
|
|
283
|
-
// lint
|
|
284
|
-
this._options.lint === true
|
|
285
|
-
? this._runLint(program, affectedFiles)
|
|
286
|
-
: Promise.resolve(undefined),
|
|
287
|
-
]);
|
|
288
|
-
|
|
289
|
-
// 12. 상태 저장
|
|
290
|
-
this._builderProgram = builderProgram;
|
|
291
|
-
|
|
292
|
-
logger.debug(`[${pkgName}] compileAsync 완료`);
|
|
440
|
+
return report;
|
|
441
|
+
}
|
|
293
442
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
443
|
+
private _probeCrashPerFileTsc(
|
|
444
|
+
builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram,
|
|
445
|
+
affectedSourceFiles: ReadonlySet<ts.SourceFile>,
|
|
446
|
+
): string[] {
|
|
447
|
+
const report: string[] = [];
|
|
448
|
+
const { cwd } = this._options;
|
|
449
|
+
|
|
450
|
+
const targets =
|
|
451
|
+
affectedSourceFiles.size > 0
|
|
452
|
+
? affectedSourceFiles
|
|
453
|
+
: new Set(builderProgram.getSourceFiles());
|
|
454
|
+
|
|
455
|
+
for (const sf of targets) {
|
|
456
|
+
try {
|
|
457
|
+
builderProgram.getSemanticDiagnostics(sf);
|
|
458
|
+
} catch (e) {
|
|
459
|
+
const rel = path.relative(cwd, sf.fileName);
|
|
460
|
+
report.push(
|
|
461
|
+
` - ${rel} [getSemanticDiagnostics]: ${e instanceof Error ? e.message : String(e)}`,
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return report;
|
|
309
466
|
}
|
|
310
467
|
|
|
311
468
|
private async _runLint(
|
|
@@ -322,12 +479,12 @@ export class SdTsCompiler {
|
|
|
322
479
|
});
|
|
323
480
|
}
|
|
324
481
|
|
|
325
|
-
|
|
482
|
+
this._logger.debug(`[${pkgName}] lint 시작`);
|
|
326
483
|
const result = await this._lintRunner.lint({
|
|
327
484
|
program,
|
|
328
485
|
affectedFiles,
|
|
329
486
|
});
|
|
330
|
-
|
|
487
|
+
this._logger.debug(`[${pkgName}] lint 완료 (에러: ${result.errorCount}, 경고: ${result.warningCount})`);
|
|
331
488
|
|
|
332
489
|
return result;
|
|
333
490
|
}
|
|
@@ -456,14 +613,17 @@ export class SdTsCompiler {
|
|
|
456
613
|
private _collectDiagnosticsForTsc(
|
|
457
614
|
builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram,
|
|
458
615
|
): ts.Diagnostic[] {
|
|
459
|
-
|
|
616
|
+
const diagnostics: ts.Diagnostic[] = [
|
|
460
617
|
...builderProgram.getConfigFileParsingDiagnostics(),
|
|
461
618
|
...builderProgram.getSyntacticDiagnostics(),
|
|
462
619
|
...builderProgram.getOptionsDiagnostics(),
|
|
463
620
|
...builderProgram.getGlobalDiagnostics(),
|
|
464
621
|
...builderProgram.getSemanticDiagnostics(),
|
|
465
|
-
...(!this._options.output.dts ? builderProgram.getProgram().getDeclarationDiagnostics() : []),
|
|
466
622
|
];
|
|
623
|
+
if (!this._options.output.dts) {
|
|
624
|
+
diagnostics.push(...builderProgram.getProgram().getDeclarationDiagnostics());
|
|
625
|
+
}
|
|
626
|
+
return diagnostics;
|
|
467
627
|
}
|
|
468
628
|
|
|
469
629
|
private _collectDiagnosticsForAngular(
|
|
@@ -490,17 +650,9 @@ export class SdTsCompiler {
|
|
|
490
650
|
continue;
|
|
491
651
|
}
|
|
492
652
|
|
|
653
|
+
this._setCrashContext("collectDiagnostics.getSemanticDiagnostics", sourceFile.fileName);
|
|
493
654
|
diagnostics.push(...builderProgram.getSyntacticDiagnostics(sourceFile));
|
|
494
|
-
|
|
495
|
-
// TypeScript 5.9 + NgtscProgram: getSemanticDiagnostics 크래시 방어
|
|
496
|
-
let semanticDiags: readonly ts.Diagnostic[];
|
|
497
|
-
try {
|
|
498
|
-
semanticDiags = builderProgram.getSemanticDiagnostics(sourceFile);
|
|
499
|
-
} catch {
|
|
500
|
-
logger.debug(`getSemanticDiagnostics 크래시 (무시): ${sourceFile.fileName}`);
|
|
501
|
-
semanticDiags = [];
|
|
502
|
-
}
|
|
503
|
-
diagnostics.push(...semanticDiags);
|
|
655
|
+
diagnostics.push(...builderProgram.getSemanticDiagnostics(sourceFile));
|
|
504
656
|
|
|
505
657
|
// Declaration files는 Angular 진단 없음
|
|
506
658
|
if (sourceFile.isDeclarationFile) {
|
|
@@ -509,6 +661,7 @@ export class SdTsCompiler {
|
|
|
509
661
|
|
|
510
662
|
// Angular 템플릿 진단 (diagnosticCache 활용)
|
|
511
663
|
if (affectedSourceFiles.has(sourceFile)) {
|
|
664
|
+
this._setCrashContext("collectDiagnostics.getDiagnosticsForFile", sourceFile.fileName);
|
|
512
665
|
const angularDiagnostics = angularCompiler.getDiagnosticsForFile(
|
|
513
666
|
sourceFile,
|
|
514
667
|
optimization,
|
|
@@ -572,6 +725,7 @@ export class SdTsCompiler {
|
|
|
572
725
|
const tsProgram = ngtscProgram.getTsProgram();
|
|
573
726
|
|
|
574
727
|
// prepareEmit() → Angular transformers 획득
|
|
728
|
+
this._setCrashContext("emit.prepareEmit");
|
|
575
729
|
const transformers = angularCompiler.prepareEmit().transformers;
|
|
576
730
|
transformers.before ??= [];
|
|
577
731
|
transformers.after ??= [];
|
|
@@ -622,6 +776,7 @@ export class SdTsCompiler {
|
|
|
622
776
|
) {
|
|
623
777
|
continue;
|
|
624
778
|
}
|
|
779
|
+
this._setCrashContext("emit.tsProgram.emit", sourceFile.fileName);
|
|
625
780
|
tsProgram.emit(
|
|
626
781
|
sourceFile,
|
|
627
782
|
writeFileCallback,
|
|
@@ -631,15 +786,11 @@ export class SdTsCompiler {
|
|
|
631
786
|
);
|
|
632
787
|
}
|
|
633
788
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
builderProgram.emit(undefined, () => {});
|
|
637
|
-
} catch {
|
|
638
|
-
logger.debug("builderProgram.emit 크래시 (무시) — tsbuildinfo 영속화 생략");
|
|
639
|
-
}
|
|
789
|
+
this._setCrashContext("emit.builderProgram.emit");
|
|
790
|
+
builderProgram.emit(undefined, () => {});
|
|
640
791
|
|
|
641
792
|
// sourceFilter 적용
|
|
642
|
-
|
|
793
|
+
this._logger.debug(`emitAffectedFiles 완료 (${emitResults.length}개 파일)`);
|
|
643
794
|
if (emitOptions?.sourceFilter != null) {
|
|
644
795
|
return emitResults.filter((r) => emitOptions.sourceFilter!(r.sourceFileName));
|
|
645
796
|
}
|
|
@@ -656,7 +807,6 @@ export class SdTsCompiler {
|
|
|
656
807
|
if ("fileName" in result.affected) {
|
|
657
808
|
affectedFiles.add(pathx.posix(result.affected.fileName));
|
|
658
809
|
} else {
|
|
659
|
-
// ts.Program 반환 — 전역 변경, 전체 리빌드로 처리
|
|
660
810
|
return undefined;
|
|
661
811
|
}
|
|
662
812
|
}
|
|
@@ -667,40 +817,32 @@ export class SdTsCompiler {
|
|
|
667
817
|
builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram,
|
|
668
818
|
angularCompiler: NgCompiler,
|
|
669
819
|
sourceFileCache?: AngularSourceFileCache,
|
|
670
|
-
): {
|
|
671
|
-
|
|
820
|
+
): {
|
|
821
|
+
affectedSourceFiles: Set<ts.SourceFile>;
|
|
822
|
+
affectedPaths: ReadonlySet<string> | undefined;
|
|
823
|
+
} {
|
|
824
|
+
this._logger.debug("Angular affected 파일 탐색 시작");
|
|
672
825
|
const affectedSourceFiles = new Set<ts.SourceFile>();
|
|
673
826
|
let isGlobalChange = false;
|
|
674
827
|
|
|
675
828
|
while (true) {
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
)
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
if (originalSourceFile) {
|
|
688
|
-
affectedSourceFiles.add(originalSourceFile);
|
|
689
|
-
}
|
|
690
|
-
return true;
|
|
829
|
+
const result = builderProgram.getSemanticDiagnosticsOfNextAffectedFile(
|
|
830
|
+
undefined,
|
|
831
|
+
(sourceFile) => {
|
|
832
|
+
if (
|
|
833
|
+
angularCompiler.ignoreForDiagnostics.has(sourceFile) &&
|
|
834
|
+
sourceFile.fileName.endsWith(".ngtypecheck.ts")
|
|
835
|
+
) {
|
|
836
|
+
const originalFilename = sourceFile.fileName.slice(0, -15) + ".ts";
|
|
837
|
+
const originalSourceFile = builderProgram.getSourceFile(originalFilename);
|
|
838
|
+
if (originalSourceFile) {
|
|
839
|
+
affectedSourceFiles.add(originalSourceFile);
|
|
691
840
|
}
|
|
692
|
-
return
|
|
693
|
-
},
|
|
694
|
-
);
|
|
695
|
-
} catch {
|
|
696
|
-
logger.debug("getSemanticDiagnosticsOfNextAffectedFile 크래시 (무시) — 모든 소스를 affected로 처리");
|
|
697
|
-
for (const sourceFile of builderProgram.getSourceFiles()) {
|
|
698
|
-
if (!angularCompiler.ignoreForDiagnostics.has(sourceFile)) {
|
|
699
|
-
affectedSourceFiles.add(sourceFile);
|
|
841
|
+
return true;
|
|
700
842
|
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
843
|
+
return false;
|
|
844
|
+
},
|
|
845
|
+
);
|
|
704
846
|
if (!result) break;
|
|
705
847
|
if ("fileName" in result.affected) {
|
|
706
848
|
affectedSourceFiles.add(result.affected);
|
|
@@ -748,7 +890,7 @@ export class SdTsCompiler {
|
|
|
748
890
|
affectedPaths = paths;
|
|
749
891
|
}
|
|
750
892
|
|
|
751
|
-
|
|
893
|
+
this._logger.debug(`Angular affected 파일 탐색 완료 (${affectedSourceFiles.size}개)`);
|
|
752
894
|
return { affectedSourceFiles, affectedPaths };
|
|
753
895
|
}
|
|
754
896
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import ts from "typescript";
|
|
3
|
-
import { consola } from "consola";
|
|
4
3
|
import { pathx } from "@simplysm/core-node";
|
|
4
|
+
import { createLazyLogger } from "../runtime/lazy-logger";
|
|
5
5
|
import { parseTsconfig } from "../utils/tsconfig";
|
|
6
6
|
import { serializeDiagnostic, type SerializedDiagnostic } from "./typecheck-serialization";
|
|
7
7
|
|
|
8
|
-
const logger =
|
|
8
|
+
const logger = createLazyLogger("sd:cli:typecheck-non-pkg");
|
|
9
9
|
|
|
10
10
|
export interface NonPackageTypecheckResult {
|
|
11
11
|
success: boolean;
|