@cosmicdrift/kumiko-framework 0.389.0 → 0.390.0
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/AGENTS.md +9 -4
- package/README.md +1 -1
- package/agents/examples/apex-surface-auth.md +2 -3
- package/agents/examples/api-worker-split.md +9 -2
- package/agents/examples/auth-claims.md +1 -1
- package/agents/examples/cross-feature-events.md +12 -12
- package/agents/examples/crypto-shredding-hr.md +2 -2
- package/agents/examples/encrypted-tenant-config.md +1 -1
- package/agents/examples/error-contract.md +12 -7
- package/agents/examples/event-sourcing.md +29 -29
- package/agents/examples/files-post-processing.md +10 -8
- package/agents/examples/inbound-mail-triage.md +1 -0
- package/agents/examples/lane-routing.md +2 -1
- package/agents/examples/legal-pages.md +2 -2
- package/agents/examples/lifecycle-hooks.md +3 -3
- package/agents/examples/managed-config.md +4 -4
- package/agents/examples/managed-pages.md +1 -1
- package/agents/examples/relations.md +19 -4
- package/agents/examples/search.md +4 -4
- package/agents/examples/secrets-demo.md +9 -6
- package/agents/examples/state-machine.md +2 -2
- package/agents/examples/tenant-settings.md +1 -1
- package/agents/examples/user-data-rights.md +3 -6
- package/agents/examples/workflow-engine.md +53 -47
- package/agents/examples.md +4 -4
- package/agents/features.md +1 -1
- package/dist/api/auth-middleware.js +1 -1
- package/dist/api/auth-routes-invite.js +2 -1
- package/dist/api/entity-read-access.d.ts +3 -1
- package/dist/api/export/export-columns.d.ts +3 -1
- package/dist/api/export/export-route.js +3 -2
- package/dist/api/export/export-screen.d.ts +2 -1
- package/dist/api/extra-route.d.ts +3 -1
- package/dist/api/index.d.ts +23 -27
- package/dist/api/index.js +13 -15
- package/dist/api/jwt.js +1 -1
- package/dist/api/observability-middleware.d.ts +1 -1
- package/dist/api/observability-middleware.js +2 -1
- package/dist/api/request-context-internals.d.ts +31 -0
- package/dist/api/request-context-internals.js +11 -0
- package/dist/api/request-context-scopes.d.ts +14 -0
- package/dist/api/request-context-scopes.js +69 -0
- package/dist/api/request-context.d.ts +1 -40
- package/dist/api/request-context.js +22 -51
- package/dist/api/request-id-middleware.d.ts +1 -1
- package/dist/api/route-registrars.d.ts +2 -1
- package/dist/api/route-registrars.js +1 -1
- package/dist/api/routes.js +7 -3
- package/dist/api/server-boot-checks.d.ts +1 -1
- package/dist/api/server-boot-checks.js +2 -2
- package/dist/api/server-event-dispatcher.d.ts +6 -1
- package/dist/api/server-event-dispatcher.js +3 -4
- package/dist/api/server-extra-routes.d.ts +1 -1
- package/dist/api/server-extra-routes.js +2 -1
- package/dist/api/server-middleware.js +3 -1
- package/dist/api/server-routes.d.ts +2 -1
- package/dist/api/server-wiring.js +6 -4
- package/dist/api/server.d.ts +2 -1
- package/dist/api/sse-route.d.ts +2 -1
- package/dist/api/tenant-scoped-secrets.d.ts +2 -0
- package/dist/api/tenant-scoped-secrets.js +13 -0
- package/dist/api/websocket-route.d.ts +1 -1
- package/dist/auth/index.d.ts +0 -1
- package/dist/auth/roles.d.ts +0 -5
- package/dist/compliance/duration-spec.d.ts +0 -1
- package/dist/compliance/duration-spec.js +0 -5
- package/dist/compliance/index.d.ts +4 -4
- package/dist/compliance/index.js +2 -2
- package/dist/compliance/profiles.d.ts +0 -15
- package/dist/compliance/profiles.js +0 -23
- package/dist/config/index.d.ts +10 -10
- package/dist/config/index.js +13 -1
- package/dist/config/internals.d.ts +9 -0
- package/dist/config/internals.js +1 -0
- package/dist/consumer-cli-internals.d.ts +4 -0
- package/dist/consumer-cli-internals.js +1 -0
- package/dist/consumer-cli.d.ts +1 -4
- package/dist/consumer-cli.js +5 -1
- package/dist/crypto/event-pii.js +1 -1
- package/dist/crypto/index.d.ts +8 -9
- package/dist/crypto/index.js +7 -8
- package/dist/crypto/pg-kms-adapter.js +6 -1
- package/dist/db/apply-entity-event.d.ts +1 -1
- package/dist/db/apply-entity-event.js +15 -47
- package/dist/db/blind-index-cleanup.js +91 -77
- package/dist/db/collect-table-metas.js +1 -1
- package/dist/db/compound-types.d.ts +1 -1
- package/dist/db/compound-types.js +0 -7
- package/dist/db/config-seed.d.ts +2 -1
- package/dist/db/config-seed.js +6 -1
- package/dist/db/connection.d.ts +3 -1
- package/dist/db/connection.js +15 -5
- package/dist/db/cross-tenant-reads.d.ts +1 -1
- package/dist/db/cross-tenant-reads.js +1 -1
- package/dist/db/dialect.d.ts +0 -5
- package/dist/db/dialect.js +0 -3
- package/dist/db/eagerload.d.ts +2 -1
- package/dist/db/entity-field-encryption.d.ts +1 -1
- package/dist/db/entity-table-meta.d.ts +1 -1
- package/dist/db/event-store-executor-context.d.ts +3 -1
- package/dist/db/event-store-executor-context.js +4 -3
- package/dist/db/event-store-executor-read-filter.d.ts +1 -1
- package/dist/db/event-store-executor-read-rows.d.ts +2 -1
- package/dist/db/event-store-executor-read-search.d.ts +2 -1
- package/dist/db/event-store-executor-read-sort.d.ts +2 -1
- package/dist/db/event-store-executor-read.js +2 -2
- package/dist/db/event-store-executor-write-atomic.js +8 -7
- package/dist/db/event-store-executor-write-steps.d.ts +3 -2
- package/dist/db/event-store-executor-write.js +7 -4
- package/dist/db/event-store-executor.d.ts +1 -1
- package/dist/db/executor-managed-tables.d.ts +7 -1
- package/dist/db/executor-managed-tables.js +11 -2
- package/dist/db/index.d.ts +29 -28
- package/dist/db/index.js +22 -20
- package/dist/db/known-table-names.d.ts +6 -0
- package/dist/db/known-table-names.js +21 -0
- package/dist/db/list-aggregate-labels.d.ts +1 -1
- package/dist/db/located-timestamp.d.ts +1 -1
- package/dist/db/located-timestamp.js +0 -5
- package/dist/db/migrate-generator.d.ts +17 -1
- package/dist/db/migrate-generator.js +50 -20
- package/dist/db/migrate-primary-key.d.ts +12 -0
- package/dist/db/migrate-primary-key.js +45 -0
- package/dist/db/migrate-rls-diff.d.ts +20 -0
- package/dist/db/migrate-rls-diff.js +61 -0
- package/dist/db/migrate-runner.js +4 -0
- package/dist/db/money.d.ts +1 -1
- package/dist/db/money.js +1 -1
- package/dist/db/parent-ref-clause.d.ts +2 -1
- package/dist/db/pg-error.d.ts +2 -0
- package/dist/db/pg-error.js +11 -0
- package/dist/db/queries/ddl.d.ts +3 -0
- package/dist/db/queries/ddl.js +34 -1
- package/dist/db/queries/event-store.js +4 -2
- package/dist/db/queries/event-tenants.d.ts +2 -0
- package/dist/db/queries/event-tenants.js +17 -0
- package/dist/db/queries/rebuild-rls-guard.d.ts +2 -0
- package/dist/db/queries/rebuild-rls-guard.js +29 -0
- package/dist/db/queries/rls-boot-catalog.d.ts +16 -0
- package/dist/db/queries/rls-boot-catalog.js +39 -0
- package/dist/db/queries/rls-catalog.d.ts +6 -0
- package/dist/db/queries/rls-catalog.js +82 -0
- package/dist/db/queries/rls-scope.d.ts +3 -0
- package/dist/db/queries/rls-scope.js +17 -0
- package/dist/db/queries/rls-shape.d.ts +10 -0
- package/dist/db/queries/rls-shape.js +42 -0
- package/dist/db/queries/session-advisory-lock.d.ts +2 -0
- package/dist/db/queries/session-advisory-lock.js +23 -0
- package/dist/db/queries/shadow-swap.d.ts +1 -2
- package/dist/db/queries/shadow-swap.js +9 -25
- package/dist/db/queries/test-stack.d.ts +4 -1
- package/dist/db/queries/test-stack.js +83 -2
- package/dist/db/query.js +11 -7
- package/dist/db/reference-data.d.ts +1 -1
- package/dist/db/reference-data.js +6 -1
- package/dist/db/render-ddl.d.ts +6 -2
- package/dist/db/render-ddl.js +7 -7
- package/dist/db/render-rls-ddl.d.ts +35 -0
- package/dist/db/render-rls-ddl.js +127 -0
- package/dist/db/replay-migration-sql.d.ts +3 -1
- package/dist/db/replay-migration-sql.js +22 -5
- package/dist/db/replay-rls.d.ts +25 -0
- package/dist/db/replay-rls.js +156 -0
- package/dist/db/row-level-security-boot-check.d.ts +5 -0
- package/dist/db/row-level-security-boot-check.js +85 -0
- package/dist/db/row-level-security-connection.d.ts +3 -0
- package/dist/db/row-level-security-connection.js +213 -0
- package/dist/db/row-level-security-scope.d.ts +33 -0
- package/dist/db/row-level-security-scope.js +127 -0
- package/dist/db/scope-tenant-db-to-tenant.d.ts +3 -0
- package/dist/db/scope-tenant-db-to-tenant.js +14 -0
- package/dist/db/sql-identifier.d.ts +1 -0
- package/dist/db/sql-identifier.js +3 -0
- package/dist/db/table-builder.d.ts +2 -1
- package/dist/db/table-builder.js +1 -1
- package/dist/db/table-info.js +1 -1
- package/dist/db/table-push.d.ts +11 -2
- package/dist/db/table-push.js +15 -2
- package/dist/db/tenant-db-runner.d.ts +3 -1
- package/dist/db/tenant-db-runner.js +4 -3
- package/dist/db/tenant-db-scoped-rebind.d.ts +10 -0
- package/dist/db/tenant-db-scoped-rebind.js +33 -0
- package/dist/db/tenant-db-statement-runner.d.ts +13 -0
- package/dist/db/tenant-db-statement-runner.js +48 -0
- package/dist/db/tenant-db.d.ts +17 -12
- package/dist/db/tenant-db.js +49 -120
- package/dist/db/tenant-id-filter.d.ts +3 -0
- package/dist/db/tenant-id-filter.js +30 -0
- package/dist/db/transaction-serialization.d.ts +6 -0
- package/dist/db/transaction-serialization.js +60 -0
- package/dist/derivatives/delete-stored-file.js +1 -1
- package/dist/derivatives/index.d.ts +2 -5
- package/dist/derivatives/index.js +2 -3
- package/dist/engine/access.d.ts +2 -1
- package/dist/engine/access.js +1 -1
- package/dist/engine/boot-validator/entity-handler.d.ts +2 -1
- package/dist/engine/boot-validator/entity-handler.js +1 -1
- package/dist/engine/boot-validator/entity-list-aggregate-options.d.ts +1 -1
- package/dist/engine/boot-validator/list-table-aggregate-options.d.ts +1 -1
- package/dist/engine/boot-validator/list-table-aggregate-query.d.ts +2 -1
- package/dist/engine/boot-validator/nav.d.ts +3 -1
- package/dist/engine/boot-validator/nav.js +1 -1
- package/dist/engine/boot-validator/ownership.d.ts +2 -1
- package/dist/engine/boot-validator/parent-ref.d.ts +2 -1
- package/dist/engine/boot-validator/projection-list-screens.d.ts +2 -1
- package/dist/engine/boot-validator/query-refs.d.ts +2 -1
- package/dist/engine/boot-validator/screens-forms.d.ts +2 -1
- package/dist/engine/boot-validator/screens-kind-shared.d.ts +3 -1
- package/dist/engine/boot-validator/screens.d.ts +2 -1
- package/dist/engine/boot-validator/workspaces.d.ts +3 -1
- package/dist/engine/bridge-stub.d.ts +5 -2
- package/dist/engine/bridge-stub.js +39 -24
- package/dist/engine/config-helpers.d.ts +2 -2
- package/dist/engine/config-helpers.js +0 -9
- package/dist/engine/constants.d.ts +0 -10
- package/dist/engine/constants.js +0 -8
- package/dist/engine/create-app.js +1 -1
- package/dist/engine/define-feature.d.ts +2 -1
- package/dist/engine/define-feature.js +1 -2
- package/dist/engine/define-handler.d.ts +1 -1
- package/dist/engine/define-step.d.ts +0 -1
- package/dist/engine/define-step.js +0 -3
- package/dist/engine/embedded-derived.d.ts +1 -1
- package/dist/engine/entity-handlers.d.ts +2 -1
- package/dist/engine/entity-handlers.js +7 -7
- package/dist/engine/entity-list-runtime-options.js +3 -1
- package/dist/engine/entity-list-searchability.d.ts +2 -1
- package/dist/engine/event-def.d.ts +2 -1
- package/dist/engine/event-helpers.d.ts +3 -1
- package/dist/engine/event-helpers.js +3 -3
- package/dist/engine/extension-names.d.ts +2 -8
- package/dist/engine/extension-names.js +2 -2
- package/dist/engine/extension-selector-plugins.d.ts +1 -1
- package/dist/engine/extensions/storage-provider.d.ts +1 -2
- package/dist/engine/extensions/user-data.d.ts +0 -8
- package/dist/engine/factories.d.ts +2 -1
- package/dist/engine/feature-builder-state.d.ts +8 -1
- package/dist/engine/feature-changelog.d.ts +1 -1
- package/dist/engine/feature-config-events-jobs.d.ts +4 -1
- package/dist/engine/feature-entity-handlers.d.ts +5 -1
- package/dist/engine/feature-manifest.js +1 -1
- package/dist/engine/feature-ui-extensions.d.ts +7 -1
- package/dist/engine/feature-ui-extensions.js +6 -4
- package/dist/engine/field-access.d.ts +2 -1
- package/dist/engine/handler-field-references.d.ts +0 -4
- package/dist/engine/index.d.ts +57 -54
- package/dist/engine/index.js +22 -27
- package/dist/engine/instruction-fields.d.ts +1 -1
- package/dist/engine/personal-data-fields.d.ts +1 -1
- package/dist/engine/qualified-name.d.ts +0 -1
- package/dist/engine/read-claim.d.ts +2 -1
- package/dist/engine/registry-facade.js +0 -3
- package/dist/engine/registry-ingest.d.ts +2 -1
- package/dist/engine/registry-ingest.js +1 -2
- package/dist/engine/registry-state.d.ts +12 -2
- package/dist/engine/registry-state.js +2 -3
- package/dist/engine/registry-validate.d.ts +3 -1
- package/dist/engine/registry-validate.js +7 -7
- package/dist/engine/run-in.d.ts +1 -1
- package/dist/engine/run-in.js +0 -1
- package/dist/engine/schema-builder.d.ts +1 -1
- package/dist/engine/schema-builder.js +1 -1
- package/dist/engine/screen-filter-ops.d.ts +2 -1
- package/dist/engine/screen-filter-ops.js +0 -5
- package/dist/engine/soft-delete-cleanup.d.ts +1 -1
- package/dist/engine/soft-delete-cleanup.js +4 -4
- package/dist/engine/state-machine.js +2 -1
- package/dist/engine/steps/_read-source.js +1 -1
- package/dist/engine/steps/aggregate-append-event.js +2 -2
- package/dist/engine/steps/call-feature.js +2 -2
- package/dist/engine/steps/mail-send.js +1 -1
- package/dist/engine/steps/retry.js +1 -1
- package/dist/engine/steps/wait-for-event.js +1 -1
- package/dist/engine/steps/wait.js +1 -1
- package/dist/engine/steps/webhook-send.js +1 -1
- package/dist/engine/template-variables.d.ts +2 -1
- package/dist/engine/transfer-adjacency.d.ts +1 -1
- package/dist/engine/types/index.d.ts +8 -31
- package/dist/engine/types/index.js +2 -10
- package/dist/engine/validation.d.ts +2 -1
- package/dist/entrypoint/index.d.ts +7 -35
- package/dist/entrypoint/index.js +7 -1
- package/dist/entrypoint/internals.d.ts +40 -0
- package/dist/entrypoint/internals.js +1 -0
- package/dist/entrypoint/row-level-security-mode-check.d.ts +3 -0
- package/dist/entrypoint/row-level-security-mode-check.js +19 -0
- package/dist/env/dry-run-internals.d.ts +10 -0
- package/dist/env/dry-run-internals.js +1 -0
- package/dist/env/dry-run.d.ts +1 -10
- package/dist/env/dry-run.js +2 -1
- package/dist/env/index.d.ts +1 -85
- package/dist/env/index.js +6 -50
- package/dist/env/internals.d.ts +87 -0
- package/dist/env/internals.js +53 -0
- package/dist/errors/classes.js +2 -2
- package/dist/errors/index.d.ts +5 -14
- package/dist/errors/index.js +4 -9
- package/dist/errors/member-resolution.js +1 -1
- package/dist/errors/reasons.d.ts +0 -1
- package/dist/errors/reasons.js +7 -7
- package/dist/errors/serialize.d.ts +0 -18
- package/dist/errors/serialize.js +0 -27
- package/dist/es-ops/index.d.ts +4 -4
- package/dist/es-ops/index.js +2 -2
- package/dist/es-ops/operations-schema.d.ts +1 -1
- package/dist/es-ops/types.d.ts +4 -5
- package/dist/event-store/admin-api-internals.d.ts +14 -0
- package/dist/event-store/admin-api-internals.js +1 -0
- package/dist/event-store/admin-api.d.ts +1 -14
- package/dist/event-store/admin-api.js +11 -6
- package/dist/event-store/archive.js +4 -2
- package/dist/event-store/errors.js +2 -2
- package/dist/event-store/event-store.js +41 -34
- package/dist/event-store/events-schema.js +4 -1
- package/dist/event-store/index.d.ts +11 -13
- package/dist/event-store/index.js +7 -9
- package/dist/event-store/rebuild-dead-letter.js +4 -2
- package/dist/event-store/snapshot.js +4 -3
- package/dist/event-store/stream-scope.d.ts +2 -0
- package/dist/event-store/stream-scope.js +6 -0
- package/dist/event-store/upcaster-dead-letter.js +4 -2
- package/dist/event-store/upcaster.d.ts +2 -1
- package/dist/files/action-form-upload.d.ts +2 -1
- package/dist/files/action-form-upload.js +1 -1
- package/dist/files/assert-file-refs-belong-to-tenant.d.ts +2 -1
- package/dist/files/assert-file-refs-belong-to-tenant.js +1 -1
- package/dist/files/bind-pending-file-refs.d.ts +2 -1
- package/dist/files/bind-pending-file-refs.js +2 -1
- package/dist/files/bind-referenced-files.write.js +1 -1
- package/dist/files/create-file-ref-from-bytes.d.ts +6 -3
- package/dist/files/create-file-ref-from-bytes.js +3 -3
- package/dist/files/create-file-ref.d.ts +3 -2
- package/dist/files/create-file-ref.js +2 -2
- package/dist/files/dispose-removed-file-refs.d.ts +2 -1
- package/dist/files/dispose-removed-file-refs.js +1 -1
- package/dist/files/feature.js +2 -2
- package/dist/files/file-handle.js +1 -1
- package/dist/files/file-routes.d.ts +1 -1
- package/dist/files/file-routes.js +12 -2
- package/dist/files/index.d.ts +11 -13
- package/dist/files/index.js +5 -7
- package/dist/files/load-save-file-refs.d.ts +2 -1
- package/dist/files/load-save-file-refs.js +1 -1
- package/dist/files/provider-resolver.d.ts +5 -4
- package/dist/files/provider-resolver.js +4 -4
- package/dist/files/storage-tracking.js +4 -2
- package/dist/files/sweep-orphaned-uploads.d.ts +1 -1
- package/dist/files/sweep-orphaned-uploads.js +1 -1
- package/dist/i18n/index.d.ts +2 -8
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/internals.d.ts +7 -0
- package/dist/i18n/internals.js +1 -0
- package/dist/i18n/required-surface-keys.d.ts +4 -1
- package/dist/internal/row-level-security.d.ts +3 -0
- package/dist/internal/row-level-security.js +3 -0
- package/dist/internal/stack-support.d.ts +1 -1
- package/dist/internal/stack-support.js +1 -1
- package/dist/internal/testing.d.ts +1 -0
- package/dist/internal/testing.js +9 -5
- package/dist/jobs/index.d.ts +1 -1
- package/dist/jobs/job-append-event.d.ts +12 -0
- package/dist/jobs/job-append-event.js +30 -0
- package/dist/jobs/job-runner-context.d.ts +2 -2
- package/dist/jobs/job-runner-context.js +46 -16
- package/dist/jobs/job-runner-execution.d.ts +1 -1
- package/dist/jobs/job-runner-execution.js +6 -4
- package/dist/jobs/job-runner-gates.d.ts +1 -1
- package/dist/jobs/job-runner-gates.js +0 -1
- package/dist/jobs/job-runner-helpers.d.ts +11 -4
- package/dist/jobs/job-runner-helpers.js +10 -1
- package/dist/jobs/job-runner-scope.d.ts +5 -2
- package/dist/jobs/job-runner-types.d.ts +2 -1
- package/dist/jobs/job-runner.js +19 -6
- package/dist/jobs/max-per-tenant.d.ts +1 -1
- package/dist/logging/index.d.ts +1 -2
- package/dist/logging/index.js +1 -1
- package/dist/logging/pino-logger.js +1 -1
- package/dist/logging/utils.d.ts +1 -0
- package/dist/logging/utils.js +6 -0
- package/dist/migrations/index.d.ts +3 -3
- package/dist/migrations/index.js +3 -3
- package/dist/migrations/pending-rebuilds.d.ts +1 -1
- package/dist/migrations/pending-rebuilds.js +1 -1
- package/dist/migrations/pii-event-backfill.js +4 -1
- package/dist/observability/escape-hatch-report.d.ts +2 -1
- package/dist/observability/index.d.ts +7 -15
- package/dist/observability/index.js +4 -12
- package/dist/observability/metric-validator.js +1 -1
- package/dist/observability/metrics-handle.d.ts +0 -1
- package/dist/observability/metrics-handle.js +2 -15
- package/dist/observability/recording-tracer.d.ts +1 -2
- package/dist/observability/recording-tracer.js +0 -6
- package/dist/observability/sensitive-filter.d.ts +0 -2
- package/dist/observability/sensitive-filter.js +0 -29
- package/dist/pipeline/active-membership.d.ts +2 -1
- package/dist/pipeline/active-membership.js +6 -2
- package/dist/pipeline/append-event-core.d.ts +2 -1
- package/dist/pipeline/append-event-core.js +2 -2
- package/dist/pipeline/attach-outside-transaction.d.ts +3 -0
- package/dist/pipeline/attach-outside-transaction.js +13 -0
- package/dist/pipeline/auth-claims-resolver.d.ts +2 -1
- package/dist/pipeline/cascade-handler.d.ts +2 -1
- package/dist/pipeline/cascade-handler.js +3 -2
- package/dist/pipeline/config-accessor-factory.d.ts +1 -1
- package/dist/pipeline/config-accessor-factory.js +1 -1
- package/dist/pipeline/context-services.d.ts +56 -0
- package/dist/pipeline/context-services.js +73 -0
- package/dist/pipeline/dispatch-batch.d.ts +2 -1
- package/dist/pipeline/dispatch-batch.js +31 -18
- package/dist/pipeline/dispatch-query.js +5 -4
- package/dist/pipeline/dispatch-scope.d.ts +6 -0
- package/dist/pipeline/dispatch-scope.js +27 -0
- package/dist/pipeline/dispatch-shared.d.ts +13 -9
- package/dist/pipeline/dispatch-shared.js +75 -198
- package/dist/pipeline/dispatch-stream.js +8 -4
- package/dist/pipeline/dispatch-write.d.ts +2 -1
- package/dist/pipeline/dispatch-write.js +10 -8
- package/dist/pipeline/dispatcher-utils.d.ts +3 -1
- package/dist/pipeline/dispatcher-utils.js +8 -2
- package/dist/pipeline/dispatcher.d.ts +3 -2
- package/dist/pipeline/dispatcher.js +4 -3
- package/dist/pipeline/event-consumer-state.d.ts +0 -1
- package/dist/pipeline/event-dispatcher-delivery.d.ts +1 -1
- package/dist/pipeline/event-dispatcher-delivery.js +4 -2
- package/dist/pipeline/event-dispatcher.d.ts +2 -2
- package/dist/pipeline/event-dispatcher.js +7 -3
- package/dist/pipeline/event-retention.js +59 -56
- package/dist/pipeline/handler-access-error.js +2 -1
- package/dist/pipeline/handler-context-auth.d.ts +5 -6
- package/dist/pipeline/handler-context-auth.js +7 -4
- package/dist/pipeline/handler-context-config.d.ts +2 -5
- package/dist/pipeline/handler-context-config.js +2 -2
- package/dist/pipeline/handler-context-db.d.ts +32 -7
- package/dist/pipeline/handler-context-db.js +26 -17
- package/dist/pipeline/handler-context-dispatch.d.ts +13 -7
- package/dist/pipeline/handler-context-dispatch.js +9 -8
- package/dist/pipeline/handler-context-events.d.ts +22 -36
- package/dist/pipeline/handler-context-events.js +36 -31
- package/dist/pipeline/handler-context-member-resolution.d.ts +2 -0
- package/dist/pipeline/handler-context-member-resolution.js +110 -0
- package/dist/pipeline/handler-context-notify.d.ts +3 -2
- package/dist/pipeline/handler-context-notify.js +1 -1
- package/dist/pipeline/handler-context-observability.d.ts +2 -4
- package/dist/pipeline/handler-context-observability.js +7 -5
- package/dist/pipeline/handler-context-phase-denials.d.ts +11 -0
- package/dist/pipeline/handler-context-phase-denials.js +98 -0
- package/dist/pipeline/handler-context-scope.d.ts +7 -10
- package/dist/pipeline/handler-context-scope.js +18 -20
- package/dist/pipeline/index.d.ts +9 -21
- package/dist/pipeline/index.js +5 -7
- package/dist/pipeline/irreversible-operation-gate.d.ts +1 -1
- package/dist/pipeline/irreversible-operation-gate.js +2 -2
- package/dist/pipeline/lifecycle-pipeline.d.ts +8 -7
- package/dist/pipeline/lifecycle-pipeline.js +9 -15
- package/dist/pipeline/member-read-only-transaction.js +11 -3
- package/dist/pipeline/member-reader.d.ts +1 -1
- package/dist/pipeline/member-reader.js +2 -2
- package/dist/pipeline/msp-rebuild.js +5 -3
- package/dist/pipeline/multi-stream-apply-context.js +3 -2
- package/dist/pipeline/notify-scope.d.ts +2 -1
- package/dist/pipeline/pre-handler-gates.d.ts +2 -1
- package/dist/pipeline/pre-transaction-reservations.d.ts +3 -3
- package/dist/pipeline/pre-transaction-reservations.js +9 -7
- package/dist/pipeline/projection-rebuild.js +12 -5
- package/dist/pipeline/projection-state.d.ts +0 -6
- package/dist/pipeline/projection-state.js +0 -5
- package/dist/pipeline/projections-runner.d.ts +2 -1
- package/dist/pipeline/projections-runner.js +10 -6
- package/dist/pipeline/system-hooks.d.ts +3 -1
- package/dist/pipeline/system-hooks.js +6 -4
- package/dist/pipeline/system-identity-switch.d.ts +4 -2
- package/dist/pipeline/system-identity-switch.js +51 -36
- package/dist/pipeline/typed-append-event.d.ts +2 -0
- package/dist/pipeline/typed-append-event.js +4 -0
- package/dist/pipeline/write-origin.js +2 -2
- package/dist/pipeline/write-result-masking.d.ts +1 -1
- package/dist/random/index.d.ts +1 -2
- package/dist/random/index.js +1 -2
- package/dist/rate-limit/bucket.d.ts +2 -1
- package/dist/rate-limit/middleware.js +2 -1
- package/dist/redis/index.d.ts +3 -4
- package/dist/redis/index.js +2 -2
- package/dist/schema-cli/apply-command.js +5 -2
- package/dist/schema-cli/baseline-command.js +7 -2
- package/dist/schema-cli/generate-command.js +7 -9
- package/dist/schema-cli/shared.d.ts +4 -0
- package/dist/schema-cli/shared.js +21 -2
- package/dist/schema-cli/status-command.js +8 -2
- package/dist/schema-cli/validate-command.js +52 -4
- package/dist/schema-cli.d.ts +0 -1
- package/dist/search/configure-tenant-index.d.ts +1 -3
- package/dist/search/configure-tenant-index.js +0 -4
- package/dist/search/index.d.ts +1 -4
- package/dist/search/index.js +0 -2
- package/dist/search/meilisearch-adapter-internals.d.ts +8 -0
- package/dist/search/meilisearch-adapter-internals.js +9 -0
- package/dist/search/meilisearch-adapter.d.ts +1 -8
- package/dist/search/meilisearch-adapter.js +6 -7
- package/dist/search/meilisearch-peer.d.ts +2 -0
- package/dist/search/meilisearch-peer.js +5 -0
- package/dist/search/reindex-entity.js +93 -87
- package/dist/secrets/index.d.ts +3 -4
- package/dist/secrets/index.js +2 -3
- package/dist/seeding/index.d.ts +2 -2
- package/dist/seeding/index.js +1 -2
- package/dist/time/index.d.ts +2 -2
- package/dist/time/index.js +1 -1
- package/dist/time/tz-context.d.ts +0 -5
- package/dist/time/tz-context.js +0 -9
- package/dist/ui-types/index.d.ts +8 -11
- package/dist/ui-types/index.js +3 -3
- package/dist/upgrade-changelog.d.ts +3 -2
- package/dist/upgrade-changelog.js +12 -8
- package/dist/upgrade-cli-internals.d.ts +8 -0
- package/dist/upgrade-cli-internals.js +63 -0
- package/dist/upgrade-cli.d.ts +1 -9
- package/dist/upgrade-cli.js +10 -64
- package/dist/utils/import-optional-peer.d.ts +6 -0
- package/dist/utils/import-optional-peer.js +19 -0
- package/dist/utils/index.d.ts +1 -4
- package/dist/utils/index.js +1 -4
- package/package.json +22 -18
- package/src/changes.json +206 -0
- package/dist/crypto/request-kms-cache.d.ts +0 -8
- package/dist/crypto/request-kms-cache.js +0 -21
- package/dist/engine/codemod/index.d.ts +0 -2
- package/dist/engine/codemod/index.js +0 -1
- package/dist/engine/codemod/pipeline-codemod.d.ts +0 -50
- package/dist/engine/codemod/pipeline-codemod.js +0 -536
- package/dist/engine/feature-ast/entity-field-types.d.ts +0 -13
- package/dist/engine/feature-ast/entity-field-types.js +0 -35
- package/dist/engine/feature-ast/extractors/ai-steps.d.ts +0 -6
- package/dist/engine/feature-ast/extractors/ai-steps.js +0 -254
- package/dist/engine/feature-ast/extractors/events.d.ts +0 -5
- package/dist/engine/feature-ast/extractors/events.js +0 -275
- package/dist/engine/feature-ast/extractors/handlers.d.ts +0 -24
- package/dist/engine/feature-ast/extractors/handlers.js +0 -358
- package/dist/engine/feature-ast/extractors/hooks.d.ts +0 -24
- package/dist/engine/feature-ast/extractors/hooks.js +0 -248
- package/dist/engine/feature-ast/extractors/index.d.ts +0 -14
- package/dist/engine/feature-ast/extractors/index.js +0 -13
- package/dist/engine/feature-ast/extractors/jobs-routes.d.ts +0 -7
- package/dist/engine/feature-ast/extractors/jobs-routes.js +0 -145
- package/dist/engine/feature-ast/extractors/projections-screens.d.ts +0 -10
- package/dist/engine/feature-ast/extractors/projections-screens.js +0 -195
- package/dist/engine/feature-ast/extractors/resolve-import.d.ts +0 -21
- package/dist/engine/feature-ast/extractors/resolve-import.js +0 -180
- package/dist/engine/feature-ast/extractors/round1.d.ts +0 -11
- package/dist/engine/feature-ast/extractors/round1.js +0 -87
- package/dist/engine/feature-ast/extractors/round2.d.ts +0 -7
- package/dist/engine/feature-ast/extractors/round2.js +0 -191
- package/dist/engine/feature-ast/extractors/round3.d.ts +0 -23
- package/dist/engine/feature-ast/extractors/round3.js +0 -292
- package/dist/engine/feature-ast/extractors/round5.d.ts +0 -9
- package/dist/engine/feature-ast/extractors/round5.js +0 -68
- package/dist/engine/feature-ast/extractors/round6.d.ts +0 -4
- package/dist/engine/feature-ast/extractors/round6.js +0 -17
- package/dist/engine/feature-ast/extractors/shared.d.ts +0 -94
- package/dist/engine/feature-ast/extractors/shared.js +0 -343
- package/dist/engine/feature-ast/index.d.ts +0 -16
- package/dist/engine/feature-ast/index.js +0 -10
- package/dist/engine/feature-ast/parse.d.ts +0 -31
- package/dist/engine/feature-ast/parse.js +0 -485
- package/dist/engine/feature-ast/patch.d.ts +0 -212
- package/dist/engine/feature-ast/patch.js +0 -611
- package/dist/engine/feature-ast/patcher.d.ts +0 -217
- package/dist/engine/feature-ast/patcher.js +0 -281
- package/dist/engine/feature-ast/pattern-change-schema.d.ts +0 -1238
- package/dist/engine/feature-ast/pattern-change-schema.js +0 -1072
- package/dist/engine/feature-ast/pattern-id-matchers.d.ts +0 -7
- package/dist/engine/feature-ast/pattern-id-matchers.js +0 -211
- package/dist/engine/feature-ast/pattern-id-schema.d.ts +0 -251
- package/dist/engine/feature-ast/pattern-id-schema.js +0 -166
- package/dist/engine/feature-ast/patterns.d.ts +0 -322
- package/dist/engine/feature-ast/patterns.js +0 -107
- package/dist/engine/feature-ast/render.d.ts +0 -47
- package/dist/engine/feature-ast/render.js +0 -666
- package/dist/engine/feature-ast/source-location.d.ts +0 -17
- package/dist/engine/feature-ast/source-location.js +0 -27
- package/dist/engine/pattern-library/index.d.ts +0 -2
- package/dist/engine/pattern-library/index.js +0 -3
- package/dist/engine/pattern-library/library.d.ts +0 -14
- package/dist/engine/pattern-library/library.js +0 -94
- package/dist/engine/pattern-library/mixed-schemas.d.ts +0 -16
- package/dist/engine/pattern-library/mixed-schemas.js +0 -559
- package/dist/engine/pattern-library/opaque-schemas.d.ts +0 -7
- package/dist/engine/pattern-library/opaque-schemas.js +0 -115
- package/dist/engine/pattern-library/shared-fields.d.ts +0 -122
- package/dist/engine/pattern-library/shared-fields.js +0 -88
- package/dist/engine/pattern-library/static-schemas.d.ts +0 -21
- package/dist/engine/pattern-library/static-schemas.js +0 -487
- package/dist/engine/pattern-library/types.d.ts +0 -158
- package/dist/engine/pattern-library/types.js +0 -36
- package/dist/engine/resolve-config-or-param.d.ts +0 -18
- package/dist/engine/resolve-config-or-param.js +0 -76
- package/src/scripts/codemod/README.md +0 -187
- package/src/scripts/codemod/codemod-support.ts +0 -334
- package/src/scripts/codemod/collect-source-files.ts +0 -48
- package/src/scripts/codemod/crypto-shredding-testing-move.ts +0 -119
- package/src/scripts/codemod/db-factory.ts +0 -810
- package/src/scripts/codemod/feature-factory.ts +0 -429
- package/src/scripts/codemod/feature-layout.ts +0 -424
- package/src/scripts/codemod/import-extensions.ts +0 -118
- package/src/scripts/codemod/migrate-cross-tenant.ts +0 -328
- package/src/scripts/codemod/migrate-db-raw.ts +0 -401
- package/src/scripts/codemod/migrate-open-to-all.ts +0 -235
- package/src/scripts/codemod/object-form.ts +0 -746
- package/src/scripts/codemod/package-merge.ts +0 -299
- package/src/scripts/codemod/pii-personal-migration.ts +0 -816
- package/src/scripts/codemod/remove-engine-payload-casts.ts +0 -318
- package/src/scripts/codemod/s3-imports.ts +0 -236
- package/src/scripts/codemod/tenant-db-options.ts +0 -454
- package/src/scripts/codemod/testing-injection.ts +0 -215
- package/src/scripts/codemod/testing-move-targets.ts +0 -161
- package/src/scripts/codemod/testing-move.ts +0 -542
- package/src/scripts/codemod/unprocessable-error-details-reason.ts +0 -411
|
@@ -1,611 +0,0 @@
|
|
|
1
|
-
// Patch operations: apply add/replace/remove/update changes to a feature-file's
|
|
2
|
-
// SourceFile in-place, working at the r.*-call granularity. Custom code
|
|
3
|
-
// (helpers, comments, imports, anything between calls) survives every
|
|
4
|
-
// patch unchanged — the patcher only touches the spans it owns.
|
|
5
|
-
//
|
|
6
|
-
// **Identity model — Natural-Key:** patterns are addressed by the
|
|
7
|
-
// human-readable name they carry: entity-name, handler-name, nav-id,
|
|
8
|
-
// hook-target+type, etc. Reorders and re-renderings don't break IDs;
|
|
9
|
-
// renames are explicit (remove old → add new). For the few singleton
|
|
10
|
-
// patterns (toggleable, requires, systemScope) the kind itself is the
|
|
11
|
-
// key — a feature has at most one of each.
|
|
12
|
-
//
|
|
13
|
-
// **Position semantics:**
|
|
14
|
-
// - addPattern → appended at the end of the setup callback
|
|
15
|
-
// - replacePattern → in place, same indentation as the original call
|
|
16
|
-
// - removePattern → call + leading blank-line whitespace gone
|
|
17
|
-
// - updatePattern → only the named header properties of a handler's
|
|
18
|
-
// inline object literal change; everything else, comments included,
|
|
19
|
-
// stays byte-identical (no re-render)
|
|
20
|
-
//
|
|
21
|
-
// **Renderer-driven output.** Every pattern lands in canonical Object-
|
|
22
|
-
// Form (single-arg literal, see render.ts). Existing patterns in legacy
|
|
23
|
-
// positional form get converted on replace; new patterns start
|
|
24
|
-
// canonical. Schema-Version-Header is the renderer's responsibility.
|
|
25
|
-
//
|
|
26
|
-
// **Comment-Preservation — known limitation.** Inline comments INSIDE a
|
|
27
|
-
// pattern (e.g. `// reason: legacy field` on an entity field property)
|
|
28
|
-
// are LOST on replace, because the renderer regenerates the call from
|
|
29
|
-
// the parsed FeaturePattern, which doesn't carry comment-trivia.
|
|
30
|
-
// Comments BETWEEN patterns (helper-functions, top-of-feature notes,
|
|
31
|
-
// imports) survive every patch — only comments authored on lines the
|
|
32
|
-
// patcher rewrites are dropped. Tracked as a future-work item: see
|
|
33
|
-
// roadmap C-Notes for the canonical-comment-attach Pattern that would
|
|
34
|
-
// preserve prefixed `// kumiko-comment:` markers across roundtrips.
|
|
35
|
-
import { SyntaxKind, } from "ts-morph";
|
|
36
|
-
import { readPropertyKey } from "./extractors/shared.js";
|
|
37
|
-
import { callMatchesId } from "./pattern-id-matchers.js";
|
|
38
|
-
import { indent, PATTERN_INDENT, renderPattern, renderValue } from "./render.js";
|
|
39
|
-
/**
|
|
40
|
-
* Apply a sequence of changes to the source file in-place. The list is
|
|
41
|
-
* processed in order; replace/remove failures (id not found) throw so
|
|
42
|
-
* callers can react explicitly — silent no-ops would mask design bugs
|
|
43
|
-
* in the Designer/AI generator. Adds always succeed.
|
|
44
|
-
*
|
|
45
|
-
* The function does NOT save the file — `sourceFile.saveSync()` (or the
|
|
46
|
-
* caller's persistence layer) is expected to follow.
|
|
47
|
-
*/
|
|
48
|
-
export function applyChanges(sourceFile, changes) {
|
|
49
|
-
for (const change of changes) {
|
|
50
|
-
switch (change.op) {
|
|
51
|
-
case "add":
|
|
52
|
-
addPattern(sourceFile, change.pattern);
|
|
53
|
-
break;
|
|
54
|
-
case "replace":
|
|
55
|
-
replacePattern(sourceFile, change.id, change.pattern);
|
|
56
|
-
break;
|
|
57
|
-
case "remove":
|
|
58
|
-
removePattern(sourceFile, change.id);
|
|
59
|
-
break;
|
|
60
|
-
case "update":
|
|
61
|
-
updatePattern(sourceFile, change);
|
|
62
|
-
break;
|
|
63
|
-
default: {
|
|
64
|
-
const _exhaustive = change;
|
|
65
|
-
throw new Error(`applyChanges: unknown op ${String(_exhaustive)}`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
// =============================================================================
|
|
71
|
-
// Add
|
|
72
|
-
// =============================================================================
|
|
73
|
-
/**
|
|
74
|
-
* Low-level escape hatch: append a hand-built FeaturePattern at the end
|
|
75
|
-
* of the setup callback's body. **Prefer the typed `add{Kind}` methods
|
|
76
|
-
* on `createFeaturePatcher(sf)`** — they take natural args, build the
|
|
77
|
-
* FeaturePattern internally, and avoid SourceLocation boilerplate.
|
|
78
|
-
*
|
|
79
|
-
* Use this directly when:
|
|
80
|
-
* - Migrating a parsed pattern from another file (already-built
|
|
81
|
-
* FeaturePattern object on hand)
|
|
82
|
-
* - The pattern kind isn't yet covered by a typed `add{Kind}`
|
|
83
|
-
*
|
|
84
|
-
* The pattern is rendered (canonical Object-Form) and inserted as the
|
|
85
|
-
* last statement, separated from the previous one by a blank line —
|
|
86
|
-
* biome-stable formatting that matches the renderFeatureFile output.
|
|
87
|
-
*/
|
|
88
|
-
export function addPattern(sourceFile, pattern) {
|
|
89
|
-
if (isAiStepId(pattern)) {
|
|
90
|
-
throw new Error(`addPattern: ${pattern.kind} steps must be inserted into a defineWorkflow steps array, not the setup body`);
|
|
91
|
-
}
|
|
92
|
-
const setup = findSetupCallback(sourceFile);
|
|
93
|
-
if (!setup) {
|
|
94
|
-
throw new Error("addPattern: no defineFeature(name, (r) => { ... }) call found");
|
|
95
|
-
}
|
|
96
|
-
const body = setup.body;
|
|
97
|
-
const rendered = indent(renderPattern(pattern), PATTERN_INDENT);
|
|
98
|
-
// Find the closing brace of the body to insert just before it. The body
|
|
99
|
-
// is a Block; its last child is the close-brace, so the safe insertion
|
|
100
|
-
// point is the position of the close-brace (insertText pushes it down).
|
|
101
|
-
const closeBracePos = body.getEnd() - 1; // `}`
|
|
102
|
-
const lastStatement = lastNonTriviaChild(body);
|
|
103
|
-
// If the body has at least one statement, prefix with a blank line so
|
|
104
|
-
// every pattern is visually separated. For an empty setup callback,
|
|
105
|
-
// skip the leading newline so the first statement isn't preceded by a
|
|
106
|
-
// gratuitous blank line.
|
|
107
|
-
const needsLeadingBlank = lastStatement !== undefined;
|
|
108
|
-
const text = needsLeadingBlank ? `\n${rendered}\n` : `${rendered}\n`;
|
|
109
|
-
sourceFile.insertText(closeBracePos, text);
|
|
110
|
-
}
|
|
111
|
-
// =============================================================================
|
|
112
|
-
// Replace
|
|
113
|
-
// =============================================================================
|
|
114
|
-
/**
|
|
115
|
-
* Find the call matching `id` and replace the entire CallExpression text
|
|
116
|
-
* with the rendered version of `pattern`. The replacement is reindented
|
|
117
|
-
* to match the original call's column so existing helpers/comments
|
|
118
|
-
* around it stay aligned. Throws when no call matches — callers must
|
|
119
|
-
* handle that case explicitly.
|
|
120
|
-
*/
|
|
121
|
-
export function replacePattern(sourceFile, id, pattern) {
|
|
122
|
-
const call = findCallForId(sourceFile, id);
|
|
123
|
-
if (!call) {
|
|
124
|
-
throw new Error(`replacePattern: no call found for ${describeId(id)}`);
|
|
125
|
-
}
|
|
126
|
-
// Whole call-statement spans from the CallExpression's start through
|
|
127
|
-
// its enclosing ExpressionStatement (which carries the trailing `;`).
|
|
128
|
-
const enclosingStatement = call.getFirstAncestorByKind(SyntaxKind.ExpressionStatement);
|
|
129
|
-
const startNode = isAiStepId(id) ? call : (enclosingStatement ?? call);
|
|
130
|
-
const startPos = startNode.getStart();
|
|
131
|
-
// AI steps live in array literals — replace only the CallExpression so the
|
|
132
|
-
// surrounding comma stays (comma-eating belongs to removePattern alone).
|
|
133
|
-
const endPos = isAiStepId(id) ? call.getEnd() : startNode.getEnd();
|
|
134
|
-
// Detect column of the original call's first non-whitespace character;
|
|
135
|
-
// the rendered pattern starts at column 0 and gets indented to match.
|
|
136
|
-
const startLineCol = sourceFile.getLineAndColumnAtPos(startPos);
|
|
137
|
-
const originalIndent = " ".repeat(Math.max(0, startLineCol.column - 1));
|
|
138
|
-
const rendered = indent(renderPattern(pattern), originalIndent).trimStart();
|
|
139
|
-
sourceFile.replaceText([startPos, endPos], rendered);
|
|
140
|
-
}
|
|
141
|
-
// =============================================================================
|
|
142
|
-
// Remove
|
|
143
|
-
// =============================================================================
|
|
144
|
-
/**
|
|
145
|
-
* Find the call matching `id` and remove it together with its trailing
|
|
146
|
-
* newline. Comments belonging to the pattern are unaffected only when
|
|
147
|
-
* they live BEFORE the call as line-leading trivia — those leading
|
|
148
|
-
* comments are kept (they may belong to surrounding code, the patcher
|
|
149
|
-
* can't disambiguate without semantic markers). Inline comments on the
|
|
150
|
-
* same line as the call are removed with the call.
|
|
151
|
-
*/
|
|
152
|
-
export function removePattern(sourceFile, id) {
|
|
153
|
-
const call = findCallForId(sourceFile, id);
|
|
154
|
-
if (!call) {
|
|
155
|
-
throw new Error(`removePattern: no call found for ${describeId(id)}`);
|
|
156
|
-
}
|
|
157
|
-
if (isAiStepId(id)) {
|
|
158
|
-
const { start, end } = aiStepPatchSpan(sourceFile, call);
|
|
159
|
-
sourceFile.replaceText([start, end], "");
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
const enclosingStatement = call.getFirstAncestorByKind(SyntaxKind.ExpressionStatement);
|
|
163
|
-
const target = enclosingStatement ?? call;
|
|
164
|
-
// Erase from the start of the line containing the statement (so leading
|
|
165
|
-
// indentation goes with it) through the trailing newline, including the
|
|
166
|
-
// *leading* blank line that addPattern emits — keeps blank-line counts
|
|
167
|
-
// stable under add → remove cycles. We don't touch leading comments.
|
|
168
|
-
const startPos = lineStart(sourceFile, target.getStart());
|
|
169
|
-
const endPos = lineEnd(sourceFile, target.getEnd());
|
|
170
|
-
// Collapse a preceding blank line if there is one (avoids a double
|
|
171
|
-
// blank line between the now-adjacent statements).
|
|
172
|
-
const collapseStart = collapsePrecedingBlankLine(sourceFile, startPos);
|
|
173
|
-
sourceFile.replaceText([collapseStart, endPos + 1], "");
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
// =============================================================================
|
|
177
|
-
// Update — patch a subset of a handler pattern's header fields in place
|
|
178
|
-
// =============================================================================
|
|
179
|
-
const WRITE_HANDLER_HEADER_KEY_FLAGS = {
|
|
180
|
-
access: true,
|
|
181
|
-
description: true,
|
|
182
|
-
agent: true,
|
|
183
|
-
rateLimit: true,
|
|
184
|
-
additionalRateLimits: true,
|
|
185
|
-
unsafeSkipTransitionGuard: true,
|
|
186
|
-
escapeHatch: true,
|
|
187
|
-
};
|
|
188
|
-
const QUERY_HANDLER_HEADER_KEY_FLAGS = {
|
|
189
|
-
access: true,
|
|
190
|
-
description: true,
|
|
191
|
-
agent: true,
|
|
192
|
-
rateLimit: true,
|
|
193
|
-
escapeHatch: true,
|
|
194
|
-
};
|
|
195
|
-
const STREAM_HANDLER_HEADER_KEY_FLAGS = {
|
|
196
|
-
access: true,
|
|
197
|
-
rateLimit: true,
|
|
198
|
-
escapeHatch: true,
|
|
199
|
-
};
|
|
200
|
-
const HEADER_KEY_FLAGS_BY_HANDLER_KIND = {
|
|
201
|
-
writeHandler: WRITE_HANDLER_HEADER_KEY_FLAGS,
|
|
202
|
-
queryHandler: QUERY_HANDLER_HEADER_KEY_FLAGS,
|
|
203
|
-
streamHandler: STREAM_HANDLER_HEADER_KEY_FLAGS,
|
|
204
|
-
};
|
|
205
|
-
function lastProperty(obj) {
|
|
206
|
-
return obj.getProperties().at(-1);
|
|
207
|
-
}
|
|
208
|
-
// ts-morph's getProperty(name) keeps the quotes of string-literal keys, so `"description": x` would never match `description`.
|
|
209
|
-
function findPropertyByKey(obj, key) {
|
|
210
|
-
return obj.getProperties().find((prop) => {
|
|
211
|
-
const assign = prop.asKind(SyntaxKind.PropertyAssignment);
|
|
212
|
-
if (assign)
|
|
213
|
-
return readPropertyKey(assign) === key;
|
|
214
|
-
return prop.asKind(SyntaxKind.ShorthandPropertyAssignment)?.getName() === key;
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
// Replaces the value of an already-present key; undefined when the key is missing.
|
|
218
|
-
function buildInPlaceSetEdit(obj, key, value) {
|
|
219
|
-
const sourceFile = obj.getSourceFile();
|
|
220
|
-
const existing = findPropertyByKey(obj, key);
|
|
221
|
-
const assign = existing?.asKind(SyntaxKind.PropertyAssignment);
|
|
222
|
-
if (assign) {
|
|
223
|
-
const init = assign.getInitializer();
|
|
224
|
-
if (init) {
|
|
225
|
-
// Column of the *property*, not the initializer — the initializer's
|
|
226
|
-
// further-right column would misalign a multi-line rendered value.
|
|
227
|
-
const col = sourceFile.getLineAndColumnAtPos(assign.getStart()).column;
|
|
228
|
-
return { start: init.getStart(), end: init.getEnd(), text: renderValue(value, col - 1) };
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
const shorthand = existing?.asKind(SyntaxKind.ShorthandPropertyAssignment);
|
|
232
|
-
if (shorthand) {
|
|
233
|
-
const col = sourceFile.getLineAndColumnAtPos(shorthand.getStart()).column;
|
|
234
|
-
return {
|
|
235
|
-
start: shorthand.getStart(),
|
|
236
|
-
end: shorthand.getEnd(),
|
|
237
|
-
text: `${key}: ${renderValue(value, col - 1)}`,
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
return undefined;
|
|
241
|
-
}
|
|
242
|
-
// All missing keys go into ONE edit: separate edits would share the same
|
|
243
|
-
// anchor position and depend on apply order and trailing-comma luck.
|
|
244
|
-
function buildAppendEdit(obj, entries) {
|
|
245
|
-
const sourceFile = obj.getSourceFile();
|
|
246
|
-
const last = lastProperty(obj);
|
|
247
|
-
const fullText = sourceFile.getFullText();
|
|
248
|
-
const isSingleLineLiteral = !obj.getText().includes("\n");
|
|
249
|
-
if (!last) {
|
|
250
|
-
// Empty literal — insert right after the opening brace.
|
|
251
|
-
const openBrace = obj.getFirstChildByKindOrThrow(SyntaxKind.OpenBraceToken);
|
|
252
|
-
const joined = entries.map(([key, value]) => `${key}: ${renderValue(value, 0)}`).join(", ");
|
|
253
|
-
return { start: openBrace.getEnd(), end: openBrace.getEnd(), text: ` ${joined} ` };
|
|
254
|
-
}
|
|
255
|
-
if (isSingleLineLiteral) {
|
|
256
|
-
let pos = last.getEnd();
|
|
257
|
-
const hasComma = fullText[pos] === ",";
|
|
258
|
-
if (hasComma)
|
|
259
|
-
pos++;
|
|
260
|
-
const joined = entries.map(([key, value]) => `${key}: ${renderValue(value, 0)}`).join(", ");
|
|
261
|
-
return { start: pos, end: pos, text: `${hasComma ? "" : ","} ${joined}` };
|
|
262
|
-
}
|
|
263
|
-
const col = sourceFile.getLineAndColumnAtPos(last.getStart()).column;
|
|
264
|
-
const indentStr = " ".repeat(col - 1);
|
|
265
|
-
const valueEnd = last.getEnd();
|
|
266
|
-
const hasComma = fullText[valueEnd] === ",";
|
|
267
|
-
const contentStart = hasComma ? valueEnd + 1 : valueEnd;
|
|
268
|
-
const lineEndPos = lineEnd(sourceFile, contentStart);
|
|
269
|
-
// Rest of the line after the value/comma — normally empty, or a trailing comment.
|
|
270
|
-
const restOfLine = fullText.slice(contentStart, lineEndPos);
|
|
271
|
-
const restIsBlankOrComment = restOfLine.trim().length === 0 || restOfLine.trim().startsWith("//");
|
|
272
|
-
if (!restIsBlankOrComment) {
|
|
273
|
-
// Last property shares its line with other content (e.g. `});`) —
|
|
274
|
-
// appending here would land after it. Narrower than replace; bail.
|
|
275
|
-
throw new Error("updatePattern: cannot append a header field — the handler literal's last property shares a line with other code; use replace");
|
|
276
|
-
}
|
|
277
|
-
const appended = entries
|
|
278
|
-
.map(([key, value]) => `\n${indentStr}${key}: ${renderValue(value, col - 1)},`)
|
|
279
|
-
.join("");
|
|
280
|
-
// Reconstruct the comma here (not inserted after the value) so it lands
|
|
281
|
-
// right after the value, never inside a trailing `//` comment.
|
|
282
|
-
return { start: valueEnd, end: lineEndPos, text: `,${restOfLine}${appended}` };
|
|
283
|
-
}
|
|
284
|
-
// Whole-line delete: property was alone on its line (with its indentation
|
|
285
|
-
// and trailing newline) — used when nothing else shares that line.
|
|
286
|
-
function buildWholeLineUnsetEdit(sourceFile, lineStartPos, afterPos) {
|
|
287
|
-
const text = sourceFile.getFullText();
|
|
288
|
-
let end = afterPos;
|
|
289
|
-
while (end < text.length && text[end] !== "\n")
|
|
290
|
-
end++;
|
|
291
|
-
if (end < text.length)
|
|
292
|
-
end++;
|
|
293
|
-
return { start: lineStartPos, end, text: "" };
|
|
294
|
-
}
|
|
295
|
-
// Inline delete: property shares its line with other content — remove only
|
|
296
|
-
// the property plus its trailing comma+space, or (last on the line, no
|
|
297
|
-
// trailing comma) the preceding comma+space.
|
|
298
|
-
function buildInlineUnsetEdit(text, propStart, afterPos, hasTrailingComma) {
|
|
299
|
-
let start = propStart;
|
|
300
|
-
let end = afterPos;
|
|
301
|
-
if (hasTrailingComma && text[end] === " ")
|
|
302
|
-
end++;
|
|
303
|
-
if (!hasTrailingComma) {
|
|
304
|
-
let precedingStart = propStart;
|
|
305
|
-
while (precedingStart > 0 && text[precedingStart - 1] === " ")
|
|
306
|
-
precedingStart--;
|
|
307
|
-
if (text[precedingStart - 1] === ",")
|
|
308
|
-
start = precedingStart - 1;
|
|
309
|
-
}
|
|
310
|
-
return { start, end, text: "" };
|
|
311
|
-
}
|
|
312
|
-
function buildUnsetEdit(obj, key) {
|
|
313
|
-
const prop = findPropertyByKey(obj, key);
|
|
314
|
-
if (!prop)
|
|
315
|
-
return undefined; // no-op: nothing to remove, unset is idempotent
|
|
316
|
-
const sourceFile = obj.getSourceFile();
|
|
317
|
-
const text = sourceFile.getFullText();
|
|
318
|
-
const propStart = prop.getStart();
|
|
319
|
-
const lineStartPos = lineStart(sourceFile, propStart);
|
|
320
|
-
const beforeOnLine = text.slice(lineStartPos, propStart);
|
|
321
|
-
let afterPos = prop.getEnd();
|
|
322
|
-
const hasTrailingComma = text[afterPos] === ",";
|
|
323
|
-
if (hasTrailingComma)
|
|
324
|
-
afterPos++;
|
|
325
|
-
let probe = afterPos;
|
|
326
|
-
while (probe < text.length && (text[probe] === " " || text[probe] === "\t"))
|
|
327
|
-
probe++;
|
|
328
|
-
const restOfLine = text.slice(probe, lineEnd(sourceFile, probe));
|
|
329
|
-
// Whole-line delete only when the property is alone on its line — else
|
|
330
|
-
// this would eat sibling properties or the enclosing call's `});`.
|
|
331
|
-
const aloneOnLine = beforeOnLine.trim().length === 0 &&
|
|
332
|
-
(restOfLine.trim().length === 0 || restOfLine.trim().startsWith("//"));
|
|
333
|
-
if (aloneOnLine)
|
|
334
|
-
return buildWholeLineUnsetEdit(sourceFile, lineStartPos, afterPos);
|
|
335
|
-
return buildInlineUnsetEdit(text, propStart, afterPos, hasTrailingComma);
|
|
336
|
-
}
|
|
337
|
-
function resolveUpdatableHandlerLiteral(sourceFile, change) {
|
|
338
|
-
const call = findCallForId(sourceFile, change.id);
|
|
339
|
-
if (!call) {
|
|
340
|
-
throw new Error(`updatePattern: no call found for ${describeId(change.id)}`);
|
|
341
|
-
}
|
|
342
|
-
const args = call.getArguments();
|
|
343
|
-
if (args.length !== 1) {
|
|
344
|
-
throw new Error(`updatePattern: ${describeId(change.id)} uses the positional call form; update requires the object form; use replace`);
|
|
345
|
-
}
|
|
346
|
-
const arg0 = args[0];
|
|
347
|
-
if (!arg0) {
|
|
348
|
-
throw new Error(`updatePattern: no call found for ${describeId(change.id)}`);
|
|
349
|
-
}
|
|
350
|
-
const obj = arg0.asKind(SyntaxKind.ObjectLiteralExpression);
|
|
351
|
-
if (!obj) {
|
|
352
|
-
throw new Error(`updatePattern: ${describeId(change.id)} is not an inline object literal; use replace`);
|
|
353
|
-
}
|
|
354
|
-
if (obj.getProperties().some((prop) => prop.isKind(SyntaxKind.SpreadAssignment))) {
|
|
355
|
-
throw new Error("updatePattern: cannot update a handler literal containing a spread; use replace");
|
|
356
|
-
}
|
|
357
|
-
return obj;
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* Apply a `HandlerHeaderUpdate` to the header fields named in `set`/`unset`
|
|
361
|
-
* only, via targeted text edits — `schemaSource`, `handlerBody`, comments,
|
|
362
|
-
* and every unnamed field stay byte-identical (narrower than replacePattern).
|
|
363
|
-
*/
|
|
364
|
-
export function updatePattern(sourceFile, change) {
|
|
365
|
-
const obj = resolveUpdatableHandlerLiteral(sourceFile, change);
|
|
366
|
-
const headerFlags = HEADER_KEY_FLAGS_BY_HANDLER_KIND[change.id.kind];
|
|
367
|
-
const setEntries = Object.entries(change.set).filter(([, v]) => v !== undefined);
|
|
368
|
-
for (const [key] of setEntries) {
|
|
369
|
-
if (!Object.hasOwn(headerFlags, key)) {
|
|
370
|
-
throw new Error(`updatePattern: "${key}" is not a header field of ${change.id.kind}`);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
// Widen to `string`: this is a runtime boundary, re-check even though the
|
|
374
|
-
// static type already excludes "access" from `unset`.
|
|
375
|
-
const unsetKeyList = change.unset ?? [];
|
|
376
|
-
const setKeySet = new Set(setEntries.map(([key]) => key));
|
|
377
|
-
for (const key of unsetKeyList) {
|
|
378
|
-
if (!Object.hasOwn(headerFlags, key)) {
|
|
379
|
-
throw new Error(`updatePattern: "${key}" is not a header field of ${change.id.kind}`);
|
|
380
|
-
}
|
|
381
|
-
if (key === "access") {
|
|
382
|
-
throw new Error("updatePattern: access is required and cannot be unset");
|
|
383
|
-
}
|
|
384
|
-
if (setKeySet.has(key)) {
|
|
385
|
-
throw new Error(`updatePattern: "${key}" is in both set and unset`);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
// Dedupe: two identical `unset` entries would otherwise produce two
|
|
389
|
-
// overlapping deletes, the second eating text past the first's shrink.
|
|
390
|
-
const unsetKeys = new Set(unsetKeyList);
|
|
391
|
-
const originalText = sourceFile.getFullText();
|
|
392
|
-
try {
|
|
393
|
-
// Unsets run first and the set edits are built against the re-parsed
|
|
394
|
-
// result: an append anchor and an inline unset can otherwise share the
|
|
395
|
-
// same comma and overlap.
|
|
396
|
-
applyEditsDescending(sourceFile, [...unsetKeys]
|
|
397
|
-
.map((key) => buildUnsetEdit(obj, key))
|
|
398
|
-
.filter((edit) => edit !== undefined));
|
|
399
|
-
const settable = unsetKeys.size > 0 ? resolveUpdatableHandlerLiteral(sourceFile, change) : obj;
|
|
400
|
-
const inPlaceEdits = [];
|
|
401
|
-
const missingEntries = [];
|
|
402
|
-
for (const [key, value] of setEntries) {
|
|
403
|
-
const edit = buildInPlaceSetEdit(settable, key, value);
|
|
404
|
-
if (edit)
|
|
405
|
-
inPlaceEdits.push(edit);
|
|
406
|
-
else
|
|
407
|
-
missingEntries.push([key, value]);
|
|
408
|
-
}
|
|
409
|
-
applyEditsDescending(sourceFile, [
|
|
410
|
-
...inPlaceEdits,
|
|
411
|
-
...(missingEntries.length > 0 ? [buildAppendEdit(settable, missingEntries)] : []),
|
|
412
|
-
]);
|
|
413
|
-
}
|
|
414
|
-
catch (error) {
|
|
415
|
-
sourceFile.replaceWithText(originalText);
|
|
416
|
-
throw error;
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
// Apply from the highest offset down so an earlier edit's positions,
|
|
420
|
-
// captured against the pre-edit text, stay valid.
|
|
421
|
-
function applyEditsDescending(sourceFile, edits) {
|
|
422
|
-
const sorted = edits.slice().sort((a, b) => b.start - a.start);
|
|
423
|
-
for (let i = 1; i < sorted.length; i++) {
|
|
424
|
-
const previous = sorted[i - 1];
|
|
425
|
-
const current = sorted[i];
|
|
426
|
-
if (previous && current && current.end > previous.start) {
|
|
427
|
-
throw new Error("updatePattern: internal error, text edits overlap");
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
for (const edit of sorted)
|
|
431
|
-
sourceFile.replaceText([edit.start, edit.end], edit.text);
|
|
432
|
-
}
|
|
433
|
-
function isAiStepId(idOrPattern) {
|
|
434
|
-
return (idOrPattern.kind === "ai.generate" ||
|
|
435
|
-
idOrPattern.kind === "ai.extract" ||
|
|
436
|
-
idOrPattern.kind === "ai.classify");
|
|
437
|
-
}
|
|
438
|
-
function aiStepPatchSpan(sourceFile, call) {
|
|
439
|
-
const start = call.getStart();
|
|
440
|
-
let end = call.getEnd();
|
|
441
|
-
const text = sourceFile.getFullText();
|
|
442
|
-
while (end < text.length && (text[end] === " " || text[end] === " "))
|
|
443
|
-
end++;
|
|
444
|
-
if (text[end] === ",")
|
|
445
|
-
end++;
|
|
446
|
-
while (end < text.length && (text[end] === " " || text[end] === " "))
|
|
447
|
-
end++;
|
|
448
|
-
if (end < text.length && text[end] === "\n")
|
|
449
|
-
end++;
|
|
450
|
-
return { start, end };
|
|
451
|
-
}
|
|
452
|
-
function findSetupCallback(sourceFile) {
|
|
453
|
-
for (const stmt of sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {
|
|
454
|
-
if (stmt.getExpression().getText() !== "defineFeature")
|
|
455
|
-
continue;
|
|
456
|
-
const setupArg = stmt.getArguments()[1];
|
|
457
|
-
if (!setupArg)
|
|
458
|
-
continue;
|
|
459
|
-
const arrow = setupArg.asKind(SyntaxKind.ArrowFunction);
|
|
460
|
-
if (!arrow)
|
|
461
|
-
continue;
|
|
462
|
-
return { call: stmt, body: arrow.getBody() };
|
|
463
|
-
}
|
|
464
|
-
return undefined;
|
|
465
|
-
}
|
|
466
|
-
/**
|
|
467
|
-
* Singleton kinds: a feature has at most one of each. The Boot-Validator
|
|
468
|
-
* rejects features that declare two `r.requires(...)` etc. — the patcher
|
|
469
|
-
* asserts the same invariant so a corrupt source file produces an
|
|
470
|
-
* explicit error here, not a silent first-match win.
|
|
471
|
-
*
|
|
472
|
-
* Exported so the pattern-library tests + downstream consumers
|
|
473
|
-
* (Designer, AI-Builder) share one source-of-truth — duplicating this
|
|
474
|
-
* set would let the library's `singleton: true` flags drift silently
|
|
475
|
-
* from the patcher's enforcement.
|
|
476
|
-
*/
|
|
477
|
-
export const SINGLETON_KINDS = new Set([
|
|
478
|
-
"requires",
|
|
479
|
-
"optionalRequires",
|
|
480
|
-
"readsConfig",
|
|
481
|
-
"systemScope",
|
|
482
|
-
"toggleable",
|
|
483
|
-
"describe",
|
|
484
|
-
"uiHints",
|
|
485
|
-
"adoptsBundledLists",
|
|
486
|
-
"config",
|
|
487
|
-
"translations",
|
|
488
|
-
"authClaims",
|
|
489
|
-
// Tree-Actions slot — at-most-one per feature, mirrors the registrar's
|
|
490
|
-
// only-once-guard in define-feature.ts.
|
|
491
|
-
"treeActions",
|
|
492
|
-
]);
|
|
493
|
-
/**
|
|
494
|
-
* Return the CallExpression in the setup callback whose call shape
|
|
495
|
-
* matches the given id. Reads the call arguments structurally — same
|
|
496
|
-
* paths the parser walks, no re-parsing through extractors.ts (would
|
|
497
|
-
* be redundant work).
|
|
498
|
-
*
|
|
499
|
-
* For singleton kinds (requires, toggleable, etc.) the patcher
|
|
500
|
-
* additionally asserts that the file contains AT MOST one matching
|
|
501
|
-
* call. Two calls of the same singleton kind would let the first-match
|
|
502
|
-
* silently win; we'd rather throw so Designer/AI surfacing the corrupt
|
|
503
|
-
* feature can fix it explicitly.
|
|
504
|
-
*/
|
|
505
|
-
function findCallForId(sourceFile, id) {
|
|
506
|
-
if (isAiStepId(id)) {
|
|
507
|
-
return findAiStepCall(sourceFile, id);
|
|
508
|
-
}
|
|
509
|
-
const setup = findSetupCallback(sourceFile);
|
|
510
|
-
if (!setup)
|
|
511
|
-
return undefined;
|
|
512
|
-
const registrarParam = setup.call
|
|
513
|
-
.getArguments()[1]
|
|
514
|
-
?.asKind(SyntaxKind.ArrowFunction)
|
|
515
|
-
?.getParameters()[0]
|
|
516
|
-
?.getName();
|
|
517
|
-
if (!registrarParam)
|
|
518
|
-
return undefined;
|
|
519
|
-
const matches = [];
|
|
520
|
-
for (const call of setup.body.getDescendantsOfKind(SyntaxKind.CallExpression)) {
|
|
521
|
-
const propAccess = call.getExpression().asKind(SyntaxKind.PropertyAccessExpression);
|
|
522
|
-
if (!propAccess)
|
|
523
|
-
continue;
|
|
524
|
-
if (propAccess.getExpression().getText() !== registrarParam)
|
|
525
|
-
continue;
|
|
526
|
-
if (propAccess.getName() !== id.kind)
|
|
527
|
-
continue;
|
|
528
|
-
if (callMatchesId(call, id.kind, id))
|
|
529
|
-
matches.push(call);
|
|
530
|
-
}
|
|
531
|
-
if (SINGLETON_KINDS.has(id.kind) && matches.length > 1) {
|
|
532
|
-
throw new Error(`findCallForId: ${id.kind} is a singleton but ${matches.length} calls were found — feature file is corrupt`);
|
|
533
|
-
}
|
|
534
|
-
return matches[0];
|
|
535
|
-
}
|
|
536
|
-
const AI_STEP_FACTORY = {
|
|
537
|
-
"ai.generate": "aiGenerateStep",
|
|
538
|
-
"ai.extract": "aiExtractStep",
|
|
539
|
-
"ai.classify": "aiClassifyStep",
|
|
540
|
-
};
|
|
541
|
-
function findAiStepCall(sourceFile, id) {
|
|
542
|
-
if (!isAiStepId(id))
|
|
543
|
-
return undefined;
|
|
544
|
-
const factory = AI_STEP_FACTORY[id.kind];
|
|
545
|
-
const matches = [];
|
|
546
|
-
for (const call of sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {
|
|
547
|
-
if (call.getExpression().getText() !== factory)
|
|
548
|
-
continue;
|
|
549
|
-
if (callMatchesId(call, id.kind, id))
|
|
550
|
-
matches.push(call);
|
|
551
|
-
}
|
|
552
|
-
if (matches.length > 1) {
|
|
553
|
-
throw new Error(`findAiStepCall: ambiguous ${id.kind} stepKey=${JSON.stringify("stepKey" in id ? id.stepKey : undefined)} — ${matches.length} matches; disambiguate or include workflowName in PatternId`);
|
|
554
|
-
}
|
|
555
|
-
return matches[0];
|
|
556
|
-
}
|
|
557
|
-
// =============================================================================
|
|
558
|
-
// Format helpers — line boundaries / blank-line collapse
|
|
559
|
-
// (indent / PATTERN_INDENT live in render.ts and are imported above.)
|
|
560
|
-
// =============================================================================
|
|
561
|
-
function lastNonTriviaChild(body) {
|
|
562
|
-
// Block nodes have child[0] = `{`, last = `}`. Find the last
|
|
563
|
-
// SyntaxList element that's an actual statement — that signals
|
|
564
|
-
// whether the body is empty for blank-line decisions.
|
|
565
|
-
if (!body.isKind(SyntaxKind.Block))
|
|
566
|
-
return undefined;
|
|
567
|
-
const statements = body.getStatements();
|
|
568
|
-
return statements[statements.length - 1];
|
|
569
|
-
}
|
|
570
|
-
function lineStart(sourceFile, pos) {
|
|
571
|
-
const text = sourceFile.getFullText();
|
|
572
|
-
let i = pos;
|
|
573
|
-
while (i > 0 && text[i - 1] !== "\n")
|
|
574
|
-
i--;
|
|
575
|
-
return i;
|
|
576
|
-
}
|
|
577
|
-
function lineEnd(sourceFile, pos) {
|
|
578
|
-
const text = sourceFile.getFullText();
|
|
579
|
-
let i = pos;
|
|
580
|
-
while (i < text.length && text[i] !== "\n")
|
|
581
|
-
i++;
|
|
582
|
-
return i;
|
|
583
|
-
}
|
|
584
|
-
function collapsePrecedingBlankLine(sourceFile, startPos) {
|
|
585
|
-
// If the line preceding `startPos` is empty (only whitespace), include
|
|
586
|
-
// it in the deletion range so add → remove leaves a clean file.
|
|
587
|
-
const text = sourceFile.getFullText();
|
|
588
|
-
if (startPos < 2)
|
|
589
|
-
return startPos;
|
|
590
|
-
const i = startPos - 1; // \n at end of previous line
|
|
591
|
-
if (text[i] !== "\n")
|
|
592
|
-
return startPos;
|
|
593
|
-
let j = i - 1;
|
|
594
|
-
while (j >= 0 && text[j] !== "\n" && (text[j] === " " || text[j] === "\t"))
|
|
595
|
-
j--;
|
|
596
|
-
if (j < 0 || text[j] === "\n") {
|
|
597
|
-
// Found an empty (whitespace-only) preceding line — include its
|
|
598
|
-
// newline in the deletion span.
|
|
599
|
-
return j + 1;
|
|
600
|
-
}
|
|
601
|
-
return startPos;
|
|
602
|
-
}
|
|
603
|
-
// Used only in error messages — stringifies kind + identifying fields
|
|
604
|
-
// in a `kind(field=value, ...)` shape for at-a-glance debugging.
|
|
605
|
-
function describeId(id) {
|
|
606
|
-
const fields = Object.entries(id)
|
|
607
|
-
.filter(([key]) => key !== "kind")
|
|
608
|
-
.map(([key, value]) => `${key}=${String(value)}`)
|
|
609
|
-
.join(", ");
|
|
610
|
-
return `${id.kind}(${fields})`;
|
|
611
|
-
}
|