pipework 0.252.0 → 0.253.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/CHANGELOG.md +10 -0
- package/dist/infra/support/handle.d.ts +8 -1
- package/dist/infra/support/handle.d.ts.map +1 -1
- package/dist/infra/support/handle.js +9 -2
- package/dist/infra/support/handle.js.map +1 -1
- package/dist/infra/support/namespace.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/async/jobs/abortable-delay.ts +18 -0
- package/src/async/jobs/claims.ts +52 -0
- package/src/async/jobs/cron.ts +179 -0
- package/src/async/jobs/errors.ts +56 -0
- package/src/async/jobs/exclusion.ts +117 -0
- package/src/async/jobs/execute.ts +219 -0
- package/src/async/jobs/index.ts +10 -0
- package/src/async/jobs/listener.ts +135 -0
- package/src/async/jobs/namespace.ts +20 -0
- package/src/async/jobs/queue-door.ts +44 -0
- package/src/async/jobs/queue.ts +1012 -0
- package/src/async/jobs/run-script.ts +67 -0
- package/src/async/jobs/scheduler.ts +218 -0
- package/src/async/jobs/schedules-table.ts +37 -0
- package/src/async/jobs/serialize-error.ts +48 -0
- package/src/async/jobs/table.ts +191 -0
- package/src/async/pipeline/define.ts +53 -0
- package/src/async/pipeline/errors.ts +35 -0
- package/src/async/pipeline/execute.ts +53 -0
- package/src/async/pipeline/index.ts +13 -0
- package/src/async/pipeline/namespace.ts +12 -0
- package/src/async/pipeline/resume.ts +67 -0
- package/src/async/pipeline/run-steps.ts +98 -0
- package/src/async/pipeline/types.ts +57 -0
- package/src/async/state-machine/define.ts +64 -0
- package/src/async/state-machine/errors.ts +29 -0
- package/src/async/state-machine/index.ts +3 -0
- package/src/async/state-machine/namespace.ts +12 -0
- package/src/async/state-machine/transition.ts +90 -0
- package/src/async/state-machine/types.ts +37 -0
- package/src/async/steps/errors.ts +31 -0
- package/src/async/steps/graph.ts +1214 -0
- package/src/async/steps/hash.ts +40 -0
- package/src/async/steps/index.ts +7 -0
- package/src/async/steps/namespace.ts +7 -0
- package/src/async/steps/table.ts +97 -0
- package/src/async/steps/types.ts +318 -0
- package/src/audit/chain/index.ts +9 -0
- package/src/audit/chain/install.ts +113 -0
- package/src/audit/chain/retire.ts +52 -0
- package/src/audit/chain/verify.ts +257 -0
- package/src/audit/query/cursor.ts +37 -0
- package/src/audit/query/index.ts +9 -0
- package/src/audit/query/query.ts +223 -0
- package/src/audit/schema/audit-record-fields.ts +68 -0
- package/src/audit/schema/audit-record.ts +23 -0
- package/src/auth/auth/audit.ts +31 -0
- package/src/auth/auth/chain.ts +84 -0
- package/src/auth/auth/cookie.ts +136 -0
- package/src/auth/auth/email-links.ts +311 -0
- package/src/auth/auth/guard.ts +128 -0
- package/src/auth/auth/index.ts +18 -0
- package/src/auth/auth/multi-org.ts +337 -0
- package/src/auth/auth/namespace.ts +34 -0
- package/src/auth/auth/parse-expiry.ts +13 -0
- package/src/auth/auth/passwords.ts +110 -0
- package/src/auth/auth/schema.ts +110 -0
- package/src/auth/auth/sessions.ts +565 -0
- package/src/auth/auth/sign-in.ts +156 -0
- package/src/auth/auth/signing-keys.ts +69 -0
- package/src/auth/auth/types.ts +26 -0
- package/src/auth/auth/uuid.ts +10 -0
- package/src/auth/rbac/cache.ts +55 -0
- package/src/auth/rbac/check.ts +30 -0
- package/src/auth/rbac/create.ts +35 -0
- package/src/auth/rbac/index.ts +5 -0
- package/src/auth/rbac/middleware.ts +20 -0
- package/src/auth/rbac/namespace.ts +15 -0
- package/src/auth/rbac/resolve.ts +31 -0
- package/src/auth/rbac/schema.sql +31 -0
- package/src/auth/rbac/seed.ts +67 -0
- package/src/auth/rbac/tables.ts +32 -0
- package/src/auth/rbac/types.ts +65 -0
- package/src/auth/tenant/extract.ts +33 -0
- package/src/auth/tenant/in-tenant.ts +49 -0
- package/src/auth/tenant/index.ts +7 -0
- package/src/auth/tenant/namespace.ts +23 -0
- package/src/auth/tenant/propagate.ts +20 -0
- package/src/auth/tenant/rls.ts +120 -0
- package/src/auth/tenant/scope.ts +33 -0
- package/src/auth/tenant/scoped-db.ts +581 -0
- package/src/auth/tenant/types.ts +14 -0
- package/src/auth/tenant/validate.ts +27 -0
- package/src/cli/commands/add.ts +158 -0
- package/src/cli/commands/alerts.ts +98 -0
- package/src/cli/commands/check.ts +1418 -0
- package/src/cli/commands/codemod.ts +78 -0
- package/src/cli/commands/db.ts +356 -0
- package/src/cli/commands/dev.ts +101 -0
- package/src/cli/commands/generate.ts +75 -0
- package/src/cli/commands/init.ts +36 -0
- package/src/cli/commands/install.ts +28 -0
- package/src/cli/commands/lint.ts +62 -0
- package/src/cli/commands/migrate.ts +132 -0
- package/src/cli/commands/openapi.ts +63 -0
- package/src/cli/commands/remove.ts +72 -0
- package/src/cli/commands/run.ts +50 -0
- package/src/cli/commands/scope.ts +54 -0
- package/src/cli/commands/serve.ts +68 -0
- package/src/cli/commands/shard.ts +31 -0
- package/src/cli/commands/shared/config-pipework-version.ts +28 -0
- package/src/cli/commands/shared/find-config.ts +22 -0
- package/src/cli/commands/shared/load-config.ts +35 -0
- package/src/cli/commands/shared/pnpm-install.ts +95 -0
- package/src/cli/commands/shared/report-removed.ts +8 -0
- package/src/cli/commands/sync.ts +32 -0
- package/src/cli/commands/test.ts +307 -0
- package/src/cli/commands/upgrade.ts +48 -0
- package/src/cli/dev-bootstrap.ts +24 -0
- package/src/cli/errors.ts +10 -0
- package/src/cli/index.ts +303 -0
- package/src/cli/output.ts +17 -0
- package/src/cli/port.ts +15 -0
- package/src/cli/surface-kinds.ts +20 -0
- package/src/client/index.ts +4 -0
- package/src/client/poll.ts +130 -0
- package/src/client/report-fault.ts +119 -0
- package/src/core/config/app-pool.ts +19 -0
- package/src/core/config/aws-env.ts +29 -0
- package/src/core/config/base-dir.ts +24 -0
- package/src/core/config/discover.ts +64 -0
- package/src/core/config/env-resolve.ts +87 -0
- package/src/core/config/env-types.ts +116 -0
- package/src/core/config/env.ts +55 -0
- package/src/core/config/errors.ts +9 -0
- package/src/core/config/import-config.ts +40 -0
- package/src/core/config/index.ts +8 -0
- package/src/core/config/load.ts +417 -0
- package/src/core/config/namespace.ts +14 -0
- package/src/core/config/resolve.ts +195 -0
- package/src/core/config/schema.ts +488 -0
- package/src/core/config/statement-observer.ts +48 -0
- package/src/core/config/ts-inline-hooks.ts +75 -0
- package/src/core/config/ts-register.ts +4 -0
- package/src/core/config/ts-resolve-hooks.ts +101 -0
- package/src/core/errors/base.ts +49 -0
- package/src/core/errors/http.ts +146 -0
- package/src/core/errors/index.ts +2 -0
- package/src/core/errors/namespace.ts +31 -0
- package/src/core/lifecycle/drain.ts +33 -0
- package/src/core/lifecycle/health.ts +72 -0
- package/src/core/lifecycle/index.ts +4 -0
- package/src/core/lifecycle/namespace.ts +7 -0
- package/src/core/lifecycle/startup.ts +102 -0
- package/src/core/lifecycle/types.ts +36 -0
- package/src/core/logging/context.ts +60 -0
- package/src/core/logging/error-chain.ts +68 -0
- package/src/core/logging/index.ts +5 -0
- package/src/core/logging/logger.ts +65 -0
- package/src/core/logging/namespace.ts +16 -0
- package/src/core/logging/proxy.ts +22 -0
- package/src/core/logging/redact-match.ts +24 -0
- package/src/core/logging/types.ts +47 -0
- package/src/core/pipework.ts +566 -0
- package/src/core/runtime/broker.ts +69 -0
- package/src/core/surface/http.ts +133 -0
- package/src/core/surface/index.ts +11 -0
- package/src/core/surface/job-timeout.ts +40 -0
- package/src/core/surface/namespace.ts +13 -0
- package/src/core/surface/script.ts +33 -0
- package/src/core/surface/start.ts +142 -0
- package/src/core/surface/types.ts +225 -0
- package/src/core/surface/validate.ts +88 -0
- package/src/core/surface/worker.ts +528 -0
- package/src/core/validation/connectivity.ts +49 -0
- package/src/core/validation/domain.ts +99 -0
- package/src/core/validation/index.ts +5 -0
- package/src/core/validation/queue-tables.ts +312 -0
- package/src/core/validation/rls-role.ts +138 -0
- package/src/core/validation/startup.ts +51 -0
- package/src/core/validation/surfaces.ts +65 -0
- package/src/core/validation/types.ts +25 -0
- package/src/data/db/advisory-lock.ts +55 -0
- package/src/data/db/aggregates.ts +172 -0
- package/src/data/db/array-elements.ts +111 -0
- package/src/data/db/bulk-set.ts +53 -0
- package/src/data/db/col/index.ts +14 -0
- package/src/data/db/composed.ts +53 -0
- package/src/data/db/db.ts +276 -0
- package/src/data/db/excluded.ts +16 -0
- package/src/data/db/expressions.ts +473 -0
- package/src/data/db/filter.ts +90 -0
- package/src/data/db/function-source.ts +114 -0
- package/src/data/db/identifiers.ts +16 -0
- package/src/data/db/idx/index.ts +9 -0
- package/src/data/db/in-list.ts +49 -0
- package/src/data/db/index.ts +9 -0
- package/src/data/db/insert-split.ts +137 -0
- package/src/data/db/instrumentation.ts +82 -0
- package/src/data/db/maintenance.ts +28 -0
- package/src/data/db/namespace.ts +107 -0
- package/src/data/db/owner-labels.ts +9 -0
- package/src/data/db/pool.ts +187 -0
- package/src/data/db/query-label.ts +13 -0
- package/src/data/db/query-watch.ts +116 -0
- package/src/data/db/raw-client-warning.ts +37 -0
- package/src/data/db/readonly.ts +23 -0
- package/src/data/db/reservation.ts +151 -0
- package/src/data/db/schema-features.ts +14 -0
- package/src/data/db/serializable.ts +83 -0
- package/src/data/db/sql.ts +1 -0
- package/src/data/db/timeouts.ts +76 -0
- package/src/data/db/types.ts +18 -0
- package/src/data/db/unbound.ts +33 -0
- package/src/data/db/values.ts +29 -0
- package/src/data/domain/brand.ts +15 -0
- package/src/data/domain/build-factory.ts +193 -0
- package/src/data/domain/build-schema.ts +161 -0
- package/src/data/domain/build-table.ts +355 -0
- package/src/data/domain/define.ts +239 -0
- package/src/data/domain/external-registry.ts +34 -0
- package/src/data/domain/external.ts +77 -0
- package/src/data/domain/field.ts +279 -0
- package/src/data/domain/index.ts +13 -0
- package/src/data/domain/naming.ts +6 -0
- package/src/data/domain/projections.ts +57 -0
- package/src/data/domain/trace-safe-projection.ts +31 -0
- package/src/data/domain/traits.ts +108 -0
- package/src/data/domain/types.ts +289 -0
- package/src/data/jsonb/composed.ts +18 -0
- package/src/data/jsonb/index.ts +1 -0
- package/src/data/jsonb/namespace.ts +30 -0
- package/src/data/jsonb/query.ts +86 -0
- package/src/data/migrate/append-only-generate.ts +47 -0
- package/src/data/migrate/applied.ts +47 -0
- package/src/data/migrate/apply.ts +309 -0
- package/src/data/migrate/check.ts +119 -0
- package/src/data/migrate/diff.ts +357 -0
- package/src/data/migrate/door-generate.ts +130 -0
- package/src/data/migrate/framework-rls.ts +58 -0
- package/src/data/migrate/generate.ts +201 -0
- package/src/data/migrate/history.ts +215 -0
- package/src/data/migrate/index.ts +9 -0
- package/src/data/migrate/internal-definitions.ts +175 -0
- package/src/data/migrate/post-process.ts +73 -0
- package/src/data/migrate/pragma.ts +73 -0
- package/src/data/migrate/provision-framework.ts +147 -0
- package/src/data/migrate/rls-generate.ts +61 -0
- package/src/data/migrate/run.ts +124 -0
- package/src/data/migrate/safety.ts +167 -0
- package/src/data/migrate/snapshot.ts +368 -0
- package/src/data/migrate/sql-emit.ts +392 -0
- package/src/data/migrate/statements.ts +312 -0
- package/src/data/query/alias.ts +126 -0
- package/src/data/query/batch.ts +8 -0
- package/src/data/query/cache/core/cache.ts +78 -0
- package/src/data/query/cache/core/index.ts +1 -0
- package/src/data/query/cache/core/types.ts +29 -0
- package/src/data/query/cache/readme.md +230 -0
- package/src/data/query/casing.ts +76 -0
- package/src/data/query/collation.ts +11 -0
- package/src/data/query/column-builder.ts +370 -0
- package/src/data/query/column.ts +150 -0
- package/src/data/query/entity.ts +42 -0
- package/src/data/query/errors.ts +33 -0
- package/src/data/query/index.ts +14 -0
- package/src/data/query/logger.ts +47 -0
- package/src/data/query/operations.ts +45 -0
- package/src/data/query/pg-core/alias.ts +12 -0
- package/src/data/query/pg-core/checks.ts +32 -0
- package/src/data/query/pg-core/columns/all.ts +71 -0
- package/src/data/query/pg-core/columns/bigint.ts +110 -0
- package/src/data/query/pg-core/columns/bigserial.ts +128 -0
- package/src/data/query/pg-core/columns/boolean.ts +43 -0
- package/src/data/query/pg-core/columns/char.ts +85 -0
- package/src/data/query/pg-core/columns/cidr.ts +43 -0
- package/src/data/query/pg-core/columns/common.ts +366 -0
- package/src/data/query/pg-core/columns/custom.ts +232 -0
- package/src/data/query/pg-core/columns/date.common.ts +15 -0
- package/src/data/query/pg-core/columns/date.ts +112 -0
- package/src/data/query/pg-core/columns/double-precision.ts +55 -0
- package/src/data/query/pg-core/columns/enum.ts +201 -0
- package/src/data/query/pg-core/columns/index.ts +35 -0
- package/src/data/query/pg-core/columns/inet.ts +43 -0
- package/src/data/query/pg-core/columns/int.common.ts +57 -0
- package/src/data/query/pg-core/columns/integer.ts +53 -0
- package/src/data/query/pg-core/columns/interval.ts +83 -0
- package/src/data/query/pg-core/columns/json.ts +58 -0
- package/src/data/query/pg-core/columns/jsonb.ts +56 -0
- package/src/data/query/pg-core/columns/line.ts +117 -0
- package/src/data/query/pg-core/columns/macaddr.ts +43 -0
- package/src/data/query/pg-core/columns/macaddr8.ts +43 -0
- package/src/data/query/pg-core/columns/numeric.ts +227 -0
- package/src/data/query/pg-core/columns/point.ts +127 -0
- package/src/data/query/pg-core/columns/postgis_extension/geometry.ts +119 -0
- package/src/data/query/pg-core/columns/postgis_extension/utils.ts +47 -0
- package/src/data/query/pg-core/columns/real.ts +58 -0
- package/src/data/query/pg-core/columns/serial.ts +55 -0
- package/src/data/query/pg-core/columns/smallint.ts +53 -0
- package/src/data/query/pg-core/columns/smallserial.ts +60 -0
- package/src/data/query/pg-core/columns/text.ts +67 -0
- package/src/data/query/pg-core/columns/time.ts +72 -0
- package/src/data/query/pg-core/columns/timestamp.ts +163 -0
- package/src/data/query/pg-core/columns/uuid.ts +51 -0
- package/src/data/query/pg-core/columns/varchar.ts +89 -0
- package/src/data/query/pg-core/columns/vector_extension/bit.ts +68 -0
- package/src/data/query/pg-core/columns/vector_extension/halfvec.ts +80 -0
- package/src/data/query/pg-core/columns/vector_extension/sparsevec.ts +67 -0
- package/src/data/query/pg-core/columns/vector_extension/vector.ts +80 -0
- package/src/data/query/pg-core/db.ts +674 -0
- package/src/data/query/pg-core/dialect.ts +1404 -0
- package/src/data/query/pg-core/expressions.ts +25 -0
- package/src/data/query/pg-core/foreign-keys.ts +130 -0
- package/src/data/query/pg-core/index.ts +21 -0
- package/src/data/query/pg-core/indexes.ts +276 -0
- package/src/data/query/pg-core/policies.ts +56 -0
- package/src/data/query/pg-core/primary-keys.ts +62 -0
- package/src/data/query/pg-core/query-builders/count.ts +86 -0
- package/src/data/query/pg-core/query-builders/delete.ts +293 -0
- package/src/data/query/pg-core/query-builders/index.ts +7 -0
- package/src/data/query/pg-core/query-builders/insert.ts +452 -0
- package/src/data/query/pg-core/query-builders/query-builder.ts +123 -0
- package/src/data/query/pg-core/query-builders/query.ts +157 -0
- package/src/data/query/pg-core/query-builders/raw.ts +49 -0
- package/src/data/query/pg-core/query-builders/refresh-materialized-view.ts +108 -0
- package/src/data/query/pg-core/query-builders/select.ts +1346 -0
- package/src/data/query/pg-core/query-builders/select.types.ts +437 -0
- package/src/data/query/pg-core/query-builders/update.ts +626 -0
- package/src/data/query/pg-core/roles.ts +41 -0
- package/src/data/query/pg-core/schema.ts +72 -0
- package/src/data/query/pg-core/sequence.ts +41 -0
- package/src/data/query/pg-core/session.ts +292 -0
- package/src/data/query/pg-core/subquery.ts +46 -0
- package/src/data/query/pg-core/table.ts +252 -0
- package/src/data/query/pg-core/unique-constraint.ts +73 -0
- package/src/data/query/pg-core/utils/array.ts +95 -0
- package/src/data/query/pg-core/utils/index.ts +1 -0
- package/src/data/query/pg-core/utils.ts +104 -0
- package/src/data/query/pg-core/view-base.ts +14 -0
- package/src/data/query/pg-core/view-common.ts +1 -0
- package/src/data/query/pg-core/view.ts +435 -0
- package/src/data/query/pg-core/with-builder.ts +41 -0
- package/src/data/query/postgres-js/README.md +46 -0
- package/src/data/query/postgres-js/array-parser.ts +45 -0
- package/src/data/query/postgres-js/driver-error-boundary.ts +149 -0
- package/src/data/query/postgres-js/driver.ts +163 -0
- package/src/data/query/postgres-js/index.ts +2 -0
- package/src/data/query/postgres-js/session.ts +234 -0
- package/src/data/query/primary-key.ts +11 -0
- package/src/data/query/query-builders/query-builder.ts +19 -0
- package/src/data/query/query-builders/select.types.ts +175 -0
- package/src/data/query/query-promise.ts +35 -0
- package/src/data/query/relations.ts +725 -0
- package/src/data/query/runnable-query.ts +12 -0
- package/src/data/query/selection-proxy.ts +121 -0
- package/src/data/query/session.ts +8 -0
- package/src/data/query/sql/expressions/conditions.ts +741 -0
- package/src/data/query/sql/expressions/index.ts +2 -0
- package/src/data/query/sql/expressions/select.ts +45 -0
- package/src/data/query/sql/functions/aggregate.ts +129 -0
- package/src/data/query/sql/functions/index.ts +2 -0
- package/src/data/query/sql/functions/vector.ts +178 -0
- package/src/data/query/sql/index.ts +3 -0
- package/src/data/query/sql/sql.ts +794 -0
- package/src/data/query/subquery.ts +53 -0
- package/src/data/query/table.ts +208 -0
- package/src/data/query/table.utils.ts +2 -0
- package/src/data/query/tracing-utils.ts +3 -0
- package/src/data/query/tracing.ts +11 -0
- package/src/data/query/utils.ts +357 -0
- package/src/data/query/version.ts +4 -0
- package/src/data/query/view-common.ts +1 -0
- package/src/data/schema/branded.ts +13 -0
- package/src/data/schema/generated/coerce.ts +5 -0
- package/src/data/schema/generated/combinator.ts +6 -0
- package/src/data/schema/generated/encoding.ts +5 -0
- package/src/data/schema/generated/error.ts +6 -0
- package/src/data/schema/generated/format.ts +5 -0
- package/src/data/schema/generated/type-constructor.ts +10 -0
- package/src/data/schema/generated/type.ts +6 -0
- package/src/data/schema/index.ts +6 -0
- package/src/data/schema/json-schema.ts +33 -0
- package/src/data/schema/namespace.ts +55 -0
- package/src/data/schema/parse.ts +39 -0
- package/src/data/schema/types.ts +39 -0
- package/src/data/temporal/append-only.ts +134 -0
- package/src/data/temporal/close.ts +27 -0
- package/src/data/temporal/columns.ts +10 -0
- package/src/data/temporal/definition-queries.ts +70 -0
- package/src/data/temporal/errors.ts +10 -0
- package/src/data/temporal/get-current.ts +22 -0
- package/src/data/temporal/index.ts +9 -0
- package/src/data/temporal/namespace.ts +36 -0
- package/src/data/temporal/query.ts +25 -0
- package/src/data/temporal/resolve.ts +17 -0
- package/src/data/temporal/revise.ts +67 -0
- package/src/data/temporal/types.ts +22 -0
- package/src/data/valve/artifact.ts +33 -0
- package/src/data/valve/contract-diff.ts +21 -0
- package/src/data/valve/cross.ts +57 -0
- package/src/data/valve/crossing-ledger.ts +50 -0
- package/src/data/valve/decision.ts +44 -0
- package/src/data/valve/durable-crossing.ts +52 -0
- package/src/data/valve/execute-crossing.ts +77 -0
- package/src/data/valve/faucet.ts +56 -0
- package/src/data/valve/gate.ts +114 -0
- package/src/data/valve/graph.ts +77 -0
- package/src/data/valve/index.ts +53 -0
- package/src/data/valve/namespace.ts +57 -0
- package/src/data/valve/registry.ts +50 -0
- package/src/data/valve/schema/valve-crossing-fields.ts +23 -0
- package/src/data/valve/schema/valve-crossing.ts +9 -0
- package/src/data/valve/supply.ts +154 -0
- package/src/data/valve/types.ts +143 -0
- package/src/data/vector/columns.ts +27 -0
- package/src/data/vector/index.ts +4 -0
- package/src/data/vector/namespace.ts +33 -0
- package/src/data/vector/query.ts +85 -0
- package/src/data/vector/validate.ts +16 -0
- package/src/data/write/audit/actor.ts +15 -0
- package/src/data/write/audit/audit-columns.ts +18 -0
- package/src/data/write/audit/audit-select.ts +111 -0
- package/src/data/write/audit/bound-transaction.ts +14 -0
- package/src/data/write/audit/cte-compile.ts +32 -0
- package/src/data/write/audit/decode-returning.ts +47 -0
- package/src/data/write/audit/final-select.ts +43 -0
- package/src/data/write/audit/infra-audit.ts +36 -0
- package/src/data/write/audit/primary-key.ts +65 -0
- package/src/data/write/audit/projection.ts +41 -0
- package/src/data/write/audit/read-touches.ts +86 -0
- package/src/data/write/audit/touch-match.ts +78 -0
- package/src/data/write/audit/verb-delete.ts +62 -0
- package/src/data/write/audit/verb-insert.ts +36 -0
- package/src/data/write/audit/verb-select.ts +47 -0
- package/src/data/write/audit/verb-update.ts +60 -0
- package/src/data/write/audit/verb-upsert.ts +104 -0
- package/src/data/write/conflict.ts +43 -0
- package/src/data/write/delete.ts +38 -0
- package/src/data/write/execute.ts +243 -0
- package/src/data/write/index.ts +11 -0
- package/src/data/write/insert.ts +63 -0
- package/src/data/write/state.ts +43 -0
- package/src/data/write/update.ts +54 -0
- package/src/data/write/upsert.ts +58 -0
- package/src/data/write/values.ts +19 -0
- package/src/index.ts +230 -0
- package/src/infra/access-links/code.ts +70 -0
- package/src/infra/access-links/handle.ts +892 -0
- package/src/infra/access-links/index.ts +9 -0
- package/src/infra/access-links/namespace.ts +30 -0
- package/src/infra/access-links/person-check.ts +177 -0
- package/src/infra/access-links/schema.ts +71 -0
- package/src/infra/alerts/async-sources.ts +231 -0
- package/src/infra/alerts/audit.ts +36 -0
- package/src/infra/alerts/beat.ts +123 -0
- package/src/infra/alerts/client-faults.ts +111 -0
- package/src/infra/alerts/faults.ts +156 -0
- package/src/infra/alerts/handle.ts +778 -0
- package/src/infra/alerts/http.ts +192 -0
- package/src/infra/alerts/index.ts +12 -0
- package/src/infra/alerts/infra-sources.ts +180 -0
- package/src/infra/alerts/namespace.ts +81 -0
- package/src/infra/alerts/redact.ts +21 -0
- package/src/infra/alerts/request-faults.ts +41 -0
- package/src/infra/alerts/schema.ts +124 -0
- package/src/infra/alerts/sinks.ts +125 -0
- package/src/infra/alerts/source-options.ts +26 -0
- package/src/infra/alerts/sources.ts +503 -0
- package/src/infra/alerts/subsystem-sources.ts +137 -0
- package/src/infra/audit/emit.ts +87 -0
- package/src/infra/audit/index.ts +2 -0
- package/src/infra/audit/namespace.ts +22 -0
- package/src/infra/audit/schema.sql +35 -0
- package/src/infra/audit/types.ts +18 -0
- package/src/infra/aws/credentials.ts +147 -0
- package/src/infra/aws/sigv4.ts +140 -0
- package/src/infra/cache/create.ts +58 -0
- package/src/infra/cache/entry.ts +81 -0
- package/src/infra/cache/index.ts +4 -0
- package/src/infra/cache/namespace.ts +10 -0
- package/src/infra/cache/tenant.ts +93 -0
- package/src/infra/cache/types.ts +24 -0
- package/src/infra/crawl/audit.ts +35 -0
- package/src/infra/crawl/errors.ts +25 -0
- package/src/infra/crawl/handle.ts +693 -0
- package/src/infra/crawl/index.ts +9 -0
- package/src/infra/crawl/links.ts +160 -0
- package/src/infra/crawl/namespace.ts +36 -0
- package/src/infra/crawl/robots.ts +100 -0
- package/src/infra/crawl/schema.ts +89 -0
- package/src/infra/credit-line/handle.ts +883 -0
- package/src/infra/credit-line/index.ts +6 -0
- package/src/infra/credit-line/namespace.ts +7 -0
- package/src/infra/credit-line/schema.ts +96 -0
- package/src/infra/credits/handle.ts +706 -0
- package/src/infra/credits/index.ts +5 -0
- package/src/infra/credits/namespace.ts +7 -0
- package/src/infra/credits/schema.ts +83 -0
- package/src/infra/email/audit.ts +36 -0
- package/src/infra/email/inbound.ts +622 -0
- package/src/infra/email/index.ts +11 -0
- package/src/infra/email/mail.ts +517 -0
- package/src/infra/email/mime.ts +447 -0
- package/src/infra/email/namespace.ts +22 -0
- package/src/infra/email/providers.ts +111 -0
- package/src/infra/email/schema.ts +96 -0
- package/src/infra/email/sns.ts +200 -0
- package/src/infra/email/unsubscribe.ts +44 -0
- package/src/infra/fetch/address.ts +88 -0
- package/src/infra/fetch/connect-retry.ts +87 -0
- package/src/infra/fetch/handle.ts +329 -0
- package/src/infra/fetch/index.ts +7 -0
- package/src/infra/fetch/namespace.ts +70 -0
- package/src/infra/idempotency/index.ts +3 -0
- package/src/infra/idempotency/middleware.ts +87 -0
- package/src/infra/idempotency/store.ts +92 -0
- package/src/infra/idempotency/types.ts +30 -0
- package/src/infra/join-requests/handle.ts +312 -0
- package/src/infra/join-requests/index.ts +2 -0
- package/src/infra/join-requests/namespace.ts +7 -0
- package/src/infra/join-requests/schema.ts +33 -0
- package/src/infra/outbox/core.ts +165 -0
- package/src/infra/quota/errors.ts +32 -0
- package/src/infra/quota/handle.ts +215 -0
- package/src/infra/quota/index.ts +5 -0
- package/src/infra/quota/namespace.ts +7 -0
- package/src/infra/quota/schema.ts +15 -0
- package/src/infra/storage/backend.ts +34 -0
- package/src/infra/storage/handle.ts +513 -0
- package/src/infra/storage/index.ts +9 -0
- package/src/infra/storage/local.ts +104 -0
- package/src/infra/storage/namespace.ts +13 -0
- package/src/infra/storage/s3.ts +257 -0
- package/src/infra/storage/schema.ts +24 -0
- package/src/infra/support/handle.ts +869 -0
- package/src/infra/support/http.ts +229 -0
- package/src/infra/support/index.ts +7 -0
- package/src/infra/support/namespace.ts +12 -0
- package/src/infra/support/schema.ts +96 -0
- package/src/infra/webhook/inbound.ts +45 -0
- package/src/infra/webhook/index.ts +5 -0
- package/src/infra/webhook/namespace.ts +24 -0
- package/src/infra/webhook/outbound.ts +315 -0
- package/src/infra/webhook/sign.ts +32 -0
- package/src/infra/webhook/verify.ts +82 -0
- package/src/invariants/assert.ts +26 -0
- package/src/invariants/index.ts +1 -0
- package/src/lint/config.ts +56 -0
- package/src/lint/doctrine.ts +163 -0
- package/src/lint/include.ts +97 -0
- package/src/lint/index.ts +3 -0
- package/src/lint/preset.ts +10 -0
- package/src/lint/resolver.ts +218 -0
- package/src/lint/rules/no-reexports.ts +46 -0
- package/src/request/behavior/audited.ts +85 -0
- package/src/request/behavior/cached.ts +62 -0
- package/src/request/behavior/compose.ts +28 -0
- package/src/request/behavior/index.ts +5 -0
- package/src/request/behavior/namespace.ts +16 -0
- package/src/request/behavior/types.ts +26 -0
- package/src/request/behavior/versioned.ts +54 -0
- package/src/request/context/create.ts +103 -0
- package/src/request/context/guard.ts +49 -0
- package/src/request/context/index.ts +4 -0
- package/src/request/context/run-in-transaction.ts +200 -0
- package/src/request/context/store.ts +28 -0
- package/src/request/context/types.ts +50 -0
- package/src/request/di/builder.ts +535 -0
- package/src/request/di/index.ts +8 -0
- package/src/request/di/resolve.ts +271 -0
- package/src/request/di/types.ts +262 -0
- package/src/request/fitting/namespace.ts +7 -0
- package/src/request/fixture/batch.ts +71 -0
- package/src/request/fixture/builder.ts +26 -0
- package/src/request/fixture/errors.ts +10 -0
- package/src/request/fixture/index.ts +8 -0
- package/src/request/fixture/namespace.ts +23 -0
- package/src/request/fixture/paginate.ts +44 -0
- package/src/request/fixture/to-handlers.ts +260 -0
- package/src/request/fixture/types.ts +79 -0
- package/src/request/flow/act-as.ts +78 -0
- package/src/request/flow/namespace.ts +17 -0
- package/src/request/http/error-step.ts +42 -0
- package/src/request/http/file.ts +141 -0
- package/src/request/http/index.ts +4 -0
- package/src/request/http/middleware.ts +141 -0
- package/src/request/http/namespace.ts +5 -0
- package/src/request/http/rate-limit-classes.ts +170 -0
- package/src/request/http/response.ts +82 -0
- package/src/request/http/server.ts +916 -0
- package/src/request/http/sniff.ts +261 -0
- package/src/request/http/types.ts +250 -0
- package/src/request/http/upload.ts +284 -0
- package/src/request/internal/text.ts +6 -0
- package/src/request/openapi/generate.ts +205 -0
- package/src/request/openapi/index.ts +2 -0
- package/src/request/openapi/namespace.ts +7 -0
- package/src/test/auth.ts +13 -0
- package/src/test/auto-setup.ts +45 -0
- package/src/test/context.ts +91 -0
- package/src/test/crawl-fixture.ts +157 -0
- package/src/test/discover-fork.ts +17 -0
- package/src/test/fingerprint.ts +135 -0
- package/src/test/globals.d.ts +7 -0
- package/src/test/index.ts +19 -0
- package/src/test/namespace.ts +87 -0
- package/src/test/plugin.ts +189 -0
- package/src/test/progress.ts +185 -0
- package/src/test/reap-after-run.ts +28 -0
- package/src/test/reap.ts +286 -0
- package/src/test/reset.ts +253 -0
- package/src/test/savepoints.ts +172 -0
- package/src/test/setup.ts +1422 -0
- package/src/test/system-channel.ts +50 -0
- package/src/test/vitest-plugin.ts +142 -0
- package/src/test/vitest-workspace.ts +507 -0
- package/src/test/vitest.ts +333 -0
- package/src/test/watch.ts +105 -0
- package/src/trace/capture/bounded-serializer.ts +146 -0
- package/src/trace/cardinality/analyze.ts +173 -0
- package/src/trace/cardinality/branch-context.ts +214 -0
- package/src/trace/cardinality/check.ts +33 -0
- package/src/trace/cardinality/classify-edge.ts +64 -0
- package/src/trace/cardinality/structural-max.ts +107 -0
- package/src/trace/check/coverage-check.ts +188 -0
- package/src/trace/check/flow-check.ts +103 -0
- package/src/trace/check/flow-step-site.ts +234 -0
- package/src/trace/check/io-pattern.ts +116 -0
- package/src/trace/codemod/add-cardinality.ts +152 -0
- package/src/trace/codemod/run.ts +80 -0
- package/src/trace/entry/child-trace.ts +21 -0
- package/src/trace/entry/close-trace.ts +87 -0
- package/src/trace/entry/finalize-trace.ts +28 -0
- package/src/trace/entry/open-trace.ts +138 -0
- package/src/trace/entry/parent-trace.ts +20 -0
- package/src/trace/entry/parse-traceparent.ts +39 -0
- package/src/trace/entry/process-start.ts +38 -0
- package/src/trace/entry/trace-context.ts +26 -0
- package/src/trace/entry/tracing-enabled.ts +10 -0
- package/src/trace/external/record.ts +195 -0
- package/src/trace/external/report.ts +66 -0
- package/src/trace/namespace.ts +19 -0
- package/src/trace/partition/day.ts +47 -0
- package/src/trace/partition/index.ts +14 -0
- package/src/trace/partition/partition-name.ts +23 -0
- package/src/trace/partition/plan.ts +82 -0
- package/src/trace/partition/schedule.ts +26 -0
- package/src/trace/partition/startup-hook.ts +39 -0
- package/src/trace/partition/sync.ts +154 -0
- package/src/trace/partition/tables.ts +53 -0
- package/src/trace/read/tree.ts +83 -0
- package/src/trace/retain/copy-on-error.ts +76 -0
- package/src/trace/runtime/expire-stale-traces.ts +54 -0
- package/src/trace/runtime/flow-step.ts +147 -0
- package/src/trace/runtime/flush-steps.ts +31 -0
- package/src/trace/runtime/pending-writes.ts +54 -0
- package/src/trace/runtime/step-buffer.ts +298 -0
- package/src/trace/runtime/step-error.ts +21 -0
- package/src/trace/runtime/step-meta.ts +55 -0
- package/src/trace/runtime/thenable.ts +12 -0
- package/src/trace/runtime/truncate-trace.ts +62 -0
- package/src/trace/schema/trace-fields.ts +52 -0
- package/src/trace/schema/trace-retained.ts +22 -0
- package/src/trace/schema/trace-step-fields.ts +44 -0
- package/src/trace/schema/trace-step-retained.ts +25 -0
- package/src/trace/schema/trace-step.ts +18 -0
- package/src/trace/schema/trace.ts +12 -0
- package/src/trace/transformer/apply.ts +79 -0
- package/src/trace/transformer/build-meta-literal.ts +30 -0
- package/src/trace/transformer/find-flow-step-sites.ts +85 -0
- package/src/trace/transformer/inject-flow-step-import.ts +39 -0
- package/src/trace/transformer/transform-error.ts +14 -0
- package/src/trace/transformer/transform-flow-steps.ts +123 -0
- package/src/trace/transformer/wrap-function-declaration.ts +62 -0
- package/src/trace/transformer/wrap-variable-declaration.ts +67 -0
- package/src/workspace/affected.ts +110 -0
- package/src/workspace/changed-files.ts +163 -0
- package/src/workspace/check-deps.ts +213 -0
- package/src/workspace/checksum.ts +20 -0
- package/src/workspace/dependency-graph.ts +67 -0
- package/src/workspace/detect-pipework-copies.ts +93 -0
- package/src/workspace/discover.ts +206 -0
- package/src/workspace/generate.ts +401 -0
- package/src/workspace/index.ts +7 -0
- package/src/workspace/module-imports-pipework.ts +39 -0
- package/src/workspace/module-package-name.ts +12 -0
- package/src/workspace/scrub-git-env.ts +23 -0
- package/src/workspace/source-paths.ts +36 -0
- package/src/workspace/sync.ts +182 -0
- package/dist/REFERENCE.md +0 -1477
- package/dist/infra/access-links/rate-limit.d.ts +0 -10
- package/dist/infra/access-links/rate-limit.d.ts.map +0 -1
- package/dist/infra/access-links/rate-limit.js +0 -28
- package/dist/infra/access-links/rate-limit.js.map +0 -1
- package/dist/infra/email/sigv4.d.ts +0 -24
- package/dist/infra/email/sigv4.d.ts.map +0 -1
- package/dist/infra/email/sigv4.js +0 -55
- package/dist/infra/email/sigv4.js.map +0 -1
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// Tier-2 coverage check (Q9): every I/O call site is inside a `@flow_step`,
|
|
2
|
+
// and a flow_step performs at most one I/O — at most one write, in particular.
|
|
3
|
+
// Without this, the trace is gap-prone by construction: an unannotated read or
|
|
4
|
+
// write goes silently untraced and the build doesn't notice.
|
|
5
|
+
//
|
|
6
|
+
// Ships as warning (Phase 6f): violations are surfaced but do not fail
|
|
7
|
+
// `pipework check`. Once the consumer corpus has been migrated, Phase 7a
|
|
8
|
+
// flips it to an error.
|
|
9
|
+
//
|
|
10
|
+
// Two rules:
|
|
11
|
+
// - flow/io-outside-flow-step — an I/O call appears outside any annotated
|
|
12
|
+
// flow_step function. The runtime can't open a `trace_step` for it.
|
|
13
|
+
// - flow/multi-io-per-flow-step — a flow_step body contains more than one
|
|
14
|
+
// I/O call. Split it so each I/O is its own step. The stricter variant,
|
|
15
|
+
// more than one *write* in the same step, is reported as
|
|
16
|
+
// flow/multi-write-per-flow-step — surfaces the Q8 one-write-per-step
|
|
17
|
+
// rule with its own diagnostic.
|
|
18
|
+
//
|
|
19
|
+
// Lexical: I/O inside a nested closure inside a flow_step body still counts
|
|
20
|
+
// as "inside the flow_step" — otherwise writes hide inside callbacks. The
|
|
21
|
+
// cardinality analyzer's "don't follow nested closures" convention is the
|
|
22
|
+
// opposite default, by design (Q1 vs Q9).
|
|
23
|
+
|
|
24
|
+
import { readFileSync, existsSync } from 'node:fs'
|
|
25
|
+
import { join } from 'node:path'
|
|
26
|
+
import { parse } from '@typescript-eslint/parser'
|
|
27
|
+
import { collectFlowStepSites, isNode, type AstNode, type FlowStepSite } from './flow-step-site.js'
|
|
28
|
+
import { classifyIo, type IoKind } from './io-pattern.js'
|
|
29
|
+
|
|
30
|
+
export interface CoverageViolation {
|
|
31
|
+
readonly rule: string
|
|
32
|
+
readonly file: string
|
|
33
|
+
readonly line: number
|
|
34
|
+
readonly message: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface CoverageCheckResult {
|
|
38
|
+
readonly violations: readonly CoverageViolation[]
|
|
39
|
+
readonly scanned: number
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface IoSite {
|
|
43
|
+
readonly kind: IoKind
|
|
44
|
+
/** 1-based line. */
|
|
45
|
+
readonly line: number
|
|
46
|
+
/** Character offset of the call expression in the file (for in-range checks). */
|
|
47
|
+
readonly start: number
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Tier-2 coverage check across `sourceFiles` (paths relative to `cwd`).
|
|
52
|
+
*
|
|
53
|
+
* `extras` extends the stock pipework I/O registry with consumer-declared
|
|
54
|
+
* patterns from `config.trace.io`. Defaults to empty — the stock registry
|
|
55
|
+
* (`pipe.*` writes, `pipe(...)`-chain reads) is always live.
|
|
56
|
+
*/
|
|
57
|
+
export function checkCoverage(
|
|
58
|
+
cwd: string,
|
|
59
|
+
sourceFiles: readonly string[],
|
|
60
|
+
extras: Readonly<Record<string, IoKind>> = {},
|
|
61
|
+
): CoverageCheckResult {
|
|
62
|
+
const violations: CoverageViolation[] = []
|
|
63
|
+
let scanned = 0
|
|
64
|
+
|
|
65
|
+
for (const file of sourceFiles) {
|
|
66
|
+
const abs = join(cwd, file)
|
|
67
|
+
if (!existsSync(abs)) continue
|
|
68
|
+
|
|
69
|
+
let program: AstNode | null = null
|
|
70
|
+
let sites: readonly FlowStepSite[] = []
|
|
71
|
+
try {
|
|
72
|
+
// Read the file once — #322: it was being read (and parsed) twice here.
|
|
73
|
+
const source = readFileSync(abs, 'utf-8')
|
|
74
|
+
program = parseProgram(source, file)
|
|
75
|
+
sites = collectFlowStepSites(source, file)
|
|
76
|
+
} catch {
|
|
77
|
+
// Unparseable — leave syntax errors to the type checker.
|
|
78
|
+
continue
|
|
79
|
+
}
|
|
80
|
+
scanned++
|
|
81
|
+
|
|
82
|
+
const ioSites = collectIoSites(program, extras)
|
|
83
|
+
const flowStepRanges = collectFlowStepRanges(sites)
|
|
84
|
+
|
|
85
|
+
for (const io of ioSites) {
|
|
86
|
+
const enclosing = flowStepRanges.find(r => io.start >= r.bodyStart && io.start < r.bodyEnd)
|
|
87
|
+
if (enclosing === undefined) {
|
|
88
|
+
violations.push({
|
|
89
|
+
rule: 'flow/io-outside-flow-step',
|
|
90
|
+
file,
|
|
91
|
+
line: io.line,
|
|
92
|
+
message:
|
|
93
|
+
`I/O ${io.kind} is outside any @flow_step. Wrap it in a standalone function and ` +
|
|
94
|
+
`annotate that function with @flow_step so the runtime can open a trace_step for it.`,
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
for (const range of flowStepRanges) {
|
|
100
|
+
const inside = ioSites.filter(s => s.start >= range.bodyStart && s.start < range.bodyEnd)
|
|
101
|
+
if (inside.length <= 1) continue
|
|
102
|
+
|
|
103
|
+
const writes = inside.filter(s => s.kind === 'write')
|
|
104
|
+
if (writes.length > 1) {
|
|
105
|
+
violations.push({
|
|
106
|
+
rule: 'flow/multi-write-per-flow-step',
|
|
107
|
+
file,
|
|
108
|
+
line: range.line,
|
|
109
|
+
message:
|
|
110
|
+
`@flow_step "${range.name}" performs ${String(writes.length)} writes. A flow_step ` +
|
|
111
|
+
`may perform at most one write (Q8). Split each write into its own flow_step.`,
|
|
112
|
+
})
|
|
113
|
+
continue
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
violations.push({
|
|
117
|
+
rule: 'flow/multi-io-per-flow-step',
|
|
118
|
+
file,
|
|
119
|
+
line: range.line,
|
|
120
|
+
message:
|
|
121
|
+
`@flow_step "${range.name}" performs ${String(inside.length)} I/O calls. A flow_step ` +
|
|
122
|
+
`may perform at most one I/O call. Split each call into its own flow_step.`,
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return { violations, scanned }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
interface FlowStepRange {
|
|
131
|
+
readonly name: string
|
|
132
|
+
readonly line: number
|
|
133
|
+
readonly bodyStart: number
|
|
134
|
+
readonly bodyEnd: number
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function collectFlowStepRanges(sites: readonly FlowStepSite[]): FlowStepRange[] {
|
|
138
|
+
const ranges: FlowStepRange[] = []
|
|
139
|
+
for (const site of sites) {
|
|
140
|
+
const body = site.subject.body
|
|
141
|
+
if (body === null) continue
|
|
142
|
+
ranges.push({
|
|
143
|
+
name: site.subject.name,
|
|
144
|
+
line: site.subject.line,
|
|
145
|
+
bodyStart: body.range[0],
|
|
146
|
+
bodyEnd: body.range[1],
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
return ranges
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function collectIoSites(program: AstNode, extras: Readonly<Record<string, IoKind>>): IoSite[] {
|
|
153
|
+
const out: IoSite[] = []
|
|
154
|
+
walk(program, node => {
|
|
155
|
+
if (node.type !== 'CallExpression') return
|
|
156
|
+
const kind = classifyIo(node, extras)
|
|
157
|
+
if (kind === null) return
|
|
158
|
+
out.push({ kind, line: node.loc.start.line, start: node.range[0] })
|
|
159
|
+
})
|
|
160
|
+
return out
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const SKIP_KEYS = new Set(['loc', 'range', 'parent'])
|
|
164
|
+
|
|
165
|
+
function walk(node: AstNode, visit: (n: AstNode) => void): void {
|
|
166
|
+
visit(node)
|
|
167
|
+
for (const key of Object.keys(node)) {
|
|
168
|
+
if (SKIP_KEYS.has(key)) continue
|
|
169
|
+
const value = node[key]
|
|
170
|
+
if (Array.isArray(value)) {
|
|
171
|
+
for (const item of value) {
|
|
172
|
+
if (isNode(item)) walk(item, visit)
|
|
173
|
+
}
|
|
174
|
+
} else if (isNode(value)) {
|
|
175
|
+
walk(value, visit)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function parseProgram(code: string, fileName: string): AstNode {
|
|
181
|
+
return parse(code, {
|
|
182
|
+
...(fileName.endsWith('.tsx') ? { jsx: true } : {}),
|
|
183
|
+
range: true,
|
|
184
|
+
loc: true,
|
|
185
|
+
comment: true,
|
|
186
|
+
sourceType: 'module',
|
|
187
|
+
}) as unknown as AstNode
|
|
188
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// The `flow` check: validates `@flow_step` annotations across a set of source
|
|
2
|
+
// files. This is the syntactic tier — it rejects what is locally wrong about an
|
|
3
|
+
// annotation without consulting the call graph. Three rules:
|
|
4
|
+
//
|
|
5
|
+
// - a `@flow_step` block must document a standalone function, not a method;
|
|
6
|
+
// - every `@downstream` must declare its cardinality (`step` | `branch`);
|
|
7
|
+
// - the annotation must parse.
|
|
8
|
+
//
|
|
9
|
+
// Cardinality is *correct* only relative to the call graph — that is the
|
|
10
|
+
// cardinality analyzer's job, not this one. See PLAN.tracing.md, component 2.
|
|
11
|
+
|
|
12
|
+
import { readFileSync, existsSync } from 'node:fs'
|
|
13
|
+
import { join } from 'node:path'
|
|
14
|
+
import { collectFlowStepSites, type FlowStepSite } from './flow-step-site.js'
|
|
15
|
+
|
|
16
|
+
export interface FlowViolation {
|
|
17
|
+
readonly rule: string
|
|
18
|
+
readonly file: string
|
|
19
|
+
readonly line: number
|
|
20
|
+
readonly message: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface FlowCheckResult {
|
|
24
|
+
readonly violations: readonly FlowViolation[]
|
|
25
|
+
readonly scanned: number
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Validates every `@flow_step` annotation in `sourceFiles` (paths relative to `cwd`). */
|
|
29
|
+
export function checkFlowAnnotations(cwd: string, sourceFiles: readonly string[]): FlowCheckResult {
|
|
30
|
+
const violations: FlowViolation[] = []
|
|
31
|
+
let scanned = 0
|
|
32
|
+
|
|
33
|
+
for (const file of sourceFiles) {
|
|
34
|
+
const abs = join(cwd, file)
|
|
35
|
+
if (!existsSync(abs)) continue
|
|
36
|
+
|
|
37
|
+
let sites: readonly FlowStepSite[]
|
|
38
|
+
try {
|
|
39
|
+
sites = collectFlowStepSites(readFileSync(abs, 'utf-8'), file)
|
|
40
|
+
} catch {
|
|
41
|
+
// Unparseable file — leave syntax errors to the type checker.
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
44
|
+
scanned++
|
|
45
|
+
|
|
46
|
+
for (const site of sites) {
|
|
47
|
+
collectSiteViolations(file, site, violations)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return { violations, scanned }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function collectSiteViolations(file: string, site: FlowStepSite, out: FlowViolation[]): void {
|
|
55
|
+
const { subject, annotation, commentLine } = site
|
|
56
|
+
|
|
57
|
+
if (subject.shape === 'orphan') {
|
|
58
|
+
out.push({
|
|
59
|
+
rule: 'flow/orphan-annotation',
|
|
60
|
+
file,
|
|
61
|
+
line: commentLine,
|
|
62
|
+
message:
|
|
63
|
+
'@flow_step JSDoc is not attached to a function. A flow step must document a '
|
|
64
|
+
+ 'standalone function declaration so it has a stable path:symbol identity.',
|
|
65
|
+
})
|
|
66
|
+
} else if (subject.shape === 'method') {
|
|
67
|
+
out.push({
|
|
68
|
+
rule: 'flow/no-method-flow-step',
|
|
69
|
+
file,
|
|
70
|
+
line: subject.line,
|
|
71
|
+
message:
|
|
72
|
+
`@flow_step on method "${subject.name}" — a method cannot be a flow step. It carries `
|
|
73
|
+
+ `hidden "this" state, so the trace boundary is untrustworthy. Extract "${subject.name}" `
|
|
74
|
+
+ 'into a standalone function.',
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (annotation.kind === 'invalid') {
|
|
79
|
+
for (const err of annotation.errors) {
|
|
80
|
+
out.push({
|
|
81
|
+
rule: 'flow/invalid-annotation',
|
|
82
|
+
file,
|
|
83
|
+
line: commentLine + err.line - 1,
|
|
84
|
+
message: err.message,
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
for (const edge of annotation.annotation.downstream) {
|
|
91
|
+
if (edge.cardinality === null) {
|
|
92
|
+
out.push({
|
|
93
|
+
rule: 'flow/missing-cardinality',
|
|
94
|
+
file,
|
|
95
|
+
line: commentLine,
|
|
96
|
+
message:
|
|
97
|
+
`@downstream ${edge.path}:${edge.symbol} is missing a cardinality. Add "step" or `
|
|
98
|
+
+ `"branch": @downstream ${edge.path}:${edge.symbol} branch. A branch is an edge `
|
|
99
|
+
+ 'traversed more than once (loop, batch, recursion, fan-out).',
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
// Locates `@flow_step` annotation sites in a TypeScript source file: each site
|
|
2
|
+
// pairs a parsed annotation with the declaration it documents and how that
|
|
3
|
+
// declaration is shaped — a standalone function, a method, or nothing at all.
|
|
4
|
+
// The `flow` check and the cardinality analyzer both build on this; it is the
|
|
5
|
+
// one place that answers "where are the flow steps in this file".
|
|
6
|
+
|
|
7
|
+
import { parse } from '@typescript-eslint/parser'
|
|
8
|
+
import { parseFlowStepAnnotation, type FlowStepParseResult } from 'pipework-flow-parser'
|
|
9
|
+
|
|
10
|
+
interface Position {
|
|
11
|
+
readonly line: number
|
|
12
|
+
readonly column: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface SourceLocation {
|
|
16
|
+
readonly start: Position
|
|
17
|
+
readonly end: Position
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** A structurally-typed ESTree node — enough to walk without a parser type dependency. */
|
|
21
|
+
export interface AstNode {
|
|
22
|
+
readonly type: string
|
|
23
|
+
readonly range: readonly [number, number]
|
|
24
|
+
readonly loc: SourceLocation
|
|
25
|
+
readonly [key: string]: unknown
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface CommentNode {
|
|
29
|
+
readonly type: 'Block' | 'Line'
|
|
30
|
+
readonly value: string
|
|
31
|
+
readonly range: readonly [number, number]
|
|
32
|
+
readonly loc: SourceLocation
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface Program extends AstNode {
|
|
36
|
+
readonly comments: readonly CommentNode[]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* How a `@flow_step`-annotated declaration is shaped.
|
|
41
|
+
*
|
|
42
|
+
* - `function` — a standalone function (declaration or a `const` bound to an
|
|
43
|
+
* arrow / function expression). The only legal shape.
|
|
44
|
+
* - `method` — a class method, class field bound to a function, or object
|
|
45
|
+
* literal method. Banned: a method carries hidden `this` state, so the trace
|
|
46
|
+
* boundary is untrustworthy. See PLAN.tracing.md, Q3.
|
|
47
|
+
* - `orphan` — the JSDoc block documents no declaration the analyzer can see.
|
|
48
|
+
*/
|
|
49
|
+
export type FlowStepShape = 'function' | 'method' | 'orphan'
|
|
50
|
+
|
|
51
|
+
export interface FlowStepSubject {
|
|
52
|
+
readonly shape: FlowStepShape
|
|
53
|
+
/** Declared name, or `<anonymous>` / `<computed>` when none can be read. */
|
|
54
|
+
readonly name: string
|
|
55
|
+
/** 1-based line of the declaration, or of the JSDoc block when orphaned. */
|
|
56
|
+
readonly line: number
|
|
57
|
+
/** The declaration node, or `null` when orphaned. */
|
|
58
|
+
readonly node: AstNode | null
|
|
59
|
+
/**
|
|
60
|
+
* The documented function's executable body — what the cardinality analyzer
|
|
61
|
+
* walks. `null` exactly when `node` is `null` (an orphan): every `function`
|
|
62
|
+
* and `method` subject resolves to a function with a body.
|
|
63
|
+
*/
|
|
64
|
+
readonly body: AstNode | null
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface FlowStepSite {
|
|
68
|
+
/** Parsed content of the `@flow_step` JSDoc block — never `not-a-flow-step`. */
|
|
69
|
+
readonly annotation: Exclude<FlowStepParseResult, { kind: 'not-a-flow-step' }>
|
|
70
|
+
/** The declaration the block documents, and how it is shaped. */
|
|
71
|
+
readonly subject: FlowStepSubject
|
|
72
|
+
/** 1-based line where the `@flow_step` JSDoc block opens. */
|
|
73
|
+
readonly commentLine: number
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface Candidate {
|
|
77
|
+
readonly node: AstNode
|
|
78
|
+
readonly shape: Exclude<FlowStepShape, 'orphan'>
|
|
79
|
+
readonly name: string
|
|
80
|
+
readonly body: AstNode | null
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const flowStepSiteCache = new Map<string, FlowStepSite[]>()
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Parse `code` and return every `@flow_step` site it contains, in source order.
|
|
87
|
+
*
|
|
88
|
+
* Memoized by source text: the flow, cardinality, and coverage checks each scan
|
|
89
|
+
* the same file, and the parse-and-walk produces a bit-identical result every
|
|
90
|
+
* time — the cache collapses it to one parse per file. Issue #322.
|
|
91
|
+
*
|
|
92
|
+
* Throws if `code` is not parseable — callers scanning many files should catch
|
|
93
|
+
* and skip, leaving syntax errors to the type checker. A `fileName` ending in
|
|
94
|
+
* `.tsx` parses with JSX enabled.
|
|
95
|
+
*/
|
|
96
|
+
export function collectFlowStepSites(code: string, fileName?: string): FlowStepSite[] {
|
|
97
|
+
const jsx = fileName?.endsWith('.tsx') === true
|
|
98
|
+
const key = jsx ? 'jsx\0' + code : code
|
|
99
|
+
const cached = flowStepSiteCache.get(key)
|
|
100
|
+
if (cached !== undefined) return cached
|
|
101
|
+
const sites = parseFlowStepSites(code, jsx)
|
|
102
|
+
flowStepSiteCache.set(key, sites)
|
|
103
|
+
return sites
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function parseFlowStepSites(code: string, jsx: boolean): FlowStepSite[] {
|
|
107
|
+
const program = parse(code, {
|
|
108
|
+
...(jsx ? { jsx: true } : {}),
|
|
109
|
+
range: true,
|
|
110
|
+
loc: true,
|
|
111
|
+
comment: true,
|
|
112
|
+
sourceType: 'module',
|
|
113
|
+
}) as unknown as Program
|
|
114
|
+
|
|
115
|
+
const candidates: Candidate[] = []
|
|
116
|
+
walk(program, node => {
|
|
117
|
+
const candidate = classify(node)
|
|
118
|
+
if (candidate !== null) candidates.push(candidate)
|
|
119
|
+
})
|
|
120
|
+
candidates.sort((a, b) => a.node.range[0] - b.node.range[0])
|
|
121
|
+
|
|
122
|
+
const sites: FlowStepSite[] = []
|
|
123
|
+
for (const comment of program.comments) {
|
|
124
|
+
if (comment.type !== 'Block') continue
|
|
125
|
+
const annotation = parseFlowStepAnnotation(`/*${comment.value}*/`)
|
|
126
|
+
if (annotation.kind === 'not-a-flow-step') continue
|
|
127
|
+
sites.push({
|
|
128
|
+
annotation,
|
|
129
|
+
subject: subjectFor(comment, candidates),
|
|
130
|
+
commentLine: comment.loc.start.line,
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
return sites
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** The declaration a `@flow_step` block documents: the nearest one that follows it. */
|
|
137
|
+
function subjectFor(comment: CommentNode, candidates: readonly Candidate[]): FlowStepSubject {
|
|
138
|
+
const documented = candidates.find(c => c.node.range[0] >= comment.range[1])
|
|
139
|
+
if (documented === undefined) {
|
|
140
|
+
return { shape: 'orphan', name: '<unknown>', line: comment.loc.start.line, node: null, body: null }
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
shape: documented.shape,
|
|
144
|
+
name: documented.name,
|
|
145
|
+
line: documented.node.loc.start.line,
|
|
146
|
+
node: documented.node,
|
|
147
|
+
body: documented.body,
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Classifies a node as a flow-step-able declaration, or `null` if it is not one. */
|
|
152
|
+
function classify(node: AstNode): Candidate | null {
|
|
153
|
+
switch (node.type) {
|
|
154
|
+
case 'FunctionDeclaration':
|
|
155
|
+
return { node, shape: 'function', name: readName(node['id']), body: bodyOf(node) }
|
|
156
|
+
case 'VariableDeclaration': {
|
|
157
|
+
const bound = functionBoundDeclarator(node)
|
|
158
|
+
if (bound === null) return null
|
|
159
|
+
return { node, shape: 'function', name: readName(bound['id']), body: bodyOf(bound['init']) }
|
|
160
|
+
}
|
|
161
|
+
case 'MethodDefinition':
|
|
162
|
+
case 'TSAbstractMethodDefinition':
|
|
163
|
+
return { node, shape: 'method', name: readName(node['key']), body: bodyOf(node['value']) }
|
|
164
|
+
case 'PropertyDefinition':
|
|
165
|
+
case 'TSAbstractPropertyDefinition':
|
|
166
|
+
case 'Property':
|
|
167
|
+
return isFunctionExpression(node['value'])
|
|
168
|
+
? { node, shape: 'method', name: readName(node['key']), body: bodyOf(node['value']) }
|
|
169
|
+
: null
|
|
170
|
+
default:
|
|
171
|
+
return null
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** The executable `body` of a function node — a `BlockStatement` or, for a
|
|
176
|
+
* concise arrow, the returned expression. `null` when `fn` is not a function. */
|
|
177
|
+
function bodyOf(fn: unknown): AstNode | null {
|
|
178
|
+
if (!isNode(fn)) return null
|
|
179
|
+
const body = fn['body']
|
|
180
|
+
return isNode(body) ? body : null
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** The first declarator in a `VariableDeclaration` bound to a function, or `null`. */
|
|
184
|
+
function functionBoundDeclarator(node: AstNode): AstNode | null {
|
|
185
|
+
const declarations = node['declarations']
|
|
186
|
+
if (!Array.isArray(declarations)) return null
|
|
187
|
+
for (const declarator of declarations) {
|
|
188
|
+
if (isNode(declarator) && isFunctionExpression(declarator['init'])) return declarator
|
|
189
|
+
}
|
|
190
|
+
return null
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function isFunctionExpression(value: unknown): boolean {
|
|
194
|
+
return isNode(value)
|
|
195
|
+
&& (value.type === 'ArrowFunctionExpression' || value.type === 'FunctionExpression')
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function readName(keyOrId: unknown): string {
|
|
199
|
+
if (!isNode(keyOrId)) return '<anonymous>'
|
|
200
|
+
switch (keyOrId.type) {
|
|
201
|
+
case 'Identifier':
|
|
202
|
+
return String(keyOrId['name'])
|
|
203
|
+
case 'PrivateIdentifier':
|
|
204
|
+
return `#${String(keyOrId['name'])}`
|
|
205
|
+
case 'Literal':
|
|
206
|
+
return String(keyOrId['value'])
|
|
207
|
+
default:
|
|
208
|
+
return '<computed>'
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const SKIP_KEYS = new Set(['loc', 'range', 'parent'])
|
|
213
|
+
|
|
214
|
+
/** Depth-first visit of every node reachable from `node`, parents before children. */
|
|
215
|
+
function walk(node: AstNode, visit: (n: AstNode) => void): void {
|
|
216
|
+
visit(node)
|
|
217
|
+
for (const key of Object.keys(node)) {
|
|
218
|
+
if (SKIP_KEYS.has(key)) continue
|
|
219
|
+
const value = node[key]
|
|
220
|
+
if (Array.isArray(value)) {
|
|
221
|
+
for (const item of value) {
|
|
222
|
+
if (isNode(item)) walk(item, visit)
|
|
223
|
+
}
|
|
224
|
+
} else if (isNode(value)) {
|
|
225
|
+
walk(value, visit)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function isNode(value: unknown): value is AstNode {
|
|
231
|
+
return typeof value === 'object'
|
|
232
|
+
&& value !== null
|
|
233
|
+
&& typeof (value as { type?: unknown }).type === 'string'
|
|
234
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// The I/O call-target registry consumed by the Tier-2 coverage check. Given a
|
|
2
|
+
// `CallExpression`, classifies it as a read, a write, or not-I/O.
|
|
3
|
+
//
|
|
4
|
+
// Stock list (pipework-owned, lexical):
|
|
5
|
+
// - Writes: `pipe.insert / pipe.update / pipe.delete / pipe.upsert /
|
|
6
|
+
// pipe.bulkSet`. These are the locked write entrypoints from Q8; the
|
|
7
|
+
// raw-write lint rule (component 13) backs them up.
|
|
8
|
+
// - Reads: any call whose callee chains off `pipe(...)` — e.g.
|
|
9
|
+
// `pipe('db').execute(...)`, `pipe(name).select(...)`,
|
|
10
|
+
// `pipe('db').query.users.findMany(...)`. The `pipe(name)` accessor only
|
|
11
|
+
// exists to perform I/O, so any method called on its result counts.
|
|
12
|
+
//
|
|
13
|
+
// Consumer extension (Q9): cache, external HTTP, queue publishes — anything
|
|
14
|
+
// outside the stock list — is registered through `pipework.config.ts` under
|
|
15
|
+
// `trace.io`. The registry is a `Record<string, 'read' | 'write'>` where the
|
|
16
|
+
// key is a lexical call pattern: a bare identifier (`"fetch"`) matches an
|
|
17
|
+
// identifier callee; an `"object.method"` pattern matches a single-level
|
|
18
|
+
// member-access callee. The schema validator rejects anything more elaborate —
|
|
19
|
+
// type resolution is out of scope, lexical matching is the contract.
|
|
20
|
+
|
|
21
|
+
import { isNode, type AstNode } from './flow-step-site.js'
|
|
22
|
+
|
|
23
|
+
export type IoKind = 'read' | 'write'
|
|
24
|
+
|
|
25
|
+
const PIPE_WRITE_METHODS = new Set(['insert', 'update', 'delete', 'upsert', 'bulkSet'])
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Classify `call` against the stock I/O registry and the optional consumer
|
|
29
|
+
* `extras` registry, or return `null` if the call is not I/O. `extras` is the
|
|
30
|
+
* `Record` shape `config.trace.io` resolves to — keys are lexical patterns
|
|
31
|
+
* (`"fetch"` or `"cache.get"`), values are `'read' | 'write'`.
|
|
32
|
+
*
|
|
33
|
+
* `call` must be a `CallExpression`; callers walk the AST and hand each one
|
|
34
|
+
* over. This function is pure over the node — no parent lookups, no type
|
|
35
|
+
* resolution. Lexical match only.
|
|
36
|
+
*/
|
|
37
|
+
export function classifyIo(
|
|
38
|
+
call: AstNode,
|
|
39
|
+
extras: Readonly<Record<string, IoKind>> = {},
|
|
40
|
+
): IoKind | null {
|
|
41
|
+
if (call.type !== 'CallExpression') return null
|
|
42
|
+
const callee = call['callee']
|
|
43
|
+
if (!isNode(callee)) return null
|
|
44
|
+
|
|
45
|
+
if (isPipeWriteCallee(callee)) return 'write'
|
|
46
|
+
if (chainsOffPipeAccessor(callee)) return 'read'
|
|
47
|
+
|
|
48
|
+
return matchExtras(callee, extras)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** `pipe.<verb>` where `<verb>` is one of the locked write entrypoints. */
|
|
52
|
+
function isPipeWriteCallee(callee: AstNode): boolean {
|
|
53
|
+
if (callee.type !== 'MemberExpression') return false
|
|
54
|
+
if (callee['computed'] === true) return false
|
|
55
|
+
|
|
56
|
+
const object = callee['object']
|
|
57
|
+
const property = callee['property']
|
|
58
|
+
if (!isNode(object) || object.type !== 'Identifier' || object['name'] !== 'pipe') return false
|
|
59
|
+
if (!isNode(property) || property.type !== 'Identifier') return false
|
|
60
|
+
|
|
61
|
+
const name = property['name']
|
|
62
|
+
return typeof name === 'string' && PIPE_WRITE_METHODS.has(name)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The callee is a chain off `pipe(...)` — anywhere up the member-expression
|
|
67
|
+
* spine. `pipe('db').execute(sql)` matches; `pipe('db').query.users.findMany()`
|
|
68
|
+
* matches; `pipe.update(t)` (no call on `pipe`) does not.
|
|
69
|
+
*/
|
|
70
|
+
function chainsOffPipeAccessor(callee: AstNode): boolean {
|
|
71
|
+
let cursor: AstNode = callee
|
|
72
|
+
while (cursor.type === 'MemberExpression') {
|
|
73
|
+
const object = cursor['object']
|
|
74
|
+
if (!isNode(object)) return false
|
|
75
|
+
if (isPipeInvocation(object)) return true
|
|
76
|
+
cursor = object
|
|
77
|
+
}
|
|
78
|
+
return false
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** `pipe(...)` — a call expression whose callee is the identifier `pipe`. */
|
|
82
|
+
function isPipeInvocation(node: AstNode): boolean {
|
|
83
|
+
if (node.type !== 'CallExpression') return false
|
|
84
|
+
const callee = node['callee']
|
|
85
|
+
return isNode(callee) && callee.type === 'Identifier' && callee['name'] === 'pipe'
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Looks up `callee` against the consumer registry. Two shapes match:
|
|
90
|
+
* - Identifier `foo` → key `"foo"`
|
|
91
|
+
* - Non-computed MemberExpression `obj.method` (Identifier object,
|
|
92
|
+
* Identifier property) → key `"obj.method"`
|
|
93
|
+
* Anything else falls through (returns `null`) — the stock registry has
|
|
94
|
+
* already exited above, so this is the not-I/O bucket.
|
|
95
|
+
*/
|
|
96
|
+
function matchExtras(
|
|
97
|
+
callee: AstNode,
|
|
98
|
+
extras: Readonly<Record<string, IoKind>>,
|
|
99
|
+
): IoKind | null {
|
|
100
|
+
if (callee.type === 'Identifier') {
|
|
101
|
+
const name = callee['name']
|
|
102
|
+
if (typeof name !== 'string') return null
|
|
103
|
+
return extras[name] ?? null
|
|
104
|
+
}
|
|
105
|
+
if (callee.type === 'MemberExpression' && callee['computed'] !== true) {
|
|
106
|
+
const object = callee['object']
|
|
107
|
+
const property = callee['property']
|
|
108
|
+
if (!isNode(object) || object.type !== 'Identifier') return null
|
|
109
|
+
if (!isNode(property) || property.type !== 'Identifier') return null
|
|
110
|
+
const objectName = object['name']
|
|
111
|
+
const propertyName = property['name']
|
|
112
|
+
if (typeof objectName !== 'string' || typeof propertyName !== 'string') return null
|
|
113
|
+
return extras[`${objectName}.${propertyName}`] ?? null
|
|
114
|
+
}
|
|
115
|
+
return null
|
|
116
|
+
}
|