Skip to content

Commit 9f3b4bb

Browse files
refactor(objectql): one shared host per facet in the engine.ts codemod stubs (body-identical; engine.ts 14,140 -> 13,548) (#30083)
<!-- claude-projects-attribution: {"github_login":"os-support-ai"} --> _Requested by **Yibo Wang** · [project thread](https://claude.ai/code/project/chan_01BVUyyPie8gHwoPM18iABwB?thread=cmsg_01BVUyyPie8gHwoPM18iABwBQdjPLZDve4g9Vssqoo6oK8)_ Fixes #30051 ## 维护者速读 - 改了什么:`scripts/codemod-split-engine.mjs` 改为每个 facet 只建一个共享 host(每个引擎实例一份,首次调用时由类的 static 块安装的工厂建成,存在新模块 `engine-facet-hosts.ts`),类上的 stub 从「每次调用现建一个 host 字面量」变成一行 `Facet.x.call(xHost.of(this), …)`。从 base 重新生成,生成物未手改。`engine.ts` 14,140 → 13,548 行(−592)。`protocol.ts` 不动:它的 codemod 存根本来就走共享的 `protocolHost(this)`,没有可压缩的。 - 为什么改:维护者在 #30012 上要求进一步压缩 `engine.ts`(「我觉得文件还是太长,还有进一步的拆分优化空间吗」「可以后续立卡处理」),本卡是其中的 stub 压缩一项。 - 风险与回滚:只改 stub 和新增 host 模块,161/161 方法体、146/146 顶层声明逐字节不变,撤销拆分逐字节还原 base `engine.ts`;打包后 6 个 `.d.ts` 与 main 逐字节相同;objectql 测试 base 547 文件/10,833 = head;回滚就是 revert。 - 先看:① `packages/objectql/src/engine-facet-hosts.ts`(`FacetHost` 缓存,78 行);② `engine.ts` 类末尾第二个 static 块(16 个 host 工厂);③ codemod 里的 `hostsTexts` / `stubBody` 和 `verify` 新增的 stub 与 host 校验。 - 两分钟验证:`pnpm install --frozen-lockfile` 后运行 `node scripts/codemod-split-engine.mjs --verify --base c2d353d`,应看到 `161/161 moved bodies identical`、`23245 -> 13548 lines`,退出码 0;`--self-test` 应通过 68 例。 - 需要你做的:改动共 1,996 行(未超过 3,000 行线),但按席位裁决本 PR 保持草稿,在您定的窗口里落地。 Clause-②: no Metadata-protocol: none ## What changes - **`scripts/codemod-split-engine.mjs`.** Each facet's host is now built ONCE per engine instead of once per call. - `hostsTexts` writes a new module, `engine-facet-hosts.ts`. It holds `FacetHost`, a `WeakMap` cache keyed by engine with a factory slot, and one exported instance per facet module (`actionsHost`, `cascadePlanningHost`, …, 16 in all). The module imports types only, so it forms no evaluation cycle and is evaluated before the class whichever module loads first. This matters because 4 facet modules import `ObjectQLStatics` from `engine.ts` by value, so a cache inside a facet module could be in its temporal dead zone when the class's static block runs. - A second static block at the end of `ObjectQL` installs each facet's factory: `xHost.install((engine) => ({ … }))`. The factory forwards each member as the per-call literal did. A method is a closure called on the engine at call time (`m: (...a) => engine.m(...a)`), so a spy or subclass override installed later is still reached. A field or accessor is a getter, and a field a body assigns also gets a setter. The host is the facet's whole host interface (`ActionsHost` and so on), which satisfies every body's `Pick`. A static block adds no class member, so the `.d.ts` does not move. - `stubBody` writes `return Facet.x.call(xHost.of(this), …args);` (a generic method still calls its body instantiated with its own type parameters). A stub whose body reads no member is unchanged. - A facet host can be told apart from a per-call literal only by identity across calls. No moved body can observe that: a body that reads `this` bare already stays on the class (`bare-this`). - `verify` now also checks that (1) every stub equals the generated one-call stub for its method, facet and host, (2) `engine-facet-hosts.ts` equals the generated text for the host interfaces on disk, and (3) the install block equals the generated block. Each member is forwarded by its BASE class kind: a method as a closure, anything else as a getter, plus a setter when the interface does not mark it `readonly`. The undo drops the block and the import. - Generation refuses when `engine.ts` already binds a host name, or when a moving method has a parameter named after its facet's host. - `--self-test`: 68 cases in 6 batteries. "facets, statics and docblocks" goes from 11 to 17 cases, and its floor is raised to 17. The new refusals: a stub handing another facet's host, an edited host module, and a written field's setter left out. - **The regenerated split.** `--write` on `engine.ts` at `c2d353d2` (main's last unsplit `engine.ts`; nothing has touched `engine*.ts` since #30012 merged as `237f5137`), unedited. The diff: `engine.ts` (145 stubs lose their literal, plus the install block and one import), the new `engine-facet-hosts.ts`, and the header prose of the 16 facet modules (the host paragraph). No body moved. - **`protocol.ts` / `scripts/codemod-split-protocol.mjs`: no change.** The card's premise does not hold for this file. Its 85 codemod stubs already reach their bodies through one shared host per instance, `ProtocolClassHeadFacet.x(protocolHost(this), …)` (`protocol-host.ts`, a `WeakMap` cache installed by the class's static block). That is the shape this PR gives `engine.ts`. `grep -c 'const host: ThisParameterType' scripts/codemod-split-protocol.mjs` reads 0. The per-call literals left in `protocol.ts` (164 stubs, 774 lines) are all hand-series stubs that the codemod did not write (see Acceptance notes). ### Line counts | File | Before (main `c23501b2`) | After | Δ | |:--|--:|--:|--:| | `packages/objectql/src/engine.ts` | 14,140 | 13,548 | −592 | | `packages/objectql/src/engine-facet-hosts.ts` | — | 78 | +78 | | `packages/metadata-protocol/src/protocol.ts` | 13,647 | 13,647 | 0 | The card estimated about 1,000 lines off `engine.ts`. The measured figure is 592. The 145 per-call literals were 869 lines, and the install block adds back one line per host member (207 across 16 facets, plus 31 setters and 2 lines per facet). PR size: 847 additions + 1,149 deletions = 1,996 changed lines. ## Tests <details><summary>Proofs (all at head 73a7605 unless stated)</summary> - `node scripts/codemod-split-engine.mjs --verify --base c2d353d`: exit 0. 161/161 moved bodies identical (body, parameters, return type, async), 146/146 top-level declarations identical, every stub equals the generated one, the host module and install block are the generated ones, and the undo rebuilds base `engine.ts` byte for byte once 107 import bindings are pruned. `engine.ts 23245 -> 13548 lines`. - Determinism: two `--write` runs from base `engine.ts` (sha256 `dc5677f3…`), one in a separate worktree, print the same output tree sha256 `09c80319211a965b89820ab7bb650d74cf6aaaec0afc0afb9cd75f2b867e3554`. The second worktree's regenerated tree equals the committed head (`git status` empty). - `.d.ts`: `packages/objectql/dist` built at main (`c23501b2`) ×2 and at head ×2. All 6 declaration files (`index`, `core`, `util-BWl1U61F`, each `.d.ts` + `.d.mts`) are **byte-identical** base vs head. The public-surface reading (`pubsurface.mjs` from #29986) passes base1=base2, head1=head2, base1=head1 and base2=head2, and its controls behave (a private member made public is caught, a public type change is caught, a private docblock edit is not). - objectql `test`: base (main `c23501b2`) 547 files / 10,833 passed = head 547 / 10,833. `test:repo`: 1 file / 5 = 5. - objectql `typecheck` (tsc + check:test-typecheck): exit 0. - Built-dist smoke (ESM `index.mjs` and CJS `index.js`): two engines keep separate hosts (`residualOwnerSource` set on one reads `undefined` on the other), a host setter writes through (`setDefaultBodyRunner` first-wins `true`, then `false`). - Facade gate `node scripts/check-facade-delegation-only.mjs`: exit 0, registry unchanged (2 facades, 60 exceptions). The `engine.ts` delegation kinds move from 217 host-literal stubs to 144 host delegations plus 73 host-literal stubs (the hand series). The new install block reads as a second `static host factory`. - Durability census `check-durability-degradation-log-level.mjs`: base (main) and head output byte-identical (51 seams, 9 propagating; 101 read seams, 13 discriminated). `--self-test` exit 0. </details> <details><summary>Ablations (each red, then restored; file hash back to its HEAD blob)</summary> Done through `scripts/ablation-replace.mjs`. 1. verify's stub check turned off: the self-test case "a stub handing another facet's host fails" goes red. 2. verify's host-module comparison turned off: "an edited host module fails" goes red. 3. verify's install-block comparison turned off: "a written field's setter left out of the host fails" goes red. 4. On the real tree, one `engine.ts` stub pointed at another facet's host: `--verify --base c2d353d` exits 1 with `recordResidualOwner: its stub is not the generated one-call stub`. </details> ## Acceptance notes - **The hand-series stubs keep their per-call literals.** In `engine.ts` that is 73 stubs (454 lines; the #25522 hand modules). In `protocol.ts` it is 164 stubs (774 lines; the #25467 hand modules). The codemods do not write those stubs, and this card's ruling is codemod-only. The same mechanism would apply (route them through the facet hosts or `protocolHost`, after widening `ProtocolHost`). By arithmetic, not a generated run, that is about −400 lines in `engine.ts` and about −700 in `protocol.ts`. Carrier: the seat, if it wants a card. - No changeset, following #30012 and pilot #29598 (`skip-changeset`): the behaviour and the published declaration files do not change. ## Verification Local, at head `73a7605b`: - `npx turbo run build --concurrency=2`: 120/120 tasks, exit 0. `pnpm lint`: exit 0. objectql `typecheck`: exit 0. - `node scripts/pm/dispatch-gates.mjs --commands`: 64 families derived, each run, all exit 0. Three exited 3 on the first sweep because a prerequisite was missing (`check-plugin-teardown-shape --self-test` needs the pinned fixture commit fetched; `check:dual-build-cjs-loads` and `check:lean-entry-closure` need the full build). Each passed when rerun after its prerequisite was in place. `--ran`: 64 derived, 64 run, 0 NOT-MEASURED, 0 UNRUN. - Run by hand, outside the derivation: `check-facade-delegation-only.mjs` (exit 0, registry unchanged), `check-durability-degradation-log-level.mjs` (base = head output), `codemod-split-engine.mjs --self-test` (68 cases). - Declared to CI: the full lint workflow battery, core `test:repo`, and dogfood (the title has no `!` and there is no narrowing arm). ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (not touched) - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; `pnpm lint` passes. - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. (`skip-changeset`, see above) - [x] 6. `packages/spec` touched: its generated artifacts are regenerated and committed. (not touched) - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English. --- _Generated by [Claude Code](https://claude.ai/code/session_01WGufzfeJWRytJdoFWR9Pc8)_ <!-- signed: domain:server#6 · os-support-ai · session_01WGufzfeJWRytJdoFWR9Pc8 --> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 61b487b commit 9f3b4bb

19 files changed

Lines changed: 873 additions & 1160 deletions

‎packages/objectql/src/engine-actions.ts‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@
1919
* with its body. The state stays on `ObjectQL`.
2020
*
2121
* The bodies reach the class through {@link ActionsHost}: exactly the
22-
* `ObjectQL` members they read, private ones included. Each stub hands its
23-
* body one literal of the members that body reads, plus a `.call`: methods go
24-
* as closures that call them on the engine at call time, so a subclass
25-
* override or an instance spy is still the one reached; fields and accessors
26-
* go as GETTERS, read when the body reads them, as they were on the class,
27-
* and a field a body assigns goes with a SETTER that assigns it on the engine.
22+
* `ObjectQL` members they read, private ones included. Every stub hands its
23+
* body, by a `.call`, the same host: `actionsHost` in `engine-facet-hosts.ts`,
24+
* built once per engine by the class's static block. Methods go as closures
25+
* that call them on the engine at call time, so a subclass override or an
26+
* instance spy is still the one reached; fields and accessors go as GETTERS,
27+
* read when the body reads them, as they were on the class, and a field a body
28+
* assigns goes with a SETTER that assigns it on the engine.
2829
*
2930
* The module imports `engine.ts` for types only, so the two modules form no
3031
* evaluation cycle. `index.ts` re-exports nothing from this module.

‎packages/objectql/src/engine-cascade-planning.ts‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@
2424
* with its body. The state stays on `ObjectQL`.
2525
*
2626
* The bodies reach the class through {@link CascadePlanningHost}: exactly the
27-
* `ObjectQL` members they read, private ones included. Each stub hands its
28-
* body one literal of the members that body reads, plus a `.call`: methods go
29-
* as closures that call them on the engine at call time, so a subclass
30-
* override or an instance spy is still the one reached; fields and accessors
31-
* go as GETTERS, read when the body reads them, as they were on the class,
32-
* and a field a body assigns goes with a SETTER that assigns it on the engine.
27+
* `ObjectQL` members they read, private ones included. Every stub hands its
28+
* body, by a `.call`, the same host: `cascadePlanningHost` in
29+
* `engine-facet-hosts.ts`, built once per engine by the class's static block.
30+
* Methods go as closures that call them on the engine at call time, so a
31+
* subclass override or an instance spy is still the one reached; fields and
32+
* accessors go as GETTERS, read when the body reads them, as they were on the
33+
* class, and a field a body assigns goes with a SETTER that assigns it on the
34+
* engine.
3335
*
3436
* `ObjectQL` here is `ObjectQLStatics` (imported AS `ObjectQL`): forwarders to the
3537
* statics the bodies read, private ones included, which the class fills in a

‎packages/objectql/src/engine-compatibility-section.ts‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@
1616
* docblock on the class, the contract; a private method's docblock moved here
1717
* with its body. The state stays on `ObjectQL`.
1818
*
19-
* The bodies reach the class through {@link CompatibilitySectionHost}: exactly the
20-
* `ObjectQL` members they read, private ones included. Each stub hands its
21-
* body one literal of the members that body reads, plus a `.call`: methods go
22-
* as closures that call them on the engine at call time, so a subclass
23-
* override or an instance spy is still the one reached; fields and accessors
24-
* go as GETTERS, read when the body reads them, as they were on the class,
25-
* and a field a body assigns goes with a SETTER that assigns it on the engine.
19+
* The bodies reach the class through {@link CompatibilitySectionHost}: exactly
20+
* the `ObjectQL` members they read, private ones included. Every stub hands its
21+
* body, by a `.call`, the same host: `compatibilitySectionHost` in
22+
* `engine-facet-hosts.ts`, built once per engine by the class's static block.
23+
* Methods go as closures that call them on the engine at call time, so a
24+
* subclass override or an instance spy is still the one reached; fields and
25+
* accessors go as GETTERS, read when the body reads them, as they were on the
26+
* class, and a field a body assigns goes with a SETTER that assigns it on the
27+
* engine.
2628
*
2729
* Values that stayed in `engine.ts` are imported from it (lever (a) of
2830
* ruling 6591753301); every use is inside a function body, so the import

‎packages/objectql/src/engine-defaults-and-autonumbers.ts‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717
* docblock on the class, the contract; a private method's docblock moved here
1818
* with its body. The state stays on `ObjectQL`.
1919
*
20-
* The bodies reach the class through {@link DefaultsAndAutonumbersHost}: exactly the
21-
* `ObjectQL` members they read, private ones included. Each stub hands its
22-
* body one literal of the members that body reads, plus a `.call`: methods go
23-
* as closures that call them on the engine at call time, so a subclass
24-
* override or an instance spy is still the one reached; fields and accessors
25-
* go as GETTERS, read when the body reads them, as they were on the class,
26-
* and a field a body assigns goes with a SETTER that assigns it on the engine.
20+
* The bodies reach the class through {@link DefaultsAndAutonumbersHost}:
21+
* exactly the `ObjectQL` members they read, private ones included. Every stub
22+
* hands its body, by a `.call`, the same host: `defaultsAndAutonumbersHost` in
23+
* `engine-facet-hosts.ts`, built once per engine by the class's static block.
24+
* Methods go as closures that call them on the engine at call time, so a
25+
* subclass override or an instance spy is still the one reached; fields and
26+
* accessors go as GETTERS, read when the body reads them, as they were on the
27+
* class, and a field a body assigns goes with a SETTER that assigns it on the
28+
* engine.
2729
*
2830
* The module imports `engine.ts` for types only, so the two modules form no
2931
* evaluation cycle. `index.ts` re-exports nothing from this module.

‎packages/objectql/src/engine-delete-and-aggregate.ts‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
* docblock on the class, the contract; a private method's docblock moved here
1515
* with its body. The state stays on `ObjectQL`.
1616
*
17-
* The bodies reach the class through {@link DeleteAndAggregateHost}: exactly the
18-
* `ObjectQL` members they read, private ones included. Each stub hands its
19-
* body one literal of the members that body reads, plus a `.call`: methods go
20-
* as closures that call them on the engine at call time, so a subclass
21-
* override or an instance spy is still the one reached; fields and accessors
22-
* go as GETTERS, read when the body reads them, as they were on the class,
23-
* and a field a body assigns goes with a SETTER that assigns it on the engine.
17+
* The bodies reach the class through {@link DeleteAndAggregateHost}: exactly
18+
* the `ObjectQL` members they read, private ones included. Every stub hands its
19+
* body, by a `.call`, the same host: `deleteAndAggregateHost` in
20+
* `engine-facet-hosts.ts`, built once per engine by the class's static block.
21+
* Methods go as closures that call them on the engine at call time, so a
22+
* subclass override or an instance spy is still the one reached; fields and
23+
* accessors go as GETTERS, read when the body reads them, as they were on the
24+
* class, and a field a body assigns goes with a SETTER that assigns it on the
25+
* engine.
2426
*
2527
* The module imports `engine.ts` for types only, so the two modules form no
2628
* evaluation cycle. `index.ts` re-exports nothing from this module.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* [#29986 codemod] The host of each facet of `ObjectQL`, built ONCE per engine (#30051):
5+
* what every stub of a facet hands that facet's bodies as `this`, in place of
6+
* a host literal built on every call. Each `FacetHost` below is filled by the
7+
* factory `ObjectQL`'s static block installs, the one place that can read
8+
* the class's private members; the host is built on the first call that needs
9+
* it and kept for the engine's life. A method goes as a closure that calls it
10+
* on the engine at call time, a field or accessor as a getter (and a setter
11+
* when a body assigns it), so a body reads and writes the engine exactly as
12+
* the per-call literal let it.
13+
*
14+
* Written by `scripts/codemod-split-engine.mjs`; it imports types only, so it forms no
15+
* evaluation cycle and is evaluated before the class whichever module loads
16+
* first. `index.ts` re-exports nothing from this module.
17+
*/
18+
19+
import type { ObjectQL } from './engine.js';
20+
import type { ActionsHost } from './engine-actions.js';
21+
import type { CascadePlanningHost } from './engine-cascade-planning.js';
22+
import type { CompatibilitySectionHost } from './engine-compatibility-section.js';
23+
import type { DefaultsAndAutonumbersHost } from './engine-defaults-and-autonumbers.js';
24+
import type { DeleteAndAggregateHost } from './engine-delete-and-aggregate.js';
25+
import type { FindHost } from './engine-find.js';
26+
import type { HooksAndFunctionsHost } from './engine-hooks-and-functions.js';
27+
import type { InsertHost } from './engine-insert.js';
28+
import type { MiddlewareAndContextHost } from './engine-middleware-and-context.js';
29+
import type { MigrationStateHost } from './engine-migration-state.js';
30+
import type { ReferencesAndMasterDetailHost } from './engine-references-and-master-detail.js';
31+
import type { RegistrationHost } from './engine-registration.js';
32+
import type { SecretsAndRoutingHost } from './engine-secrets-and-routing.js';
33+
import type { SecurityResolversHost } from './engine-security-resolvers.js';
34+
import type { SummariesAndExpansionHost } from './engine-summaries-and-expansion.js';
35+
import type { TransactionsSectionHost } from './engine-transactions-section.js';
36+
37+
/** One facet's host for each engine: built on first use, kept for the engine's life. */
38+
export class FacetHost<H> {
39+
private readonly hosts = new WeakMap<ObjectQL, H>();
40+
private build: ((engine: ObjectQL) => H) | undefined;
41+
42+
constructor(private readonly facet: string) {}
43+
44+
/** Called once, from `ObjectQL`'s static block. */
45+
install(build: (engine: ObjectQL) => H): void {
46+
this.build = build;
47+
}
48+
49+
/** The host of `engine`, built on first use. */
50+
of(engine: ObjectQL): H {
51+
let host = this.hosts.get(engine);
52+
if (host === undefined) {
53+
if (this.build === undefined) {
54+
throw new Error(`${this.facet}: ObjectQL has not installed its host factory`);
55+
}
56+
host = this.build(engine);
57+
this.hosts.set(engine, host);
58+
}
59+
return host;
60+
}
61+
}
62+
63+
export const actionsHost = new FacetHost<ActionsHost>('ActionsFacet');
64+
export const cascadePlanningHost = new FacetHost<CascadePlanningHost>('CascadePlanningFacet');
65+
export const compatibilitySectionHost = new FacetHost<CompatibilitySectionHost>('CompatibilitySectionFacet');
66+
export const defaultsAndAutonumbersHost = new FacetHost<DefaultsAndAutonumbersHost>('DefaultsAndAutonumbersFacet');
67+
export const deleteAndAggregateHost = new FacetHost<DeleteAndAggregateHost>('DeleteAndAggregateFacet');
68+
export const findHost = new FacetHost<FindHost>('FindFacet');
69+
export const hooksAndFunctionsHost = new FacetHost<HooksAndFunctionsHost>('HooksAndFunctionsFacet');
70+
export const insertHost = new FacetHost<InsertHost>('InsertFacet');
71+
export const middlewareAndContextHost = new FacetHost<MiddlewareAndContextHost>('MiddlewareAndContextFacet');
72+
export const migrationStateHost = new FacetHost<MigrationStateHost>('MigrationStateFacet');
73+
export const referencesAndMasterDetailHost = new FacetHost<ReferencesAndMasterDetailHost>('ReferencesAndMasterDetailFacet');
74+
export const registrationHost = new FacetHost<RegistrationHost>('RegistrationFacet');
75+
export const secretsAndRoutingHost = new FacetHost<SecretsAndRoutingHost>('SecretsAndRoutingFacet');
76+
export const securityResolversHost = new FacetHost<SecurityResolversHost>('SecurityResolversFacet');
77+
export const summariesAndExpansionHost = new FacetHost<SummariesAndExpansionHost>('SummariesAndExpansionFacet');
78+
export const transactionsSectionHost = new FacetHost<TransactionsSectionHost>('TransactionsSectionFacet');

‎packages/objectql/src/engine-find.ts‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616
* docblock on the class, the contract; a private method's docblock moved here
1717
* with its body. The state stays on `ObjectQL`.
1818
*
19-
* The bodies reach the class through {@link FindHost}: exactly the
20-
* `ObjectQL` members they read, private ones included. Each stub hands its
21-
* body one literal of the members that body reads, plus a `.call`: methods go
22-
* as closures that call them on the engine at call time, so a subclass
23-
* override or an instance spy is still the one reached; fields and accessors
24-
* go as GETTERS, read when the body reads them, as they were on the class,
25-
* and a field a body assigns goes with a SETTER that assigns it on the engine.
19+
* The bodies reach the class through {@link FindHost}: exactly the `ObjectQL`
20+
* members they read, private ones included. Every stub hands its body, by a
21+
* `.call`, the same host: `findHost` in `engine-facet-hosts.ts`, built once per
22+
* engine by the class's static block. Methods go as closures that call them on
23+
* the engine at call time, so a subclass override or an instance spy is still
24+
* the one reached; fields and accessors go as GETTERS, read when the body reads
25+
* them, as they were on the class, and a field a body assigns goes with a
26+
* SETTER that assigns it on the engine.
2627
*
2728
* The module imports `engine.ts` for types only, so the two modules form no
2829
* evaluation cycle. `index.ts` re-exports nothing from this module.

‎packages/objectql/src/engine-hooks-and-functions.ts‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@
2121
* with its body. The state stays on `ObjectQL`.
2222
*
2323
* The bodies reach the class through {@link HooksAndFunctionsHost}: exactly the
24-
* `ObjectQL` members they read, private ones included. Each stub hands its
25-
* body one literal of the members that body reads, plus a `.call`: methods go
26-
* as closures that call them on the engine at call time, so a subclass
27-
* override or an instance spy is still the one reached; fields and accessors
28-
* go as GETTERS, read when the body reads them, as they were on the class,
29-
* and a field a body assigns goes with a SETTER that assigns it on the engine.
24+
* `ObjectQL` members they read, private ones included. Every stub hands its
25+
* body, by a `.call`, the same host: `hooksAndFunctionsHost` in
26+
* `engine-facet-hosts.ts`, built once per engine by the class's static block.
27+
* Methods go as closures that call them on the engine at call time, so a
28+
* subclass override or an instance spy is still the one reached; fields and
29+
* accessors go as GETTERS, read when the body reads them, as they were on the
30+
* class, and a field a body assigns goes with a SETTER that assigns it on the
31+
* engine.
3032
*
3133
* The module imports `engine.ts` for types only, so the two modules form no
3234
* evaluation cycle. `index.ts` re-exports nothing from this module.

‎packages/objectql/src/engine-insert.ts‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
* docblock on the class, the contract; a private method's docblock moved here
1616
* with its body. The state stays on `ObjectQL`.
1717
*
18-
* The bodies reach the class through {@link InsertHost}: exactly the
19-
* `ObjectQL` members they read, private ones included. Each stub hands its
20-
* body one literal of the members that body reads, plus a `.call`: methods go
21-
* as closures that call them on the engine at call time, so a subclass
22-
* override or an instance spy is still the one reached; fields and accessors
23-
* go as GETTERS, read when the body reads them, as they were on the class,
24-
* and a field a body assigns goes with a SETTER that assigns it on the engine.
18+
* The bodies reach the class through {@link InsertHost}: exactly the `ObjectQL`
19+
* members they read, private ones included. Every stub hands its body, by a
20+
* `.call`, the same host: `insertHost` in `engine-facet-hosts.ts`, built once
21+
* per engine by the class's static block. Methods go as closures that call them
22+
* on the engine at call time, so a subclass override or an instance spy is
23+
* still the one reached; fields and accessors go as GETTERS, read when the body
24+
* reads them, as they were on the class, and a field a body assigns goes with a
25+
* SETTER that assigns it on the engine.
2526
*
2627
* The module imports `engine.ts` for types only, so the two modules form no
2728
* evaluation cycle. `index.ts` re-exports nothing from this module.

‎packages/objectql/src/engine-middleware-and-context.ts‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@
2020
* docblock on the class, the contract; a private method's docblock moved here
2121
* with its body. The state stays on `ObjectQL`.
2222
*
23-
* The bodies reach the class through {@link MiddlewareAndContextHost}: exactly the
24-
* `ObjectQL` members they read, private ones included. Each stub hands its
25-
* body one literal of the members that body reads, plus a `.call`: methods go
26-
* as closures that call them on the engine at call time, so a subclass
27-
* override or an instance spy is still the one reached; fields and accessors
28-
* go as GETTERS, read when the body reads them, as they were on the class,
29-
* and a field a body assigns goes with a SETTER that assigns it on the engine.
23+
* The bodies reach the class through {@link MiddlewareAndContextHost}: exactly
24+
* the `ObjectQL` members they read, private ones included. Every stub hands its
25+
* body, by a `.call`, the same host: `middlewareAndContextHost` in
26+
* `engine-facet-hosts.ts`, built once per engine by the class's static block.
27+
* Methods go as closures that call them on the engine at call time, so a
28+
* subclass override or an instance spy is still the one reached; fields and
29+
* accessors go as GETTERS, read when the body reads them, as they were on the
30+
* class, and a field a body assigns goes with a SETTER that assigns it on the
31+
* engine.
3032
*
3133
* The module imports `engine.ts` for types only, so the two modules form no
3234
* evaluation cycle. `index.ts` re-exports nothing from this module.

0 commit comments

Comments
 (0)