@simplysm/sd-cli 14.0.41 → 14.0.43
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/angular/angular-compiler.d.ts +0 -35
- package/dist/angular/angular-compiler.d.ts.map +1 -1
- package/dist/angular/angular-compiler.js +0 -374
- package/dist/angular/angular-compiler.js.map +1 -1
- package/dist/angular/hmr-candidates.d.ts +13 -0
- package/dist/angular/hmr-candidates.d.ts.map +1 -0
- package/dist/angular/hmr-candidates.js +230 -0
- package/dist/angular/hmr-candidates.js.map +1 -0
- package/dist/angular/ngtsc-build-core.d.ts +29 -34
- package/dist/angular/ngtsc-build-core.d.ts.map +1 -1
- package/dist/angular/ngtsc-build-core.js +90 -51
- package/dist/angular/ngtsc-build-core.js.map +1 -1
- package/dist/angular/vite-angular-plugin.d.ts +1 -1
- package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
- package/dist/angular/vite-angular-plugin.js +63 -56
- package/dist/angular/vite-angular-plugin.js.map +1 -1
- package/dist/angular/web-worker-transformer.d.ts +9 -0
- package/dist/angular/web-worker-transformer.d.ts.map +1 -0
- package/dist/angular/web-worker-transformer.js +73 -0
- package/dist/angular/web-worker-transformer.js.map +1 -0
- package/dist/capacitor/capacitor.d.ts.map +1 -1
- package/dist/capacitor/capacitor.js +6 -4
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/commands/check.d.ts +1 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +15 -65
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/publish/deployment-phase.d.ts.map +1 -1
- package/dist/commands/publish/deployment-phase.js +13 -5
- package/dist/commands/publish/deployment-phase.js.map +1 -1
- package/dist/commands/publish/npm-publisher.js +1 -1
- package/dist/commands/publish/npm-publisher.js.map +1 -1
- package/dist/commands/publish/publish-command.js +1 -1
- package/dist/commands/publish/publish-command.js.map +1 -1
- package/dist/commands/publish/version-upgrade.js +1 -1
- package/dist/commands/publish/version-upgrade.js.map +1 -1
- package/dist/commands/replace-deps.d.ts.map +1 -1
- package/dist/commands/replace-deps.js +2 -1
- package/dist/commands/replace-deps.js.map +1 -1
- package/dist/deps/replace-deps/collect-deps.d.ts.map +1 -1
- package/dist/deps/replace-deps/collect-deps.js +5 -2
- package/dist/deps/replace-deps/collect-deps.js.map +1 -1
- package/dist/deps/replace-deps/replace-deps.d.ts +21 -3
- package/dist/deps/replace-deps/replace-deps.d.ts.map +1 -1
- package/dist/deps/replace-deps/replace-deps.js +107 -62
- package/dist/deps/replace-deps/replace-deps.js.map +1 -1
- package/dist/electron/electron.js +7 -7
- package/dist/electron/electron.js.map +1 -1
- package/dist/engines/BaseEngine.d.ts.map +1 -1
- package/dist/engines/BaseEngine.js +2 -5
- package/dist/engines/BaseEngine.js.map +1 -1
- package/dist/engines/EsbuildClientEngine.d.ts.map +1 -1
- package/dist/engines/EsbuildClientEngine.js +16 -9
- package/dist/engines/EsbuildClientEngine.js.map +1 -1
- package/dist/engines/NgtscEngine.d.ts +4 -4
- package/dist/engines/NgtscEngine.d.ts.map +1 -1
- package/dist/engines/NgtscEngine.js +5 -5
- package/dist/engines/NgtscEngine.js.map +1 -1
- package/dist/engines/TscEngine.d.ts.map +1 -1
- package/dist/engines/TscEngine.js +0 -2
- package/dist/engines/TscEngine.js.map +1 -1
- package/dist/engines/types.d.ts +2 -0
- package/dist/engines/types.d.ts.map +1 -1
- package/dist/esbuild/esbuild-angular-compiler-plugin.d.ts +36 -0
- package/dist/esbuild/esbuild-angular-compiler-plugin.d.ts.map +1 -0
- package/dist/esbuild/esbuild-angular-compiler-plugin.js +464 -0
- package/dist/esbuild/esbuild-angular-compiler-plugin.js.map +1 -0
- package/dist/esbuild/esbuild-client-config.d.ts +8 -2
- package/dist/esbuild/esbuild-client-config.d.ts.map +1 -1
- package/dist/esbuild/esbuild-client-config.js +48 -33
- package/dist/esbuild/esbuild-client-config.js.map +1 -1
- package/dist/esbuild/esbuild-tsc-plugin.d.ts +4 -1
- package/dist/esbuild/esbuild-tsc-plugin.d.ts.map +1 -1
- package/dist/esbuild/esbuild-tsc-plugin.js +27 -23
- package/dist/esbuild/esbuild-tsc-plugin.js.map +1 -1
- package/dist/esbuild/file-reference-tracker.d.ts +24 -0
- package/dist/esbuild/file-reference-tracker.d.ts.map +1 -0
- package/dist/esbuild/file-reference-tracker.js +57 -0
- package/dist/esbuild/file-reference-tracker.js.map +1 -0
- package/dist/esbuild/lmdb-cache-store.d.ts +18 -0
- package/dist/esbuild/lmdb-cache-store.d.ts.map +1 -0
- package/dist/esbuild/lmdb-cache-store.js +41 -0
- package/dist/esbuild/lmdb-cache-store.js.map +1 -0
- package/dist/esbuild/load-result-cache.d.ts +17 -0
- package/dist/esbuild/load-result-cache.d.ts.map +1 -0
- package/dist/esbuild/load-result-cache.js +61 -0
- package/dist/esbuild/load-result-cache.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lint/lint-core.js +7 -7
- package/dist/lint/lint-core.js.map +1 -1
- package/dist/orchestrators/BaseOrchestrator.js +2 -2
- package/dist/orchestrators/BaseOrchestrator.js.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.js +5 -19
- package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
- package/dist/orchestrators/DevOrchestrator.js +5 -5
- package/dist/orchestrators/DevOrchestrator.js.map +1 -1
- package/dist/orchestrators/WatchOrchestrator.js +6 -6
- package/dist/orchestrators/WatchOrchestrator.js.map +1 -1
- package/dist/runtime/ResultCollector.d.ts +1 -0
- package/dist/runtime/ResultCollector.d.ts.map +1 -1
- package/dist/runtime/ResultCollector.js.map +1 -1
- package/dist/runtime/engine-watch-events.d.ts.map +1 -1
- package/dist/runtime/engine-watch-events.js +3 -0
- package/dist/runtime/engine-watch-events.js.map +1 -1
- package/dist/runtime/rebuild-manager.js +1 -1
- package/dist/runtime/rebuild-manager.js.map +1 -1
- package/dist/runtime/worker-utils.js +1 -1
- package/dist/runtime/worker-utils.js.map +1 -1
- package/dist/sd-cli-entry.d.ts.map +1 -1
- package/dist/sd-cli-entry.js +4 -3
- package/dist/sd-cli-entry.js.map +1 -1
- package/dist/sd-cli.js +3 -3
- package/dist/sd-cli.js.map +1 -1
- package/dist/ts-compiler/SdTsCompiler.d.ts +39 -0
- package/dist/ts-compiler/SdTsCompiler.d.ts.map +1 -0
- package/dist/ts-compiler/SdTsCompiler.js +593 -0
- package/dist/ts-compiler/SdTsCompiler.js.map +1 -0
- package/dist/ts-compiler/sd-ts-compiler-options.d.ts +40 -0
- package/dist/ts-compiler/sd-ts-compiler-options.d.ts.map +1 -0
- package/dist/ts-compiler/sd-ts-compiler-options.js +2 -0
- package/dist/ts-compiler/sd-ts-compiler-options.js.map +1 -0
- package/dist/ts-compiler/sd-ts-compiler-result.d.ts +34 -0
- package/dist/ts-compiler/sd-ts-compiler-result.d.ts.map +1 -0
- package/dist/ts-compiler/sd-ts-compiler-result.js +2 -0
- package/dist/ts-compiler/sd-ts-compiler-result.js.map +1 -0
- package/dist/utils/copy-public.d.ts +6 -4
- package/dist/utils/copy-public.d.ts.map +1 -1
- package/dist/utils/copy-public.js +9 -7
- package/dist/utils/copy-public.js.map +1 -1
- package/dist/utils/diagnostic-utils.d.ts +2 -3
- package/dist/utils/diagnostic-utils.d.ts.map +1 -1
- package/dist/utils/diagnostic-utils.js +8 -9
- package/dist/utils/diagnostic-utils.js.map +1 -1
- package/dist/utils/output-utils.d.ts +8 -2
- package/dist/utils/output-utils.d.ts.map +1 -1
- package/dist/utils/output-utils.js +32 -8
- package/dist/utils/output-utils.js.map +1 -1
- package/dist/workers/client.worker.d.ts +1 -1
- package/dist/workers/client.worker.d.ts.map +1 -1
- package/dist/workers/client.worker.js +136 -110
- package/dist/workers/client.worker.js.map +1 -1
- package/dist/workers/library-build.worker.d.ts +0 -2
- package/dist/workers/library-build.worker.d.ts.map +1 -1
- package/dist/workers/library-build.worker.js +147 -70
- package/dist/workers/library-build.worker.js.map +1 -1
- package/dist/workers/server-build.worker.d.ts.map +1 -1
- package/dist/workers/server-build.worker.js +30 -57
- package/dist/workers/server-build.worker.js.map +1 -1
- package/dist/workers/server-esbuild-context.d.ts +7 -0
- package/dist/workers/server-esbuild-context.d.ts.map +1 -1
- package/dist/workers/server-esbuild-context.js +11 -2
- package/dist/workers/server-esbuild-context.js.map +1 -1
- package/package.json +7 -6
- package/src/angular/angular-compiler.ts +0 -502
- package/src/angular/hmr-candidates.ts +295 -0
- package/src/angular/ngtsc-build-core.ts +125 -92
- package/src/angular/vite-angular-plugin.ts +71 -65
- package/src/angular/web-worker-transformer.ts +117 -0
- package/src/capacitor/capacitor.ts +6 -4
- package/src/commands/check.ts +17 -76
- package/src/commands/publish/deployment-phase.ts +11 -7
- package/src/commands/publish/npm-publisher.ts +1 -1
- package/src/commands/publish/publish-command.ts +1 -1
- package/src/commands/publish/version-upgrade.ts +1 -1
- package/src/commands/replace-deps.ts +3 -1
- package/src/deps/replace-deps/collect-deps.ts +4 -2
- package/src/deps/replace-deps/replace-deps.ts +114 -66
- package/src/electron/electron.ts +7 -7
- package/src/engines/BaseEngine.ts +2 -6
- package/src/engines/EsbuildClientEngine.ts +16 -10
- package/src/engines/NgtscEngine.ts +7 -7
- package/src/engines/TscEngine.ts +0 -2
- package/src/engines/types.ts +2 -0
- package/src/esbuild/esbuild-angular-compiler-plugin.ts +647 -0
- package/src/esbuild/esbuild-client-config.ts +57 -41
- package/src/esbuild/esbuild-tsc-plugin.ts +33 -23
- package/src/esbuild/file-reference-tracker.ts +61 -0
- package/src/esbuild/lmdb-cache-store.ts +46 -0
- package/src/esbuild/load-result-cache.ts +85 -0
- package/src/index.ts +5 -0
- package/src/lint/lint-core.ts +7 -7
- package/src/orchestrators/BaseOrchestrator.ts +2 -2
- package/src/orchestrators/BuildOrchestrator.ts +5 -24
- package/src/orchestrators/DevOrchestrator.ts +5 -5
- package/src/orchestrators/WatchOrchestrator.ts +6 -6
- package/src/runtime/ResultCollector.ts +1 -0
- package/src/runtime/engine-watch-events.ts +3 -0
- package/src/runtime/rebuild-manager.ts +1 -1
- package/src/runtime/worker-utils.ts +1 -1
- package/src/sd-cli-entry.ts +5 -3
- package/src/sd-cli.ts +4 -4
- package/src/ts-compiler/SdTsCompiler.ts +815 -0
- package/src/ts-compiler/sd-ts-compiler-options.ts +46 -0
- package/src/ts-compiler/sd-ts-compiler-result.ts +34 -0
- package/src/utils/copy-public.ts +9 -6
- package/src/utils/diagnostic-utils.ts +8 -9
- package/src/utils/output-utils.ts +38 -8
- package/src/workers/client.worker.ts +160 -126
- package/src/workers/library-build.worker.ts +187 -75
- package/src/workers/server-build.worker.ts +31 -61
- package/src/workers/server-esbuild-context.ts +14 -2
- package/tests/angular/fixtures/packages/basic-app/dist/styles.css +3 -0
- package/tests/angular/fixtures/packages/basic-app/scss/styles.scss +5 -0
- package/tests/angular/vite-angular-plugin-sdtscompiler.verify.md +13 -0
- package/tests/angular/web-worker-transformer.spec.ts +154 -0
- package/tests/capacitor/capacitor-build.spec.ts +1 -1
- package/tests/capacitor/capacitor-icon.spec.ts +1 -1
- package/tests/capacitor/capacitor-init.spec.ts +1 -1
- package/tests/commands/check.spec.ts +90 -104
- package/tests/commands/publish.spec.ts +12 -4
- package/tests/commands/slice3-severity-cleanup.verify.md +12 -0
- package/tests/deps/replace-deps/collect-deps.acc.spec.ts +62 -0
- package/tests/deps/replace-deps/collect-deps.spec.ts +49 -0
- package/tests/deps/replace-deps/replace-deps-filter.spec.ts +103 -0
- package/tests/deps/replace-deps/replace-deps-setup.acc.spec.ts +156 -0
- package/tests/electron/electron.spec.ts +4 -1
- package/tests/engines/engine-adapter-isolation.spec.ts +5 -6
- package/tests/engines/engine-duplicate-output-removal.verify.md +10 -0
- package/tests/engines/esbuild-client-engine.acc.spec.ts +79 -0
- package/tests/engines/esbuild-client-engine.spec.ts +73 -3
- package/tests/esbuild/esbuild-angular-compiler-plugin-hmr.verify.md +23 -0
- package/tests/esbuild/esbuild-angular-compiler-plugin-onload.verify.md +21 -0
- package/tests/esbuild/esbuild-angular-compiler-plugin-onstart-extraction.verify.md +16 -0
- package/tests/esbuild/esbuild-angular-compiler-plugin-sdtscompiler.verify.md +15 -0
- package/tests/esbuild/esbuild-angular-compiler-plugin-stylesheet.verify.md +31 -0
- package/tests/esbuild/esbuild-angular-compiler-plugin-worker.verify.md +31 -0
- package/tests/esbuild/esbuild-angular-compiler-plugin.spec.ts +397 -0
- package/tests/esbuild/esbuild-angular-compiler-plugin.verify.md +21 -0
- package/tests/esbuild/esbuild-tsc-plugin-imports.verify.md +13 -0
- package/tests/esbuild/esbuild-tsc-plugin.acc.spec.ts +56 -111
- package/tests/esbuild/esbuild-tsc-plugin.spec.ts +116 -52
- package/tests/esbuild/file-reference-tracker.spec.ts +99 -0
- package/tests/esbuild/lmdb-cache-store.spec.ts +58 -0
- package/tests/esbuild/load-result-cache.acc.spec.ts +55 -0
- package/tests/esbuild/load-result-cache.spec.ts +133 -0
- package/tests/orchestrators/build-orchestrator.spec.ts +4 -3
- package/tests/orchestrators/dev-orchestrator.spec.ts +5 -5
- package/tests/orchestrators/slice1-stdout-to-consola.verify.md +10 -0
- package/tests/orchestrators/typecheck-orchestrator.spec.ts +1 -1
- package/tests/orchestrators/watch-orchestrator.spec.ts +7 -7
- package/tests/runtime/result-collector.spec.ts +64 -0
- package/tests/sd-cli-entry.spec.ts +3 -4
- package/tests/sd-cli-log-tag.verify.md +11 -0
- package/tests/ts-compiler/SdTsCompiler-affected-files.verify.md +8 -0
- package/tests/ts-compiler/SdTsCompiler-diagnostics.verify.md +12 -0
- package/tests/ts-compiler/SdTsCompiler-emit.verify.md +9 -0
- package/tests/ts-compiler/SdTsCompiler.acc.spec.ts +603 -0
- package/tests/ts-compiler/SdTsCompiler.spec.ts +265 -0
- package/tests/ts-compiler/SdTsCompiler.verify.md +41 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck-browser.tsbuildinfo +1 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck-node.tsbuildinfo +1 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck.tsbuildinfo +1 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/dist/index.d.ts +2 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/dist/index.d.ts.map +1 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/dist/index.js +4 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/dist/index.js.map +1 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/dist/util.d.ts +2 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/dist/util.d.ts.map +1 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/dist/util.js +4 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/dist/util.js.map +1 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/src/index.ts +3 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/src/util.ts +3 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/tests/sample.test-file.ts +3 -0
- package/tests/ts-compiler/fixtures/non-angular-pkg/tsconfig.json +12 -0
- package/tests/ts-compiler/scss-lint-integration.verify.md +14 -0
- package/tests/utils/angular-build.spec.ts +1 -1
- package/tests/utils/copy-public-outdir.verify.md +8 -0
- package/tests/utils/copy-public.acc.spec.ts +52 -0
- package/tests/utils/copy-public.spec.ts +56 -0
- package/tests/utils/diagnostic-utils.spec.ts +24 -15
- package/tests/utils/engine-watch-events.acc.spec.ts +59 -0
- package/tests/utils/engine-watch-events.spec.ts +58 -0
- package/tests/utils/esbuild-client-config-integration.verify.md +9 -0
- package/tests/utils/esbuild-client-config.acc.spec.ts +45 -61
- package/tests/utils/esbuild-client-config.spec.ts +70 -52
- package/tests/utils/ngtsc-build-core-write-emit.spec.ts +12 -12
- package/tests/utils/ngtsc-build-core.spec.ts +1 -44
- package/tests/utils/output-utils.spec.ts +133 -13
- package/tests/utils/replace-deps-watch.acc.spec.ts +7 -1
- package/tests/utils/replace-deps-watch.spec.ts +57 -1
- package/tests/utils/worker-utils.spec.ts +8 -2
- package/tests/workers/client-worker-initial-build-error.verify.md +2 -3
- package/tests/workers/client-worker-initial-build-warnings.verify.md +7 -0
- package/tests/workers/client-worker-refactor.verify.md +22 -0
- package/tests/workers/client-worker-ts-cache-invalidation.verify.md +12 -0
- package/tests/workers/client-worker.acc.spec.ts +6 -3
- package/tests/workers/library-build-lint.spec.ts +40 -45
- package/tests/workers/library-build-worker.spec.ts +294 -40
- package/tests/workers/server-build-lint.spec.ts +59 -45
- package/tests/workers/server-build-worker.spec.ts +63 -24
- package/tests/workers/server-esbuild-context.acc.spec.ts +2 -0
- package/tests/workers/server-esbuild-context.spec.ts +2 -0
- package/tests/workers/server-runtime-worker.spec.ts +1 -1
- package/tests/workers/shared-worker-lifecycle.acc.spec.ts +1 -1
- package/dist/angular/angular-build-pipeline.d.ts +0 -97
- package/dist/angular/angular-build-pipeline.d.ts.map +0 -1
- package/dist/angular/angular-build-pipeline.js +0 -285
- package/dist/angular/angular-build-pipeline.js.map +0 -1
- package/dist/utils/tsc-build.d.ts +0 -51
- package/dist/utils/tsc-build.d.ts.map +0 -1
- package/dist/utils/tsc-build.js +0 -156
- package/dist/utils/tsc-build.js.map +0 -1
- package/dist/workers/ngtsc-build.worker.d.ts +0 -23
- package/dist/workers/ngtsc-build.worker.d.ts.map +0 -1
- package/dist/workers/ngtsc-build.worker.js +0 -267
- package/dist/workers/ngtsc-build.worker.js.map +0 -1
- package/src/angular/angular-build-pipeline.ts +0 -406
- package/src/utils/tsc-build.ts +0 -226
- package/src/workers/ngtsc-build.worker.ts +0 -351
- package/tests/angular/angular-build-pipeline.spec.ts +0 -247
- package/tests/angular/angular-compiler-aot.acc.spec.ts +0 -68
- package/tests/angular/angular-compiler-aot.spec.ts +0 -80
- package/tests/utils/angular-compiler-emit.spec.ts +0 -666
- package/tests/utils/angular-compiler.spec.ts +0 -707
- package/tests/utils/tsc-build.spec.ts +0 -527
- package/tests/workers/ngtsc-build-lint.spec.ts +0 -141
- package/tests/workers/ngtsc-build-worker.spec.ts +0 -199
|
@@ -0,0 +1,815 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { createHash } from "crypto";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
import { consola } from "consola";
|
|
5
|
+
import { pathx } from "@simplysm/core-node";
|
|
6
|
+
import type { ISdTsCompilerOptions, ISdTsCompilerEmitOptions } from "./sd-ts-compiler-options";
|
|
7
|
+
import type { ISdTsCompilerResult } from "./sd-ts-compiler-result";
|
|
8
|
+
import type { EmitResult } from "../angular/angular-compiler";
|
|
9
|
+
import {
|
|
10
|
+
parseTsconfig,
|
|
11
|
+
getPackageSourceFiles,
|
|
12
|
+
getPackageFiles,
|
|
13
|
+
getCompilerOptionsForEnv,
|
|
14
|
+
} from "../utils/tsconfig";
|
|
15
|
+
import { createOutputPathRewriter, addJsExtensionToImports } from "../utils/output-path-rewriter";
|
|
16
|
+
import { serializeDiagnostic, type SerializedDiagnostic } from "../typecheck/typecheck-serialization";
|
|
17
|
+
import { isWorkspaceDiagnostic, formatDiagnosticError } from "../utils/diagnostic-utils";
|
|
18
|
+
import { NgtscProgram, OptimizeFor } from "../angular/angular-build";
|
|
19
|
+
import {
|
|
20
|
+
AngularSourceFileCache,
|
|
21
|
+
augmentHostWithCaching,
|
|
22
|
+
} from "../angular/angular-compiler";
|
|
23
|
+
import {
|
|
24
|
+
createLibraryTransformStylesheet,
|
|
25
|
+
compileGlobalScss,
|
|
26
|
+
compileSideEffectScss as compileSideEffectScssEntries,
|
|
27
|
+
type SideEffectScssEntry,
|
|
28
|
+
} from "../angular/ngtsc-build-core";
|
|
29
|
+
import { LintWithProgramRunner, type LintWithProgramResult } from "../lint/lint-with-program";
|
|
30
|
+
|
|
31
|
+
const logger = consola.withTag("sd:cli:SdTsCompiler");
|
|
32
|
+
|
|
33
|
+
type NgCompiler = NgtscProgram["compiler"];
|
|
34
|
+
|
|
35
|
+
function hasTemplateExtension(file: string): boolean {
|
|
36
|
+
const ext = path.extname(file).toLowerCase();
|
|
37
|
+
return ext === ".htm" || ext === ".html" || ext === ".svg";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function ensureSourceFileVersions(program: ts.Program): void {
|
|
41
|
+
const baseGetSourceFiles = program.getSourceFiles;
|
|
42
|
+
program.getSourceFiles = function (...parameters: Parameters<typeof baseGetSourceFiles>) {
|
|
43
|
+
const files = baseGetSourceFiles.apply(this, parameters);
|
|
44
|
+
for (const file of files) {
|
|
45
|
+
if ((file as unknown as { version?: string }).version == null) {
|
|
46
|
+
(file as unknown as { version: string }).version = createHash("sha256")
|
|
47
|
+
.update(file.text)
|
|
48
|
+
.digest("hex");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return files;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class SdTsCompiler {
|
|
56
|
+
private readonly _options: ISdTsCompilerOptions;
|
|
57
|
+
|
|
58
|
+
// ── 파생 상태 (첫 compileAsync에서 결정) ──
|
|
59
|
+
private _isForAngular?: boolean;
|
|
60
|
+
private _sourceFileCache?: AngularSourceFileCache;
|
|
61
|
+
|
|
62
|
+
// ── 컴파일 상태 (compileAsync마다 갱신) ──
|
|
63
|
+
private _ngtscProgram?: NgtscProgram;
|
|
64
|
+
private _builderProgram?: ts.EmitAndSemanticDiagnosticsBuilderProgram;
|
|
65
|
+
|
|
66
|
+
// ── 영속 상태 (compileAsync 간 재사용) ──
|
|
67
|
+
private _packageJsonCache?: ts.PackageJsonInfoCache;
|
|
68
|
+
private readonly _diagnosticCache = new WeakMap<ts.SourceFile, ts.Diagnostic[]>();
|
|
69
|
+
|
|
70
|
+
// ── affected files (compileAsync에서 갱신, emit/diagnostics에서 사용) ──
|
|
71
|
+
private _affectedSourceFiles = new Set<ts.SourceFile>();
|
|
72
|
+
|
|
73
|
+
// ── SCSS 상태 (compileAsync마다 리셋)
|
|
74
|
+
private readonly _scssErrors: string[] = [];
|
|
75
|
+
private readonly _scssDependencies = new Map<string, Set<string>>();
|
|
76
|
+
|
|
77
|
+
// ── Side-effect SCSS (compileAsync 간 유지) ──
|
|
78
|
+
private readonly _sideEffectScssRegistry = new Map<string, SideEffectScssEntry>();
|
|
79
|
+
|
|
80
|
+
// ── Lint (lazy init, 인스턴스 재사용) ──
|
|
81
|
+
private _lintRunner?: LintWithProgramRunner;
|
|
82
|
+
|
|
83
|
+
constructor(options: ISdTsCompilerOptions) {
|
|
84
|
+
this._options = options;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private _getScssLoadPaths(): string[] {
|
|
88
|
+
const { pkgDir, cwd } = this._options;
|
|
89
|
+
return [path.join(pkgDir, "scss"), path.join(cwd, "node_modules")];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Side-effect SCSS 레지스트리 참조 (emit 코드에서 항목 등록용) */
|
|
93
|
+
get sideEffectScssRegistry(): Map<string, SideEffectScssEntry> {
|
|
94
|
+
return this._sideEffectScssRegistry;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Side-effect SCSS 레지스트리의 모든 항목을 CSS로 컴파일 */
|
|
98
|
+
compileSideEffectScss(): void {
|
|
99
|
+
const loadPaths = this._getScssLoadPaths();
|
|
100
|
+
compileSideEffectScssEntries(
|
|
101
|
+
this._sideEffectScssRegistry,
|
|
102
|
+
loadPaths,
|
|
103
|
+
this._scssErrors,
|
|
104
|
+
this._scssDependencies,
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** SCSS 의존성 역방향 탐색: scssPath에 의존하는 파일 목록 반환 */
|
|
109
|
+
findAffectedByScss(scssPath: string): string[] {
|
|
110
|
+
const normalizedPath = pathx.posix(scssPath);
|
|
111
|
+
const affected: string[] = [];
|
|
112
|
+
for (const [ownerFile, deps] of this._scssDependencies) {
|
|
113
|
+
if (deps.has(normalizedPath)) {
|
|
114
|
+
affected.push(ownerFile);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return affected;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async compileAsync(
|
|
121
|
+
modifiedFiles?: ReadonlySet<string>,
|
|
122
|
+
emitOptions?: ISdTsCompilerEmitOptions,
|
|
123
|
+
): Promise<ISdTsCompilerResult> {
|
|
124
|
+
const { pkgDir } = this._options;
|
|
125
|
+
const pkgName = path.basename(pkgDir);
|
|
126
|
+
|
|
127
|
+
// 1. 증분: sourceFileCache 무효화 + packageJsonCache 클리어
|
|
128
|
+
if (modifiedFiles != null && modifiedFiles.size > 0) {
|
|
129
|
+
if (this._sourceFileCache != null) {
|
|
130
|
+
this._sourceFileCache.invalidate(modifiedFiles);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// node_modules 변경 시 packageJsonCache 클리어 (stale 모듈 해석 방지)
|
|
134
|
+
if (this._packageJsonCache != null) {
|
|
135
|
+
for (const file of modifiedFiles) {
|
|
136
|
+
if (file.includes("node_modules")) {
|
|
137
|
+
this._packageJsonCache.clear();
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// 2. tsconfig 파싱 (매 호출)
|
|
145
|
+
const parsed = parseTsconfig(pkgDir);
|
|
146
|
+
const isForAngular = parsed.raw?.angularCompilerOptions != null;
|
|
147
|
+
this._isForAngular = isForAngular;
|
|
148
|
+
const angularCompilerOptions = isForAngular
|
|
149
|
+
? (parsed.raw.angularCompilerOptions as Record<string, unknown>)
|
|
150
|
+
: undefined;
|
|
151
|
+
|
|
152
|
+
logger.debug(`[${pkgName}] isForAngular: ${isForAngular}`);
|
|
153
|
+
|
|
154
|
+
// 3. rootNames 필터링
|
|
155
|
+
const rootNames = this._filterRootNames(parsed);
|
|
156
|
+
|
|
157
|
+
logger.debug(`[${pkgName}] rootNames: ${rootNames.length}개`);
|
|
158
|
+
|
|
159
|
+
// 4. compilerOptions 구성
|
|
160
|
+
const compilerOptions = this._buildCompilerOptions(
|
|
161
|
+
parsed.options,
|
|
162
|
+
isForAngular,
|
|
163
|
+
angularCompilerOptions,
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// 5. SCSS 상태 리셋
|
|
167
|
+
this._scssErrors.length = 0;
|
|
168
|
+
this._scssDependencies.clear();
|
|
169
|
+
|
|
170
|
+
// 6. transformStylesheet 결정: isForAngular + 미제공 시 라이브러리 콜백 자동 생성
|
|
171
|
+
let effectiveTransformStylesheet = this._options.transformStylesheet;
|
|
172
|
+
if (isForAngular && effectiveTransformStylesheet == null) {
|
|
173
|
+
const loadPaths = this._getScssLoadPaths();
|
|
174
|
+
effectiveTransformStylesheet = createLibraryTransformStylesheet(
|
|
175
|
+
loadPaths,
|
|
176
|
+
this._scssErrors,
|
|
177
|
+
this._scssDependencies,
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 7. compiler host 생성
|
|
182
|
+
const host = this._createHost(compilerOptions, isForAngular, effectiveTransformStylesheet);
|
|
183
|
+
|
|
184
|
+
// 8. program 생성
|
|
185
|
+
let program: ts.Program;
|
|
186
|
+
let builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram;
|
|
187
|
+
|
|
188
|
+
if (isForAngular) {
|
|
189
|
+
// Angular: sourceFileCache 확보
|
|
190
|
+
if (this._sourceFileCache == null) {
|
|
191
|
+
this._sourceFileCache = this._options.sourceFileCache ?? new AngularSourceFileCache();
|
|
192
|
+
}
|
|
193
|
+
augmentHostWithCaching(host, this._sourceFileCache);
|
|
194
|
+
|
|
195
|
+
// NgtscProgram 생성
|
|
196
|
+
logger.debug(`[${pkgName}] NgtscProgram 생성 중...`);
|
|
197
|
+
const angularProgram = new NgtscProgram(
|
|
198
|
+
rootNames,
|
|
199
|
+
compilerOptions,
|
|
200
|
+
host,
|
|
201
|
+
this._ngtscProgram,
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
const tsProgram = angularProgram.getTsProgram();
|
|
205
|
+
ensureSourceFileVersions(tsProgram);
|
|
206
|
+
|
|
207
|
+
builderProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram(
|
|
208
|
+
tsProgram,
|
|
209
|
+
host,
|
|
210
|
+
this._builderProgram,
|
|
211
|
+
);
|
|
212
|
+
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
|
+
} else {
|
|
221
|
+
// Non-Angular: BuilderProgram 직접 생성
|
|
222
|
+
builderProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram(
|
|
223
|
+
rootNames,
|
|
224
|
+
compilerOptions,
|
|
225
|
+
host,
|
|
226
|
+
this._builderProgram,
|
|
227
|
+
);
|
|
228
|
+
program = builderProgram.getProgram();
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// 8. affected files 추적
|
|
232
|
+
let affectedFiles: ReadonlySet<string> | undefined;
|
|
233
|
+
if (isForAngular) {
|
|
234
|
+
const result = this._findAffectedFilesForAngular(
|
|
235
|
+
builderProgram,
|
|
236
|
+
this._ngtscProgram!.compiler,
|
|
237
|
+
this._sourceFileCache,
|
|
238
|
+
);
|
|
239
|
+
this._affectedSourceFiles = result.affectedSourceFiles;
|
|
240
|
+
affectedFiles = result.affectedPaths;
|
|
241
|
+
} else {
|
|
242
|
+
affectedFiles = this._findAffectedFilesForTsc(builderProgram);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
logger.debug(`[${pkgName}] affected files: ${affectedFiles != null ? `${affectedFiles.size}개` : "전체 (global change)"}`);
|
|
246
|
+
|
|
247
|
+
// 9. emit 처리
|
|
248
|
+
let emitResults: EmitResult[] | undefined;
|
|
249
|
+
if (isForAngular) {
|
|
250
|
+
emitResults = this._emitAngular(
|
|
251
|
+
this._ngtscProgram!,
|
|
252
|
+
builderProgram,
|
|
253
|
+
this._affectedSourceFiles,
|
|
254
|
+
emitOptions,
|
|
255
|
+
);
|
|
256
|
+
} else {
|
|
257
|
+
this._emitTsc(builderProgram);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 10. 진단 수집
|
|
261
|
+
let rawDiagnostics: ts.Diagnostic[];
|
|
262
|
+
if (isForAngular) {
|
|
263
|
+
rawDiagnostics = this._collectDiagnosticsForAngular(
|
|
264
|
+
this._ngtscProgram!,
|
|
265
|
+
builderProgram,
|
|
266
|
+
this._affectedSourceFiles,
|
|
267
|
+
);
|
|
268
|
+
} else {
|
|
269
|
+
rawDiagnostics = this._collectDiagnosticsForTsc(builderProgram);
|
|
270
|
+
}
|
|
271
|
+
const diagResult = this._finalizeDiagnostics(rawDiagnostics);
|
|
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 완료`);
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
program,
|
|
296
|
+
builderProgram,
|
|
297
|
+
isForAngular,
|
|
298
|
+
affectedFiles,
|
|
299
|
+
diagnostics: diagResult.diagnostics,
|
|
300
|
+
errorCount: diagResult.errorCount,
|
|
301
|
+
warningCount: diagResult.warningCount,
|
|
302
|
+
errors: diagResult.errors,
|
|
303
|
+
ngtscProgram: this._ngtscProgram,
|
|
304
|
+
emitResults,
|
|
305
|
+
lint: lintResult,
|
|
306
|
+
scssErrors: [...this._scssErrors],
|
|
307
|
+
scssDependencies: new Map(this._scssDependencies),
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
private async _runLint(
|
|
312
|
+
program: ts.Program,
|
|
313
|
+
affectedFiles?: ReadonlySet<string>,
|
|
314
|
+
): Promise<LintWithProgramResult> {
|
|
315
|
+
const { cwd, pkgDir } = this._options;
|
|
316
|
+
const pkgName = path.basename(pkgDir);
|
|
317
|
+
|
|
318
|
+
if (this._lintRunner == null) {
|
|
319
|
+
this._lintRunner = new LintWithProgramRunner({
|
|
320
|
+
cwd,
|
|
321
|
+
pkgName,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
logger.debug(`[${pkgName}] lint 시작`);
|
|
326
|
+
const result = await this._lintRunner.lint({
|
|
327
|
+
program,
|
|
328
|
+
affectedFiles,
|
|
329
|
+
});
|
|
330
|
+
logger.debug(`[${pkgName}] lint 완료 (에러: ${result.errorCount}, 경고: ${result.warningCount})`);
|
|
331
|
+
|
|
332
|
+
return result;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
private _filterRootNames(parsed: ts.ParsedCommandLine): string[] {
|
|
336
|
+
const { pkgDir, includeTests } = this._options;
|
|
337
|
+
|
|
338
|
+
if (includeTests === true) {
|
|
339
|
+
return getPackageFiles(pkgDir, parsed);
|
|
340
|
+
}
|
|
341
|
+
return getPackageSourceFiles(pkgDir, parsed);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
private _buildCompilerOptions(
|
|
345
|
+
baseOptions: ts.CompilerOptions,
|
|
346
|
+
isForAngular: boolean,
|
|
347
|
+
angularCompilerOptions?: Record<string, unknown>,
|
|
348
|
+
): ts.CompilerOptions {
|
|
349
|
+
const { pkgDir, output, env, compilerOptionsTransformer } = this._options;
|
|
350
|
+
const needsEmit = output.js || output.dts;
|
|
351
|
+
|
|
352
|
+
// env 조정
|
|
353
|
+
let options = env != null
|
|
354
|
+
? getCompilerOptionsForEnv(baseOptions, env, pkgDir)
|
|
355
|
+
: { ...baseOptions };
|
|
356
|
+
|
|
357
|
+
// output 플래그
|
|
358
|
+
options.sourceMap = !isForAngular && output.js;
|
|
359
|
+
options.incremental = true;
|
|
360
|
+
options.outDir = path.join(pkgDir, "dist");
|
|
361
|
+
|
|
362
|
+
if (output.js && output.dts) {
|
|
363
|
+
options.noEmit = false;
|
|
364
|
+
options.emitDeclarationOnly = false;
|
|
365
|
+
options.declaration = true;
|
|
366
|
+
options.declarationMap = true;
|
|
367
|
+
options.declarationDir = path.join(pkgDir, "dist");
|
|
368
|
+
} else if (output.js) {
|
|
369
|
+
options.noEmit = false;
|
|
370
|
+
options.emitDeclarationOnly = false;
|
|
371
|
+
options.declaration = false;
|
|
372
|
+
options.declarationMap = false;
|
|
373
|
+
} else if (output.dts) {
|
|
374
|
+
options.noEmit = false;
|
|
375
|
+
options.emitDeclarationOnly = true;
|
|
376
|
+
options.declaration = true;
|
|
377
|
+
options.declarationMap = true;
|
|
378
|
+
options.declarationDir = path.join(pkgDir, "dist");
|
|
379
|
+
} else {
|
|
380
|
+
options.noEmit = true;
|
|
381
|
+
options.emitDeclarationOnly = false;
|
|
382
|
+
options.declaration = false;
|
|
383
|
+
options.declarationMap = false;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Angular compilerOptions 병합
|
|
387
|
+
if (angularCompilerOptions != null) {
|
|
388
|
+
options = { ...options, ...(angularCompilerOptions as ts.CompilerOptions) };
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// tsBuildInfoFile
|
|
392
|
+
const envSuffix = env != null ? `-${env}` : "";
|
|
393
|
+
const prefix = isForAngular ? "ngtsc-" : "";
|
|
394
|
+
options.tsBuildInfoFile = path.join(
|
|
395
|
+
pkgDir,
|
|
396
|
+
".cache",
|
|
397
|
+
needsEmit
|
|
398
|
+
? `${prefix}build${output.dts ? "" : "-no-dts"}${envSuffix}.tsbuildinfo`
|
|
399
|
+
: `${prefix}typecheck${envSuffix}.tsbuildinfo`,
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
// compilerOptionsTransformer 적용
|
|
403
|
+
if (compilerOptionsTransformer != null) {
|
|
404
|
+
options = compilerOptionsTransformer(options);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return options;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
private _createHost(
|
|
411
|
+
compilerOptions: ts.CompilerOptions,
|
|
412
|
+
isForAngular: boolean,
|
|
413
|
+
effectiveTransformStylesheet?: ISdTsCompilerOptions["transformStylesheet"],
|
|
414
|
+
): ts.CompilerHost {
|
|
415
|
+
const host = ts.createIncrementalCompilerHost(compilerOptions);
|
|
416
|
+
const { pkgDir, output } = this._options;
|
|
417
|
+
const needsEmit = output.js || output.dts;
|
|
418
|
+
|
|
419
|
+
// Non-Angular emit용 writeFile 훅
|
|
420
|
+
if (!isForAngular && needsEmit) {
|
|
421
|
+
const rewritePath = createOutputPathRewriter(pkgDir);
|
|
422
|
+
const originalWriteFile = host.writeFile;
|
|
423
|
+
host.writeFile = (fileName, content, writeByteOrderMark, onError, sourceFiles, data) => {
|
|
424
|
+
const result = rewritePath(fileName, content);
|
|
425
|
+
if (result != null) {
|
|
426
|
+
let [newPath, newContent] = result;
|
|
427
|
+
if (newPath.endsWith(".js")) {
|
|
428
|
+
newContent = addJsExtensionToImports(newContent);
|
|
429
|
+
}
|
|
430
|
+
originalWriteFile(newPath, newContent, writeByteOrderMark, onError, sourceFiles, data);
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Angular host 확장
|
|
436
|
+
if (isForAngular) {
|
|
437
|
+
this._extendHostForAngular(host, effectiveTransformStylesheet);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// moduleResolutionCache
|
|
441
|
+
const moduleResolutionCache = ts.createModuleResolutionCache(
|
|
442
|
+
host.getCurrentDirectory(),
|
|
443
|
+
host.getCanonicalFileName.bind(host),
|
|
444
|
+
compilerOptions,
|
|
445
|
+
this._packageJsonCache,
|
|
446
|
+
);
|
|
447
|
+
host.getModuleResolutionCache = () => moduleResolutionCache;
|
|
448
|
+
|
|
449
|
+
if (this._packageJsonCache == null) {
|
|
450
|
+
this._packageJsonCache = moduleResolutionCache.getPackageJsonInfoCache();
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return host;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
private _collectDiagnosticsForTsc(
|
|
457
|
+
builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram,
|
|
458
|
+
): ts.Diagnostic[] {
|
|
459
|
+
return [
|
|
460
|
+
...builderProgram.getConfigFileParsingDiagnostics(),
|
|
461
|
+
...builderProgram.getSyntacticDiagnostics(),
|
|
462
|
+
...builderProgram.getOptionsDiagnostics(),
|
|
463
|
+
...builderProgram.getGlobalDiagnostics(),
|
|
464
|
+
...builderProgram.getSemanticDiagnostics(),
|
|
465
|
+
...(!this._options.output.dts ? builderProgram.getProgram().getDeclarationDiagnostics() : []),
|
|
466
|
+
];
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
private _collectDiagnosticsForAngular(
|
|
470
|
+
ngtscProgram: NgtscProgram,
|
|
471
|
+
builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram,
|
|
472
|
+
affectedSourceFiles: Set<ts.SourceFile>,
|
|
473
|
+
): ts.Diagnostic[] {
|
|
474
|
+
const angularCompiler = ngtscProgram.compiler;
|
|
475
|
+
const diagnostics: ts.Diagnostic[] = [];
|
|
476
|
+
const optimization =
|
|
477
|
+
affectedSourceFiles.size === 1 ? OptimizeFor.SingleFile : OptimizeFor.WholeProgram;
|
|
478
|
+
|
|
479
|
+
// 1. Option 진단
|
|
480
|
+
diagnostics.push(...builderProgram.getConfigFileParsingDiagnostics());
|
|
481
|
+
diagnostics.push(...angularCompiler.getOptionDiagnostics());
|
|
482
|
+
diagnostics.push(...builderProgram.getOptionsDiagnostics());
|
|
483
|
+
|
|
484
|
+
// 2. Global
|
|
485
|
+
diagnostics.push(...builderProgram.getGlobalDiagnostics());
|
|
486
|
+
|
|
487
|
+
// 3. 파일별 루프
|
|
488
|
+
for (const sourceFile of builderProgram.getSourceFiles()) {
|
|
489
|
+
if (angularCompiler.ignoreForDiagnostics.has(sourceFile)) {
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
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);
|
|
504
|
+
|
|
505
|
+
// Declaration files는 Angular 진단 없음
|
|
506
|
+
if (sourceFile.isDeclarationFile) {
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Angular 템플릿 진단 (diagnosticCache 활용)
|
|
511
|
+
if (affectedSourceFiles.has(sourceFile)) {
|
|
512
|
+
const angularDiagnostics = angularCompiler.getDiagnosticsForFile(
|
|
513
|
+
sourceFile,
|
|
514
|
+
optimization,
|
|
515
|
+
);
|
|
516
|
+
this._diagnosticCache.set(sourceFile, angularDiagnostics);
|
|
517
|
+
diagnostics.push(...angularDiagnostics);
|
|
518
|
+
} else {
|
|
519
|
+
const cached = this._diagnosticCache.get(sourceFile);
|
|
520
|
+
if (cached) {
|
|
521
|
+
diagnostics.push(...cached);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
return diagnostics;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
private _finalizeDiagnostics(rawDiagnostics: ts.Diagnostic[]): {
|
|
530
|
+
diagnostics: SerializedDiagnostic[];
|
|
531
|
+
errorCount: number;
|
|
532
|
+
warningCount: number;
|
|
533
|
+
errors?: string[];
|
|
534
|
+
} {
|
|
535
|
+
const filtered = rawDiagnostics.filter((d) => isWorkspaceDiagnostic(d, this._options.cwd));
|
|
536
|
+
const serialized = filtered.map(serializeDiagnostic);
|
|
537
|
+
const errorCount = filtered.filter((d) => d.category === ts.DiagnosticCategory.Error).length;
|
|
538
|
+
const warningCount = filtered.filter(
|
|
539
|
+
(d) => d.category === ts.DiagnosticCategory.Warning,
|
|
540
|
+
).length;
|
|
541
|
+
const errors = filtered
|
|
542
|
+
.filter((d) => d.category === ts.DiagnosticCategory.Error)
|
|
543
|
+
.map((d) => formatDiagnosticError(d, this._options.cwd));
|
|
544
|
+
return {
|
|
545
|
+
diagnostics: serialized,
|
|
546
|
+
errorCount,
|
|
547
|
+
warningCount,
|
|
548
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
private _emitTsc(
|
|
553
|
+
builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram,
|
|
554
|
+
): void {
|
|
555
|
+
builderProgram.emit();
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
private _emitAngular(
|
|
559
|
+
ngtscProgram: NgtscProgram,
|
|
560
|
+
builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram,
|
|
561
|
+
affectedSourceFiles: Set<ts.SourceFile>,
|
|
562
|
+
emitOptions?: ISdTsCompilerEmitOptions,
|
|
563
|
+
): EmitResult[] | undefined {
|
|
564
|
+
const compilerOptions = builderProgram.getCompilerOptions();
|
|
565
|
+
|
|
566
|
+
// noEmit이면 emit 건너뜀
|
|
567
|
+
if (compilerOptions.noEmit) {
|
|
568
|
+
return undefined;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const angularCompiler = ngtscProgram.compiler;
|
|
572
|
+
const tsProgram = ngtscProgram.getTsProgram();
|
|
573
|
+
|
|
574
|
+
// prepareEmit() → Angular transformers 획득
|
|
575
|
+
const transformers = angularCompiler.prepareEmit().transformers;
|
|
576
|
+
transformers.before ??= [];
|
|
577
|
+
transformers.after ??= [];
|
|
578
|
+
|
|
579
|
+
// additionalTransformers 병합
|
|
580
|
+
if (emitOptions?.additionalTransformers != null) {
|
|
581
|
+
if (emitOptions.additionalTransformers.before != null) {
|
|
582
|
+
transformers.before.push(...emitOptions.additionalTransformers.before);
|
|
583
|
+
}
|
|
584
|
+
if (emitOptions.additionalTransformers.after != null) {
|
|
585
|
+
transformers.after.push(...emitOptions.additionalTransformers.after);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// emit 결과를 수집
|
|
590
|
+
const emitResults: EmitResult[] = [];
|
|
591
|
+
const emitDeclarationOnly = !!compilerOptions.emitDeclarationOnly;
|
|
592
|
+
|
|
593
|
+
const writeFileCallback: ts.WriteFileCallback = (
|
|
594
|
+
filename,
|
|
595
|
+
contents,
|
|
596
|
+
_writeByteOrderMark,
|
|
597
|
+
_onError,
|
|
598
|
+
sourceFiles,
|
|
599
|
+
) => {
|
|
600
|
+
if (sourceFiles == null || sourceFiles.length === 0) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
|
|
604
|
+
if (angularCompiler.ignoreForEmit.has(sourceFile)) {
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
angularCompiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
|
|
608
|
+
emitResults.push({ filename, contents, sourceFileName: sourceFile.fileName });
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
// per-file emit
|
|
612
|
+
for (const sourceFile of tsProgram.getSourceFiles()) {
|
|
613
|
+
if (angularCompiler.ignoreForEmit.has(sourceFile)) {
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
616
|
+
if (sourceFile.isDeclarationFile) {
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
if (
|
|
620
|
+
angularCompiler.incrementalCompilation.safeToSkipEmit(sourceFile) &&
|
|
621
|
+
!affectedSourceFiles.has(sourceFile)
|
|
622
|
+
) {
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
tsProgram.emit(
|
|
626
|
+
sourceFile,
|
|
627
|
+
writeFileCallback,
|
|
628
|
+
undefined,
|
|
629
|
+
emitDeclarationOnly,
|
|
630
|
+
transformers,
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// .tsbuildinfo 영속화 (try-catch: TS 5.9 + NgtscProgram 크래시 방어)
|
|
635
|
+
try {
|
|
636
|
+
builderProgram.emit(undefined, () => {});
|
|
637
|
+
} catch {
|
|
638
|
+
logger.debug("builderProgram.emit 크래시 (무시) — tsbuildinfo 영속화 생략");
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// sourceFilter 적용
|
|
642
|
+
logger.debug(`emitAffectedFiles 완료 (${emitResults.length}개 파일)`);
|
|
643
|
+
if (emitOptions?.sourceFilter != null) {
|
|
644
|
+
return emitResults.filter((r) => emitOptions.sourceFilter!(r.sourceFileName));
|
|
645
|
+
}
|
|
646
|
+
return emitResults;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
private _findAffectedFilesForTsc(
|
|
650
|
+
builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram,
|
|
651
|
+
): ReadonlySet<string> | undefined {
|
|
652
|
+
const affectedFiles = new Set<string>();
|
|
653
|
+
while (true) {
|
|
654
|
+
const result = builderProgram.getSemanticDiagnosticsOfNextAffectedFile();
|
|
655
|
+
if (result == null) break;
|
|
656
|
+
if ("fileName" in result.affected) {
|
|
657
|
+
affectedFiles.add(pathx.posix(result.affected.fileName));
|
|
658
|
+
} else {
|
|
659
|
+
// ts.Program 반환 — 전역 변경, 전체 리빌드로 처리
|
|
660
|
+
return undefined;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return affectedFiles;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
private _findAffectedFilesForAngular(
|
|
667
|
+
builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram,
|
|
668
|
+
angularCompiler: NgCompiler,
|
|
669
|
+
sourceFileCache?: AngularSourceFileCache,
|
|
670
|
+
): { affectedSourceFiles: Set<ts.SourceFile>; affectedPaths: ReadonlySet<string> | undefined } {
|
|
671
|
+
logger.debug("Angular affected 파일 탐색 시작");
|
|
672
|
+
const affectedSourceFiles = new Set<ts.SourceFile>();
|
|
673
|
+
let isGlobalChange = false;
|
|
674
|
+
|
|
675
|
+
while (true) {
|
|
676
|
+
let result: ReturnType<typeof builderProgram.getSemanticDiagnosticsOfNextAffectedFile>;
|
|
677
|
+
try {
|
|
678
|
+
result = builderProgram.getSemanticDiagnosticsOfNextAffectedFile(
|
|
679
|
+
undefined,
|
|
680
|
+
(sourceFile) => {
|
|
681
|
+
if (
|
|
682
|
+
angularCompiler.ignoreForDiagnostics.has(sourceFile) &&
|
|
683
|
+
sourceFile.fileName.endsWith(".ngtypecheck.ts")
|
|
684
|
+
) {
|
|
685
|
+
const originalFilename = sourceFile.fileName.slice(0, -15) + ".ts";
|
|
686
|
+
const originalSourceFile = builderProgram.getSourceFile(originalFilename);
|
|
687
|
+
if (originalSourceFile) {
|
|
688
|
+
affectedSourceFiles.add(originalSourceFile);
|
|
689
|
+
}
|
|
690
|
+
return true;
|
|
691
|
+
}
|
|
692
|
+
return false;
|
|
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);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
break;
|
|
703
|
+
}
|
|
704
|
+
if (!result) break;
|
|
705
|
+
if ("fileName" in result.affected) {
|
|
706
|
+
affectedSourceFiles.add(result.affected);
|
|
707
|
+
} else {
|
|
708
|
+
isGlobalChange = true;
|
|
709
|
+
for (const sourceFile of builderProgram.getSourceFiles()) {
|
|
710
|
+
if (!angularCompiler.ignoreForDiagnostics.has(sourceFile)) {
|
|
711
|
+
affectedSourceFiles.add(sourceFile);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// 리소스 의존성 기반 diagnosticCache 무효화
|
|
718
|
+
if (sourceFileCache != null && sourceFileCache.modifiedFiles.size > 0) {
|
|
719
|
+
const normalizedModifiedFiles = new Set<string>();
|
|
720
|
+
for (const f of sourceFileCache.modifiedFiles) {
|
|
721
|
+
normalizedModifiedFiles.add(pathx.posix(f));
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
for (const sourceFile of builderProgram.getSourceFiles()) {
|
|
725
|
+
if (angularCompiler.ignoreForEmit.has(sourceFile)) {
|
|
726
|
+
continue;
|
|
727
|
+
}
|
|
728
|
+
const resourceDependencies = angularCompiler.getResourceDependencies(sourceFile);
|
|
729
|
+
for (const resourceDep of resourceDependencies) {
|
|
730
|
+
if (normalizedModifiedFiles.has(pathx.posix(resourceDep))) {
|
|
731
|
+
this._diagnosticCache.delete(sourceFile);
|
|
732
|
+
affectedSourceFiles.add(sourceFile);
|
|
733
|
+
break;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// affectedPaths 변환
|
|
740
|
+
let affectedPaths: ReadonlySet<string> | undefined;
|
|
741
|
+
if (isGlobalChange) {
|
|
742
|
+
affectedPaths = undefined;
|
|
743
|
+
} else {
|
|
744
|
+
const paths = new Set<string>();
|
|
745
|
+
for (const sf of affectedSourceFiles) {
|
|
746
|
+
paths.add(pathx.posix(sf.fileName));
|
|
747
|
+
}
|
|
748
|
+
affectedPaths = paths;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
logger.debug(`Angular affected 파일 탐색 완료 (${affectedSourceFiles.size}개)`);
|
|
752
|
+
return { affectedSourceFiles, affectedPaths };
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
private _extendHostForAngular(
|
|
756
|
+
host: ts.CompilerHost,
|
|
757
|
+
effectiveTransformStylesheet?: ISdTsCompilerOptions["transformStylesheet"],
|
|
758
|
+
): void {
|
|
759
|
+
const hostAny = host as ts.CompilerHost & Record<string, unknown>;
|
|
760
|
+
const { externalStylesheets, sourceFileCache } = this._options;
|
|
761
|
+
const transformStylesheet = effectiveTransformStylesheet;
|
|
762
|
+
|
|
763
|
+
// readResource
|
|
764
|
+
hostAny["readResource"] = (fileName: string) => {
|
|
765
|
+
return host.readFile(fileName) ?? "";
|
|
766
|
+
};
|
|
767
|
+
|
|
768
|
+
// transformResource
|
|
769
|
+
if (transformStylesheet != null) {
|
|
770
|
+
hostAny["transformResource"] = async (
|
|
771
|
+
data: string,
|
|
772
|
+
context: { type: string; containingFile: string; resourceFile: string | null },
|
|
773
|
+
) => {
|
|
774
|
+
if (context.type !== "style") {
|
|
775
|
+
return null;
|
|
776
|
+
}
|
|
777
|
+
if (data.trim().length === 0) {
|
|
778
|
+
return { content: "" };
|
|
779
|
+
}
|
|
780
|
+
const result = await transformStylesheet(
|
|
781
|
+
data,
|
|
782
|
+
context.containingFile,
|
|
783
|
+
context.resourceFile ?? undefined,
|
|
784
|
+
);
|
|
785
|
+
return typeof result === "string" ? { content: result } : null;
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// getModifiedResourceFiles
|
|
790
|
+
const cache = this._sourceFileCache ?? sourceFileCache;
|
|
791
|
+
if (cache != null) {
|
|
792
|
+
hostAny["getModifiedResourceFiles"] = () => cache.modifiedFiles;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// resourceNameToFileName
|
|
796
|
+
hostAny["resourceNameToFileName"] = (
|
|
797
|
+
resourceName: string,
|
|
798
|
+
containingFile: string,
|
|
799
|
+
): string | null => {
|
|
800
|
+
const resolvedPath = path.join(path.dirname(containingFile), resourceName);
|
|
801
|
+
if (!host.fileExists(resolvedPath)) {
|
|
802
|
+
return null;
|
|
803
|
+
}
|
|
804
|
+
if (externalStylesheets == null || hasTemplateExtension(resolvedPath)) {
|
|
805
|
+
return resolvedPath;
|
|
806
|
+
}
|
|
807
|
+
let externalId = externalStylesheets.get(resolvedPath);
|
|
808
|
+
if (externalId == null) {
|
|
809
|
+
externalId = createHash("sha256").update(resolvedPath).digest("hex");
|
|
810
|
+
externalStylesheets.set(resolvedPath, externalId);
|
|
811
|
+
}
|
|
812
|
+
return externalId + ".css";
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
}
|