@omgbase/oqx 0.24.0 → 0.26.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +267 -202
  3. package/dist/ast.d.ts +19 -1
  4. package/dist/ast.d.ts.map +1 -1
  5. package/dist/ast.js.map +1 -1
  6. package/dist/build.d.ts +3 -1
  7. package/dist/build.d.ts.map +1 -1
  8. package/dist/build.js +4 -2
  9. package/dist/build.js.map +1 -1
  10. package/dist/engine.d.ts +2 -0
  11. package/dist/engine.d.ts.map +1 -1
  12. package/dist/engine.js +95 -44
  13. package/dist/engine.js.map +1 -1
  14. package/dist/optimize/analysis.d.ts +3 -2
  15. package/dist/optimize/analysis.d.ts.map +1 -1
  16. package/dist/optimize/analysis.js +12 -2
  17. package/dist/optimize/analysis.js.map +1 -1
  18. package/dist/optimize/ir.d.ts +4 -1
  19. package/dist/optimize/ir.d.ts.map +1 -1
  20. package/dist/optimize/ir.js +1 -0
  21. package/dist/optimize/ir.js.map +1 -1
  22. package/dist/optimize/rules.d.ts.map +1 -1
  23. package/dist/optimize/rules.js +3 -2
  24. package/dist/optimize/rules.js.map +1 -1
  25. package/dist/parser.d.ts.map +1 -1
  26. package/dist/parser.js +206 -42
  27. package/dist/parser.js.map +1 -1
  28. package/dist/print.d.ts +2 -2
  29. package/dist/print.d.ts.map +1 -1
  30. package/dist/print.js +88 -25
  31. package/dist/print.js.map +1 -1
  32. package/dist/references.d.ts.map +1 -1
  33. package/dist/references.js +39 -1
  34. package/dist/references.js.map +1 -1
  35. package/dist/resolve.d.ts.map +1 -1
  36. package/dist/resolve.js +9 -2
  37. package/dist/resolve.js.map +1 -1
  38. package/dist/version.d.ts +1 -1
  39. package/dist/version.js +1 -1
  40. package/dist/walk.d.ts +1 -1
  41. package/dist/walk.d.ts.map +1 -1
  42. package/dist/walk.js +5 -0
  43. package/dist/walk.js.map +1 -1
  44. package/package.json +1 -1
  45. package/src/ast.ts +20 -1
  46. package/src/build.ts +5 -3
  47. package/src/engine.ts +89 -39
  48. package/src/optimize/analysis.ts +9 -2
  49. package/src/optimize/ir.ts +5 -1
  50. package/src/optimize/rules.ts +3 -2
  51. package/src/parser.ts +193 -41
  52. package/src/print.ts +92 -30
  53. package/src/references.ts +34 -2
  54. package/src/resolve.ts +10 -3
  55. package/src/version.ts +1 -1
  56. package/src/walk.ts +6 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@ All notable changes to `@omgbase/oqx` are recorded here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
