@automaton-labs/aib 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -578
- package/config/agent-dx-policy.default.json +31 -0
- package/config/control-plane-client.default.json +3 -0
- package/dist/agent-dx/agent-dx.js +805 -0
- package/dist/agent-dx/presentation.js +32 -0
- package/dist/alias-advisor/analyze.js +982 -0
- package/dist/alias-advisor/exact-text-cost.js +74 -0
- package/dist/alias-advisor/lexical.js +240 -0
- package/dist/alias-advisor/model.js +2 -0
- package/dist/alias-advisor/path-identity.js +49 -0
- package/dist/alias-advisor/ranking.js +171 -0
- package/dist/alias-advisor/token-estimator.js +85 -0
- package/dist/bin/aib.js +5 -1
- package/dist/bin/cli.js +811 -4
- package/dist/commands/add-missing-imports-preview-cache.js +99 -2
- package/dist/commands/add-missing-imports.js +241 -2
- package/dist/commands/apply-module-plan.js +1319 -3
- package/dist/commands/background-command.js +378 -2
- package/dist/commands/captured-input.js +74 -1
- package/dist/commands/config-command.js +314 -2
- package/dist/commands/config-output.js +357 -10
- package/dist/commands/control-plane-command.js +183 -1
- package/dist/commands/declaration-command.js +1209 -7
- package/dist/commands/declaration-execution-cache.js +79 -1
- package/dist/commands/declaration-format.js +221 -1
- package/dist/commands/declaration-preview-cache.js +114 -2
- package/dist/commands/diagnostics-command.js +70 -3
- package/dist/commands/doctor.js +137 -3
- package/dist/commands/execution-command.js +117 -1
- package/dist/commands/exports-star-collapse-command.js +178 -0
- package/dist/commands/exports-star-command.js +252 -0
- package/dist/commands/exports-star-preview-cache.js +84 -0
- package/dist/commands/feedback-command.js +176 -3
- package/dist/commands/file-move-to-dir-execution-cache.js +92 -1
- package/dist/commands/file-move-to-dir-preview-cache.js +125 -2
- package/dist/commands/file-move-to-dir-worker.js +54 -0
- package/dist/commands/file-move-to-dir.js +1073 -5
- package/dist/commands/file-mutation-runtime.js +102 -1
- package/dist/commands/file-mutation-worker-apply.js +180 -0
- package/dist/commands/file-refactor-batch-execution-cache.js +90 -1
- package/dist/commands/file-refactor-batch-preview-cache.js +125 -2
- package/dist/commands/file-refactor-batch-worker.js +54 -0
- package/dist/commands/file-refactor-batch.js +1154 -5
- package/dist/commands/file-rename-execution-cache.js +92 -1
- package/dist/commands/file-rename-preview-cache.js +125 -2
- package/dist/commands/file-rename-worker.js +54 -0
- package/dist/commands/file-rename.js +1053 -5
- package/dist/commands/file-text-edit-executor.js +205 -0
- package/dist/commands/find-importers.js +52 -1
- package/dist/commands/find-unused-imports.js +55 -1
- package/dist/commands/generate-docs-command.js +244 -6
- package/dist/commands/help-command.js +460 -7
- package/dist/commands/import-specifier-policy.js +391 -0
- package/dist/commands/imports-command.js +68 -1
- package/dist/commands/imports-rebase.js +1138 -0
- package/dist/commands/init-skill-usage.js +92 -3
- package/dist/commands/init-workspace.js +30 -1
- package/dist/commands/inspect-alias-candidates.js +413 -0
- package/dist/commands/inspect-cycles.js +811 -5
- package/dist/commands/inspect-direct-usages.js +98 -0
- package/dist/commands/inspect-duplicates-format.js +229 -0
- package/dist/commands/inspect-format-primitives.js +127 -0
- package/dist/commands/inspect-format.js +1590 -18
- package/dist/commands/inspect-graph.js +1553 -9
- package/dist/commands/inspect-imports.js +339 -2
- package/dist/commands/inspect-mixed-format.js +524 -0
- package/dist/commands/inspect-module-plan-format.js +216 -0
- package/dist/commands/inspect-module-plan-serialization.js +402 -0
- package/dist/commands/inspect-reference-path-format.js +157 -0
- package/dist/commands/inspect-request-values.js +599 -0
- package/dist/commands/inspect-selector-kind.js +21 -0
- package/dist/commands/inspect-selector.js +50 -0
- package/dist/commands/inspect-symbol-format.js +90 -0
- package/dist/commands/inspect-topology.js +435 -0
- package/dist/commands/inspect-tree.js +827 -5
- package/dist/commands/inspect-usages-detail.js +793 -0
- package/dist/commands/inspect-usages-evidence.js +31 -0
- package/dist/commands/inspect-usages-format.js +367 -0
- package/dist/commands/inspect.js +1450 -16
- package/dist/commands/internal-command.js +64 -0
- package/dist/commands/json-file-input.js +60 -1
- package/dist/commands/module-plan-cache.js +156 -2
- package/dist/commands/module-plan-standalone.js +208 -0
- package/dist/commands/module-plan-timeout.js +77 -1
- package/dist/commands/move-preview-cache.js +101 -2
- package/dist/commands/mutate-aggregate-output.js +996 -0
- package/dist/commands/mutate-child-execution.js +374 -0
- package/dist/commands/mutate-command.js +1394 -0
- package/dist/commands/mutate-declaration-output.js +313 -0
- package/dist/commands/mutate-domain-adapters.js +638 -0
- package/dist/commands/mutate-execution-cache.js +114 -0
- package/dist/commands/mutate-execution-status.js +598 -0
- package/dist/commands/mutate-failure-output.js +531 -0
- package/dist/commands/mutate-file-view.js +151 -0
- package/dist/commands/mutate-object-output.js +91 -0
- package/dist/commands/mutate-output-values.js +97 -0
- package/dist/commands/mutate-preview-cache.js +86 -0
- package/dist/commands/mutate-response-replay.js +153 -0
- package/dist/commands/mutate-result-projection.js +818 -0
- package/dist/commands/mutation-eta.js +28 -0
- package/dist/commands/mutation-execution-cache.js +140 -3
- package/dist/commands/mutation-recovery-journal.js +195 -0
- package/dist/commands/normalize-imports.js +1120 -4
- package/dist/commands/object-pack-command.js +546 -0
- package/dist/commands/object-pack-preview-cache.js +88 -0
- package/dist/commands/observability-command.js +47 -3
- package/dist/commands/ota-command.js +403 -2
- package/dist/commands/print-config.js +10 -1
- package/dist/commands/quick-read.js +1113 -11
- package/dist/commands/refactor-batch-builder.js +265 -1
- package/dist/commands/refactor-batch-execution-cache.js +85 -1
- package/dist/commands/refactor-batch-preview-cache.js +96 -2
- package/dist/commands/refactor-batch.js +461 -4
- package/dist/commands/rename-entities.js +794 -4
- package/dist/commands/rename-execution-cache.js +49 -1
- package/dist/commands/rename-input.js +22 -1
- package/dist/commands/rename-polling-policy.js +68 -0
- package/dist/commands/rename-preview-cache.js +96 -2
- package/dist/commands/result-view.js +993 -7
- package/dist/commands/reveal-command.js +445 -5
- package/dist/commands/selector-suggestions.js +93 -0
- package/dist/commands/session-workspace.js +1836 -31
- package/dist/commands/shared.js +2 -1
- package/dist/commands/skills-command.js +315 -0
- package/dist/commands/sync-command.js +59 -2
- package/dist/commands/worker-command.js +173 -1
- package/dist/commands/workspace-cache.js +55 -1
- package/dist/config/defaults.js +26 -1
- package/dist/config/env-vars.js +77 -1
- package/dist/config/glob-match.js +44 -1
- package/dist/config/import-rules.js +165 -1
- package/dist/config/local-config.js +293 -3
- package/dist/config/mutation-comments.js +51 -1
- package/dist/config/path-aliases.js +165 -1
- package/dist/config/path-display.js +84 -1
- package/dist/config/product-storage.js +37 -1
- package/dist/config/request-env.js +21 -0
- package/dist/config/request-routing-context.js +23 -0
- package/dist/config/resolve-command-alias.js +74 -1
- package/dist/config/resolve.js +24 -1
- package/dist/config/tsconfig-discovery.js +113 -1
- package/dist/config/typescript-preferences.js +131 -0
- package/dist/config/workspace-root.js +310 -3
- package/dist/config/workspace-state.js +254 -1
- package/dist/content/content-bundle.js +88 -1
- package/dist/diagnostics/module-plan-timeline.js +75 -2
- package/dist/diagnostics/readiness-text.js +45 -8
- package/dist/dsl/aib-dsl.js +838 -1
- package/dist/dsl/declaration-dsl.js +264 -1
- package/dist/dsl/file-move-to-dir-dsl.js +123 -1
- package/dist/dsl/file-refactor-batch-dsl.js +203 -1
- package/dist/dsl/file-rename-dsl.js +135 -1
- package/dist/dsl/mutate-dsl.js +746 -0
- package/dist/help/bootstrap.bash.md +176 -341
- package/dist/help/bootstrap.md +175 -340
- package/dist/help/bootstrap.pwsh.md +176 -341
- package/dist/help/docs/basics.md +1 -1
- package/dist/help/docs/config-setup.import-normalize.md +65 -65
- package/dist/help/docs/config-setup.import-rules.md +6 -5
- package/dist/help/docs/first-setup.md +6 -5
- package/dist/help/docs/help-protocol.md +4 -3
- package/dist/help/docs/import.base.md +38 -0
- package/dist/help/docs/import.rebase.md +85 -0
- package/dist/help/docs/inspect.aliasCandidates.md +39 -0
- package/dist/help/docs/inspect.code.md +1 -7
- package/dist/help/docs/inspect.file.md +10 -19
- package/dist/help/docs/inspect.graph.md +3 -17
- package/dist/help/{dsl/docs/inspect.md → docs/inspect.shared.md} +13 -12
- package/dist/help/docs/modulePlan.md +24 -28
- package/dist/help/docs/move.md +19 -22
- package/dist/help/{dsl/topics/file.move.md → docs/moveToDir.md} +36 -34
- package/dist/help/docs/mutate.mixed.md +34 -0
- package/dist/help/docs/mutation.shared.md +55 -0
- package/dist/help/docs/patterns.md +3 -12
- package/dist/help/docs/qr.md +12 -6
- package/dist/help/docs/quick-map.md +36 -24
- package/dist/help/docs/recipe.file-layout.md +10 -10
- package/dist/help/docs/recipe.import-boundary.md +92 -0
- package/dist/help/docs/recipe.safe-artifact-probing.md +68 -0
- package/dist/help/docs/recipe.unfamiliar-area.md +64 -0
- package/dist/help/docs/recipes.md +20 -0
- package/dist/help/docs/rename.md +19 -27
- package/dist/help/docs/renameFile.md +36 -0
- package/dist/help/docs/rules.md +26 -0
- package/dist/help/dsl/bootstrap.bash.md +176 -341
- package/dist/help/dsl/bootstrap.md +175 -340
- package/dist/help/dsl/bootstrap.pwsh.md +176 -341
- package/dist/help/dsl/docs/basics.md +1 -1
- package/dist/help/dsl/docs/config-setup.import-normalize.md +65 -65
- package/dist/help/dsl/docs/config-setup.import-rules.md +6 -5
- package/dist/help/dsl/docs/first-setup.md +6 -5
- package/dist/help/dsl/docs/help-protocol.md +4 -3
- package/dist/help/dsl/docs/import.base.md +38 -0
- package/dist/help/dsl/docs/import.rebase.md +85 -0
- package/dist/help/dsl/docs/inspect.aliasCandidates.md +39 -0
- package/dist/help/dsl/docs/inspect.code.md +1 -7
- package/dist/help/dsl/docs/inspect.file.md +10 -19
- package/dist/help/dsl/docs/inspect.graph.md +3 -17
- package/dist/help/{docs/inspect.md → dsl/docs/inspect.shared.md} +13 -12
- package/dist/help/dsl/docs/modulePlan.md +24 -28
- package/dist/help/dsl/docs/move.md +19 -22
- package/dist/help/{topics/file.move.md → dsl/docs/moveToDir.md} +36 -34
- package/dist/help/dsl/docs/mutate.mixed.md +34 -0
- package/dist/help/dsl/docs/mutation.shared.md +55 -0
- package/dist/help/dsl/docs/patterns.md +3 -12
- package/dist/help/dsl/docs/qr.md +12 -6
- package/dist/help/dsl/docs/quick-map.md +36 -24
- package/dist/help/dsl/docs/recipe.file-layout.md +10 -10
- package/dist/help/dsl/docs/recipe.import-boundary.md +92 -0
- package/dist/help/dsl/docs/recipe.safe-artifact-probing.md +68 -0
- package/dist/help/dsl/docs/recipe.unfamiliar-area.md +64 -0
- package/dist/help/dsl/docs/recipes.md +20 -0
- package/dist/help/dsl/docs/rename.md +19 -27
- package/dist/help/dsl/docs/renameFile.md +36 -0
- package/dist/help/dsl/docs/rules.md +26 -0
- package/dist/help/dsl/full.md +175 -340
- package/dist/help/dsl/help-index.md +48 -43
- package/dist/help/dsl/snippets/agents.md +2 -2
- package/dist/help/dsl/tokens/qr.inline.examples.md +1 -1
- package/dist/help/dsl/topics/basics.md +1 -1
- package/dist/help/dsl/topics/config-setup.import-normalize.md +65 -65
- package/dist/help/dsl/topics/config-setup.import-rules.md +6 -5
- package/dist/help/dsl/topics/first-setup.md +6 -5
- package/dist/help/dsl/topics/help-protocol.md +4 -3
- package/dist/help/dsl/topics/import.base.md +36 -0
- package/dist/help/dsl/topics/import.rebase.md +83 -0
- package/dist/help/dsl/topics/inspect.aliasCandidates.md +37 -0
- package/dist/help/dsl/topics/inspect.code.md +1 -7
- package/dist/help/dsl/topics/inspect.file.md +10 -19
- package/dist/help/dsl/topics/inspect.graph.md +3 -17
- package/dist/help/dsl/topics/{inspect.md → inspect.shared.md} +13 -12
- package/dist/help/dsl/topics/modulePlan.md +21 -26
- package/dist/help/dsl/topics/move.md +17 -18
- package/dist/help/{docs/file.move.md → dsl/topics/moveToDir.md} +33 -35
- package/dist/help/dsl/topics/mutate.mixed.md +32 -0
- package/dist/help/dsl/topics/mutation.shared.md +53 -0
- package/dist/help/dsl/topics/patterns.md +3 -12
- package/dist/help/dsl/topics/qr.md +12 -6
- package/dist/help/dsl/topics/quick-map.md +36 -24
- package/dist/help/dsl/topics/recipe.file-layout.md +10 -10
- package/dist/help/dsl/topics/recipe.import-boundary.md +90 -0
- package/dist/help/dsl/topics/recipe.safe-artifact-probing.md +66 -0
- package/dist/help/dsl/topics/recipe.unfamiliar-area.md +62 -0
- package/dist/help/dsl/topics/recipes.md +18 -0
- package/dist/help/dsl/topics/rename.md +15 -15
- package/dist/help/dsl/topics/renameFile.md +34 -0
- package/dist/help/dsl/topics/rules.md +24 -0
- package/dist/help/full.md +175 -340
- package/dist/help/help-index.md +48 -43
- package/dist/help/help-meta.json +98 -48
- package/dist/help/index.md +52 -20
- package/dist/help/snippets/agents.md +2 -2
- package/dist/help/tokens/qr.inline.examples.md +1 -1
- package/dist/help/topics/basics.md +1 -1
- package/dist/help/topics/config-setup.import-normalize.md +65 -65
- package/dist/help/topics/config-setup.import-rules.md +6 -5
- package/dist/help/topics/first-setup.md +6 -5
- package/dist/help/topics/help-protocol.md +4 -3
- package/dist/help/topics/import.base.md +36 -0
- package/dist/help/topics/import.rebase.md +83 -0
- package/dist/help/topics/inspect.aliasCandidates.md +37 -0
- package/dist/help/topics/inspect.code.md +1 -7
- package/dist/help/topics/inspect.file.md +10 -19
- package/dist/help/topics/inspect.graph.md +3 -17
- package/dist/help/topics/{inspect.md → inspect.shared.md} +13 -12
- package/dist/help/topics/modulePlan.md +21 -26
- package/dist/help/topics/move.md +17 -18
- package/dist/help/{dsl/docs/file.move.md → topics/moveToDir.md} +33 -35
- package/dist/help/topics/mutate.mixed.md +32 -0
- package/dist/help/topics/mutation.shared.md +53 -0
- package/dist/help/topics/patterns.md +3 -12
- package/dist/help/topics/qr.md +12 -6
- package/dist/help/topics/quick-map.md +36 -24
- package/dist/help/topics/recipe.file-layout.md +10 -10
- package/dist/help/topics/recipe.import-boundary.md +90 -0
- package/dist/help/topics/recipe.safe-artifact-probing.md +66 -0
- package/dist/help/topics/recipe.unfamiliar-area.md +62 -0
- package/dist/help/topics/recipes.md +18 -0
- package/dist/help/topics/rename.md +15 -15
- package/dist/help/topics/renameFile.md +34 -0
- package/dist/help/topics/rules.md +24 -0
- package/dist/host/capabilities.js +56 -1
- package/dist/imports/standalone-import-analysis.js +602 -0
- package/dist/imports/standalone-import-model.js +2 -0
- package/dist/imports/standalone-import-process.js +66 -0
- package/dist/imports/standalone-import-worker.js +27 -0
- package/dist/imports/standalone-ts-project.js +147 -0
- package/dist/inspect/inspect-duplicates-service.js +526 -0
- package/dist/inspect/inspect-reverse-module-closure.js +338 -0
- package/dist/inspect/inspect-source-ranges.js +82 -0
- package/dist/inspect/inspect-source-shape.js +649 -0
- package/dist/inspect/standalone-inspect-analysis.js +319 -0
- package/dist/inspect/standalone-inspect-model.js +9 -0
- package/dist/inspect/standalone-inspect-process.js +55 -0
- package/dist/inspect/standalone-inspect-usages.js +274 -0
- package/dist/inspect/standalone-inspect-worker.js +13 -0
- package/dist/metrics/central-metrics.js +101 -2
- package/dist/mutation/concrete-edit-plan.js +157 -0
- package/dist/mutation/exports-star-collapse-preview.js +361 -0
- package/dist/mutation/exports-star-expand-apply.js +373 -0
- package/dist/mutation/exports-star-expand-preview.js +807 -0
- package/dist/mutation/file-impact-scan.js +182 -0
- package/dist/mutation/file-mutation-discovery.js +674 -0
- package/dist/mutation/file-mutation-eta.js +99 -0
- package/dist/mutation/file-mutation-standalone-apply.js +584 -0
- package/dist/mutation/file-mutation-standalone-planner.js +500 -0
- package/dist/mutation/file-mutation-tsserver-session.js +473 -0
- package/dist/mutation/mutation-estimate.js +45 -0
- package/dist/mutation/mutation-plan.js +467 -0
- package/dist/mutation/object-mutation-foundation.js +2 -0
- package/dist/mutation/object-mutation-partition.js +148 -0
- package/dist/mutation/object-pack-semantic-apply.js +507 -0
- package/dist/mutation/object-pack-semantic-preview.js +984 -0
- package/dist/mutation/object-unpack-semantic-preview.js +993 -0
- package/dist/mutation/package-manifest-impact.js +176 -0
- package/dist/mutation/rename-owner-worker-child.js +37 -0
- package/dist/mutation/rename-owner-worker.js +122 -0
- package/dist/mutation/runtime-cycle-query.js +66 -0
- package/dist/mutation/semantic-execution-progress.js +63 -0
- package/dist/mutation/semantic-export-index.js +474 -0
- package/dist/mutation/semantic-impact-scan.js +434 -0
- package/dist/mutation/semantic-model.js +2 -0
- package/dist/mutation/semantic-move-best-effort-planner.js +209 -0
- package/dist/mutation/semantic-move-config-worker-child.js +61 -0
- package/dist/mutation/semantic-move-config-worker.js +449 -0
- package/dist/mutation/semantic-move-declarations.js +94 -0
- package/dist/mutation/semantic-move-metrics.js +119 -0
- package/dist/mutation/semantic-move-model.js +2 -0
- package/dist/mutation/semantic-move-owner-authority.js +122 -0
- package/dist/mutation/semantic-move-owner-candidates.js +300 -0
- package/dist/mutation/semantic-move-owner-divergence-harness.js +474 -0
- package/dist/mutation/semantic-move-owner-divergence-runner.js +162 -0
- package/dist/mutation/semantic-move-plan-hash.js +56 -0
- package/dist/mutation/semantic-move-policy.js +360 -0
- package/dist/mutation/semantic-move-process.js +218 -0
- package/dist/mutation/semantic-move-provider-diagnostics.js +27 -0
- package/dist/mutation/semantic-move-standalone-engine.js +919 -0
- package/dist/mutation/semantic-move-standalone-planner.js +1553 -0
- package/dist/mutation/semantic-move-transaction.js +639 -0
- package/dist/mutation/semantic-mutation-engine.js +478 -0
- package/dist/mutation/semantic-mutation-runtime.js +521 -0
- package/dist/mutation/semantic-planner-retry.js +26 -0
- package/dist/mutation/semantic-program-roots.js +69 -0
- package/dist/mutation/semantic-rename-commonjs.js +229 -0
- package/dist/mutation/semantic-rename-config-worker-child.js +46 -0
- package/dist/mutation/semantic-rename-config-worker.js +498 -0
- package/dist/mutation/semantic-rename-locations.js +192 -0
- package/dist/mutation/semantic-rename-model.js +2 -0
- package/dist/mutation/semantic-rename-process.js +217 -0
- package/dist/mutation/semantic-rename-standalone-engine.js +302 -0
- package/dist/mutation/semantic-rename-standalone-planner.js +567 -0
- package/dist/mutation/semantic-rename-transaction.js +333 -0
- package/dist/mutation/semantic-unused-import-cleanup.js +248 -0
- package/dist/mutation/semantic-worker-retry.js +40 -0
- package/dist/mutation/semantic-workspace.js +804 -0
- package/dist/mutation/targeted-import-canonicalizer.js +359 -0
- package/dist/observability/config.js +206 -1
- package/dist/observability/context.js +59 -1
- package/dist/observability/failure-snapshot.js +124 -2
- package/dist/observability/recent.js +63 -2
- package/dist/payloads/read-stdin-json.js +212 -1
- package/dist/rg-wrapper/core.js +714 -6
- package/dist/rg-wrapper/options.js +125 -1
- package/dist/rtk-wrapper/core.js +144 -2
- package/dist/rtk-wrapper/git-safety.js +203 -0
- package/dist/rtk-wrapper/output-adapter.js +106 -0
- package/dist/runtime/buffered-process.js +114 -0
- package/dist/runtime/bundled-node.js +97 -1
- package/dist/runtime/command-lifecycle.js +2 -0
- package/dist/runtime/input-source.js +238 -1
- package/dist/runtime/node-cli-identity.js +37 -0
- package/dist/runtime/run-command.js +191 -1
- package/dist/selectors/parse-entities.js +84 -1
- package/dist/semantic/semantic-context-pool.js +830 -0
- package/dist/semantic/semantic-context-provider.js +416 -0
- package/dist/semantic/semantic-resident-admission.js +38 -0
- package/dist/semantic/semantic-worker-child.js +40 -0
- package/dist/semantic/semantic-worker-manager.js +460 -0
- package/dist/semantic/semantic-worker-protocol.js +2 -0
- package/dist/semantic/semantic-worker-runtime.js +38 -0
- package/dist/semantic/workspace-semantic-context-pools.js +136 -0
- package/dist/session/client.js +359 -1
- package/dist/session/daemon-state.js +185 -2
- package/dist/session/external-tool-coordinator.js +88 -0
- package/dist/session/external-tool-request.js +52 -0
- package/dist/session/lane-owner.js +116 -0
- package/dist/session/paths.js +71 -1
- package/dist/session/runtime-lifecycle.js +225 -0
- package/dist/session/runtime-shutdown.js +95 -0
- package/dist/session/server.js +1194 -7
- package/dist/session/session-health.js +27 -0
- package/dist/shared/agent-text.js +29 -1
- package/dist/shared/errors.js +496 -30
- package/dist/shared/event-loop.js +6 -1
- package/dist/shared/hints.js +37 -1
- package/dist/shared/metrics.js +43 -1
- package/dist/shared/presentation.js +69 -4
- package/dist/shared/stdin-examples.js +77 -1
- package/dist/shared/stdout.js +6 -2
- package/dist/shared/types.js +23 -1
- package/dist/tool-runtime/runtime-tools.js +120 -1
- package/dist/topology/availability.js +663 -0
- package/dist/topology/cache.js +130 -0
- package/dist/topology/candidates.js +372 -0
- package/dist/topology/core.js +903 -0
- package/dist/topology/dependency-snapshot.js +189 -0
- package/dist/topology/model.js +2 -0
- package/dist/topology/scope.js +100 -0
- package/dist/topology/ts-oracle-batch.js +529 -0
- package/dist/topology/ts-oracle-host.js +69 -0
- package/dist/topology/ts-oracle-model.js +2 -0
- package/dist/topology/ts-oracle.js +224 -0
- package/dist/topology/tsconfig-loader.js +105 -0
- package/dist/topology/workspace-project-index.js +542 -0
- package/dist/tracing/config.js +192 -2
- package/dist/tracing/failure-summary.js +100 -0
- package/dist/tracing/trace.js +318 -5
- package/dist/tsc-wrapper/core.js +697 -0
- package/dist/workers/control-plane/aib-control-plane-worker.cjs +32 -32
- package/dist/workers/control-plane/client-config.default.json +3 -3
- package/dist/workers/lexical-worker-child.js +27 -0
- package/dist/workers/lexical-worker-manager.js +394 -0
- package/dist/workers/lexical-worker-protocol.js +2 -0
- package/dist/workers/lexical-worker-runtime.js +25 -0
- package/dist/workers/owned-one-shot-process.js +115 -0
- package/dist/workers/product-storage.js +23 -1
- package/dist/workers/registry.js +241 -1
- package/package.json +8 -13
- package/scripts/postinstall.cjs +29 -29
- package/scripts/provision-runtime.cjs +411 -459
- package/dist/client/http-client.js +0 -1
- package/dist/client/transport-options.js +0 -1
- package/dist/client/websocket-client.js +0 -1
- package/dist/commands/entity-resolution.js +0 -1
- package/dist/commands/file-command.js +0 -1
- package/dist/commands/host-command.js +0 -1
- package/dist/commands/inspect-symbol-query.js +0 -1
- package/dist/commands/list-instances.js +0 -1
- package/dist/commands/module-plan-command.js +0 -1
- package/dist/commands/move-command.js +0 -1
- package/dist/commands/move-to-file.js +0 -2
- package/dist/commands/ping.js +0 -1
- package/dist/commands/refactor-command.js +0 -1
- package/dist/commands/rename-command.js +0 -1
- package/dist/commands/runtime-command.js +0 -4
- package/dist/commands/runtime-info.js +0 -1
- package/dist/commands/validate-module-plan.js +0 -2
- package/dist/compatibility/policy.js +0 -1
- package/dist/config/auto-start-ide.js +0 -1
- package/dist/discovery/registry.js +0 -1
- package/dist/discovery/select-instance.js +0 -1
- package/dist/help/docs/file.rename.md +0 -35
- package/dist/help/docs/mutation.md +0 -60
- package/dist/help/docs/refactor.batch.md +0 -44
- package/dist/help/dsl/docs/file.rename.md +0 -35
- package/dist/help/dsl/docs/mutation.md +0 -60
- package/dist/help/dsl/docs/refactor.batch.md +0 -44
- package/dist/help/dsl/topics/file.rename.md +0 -33
- package/dist/help/dsl/topics/mutation.md +0 -58
- package/dist/help/dsl/topics/refactor.batch.md +0 -33
- package/dist/help/topics/file.rename.md +0 -33
- package/dist/help/topics/mutation.md +0 -58
- package/dist/help/topics/refactor.batch.md +0 -33
- package/dist/ide-launch/common.cjs +0 -162
- package/dist/managed-host/extension-vsix-resolver.js +0 -1
- package/dist/managed-host/manage-serve-web-host.cjs +0 -141
- package/dist/managed-host/serve-web-autostart.js +0 -1
- package/dist/managed-host/serve-web-host.cjs +0 -2115
- package/dist/runtime/managed-runtime-provisioning.js +0 -1
- package/dist/shared/diagnostic-catalog.js +0 -1
- package/dist/shared/diagnostics.js +0 -1
- package/dist/shared/operations.js +0 -1
- package/dist/shared/protocol.js +0 -1
- package/dist/shared/routes.js +0 -1
- package/extension/vscode-refactor-bridge-extension.vsix +0 -0
- package/runtimes/launcher/linux-x64/aib +0 -0
- package/runtimes/launcher/win-x64/aib.exe +0 -0
|
@@ -1,4 +1,1120 @@
|
|
|
1
|
-
"use strict";var G=exports&&exports.__createBinding||(Object.create?(function(e,t,r,n){n===void 0&&(n=r);var i=Object.getOwnPropertyDescriptor(t,r);(!i||("get"in i?!t.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,n,i)}):(function(e,t,r,n){n===void 0&&(n=r),e[n]=t[r]})),H=exports&&exports.__setModuleDefault||(Object.create?(function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}):function(e,t){e.default=t}),R=exports&&exports.__importStar||(function(){var e=function(t){return e=Object.getOwnPropertyNames||function(r){var n=[];for(var i in r)Object.prototype.hasOwnProperty.call(r,i)&&(n[n.length]=i);return n},e(t)};return function(t){if(t&&t.__esModule)return t;var r={};if(t!=null)for(var n=e(t),i=0;i<n.length;i++)n[i]!=="default"&&G(r,t,n[i]);return H(r,t),r}})();Object.defineProperty(exports,"__esModule",{value:!0}),exports.runNormalizeImports=te,exports.readWorkspaceNormalizeImportRules=B;const K=R(require("node:crypto")),u=R(require("node:fs")),c=R(require("node:path")),m=require("../shared/errors"),Y=require("./json-file-input"),q=require("./workspace-cache"),E=[".ts",".tsx",".mts",".cts"],N=[".ts",".tsx",".mts",".cts",".js",".jsx",".mjs",".cjs"],ee=new Set(["node_modules",".git","dist","out","build",".tmp"]);function te(e,t,r){const n=xe(e,t);if(n.action==="apply"){const l=n.applyPlanId;if(!l)throw new m.CliError("NORMALIZE_IMPORTS_PLAN_REQUIRED","imports normalize apply expects a preview id.");return re(e,l,n.showAll)}if(n.action==="show"){const l=n.showPlanId;if(!l)throw new m.CliError("NORMALIZE_IMPORTS_PLAN_REQUIRED","imports normalize show expects a preview id.");return ne(e,l,n.showAll)}const i=x(t,"--from-json"),o=r!==void 0?oe(r):i?(0,Y.readJsonObjectFile)(e,i,"INVALID_NORMALIZE_IMPORTS_JSON_FILE"):null;if(o){const a=ie(e,o,n).map(f=>C(e,f));return a.length===1?a[0]:{ok:a.every(f=>f.ok!==!1),operation:"imports.normalizeBatch",results:a}}const s=n.positionals[0];if(!s)throw new m.CliError("NORMALIZE_IMPORTS_SCOPE_REQUIRED","normalizeImports expects a file or directory scope.");return C(e,L(e,{scope:s,action:n.action,...n.mode!==void 0?{mode:n.mode}:{},...n.preferAlias!==void 0?{preferAlias:n.preferAlias}:{},exclude:n.exclude,ruleSources:n.ruleSources,showAll:n.showAll},n.rules))}function C(e,t){if(!t.scope)throw new m.CliError("NORMALIZE_IMPORTS_SCOPE_REQUIRED","normalizeImports JSON requests expect scope, file, dir, or directory.");const r=U(c.resolve(e,t.scope),e,t.exclude),n=new Map,i=r.flatMap(l=>se(e,l,t.mode,t.preferAlias,n)),o=new Set(i.map(l=>l.file)).size;t.action==="execute"&&D(e,i);const s={ok:!0,operation:"imports.normalize",mode:t.action,target:t.mode,filesScanned:r.length,filesChanged:o,edits:i.length,...t.exclude.length>0?{exclude:t.exclude}:{},...t.ruleSources.length>0?{ruleSources:t.ruleSources.map(l=>I(e,l))}:{},...z(i,t.showAll),next:t.action==="execute"?"Run typecheck or targeted validation for the affected project.":"Rerun with execute or apply the preview id if the preview matches intent."};if(t.action==="preview"){const l=ze(e,t,i);Pe(e,{planId:l,createdAt:new Date().toISOString(),cwd:e,request:t,files:Me(e,i),edits:i}),s.planId=l,s.next=`aib imports normalize apply ${l}`}return s}function re(e,t,r=!1){const n=k(e,t),i=Object.entries(n.files).filter(([o,s])=>{const l=c.resolve(e,o);return!u.existsSync(l)||b(u.readFileSync(l))!==s}).map(([o])=>o);if(i.length>0)throw new m.CliError("NORMALIZE_IMPORTS_PLAN_STALE",`imports normalize plan is stale: ${t}`,{planId:t,staleFiles:i.slice(0,20),...i.length>20?{hidden:`+ ${i.length-20} more stale files`}:{}});return D(e,n.edits),{ok:!0,operation:"imports.normalize",mode:"apply",planId:t,target:n.request.mode,filesChanged:new Set(n.edits.map(o=>o.file)).size,edits:n.edits.length,...z(n.edits,r),next:"Run typecheck or targeted validation for the affected project."}}function ne(e,t,r){const n=k(e,t);return{ok:!0,operation:"imports.normalize",mode:"show",planId:t,target:n.request.mode,filesChanged:new Set(n.edits.map(i=>i.file)).size,edits:n.edits.length,...z(n.edits,r),next:`aib imports normalize apply ${t}`}}function ie(e,t,r){const n=P(t),i=[...r.rules,...n],o=v(t,r);return(Array.isArray(t.requests)?t.requests:[t]).map((l,a)=>{if(!S(l))throw new m.CliError("INVALID_NORMALIZE_IMPORTS_REQUEST",`normalizeImports request at index ${a} must be an object.`);return L(e,v({...o,...l},r),i)})}function v(e,t){const r=p(e.scope)??p(e.file)??p(e.dir)??p(e.directory),n=t.action==="show"?"preview":t.action;return{scope:r??"",...T(e,t)!==void 0?{mode:T(e,t)}:{},action:e.execute===!0?"execute":n,...p(e.preferAlias)?{preferAlias:p(e.preferAlias)}:{},exclude:A([...t.exclude,...g(e.exclude),...g(e.excludes)]),ruleSources:t.ruleSources,showAll:t.showAll||e.all===!0||e.details==="all"}}function L(e,t,r=[]){const n=B(e),s=[...n.rules,...r].filter(f=>Re(e,t.scope,f)).sort((f,d)=>Q(d)-Q(f))[0],l=t.mode??s?.mode??"relative",a=t.preferAlias??s?.preferAlias;return{scope:t.scope,mode:l,action:t.action,...a?{preferAlias:a}:{},exclude:A([...s?.exclude??[],...t.exclude]),ruleSources:A([...n.sources,...t.ruleSources]),showAll:t.showAll}}function T(e,t){const r=p(e.to)??p(e.mode)??t.mode;if(r!==void 0){if(V(r))return r;throw new m.CliError("INVALID_NORMALIZE_IMPORTS_MODE","normalizeImports to/mode expects relative, alias, or shortestAlias.")}}function oe(e){if(!je(e))throw new m.CliError("INVALID_NORMALIZE_IMPORTS_STDIN","normalizeImports --stdin expects a JSON object payload.");return e}function se(e,t,r,n,i){const o=u.readFileSync(t,"utf8"),s=pe(t,e,i),l=[],a=/\b(from\s+["']|import\s*\(\s*["'])([^"']+)(["'])/g;for(const f of o.matchAll(a)){const d=f[2];if(!d)continue;const h=le(t,d,s);if(!h)continue;const y=r==="relative"?ce(t,h):ue(h,s,n,r);!y||y===d||l.push({file:I(e,t),from:d,to:y})}return l}function D(e,t){const r=new Map;for(const n of t){const i=r.get(n.file)??[];i.push(n),r.set(n.file,i)}for(const[n,i]of r.entries()){const o=c.resolve(e,n);let s=u.readFileSync(o,"utf8");for(const l of i)s=s.replace(new RegExp(F(`"${l.from}"`),"g"),`"${l.to}"`),s=s.replace(new RegExp(F(`'${l.from}'`),"g"),`'${l.to}'`);u.writeFileSync(o,s)}}function U(e,t,r){if(!u.existsSync(e))throw new m.CliError("NORMALIZE_IMPORTS_SCOPE_NOT_FOUND",`Scope does not exist: ${e}`);if(M(t,e,r))return[];const n=u.statSync(e);if(n.isFile())return $(e)?[e]:[];if(!n.isDirectory())return[];const i=[];for(const o of u.readdirSync(e,{withFileTypes:!0})){const s=c.join(e,o.name);if(o.isDirectory()){!ee.has(o.name)&&!M(t,s,r)&&i.push(...U(s,t,r));continue}o.isFile()&&$(s)&&!M(t,s,r)&&i.push(s)}return i.sort()}function le(e,t,r){if(t.startsWith("."))return J(c.resolve(c.dirname(e),t));if(!r)return null;for(const n of r.mappings){const i=Se(t,n);if(i!==null)for(const o of n.targets){const s=o.includes("*")?o.replace(/\*/g,i):o,l=J(c.resolve(n.baseUrl,s));if(l)return l}}return null}function ce(e,t){const r=c.dirname(e),n=O(t);let i=c.relative(r,n).replace(/\\/g,"/");return i.startsWith(".")||(i=`./${i}`),`${i}.js`}function ue(e,t,r,n){if(!t||t.mappings.length===0)return null;const i=ae(e,t,r);return(n==="shortestAlias"?i.sort((s,l)=>s.specifier.length-l.specifier.length||s.specifier.localeCompare(l.specifier)):i.sort((s,l)=>l.specificity-s.specificity||s.specifier.length-l.specifier.length||s.specifier.localeCompare(l.specifier)))[0]?.specifier??null}function ae(e,t,r){const n=O(e);return t.mappings.filter(i=>!r||i.pattern===r).flatMap(i=>i.targets.map(o=>{const s=fe(n,i,o);return s?{specifier:s,pattern:i.pattern,specificity:i.specificity}:null}).filter(o=>o!==null))}function fe(e,t,r){const n=r.indexOf("*");if(n<0)return O(c.resolve(t.baseUrl,r))===e&&!t.pattern.includes("*")?t.pattern:null;const i=O(c.resolve(t.baseUrl,r.slice(0,n))),o=O(r.slice(n+1));if(!e.startsWith(i)||o&&!e.endsWith(o))return null;const s=e.slice(i.length,o?-o.length:void 0).replace(/^[/\\]/,"");return t.pattern.replace("*",s.replace(/\\/g,"/"))}function pe(e,t,r){let n=c.dirname(e);const i=c.parse(c.resolve(t)).root;for(;;){const o=c.join(n,"tsconfig.json");if(u.existsSync(o))return W(o,r);const s=c.dirname(n);if(s===n||n===i)return null;n=s}}function W(e,t){const r=c.resolve(e);if(t.has(r))return t.get(r)??null;t.set(r,null);try{const n=w(u.readFileSync(r,"utf8")),i=de(r,n,t),o=S(n.compilerOptions)?n.compilerOptions:{},s=typeof o.baseUrl=="string"?c.resolve(c.dirname(r),o.baseUrl):i?.baseUrl??c.dirname(r),l=S(o.paths)?o.paths:null,a=(l?Object.entries(l).flatMap(([d,h])=>Array.isArray(h)?he(d,h.filter(y=>typeof y=="string"),s):[]):i?.mappings??[]).sort((d,h)=>h.specificity-d.specificity||d.pattern.localeCompare(h.pattern)),f={configPath:r,baseUrl:s,mappings:a};return t.set(r,f),f}catch{return t.set(r,null),null}}function de(e,t,r){const n=p(t.extends);if(!n)return null;const i=me(e,n);return i?W(i,r):null}function me(e,t){const r=[];return t.startsWith(".")||c.isAbsolute(t)?r.push(c.resolve(c.dirname(e),t)):r.push(c.resolve(c.dirname(e),"node_modules",t)),r.flatMap(i=>c.extname(i)?[i]:[`${i}.json`,c.join(i,"tsconfig.json")]).find(i=>u.existsSync(i)&&u.statSync(i).isFile())??null}function he(e,t,r){const n=e.indexOf("*");return[{pattern:e,prefix:n>=0?e.slice(0,n):e,suffix:n>=0?e.slice(n+1):"",targets:t,specificity:e.replace("*","").length,baseUrl:r}]}function Se(e,t){return t.pattern.includes("*")?!e.startsWith(t.prefix)||!e.endsWith(t.suffix)?null:e.slice(t.prefix.length,e.length-t.suffix.length):e===t.pattern?"":null}function J(e){const t=new Set;t.add(e);const r=c.extname(e);if(r&&[".js",".jsx",".mjs",".cjs"].includes(r)){const n=e.slice(0,-r.length);for(const i of E)t.add(`${n}${i}`)}if(!r)for(const n of N)t.add(`${e}${n}`);for(const n of N)t.add(c.join(e,`index${n}`));for(const n of t)if(u.existsSync(n)&&u.statSync(n).isFile()&&$(n))return n;return null}function w(e){const t=ye(e),r=JSON.parse(t.replace(/,\s*([}\]])/g,"$1"));return S(r)?r:{}}function ye(e){let t="",r=!1,n=!1;for(let i=0;i<e.length;i+=1){const o=e[i]??"",s=e[i+1]??"";if(r){t+=o,n?n=!1:o==="\\"?n=!0:o==='"'&&(r=!1);continue}if(o==='"'){r=!0,t+=o;continue}if(o==="/"&&s==="/"){for(;i<e.length&&e[i]!==`
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.runNormalizeImports = runNormalizeImports;
|
|
40
|
+
exports.readWorkspaceNormalizeImportRules = readWorkspaceNormalizeImportRules;
|
|
41
|
+
const crypto = __importStar(require("node:crypto"));
|
|
42
|
+
const fs = __importStar(require("node:fs"));
|
|
43
|
+
const path = __importStar(require("node:path"));
|
|
44
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
45
|
+
const workspace_root_1 = require("../config/workspace-root");
|
|
46
|
+
const errors_1 = require("../shared/errors");
|
|
47
|
+
const import_specifier_policy_1 = require("./import-specifier-policy");
|
|
48
|
+
const json_file_input_1 = require("./json-file-input");
|
|
49
|
+
const session_workspace_1 = require("./session-workspace");
|
|
50
|
+
const workspace_cache_1 = require("./workspace-cache");
|
|
51
|
+
const SOURCE_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts"];
|
|
52
|
+
const IMPORT_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
|
|
53
|
+
const EXCLUDED_DIRS = new Set(["node_modules", ".git", "dist", "out", "build", ".tmp"]);
|
|
54
|
+
const NORMALIZE_VISIBLE_SAMPLE_LIMIT = 5;
|
|
55
|
+
const NORMALIZE_VISIBLE_FILE_LIMIT = 12;
|
|
56
|
+
function runNormalizeImports(cwd, restArgs, stdinPayload) {
|
|
57
|
+
const parsedArgs = parseNormalizeArgs(cwd, restArgs);
|
|
58
|
+
if (parsedArgs.action === "apply") {
|
|
59
|
+
const planId = parsedArgs.applyPlanId;
|
|
60
|
+
if (!planId) {
|
|
61
|
+
throw new errors_1.CliError("NORMALIZE_IMPORTS_PLAN_REQUIRED", "imports normalize apply expects a preview id.");
|
|
62
|
+
}
|
|
63
|
+
return applyNormalizeImportsPlan(cwd, planId, parsedArgs.showAll);
|
|
64
|
+
}
|
|
65
|
+
if (parsedArgs.action === "show") {
|
|
66
|
+
const planId = parsedArgs.showPlanId;
|
|
67
|
+
if (!planId) {
|
|
68
|
+
throw new errors_1.CliError("NORMALIZE_IMPORTS_PLAN_REQUIRED", "imports normalize show expects a preview id.");
|
|
69
|
+
}
|
|
70
|
+
return showNormalizeImportsPlan(cwd, planId, parsedArgs.showAll);
|
|
71
|
+
}
|
|
72
|
+
const fromJson = readFlagValue(restArgs, "--from-json");
|
|
73
|
+
const payload = stdinPayload !== undefined
|
|
74
|
+
? assertNormalizeImportsPayload(stdinPayload)
|
|
75
|
+
: fromJson
|
|
76
|
+
? (0, json_file_input_1.readJsonObjectFile)(cwd, fromJson, "INVALID_NORMALIZE_IMPORTS_JSON_FILE")
|
|
77
|
+
: null;
|
|
78
|
+
if (payload) {
|
|
79
|
+
const requests = expandNormalizeImportsPayload(cwd, payload, parsedArgs);
|
|
80
|
+
const results = requests.map((request) => runNormalizeImportsRequest(cwd, request));
|
|
81
|
+
return results.length === 1
|
|
82
|
+
? results[0]
|
|
83
|
+
: {
|
|
84
|
+
ok: results.every((result) => result.ok !== false),
|
|
85
|
+
operation: "imports.normalizeBatch",
|
|
86
|
+
results
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const scope = parsedArgs.positionals[0];
|
|
90
|
+
if (!scope) {
|
|
91
|
+
throw new errors_1.CliError("NORMALIZE_IMPORTS_SCOPE_REQUIRED", "normalizeImports expects a file or directory scope.");
|
|
92
|
+
}
|
|
93
|
+
return runNormalizeImportsRequest(cwd, finalizeNormalizeImportsRequest(cwd, {
|
|
94
|
+
scope,
|
|
95
|
+
action: parsedArgs.action,
|
|
96
|
+
...(parsedArgs.mode !== undefined ? { mode: parsedArgs.mode } : {}),
|
|
97
|
+
...(parsedArgs.preferAlias !== undefined ? { preferAlias: parsedArgs.preferAlias } : {}),
|
|
98
|
+
overrideConfig: parsedArgs.overrideConfig,
|
|
99
|
+
exclude: parsedArgs.exclude,
|
|
100
|
+
ruleSources: parsedArgs.ruleSources,
|
|
101
|
+
showAll: parsedArgs.showAll
|
|
102
|
+
}, parsedArgs.rules));
|
|
103
|
+
}
|
|
104
|
+
function runNormalizeImportsRequest(cwd, request) {
|
|
105
|
+
if (!request.scope) {
|
|
106
|
+
throw new errors_1.CliError("NORMALIZE_IMPORTS_SCOPE_REQUIRED", "normalizeImports JSON requests expect scope, file, dir, or directory.");
|
|
107
|
+
}
|
|
108
|
+
if (request.overrideConfig && !request.mode) {
|
|
109
|
+
throw new errors_1.CliError("INVALID_NORMALIZE_IMPORTS_OVERRIDE", "+overrideConfig requires an explicit imports.normalize to= target.");
|
|
110
|
+
}
|
|
111
|
+
const files = collectSourceFiles(path.resolve(cwd, request.scope), cwd, request.exclude);
|
|
112
|
+
const configCache = new Map();
|
|
113
|
+
const plan = collectNormalizePlan(cwd, files, request, configCache);
|
|
114
|
+
const edits = plan.edits;
|
|
115
|
+
const filesChanged = uniqueStrings(edits.map((edit) => edit.file));
|
|
116
|
+
const target = request.overrideConfig && request.mode ? request.mode : request.mode ?? "config";
|
|
117
|
+
if (request.action === "execute") {
|
|
118
|
+
applyImportEdits(cwd, edits);
|
|
119
|
+
}
|
|
120
|
+
const response = {
|
|
121
|
+
ok: true,
|
|
122
|
+
operation: "imports.normalize",
|
|
123
|
+
mode: request.action,
|
|
124
|
+
target,
|
|
125
|
+
...(request.overrideConfig ? { overrideConfig: true } : {}),
|
|
126
|
+
...(plan.noPolicy ? { noPolicy: true } : {}),
|
|
127
|
+
filesScanned: files.length,
|
|
128
|
+
filesChanged: filesChanged.length,
|
|
129
|
+
filesTouched: filesChanged,
|
|
130
|
+
...(request.action === "execute" ? { filesWritten: filesChanged } : {}),
|
|
131
|
+
edits: edits.length,
|
|
132
|
+
importEdits: edits,
|
|
133
|
+
policyGroups: policyGroupsToJson(plan.policyGroups),
|
|
134
|
+
configuredFiles: plan.configuredFiles.length,
|
|
135
|
+
...(request.exclude.length > 0 ? { exclude: request.exclude } : {}),
|
|
136
|
+
...(request.ruleSources.length > 0 ? { ruleSources: request.ruleSources.map((source) => toDisplayPath(cwd, source)) } : {}),
|
|
137
|
+
...buildImportEditPresentation(cwd, request.action, target, edits, request.showAll, plan.policyGroups),
|
|
138
|
+
next: request.action === "execute"
|
|
139
|
+
? "Run typecheck or targeted validation for the affected project."
|
|
140
|
+
: "Rerun with execute or apply the preview id if the preview matches intent."
|
|
141
|
+
};
|
|
142
|
+
if (request.action === "preview" && !plan.noPolicy) {
|
|
143
|
+
const planId = buildNormalizeImportsPlanId(cwd, request, edits);
|
|
144
|
+
writeNormalizeImportsPlan(cwd, {
|
|
145
|
+
planId,
|
|
146
|
+
createdAt: new Date().toISOString(),
|
|
147
|
+
cwd,
|
|
148
|
+
request,
|
|
149
|
+
files: hashEditedFiles(cwd, edits),
|
|
150
|
+
edits
|
|
151
|
+
});
|
|
152
|
+
response.planId = planId;
|
|
153
|
+
response.next = "Use the outer aib mutate apply id when this preview is run through mutate.";
|
|
154
|
+
}
|
|
155
|
+
else if (plan.noPolicy) {
|
|
156
|
+
response.next = "Add importNormalize config for this scope or rerun with an explicit to= target.";
|
|
157
|
+
}
|
|
158
|
+
return response;
|
|
159
|
+
}
|
|
160
|
+
function applyNormalizeImportsPlan(cwd, planId, showAll = false) {
|
|
161
|
+
const record = readNormalizeImportsPlan(cwd, planId);
|
|
162
|
+
const staleFiles = Object.entries(record.files)
|
|
163
|
+
.filter(([file, hash]) => {
|
|
164
|
+
const fullPath = path.resolve(cwd, file);
|
|
165
|
+
return !fs.existsSync(fullPath) || sha256(fs.readFileSync(fullPath)) !== hash;
|
|
166
|
+
})
|
|
167
|
+
.map(([file]) => file);
|
|
168
|
+
if (staleFiles.length > 0) {
|
|
169
|
+
throw new errors_1.CliError("NORMALIZE_IMPORTS_PLAN_STALE", `imports normalize plan is stale: ${planId}`, {
|
|
170
|
+
planId,
|
|
171
|
+
staleFiles: staleFiles.slice(0, 20),
|
|
172
|
+
...(staleFiles.length > 20 ? { hidden: `+ ${staleFiles.length - 20} more stale files` } : {})
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
applyImportEdits(cwd, record.edits);
|
|
176
|
+
const filesChanged = uniqueStrings(record.edits.map((edit) => edit.file));
|
|
177
|
+
return {
|
|
178
|
+
ok: true,
|
|
179
|
+
operation: "imports.normalize",
|
|
180
|
+
mode: "apply",
|
|
181
|
+
planId,
|
|
182
|
+
target: record.request.overrideConfig && record.request.mode ? record.request.mode : record.request.mode ?? "config",
|
|
183
|
+
...(record.request.overrideConfig ? { overrideConfig: true } : {}),
|
|
184
|
+
filesChanged: filesChanged.length,
|
|
185
|
+
filesTouched: filesChanged,
|
|
186
|
+
filesWritten: filesChanged,
|
|
187
|
+
edits: record.edits.length,
|
|
188
|
+
importEdits: record.edits,
|
|
189
|
+
policyGroups: policyGroupsToJson(buildPolicyGroupsFromEdits(record.edits, record.request)),
|
|
190
|
+
...buildImportEditPresentation(cwd, "apply", record.request.overrideConfig && record.request.mode ? record.request.mode : record.request.mode ?? "config", record.edits, showAll, buildPolicyGroupsFromEdits(record.edits, record.request)),
|
|
191
|
+
next: "Run typecheck or targeted validation for the affected project."
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function showNormalizeImportsPlan(cwd, planId, showAll) {
|
|
195
|
+
const record = readNormalizeImportsPlan(cwd, planId);
|
|
196
|
+
const filesChanged = uniqueStrings(record.edits.map((edit) => edit.file));
|
|
197
|
+
return {
|
|
198
|
+
ok: true,
|
|
199
|
+
operation: "imports.normalize",
|
|
200
|
+
mode: "show",
|
|
201
|
+
planId,
|
|
202
|
+
target: record.request.overrideConfig && record.request.mode ? record.request.mode : record.request.mode ?? "config",
|
|
203
|
+
filesChanged: filesChanged.length,
|
|
204
|
+
filesTouched: filesChanged,
|
|
205
|
+
edits: record.edits.length,
|
|
206
|
+
importEdits: record.edits,
|
|
207
|
+
policyGroups: policyGroupsToJson(buildPolicyGroupsFromEdits(record.edits, record.request)),
|
|
208
|
+
...buildImportEditPresentation(cwd, "preview", record.request.overrideConfig && record.request.mode ? record.request.mode : record.request.mode ?? "config", record.edits, showAll, buildPolicyGroupsFromEdits(record.edits, record.request)),
|
|
209
|
+
next: "Use aib mutate preview/apply for imports.normalize."
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function expandNormalizeImportsPayload(cwd, payload, parsedArgs) {
|
|
213
|
+
const inlineRules = extractNormalizeImportsRules(payload);
|
|
214
|
+
const rules = [...parsedArgs.rules, ...inlineRules];
|
|
215
|
+
const defaults = normalizeImportsRequestFromObject(payload, parsedArgs);
|
|
216
|
+
const rawRequests = Array.isArray(payload.requests) ? payload.requests : [payload];
|
|
217
|
+
return rawRequests.map((rawRequest, index) => {
|
|
218
|
+
if (!isRecord(rawRequest)) {
|
|
219
|
+
throw new errors_1.CliError("INVALID_NORMALIZE_IMPORTS_REQUEST", `normalizeImports request at index ${index} must be an object.`);
|
|
220
|
+
}
|
|
221
|
+
return finalizeNormalizeImportsRequest(cwd, normalizeImportsRequestFromObject({ ...defaults, ...rawRequest }, parsedArgs), rules);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
function normalizeImportsRequestFromObject(payload, parsedArgs) {
|
|
225
|
+
const scope = readString(payload.scope) ?? readString(payload.file) ?? readString(payload.dir) ?? readString(payload.directory);
|
|
226
|
+
const action = parsedArgs.action === "show" ? "preview" : parsedArgs.action;
|
|
227
|
+
return {
|
|
228
|
+
scope: scope ?? "",
|
|
229
|
+
...(readPayloadMode(payload, parsedArgs) !== undefined ? { mode: readPayloadMode(payload, parsedArgs) } : {}),
|
|
230
|
+
action: payload.execute === true ? "execute" : action,
|
|
231
|
+
...(readString(payload.preferAlias) ? { preferAlias: readString(payload.preferAlias) } : {}),
|
|
232
|
+
overrideConfig: parsedArgs.overrideConfig || payload.overrideConfig === true,
|
|
233
|
+
exclude: uniqueStrings([...parsedArgs.exclude, ...readStringArray(payload.exclude), ...readStringArray(payload.excludes)]),
|
|
234
|
+
ruleSources: parsedArgs.ruleSources,
|
|
235
|
+
showAll: parsedArgs.showAll || payload.all === true || payload.details === "all"
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
function finalizeNormalizeImportsRequest(cwd, request, explicitRules = []) {
|
|
239
|
+
const configRules = readWorkspaceNormalizeImportRules(cwd);
|
|
240
|
+
const rules = [...configRules.rules, ...explicitRules];
|
|
241
|
+
return {
|
|
242
|
+
scope: request.scope,
|
|
243
|
+
...(request.mode ? { mode: request.mode } : {}),
|
|
244
|
+
action: request.action,
|
|
245
|
+
...(request.preferAlias ? { preferAlias: request.preferAlias } : {}),
|
|
246
|
+
overrideConfig: request.overrideConfig,
|
|
247
|
+
exclude: uniqueStrings(request.exclude),
|
|
248
|
+
rules,
|
|
249
|
+
ruleSources: uniqueStrings([...configRules.sources, ...request.ruleSources]),
|
|
250
|
+
showAll: request.showAll
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
function readPayloadMode(payload, parsedArgs) {
|
|
254
|
+
const mode = readString(payload.to) ?? readString(payload.mode) ?? parsedArgs.mode;
|
|
255
|
+
if (mode === undefined) {
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
258
|
+
if (isNormalizeMode(mode)) {
|
|
259
|
+
return mode;
|
|
260
|
+
}
|
|
261
|
+
throw new errors_1.CliError("INVALID_NORMALIZE_IMPORTS_MODE", "normalizeImports to/mode expects relative, alias, or shortestAlias.");
|
|
262
|
+
}
|
|
263
|
+
function assertNormalizeImportsPayload(value) {
|
|
264
|
+
if (!isJsonObject(value)) {
|
|
265
|
+
throw new errors_1.CliError("INVALID_NORMALIZE_IMPORTS_STDIN", "normalizeImports --stdin expects a JSON object payload.");
|
|
266
|
+
}
|
|
267
|
+
return value;
|
|
268
|
+
}
|
|
269
|
+
function collectNormalizePlan(cwd, files, request, configCache) {
|
|
270
|
+
const registry = new PolicyRegistry();
|
|
271
|
+
const edits = files.flatMap((file) => collectImportEdits(cwd, file, request, configCache, registry));
|
|
272
|
+
const configuredFiles = files.filter((file) => fileHasNormalizePolicy(cwd, file, request));
|
|
273
|
+
return {
|
|
274
|
+
edits,
|
|
275
|
+
policyGroups: registry.groups(edits),
|
|
276
|
+
configuredFiles: configuredFiles.map((file) => toDisplayPath(cwd, file)),
|
|
277
|
+
noPolicy: !request.mode && !request.overrideConfig && configuredFiles.length === 0
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function collectImportEdits(cwd, file, request, configCache, registry) {
|
|
281
|
+
const text = fs.readFileSync(file, "utf8");
|
|
282
|
+
const config = (0, import_specifier_policy_1.readNearestTsConfig)(file, cwd, configCache);
|
|
283
|
+
const edits = [];
|
|
284
|
+
for (const occurrence of collectImportSpecifierOccurrences(text, file)) {
|
|
285
|
+
const resolved = (0, import_specifier_policy_1.resolveImportSpecifier)(file, occurrence.specifier, config);
|
|
286
|
+
if (!resolved) {
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
const policy = resolveNormalizePolicy(cwd, file, resolved, request, registry);
|
|
290
|
+
if (!policy) {
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
const nextSpecifier = policy.mode === "relative"
|
|
294
|
+
? (0, import_specifier_policy_1.formatRelativeImportSpecifier)(file, resolved, config)
|
|
295
|
+
: (0, import_specifier_policy_1.toAliasImportSpecifier)(resolved, config, policy.preferAlias, policy.mode);
|
|
296
|
+
if (!nextSpecifier || nextSpecifier === occurrence.specifier) {
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
edits.push({
|
|
300
|
+
file: toDisplayPath(cwd, file),
|
|
301
|
+
from: occurrence.specifier,
|
|
302
|
+
to: nextSpecifier,
|
|
303
|
+
policyId: policy.id,
|
|
304
|
+
start: occurrence.start,
|
|
305
|
+
end: occurrence.end,
|
|
306
|
+
specifiers: occurrence.specifiers,
|
|
307
|
+
importKind: occurrence.importKind,
|
|
308
|
+
statementKind: occurrence.statementKind,
|
|
309
|
+
line: occurrence.line
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
return edits;
|
|
313
|
+
}
|
|
314
|
+
class PolicyRegistry {
|
|
315
|
+
byKey = new Map();
|
|
316
|
+
ordered = [];
|
|
317
|
+
get(match) {
|
|
318
|
+
const key = stableStringify(match);
|
|
319
|
+
const existing = this.byKey.get(key);
|
|
320
|
+
if (existing) {
|
|
321
|
+
return existing;
|
|
322
|
+
}
|
|
323
|
+
const next = { ...match, id: `p${this.ordered.length + 1}` };
|
|
324
|
+
this.byKey.set(key, next);
|
|
325
|
+
this.ordered.push(next);
|
|
326
|
+
return next;
|
|
327
|
+
}
|
|
328
|
+
groups(edits) {
|
|
329
|
+
const editsByPolicy = new Map();
|
|
330
|
+
for (const edit of edits) {
|
|
331
|
+
editsByPolicy.set(edit.policyId, [...(editsByPolicy.get(edit.policyId) ?? []), edit]);
|
|
332
|
+
}
|
|
333
|
+
return this.ordered
|
|
334
|
+
.filter((policy) => editsByPolicy.has(policy.id))
|
|
335
|
+
.map((policy) => policyGroupFromPolicy(policy, editsByPolicy.get(policy.id) ?? []));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function buildPolicyGroupsFromEdits(edits, request) {
|
|
339
|
+
const policies = new Map();
|
|
340
|
+
for (const edit of edits) {
|
|
341
|
+
if (policies.has(edit.policyId)) {
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
const fallback = {
|
|
345
|
+
id: edit.policyId,
|
|
346
|
+
source: request.overrideConfig || request.mode ? "explicit" : "config",
|
|
347
|
+
ruleKind: request.overrideConfig || request.mode ? "explicit" : "simple",
|
|
348
|
+
mode: request.mode ?? "relative",
|
|
349
|
+
...(request.preferAlias ? { preferAlias: request.preferAlias } : {}),
|
|
350
|
+
...(request.overrideConfig ? { overrideConfig: true } : {})
|
|
351
|
+
};
|
|
352
|
+
policies.set(edit.policyId, fallback);
|
|
353
|
+
}
|
|
354
|
+
return Array.from(policies.values()).map((policy) => policyGroupFromPolicy(policy, edits.filter((edit) => edit.policyId === policy.id)));
|
|
355
|
+
}
|
|
356
|
+
function policyGroupFromPolicy(policy, edits) {
|
|
357
|
+
const files = uniqueStrings(edits.map((edit) => edit.file));
|
|
358
|
+
return compactObject({
|
|
359
|
+
id: policy.id,
|
|
360
|
+
source: policy.source,
|
|
361
|
+
ruleKind: policy.ruleKind,
|
|
362
|
+
...(policy.relation ? { relation: policy.relation } : {}),
|
|
363
|
+
...(policy.ruleScope ? { ruleScope: policy.ruleScope } : {}),
|
|
364
|
+
...(policy.boundary ? { boundary: policy.boundary } : {}),
|
|
365
|
+
target: policy.mode,
|
|
366
|
+
...(policy.preferAlias ? { preferAlias: policy.preferAlias } : {}),
|
|
367
|
+
...(policy.overrideConfig ? { overrideConfig: policy.overrideConfig } : {}),
|
|
368
|
+
filesChanged: files.length,
|
|
369
|
+
edits: edits.length,
|
|
370
|
+
sampleFiles: files.slice(0, 3)
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
function policyGroupsToJson(groups) {
|
|
374
|
+
return groups.map((group) => compactObject({
|
|
375
|
+
id: group.id,
|
|
376
|
+
source: group.source,
|
|
377
|
+
ruleKind: group.ruleKind,
|
|
378
|
+
...(group.relation ? { relation: group.relation } : {}),
|
|
379
|
+
...(group.ruleScope ? { ruleScope: group.ruleScope } : {}),
|
|
380
|
+
...(group.boundary ? { boundary: group.boundary } : {}),
|
|
381
|
+
target: group.target,
|
|
382
|
+
...(group.preferAlias ? { preferAlias: group.preferAlias } : {}),
|
|
383
|
+
...(group.overrideConfig ? { overrideConfig: group.overrideConfig } : {}),
|
|
384
|
+
filesChanged: group.filesChanged,
|
|
385
|
+
edits: group.edits,
|
|
386
|
+
sampleFiles: group.sampleFiles
|
|
387
|
+
}));
|
|
388
|
+
}
|
|
389
|
+
function resolveNormalizePolicy(cwd, consumerFile, targetFile, request, registry) {
|
|
390
|
+
if (request.overrideConfig) {
|
|
391
|
+
if (!request.mode) {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
return registry.get({
|
|
395
|
+
source: "explicit",
|
|
396
|
+
ruleKind: "explicit",
|
|
397
|
+
mode: request.mode,
|
|
398
|
+
...(request.preferAlias ? { preferAlias: request.preferAlias } : {}),
|
|
399
|
+
overrideConfig: true
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
const configPolicy = resolveConfigNormalizePolicy(cwd, consumerFile, targetFile, request, registry);
|
|
403
|
+
if (configPolicy) {
|
|
404
|
+
return configPolicy;
|
|
405
|
+
}
|
|
406
|
+
if (!request.mode) {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
return registry.get({
|
|
410
|
+
source: "explicit",
|
|
411
|
+
ruleKind: "explicit",
|
|
412
|
+
mode: request.mode,
|
|
413
|
+
...(request.preferAlias ? { preferAlias: request.preferAlias } : {})
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
function resolveConfigNormalizePolicy(cwd, consumerFile, targetFile, request, registry) {
|
|
417
|
+
const sortedRules = [...request.rules].sort((left, right) => ruleSpecificity(right) - ruleSpecificity(left));
|
|
418
|
+
for (const rule of sortedRules) {
|
|
419
|
+
if (!rule.boundary) {
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
if (isExcludedPath(cwd, consumerFile, rule.exclude)) {
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
const relation = boundaryRelation(cwd, consumerFile, targetFile, rule);
|
|
426
|
+
if (!relation) {
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
const target = relation === "inside" ? rule.inside : rule.outside;
|
|
430
|
+
if (!target) {
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
return registry.get({
|
|
434
|
+
source: "config",
|
|
435
|
+
ruleKind: "boundary",
|
|
436
|
+
relation,
|
|
437
|
+
...(rule.scope ? { ruleScope: rule.scope } : {}),
|
|
438
|
+
boundary: rule.boundary,
|
|
439
|
+
mode: target.mode,
|
|
440
|
+
...(target.preferAlias ? { preferAlias: target.preferAlias } : {})
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
for (const rule of sortedRules) {
|
|
444
|
+
if (rule.boundary || !rule.mode || !normalizeRuleAppliesToFile(cwd, consumerFile, rule)) {
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
if (isExcludedPath(cwd, consumerFile, rule.exclude)) {
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
return registry.get({
|
|
451
|
+
source: "config",
|
|
452
|
+
ruleKind: "simple",
|
|
453
|
+
...(rule.scope ? { ruleScope: rule.scope } : {}),
|
|
454
|
+
mode: rule.mode,
|
|
455
|
+
...(rule.preferAlias ? { preferAlias: rule.preferAlias } : {})
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
function fileHasNormalizePolicy(cwd, consumerFile, request) {
|
|
461
|
+
if (request.overrideConfig) {
|
|
462
|
+
return Boolean(request.mode);
|
|
463
|
+
}
|
|
464
|
+
if (request.mode) {
|
|
465
|
+
return true;
|
|
466
|
+
}
|
|
467
|
+
return request.rules.some((rule) => {
|
|
468
|
+
if (isExcludedPath(cwd, consumerFile, rule.exclude)) {
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
if (rule.boundary) {
|
|
472
|
+
return boundaryInstance(cwd, consumerFile, rule) !== null;
|
|
473
|
+
}
|
|
474
|
+
return Boolean(rule.mode) && normalizeRuleAppliesToFile(cwd, consumerFile, rule);
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
function boundaryRelation(cwd, consumerFile, targetFile, rule) {
|
|
478
|
+
const consumerInstance = boundaryInstance(cwd, consumerFile, rule);
|
|
479
|
+
const targetInstance = boundaryInstance(cwd, targetFile, rule);
|
|
480
|
+
if (consumerInstance && targetInstance) {
|
|
481
|
+
return consumerInstance === targetInstance ? "inside" : "outside";
|
|
482
|
+
}
|
|
483
|
+
if (consumerInstance || targetInstance) {
|
|
484
|
+
return "outside";
|
|
485
|
+
}
|
|
486
|
+
return null;
|
|
487
|
+
}
|
|
488
|
+
function boundaryInstance(cwd, file, rule) {
|
|
489
|
+
if (rule.boundary !== "*" || !rule.scope) {
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
const container = toDisplayPath(cwd, path.resolve(cwd, rule.scope));
|
|
493
|
+
const relative = toDisplayPath(cwd, path.resolve(file));
|
|
494
|
+
if (relative === container || !relative.startsWith(`${container}/`)) {
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
const rest = relative.slice(container.length + 1);
|
|
498
|
+
const [firstSegment] = rest.split("/");
|
|
499
|
+
return firstSegment && firstSegment.length > 0 ? firstSegment : null;
|
|
500
|
+
}
|
|
501
|
+
function collectImportSpecifierOccurrences(text, file) {
|
|
502
|
+
const sourceFile = typescript_1.default.createSourceFile(file, text, typescript_1.default.ScriptTarget.Latest, true, scriptKindForFile(file));
|
|
503
|
+
const occurrences = [];
|
|
504
|
+
const pushModuleSpecifier = (moduleSpecifier, specifiers, importKind, statementKind) => {
|
|
505
|
+
if (!moduleSpecifier || !typescript_1.default.isStringLiteralLike(moduleSpecifier)) {
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
const literalStart = moduleSpecifier.getStart(sourceFile);
|
|
509
|
+
const literalEnd = moduleSpecifier.getEnd();
|
|
510
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(literalStart);
|
|
511
|
+
occurrences.push({
|
|
512
|
+
specifier: moduleSpecifier.text,
|
|
513
|
+
start: literalStart + 1,
|
|
514
|
+
end: literalEnd - 1,
|
|
515
|
+
specifiers,
|
|
516
|
+
importKind,
|
|
517
|
+
statementKind,
|
|
518
|
+
line: line + 1
|
|
519
|
+
});
|
|
520
|
+
};
|
|
521
|
+
const visit = (node) => {
|
|
522
|
+
if (typescript_1.default.isImportDeclaration(node)) {
|
|
523
|
+
pushModuleSpecifier(node.moduleSpecifier, readImportClauseSpecifiers(node.importClause), readImportClauseKind(node.importClause), "import");
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
if (typescript_1.default.isExportDeclaration(node)) {
|
|
527
|
+
pushModuleSpecifier(node.moduleSpecifier, readExportClauseSpecifiers(node.exportClause), readExportDeclarationKind(node), "export");
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
if (typescript_1.default.isCallExpression(node) && node.expression.kind === typescript_1.default.SyntaxKind.ImportKeyword) {
|
|
531
|
+
const [firstArg] = node.arguments;
|
|
532
|
+
pushModuleSpecifier(firstArg, [], "unknown", "dynamicImport");
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
typescript_1.default.forEachChild(node, visit);
|
|
536
|
+
};
|
|
537
|
+
visit(sourceFile);
|
|
538
|
+
return occurrences;
|
|
539
|
+
}
|
|
540
|
+
function scriptKindForFile(file) {
|
|
541
|
+
const ext = path.extname(file).toLowerCase();
|
|
542
|
+
if (ext === ".tsx") {
|
|
543
|
+
return typescript_1.default.ScriptKind.TSX;
|
|
544
|
+
}
|
|
545
|
+
if (ext === ".js" || ext === ".mjs" || ext === ".cjs" || ext === ".jsx") {
|
|
546
|
+
return typescript_1.default.ScriptKind.JS;
|
|
547
|
+
}
|
|
548
|
+
return typescript_1.default.ScriptKind.TS;
|
|
549
|
+
}
|
|
550
|
+
function readImportClauseSpecifiers(clause) {
|
|
551
|
+
if (!clause) {
|
|
552
|
+
return [];
|
|
553
|
+
}
|
|
554
|
+
const names = [];
|
|
555
|
+
if (clause.name) {
|
|
556
|
+
names.push(clause.name.text);
|
|
557
|
+
}
|
|
558
|
+
const bindings = clause.namedBindings;
|
|
559
|
+
if (bindings && typescript_1.default.isNamespaceImport(bindings)) {
|
|
560
|
+
names.push(`* as ${bindings.name.text}`);
|
|
561
|
+
}
|
|
562
|
+
else if (bindings && typescript_1.default.isNamedImports(bindings)) {
|
|
563
|
+
for (const specifier of bindings.elements) {
|
|
564
|
+
names.push(specifier.propertyName ? `${specifier.propertyName.text} as ${specifier.name.text}` : specifier.name.text);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return names;
|
|
568
|
+
}
|
|
569
|
+
function readImportClauseKind(clause) {
|
|
570
|
+
if (!clause) {
|
|
571
|
+
return "unknown";
|
|
572
|
+
}
|
|
573
|
+
if (clause.isTypeOnly) {
|
|
574
|
+
return "type";
|
|
575
|
+
}
|
|
576
|
+
const bindings = clause.namedBindings;
|
|
577
|
+
if (!bindings || !typescript_1.default.isNamedImports(bindings)) {
|
|
578
|
+
return "value";
|
|
579
|
+
}
|
|
580
|
+
const hasTypeSpecifiers = bindings.elements.some((specifier) => specifier.isTypeOnly);
|
|
581
|
+
const hasValueSpecifiers = bindings.elements.some((specifier) => !specifier.isTypeOnly);
|
|
582
|
+
return hasTypeSpecifiers && hasValueSpecifiers ? "mixed" : hasTypeSpecifiers ? "type" : "value";
|
|
583
|
+
}
|
|
584
|
+
function readExportClauseSpecifiers(clause) {
|
|
585
|
+
if (!clause) {
|
|
586
|
+
return [];
|
|
587
|
+
}
|
|
588
|
+
if (typescript_1.default.isNamespaceExport(clause)) {
|
|
589
|
+
return [`* as ${clause.name.text}`];
|
|
590
|
+
}
|
|
591
|
+
return clause.elements.map((specifier) => specifier.propertyName ? `${specifier.propertyName.text} as ${specifier.name.text}` : specifier.name.text);
|
|
592
|
+
}
|
|
593
|
+
function readExportDeclarationKind(node) {
|
|
594
|
+
if (node.isTypeOnly) {
|
|
595
|
+
return "type";
|
|
596
|
+
}
|
|
597
|
+
const clause = node.exportClause;
|
|
598
|
+
if (!clause || !typescript_1.default.isNamedExports(clause)) {
|
|
599
|
+
return "value";
|
|
600
|
+
}
|
|
601
|
+
const hasTypeSpecifiers = clause.elements.some((specifier) => specifier.isTypeOnly);
|
|
602
|
+
const hasValueSpecifiers = clause.elements.some((specifier) => !specifier.isTypeOnly);
|
|
603
|
+
return hasTypeSpecifiers && hasValueSpecifiers ? "mixed" : hasTypeSpecifiers ? "type" : "value";
|
|
604
|
+
}
|
|
605
|
+
function applyImportEdits(cwd, edits) {
|
|
606
|
+
const byFile = new Map();
|
|
607
|
+
for (const edit of edits) {
|
|
608
|
+
const list = byFile.get(edit.file) ?? [];
|
|
609
|
+
list.push(edit);
|
|
610
|
+
byFile.set(edit.file, list);
|
|
611
|
+
}
|
|
612
|
+
for (const [relativeFile, fileEdits] of byFile.entries()) {
|
|
613
|
+
const file = path.resolve(cwd, relativeFile);
|
|
614
|
+
let text = fs.readFileSync(file, "utf8");
|
|
615
|
+
for (const edit of [...fileEdits].sort((left, right) => right.start - left.start)) {
|
|
616
|
+
if (text.slice(edit.start, edit.end) !== edit.from) {
|
|
617
|
+
throw new errors_1.CliError("NORMALIZE_IMPORTS_PLAN_STALE", `imports normalize plan is stale for ${relativeFile}`, {
|
|
618
|
+
file: relativeFile,
|
|
619
|
+
expected: edit.from,
|
|
620
|
+
actual: text.slice(edit.start, edit.end)
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
text = `${text.slice(0, edit.start)}${edit.to}${text.slice(edit.end)}`;
|
|
624
|
+
}
|
|
625
|
+
fs.writeFileSync(file, text);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
function collectSourceFiles(scope, cwd, exclude) {
|
|
629
|
+
if (!fs.existsSync(scope)) {
|
|
630
|
+
throw new errors_1.CliError("NORMALIZE_IMPORTS_SCOPE_NOT_FOUND", `Scope does not exist: ${scope}`);
|
|
631
|
+
}
|
|
632
|
+
if (isExcludedPath(cwd, scope, exclude)) {
|
|
633
|
+
return [];
|
|
634
|
+
}
|
|
635
|
+
const stat = fs.statSync(scope);
|
|
636
|
+
if (stat.isFile()) {
|
|
637
|
+
return isSourceFile(scope) ? [scope] : [];
|
|
638
|
+
}
|
|
639
|
+
if (!stat.isDirectory()) {
|
|
640
|
+
return [];
|
|
641
|
+
}
|
|
642
|
+
const files = [];
|
|
643
|
+
for (const entry of fs.readdirSync(scope, { withFileTypes: true })) {
|
|
644
|
+
const child = path.join(scope, entry.name);
|
|
645
|
+
if (entry.isDirectory()) {
|
|
646
|
+
if (!EXCLUDED_DIRS.has(entry.name) && !isExcludedPath(cwd, child, exclude)) {
|
|
647
|
+
files.push(...collectSourceFiles(child, cwd, exclude));
|
|
648
|
+
}
|
|
649
|
+
continue;
|
|
650
|
+
}
|
|
651
|
+
if (entry.isFile() && isSourceFile(child) && !isExcludedPath(cwd, child, exclude)) {
|
|
652
|
+
files.push(child);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
return files.sort();
|
|
656
|
+
}
|
|
657
|
+
function readFlagValue(args, flag) {
|
|
658
|
+
const index = args.indexOf(flag);
|
|
659
|
+
return index >= 0 ? args[index + 1] : undefined;
|
|
660
|
+
}
|
|
661
|
+
function parseNormalizeArgs(cwd, args) {
|
|
662
|
+
const positionals = args.filter((item, index) => !item.startsWith("--") && !isValueForFlag(args, index));
|
|
663
|
+
const first = positionals[0];
|
|
664
|
+
const action = first === "preview" || first === "apply" || first === "execute" || first === "show"
|
|
665
|
+
? first
|
|
666
|
+
: args.includes("--execute") ? "execute" : "preview";
|
|
667
|
+
const actualPositionals = first === action ? positionals.slice(1) : positionals;
|
|
668
|
+
const rawMode = readFlagValue(args, "--to");
|
|
669
|
+
const mode = rawMode === undefined ? undefined : readNormalizeMode(rawMode);
|
|
670
|
+
const ruleFile = readFlagValue(args, "--rules") ?? readFlagValue(args, "--rules-file");
|
|
671
|
+
const ruleSources = [];
|
|
672
|
+
const rules = ruleFile ? readNormalizeImportsRuleFile(path.resolve(cwd, ruleFile), ruleSources) : [];
|
|
673
|
+
return {
|
|
674
|
+
action,
|
|
675
|
+
...(action === "apply" && actualPositionals[0] ? { applyPlanId: actualPositionals[0] } : {}),
|
|
676
|
+
...(action === "show" && actualPositionals[0] ? { showPlanId: actualPositionals[0] } : {}),
|
|
677
|
+
positionals: action === "apply" || action === "show" ? actualPositionals.slice(1) : actualPositionals,
|
|
678
|
+
...(mode !== undefined ? { mode } : {}),
|
|
679
|
+
...(readFlagValue(args, "--prefer-alias") !== undefined ? { preferAlias: readFlagValue(args, "--prefer-alias") } : {}),
|
|
680
|
+
overrideConfig: args.includes("--override-config") || args.includes("--overrideConfig"),
|
|
681
|
+
exclude: readRepeatedFlagValues(args, "--exclude"),
|
|
682
|
+
rules,
|
|
683
|
+
ruleSources,
|
|
684
|
+
showAll: args.includes("--all") || args.includes("--details") || args.includes("--full")
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
function readNormalizeMode(value) {
|
|
688
|
+
if (isNormalizeMode(value)) {
|
|
689
|
+
return value;
|
|
690
|
+
}
|
|
691
|
+
throw new errors_1.CliError("INVALID_NORMALIZE_IMPORTS_MODE", "normalizeImports --to expects relative, alias, or shortestAlias.");
|
|
692
|
+
}
|
|
693
|
+
function isNormalizeMode(value) {
|
|
694
|
+
return value === "relative" || value === "alias" || value === "shortestAlias";
|
|
695
|
+
}
|
|
696
|
+
function readRepeatedFlagValues(args, flag) {
|
|
697
|
+
const values = [];
|
|
698
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
699
|
+
if (args[index] === flag && typeof args[index + 1] === "string") {
|
|
700
|
+
values.push(args[index + 1]);
|
|
701
|
+
index += 1;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
return values;
|
|
705
|
+
}
|
|
706
|
+
function isValueForFlag(args, index) {
|
|
707
|
+
const previous = args[index - 1];
|
|
708
|
+
return index > 0 && previous !== undefined && VALUE_FLAGS.has(previous);
|
|
709
|
+
}
|
|
710
|
+
const VALUE_FLAGS = new Set(["--to", "--prefer-alias", "--exclude", "--from-json", "--from-dsl", "--from", "--rules", "--rules-file"]);
|
|
711
|
+
function buildImportEditPresentation(cwd, action, target, edits, showAll, policyGroups) {
|
|
712
|
+
const visibleSamples = showAll ? edits : selectImportEditSamples(edits, NORMALIZE_VISIBLE_SAMPLE_LIMIT);
|
|
713
|
+
const visibleSampleKeys = new Set(visibleSamples.map(importEditKey));
|
|
714
|
+
const hiddenEdits = orderImportEditsForPresentation(edits.filter((edit) => !visibleSampleKeys.has(importEditKey(edit))));
|
|
715
|
+
const files = uniqueStrings(edits.map((edit) => edit.file));
|
|
716
|
+
const visibleFiles = showAll ? files : selectImportEditFiles(edits, NORMALIZE_VISIBLE_FILE_LIMIT);
|
|
717
|
+
const visibleFileSet = new Set(visibleFiles);
|
|
718
|
+
const hiddenFiles = orderImportFilesForPresentation(edits, files.filter((file) => !visibleFileSet.has(file)));
|
|
719
|
+
const hiddenEditCount = Math.max(0, edits.length - visibleSamples.length);
|
|
720
|
+
const hiddenFileCount = hiddenFiles.length;
|
|
721
|
+
const view = saveNormalizeImportsView(cwd, action, target, edits, hiddenEdits, hiddenFiles, policyGroups);
|
|
722
|
+
return compactObject({
|
|
723
|
+
samples: visibleSamples,
|
|
724
|
+
sampleCount: visibleSamples.length,
|
|
725
|
+
visibleFiles,
|
|
726
|
+
hiddenEditCount,
|
|
727
|
+
hiddenFileCount,
|
|
728
|
+
hidden: hiddenEditCount > 0 ? `+ ${hiddenEditCount} more import edits hidden` : null,
|
|
729
|
+
...(view ? { view: view.saved } : {})
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
function selectImportEditSamples(edits, limit) {
|
|
733
|
+
return orderImportEditsForPresentation(edits).slice(0, limit);
|
|
734
|
+
}
|
|
735
|
+
function orderImportEditsForPresentation(edits) {
|
|
736
|
+
const samples = [];
|
|
737
|
+
const sorted = [...edits].sort(compareImportEditsForSample);
|
|
738
|
+
const seenPolicies = new Set();
|
|
739
|
+
const seenBuckets = new Set();
|
|
740
|
+
for (const edit of sorted) {
|
|
741
|
+
const bucket = importEditPathBucket(edit.file);
|
|
742
|
+
if (seenPolicies.has(edit.policyId) || seenBuckets.has(bucket)) {
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
samples.push(edit);
|
|
746
|
+
seenPolicies.add(edit.policyId);
|
|
747
|
+
seenBuckets.add(bucket);
|
|
748
|
+
}
|
|
749
|
+
const seenFiles = new Set(samples.map((sample) => sample.file));
|
|
750
|
+
for (const edit of sorted) {
|
|
751
|
+
const bucket = importEditPathBucket(edit.file);
|
|
752
|
+
if (seenFiles.has(edit.file) || seenBuckets.has(bucket)) {
|
|
753
|
+
continue;
|
|
754
|
+
}
|
|
755
|
+
samples.push(edit);
|
|
756
|
+
seenFiles.add(edit.file);
|
|
757
|
+
seenBuckets.add(bucket);
|
|
758
|
+
}
|
|
759
|
+
for (const edit of sorted) {
|
|
760
|
+
if (!samples.includes(edit)) {
|
|
761
|
+
samples.push(edit);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
return samples;
|
|
765
|
+
}
|
|
766
|
+
function selectImportEditFiles(edits, limit) {
|
|
767
|
+
return orderImportFilesForPresentation(edits, uniqueStrings(edits.map((edit) => edit.file))).slice(0, limit);
|
|
768
|
+
}
|
|
769
|
+
function orderImportFilesForPresentation(edits, files) {
|
|
770
|
+
const fileScores = new Map();
|
|
771
|
+
for (const edit of edits) {
|
|
772
|
+
const current = fileScores.get(edit.file);
|
|
773
|
+
const score = importEditSampleNoise(edit);
|
|
774
|
+
if (current === undefined || score < current) {
|
|
775
|
+
fileScores.set(edit.file, score);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
const sorted = [...files].sort((left, right) => (fileScores.get(left) ?? Number.MAX_SAFE_INTEGER) - (fileScores.get(right) ?? Number.MAX_SAFE_INTEGER)
|
|
779
|
+
|| importEditPathBucket(left).localeCompare(importEditPathBucket(right))
|
|
780
|
+
|| left.localeCompare(right));
|
|
781
|
+
const selected = [];
|
|
782
|
+
const seenBuckets = new Set();
|
|
783
|
+
for (const file of sorted) {
|
|
784
|
+
const bucket = importEditPathBucket(file);
|
|
785
|
+
if (seenBuckets.has(bucket)) {
|
|
786
|
+
continue;
|
|
787
|
+
}
|
|
788
|
+
selected.push(file);
|
|
789
|
+
seenBuckets.add(bucket);
|
|
790
|
+
}
|
|
791
|
+
for (const file of sorted) {
|
|
792
|
+
if (!selected.includes(file)) {
|
|
793
|
+
selected.push(file);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
return selected;
|
|
797
|
+
}
|
|
798
|
+
function compareImportEditsForSample(left, right) {
|
|
799
|
+
return importEditSampleNoise(left) - importEditSampleNoise(right)
|
|
800
|
+
|| importEditPathBucket(left.file).localeCompare(importEditPathBucket(right.file))
|
|
801
|
+
|| left.file.localeCompare(right.file)
|
|
802
|
+
|| left.line - right.line
|
|
803
|
+
|| left.from.localeCompare(right.from);
|
|
804
|
+
}
|
|
805
|
+
function importEditSampleNoise(edit) {
|
|
806
|
+
const pathDepth = edit.file.split("/").length;
|
|
807
|
+
const importDepth = edit.from.split("/").length + edit.to.split("/").length;
|
|
808
|
+
const textLength = edit.from.length + edit.to.length;
|
|
809
|
+
const extensionNoise = edit.from.endsWith(".js") || edit.to.endsWith(".js") ? 4 : 0;
|
|
810
|
+
const lowSignalNoise = isLowSignalImportSpecifier(edit.from) || isLowSignalImportSpecifier(edit.to) ? 80 : 0;
|
|
811
|
+
const indexNoise = edit.from.endsWith("/index") || edit.to.endsWith("/index") ? 30 : 0;
|
|
812
|
+
const deepRelativeNoise = edit.from.startsWith("../../..") || edit.to.startsWith("../../..") ? 24 : 0;
|
|
813
|
+
return Math.min(pathDepth, 10) + Math.min(importDepth, 18) + Math.min(textLength, 140) + extensionNoise + lowSignalNoise + indexNoise + deepRelativeNoise;
|
|
814
|
+
}
|
|
815
|
+
function importEditPathBucket(file) {
|
|
816
|
+
const parts = file.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
817
|
+
if (parts.length <= 2) {
|
|
818
|
+
return parts.join("/");
|
|
819
|
+
}
|
|
820
|
+
if (parts[0] === "packages" && parts.length >= 3) {
|
|
821
|
+
return parts.slice(0, 3).join("/");
|
|
822
|
+
}
|
|
823
|
+
if (parts[0] === "src" && parts.length >= 3) {
|
|
824
|
+
return parts.slice(0, 3).join("/");
|
|
825
|
+
}
|
|
826
|
+
return parts.slice(0, 2).join("/");
|
|
827
|
+
}
|
|
828
|
+
function isLowSignalImportSpecifier(specifier) {
|
|
829
|
+
return specifier === "." || specifier === ".." || specifier === "./" || specifier === "../";
|
|
830
|
+
}
|
|
831
|
+
function saveNormalizeImportsView(cwd, action, target, edits, hiddenEdits, hiddenFiles, policyGroups) {
|
|
832
|
+
if (edits.length === 0) {
|
|
833
|
+
return null;
|
|
834
|
+
}
|
|
835
|
+
if (hiddenEdits.length === 0 && hiddenFiles.length === 0) {
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
838
|
+
return (0, session_workspace_1.saveSessionResultViewJson)(cwd, `res_${crypto.randomBytes(4).toString("hex")}`, compactObject({
|
|
839
|
+
kind: "importsNormalize",
|
|
840
|
+
operation: "imports.normalize",
|
|
841
|
+
mode: action,
|
|
842
|
+
target,
|
|
843
|
+
policyGroups: policyGroupsToJson(policyGroups),
|
|
844
|
+
edits,
|
|
845
|
+
hiddenEdits,
|
|
846
|
+
hiddenEditCount: hiddenEdits.length,
|
|
847
|
+
hiddenFiles,
|
|
848
|
+
hiddenFileCount: hiddenFiles.length,
|
|
849
|
+
files: uniqueStrings(edits.map((edit) => edit.file))
|
|
850
|
+
}));
|
|
851
|
+
}
|
|
852
|
+
function importEditKey(edit) {
|
|
853
|
+
return `${edit.file}\0${edit.line}\0${edit.from}\0${edit.to}\0${edit.statementKind}`;
|
|
854
|
+
}
|
|
855
|
+
function readNormalizeImportsRuleFile(filePath, sources) {
|
|
856
|
+
if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
|
|
857
|
+
throw new errors_1.CliError("NORMALIZE_IMPORTS_RULES_NOT_FOUND", `imports normalize rules file not found: ${filePath}`);
|
|
858
|
+
}
|
|
859
|
+
sources.push(filePath);
|
|
860
|
+
return extractNormalizeImportsRules((0, import_specifier_policy_1.parseJsoncObject)(fs.readFileSync(filePath, "utf8")));
|
|
861
|
+
}
|
|
862
|
+
function readWorkspaceNormalizeImportRules(cwd) {
|
|
863
|
+
const roots = collectWorkspaceConfigSearchRoots(cwd);
|
|
864
|
+
const rules = [];
|
|
865
|
+
const sources = [];
|
|
866
|
+
for (const root of roots) {
|
|
867
|
+
const filePath = path.join(root, "aib.json");
|
|
868
|
+
if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
|
|
869
|
+
continue;
|
|
870
|
+
}
|
|
871
|
+
try {
|
|
872
|
+
const extracted = extractNormalizeImportsRules((0, import_specifier_policy_1.parseJsoncObject)(fs.readFileSync(filePath, "utf8")));
|
|
873
|
+
if (extracted.length > 0) {
|
|
874
|
+
rules.push(...extracted);
|
|
875
|
+
sources.push(filePath);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
catch {
|
|
879
|
+
// Invalid local config is handled by root/session flows; normalize keeps this pass best-effort.
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
return { rules, sources };
|
|
883
|
+
}
|
|
884
|
+
function extractNormalizeImportsRules(raw) {
|
|
885
|
+
const nestedAib = isRecord(raw.aib) ? raw.aib : {};
|
|
886
|
+
const values = [
|
|
887
|
+
raw.importNormalize,
|
|
888
|
+
raw.importsNormalize,
|
|
889
|
+
raw["imports.normalize"],
|
|
890
|
+
nestedAib.importNormalize,
|
|
891
|
+
nestedAib.importsNormalize,
|
|
892
|
+
nestedAib["imports.normalize"]
|
|
893
|
+
];
|
|
894
|
+
return values.flatMap((value) => parseNormalizeImportsRulesValue(value));
|
|
895
|
+
}
|
|
896
|
+
function parseNormalizeImportsRulesValue(value) {
|
|
897
|
+
if (Array.isArray(value)) {
|
|
898
|
+
return value.flatMap((item) => isRecord(item) ? [normalizeImportsRuleFromObject(item)] : []);
|
|
899
|
+
}
|
|
900
|
+
if (!isRecord(value)) {
|
|
901
|
+
return [];
|
|
902
|
+
}
|
|
903
|
+
if (Array.isArray(value.rules)) {
|
|
904
|
+
return value.rules.flatMap((item) => isRecord(item) ? [normalizeImportsRuleFromObject(item)] : []);
|
|
905
|
+
}
|
|
906
|
+
if (Array.isArray(value.requests)) {
|
|
907
|
+
return value.requests.flatMap((item) => isRecord(item) ? [normalizeImportsRuleFromObject(item)] : []);
|
|
908
|
+
}
|
|
909
|
+
return [normalizeImportsRuleFromObject(value)];
|
|
910
|
+
}
|
|
911
|
+
function normalizeImportsRuleFromObject(value) {
|
|
912
|
+
const rawMode = readString(value.to) ?? readString(value.mode);
|
|
913
|
+
const inside = normalizeImportsRuleTargetFromObject(value.inside);
|
|
914
|
+
const outside = normalizeImportsRuleTargetFromObject(value.outside);
|
|
915
|
+
const boundary = readString(value.boundary);
|
|
916
|
+
if (rawMode !== null && (inside || outside)) {
|
|
917
|
+
throw new errors_1.CliError("INVALID_NORMALIZE_IMPORTS_RULE", "importNormalize rule cannot combine to/mode with inside/outside.");
|
|
918
|
+
}
|
|
919
|
+
if (boundary !== null && boundary !== "*") {
|
|
920
|
+
throw new errors_1.CliError("INVALID_NORMALIZE_IMPORTS_RULE", "importNormalize boundary currently supports only \"*\".");
|
|
921
|
+
}
|
|
922
|
+
return {
|
|
923
|
+
...(readString(value.scope) ? { scope: readString(value.scope) } : {}),
|
|
924
|
+
...(rawMode !== null ? { mode: readNormalizeMode(rawMode) } : {}),
|
|
925
|
+
...(readString(value.preferAlias) ? { preferAlias: readString(value.preferAlias) } : {}),
|
|
926
|
+
...(boundary === "*" ? { boundary: "*" } : {}),
|
|
927
|
+
...(inside ? { inside } : {}),
|
|
928
|
+
...(outside ? { outside } : {}),
|
|
929
|
+
exclude: uniqueStrings([...readStringArray(value.exclude), ...readStringArray(value.excludes)])
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
function normalizeImportsRuleTargetFromObject(value) {
|
|
933
|
+
if (!isRecord(value)) {
|
|
934
|
+
return null;
|
|
935
|
+
}
|
|
936
|
+
const rawMode = readString(value.to) ?? readString(value.mode);
|
|
937
|
+
if (rawMode === null) {
|
|
938
|
+
return null;
|
|
939
|
+
}
|
|
940
|
+
return compactObject({
|
|
941
|
+
mode: readNormalizeMode(rawMode),
|
|
942
|
+
...(readString(value.preferAlias) ? { preferAlias: readString(value.preferAlias) } : {})
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
function normalizeRuleAppliesToFile(cwd, file, rule) {
|
|
946
|
+
if (!rule.scope) {
|
|
947
|
+
return true;
|
|
948
|
+
}
|
|
949
|
+
const requestPath = toDisplayPath(cwd, path.resolve(file));
|
|
950
|
+
const rulePath = toDisplayPath(cwd, path.resolve(cwd, rule.scope));
|
|
951
|
+
return requestPath === rulePath || requestPath.startsWith(`${rulePath}/`);
|
|
952
|
+
}
|
|
953
|
+
function ruleSpecificity(rule) {
|
|
954
|
+
return rule.scope ? rule.scope.length : 0;
|
|
955
|
+
}
|
|
956
|
+
function isExcludedPath(cwd, candidate, exclude) {
|
|
957
|
+
if (exclude.length === 0) {
|
|
958
|
+
return false;
|
|
959
|
+
}
|
|
960
|
+
const relative = toDisplayPath(cwd, path.resolve(candidate));
|
|
961
|
+
return exclude.some((pattern) => matchesExcludePattern(cwd, relative, pattern));
|
|
962
|
+
}
|
|
963
|
+
function matchesExcludePattern(cwd, relativePath, pattern) {
|
|
964
|
+
const normalizedPattern = toDisplayPath(cwd, path.isAbsolute(pattern) ? pattern : path.resolve(cwd, pattern));
|
|
965
|
+
if (!containsGlob(pattern)) {
|
|
966
|
+
return relativePath === normalizedPattern || relativePath.startsWith(`${normalizedPattern}/`);
|
|
967
|
+
}
|
|
968
|
+
return globToRegExp(pattern.replace(/\\/g, "/")).test(relativePath);
|
|
969
|
+
}
|
|
970
|
+
function containsGlob(value) {
|
|
971
|
+
return /[*?]/.test(value);
|
|
972
|
+
}
|
|
973
|
+
function globToRegExp(pattern) {
|
|
974
|
+
let source = "";
|
|
975
|
+
for (let index = 0; index < pattern.length; index += 1) {
|
|
976
|
+
const char = pattern[index];
|
|
977
|
+
if (char === "*") {
|
|
978
|
+
if (pattern[index + 1] === "*") {
|
|
979
|
+
source += ".*";
|
|
980
|
+
index += 1;
|
|
981
|
+
}
|
|
982
|
+
else {
|
|
983
|
+
source += "[^/]*";
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
else if (char === "?") {
|
|
987
|
+
source += "[^/]";
|
|
988
|
+
}
|
|
989
|
+
else {
|
|
990
|
+
source += escapeRegExp(char ?? "");
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
return new RegExp(`^${source}$`);
|
|
994
|
+
}
|
|
995
|
+
function buildNormalizeImportsPlanId(cwd, request, edits) {
|
|
996
|
+
return `imports_${sha256(stableStringify({ cwd, request, edits })).slice(0, 8)}`;
|
|
997
|
+
}
|
|
998
|
+
function writeNormalizeImportsPlan(cwd, record) {
|
|
999
|
+
const filePath = normalizeImportsPlanPath(cwd, record.planId);
|
|
1000
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
1001
|
+
fs.writeFileSync(filePath, `${JSON.stringify(record, null, 2)}\n`);
|
|
1002
|
+
}
|
|
1003
|
+
function readNormalizeImportsPlan(cwd, planId) {
|
|
1004
|
+
const filePath = normalizeImportsPlanPath(cwd, planId);
|
|
1005
|
+
if (!fs.existsSync(filePath)) {
|
|
1006
|
+
throw new errors_1.CliError("NORMALIZE_IMPORTS_PLAN_NOT_FOUND", `imports normalize plan not found: ${planId}`, {
|
|
1007
|
+
planId,
|
|
1008
|
+
expectedPath: filePath
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
1012
|
+
}
|
|
1013
|
+
function normalizeImportsPlanPath(cwd, planId) {
|
|
1014
|
+
return (0, workspace_cache_1.workspaceCachePath)(cwd, "imports-normalize", `${planId.replace(/[^a-z0-9_-]+/gi, "-")}.json`);
|
|
1015
|
+
}
|
|
1016
|
+
function hashEditedFiles(cwd, edits) {
|
|
1017
|
+
const hashes = {};
|
|
1018
|
+
for (const file of new Set(edits.map((edit) => edit.file))) {
|
|
1019
|
+
hashes[file] = sha256(fs.readFileSync(path.resolve(cwd, file)));
|
|
1020
|
+
}
|
|
1021
|
+
return hashes;
|
|
1022
|
+
}
|
|
1023
|
+
function collectConfigSearchRoots(cwd) {
|
|
1024
|
+
const roots = [];
|
|
1025
|
+
let current = path.resolve(cwd);
|
|
1026
|
+
const parsedRoot = path.parse(current).root;
|
|
1027
|
+
while (true) {
|
|
1028
|
+
roots.push(current);
|
|
1029
|
+
if (current === parsedRoot) {
|
|
1030
|
+
break;
|
|
1031
|
+
}
|
|
1032
|
+
const parent = path.dirname(current);
|
|
1033
|
+
if (parent === current) {
|
|
1034
|
+
break;
|
|
1035
|
+
}
|
|
1036
|
+
current = parent;
|
|
1037
|
+
}
|
|
1038
|
+
return roots.reverse();
|
|
1039
|
+
}
|
|
1040
|
+
function collectWorkspaceConfigSearchRoots(cwd) {
|
|
1041
|
+
const workspace = (0, workspace_root_1.resolveWorkspaceRoot)(cwd);
|
|
1042
|
+
if (!workspace) {
|
|
1043
|
+
return collectConfigSearchRoots(cwd);
|
|
1044
|
+
}
|
|
1045
|
+
const roots = [];
|
|
1046
|
+
const stop = path.resolve(workspace.root).toLowerCase();
|
|
1047
|
+
let current = path.resolve(cwd);
|
|
1048
|
+
while (true) {
|
|
1049
|
+
roots.push(current);
|
|
1050
|
+
if (path.resolve(current).toLowerCase() === stop) {
|
|
1051
|
+
break;
|
|
1052
|
+
}
|
|
1053
|
+
const parent = path.dirname(current);
|
|
1054
|
+
if (parent === current) {
|
|
1055
|
+
break;
|
|
1056
|
+
}
|
|
1057
|
+
current = parent;
|
|
1058
|
+
}
|
|
1059
|
+
return roots.reverse();
|
|
1060
|
+
}
|
|
1061
|
+
function sha256(value) {
|
|
1062
|
+
return crypto.createHash("sha256").update(value).digest("hex");
|
|
1063
|
+
}
|
|
1064
|
+
function stableStringify(value) {
|
|
1065
|
+
if (value === null || typeof value !== "object") {
|
|
1066
|
+
return JSON.stringify(value);
|
|
1067
|
+
}
|
|
1068
|
+
if (Array.isArray(value)) {
|
|
1069
|
+
return `[${value.map((item) => stableStringify(item)).join(",")}]`;
|
|
1070
|
+
}
|
|
1071
|
+
return `{${Object.entries(value)
|
|
1072
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
1073
|
+
.map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`)
|
|
1074
|
+
.join(",")}}`;
|
|
1075
|
+
}
|
|
1076
|
+
function readString(value) {
|
|
1077
|
+
return typeof value === "string" && value.trim() !== "" ? value.trim() : null;
|
|
1078
|
+
}
|
|
1079
|
+
function readStringArray(value) {
|
|
1080
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
1081
|
+
return [value.trim()];
|
|
1082
|
+
}
|
|
1083
|
+
if (!Array.isArray(value)) {
|
|
1084
|
+
return [];
|
|
1085
|
+
}
|
|
1086
|
+
return value
|
|
1087
|
+
.filter((item) => typeof item === "string")
|
|
1088
|
+
.map((item) => item.trim())
|
|
1089
|
+
.filter((item) => item.length > 0);
|
|
1090
|
+
}
|
|
1091
|
+
function uniqueStrings(items) {
|
|
1092
|
+
return Array.from(new Set(items));
|
|
1093
|
+
}
|
|
1094
|
+
function compactObject(value) {
|
|
1095
|
+
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined &&
|
|
1096
|
+
item !== null &&
|
|
1097
|
+
!(Array.isArray(item) && item.length === 0) &&
|
|
1098
|
+
!(typeof item === "string" && item.length === 0)));
|
|
1099
|
+
}
|
|
1100
|
+
function isSourceFile(file) {
|
|
1101
|
+
return SOURCE_EXTENSIONS.includes(path.extname(file)) && !file.endsWith(".d.ts");
|
|
1102
|
+
}
|
|
1103
|
+
function withoutSourceExtension(file) {
|
|
1104
|
+
const ext = path.extname(file);
|
|
1105
|
+
return SOURCE_EXTENSIONS.includes(ext) || IMPORT_EXTENSIONS.includes(ext)
|
|
1106
|
+
? file.slice(0, -ext.length)
|
|
1107
|
+
: file;
|
|
1108
|
+
}
|
|
1109
|
+
function isRecord(value) {
|
|
1110
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1111
|
+
}
|
|
1112
|
+
function isJsonObject(value) {
|
|
1113
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1114
|
+
}
|
|
1115
|
+
function toDisplayPath(cwd, file) {
|
|
1116
|
+
return path.relative(cwd, file).replace(/\\/g, "/");
|
|
1117
|
+
}
|
|
1118
|
+
function escapeRegExp(value) {
|
|
1119
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1120
|
+
}
|