@simplysm/sd-cli 14.0.42 → 14.0.44
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 +41 -37
- package/dist/angular/ngtsc-build-core.d.ts.map +1 -1
- package/dist/angular/ngtsc-build-core.js +155 -52
- 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.d.ts.map +1 -1
- package/dist/commands/publish/version-upgrade.js +16 -13
- 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-resolve.d.ts.map +1 -1
- package/dist/deps/replace-deps/replace-deps-resolve.js +6 -7
- package/dist/deps/replace-deps/replace-deps-resolve.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 +175 -66
- 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-postcss-plugin.d.ts.map +1 -1
- package/dist/esbuild/esbuild-postcss-plugin.js +9 -6
- package/dist/esbuild/esbuild-postcss-plugin.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 +115 -110
- package/dist/workers/client.worker.js.map +1 -1
- package/dist/workers/incremental-mtime-tracker.d.ts +13 -0
- package/dist/workers/incremental-mtime-tracker.d.ts.map +1 -0
- package/dist/workers/incremental-mtime-tracker.js +65 -0
- package/dist/workers/incremental-mtime-tracker.js.map +1 -0
- 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 +169 -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 +5 -4
- package/src/angular/angular-compiler.ts +0 -502
- package/src/angular/hmr-candidates.ts +295 -0
- package/src/angular/ngtsc-build-core.ts +192 -91
- 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 +44 -35
- 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-resolve.ts +12 -7
- package/src/deps/replace-deps/replace-deps.ts +191 -69
- 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-postcss-plugin.ts +9 -6
- 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 +141 -126
- package/src/workers/incremental-mtime-tracker.ts +68 -0
- package/src/workers/library-build.worker.ts +214 -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/ngtsc-build-core.acc.spec.ts +210 -0
- package/tests/angular/ngtsc-build-core.spec.ts +52 -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/commands/version-upgrade.acc.spec.ts +210 -0
- package/tests/commands/version-upgrade.spec.ts +148 -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-perf.verify.md +15 -0
- package/tests/deps/replace-deps/replace-deps-resolve.acc.spec.ts +124 -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-postcss-plugin-chunking.verify.md +17 -0
- package/tests/esbuild/esbuild-postcss-plugin.acc.spec.ts +152 -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/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 +136 -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-mtime-incremental.verify.md +10 -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/incremental-mtime-tracker.acc.spec.ts +144 -0
- package/tests/workers/incremental-mtime-tracker.spec.ts +102 -0
- package/tests/workers/library-build-lint.spec.ts +40 -45
- package/tests/workers/library-build-worker.spec.ts +298 -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,397 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import type esbuild from "esbuild";
|
|
4
|
+
import ts from "typescript";
|
|
5
|
+
|
|
6
|
+
// 자동 테스트 가능한 순수 함수들을 테스트한다.
|
|
7
|
+
// Angular 프로젝트 의존 항목은 LLM 검증(.verify.md)으로 분리.
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
createAngularCompilerPlugin,
|
|
11
|
+
createCompilerOptionsTransformer,
|
|
12
|
+
convertDiagnostic,
|
|
13
|
+
convertSerializedDiagnosticToEsbuild,
|
|
14
|
+
requiresAngularCompiler,
|
|
15
|
+
createMissingFileDiagnostic,
|
|
16
|
+
} = await import("../../src/esbuild/esbuild-angular-compiler-plugin.js");
|
|
17
|
+
|
|
18
|
+
//#region esbuild Plugin 시뮬레이션 헬퍼
|
|
19
|
+
|
|
20
|
+
function setupPlugin(plugin: esbuild.Plugin) {
|
|
21
|
+
let onStartCb: (() => esbuild.OnStartResult | null | void | Promise<esbuild.OnStartResult | null | void>) | undefined;
|
|
22
|
+
let onEndCb: ((result: esbuild.BuildResult) => void | Promise<void>) | undefined;
|
|
23
|
+
let onDisposeCb: (() => void) | undefined;
|
|
24
|
+
|
|
25
|
+
const initialOptions: esbuild.BuildOptions = {
|
|
26
|
+
define: {},
|
|
27
|
+
absWorkingDir: "/workspace",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const mockBuild = {
|
|
31
|
+
initialOptions,
|
|
32
|
+
onStart(cb: typeof onStartCb) { onStartCb = cb; },
|
|
33
|
+
onEnd(cb: typeof onEndCb) { onEndCb = cb; },
|
|
34
|
+
onLoad() { /* noop — Feature 1.2 onLoad 훅 등록을 수용 */ },
|
|
35
|
+
onDispose(cb: typeof onDisposeCb) { onDisposeCb = cb; },
|
|
36
|
+
} as unknown as esbuild.PluginBuild;
|
|
37
|
+
|
|
38
|
+
void plugin.setup(mockBuild);
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
initialOptions,
|
|
42
|
+
async invokeOnStart() { return (await onStartCb?.()) ?? null; },
|
|
43
|
+
async invokeOnEnd(result: Partial<esbuild.BuildResult>) {
|
|
44
|
+
await onEndCb?.({
|
|
45
|
+
errors: [],
|
|
46
|
+
warnings: [],
|
|
47
|
+
mangleCache: {},
|
|
48
|
+
outputFiles: [],
|
|
49
|
+
metafile: { inputs: {}, outputs: {} },
|
|
50
|
+
...result,
|
|
51
|
+
} as esbuild.BuildResult);
|
|
52
|
+
},
|
|
53
|
+
invokeOnDispose() { onDisposeCb?.(); },
|
|
54
|
+
get onStartCb() { return onStartCb; },
|
|
55
|
+
get onEndCb() { return onEndCb; },
|
|
56
|
+
get onDisposeCb() { return onDisposeCb; },
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
//#endregion
|
|
61
|
+
|
|
62
|
+
describe("createAngularCompilerPlugin — Plugin 구조", () => {
|
|
63
|
+
it("esbuild Plugin 프로토콜을 따르는 객체를 반환한다", () => {
|
|
64
|
+
const plugin = createAngularCompilerPlugin({
|
|
65
|
+
tsconfig: "/workspace/tsconfig.json",
|
|
66
|
+
sourcemap: false,
|
|
67
|
+
advancedOptimizations: false,
|
|
68
|
+
thirdPartySourcemaps: false,
|
|
69
|
+
incremental: false,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(plugin.name).toBe("sd-angular-compiler");
|
|
73
|
+
expect(typeof plugin.setup).toBe("function");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("setup에서 onStart/onEnd/onDispose 훅이 등록된다", () => {
|
|
77
|
+
const plugin = createAngularCompilerPlugin({
|
|
78
|
+
tsconfig: "/workspace/tsconfig.json",
|
|
79
|
+
sourcemap: false,
|
|
80
|
+
advancedOptimizations: false,
|
|
81
|
+
thirdPartySourcemaps: false,
|
|
82
|
+
incremental: false,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const ctx = setupPlugin(plugin);
|
|
86
|
+
expect(ctx.onStartCb).toBeDefined();
|
|
87
|
+
expect(ctx.onEndCb).toBeDefined();
|
|
88
|
+
expect(ctx.onDisposeCb).toBeDefined();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("setup에서 ngI18nClosureMode define이 주입된다", () => {
|
|
92
|
+
const plugin = createAngularCompilerPlugin({
|
|
93
|
+
tsconfig: "/workspace/tsconfig.json",
|
|
94
|
+
sourcemap: false,
|
|
95
|
+
advancedOptimizations: false,
|
|
96
|
+
thirdPartySourcemaps: false,
|
|
97
|
+
incremental: false,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const ctx = setupPlugin(plugin);
|
|
101
|
+
expect(ctx.initialOptions.define!["ngI18nClosureMode"]).toBe("false");
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe("createCompilerOptionsTransformer", () => {
|
|
106
|
+
const baseCompilerOptions: ts.CompilerOptions = {
|
|
107
|
+
target: ts.ScriptTarget.ES2015,
|
|
108
|
+
module: ts.ModuleKind.CommonJS,
|
|
109
|
+
strict: true,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
it("target을 ES2022로, module을 ES2022로 설정한다", () => {
|
|
113
|
+
const transform = createCompilerOptionsTransformer(
|
|
114
|
+
{ tsconfig: "", sourcemap: false, advancedOptimizations: false, thirdPartySourcemaps: false, incremental: false },
|
|
115
|
+
undefined,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const result = transform(baseCompilerOptions);
|
|
119
|
+
expect(result.target).toBe(ts.ScriptTarget.ES2022);
|
|
120
|
+
expect(result.module).toBe(ts.ModuleKind.ES2022);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("noEmitOnError: false, composite: false를 설정한다", () => {
|
|
124
|
+
const transform = createCompilerOptionsTransformer(
|
|
125
|
+
{ tsconfig: "", sourcemap: false, advancedOptimizations: false, thirdPartySourcemaps: false, incremental: false },
|
|
126
|
+
undefined,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const result = transform(baseCompilerOptions);
|
|
130
|
+
expect(result.noEmitOnError).toBe(false);
|
|
131
|
+
expect(result.composite).toBe(false);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("sourcemap: true일 때 inlineSources/inlineSourceMap을 설정한다", () => {
|
|
135
|
+
const transform = createCompilerOptionsTransformer(
|
|
136
|
+
{ tsconfig: "", sourcemap: true, advancedOptimizations: false, thirdPartySourcemaps: false, incremental: false },
|
|
137
|
+
undefined,
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const result = transform(baseCompilerOptions);
|
|
141
|
+
expect(result.inlineSources).toBe(true);
|
|
142
|
+
expect(result.inlineSourceMap).toBe(true);
|
|
143
|
+
expect(result.sourceMap).toBeUndefined();
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("templateUpdates 제공 시 _enableHmr: true를 설정한다", () => {
|
|
147
|
+
const transform = createCompilerOptionsTransformer(
|
|
148
|
+
{ tsconfig: "", sourcemap: false, advancedOptimizations: false, thirdPartySourcemaps: false, incremental: false, templateUpdates: new Map() },
|
|
149
|
+
undefined,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const result = transform(baseCompilerOptions);
|
|
153
|
+
expect((result as Record<string, unknown>)["_enableHmr"]).toBe(true);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("includeTestMetadata: true일 때 supportTestBed/supportJitMode: true를 설정한다", () => {
|
|
157
|
+
const transform = createCompilerOptionsTransformer(
|
|
158
|
+
{ tsconfig: "", sourcemap: false, advancedOptimizations: false, thirdPartySourcemaps: false, incremental: false, includeTestMetadata: true },
|
|
159
|
+
undefined,
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
const result = transform(baseCompilerOptions);
|
|
163
|
+
expect((result as Record<string, unknown>)["supportTestBed"]).toBe(true);
|
|
164
|
+
expect((result as Record<string, unknown>)["supportJitMode"]).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("useDefineForClassFields가 미설정이면 false로 기본 설정한다", () => {
|
|
168
|
+
const transform = createCompilerOptionsTransformer(
|
|
169
|
+
{ tsconfig: "", sourcemap: false, advancedOptimizations: false, thirdPartySourcemaps: false, incremental: false },
|
|
170
|
+
undefined,
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const result = transform(baseCompilerOptions);
|
|
174
|
+
expect(result.useDefineForClassFields).toBe(false);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("persistentCachePath 제공 시 incremental: true, tsBuildInfoFile 설정한다", () => {
|
|
178
|
+
const transform = createCompilerOptionsTransformer(
|
|
179
|
+
{ tsconfig: "", sourcemap: false, advancedOptimizations: false, thirdPartySourcemaps: false, incremental: false, persistentCachePath: "/cache" },
|
|
180
|
+
undefined,
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
const result = transform(baseCompilerOptions);
|
|
184
|
+
expect(result.incremental).toBe(true);
|
|
185
|
+
expect(result.tsBuildInfoFile).toContain(".tsbuildinfo");
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe("stylesheetErrors / stylesheetDependencies 브릿징", () => {
|
|
190
|
+
it("onStart 시작 시 stylesheetErrors를 리셋한다", async () => {
|
|
191
|
+
const stylesheetErrors = ["SCSS error in style.scss: undefined variable", "SCSS error in other.scss: missing import"];
|
|
192
|
+
|
|
193
|
+
const plugin = createAngularCompilerPlugin({
|
|
194
|
+
tsconfig: "/nonexistent/tsconfig.json",
|
|
195
|
+
sourcemap: false,
|
|
196
|
+
advancedOptimizations: false,
|
|
197
|
+
thirdPartySourcemaps: false,
|
|
198
|
+
incremental: false,
|
|
199
|
+
stylesheetErrors,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const ctx = setupPlugin(plugin);
|
|
203
|
+
|
|
204
|
+
// onStart는 tsconfig 파싱 실패로 에러를 반환하지만, 그 전에 stylesheetErrors가 리셋되어야 한다
|
|
205
|
+
await ctx.invokeOnStart();
|
|
206
|
+
|
|
207
|
+
expect(stylesheetErrors).toHaveLength(0);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("stylesheetErrors 미제공 시 onStart가 에러 없이 진행된다", async () => {
|
|
211
|
+
const plugin = createAngularCompilerPlugin({
|
|
212
|
+
tsconfig: "/nonexistent/tsconfig.json",
|
|
213
|
+
sourcemap: false,
|
|
214
|
+
advancedOptimizations: false,
|
|
215
|
+
thirdPartySourcemaps: false,
|
|
216
|
+
incremental: false,
|
|
217
|
+
// stylesheetErrors 미제공
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const ctx = setupPlugin(plugin);
|
|
221
|
+
|
|
222
|
+
// TypeError 없이 정상 진행 (컴파일 에러는 발생하지만 stylesheetErrors 관련 에러는 없음)
|
|
223
|
+
const result = await ctx.invokeOnStart();
|
|
224
|
+
// 컴파일 실패 에러만 포함되어야 함
|
|
225
|
+
expect(result?.errors?.every((e) => !(e.text ?? "").includes("SCSS"))).toBe(true);
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe("convertDiagnostic", () => {
|
|
230
|
+
it("에러 진단을 esbuild PartialMessage로 변환한다", () => {
|
|
231
|
+
const sourceFile = ts.createSourceFile("app.ts", "const x: number = 'str';", ts.ScriptTarget.ES2022, true);
|
|
232
|
+
const diagnostic: ts.Diagnostic = {
|
|
233
|
+
file: sourceFile,
|
|
234
|
+
start: 0,
|
|
235
|
+
length: 5,
|
|
236
|
+
messageText: "Type 'string' is not assignable to type 'number'.",
|
|
237
|
+
category: ts.DiagnosticCategory.Error,
|
|
238
|
+
code: 2322,
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const result = convertDiagnostic(diagnostic, "/workspace");
|
|
242
|
+
|
|
243
|
+
expect(result.text).toContain("Type 'string' is not assignable");
|
|
244
|
+
expect(result.location).not.toBeNull();
|
|
245
|
+
expect(result.location?.line).toBe(1);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("파일 정보 없는 진단은 location: null을 반환한다", () => {
|
|
249
|
+
const diagnostic: ts.Diagnostic = {
|
|
250
|
+
file: undefined,
|
|
251
|
+
start: undefined,
|
|
252
|
+
length: undefined,
|
|
253
|
+
messageText: "Option error",
|
|
254
|
+
category: ts.DiagnosticCategory.Error,
|
|
255
|
+
code: 5000,
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const result = convertDiagnostic(diagnostic, "/workspace");
|
|
259
|
+
|
|
260
|
+
expect(result.text).toBe("Option error");
|
|
261
|
+
expect(result.location).toBeNull();
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
describe("convertSerializedDiagnosticToEsbuild", () => {
|
|
266
|
+
it("파일 위치가 있는 진단을 line/column 포함 PartialMessage로 변환한다", () => {
|
|
267
|
+
const sourceFile = ts.createSourceFile(
|
|
268
|
+
"/workspace/src/app.ts",
|
|
269
|
+
"const x: number = 'str';",
|
|
270
|
+
ts.ScriptTarget.ES2022,
|
|
271
|
+
true,
|
|
272
|
+
);
|
|
273
|
+
// 간이 Program 생성 (getSourceFile 조회용)
|
|
274
|
+
const program = {
|
|
275
|
+
getSourceFile: (fileName: string) =>
|
|
276
|
+
fileName === "/workspace/src/app.ts" ? sourceFile : undefined,
|
|
277
|
+
} as unknown as ts.Program;
|
|
278
|
+
|
|
279
|
+
const serialized = {
|
|
280
|
+
category: ts.DiagnosticCategory.Error,
|
|
281
|
+
code: 2322,
|
|
282
|
+
messageText: "Type 'string' is not assignable to type 'number'.",
|
|
283
|
+
file: { fileName: "/workspace/src/app.ts" },
|
|
284
|
+
start: 0,
|
|
285
|
+
length: 5,
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const result = convertSerializedDiagnosticToEsbuild(serialized, program, "/workspace");
|
|
289
|
+
|
|
290
|
+
expect(result.text).toContain("Type 'string' is not assignable");
|
|
291
|
+
expect(result.location).not.toBeNull();
|
|
292
|
+
expect(result.location?.file).toBe(path.relative("/workspace", "/workspace/src/app.ts"));
|
|
293
|
+
expect(result.location?.line).toBe(1);
|
|
294
|
+
expect(result.location?.column).toBe(0);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it("파일 정보 없는 진단은 location: null을 반환한다", () => {
|
|
298
|
+
const program = {
|
|
299
|
+
getSourceFile: () => undefined,
|
|
300
|
+
} as unknown as ts.Program;
|
|
301
|
+
|
|
302
|
+
const serialized = {
|
|
303
|
+
category: ts.DiagnosticCategory.Error,
|
|
304
|
+
code: 5000,
|
|
305
|
+
messageText: "Option error",
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const result = convertSerializedDiagnosticToEsbuild(serialized, program, "/workspace");
|
|
309
|
+
|
|
310
|
+
expect(result.text).toBe("Option error");
|
|
311
|
+
expect(result.location).toBeNull();
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it("program에서 소스 파일을 찾을 수 없으면 location: null을 반환한다", () => {
|
|
315
|
+
const program = {
|
|
316
|
+
getSourceFile: () => undefined,
|
|
317
|
+
} as unknown as ts.Program;
|
|
318
|
+
|
|
319
|
+
const serialized = {
|
|
320
|
+
category: ts.DiagnosticCategory.Warning,
|
|
321
|
+
code: 1234,
|
|
322
|
+
messageText: "Some warning",
|
|
323
|
+
file: { fileName: "/workspace/src/missing.ts" },
|
|
324
|
+
start: 10,
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const result = convertSerializedDiagnosticToEsbuild(serialized, program, "/workspace");
|
|
328
|
+
|
|
329
|
+
expect(result.text).toBe("Some warning");
|
|
330
|
+
expect(result.location).toBeNull();
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
describe("requiresAngularCompiler", () => {
|
|
335
|
+
it("@Component 포함 시 true를 반환한다", () => {
|
|
336
|
+
expect(requiresAngularCompiler("import { Component } from '@angular/core'; @Component({})")).toBe(true);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it("@Directive 포함 시 true를 반환한다", () => {
|
|
340
|
+
expect(requiresAngularCompiler("@Directive({})")).toBe(true);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it("@Injectable 포함 시 true를 반환한다", () => {
|
|
344
|
+
expect(requiresAngularCompiler("@Injectable()")).toBe(true);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
it("@Pipe 포함 시 true를 반환한다", () => {
|
|
348
|
+
expect(requiresAngularCompiler("@Pipe({ name: 'x' })")).toBe(true);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it("@NgModule 포함 시 true를 반환한다", () => {
|
|
352
|
+
expect(requiresAngularCompiler("@NgModule({})")).toBe(true);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it("@angular/core import만 있어도 true를 반환한다", () => {
|
|
356
|
+
expect(requiresAngularCompiler("import { inject } from '@angular/core';")).toBe(true);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it("Angular 관련 코드가 없으면 false를 반환한다", () => {
|
|
360
|
+
expect(requiresAngularCompiler("export function helper() { return 42; }")).toBe(false);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it("빈 문자열에 대해 false를 반환한다", () => {
|
|
364
|
+
expect(requiresAngularCompiler("")).toBe(false);
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
describe("createMissingFileDiagnostic", () => {
|
|
369
|
+
it("Angular 파일이면 TypeScript compilation 에러 메시지를 생성한다", () => {
|
|
370
|
+
const result = createMissingFileDiagnostic("/workspace/comp.ts", "/workspace/comp.ts", "/workspace", true);
|
|
371
|
+
|
|
372
|
+
expect(result.text).toContain("comp.ts");
|
|
373
|
+
expect(result.text).toContain("not found in TypeScript compilation");
|
|
374
|
+
expect(result.notes?.[0]?.text).toContain("Angular metadata");
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it("Angular 파일이 아니면 번들링 경고 메시지를 생성한다", () => {
|
|
378
|
+
const result = createMissingFileDiagnostic("/workspace/helper.ts", "/workspace/helper.ts", "/workspace", false);
|
|
379
|
+
|
|
380
|
+
expect(result.text).toContain("helper.ts");
|
|
381
|
+
expect(result.notes?.[0]?.text).toContain("bundled and included in the output");
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it("request와 original이 다르면 file replacement 노트를 추가한다", () => {
|
|
385
|
+
const result = createMissingFileDiagnostic("/workspace/replaced.ts", "/workspace/original.ts", "/workspace", false);
|
|
386
|
+
|
|
387
|
+
expect(result.notes?.length).toBe(2);
|
|
388
|
+
expect(result.notes?.[1]?.text).toContain("file replacement");
|
|
389
|
+
expect(result.notes?.[1]?.text).toContain("original.ts");
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it("request와 original이 같으면 file replacement 노트가 없다", () => {
|
|
393
|
+
const result = createMissingFileDiagnostic("/workspace/same.ts", "/workspace/same.ts", "/workspace", true);
|
|
394
|
+
|
|
395
|
+
expect(result.notes?.length).toBe(1);
|
|
396
|
+
});
|
|
397
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# esbuild Angular Compiler Plugin — LLM 검증
|
|
2
|
+
|
|
3
|
+
## 검증 항목
|
|
4
|
+
|
|
5
|
+
- [x] **JavaScriptTransformer 초기화**: `esbuild-angular-compiler-plugin.ts:170-181` — `@angular/build/private`에서 import한 `JavaScriptTransformer`를 `{ sourcemap, thirdPartySourcemaps, advancedOptimizations, jit }` 옵션과 `maxWorkers`, `cacheStore?.createCache("jstransformer")`로 초기화. jit은 `includeTestMetadata`에 매핑됨.
|
|
6
|
+
|
|
7
|
+
- [x] **AngularCompiler 생성 시 transformStylesheet 콜백 전달**: `esbuild-angular-compiler-plugin.ts:222-229` — `AngularCompiler` 생성자에 `pluginOptions.transformStylesheet`를 직접 전달. 미제공 시 undefined로 전달되어 AngularCompiler에서 무시됨.
|
|
8
|
+
|
|
9
|
+
- [x] **AngularCompiler 생성 시 externalStylesheets 전달**: `esbuild-angular-compiler-plugin.ts:228` — `pluginOptions.externalStylesheets`가 AngularCompiler 옵션에 전달됨.
|
|
10
|
+
|
|
11
|
+
- [x] **첫 빌드 시 tsconfig 파싱 → AngularCompiler 생성 → initialize()**: `esbuild-angular-compiler-plugin.ts:214-231` — `angularCompiler == null` 조건에서 `parseTsconfigFile()` → `new AngularCompiler()` → `initialize()` 순서로 호출. compilerOptionsTransformer도 전달됨.
|
|
12
|
+
|
|
13
|
+
- [x] **emitAffectedFiles → typeScriptFileCache 저장**: `esbuild-angular-compiler-plugin.ts:235-238` — emit 결과를 `path.normalize(filename)` 키로 저장. 원본 compiler-plugin.js와 동일한 패턴.
|
|
14
|
+
|
|
15
|
+
- [x] **onDispose에서 리소스 정리**: `esbuild-angular-compiler-plugin.ts:295-299` — `angularCompiler = undefined`, `javascriptTransformer.close()`, `cacheStore?.close()` 호출. void로 fire-and-forget 처리 (원본과 동일).
|
|
16
|
+
|
|
17
|
+
- [x] **LMDB 캐시 초기화 실패 시 graceful degradation**: `esbuild-angular-compiler-plugin.ts:160-168` — try-catch로 감싸고 logger.warn 후 cacheStore = undefined 유지. JavaScriptTransformer에 cache 없이 초기화됨.
|
|
18
|
+
|
|
19
|
+
- [x] **onEnd에서 additionalResults 병합**: `esbuild-angular-compiler-plugin.ts:282-292` — outputFiles push + metafile Object.assign. result.outputFiles가 undefined일 수 있으므로 optional chaining 사용.
|
|
20
|
+
|
|
21
|
+
- [x] **onStart 에러 처리**: `esbuild-angular-compiler-plugin.ts:262-274` — catch에서 "Angular compilation failed." 에러 메시지 + stack trace를 notes에 포함. hasCompilationErrors = true 설정.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# PostCSS 문자열 교체 청크화 — LLM 검증
|
|
2
|
+
|
|
3
|
+
## 검증 항목
|
|
4
|
+
|
|
5
|
+
- [x] 정방향 청크 배열 + join이 역순 slice와 수학적으로 동일한 결과를 생성하는가:
|
|
6
|
+
역순 slice 방식은 `code[0..start_n] + rep_n + code[end_n..start_{n-1}] + rep_{n-1} + ... + code[end_1..]` 순서로 최종 문자열을 구성한다.
|
|
7
|
+
정방향 청크 방식은 `code[0..start_1] + rep_1 + code[end_1..start_2] + rep_2 + ... + code[end_n..]` 순서로 청크를 수집하고 join한다.
|
|
8
|
+
두 방식 모두 원본 텍스트의 비교체 구간과 PostCSS 처리된 교체 텍스트를 동일한 순서로 결합하므로, replacements가 비중첩(acorn AST 노드 보장)인 한 결과가 동일하다.
|
|
9
|
+
검증 결과: **동일성 보장됨**
|
|
10
|
+
|
|
11
|
+
- [x] cursor 초기값 0과 마지막 `code.slice(cursor)` 호출이 파일 전체를 커버하는가:
|
|
12
|
+
cursor는 0에서 시작하여 각 replacement의 end로 갱신된다. 마지막 `chunks.push(code.slice(cursor))`가 마지막 replacement 이후의 원본 텍스트를 수집한다. replacements가 0건이면 `code.slice(0)` = 전체 코드가 되지만, 이 경우 `replacements.length === 0`에서 continue되므로 도달하지 않는다.
|
|
13
|
+
검증 결과: **전체 커버됨**
|
|
14
|
+
|
|
15
|
+
- [x] `replacements.sort()`가 원본 배열을 변경하는 것이 문제되지 않는가:
|
|
16
|
+
`replacements`는 각 파일 처리 시 새로 생성되는 로컬 배열이므로 in-place sort가 안전하다. 기존 코드도 동일하게 in-place sort를 사용했다.
|
|
17
|
+
검증 결과: **문제 없음**
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import type esbuild from "esbuild";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import os from "os";
|
|
6
|
+
import type { AcceptedPlugin } from "postcss";
|
|
7
|
+
import { createPostcssPlugin } from "../../src/esbuild/esbuild-postcss-plugin";
|
|
8
|
+
|
|
9
|
+
/** esbuild 플러그인 lifecycle을 시뮬레이션하는 헬퍼 */
|
|
10
|
+
function setupPlugin(plugin: esbuild.Plugin) {
|
|
11
|
+
let onEndCb:
|
|
12
|
+
| ((
|
|
13
|
+
result: esbuild.BuildResult,
|
|
14
|
+
) => esbuild.OnEndResult | null | void | Promise<esbuild.OnEndResult | null | void>)
|
|
15
|
+
| undefined;
|
|
16
|
+
|
|
17
|
+
const mockBuild = {
|
|
18
|
+
onEnd(cb: typeof onEndCb) {
|
|
19
|
+
onEndCb = cb;
|
|
20
|
+
},
|
|
21
|
+
} as unknown as esbuild.PluginBuild;
|
|
22
|
+
|
|
23
|
+
void plugin.setup(mockBuild);
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
async invokeOnEnd(result: Partial<esbuild.BuildResult>) {
|
|
27
|
+
return (
|
|
28
|
+
(await onEndCb?.({
|
|
29
|
+
errors: [],
|
|
30
|
+
warnings: [],
|
|
31
|
+
mangleCache: {},
|
|
32
|
+
outputFiles: [],
|
|
33
|
+
metafile: { inputs: {}, outputs: {} },
|
|
34
|
+
...result,
|
|
35
|
+
} as esbuild.BuildResult)) ?? null
|
|
36
|
+
);
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** 테스트용 PostCSS 플러그인: 모든 CSS 앞에 주석을 추가 */
|
|
42
|
+
function createTestPostcssPlugin(): AcceptedPlugin {
|
|
43
|
+
return {
|
|
44
|
+
postcssPlugin: "test-prefix",
|
|
45
|
+
Once(root) {
|
|
46
|
+
root.prepend({ text: "processed" });
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** ɵɵdefineComponent styles 배열을 포함하는 JS 코드를 생성 (실제 Angular 컴파일 출력 패턴) */
|
|
52
|
+
function generateJsWithStyles(styles: string[]): string {
|
|
53
|
+
const stylesLiteral = styles.map((s) => JSON.stringify(s)).join(", ");
|
|
54
|
+
return [
|
|
55
|
+
`import * as i0 from "@angular/core";`,
|
|
56
|
+
`class MyComponent {}`,
|
|
57
|
+
`MyComponent.\u0275cmp = /*@__PURE__*/ i0.\u0275\u0275defineComponent({`,
|
|
58
|
+
` type: MyComponent,`,
|
|
59
|
+
` styles: [${stylesLiteral}],`,
|
|
60
|
+
` template: function() {}`,
|
|
61
|
+
`});`,
|
|
62
|
+
`export { MyComponent };`,
|
|
63
|
+
].join("\n");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
describe("createPostcssPlugin — Acceptance Tests", () => {
|
|
67
|
+
let tmpDir: string;
|
|
68
|
+
|
|
69
|
+
beforeEach(() => {
|
|
70
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "postcss-test-"));
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
afterEach(() => {
|
|
74
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("replacements가 0건이면 파일 내용이 변경되지 않음", async () => {
|
|
78
|
+
// Given: ɵɵdefineComponent styles 배열이 없는 JS 파일
|
|
79
|
+
const jsContent = `const x = 1;\nexport default x;\n`;
|
|
80
|
+
const jsFile = path.join(tmpDir, "no-styles.js");
|
|
81
|
+
fs.writeFileSync(jsFile, jsContent, "utf-8");
|
|
82
|
+
|
|
83
|
+
const plugin = createPostcssPlugin({ plugins: [createTestPostcssPlugin()] });
|
|
84
|
+
const lifecycle = setupPlugin(plugin);
|
|
85
|
+
|
|
86
|
+
// When: PostCSS 처리를 시도
|
|
87
|
+
await lifecycle.invokeOnEnd({
|
|
88
|
+
metafile: { inputs: {}, outputs: { [jsFile]: {} as any } },
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Then: 파일 내용이 변경되지 않음
|
|
92
|
+
const result = fs.readFileSync(jsFile, "utf-8");
|
|
93
|
+
expect(result).toBe(jsContent);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("replacements가 1건이면 PostCSS 처리된 CSS로 교체됨", async () => {
|
|
97
|
+
// Given: ɵɵdefineComponent styles 배열에 문자열 리터럴이 1개
|
|
98
|
+
const originalCss = ".host { color: red; }";
|
|
99
|
+
const jsContent = generateJsWithStyles([originalCss]);
|
|
100
|
+
const jsFile = path.join(tmpDir, "one-style.js");
|
|
101
|
+
fs.writeFileSync(jsFile, jsContent, "utf-8");
|
|
102
|
+
|
|
103
|
+
const plugin = createPostcssPlugin({ plugins: [createTestPostcssPlugin()] });
|
|
104
|
+
const lifecycle = setupPlugin(plugin);
|
|
105
|
+
|
|
106
|
+
// When: PostCSS 처리 수행
|
|
107
|
+
await lifecycle.invokeOnEnd({
|
|
108
|
+
metafile: { inputs: {}, outputs: { [jsFile]: {} as any } },
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Then: PostCSS 처리된 CSS가 파일에 반영됨
|
|
112
|
+
const result = fs.readFileSync(jsFile, "utf-8");
|
|
113
|
+
expect(result).toContain("/* processed */");
|
|
114
|
+
expect(result).toContain(".host { color: red; }");
|
|
115
|
+
// 파일 앞뒤의 JS 구조가 유지됨
|
|
116
|
+
expect(result).toContain("import");
|
|
117
|
+
expect(result).toContain("export");
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("replacements가 3건이면 모든 CSS가 PostCSS 처리됨", async () => {
|
|
121
|
+
// Given: ɵɵdefineComponent styles 배열에 문자열 리터럴이 3개
|
|
122
|
+
const styles = [
|
|
123
|
+
".a { color: red; }",
|
|
124
|
+
".b { color: blue; }",
|
|
125
|
+
".c { color: green; }",
|
|
126
|
+
];
|
|
127
|
+
const jsContent = generateJsWithStyles(styles);
|
|
128
|
+
const jsFile = path.join(tmpDir, "three-styles.js");
|
|
129
|
+
fs.writeFileSync(jsFile, jsContent, "utf-8");
|
|
130
|
+
|
|
131
|
+
const plugin = createPostcssPlugin({ plugins: [createTestPostcssPlugin()] });
|
|
132
|
+
const lifecycle = setupPlugin(plugin);
|
|
133
|
+
|
|
134
|
+
// When: PostCSS 처리 수행
|
|
135
|
+
await lifecycle.invokeOnEnd({
|
|
136
|
+
metafile: { inputs: {}, outputs: { [jsFile]: {} as any } },
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Then: 3개 모두 PostCSS 처리됨
|
|
140
|
+
const result = fs.readFileSync(jsFile, "utf-8");
|
|
141
|
+
// 3번의 "/* processed */" 주석이 삽입됨
|
|
142
|
+
const processedCount = (result.match(/\/\* processed \*\//g) ?? []).length;
|
|
143
|
+
expect(processedCount).toBe(3);
|
|
144
|
+
// 원본 CSS 내용이 모두 유지됨
|
|
145
|
+
expect(result).toContain("color: red");
|
|
146
|
+
expect(result).toContain("color: blue");
|
|
147
|
+
expect(result).toContain("color: green");
|
|
148
|
+
// JS 구조가 유지됨
|
|
149
|
+
expect(result).toContain("import");
|
|
150
|
+
expect(result).toContain("export");
|
|
151
|
+
});
|
|
152
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# esbuild-tsc-plugin 전환 — LLM 검증
|
|
2
|
+
|
|
3
|
+
## 검증 항목
|
|
4
|
+
|
|
5
|
+
- [x] `esbuild-tsc-plugin.ts`에서 `runTscPackageBuild`/`parseTsconfig` import 제거됨: Grep 결과 0건
|
|
6
|
+
- [x] `esbuild-tsc-plugin.ts`에서 `SdTsCompiler` import 존재: `import { SdTsCompiler } from "../ts-compiler/SdTsCompiler"` (line 4)
|
|
7
|
+
- [x] `TscPluginOptions`에 `lint?: boolean` 필드 존재: `esbuild-tsc-plugin.ts` 인터페이스 확인
|
|
8
|
+
- [x] `TscPluginResult`에 `getLintResult()` getter 존재: `esbuild-tsc-plugin.ts` 인터페이스 확인
|
|
9
|
+
- [x] `server-build.worker.ts`에서 `runTscPackageBuild` import 제거됨: Grep 결과 0건
|
|
10
|
+
- [x] `server-build.worker.ts`에서 `LintWithProgramRunner` import 제거됨: Grep 결과 0건
|
|
11
|
+
- [x] `server-build.worker.ts`에서 `SdTsCompiler` import 존재: `import { SdTsCompiler } from "../ts-compiler/SdTsCompiler"` 확인
|
|
12
|
+
- [x] `server-esbuild-context.ts`에 `getTscLintResult()` 위임 메서드 존재: 코드 확인
|
|
13
|
+
- [x] `server-esbuild-context.ts`의 `EsbuildContextOptions.tsc`에 `lint?: boolean` 존재: 코드 확인
|