5
5
  [Semantic Versioning](https://semver.org/) (pre-1.0: a minor bump may break).
6
6
 
7
+ ## [0.26.0] - 2026-10-22
8
+
9
+ ### Minor
10
+ - **OQX 0.26 — collection-scoped queries** (`spec/oqx` 0.25 → 0.26; new suite `collection-scoped`, 28 cases: 1498 → 1526 fixtures). A query names its source as the collection before its body — `modules { select id, name where id == "launch" follow distinct ^modules { where id in ^needs depth 2 } order by $depth, name }` — instead of a `from` clause inside it. The form is the 0.17 receiver block with the implicit `collect`, so it parses to the identical tree and nothing in evaluation, planning, scoping or the AST changed; what moved is what is canonical. GRAMMAR §2 now leads with `<collection> [<consumer>] [distinct] { body }`; a body never names its source (the receiver supplied the rows), so `from E` inside a body keeps its one meaning, the re-projection (`people count { from jobs where !end }`, `follow _out_links { from _dst }`); the clause form `select … from S …` stays an accepted legacy spelling of the same tree and is no longer written anywhere. **The canonical printer** (AST.md §6) writes every query whose source can head a block collection-scoped and `collect` as the bare brace (`x collect { … }` → `x { … }`, `x collect distinct { … }` → `x distinct { … }`, the projection leading without `select`; a `collect` over a directive receiver keeps the word, `jobs first { offset 0 } collect { … }`; a literal, range, operator or aggregate source still prints in the clause form) — so `references` steps print `follow kids { … }`. The source hints were reworded (`a query must name its source before its body: \`<collection> { … }\` …`; the top-level predicate error points at `<collection> { <predicate> }`). Two more sugars desugar in the parser (suite `directive-sugar`, 28 cases): **a consumer word with no block is the directive over the empty block** — `people count`, `jobs first.employer`, `_nodes exists`, `jobs count distinct >= 1`, `follow kids first` — since a consumer word right after a complete receiver can be nothing else (the printer writes the braceless form whenever the word is written and the block is empty; the clause form's top-level `from people count` keeps its whole-query hint); and **a projection-only block over a lookup is the lookup's projection** — `jobs[0] { name }` ≡ `jobs first { name offset 0 }`, `jobs[p] { name }` ≡ `jobs first { name where p }` — refused when the outer block carries a clause of its own (it runs after the pick), when the inner directive is `distinct`, or when an outer alias would shadow a name the inner `where` reads; one consequence: `jobs[0] { name }` over no jobs is now `null` (`first` of none) where the two-directive tree gave `[]`. And **`follow` is legal in every body**: a where-position directive's block yields its walk's occurrences for the consumer to reduce (`children count { follow children } > 2`, `children { ^desc: id follow children }`; `exists`/`none` over a walk are the seeds' existence) — through 0.25 it was the eval error `` `follow` is only valid on a select-position collect ``; both engines route every consumer through one row path, so the walk, `flatten`, `group by`, ordering, `distinct` and the bound apply alike. `LANGUAGE_VERSION` 0.26 in both implementations and in `@omgbase/oqx-syntax` (assets regenerated; no lexical change — `from` stays reserved).
11
+
12
+ - omgbase surface (patch, both engines): the `query_syntax` card and manual teach the collection-scoped form (byte-identical in TS and Rust), the tool descriptions' examples and the `omg query` help examples are respelled, the `graph` macro's `queries` text prints collection-scoped (`docs { … follow distinct _out_links { from _dst depth 2 } }`), the selector's root error reads `` `docs { … }`, `blocks { … }` or `nodes { … }` ``, the selector's expression wrapper is `docs { select __omg_x: <e> }` (a malformed slot now reports `unexpected '}'` where the leaked `from` was); `spec/surface` fixtures regenerated (`reads`, `examples`, `interop`, `tool-descriptions`), `spec/cli` `invoke` regenerated. `@omgbase/dataview` emits `<source> { select … }`. Documentation, READMEs and every example converted.
13
+
14
+ ## [0.25.0] - 2026-10-16
15
+
16
+ ### Minor
17
+ - **OQX 0.25 — `flatten`** (`spec/oqx` 0.24 → 0.25; new suite `flatten` (74 cases): 1473 → 1547 fixtures; every `expect.ast` body gains `flatten: []`). The clause order gains `flatten <expr> [{ … }] [as <name>]` after `follow` and before `group by` (`select from where frontier follow flatten group by having order by limit offset`) — the one clause that may repeat, each fanning out the rows the previous produced. **Semantics** (SEMANTICS §25): the expression is read on each row like `where` and its value split by §3's coercion with one softening — an array → one row per element in collection order (an empty one yields none), an object → one row, absent → one row with the name absent (Dataview's rule: a missing field never drops the row), a scalar → one row with the scalar (not the §3 error: nothing is sourced from it). A written block is the receiver-block sugar — the `collect` op over the value, applied first (`flatten tags { where $it != "b" } as t`, `flatten jobs distinct { employer values order by pay desc limit 1 } as j`) — so a block that filters every element away yields no row for that parent and everything a select-position block admits is admitted. Each output row IS the parent row with the name bound at the same scope depth beside the lifts (step 4 of §2: it shadows a same-named property; `flatten tags` rebinds `tags`, `flatten tags as t` keeps the list), read by a later `flatten`, `group by` (a bound name is a key), `having`, the projection, `order by`, a template literal, `^name` from a nested block; `where`/`frontier` run before the fan-out and a `select` alias is not substituted into the expression (as into `order by`). Identity (§16): a flattened row's `$key` is the pair `[parent identity, element identity]` (an element's own `$key` when it is a row or an entry, else its structural value), nested by a chained flatten — what `distinct`, `is` and `follow` compare. Output order is parent order then element order; `order by`, the bounds and every consumer apply to the flattened rows; a single receiver fanned out is plural. **Grammar**: `as <name>` is required unless the expression is a plain navigation (its last segment is the name); `flatten`/`as` are contextual words; the parse errors — `` needs a name (`flatten size(tags) as <name>`) ``, `` duplicate flatten name 't' ``, `` expected a name after `as` ``, a literal word / `$`-name after `as`, `` is an aggregate and cannot be read in `flatten` ``, the clause-order sentence naming `flatten`. **AST** (AST.md): the `flatten` node `{ expr, name }` (`name` always filled; no block field — the block is the `op`), `query.flatten`/`subquery.flatten` (`[]` when none), `CHILDREN` visits it after `follow` (clause `flatten`, the row depth); `print` writes every flatten with `as` (`flatten tags as tags`), so the round-trip law holds; `references` (§5b) reports the expression in clause `flatten` on the rows and the names inside a block on the block receiver's step, and treats a bound name read after its clause as an alias (not a reference), like a lift; `build.flatten(expr, name)`. Engine: `flattenScopes` on every path (top level, walks, blocks); the fast paths (`exists`/`count` short-circuit, the `first` cap, cardinality-only blocks) step aside under `flatten`; `optimized ≡ naive` holds over every fixture. `LANGUAGE_VERSION` 0.25.
18
+ - `@omgbase/oqx-syntax`: `LANGUAGE_VERSION` 0.25; `flatten` highlighted as a clause when a value can follow, `as` as the binder before a plain name; `flatten`/`as` join the contextual words; assets regenerated; parity over every fixture.
19
+
7
20
  ## [0.24.0] - 2026-10-15
8
21
 
9
22
  ### Minor