From 17dd8aa52cdfae7708242205c3b2b203b2798be9 Mon Sep 17 00:00:00 2001
From: Eyal Alon <3756641+soyeyalon@users.noreply.github.com>
Date: Thu, 5 Nov 2026 05:59:49 +0200
Subject: [PATCH 01/13] chore(domql): enter the preview
DOMQL follows FormaUI Versioning v1.0.0-preview.1, whose stages are
preview, release candidate and stable. Its first release leaves the
beta: the runtime and the specification, both unreleased, take
1.0.0-preview.1, which orders after every beta, with the beta's
promise, and so do the changelog's and the version history's
unreleased entries, as D106 records.
---
CHANGELOG.md | 10 +++++-----
CLAUDE.md | 4 ++--
CONTRIBUTING.md | 2 +-
README.md | 2 +-
SECURITY.md | 2 +-
VERSION-HISTORY.md | 6 +++---
docs/decisions.md | 18 ++++++++++++++++--
docs/domql-design.md | 2 +-
docs/features-status.md | 29 +++++++++++++++--------------
nuget/README.md | 2 +-
spec/README.md | 4 ++--
src/Versions.mjs | 4 ++--
12 files changed, 50 insertions(+), 35 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a3c3e83..8986040 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,14 +5,14 @@ Each release of DOMQL's packages, newest first. The NuGet package `formaui-net.D
- **An entry is dated when its release is cut,** and reads *Unreleased* until then. [Cutting a release](CONTRIBUTING.md#cut-a-release) tags its commit, and its packages are published from that tag.
- **A change a caller can notice** is listed in the newest entry while it is unreleased. Once it is released, the change opens the next version's entry, and the sources declare that version in the same commit.
-
+
-## `1.0.0-beta.1`
+## `1.0.0-preview.1`
-*Unreleased · specification `1.0.0-beta.2` · Nexo language `1.0.0-beta.41` · definition format 38*
+*Unreleased · specification `1.0.0-preview.1` · Nexo language `1.0.0-beta.41` · definition format 38*
-- The first beta, and the first release. The [version history](VERSION-HISTORY.md) records what came before it.
-- Runs on Nexo's language `1.0.0-beta.41`, from Nexo's release `1.0.0-beta.2`, as the [version history](VERSION-HISTORY.md#v1-0-0-beta-2) sets out: `and` and `or` typed where their value is used, a selection into a dictionary's `entries` and a pair's `key` and `value`, a module's maintained members declaring nullable results, and the members that make a value of their receiver called as functions, `round()` and `trim()` among them, among the rest.
+- The first preview, and the first release, as [FormaUI Versioning's stages](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/versions.md#stages) name it: the runtime and the specification take `1.0.0-preview.1`, with the beta's promise. The [version history](VERSION-HISTORY.md) records what came before it.
+- Runs on Nexo's language `1.0.0-beta.41`, from Nexo's release `1.0.0-beta.2`, as the [version history](VERSION-HISTORY.md#v1-0-0-preview-1) sets out: `and` and `or` typed where their value is used, a selection into a dictionary's `entries` and a pair's `key` and `value`, a module's maintained members declaring nullable results, and the members that make a value of their receiver called as functions, `round()` and `trim()` among them, among the rest.
- Each state DOMQL declares is a Boolean property, read without a call, `it.checked`, where it was a function, `it.checked()`. An element's `hover` and `focus`, the document's `focus`, and the window's `share` and `clipboard` are `hovered`, `focused`, `canShare` and `hasClipboard`.
- Each built-in execution is named by its verb: `takeFocus`, `writeClipboard`, `readClipboard`, `writeValue` and `writeSelection` are `focus`, `writeToClipboard`, `readFromClipboard`, `replaceValue` and `select`, and `writeMuted(muted)` and `writeIndeterminate(indeterminate)` are `mute()` and `unmute()`, and `markIndeterminate()` and `clearIndeterminate()`.
- A watch of `focused`, `focusWithin`, `activeElement` or a selector testing focus follows the focus moving inside an open shadow root, and the focused element removed, in every engine.
diff --git a/CLAUDE.md b/CLAUDE.md
index a06c2d4..b88f242 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -107,8 +107,8 @@ The specification states the contract; the design explains how DOMQL is built to
Use these version rules:
- Each version is a literal in `src/Versions.mjs`, its one source, declared and never computed; the numbers may coincide, and neither determines another.
-- Runtime version: `Versions.runtime`, `1.0.0-beta.N`, numbered on from `1.0.0-beta.1`. It is the version due at the next release, and advances once a release is cut, when the next change a caller can notice opens the next entry of the [changelog](CHANGELOG.md). The package project reads it, the bundle carries it, and `domql.info.versions.runtime` reports it, from the sources as from any build. Packing rejects a bundle of another version.
-- Specification version: `Versions.specification`, DOMQL's own, `1.0.0-beta.N`, numbered on from `1.0.0-beta.1`, advanced at most once per release, for the changes to DOMQL's contract made since the release before it, never following the runtime version. The specification and design titles name the version the specification describes; `domql.info.versions.specification` reports, and the status names, the version the implementation follows, which may trail the titles while the specification moves ahead.
+- Runtime version: `Versions.runtime`, numbered by [FormaUI Versioning's stages](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/versions.md#stages), `1.0.0-preview.N` from `1.0.0-preview.1`. It is the version due at the next release, and advances once a release is cut, when the next change a caller can notice opens the next entry of the [changelog](CHANGELOG.md). The package project reads it, the bundle carries it, and `domql.info.versions.runtime` reports it, from the sources as from any build. Packing rejects a bundle of another version.
+- Specification version: `Versions.specification`, DOMQL's own, numbered by [the same stages](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/versions.md#stages), `1.0.0-preview.N` from `1.0.0-preview.1`, advanced at most once per release, for the changes to DOMQL's contract made since the release before it, never following the runtime version. The specification and design titles name the version the specification describes; `domql.info.versions.specification` reports, and the status names, the version the implementation follows, which may trail the titles while the specification moves ahead.
- Language version: `Versions.language`, which `domql.info.versions.language` reports, is the language specification version the Nexo runtime DOMQL runs on follows, read from `nexo.info.versions.language`, never maintained here.
- Preserve the version-alignment test, which checks these relationships without requiring the versions to match, and holds the changelog's newest entry and both READMEs to the versions the sources declare.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 390fde5..83f6c89 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -54,7 +54,7 @@ The [Nexo specification](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec
Keep each change focused, and follow the surrounding code's conventions. Use `.editorconfig` for formatting and style.
-Since DOMQL entered its beta, two rules hold for a change its callers can notice:
+Since DOMQL's beta, two rules hold for a change its callers can notice:
- **A break says how to migrate.** A version that breaks what the one before it allowed says how to migrate, beside the break, in its entry in the [version history](VERSION-HISTORY.md).
- **A change a caller can notice is listed** in the [changelog](CHANGELOG.md), by its rules.
diff --git a/README.md b/README.md
index 2abd877..88bef8d 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
DOMQL is a JavaScript library for querying the DOM, allowing you to read information from a document once or observe it as it changes. Its queries are written in [Nexo](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md).
-> **Beta.** No breaking redesign is planned, and a version that breaks what the one before it allowed says how to migrate. The runtime, `1.0.0-beta.1`, implements DOMQL's specification `1.0.0-beta.2` on Nexo's language `1.0.0-beta.41`, definition version 38. DOMQL declares the DOM as types of its own. It is not yet published to npm or NuGet; you can [build and try it locally](#build-and-try-it). See [the status overview](docs/features-status.md), and [what 1.0 requires](docs/features-status.md#what-1-0-requires).
+> **Preview.** No breaking redesign is planned, and a version that breaks what the one before it allowed says how to migrate. The runtime, `1.0.0-preview.1`, implements DOMQL's specification `1.0.0-preview.1` on Nexo's language `1.0.0-beta.41`, definition version 38. DOMQL declares the DOM as types of its own. It is not yet published to npm or NuGet; you can [build and try it locally](#build-and-try-it). See [the status overview](docs/features-status.md), and [what 1.0 requires](docs/features-status.md#what-1-0-requires).
## Features
diff --git a/SECURITY.md b/SECURITY.md
index 045f5a3..a5e65ca 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -13,7 +13,7 @@ We will reply after reviewing your report. Reports remain private until a fix is
## Supported versions
-DOMQL is in beta. Only the latest version receives fixes.
+DOMQL is in preview. Only the latest version receives fixes.
## Scope
diff --git a/VERSION-HISTORY.md b/VERSION-HISTORY.md
index 48e983a..586249a 100644
--- a/VERSION-HISTORY.md
+++ b/VERSION-HISTORY.md
@@ -3,7 +3,7 @@
Each version of DOMQL, newest first, with the features it added and what it changed. A version names DOMQL's contract, its [specification](spec/README.md): the DOM's vocabulary, the module that declares it, and DOMQL as the host that carries queries out. The language is Nexo's, called Lexica before `1.0.0-alpha.278`, so each entry also names the language version and definition format it describes.
- **A version collects the changes made between two releases.** The first change to DOMQL's contract after a [release](CHANGELOG.md) opens the next version's entry, which reads *Unreleased*, and each later change joins it. The release that first implements the version dates it, and fixes it.
-- **Versions before `1.0.0-beta.2` advanced with each change,** before DOMQL's first release, each dated by the day the specification first described it.
+- **Versions before `1.0.0-preview.1` advanced with each change,** before DOMQL's first release, each dated by the day the specification first described it.
- **A change stands in the first version whose implementation follows it.**
- **From `1.0.0-beta.1` on, an entry leads with examples** of what its version changed: a query's in a `domql` block, a caller's or a module's in a `js` block, each line's comment saying what it does at that version and what it did before. The list below them is the reference. A version the specification describes ahead of the implementation says so, and says which of its changes the implementation has already.
@@ -13,9 +13,9 @@ Each entry says what its version breaks:
- **From `1.0.0-beta.1` until the first release candidate,** a decision may be replaced where a demonstrated fault, an ambiguous contract or a measured cost justifies it, whether or not Forma has met it, as [D100](docs/decisions.md#d100) records. A version that breaks what the one before it allowed says, beside each break, how a query, a caller or a module migrates.
- **From `1.0.0-rc.1` on,** nothing breaks before 2.0.
-
+
-## `1.0.0-beta.2`
+## `1.0.0-preview.1`
*Unreleased · Nexo language `1.0.0-beta.41` · definition format 38*
diff --git a/docs/decisions.md b/docs/decisions.md
index 1471fd9..69a0b62 100644
--- a/docs/decisions.md
+++ b/docs/decisions.md
@@ -1176,7 +1176,7 @@ Each entry is one of three kinds:
- **Why:**
- Nexo's maintenance sweep, its `1.0.0-beta.21` to `1.0.0-beta.40`, fixed faults a query and a module could meet: stack overflows, a hang, unsound typing of `Any`, and texts that read otherwise than they were written.
- A selection checks its path with Nexo's `typeAt` and reads it with `valueAt`, which now step into the form a result holds a dictionary or a pair in, so a selection reaches every part a result holds.
- - Each break the move brings is one a beta allows with guidance: the [version history](../VERSION-HISTORY.md#v1-0-0-beta-2) gives each its migration.
+ - Each break the move brings is one a beta allows with guidance: the [version history](../VERSION-HISTORY.md#v1-0-0-preview-1) gives each its migration.
- **Declined:**
- Staying on `1.0.0-beta.20`, which would keep the faults the sweep fixed.
- Refusing a path into a dictionary or a pair in DOMQL's own check, as the specification said. A result holds them as `entries` and `key` and `value`, as a change set addresses them, so a selection that can't reach them would be the one operation that can't.
@@ -1361,7 +1361,7 @@ Each entry is one of three kinds:
- The owner's call, following Nexo's: a state is something the receiver is in, and `checked()` read as though checking were done.
- A state was a function only so a query could pass it by reference, `where(Domql.checked)`, where a body reads as well, `where(it.checked)`.
- Each new name says what the property reads. `hover` and `focus` are verbs, and `focus` names the execution that moves focus, which [D88](#d88) gives it. `share` and `clipboard` named the API, where the property says whether the window can share or has a clipboard.
- - Nexo's NEXO3017 writes the property to read where a query calls one, so each query that breaks is told what to write, and the [version history](../VERSION-HISTORY.md#v1-0-0-beta-2) says how to migrate.
+ - Nexo's NEXO3017 writes the property to read where a query calls one, so each query that breaks is told what to write, and the [version history](../VERSION-HISTORY.md#v1-0-0-preview-1) says how to migrate.
- **Declined:**
- Keeping the functions beside the properties, which would give one state two members.
- Keeping the old names as properties, `it.hover` and `it.focus`, which read as verbs, and where `focus` is the name the execution that moves focus takes.
@@ -1612,3 +1612,17 @@ Each entry is one of three kinds:
- **Decision:** Where one subscription hears an occurrence, `deliver` answers that subscription's acknowledgment itself, fulfilled with nothing as the occurrence is applied or rejected with its failure, as joining it alone with `Promise.all` would. Two or more are still joined.
- **Why:** A review's workload found the join costing about 13 to 15% of an occurrence one subscription hears, the most common delivery.
- **Measured** in five paired rounds against the commit before it, in Chromium: a move one subscription hears 3.00 → 2.38 µs and 2,938 → 2,493 bytes, one delivered as it is 2.25 → 1.75 µs, one with a slow handler 3.83 → 3.30 µs; four subscriptions unchanged, within the noise, and so are the acknowledgments outstanding and the memory retained.
+
+
+
+## D106 — DOMQL leaves the beta for the preview
+
+*November 5, 2026*
+
+- **Kind:** Process, approved.
+- **Decision:** DOMQL follows [FormaUI Versioning `v1.0.0-preview.1`](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/README.md), whose [stages](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/versions.md#stages) are preview, release candidate and stable. Its first release leaves the beta: the runtime, `1.0.0-beta.1`, and the specification, `1.0.0-beta.2`, both unreleased, take `1.0.0-preview.1`, which SemVer orders after every beta, and so do the changelog's and the version history's unreleased entries. Later previews number on from it, `1.0.0-preview.N`.
+- **Why:**
+ - The owner's call: every FormaUI project versions by one set of rules, and those rules name no beta.
+ - The preview's promise is the beta's, as [D75](#d75) and [D100](#d100) set it: a decision may be replaced until `1.0.0-rc.1`, a break says how to migrate, and from `1.0.0-rc.1` on nothing breaks before 2.0. Only the name changes.
+ - DOMQL has never been released, so no tag or published version carries a beta.
+- **Declined:** Keeping the betas until the release candidate, which would leave DOMQL outside the rules Nexo and Forma follow.
diff --git a/docs/domql-design.md b/docs/domql-design.md
index 96e5d5b..59b0367 100644
--- a/docs/domql-design.md
+++ b/docs/domql-design.md
@@ -1,4 +1,4 @@
-# DOMQL Design v1.0.0-beta.2
+# DOMQL Design v1.0.0-preview.1
The [DOMQL specification](../spec/README.md) is the contract: DOMQL's module, which declares the DOM as Nexo's domain, and the host that carries queries out against a document. This design sets out how this implementation is built to meet it, and the reasons behind the choices that shape it. It describes DOMQL's version `1.0.0-beta.2` on Nexo's definition version 38, as the specification does, and an outline of the C# half, which waits for its design; [the status overview](features-status.md) says where the implementation still differs. [Nexo's design](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/nexo-design.md), at the release DOMQL builds against, sets out how the language and its runtime are built.
diff --git a/docs/features-status.md b/docs/features-status.md
index 8bfedc1..305103a 100644
--- a/docs/features-status.md
+++ b/docs/features-status.md
@@ -2,16 +2,16 @@
## Current state
-**DOMQL is in its beta, `1.0.0-beta.1`. Its vocabulary, queries, watches, events, executions and behaviors are implemented on Nexo's language `1.0.0-beta.41`, definition version 38. The specification describes DOMQL's `1.0.0-beta.2`, which the implementation follows: the DOM declared as DOMQL's own types, read through the `Domql` module every query imports. Every [planned capability](#planned-capabilities) is implemented or declined but the C# half's, A1 and A5's queue, which wait for its design.**
+**DOMQL is in its preview, `1.0.0-preview.1`. Its vocabulary, queries, watches, events, executions and behaviors are implemented on Nexo's language `1.0.0-beta.41`, definition version 38. The specification describes DOMQL's `1.0.0-preview.1`, which the implementation follows: the DOM declared as DOMQL's own types, read through the `Domql` module every query imports. Every [planned capability](#planned-capabilities) is implemented or declined but the C# half's, A1 and A5's queue, which wait for its design.**
| Version | Implementation | Specification |
| --- | --- | --- |
-| DOMQL specification | `1.0.0-beta.2` | `1.0.0-beta.2` |
+| DOMQL specification | `1.0.0-preview.1` | `1.0.0-preview.1` |
| Nexo language | `1.0.0-beta.41` | `1.0.0-beta.41` |
| Definition format | 38 | 38 |
- **The language DOMQL runs on.** DOMQL follows Nexo's language `1.0.0-beta.41`, which Nexo's release `1.0.0-beta.2` carries, so it builds against that release once `nexo.release` pins it, through a checkout `NEXO_SOURCE` names until then; `nexo.release` pins `1.0.0-beta.1` now, of language `1.0.0-beta.40`, and its documents link to [Nexo's documents at that tag](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md), moving with the pin. The language was called Lexica before the [migration](#migration-to-nexo).
-- **Packages.** The bundle and type declarations are built, with Nexo bundled inside `domql.js`. The NuGet package is packed locally, carrying the runtime version `1.0.0-beta.1`, and is unpublished. The npm package is not made yet: `package.json` is private and carries no version.
+- **Packages.** The bundle and type declarations are built, with Nexo bundled inside `domql.js`. The NuGet package is packed locally, carrying the runtime version `1.0.0-preview.1`, and is unpublished. The npm package is not made yet: `package.json` is private and carries no version.
- **The C# half** waits for its design, as [D46](decisions.md#d46) records.
The [specification](../spec/README.md) defines the contract, and the [design](domql-design.md) explains the architecture. The [version history](../VERSION-HISTORY.md) records what each version changed, and the [changelog](../CHANGELOG.md) each release of the packages. This file tracks DOMQL's implementation and its remaining work. "Implemented" means built and tested in the gate for the current implementation version; it does not imply that later specification changes are implemented.
@@ -24,7 +24,7 @@ The [specification](../spec/README.md) defines the contract, and the [design](do
| --- | --- |
| [The C# half](#the-c-half) | Waits for its design |
| [Planned capabilities](#planned-capabilities) | The C# half's alone remain, waiting for its design |
-| [Release](#release) | The beta is declared; publishing waits for Nexo's published packages |
+| [Release](#release) | The preview is declared, `1.0.0-preview.1`, DOMQL's first release; it waits for Nexo's first preview, which it builds against |
| [What 1.0 requires](#what-1-0-requires) | Six requirements, one met in part |
- **A specification version collects the changes between two releases.** A change to DOMQL's contract joins the [version history](../VERSION-HISTORY.md)'s newest entry while it reads *Unreleased*, and opens the next version's entry once it is released, as [D79](decisions.md#d79) records.
@@ -47,7 +47,7 @@ Each feature, the contract that states it, its state in the implementation, and
| Properties, functions and indexers of the DOM | [Built-in vocabulary](../spec/vocabulary.md) | Implemented | [Before `alpha.275`](../VERSION-HISTORY.md#before-1-0-0-alpha-275) |
| Nexo's indexer forms and type names in PascalCase | [Types](../spec/vocabulary.md#vocabulary-types) | Implemented | [`alpha.277`](../VERSION-HISTORY.md#v1-0-0-alpha-277) |
| `Domql.document` and `Domql.window` | [Module members](../spec/vocabulary.md#module-members) | Implemented | [`alpha.278`](../VERSION-HISTORY.md#v1-0-0-alpha-278) |
-| States, each a Boolean property read without a call, with `hovered`, `focused`, `canShare` and `hasClipboard` | [States](../spec/vocabulary.md#states) | Implemented, as Boolean properties since [D87](decisions.md#d87) | [`alpha.276`](../VERSION-HISTORY.md#v1-0-0-alpha-276), [`beta.2`](../VERSION-HISTORY.md#v1-0-0-beta-2) |
+| States, each a Boolean property read without a call, with `hovered`, `focused`, `canShare` and `hasClipboard` | [States](../spec/vocabulary.md#states) | Implemented, as Boolean properties since [D87](decisions.md#d87) | [`alpha.276`](../VERSION-HISTORY.md#v1-0-0-alpha-276), [`preview.1`](../VERSION-HISTORY.md#v1-0-0-preview-1) |
| Conversions, Nexo's, which DOMQL's queries use | [Built-in conversions](../spec/vocabulary.md#built-in-conversions) | Implemented | [Before `alpha.275`](../VERSION-HISTORY.md#before-1-0-0-alpha-275) |
| Observation types, shared in sessions | [Observation types](../spec/vocabulary.md#observations-types) | Implemented | [Before `alpha.275`](../VERSION-HISTORY.md#before-1-0-0-alpha-275) |
| Continuous measurement, the `frame` observation, its cost measured | [Observation types](../spec/vocabulary.md#observations-types) | Implemented, as [D56](decisions.md#d56) records | [`alpha.305`](../VERSION-HISTORY.md#v1-0-0-alpha-305) |
@@ -75,15 +75,15 @@ Each feature, the contract that states it, its state in the implementation, and
| `all`, `first`, `matches` and `closest` observing what their selector reads, the `selector` observation | [`matches`](../spec/vocabulary.md#function-element-matches), [observation types](../spec/vocabulary.md#observations-types) | Implemented | [`alpha.286`](../VERSION-HISTORY.md#v1-0-0-alpha-286) |
| An element's `sizeLimits` in pixels, and a file input's `files` | [`sizeLimits`](../spec/vocabulary.md#property-element-sizelimits), [`files`](../spec/vocabulary.md#property-element-files) | Implemented | [`alpha.285`](../VERSION-HISTORY.md#v1-0-0-alpha-285) |
| `hasPointerCapture(pointerId)` | [`hasPointerCapture`](../spec/vocabulary.md#function-element-haspointercapture) | Implemented | [`alpha.284`](../VERSION-HISTORY.md#v1-0-0-alpha-284) |
-| Owned writes beside a framework: an element's text, `ownText`, written into the node it holds, and a kept value that yields to a writer keeping its own | [Owned writes](../spec/vocabulary.md#execution-element-owned-writes), [beside a framework](../spec/vocabulary.md#execution-element-owned-writes-framework) | Implemented, as [D70](decisions.md#d70) and [D83](decisions.md#d83) record | [`alpha.315`](../VERSION-HISTORY.md#v1-0-0-alpha-315), [`beta.2`](../VERSION-HISTORY.md#v1-0-0-beta-2) |
+| Owned writes beside a framework: an element's text, `ownText`, written into the node it holds, and a kept value that yields to a writer keeping its own | [Owned writes](../spec/vocabulary.md#execution-element-owned-writes), [beside a framework](../spec/vocabulary.md#execution-element-owned-writes-framework) | Implemented, as [D70](decisions.md#d70) and [D83](decisions.md#d83) record | [`alpha.315`](../VERSION-HISTORY.md#v1-0-0-alpha-315), [`preview.1`](../VERSION-HISTORY.md#v1-0-0-preview-1) |
| A chosen file shown as an element's source, `ownFileSource`, its object URL owned and revoked | [`ownFileSource`](../spec/vocabulary.md#execution-element-ownfilesource) | Implemented, as [D44](decisions.md#d44) records | [`alpha.300`](../VERSION-HISTORY.md#v1-0-0-alpha-300) |
| Placing the document's selection, `select`, `selectContents` and `collapse` of `Domql.document.selection` | [Selection placement](../spec/vocabulary.md#execution-document-selection-placement) | Implemented, as [D43](decisions.md#d43) records | [`alpha.299`](../VERSION-HISTORY.md#v1-0-0-alpha-299) |
| `dispatch`, a custom event of the page's own, of an element, the document and the window | [`dispatch`](../spec/vocabulary.md#execution-dispatch) | Implemented, as [D42](decisions.md#d42) records | [`alpha.298`](../VERSION-HISTORY.md#v1-0-0-alpha-298) |
-| Built-in executions: focusing, `focus`, and scrolling, `scrollTo`, `scrollBy` and `scrollIntoView`, of an element and of the window | [Executions](../spec/vocabulary.md#built-in-executions) | Implemented, as [D34](decisions.md#d34) and [D35](decisions.md#d35) record, named by their verbs as [D88](decisions.md#d88) records | [`alpha.292`](../VERSION-HISTORY.md#v1-0-0-alpha-292), [`beta.2`](../VERSION-HISTORY.md#v1-0-0-beta-2) |
+| Built-in executions: focusing, `focus`, and scrolling, `scrollTo`, `scrollBy` and `scrollIntoView`, of an element and of the window | [Executions](../spec/vocabulary.md#built-in-executions) | Implemented, as [D34](decisions.md#d34) and [D35](decisions.md#d35) record, named by their verbs as [D88](decisions.md#d88) records | [`alpha.292`](../VERSION-HISTORY.md#v1-0-0-alpha-292), [`preview.1`](../VERSION-HISTORY.md#v1-0-0-preview-1) |
| An instant scroll answered as the browser's method returns, without waiting for a frame, and a scroll in a hidden document asked for as instant | [Instant scrolls](../spec/vocabulary.md#execution-scroll-instant) | Implemented, as [D67](decisions.md#d67) records | [`alpha.312`](../VERSION-HISTORY.md#v1-0-0-alpha-312) |
| Pointer capture, `capturePointer` and `releasePointer` | [`capturePointer`](../spec/vocabulary.md#execution-element-capturepointer-releasepointer) | Implemented, as [D37](decisions.md#d37) records | [`alpha.294`](../VERSION-HISTORY.md#v1-0-0-alpha-294) |
-| The browser's facilities, `writeToClipboard`, `readFromClipboard`, `download`, `print` and `requestShare`, and a media element's `play`, `pause`, `mute` and `unmute`; `readClipboardText` and `writeCookie` declined, as [D40](decisions.md#d40) and [D41](decisions.md#d41) record | [`writeToClipboard`](../spec/vocabulary.md#execution-window-writetoclipboard-readfromclipboard), [`requestShare`](../spec/vocabulary.md#execution-window-requestshare), [`play`](../spec/vocabulary.md#execution-element-play-pause-mute-unmute) | Implemented, named by their verbs as [D88](decisions.md#d88) records | [`alpha.297`](../VERSION-HISTORY.md#v1-0-0-alpha-297), [`beta.2`](../VERSION-HISTORY.md#v1-0-0-beta-2) |
-| A form control's writes, `markIndeterminate`, `clearIndeterminate`, `replaceValue` and `select`, firing no event | [`markIndeterminate`](../spec/vocabulary.md#execution-element-markindeterminate-clearindeterminate), [`replaceValue`](../spec/vocabulary.md#execution-element-replacevalue), [`select`](../spec/vocabulary.md#execution-element-select) | Implemented, as [D39](decisions.md#d39) records, named by their verbs as [D88](decisions.md#d88) records | [`alpha.296`](../VERSION-HISTORY.md#v1-0-0-alpha-296), [`beta.2`](../VERSION-HISTORY.md#v1-0-0-beta-2) |
+| The browser's facilities, `writeToClipboard`, `readFromClipboard`, `download`, `print` and `requestShare`, and a media element's `play`, `pause`, `mute` and `unmute`; `readClipboardText` and `writeCookie` declined, as [D40](decisions.md#d40) and [D41](decisions.md#d41) record | [`writeToClipboard`](../spec/vocabulary.md#execution-window-writetoclipboard-readfromclipboard), [`requestShare`](../spec/vocabulary.md#execution-window-requestshare), [`play`](../spec/vocabulary.md#execution-element-play-pause-mute-unmute) | Implemented, named by their verbs as [D88](decisions.md#d88) records | [`alpha.297`](../VERSION-HISTORY.md#v1-0-0-alpha-297), [`preview.1`](../VERSION-HISTORY.md#v1-0-0-preview-1) |
+| A form control's writes, `markIndeterminate`, `clearIndeterminate`, `replaceValue` and `select`, firing no event | [`markIndeterminate`](../spec/vocabulary.md#execution-element-markindeterminate-clearindeterminate), [`replaceValue`](../spec/vocabulary.md#execution-element-replacevalue), [`select`](../spec/vocabulary.md#execution-element-select) | Implemented, as [D39](decisions.md#d39) records, named by their verbs as [D88](decisions.md#d88) records | [`alpha.296`](../VERSION-HISTORY.md#v1-0-0-alpha-296), [`preview.1`](../VERSION-HISTORY.md#v1-0-0-preview-1) |
| Owned writes of an attribute, a class and an inline style property, `ownAttribute`, `ownClass` and `ownStyle`, each restoring and keeping its value as it says | [Owned writes](../spec/vocabulary.md#execution-element-owned-writes) | Implemented, as [D38](decisions.md#d38) records | [`alpha.295`](../VERSION-HISTORY.md#v1-0-0-alpha-295) |
| The top layer's executions, `showPopover`, `hidePopover`, `showModal` and `close` | [`showPopover`](../spec/vocabulary.md#execution-element-showpopover-hidepopover), [`showModal`](../spec/vocabulary.md#execution-element-showmodal-close) | Implemented, as [D36](decisions.md#d36) records | [`alpha.293`](../VERSION-HISTORY.md#v1-0-0-alpha-293) |
| Following a change a member misses through a body's local | [Following a change a member misses](../spec/watches.md#dependencies-following-what-a-member-misses) | Implemented | [`alpha.282`](../VERSION-HISTORY.md#v1-0-0-alpha-282) |
@@ -94,8 +94,8 @@ Each feature, the contract that states it, its state in the implementation, and
| --- | --- | --- | --- |
| Queries from text or a definition, `with`, `select` and `resolve` | [Queries](../spec/queries.md) | Implemented | [Before `alpha.275`](../VERSION-HISTORY.md#before-1-0-0-alpha-275) |
| Imports, `Domql` supplied to every query | [Its imports](../spec/queries.md#making-a-query-imports) | Implemented | [`alpha.278`](../VERSION-HISTORY.md#v1-0-0-alpha-278) |
-| A query run directly, in one call, `domql.executeAsync(text, bindings, options)` and each operation of a query object alike | [Two ways to run a query](../spec/api.md#api-two-ways-to-run-a-query) | Implemented, as [D89](decisions.md#d89) records | [`beta.2`](../VERSION-HISTORY.md#v1-0-0-beta-2) |
-| Bindings of the types a query declares, `domql.query(text, bindings, { types })` | [Declared types](../spec/queries.md#making-a-query-declared-types) | Implemented, as [D82](decisions.md#d82) records | [`beta.2`](../VERSION-HISTORY.md#v1-0-0-beta-2) |
+| A query run directly, in one call, `domql.executeAsync(text, bindings, options)` and each operation of a query object alike | [Two ways to run a query](../spec/api.md#api-two-ways-to-run-a-query) | Implemented, as [D89](decisions.md#d89) records | [`preview.1`](../VERSION-HISTORY.md#v1-0-0-preview-1) |
+| Bindings of the types a query declares, `domql.query(text, bindings, { types })` | [Declared types](../spec/queries.md#making-a-query-declared-types) | Implemented, as [D82](decisions.md#d82) records | [`preview.1`](../VERSION-HISTORY.md#v1-0-0-preview-1) |
| Evaluating once, and waiting for maintained members | [Evaluation](../spec/evaluation.md) | Implemented | [Before `alpha.275`](../VERSION-HISTORY.md#before-1-0-0-alpha-275) |
| Watches, their dependencies and partial observation | [Watches](../spec/watches.md) | Implemented | [Before `alpha.275`](../VERSION-HISTORY.md#before-1-0-0-alpha-275) |
| Snapshots, live state and change sets | [Results](../spec/results.md) | Implemented; a selection takes a dictionary or a pair whole | [Before `alpha.275`](../VERSION-HISTORY.md#before-1-0-0-alpha-275) |
@@ -130,6 +130,7 @@ Each feature, the contract that states it, its state in the implementation, and
| The element a watch's list item came from, `watch.sourceOf(...path)`, for a handler in the browser | [`sourceOf`](../spec/watches.md#watching-source-elements) | Implemented, as [D72](decisions.md#d72) records | [`alpha.317`](../VERSION-HISTORY.md#v1-0-0-alpha-317) |
| Delivery options: a delayed schedule a refresh flushes, reporting on parts, and a subscription's throttle | [The delayed schedule](../spec/watches.md#watching-delayed), [reporting on parts](../spec/results.md#results-reporting-on-parts), [throttling](../spec/events.md#events-throttling) | Implemented, as [D73](decisions.md#d73) records | [`alpha.318`](../VERSION-HISTORY.md#v1-0-0-alpha-318) |
| The beta, its promise and the changelog | [Version history](../VERSION-HISTORY.md#v1-0-0-beta-1), [changelog](../CHANGELOG.md) | Implemented, as [D75](decisions.md#d75) records | [`beta.1`](../VERSION-HISTORY.md#v1-0-0-beta-1) |
+| The preview, the beta's promise under FormaUI Versioning's name for it | [Stages](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/versions.md#stages) | Implemented, as [D106](decisions.md#d106) records | [`preview.1`](../VERSION-HISTORY.md#v1-0-0-preview-1) |
| The C# half | [Design](domql-design.md#the-c-half) | Waits for its design | — |
@@ -291,7 +292,7 @@ Needs Nexo's packages, which its [release](https://github.com/FormaUI/Nexo/blob/
**Current:**
-- **NuGet:** `./publish.ps1` packs `formaui-net.DOMQL` locally. It carries the runtime version `src/Versions.mjs` declares, `1.0.0-beta.1`, and is unpublished.
+- **NuGet:** `./publish.ps1` packs `formaui-net.DOMQL` locally. It carries the runtime version `src/Versions.mjs` declares, `1.0.0-preview.1`, and is unpublished.
- **npm:** not made yet. `package.json` is private and carries no version.
- **The gate** holds the NuGet package, both READMEs, the [changelog](../CHANGELOG.md) and `domql.info.versions` to the versions the sources declare. The sources declare the version due at the next release, so nothing advances before a release is cut, as [D75](decisions.md#d75) and [D79](decisions.md#d79) record.
@@ -302,9 +303,9 @@ Needs Nexo's packages, which its [release](https://github.com/FormaUI/Nexo/blob/
Both wait for Nexo's published packages, and publishing stays with the maintainer.
-### Beta
+### Preview
-**Done.** DOMQL entered the beta at `1.0.0-beta.1`, as [D75](decisions.md#d75) records:
+**Done.** DOMQL entered the beta at `1.0.0-beta.1`, as [D75](decisions.md#d75) records, and its first release, `1.0.0-preview.1`, leaves it for the preview, the stage [FormaUI Versioning](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/versions.md#stages) names for a contract that may still change, with the same promise, as [D106](decisions.md#d106) records:
- The documents and the module API were audited, and the behavior of a cast inside an optional enclosed access was settled.
- The specification and the runtime both took `1.0.0-beta.1`. The contract is that of `1.0.0-alpha.318`, unchanged.
diff --git a/nuget/README.md b/nuget/README.md
index fa2f167..48af815 100644
--- a/nuget/README.md
+++ b/nuget/README.md
@@ -4,7 +4,7 @@
DOMQL is a JavaScript library for querying the DOM, allowing you to read information from a document once or observe it as it changes. This guide takes you from your first query to watching results, handling events and extending the library. Its queries are written in [Nexo](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md).
-> **Beta:** no breaking redesign is planned, and a version that breaks what the one before it allowed says how to migrate. `formaui-net.DOMQL` is not yet published to NuGet. [Build the package locally](#install-and-load) to try it. The package distributes a JavaScript ES module; the API in this guide runs in JavaScript. Every example here runs on this beta. The runtime, `1.0.0-beta.1`, implements DOMQL's specification `1.0.0-beta.2` on Nexo's language `1.0.0-beta.41`, definition version 38. [The status overview](https://github.com/FormaUI/DOMQL/blob/main/docs/features-status.md) says what is implemented and what is being built.
+> **Preview:** no breaking redesign is planned, and a version that breaks what the one before it allowed says how to migrate. `formaui-net.DOMQL` is not yet published to NuGet. [Build the package locally](#install-and-load) to try it. The package distributes a JavaScript ES module; the API in this guide runs in JavaScript. Every example here runs on this preview. The runtime, `1.0.0-preview.1`, implements DOMQL's specification `1.0.0-preview.1` on Nexo's language `1.0.0-beta.41`, definition version 38. [The status overview](https://github.com/FormaUI/DOMQL/blob/main/docs/features-status.md) says what is implemented and what is being built.
## In this guide
diff --git a/spec/README.md b/spec/README.md
index d322cbd..b8ff321 100644
--- a/spec/README.md
+++ b/spec/README.md
@@ -1,4 +1,4 @@
-# DOMQL Specification v1.0.0-beta.2
+# DOMQL Specification v1.0.0-preview.1
DOMQL reads the DOM and shapes what it reads as data, keeps that data current as the document changes, delivers the page's events as data, and carries out the executions its own module and its extensions declare. Its queries are scripts written in [Nexo](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md), whose specification holds two contracts: the language's, what a script means, and the runtime's, how a host binds, resolves and evaluates a script. DOMQL declares the DOM as Nexo's domain, in a module like any other, and is the host that carries each query out against a document. It adds no language rule: a rule of the language or of its runtime is Nexo's, and this specification links to it.
@@ -6,7 +6,7 @@ This specification is the authoritative contract for DOMQL. It states what DOMQL
-**Version.** This specification describes DOMQL's version `1.0.0-beta.2`, which changes as DOMQL's contract does, apart from its runtime's version and from Nexo's language. It describes DOMQL on Nexo's language version `1.0.0-beta.41`, of [definition version 38](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md#version). An implementation says which specification it follows, and which language version its Nexo runtime follows, in `domql.info.versions`, as [the API](api.md#api-entry-points-and-operations) sets out.
+**Version.** This specification describes DOMQL's version `1.0.0-preview.1`, which changes as DOMQL's contract does, apart from its runtime's version and from Nexo's language. It describes DOMQL on Nexo's language version `1.0.0-beta.41`, of [definition version 38](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md#version). An implementation says which specification it follows, and which language version its Nexo runtime follows, in `domql.info.versions`, as [the API](api.md#api-entry-points-and-operations) sets out.
## What it covers
diff --git a/src/Versions.mjs b/src/Versions.mjs
index d267d5a..03a624b 100644
--- a/src/Versions.mjs
+++ b/src/Versions.mjs
@@ -6,10 +6,10 @@ import { nexo } from '@formaui-net/nexo';
export class Versions {
/** The runtime release version, which the package and the bundle carry. */
- static runtime = '1.0.0-beta.1';
+ static runtime = '1.0.0-preview.1';
/** The DOMQL specification version the implementation follows. */
- static specification = '1.0.0-beta.2';
+ static specification = '1.0.0-preview.1';
/** The language specification version the Nexo runtime DOMQL runs on follows, as that runtime reports it. */
static language = nexo.info.versions.language;
From 5b1b2a8abfd437209dafd88329f9c8e8cf5d17da Mon Sep 17 00:00:00 2001
From: Eyal Alon <3756641+soyeyalon@users.noreply.github.com>
Date: Thu, 5 Nov 2026 06:02:27 +0200
Subject: [PATCH 02/13] build(domql): complete the package's metadata
The NuGet package links its release notes to the changelog entry at
its tag, records its repository and commit through Source Link, ships
its symbols as a .snupkg and validates its package. It keeps the
build's global.json, which it delivered to a consumer as content, out.
---
CHANGELOG.md | 1 +
nuget/Forma.DOMQL.csproj | 12 ++++++++++++
2 files changed, 13 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8986040..4ba9367 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@ Each release of DOMQL's packages, newest first. The NuGet package `formaui-net.D
*Unreleased · specification `1.0.0-preview.1` · Nexo language `1.0.0-beta.41` · definition format 38*
- The first preview, and the first release, as [FormaUI Versioning's stages](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/versions.md#stages) name it: the runtime and the specification take `1.0.0-preview.1`, with the beta's promise. The [version history](VERSION-HISTORY.md) records what came before it.
+- The NuGet package links its release notes to its changelog entry at its tag, records its repository and commit through Source Link, and ships its symbols beside it as a `.snupkg`. It no longer holds the build's `global.json`, which it delivered to a consumer as content.
- Runs on Nexo's language `1.0.0-beta.41`, from Nexo's release `1.0.0-beta.2`, as the [version history](VERSION-HISTORY.md#v1-0-0-preview-1) sets out: `and` and `or` typed where their value is used, a selection into a dictionary's `entries` and a pair's `key` and `value`, a module's maintained members declaring nullable results, and the members that make a value of their receiver called as functions, `round()` and `trim()` among them, among the rest.
- Each state DOMQL declares is a Boolean property, read without a call, `it.checked`, where it was a function, `it.checked()`. An element's `hover` and `focus`, the document's `focus`, and the window's `share` and `clipboard` are `hovered`, `focused`, `canShare` and `hasClipboard`.
- Each built-in execution is named by its verb: `takeFocus`, `writeClipboard`, `readClipboard`, `writeValue` and `writeSelection` are `focus`, `writeToClipboard`, `readFromClipboard`, `replaceValue` and `select`, and `writeMuted(muted)` and `writeIndeterminate(indeterminate)` are `mute()` and `unmute()`, and `markIndeterminate()` and `clearIndeterminate()`.
diff --git a/nuget/Forma.DOMQL.csproj b/nuget/Forma.DOMQL.csproj
index 694a2b9..ccce226 100644
--- a/nuget/Forma.DOMQL.csproj
+++ b/nuget/Forma.DOMQL.csproj
@@ -21,10 +21,20 @@
README.md
+
+
+ true
+ true
+ snupkg
+ true
+
+
+
+
@@ -32,6 +42,8 @@
$(MSBuildProjectDirectory)\..\src\Versions.mjs
$([System.Text.RegularExpressions.Regex]::Replace($([System.IO.File]::ReadAllText('$(VersionsSource)')), '(?s)^.*runtime = \x27([^\x27]+)\x27.*$', '$1'))
$(Version)
+
+ What DOMQL $(Version) changed: https://github.com/FormaUI/DOMQL/blob/v$(Version)/CHANGELOG.md#v$(Version.Replace('.', '-'))
From 6b1ac8d717c833473a8da1d850e27451dfb27cad Mon Sep 17 00:00:00 2001
From: Eyal Alon <3756641+soyeyalon@users.noreply.github.com>
Date: Thu, 5 Nov 2026 06:05:24 +0200
Subject: [PATCH 03/13] build(domql): verify the package as installed
The full gate, ./build.ps1 -Full, runs the gate, packs the NuGet
package and its symbols into artifacts/ and verifies them. Each holds
exactly the files its list in scripts/packages names, and the package
installs outside the repository from a local feed into a web
application whose published domql.js resolves a query. It replaces
publish.ps1.
---
.gitignore | 6 +-
CLAUDE.md | 4 +-
CONTRIBUTING.md | 2 +-
README.md | 2 +-
build.ps1 | 33 ++++-
docs/features-status.md | 2 +-
nuget/Forma.DOMQL.csproj | 6 +-
nuget/README.md | 2 +-
publish.ps1 | 36 -----
scripts/Test-Packages.ps1 | 126 ++++++++++++++++++
.../packages/nuget-consumer/Consumer.csproj | 14 ++
scripts/packages/nuget-consumer/Program.cs | 4 +
scripts/packages/nuget-consumer/resolve.mjs | 13 ++
scripts/packages/nuget-symbols.files | 6 +
scripts/packages/nuget.files | 16 +++
15 files changed, 225 insertions(+), 47 deletions(-)
delete mode 100644 publish.ps1
create mode 100644 scripts/Test-Packages.ps1
create mode 100644 scripts/packages/nuget-consumer/Consumer.csproj
create mode 100644 scripts/packages/nuget-consumer/Program.cs
create mode 100644 scripts/packages/nuget-consumer/resolve.mjs
create mode 100644 scripts/packages/nuget-symbols.files
create mode 100644 scripts/packages/nuget.files
diff --git a/.gitignore b/.gitignore
index 4aef39f..b8687e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,7 +9,11 @@ nuget/bin/
nuget/obj/
artifacts/
-# The bundle that publish.ps1 makes from src/.
+# What an IDE builds of the package consumer the full gate copies out of the repository.
+scripts/packages/*/bin/
+scripts/packages/*/obj/
+
+# The bundle that build.ps1 makes from src/.
nuget/wwwroot/
# The browser CI installs for the browser tests.
diff --git a/CLAUDE.md b/CLAUDE.md
index b88f242..5e9704b 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -32,7 +32,7 @@ Use these sources rather than inventing scope, status or style rules.
| `src/dom/` | Evaluation, watches, events, executions, observations, sessions and built-in implementations |
| `src/snapshots/` | Computing, comparing, dispatching and applying snapshot updates using identity metadata; no DOM access |
| `tests/` | Tests mirroring the source folders |
-| `scripts/` | Bundling scripts |
+| `scripts/` | Bundling scripts, and the package's file lists and verification |
| `spec/` | The specification, one document per subject, indexed by `spec/README.md` |
| `docs/` | The design, the status overview and the decisions |
| `VERSION-HISTORY.md` | Each DOMQL version and what it changed |
@@ -96,7 +96,7 @@ Tests mirror `src/` under `tests/`. Layout, geometry and browser-managed state b
| `npm run scale` | `tests/` | Chromium workloads timed outside the gate, one file at a time: a watch of 1,000 to 100,000 rows, a drag through owned writes, an edit in a large editor, a behavior's deliveries and owners, and transient measurements beside many observers |
| `./build.ps1` | Repository root | Tests, bundle, package build and format check |
| `./build.ps1 -Browser` | Repository root | Gate including browser tests |
-| `./publish.ps1` | Repository root | Gate followed by package creation |
+| `./build.ps1 -Browser -Full` | Repository root | The full gate: the gate including browser tests, then the NuGet package packed and verified as consumers install it |
Every compiler warning is a build failure. Keep `*.bench.js` and `*.scale.js` beside the corresponding tests, store baselines in `.local/`, and record a measurement that decides something in the design, beside the decision it settles.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 83f6c89..83fdebf 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -94,7 +94,7 @@ A release is a signed tag on the commit that dates it. The [changelog](CHANGELOG
1. Date the changelog's newest entry by the day of the release, and the version history's newest entry where it reads *Unreleased*.
2. Pass the gate, `./build.ps1 -Browser`, and commit.
3. Tag the commit with a signed tag named for the release, as `git tag -s v1.0.0-beta.1`, and push the tag.
-4. Pack the packages from the tag with `./publish.ps1`, and publish them.
+4. Pack the packages from the tag with `./build.ps1 -Browser -Full`, which verifies them as consumers install them, and publish them.
After a release, the next change a caller can notice opens the changelog's next entry, and the next change to DOMQL's contract the version history's.
diff --git a/README.md b/README.md
index 88bef8d..51db157 100644
--- a/README.md
+++ b/README.md
@@ -113,7 +113,7 @@ Clone the repository. You'll need Node.js with npm, PowerShell and the .NET SDK
```powershell
./build.ps1 # The build and the checks
./build.ps1 -Browser # With the real-browser tests
-./publish.ps1 # A local NuGet package, in artifacts/
+./build.ps1 -Full # A local NuGet package, in artifacts/, verified as installed
```
The package supplies the bundle at `_content/domql/domql.js`, with its TypeScript declarations beside it.
diff --git a/build.ps1 b/build.ps1
index 54a28ff..6ef9f8a 100644
--- a/build.ps1
+++ b/build.ps1
@@ -8,6 +8,9 @@ Removes every build output first, so the build starts from nothing.
.PARAMETER Browser
Also runs the tests that need a real browser's layout, in headless Chromium, and those of what browser engines decide differently in Chromium, Firefox and WebKit, each installed first if it is not.
+.PARAMETER Full
+Runs the full gate: the gate, then the NuGet package and its symbols packed into artifacts/ as a release ships them, each checked against the files its list names and installed into a consumer outside the repository, by scripts/Test-Packages.ps1. A release's full gate runs with -Browser too.
+
.NOTES
DOMQL builds against the Nexo release nexo.release pins, the tree of its tag, which it extracts into .nexo from the checkout beside this one, formaui-net.Nexo, fetching the tag where the checkout lacks it. Set NEXO_SOURCE to a Nexo checkout to build against that checkout's working tree instead, for a change made in both repositories.
@@ -16,11 +19,15 @@ DOMQL builds against the Nexo release nexo.release pins, the tree of its tag, wh
.EXAMPLE
./build.ps1 -Browser
+
+.EXAMPLE
+./build.ps1 -Browser -Full
#>
[CmdletBinding()]
param(
[switch] $Clean,
- [switch] $Browser
+ [switch] $Browser,
+ [switch] $Full
)
Set-StrictMode -Version Latest
@@ -197,3 +204,27 @@ try {
finally {
Pop-Location
}
+
+if (-not $Full) {
+ return
+}
+
+# The packages a release publishes: packed afresh, by a build that records its source as a release's does.
+if (Test-Path $artifacts) {
+ Remove-Item $artifacts -Recurse -Force
+}
+
+Push-Location $nuget
+try {
+ Write-Host 'Packing the NuGet package'
+ dotnet pack Forma.DOMQL.csproj -c Release -nologo -o $artifacts -p:ContinuousIntegrationBuild=true
+ if ($LASTEXITCODE -ne 0) {
+ throw 'dotnet pack failed.'
+ }
+}
+finally {
+ Pop-Location
+}
+
+$version = [regex]::Match((Get-Content (Join-Path $root 'src' 'Versions.mjs') -Raw), "runtime = '([^']+)'").Groups[1].Value
+& (Join-Path $root 'scripts' 'Test-Packages.ps1') -Directory $artifacts -Version $version
diff --git a/docs/features-status.md b/docs/features-status.md
index 305103a..ad339e0 100644
--- a/docs/features-status.md
+++ b/docs/features-status.md
@@ -292,7 +292,7 @@ Needs Nexo's packages, which its [release](https://github.com/FormaUI/Nexo/blob/
**Current:**
-- **NuGet:** `./publish.ps1` packs `formaui-net.DOMQL` locally. It carries the runtime version `src/Versions.mjs` declares, `1.0.0-preview.1`, and is unpublished.
+- **NuGet:** the full gate, `./build.ps1 -Full`, packs `formaui-net.DOMQL` locally, checks it holds exactly the files `scripts/packages` lists, and installs it into a web application outside the repository, whose published `domql.js` resolves a query. It carries the runtime version `src/Versions.mjs` declares, `1.0.0-preview.1`, and is unpublished.
- **npm:** not made yet. `package.json` is private and carries no version.
- **The gate** holds the NuGet package, both READMEs, the [changelog](../CHANGELOG.md) and `domql.info.versions` to the versions the sources declare. The sources declare the version due at the next release, so nothing advances before a release is cut, as [D75](decisions.md#d75) and [D79](decisions.md#d79) record.
diff --git a/nuget/Forma.DOMQL.csproj b/nuget/Forma.DOMQL.csproj
index ccce226..f22f64d 100644
--- a/nuget/Forma.DOMQL.csproj
+++ b/nuget/Forma.DOMQL.csproj
@@ -46,10 +46,10 @@
What DOMQL $(Version) changed: https://github.com/FormaUI/DOMQL/blob/v$(Version)/CHANGELOG.md#v$(Version.Replace('.', '-'))
-
+
-
-
+
+
diff --git a/nuget/README.md b/nuget/README.md
index 48af815..46130e8 100644
--- a/nuget/README.md
+++ b/nuget/README.md
@@ -22,7 +22,7 @@ DOMQL is a JavaScript library for querying the DOM, allowing you to read informa
## Install and load
-Build the repository with `./publish.ps1`. This writes the local NuGet package to `artifacts/`; see the [repository setup instructions](https://github.com/FormaUI/DOMQL#build-and-try-it) for prerequisites.
+Build the repository with `./build.ps1 -Full`. This writes the local NuGet package to `artifacts/`, verified as an application installs it; see the [repository setup instructions](https://github.com/FormaUI/DOMQL#build-and-try-it) for prerequisites.
From your application's project directory, add the package using that folder as the source. Adjust the path to your local `artifacts/` directory:
diff --git a/publish.ps1 b/publish.ps1
deleted file mode 100644
index 35f3290..0000000
--- a/publish.ps1
+++ /dev/null
@@ -1,36 +0,0 @@
-<#
-.SYNOPSIS
-Bundles DOMQL into the single minified file the package ships and packs the package.
-
-.DESCRIPTION
-Runs the gate first, so nothing unbuilt, untested or misformatted is packed, then writes the package to artifacts/. Pushing it to a feed is left to the caller.
-
-.EXAMPLE
-./publish.ps1
-#>
-[CmdletBinding()]
-param()
-
-Set-StrictMode -Version Latest
-$ErrorActionPreference = 'Stop'
-
-$root = $PSScriptRoot
-$nuget = Join-Path $root 'nuget'
-$artifacts = Join-Path $root 'artifacts'
-
-& (Join-Path $root 'build.ps1')
-
-# dotnet finds global.json from the working directory up, so the SDK it pins applies from the package project's folder.
-Write-Host 'Packing'
-Push-Location $nuget
-try {
- dotnet pack Forma.DOMQL.csproj -c Release -nologo -o $artifacts
- if ($LASTEXITCODE -ne 0) {
- throw 'dotnet pack failed.'
- }
-}
-finally {
- Pop-Location
-}
-
-Get-ChildItem $artifacts -Filter '*.nupkg' | ForEach-Object { Write-Host "Packed $($_.FullName)" }
diff --git a/scripts/Test-Packages.ps1 b/scripts/Test-Packages.ps1
new file mode 100644
index 0000000..d688ae1
--- /dev/null
+++ b/scripts/Test-Packages.ps1
@@ -0,0 +1,126 @@
+<#
+.SYNOPSIS
+Verifies DOMQL's package as consumers receive it.
+
+.DESCRIPTION
+Checks that the NuGet package and its symbols hold exactly the files their lists in scripts/packages name. Then it installs the package into a web application outside the repository, from a local feed holding the package and nuget.org alone, publishes the application, and has its published domql.js resolve a query.
+
+.PARAMETER Directory
+The directory holding the packages, and nothing else.
+
+.PARAMETER Version
+The version every package carries.
+
+.EXAMPLE
+./scripts/Test-Packages.ps1 -Directory artifacts -Version 1.0.0-preview.1
+#>
+[CmdletBinding()]
+param(
+ [Parameter(Mandatory)] [string] $Directory,
+ [Parameter(Mandatory)] [string] $Version
+)
+
+Set-StrictMode -Version Latest
+$ErrorActionPreference = 'Stop'
+
+$root = Split-Path $PSScriptRoot -Parent
+$packages = Join-Path $PSScriptRoot 'packages'
+$Directory = (Resolve-Path $Directory).Path
+
+# Each package the release holds, by its file name, with the list of the files it holds.
+$expected = [ordered]@{
+ "formaui-net.DOMQL.$Version.nupkg" = 'nuget.files'
+ "formaui-net.DOMQL.$Version.snupkg" = 'nuget-symbols.files'
+}
+
+# The paths a NuGet package holds, as its archive holds them.
+function Get-PackageFile {
+ param([Parameter(Mandatory)] [string] $Path)
+
+ $archive = [System.IO.Compression.ZipFile]::OpenRead($Path)
+
+ try {
+ $archive.Entries | Where-Object { -not $_.FullName.EndsWith('/') } | ForEach-Object { [uri]::UnescapeDataString($_.FullName) }
+ }
+ finally {
+ $archive.Dispose()
+ }
+}
+
+# Runs a command, and fails with what it was doing where the command fails.
+function Invoke-Checked {
+ param([Parameter(Mandatory)] [string] $Doing, [Parameter(Mandatory)] [scriptblock] $Command)
+
+ & $Command
+ if ($LASTEXITCODE -ne 0) {
+ throw "$Doing failed."
+ }
+}
+
+Write-Host 'Checking the packages hold the files their lists name'
+$present = @(Get-ChildItem -LiteralPath $Directory -File | ForEach-Object Name)
+$unexpected = @($present | Where-Object { -not $expected.Contains($_) })
+$missing = @($expected.Keys | Where-Object { $present -cnotcontains $_ })
+if ($unexpected.Count -gt 0 -or $missing.Count -gt 0) {
+ throw "$Directory holds $($present -join ', '), where it should hold $($expected.Keys -join ', ')."
+}
+
+foreach ($name in $expected.Keys) {
+ $listed = @(Get-Content -LiteralPath (Join-Path $packages $expected[$name]) | Where-Object { $_ -and -not $_.StartsWith('#') })
+ $held = @(Get-PackageFile -Path (Join-Path $Directory $name))
+ $absent = @($listed | Where-Object { $held -cnotcontains $_ })
+ $extra = @($held | Where-Object { $listed -cnotcontains $_ })
+
+ if ($absent.Count -gt 0 -or $extra.Count -gt 0) {
+ throw "$name doesn't hold the files scripts/packages/$($expected[$name]) lists. Missing: $($absent -join ', '). Not listed: $($extra -join ', ')."
+ }
+
+ Write-Host " $name holds the $($listed.Count) files its list names"
+}
+
+$work = Join-Path ([System.IO.Path]::GetTempPath()) "domql-packages-$([guid]::NewGuid().ToString('N'))"
+$previousPackages = $env:NUGET_PACKAGES
+
+try {
+ # The NuGet package, restored into a web application from the local feed and nuget.org into packages of its own, so no cached copy of the same version stands in for it. The consumer takes its own files alone, whatever an IDE built beside them.
+ Write-Host 'Installing the NuGet package into a consumer'
+ $consumer = New-Item -ItemType Directory -Path (Join-Path $work 'nuget')
+ Get-ChildItem -LiteralPath (Join-Path $packages 'nuget-consumer') -File | Copy-Item -Destination $consumer
+ Copy-Item -LiteralPath (Join-Path $root 'nuget' 'global.json') -Destination $consumer
+ $feed = [System.Security.SecurityElement]::Escape($Directory)
+ Set-Content -LiteralPath (Join-Path $consumer 'NuGet.config') -Value @"
+
+
+
+
+
+
+
+
+"@
+ $env:NUGET_PACKAGES = Join-Path $work 'nuget-packages'
+
+ Push-Location $consumer
+ try {
+ $published = Join-Path $consumer 'published'
+ Invoke-Checked 'Publishing an application with the NuGet package' { dotnet publish Consumer.csproj -c Release -o $published -nologo "-p:DomqlVersion=$Version" }
+
+ $served = Join-Path $published 'wwwroot' '_content' 'domql'
+ foreach ($file in 'domql.js', 'domql.d.ts') {
+ if (-not (Test-Path -LiteralPath (Join-Path $served $file))) {
+ throw "The published application doesn't serve _content/domql/$file."
+ }
+ }
+
+ Invoke-Checked 'Resolving with the published domql.js' { node resolve.mjs (Join-Path $served 'domql.js') $Version }
+ }
+ finally {
+ Pop-Location
+ }
+}
+finally {
+ $env:NUGET_PACKAGES = $previousPackages
+ Remove-Item -LiteralPath $work -Recurse -Force -ErrorAction SilentlyContinue
+}
+
+Write-Host "The packages of $Version are verified as consumers receive them."
diff --git a/scripts/packages/nuget-consumer/Consumer.csproj b/scripts/packages/nuget-consumer/Consumer.csproj
new file mode 100644
index 0000000..7b7f75c
--- /dev/null
+++ b/scripts/packages/nuget-consumer/Consumer.csproj
@@ -0,0 +1,14 @@
+
+
+
+
+ net11.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/scripts/packages/nuget-consumer/Program.cs b/scripts/packages/nuget-consumer/Program.cs
new file mode 100644
index 0000000..4f95e2c
--- /dev/null
+++ b/scripts/packages/nuget-consumer/Program.cs
@@ -0,0 +1,4 @@
+// Serves the static files the application's packages give it, formaui-net.DOMQL's domql.js among them.
+var app = WebApplication.CreateBuilder(args).Build();
+app.MapStaticAssets();
+app.Run();
diff --git a/scripts/packages/nuget-consumer/resolve.mjs b/scripts/packages/nuget-consumer/resolve.mjs
new file mode 100644
index 0000000..2ad3da4
--- /dev/null
+++ b/scripts/packages/nuget-consumer/resolve.mjs
@@ -0,0 +1,13 @@
+// Loads the domql.js a published application serves, as a page's module would, and resolves a query that reads the DOM with it, as the package's version; resolving needs no DOM.
+import { pathToFileURL } from 'node:url';
+
+const [path, version] = process.argv.slice(2);
+const { domql } = await import(pathToFileURL(path).href);
+const { type } = domql.query('let inputs = Domql.document.all("input")\n\nreturn { total = inputs.count, checked = inputs.where(it.checked).count }').resolve();
+
+if (domql.info.versions.runtime !== version || type !== '{ total: Number, checked: Number }') {
+ console.error(`The published domql.js answered ${domql.info.versions.runtime} and the type ${type}, where ${version} and { total: Number, checked: Number } were expected.`);
+ process.exit(1);
+}
+
+console.log(`formaui-net.DOMQL ${version} served domql.js from a published application, which resolved a query.`);
diff --git a/scripts/packages/nuget-symbols.files b/scripts/packages/nuget-symbols.files
new file mode 100644
index 0000000..ccfe2b4
--- /dev/null
+++ b/scripts/packages/nuget-symbols.files
@@ -0,0 +1,6 @@
+# The files the symbol package formaui-net.DOMQL.snupkg holds, by their path in the package; build.ps1 -Full checks the package holds exactly these.
+[Content_Types].xml
+_rels/.rels
+formaui-net.DOMQL.nuspec
+lib/net11.0/Forma.DOMQL.pdb
+package/services/metadata/core-properties/nuget.psmdcp
diff --git a/scripts/packages/nuget.files b/scripts/packages/nuget.files
new file mode 100644
index 0000000..4c566ec
--- /dev/null
+++ b/scripts/packages/nuget.files
@@ -0,0 +1,16 @@
+# The files the NuGet package formaui-net.DOMQL holds, by their path in the package; build.ps1 -Full checks the package holds exactly these.
+LICENSE
+NOTICE
+README.md
+[Content_Types].xml
+_rels/.rels
+build/Microsoft.AspNetCore.StaticWebAssets.targets
+build/formaui-net.DOMQL.PackageAssets.json
+build/formaui-net.DOMQL.targets
+buildMultiTargeting/formaui-net.DOMQL.targets
+buildTransitive/formaui-net.DOMQL.targets
+formaui-net.DOMQL.nuspec
+lib/net11.0/Forma.DOMQL.dll
+package/services/metadata/core-properties/nuget.psmdcp
+staticwebassets/domql.d.ts
+staticwebassets/domql.js
From 0d6b553b11bab408286fde150a81164656810d92 Mon Sep 17 00:00:00 2001
From: Eyal Alon <3756641+soyeyalon@users.noreply.github.com>
Date: Thu, 5 Nov 2026 06:06:11 +0200
Subject: [PATCH 04/13] ci(domql): gate every branch and pack candidates
The gate runs on every push but main's, which promotion
fast-forwards to a commit that passed on candidate, and on every pull
request. A push to candidate runs the full gate with the browser
tests, and keeps the packages it verified as the packages artifact
for the release, in place of the package job.
---
.github/workflows/ci.yml | 60 ++++++++++++----------------------------
1 file changed, 17 insertions(+), 43 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0cef4c5..53f2f08 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,15 +1,15 @@
name: CI
-# The gate on every change, on a clean Linux machine of a fixed release, so a new image never changes a result unasked: the tests, the tests in a real browser, the bundle, the package project's build with no warnings, and the format check.
+# The gate on every push but main's, which promotion fast-forwards to a commit that passed on candidate, and on every pull request, on a clean Linux machine of a fixed release, so a new image never changes a result unasked: the tests, the tests in a real browser, the bundle, the package project's build with no warnings, and the format check. A push to candidate runs the full gate, which packs the NuGet package and verifies it as consumers install it, and keeps the packages for the release to publish.
on:
push:
- branches: [main]
+ branches-ignore: [main]
pull_request:
permissions:
contents: read
-# A newer push to a pull request supersedes the older run; every commit on main keeps its own result.
+# A newer push to a pull request supersedes the older run; every commit on a branch keeps its own result.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
@@ -18,7 +18,7 @@ concurrency:
env:
PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/.playwright
-# DOMQL builds against the Nexo release nexo.release pins, the tree of its tag, taken from a checkout beside its own, formaui-net.Nexo beside formaui-net.DOMQL, until it consumes Nexo's published package, so each job checks out both, Nexo at that tag.
+# DOMQL builds against the Nexo release nexo.release pins, the tree of its tag, taken from a checkout beside its own, formaui-net.Nexo beside formaui-net.DOMQL, until it consumes Nexo's published package, so the job checks out both, Nexo at that tag.
defaults:
run:
working-directory: formaui-net.DOMQL
@@ -28,6 +28,8 @@ jobs:
gate:
name: Gate
runs-on: ubuntu-24.04
+ env:
+ CANDIDATE: ${{ github.event_name == 'push' && github.ref == 'refs/heads/candidate' }}
steps:
# The gated commit alone, since the sources declare every version and nothing reads the history.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -73,50 +75,22 @@ jobs:
npx --prefix tests playwright install-deps chromium firefox webkit
- name: Gate
+ if: env.CANDIDATE != 'true'
shell: pwsh
run: ./build.ps1 -Browser
- package:
- name: Package
- needs: gate
- runs-on: ubuntu-24.04
- steps:
- # The gated commit alone, since the sources declare every version and nothing reads the history.
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- with:
- path: formaui-net.DOMQL
-
- # The tag of the Nexo release DOMQL builds against, which nexo.release pins.
- - name: Read the pinned Nexo release
- id: nexo
- run: echo "tag=v$(tr -d '[:space:]' < nexo.release)" >> "$GITHUB_OUTPUT"
-
- # Nexo's whole history, since DOMQL's documents link to commits a record of the past names, which the link test reads.
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- with:
- repository: FormaUI/Nexo
- ref: ${{ steps.nexo.outputs.tag }}
- path: formaui-net.Nexo
- fetch-depth: 0
-
- - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
- with:
- node-version: 24
- cache: npm
- cache-dependency-path: |
- formaui-net.DOMQL/package-lock.json
- formaui-net.DOMQL/tests/package-lock.json
-
- - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
- with:
- global-json-file: formaui-net.DOMQL/nuget/global.json
-
- - name: Pack
+ - name: Full gate
+ if: env.CANDIDATE == 'true'
shell: pwsh
- run: ./publish.ps1
+ run: ./build.ps1 -Browser -Full
+ # The packages the full gate built and verified, under the name the release's checks read them by, kept as long as GitHub allows.
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
+ if: env.CANDIDATE == 'true'
with:
- name: package
- path: formaui-net.DOMQL/artifacts/*.nupkg
+ name: packages
+ path: |
+ formaui-net.DOMQL/artifacts/*.nupkg
+ formaui-net.DOMQL/artifacts/*.snupkg
if-no-files-found: error
+ retention-days: 90
From 5e04e79b0927ec99f8d35e7257f16fd8a5f2caa6 Mon Sep 17 00:00:00 2001
From: Eyal Alon <3756641+soyeyalon@users.noreply.github.com>
Date: Thu, 5 Nov 2026 06:06:12 +0200
Subject: [PATCH 05/13] ci(domql): check promotions into main
A pull request into main runs the promotion check of FormaUI
Versioning v1.0.0-preview.1, pinned by its commit.
---
.github/workflows/promotion.yml | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
create mode 100644 .github/workflows/promotion.yml
diff --git a/.github/workflows/promotion.yml b/.github/workflows/promotion.yml
new file mode 100644
index 0000000..baea08c
--- /dev/null
+++ b/.github/workflows/promotion.yml
@@ -0,0 +1,30 @@
+name: Promotion
+
+# The promotion check on every pull request into main, from the FormaUI Versioning release DOMQL follows: it comes from candidate, ci.yml's full gate passed on its head commit and kept the packages, its version is higher than every release's and on no feed, and its changelog entry is dated.
+on:
+ pull_request:
+ branches: [main]
+ types: [opened, edited, reopened, synchronize]
+
+permissions:
+ contents: read
+ actions: read
+ pull-requests: read
+
+# Each action is pinned to the commit of the release named in its comment.
+jobs:
+ promotion:
+ name: Promotion
+ runs-on: ubuntu-24.04
+ steps:
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+
+ # The runtime version src/Versions.mjs declares, which the package carries.
+ - uses: FormaUI/Versioning/actions/promotion-check@68ff74cadbe94084384d29be93466713fd989b53 # v1.0.0-preview.1
+ with:
+ gate-workflow: ci.yml
+ version-command: >-
+ [regex]::Match((Get-Content src/Versions.mjs -Raw), "runtime = '([^']+)'").Groups[1].Value
+ packages-artifact: packages
From e2bb27bdc94d59c0c47133b8a4ccb46528cf5d67 Mon Sep 17 00:00:00 2001
From: Eyal Alon <3756641+soyeyalon@users.noreply.github.com>
Date: Thu, 5 Nov 2026 06:06:12 +0200
Subject: [PATCH 06/13] ci(domql): publish a tagged release
A release tag's push runs the release check of FormaUI Versioning
v1.0.0-preview.1, attaches the packages candidate's full gate built
to the tag's GitHub release with their digests, and publishes the
NuGet package to nuget.org through trusted publishing, from the
release environment that v* tags alone deploy to.
---
.github/workflows/release.yml | 66 +++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
create mode 100644 .github/workflows/release.yml
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..82478ee
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,66 @@
+name: Release
+
+# A release tag's push: the release check of the FormaUI Versioning release DOMQL follows, then the packages candidate's full gate built, attached to the tag's GitHub release with their digests, and published from there to nuget.org through trusted publishing. A run that fails runs again for the same tag, publishing what the feed lacks. DOMQL publishes no npm package yet.
+on:
+ push:
+ tags: ['v*']
+
+permissions:
+ contents: read
+
+# Each action is pinned to the commit of the release named in its comment.
+jobs:
+ release:
+ name: Release
+ runs-on: ubuntu-24.04
+ # Only a v* tag deploys to the release environment, and the feed's trusted-publishing policy names it, so only a release tag's run publishes.
+ environment: release
+ permissions:
+ contents: write
+ actions: read
+ pull-requests: read
+ id-token: write
+ steps:
+ # The whole history, so the check finds the tag's commit in main's.
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ fetch-depth: 0
+
+ # The runtime version src/Versions.mjs declares, which the package carries.
+ - id: check
+ uses: FormaUI/Versioning/actions/release-check@68ff74cadbe94084384d29be93466713fd989b53 # v1.0.0-preview.1
+ with:
+ gate-workflow: ci.yml
+ version-command: >-
+ [regex]::Match((Get-Content src/Versions.mjs -Raw), "runtime = '([^']+)'").Groups[1].Value
+ packages-artifact: packages
+
+ - id: packages
+ uses: FormaUI/Versioning/actions/release-packages@68ff74cadbe94084384d29be93466713fd989b53 # v1.0.0-preview.1
+ with:
+ gate-run-id: ${{ steps.check.outputs.gate-run-id }}
+ packages-artifact: packages
+ name: DOMQL
+
+ - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
+ with:
+ global-json-file: nuget/global.json
+
+ # A short-lived nuget.org key, for the account NUGET_USER names, whose trusted-publishing policy names this workflow.
+ - id: nuget
+ uses: NuGet/login@8d196754b4036150537f80ac539e15c2f1028841 # v1.2.0
+ with:
+ user: ${{ vars.NUGET_USER }}
+
+ # The package and its symbols, past a version nuget.org holds already.
+ - name: Publish to nuget.org
+ shell: pwsh
+ env:
+ NUGET_API_KEY: ${{ steps.nuget.outputs.NUGET_API_KEY }}
+ PACKAGES: ${{ steps.packages.outputs.directory }}
+ VERSION: ${{ steps.check.outputs.version }}
+ run: |
+ dotnet nuget push (Join-Path $env:PACKAGES "formaui-net.DOMQL.$env:VERSION.nupkg") --api-key $env:NUGET_API_KEY --source https://api.nuget.org/v3/index.json --skip-duplicate
+ if ($LASTEXITCODE -ne 0) {
+ throw 'Publishing to nuget.org failed.'
+ }
From 450a6f7826c95b4d74436e7322ca6f6a04e5421c Mon Sep 17 00:00:00 2001
From: Eyal Alon <3756641+soyeyalon@users.noreply.github.com>
Date: Thu, 5 Nov 2026 06:08:54 +0200
Subject: [PATCH 07/13] docs(domql): follow FormaUI Versioning
Contributing states what Versioning v1.0.0-preview.1 leaves to DOMQL:
its public contract, the declarations of its versions, its gates and
workflows, and its package. Cutting a release follows Versioning's
path, the commit rules are Versioning's, and CLAUDE.md names the
release DOMQL follows. The link test holds every link into Versioning,
and every action a workflow calls of it, to one release, as D107
records.
---
CLAUDE.md | 11 +++----
CONTRIBUTING.md | 66 ++++++++++++++++++++++++++++++-------
VERSION-HISTORY.md | 4 +--
docs/decisions.md | 21 ++++++++++++
docs/features-status.md | 16 ++++++---
tests/DocumentLinks.test.js | 18 ++++++++++
6 files changed, 111 insertions(+), 25 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index 5e9704b..35b6652 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -2,6 +2,8 @@
DOMQL is a query language and JavaScript library for the DOM: reading information from the document, keeping it current, responding to events and updating the page's content or state. Its queries are written in Nexo, and DOMQL defines the DOM as Nexo's domain. A query only reads; the document changes only through an execution, a host call a module supplies, which DOMQL carries out once or keeps running. Source ES modules live in `src/`; the build produces one minified bundle, distributed by the `formaui-net.DOMQL` NuGet package.
+DOMQL follows [FormaUI Versioning `v1.0.0-preview.1`](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/README.md) for its [stages](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/versions.md#stages), [branches](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/branches.md), [commits](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/commits.md), [releases](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/releases.md) and [packages](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/packages.md); [contributing](CONTRIBUTING.md#versions-and-releases) states what it leaves to DOMQL.
+
## Before making a change
Read the documents that govern the affected contract:
@@ -19,7 +21,7 @@ Read the documents that govern the affected contract:
| [Library guide](nuget/README.md) | Using DOMQL by example; it ships in the package, so it links absolutely |
| `.editorconfig` | Code style; read it before writing C# |
-Until 1.0, add no feature: [what 1.0 requires](docs/features-status.md#what-1-0-requires) says what a change may do. Update the specification before changing a contract, the vocabulary, the API or what an operation does, and the design before changing how DOMQL is built. Advance the specification version once per release: the first change to DOMQL's contract after a release opens the next version's entry in the [version history](VERSION-HISTORY.md), and the sources and the specification declare that version in the same commit; each later change before the next release joins that entry. An entry leads with examples of what changed, run at its version, and its list below them is the reference. Since the beta, a break needs guidance on migrating. Cut a release only as [contributing](CONTRIBUTING.md#cut-a-release) sets out. List a change a caller can notice in the [changelog](CHANGELOG.md), by its rules. Each subject has one home: state a rule where it belongs and link to it elsewhere; a rule of the language or its runtime is Nexo's. Record a gap between the design and the code in the status overview until it closes, and update a row's status as soon as its work lands.
+Until 1.0, add no feature: [what 1.0 requires](docs/features-status.md#what-1-0-requires) says what a change may do. Update the specification before changing a contract, the vocabulary, the API or what an operation does, and the design before changing how DOMQL is built. Advance the specification version once per release: the first change to DOMQL's contract after a release opens the next version's entry in the [version history](VERSION-HISTORY.md), and the sources and the specification declare that version in the same commit; each later change before the next release joins that entry. An entry leads with examples of what changed, run at its version, and its list below them is the reference. A break needs guidance on migrating, as the [preview](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/versions.md#stages) promises. Cut a release only as [contributing](CONTRIBUTING.md#cut-a-release) sets out. List a change a caller can notice in the [changelog](CHANGELOG.md), by its rules. Each subject has one home: state a rule where it belongs and link to it elsewhere; a rule of the language or its runtime is Nexo's. Record a gap between the design and the code in the status overview until it closes, and update a row's status as soon as its work lands.
Use these sources rather than inventing scope, status or style rules.
@@ -122,9 +124,4 @@ Ask for permission before each state-changing Git command, once the work is read
## Commit messages
-Describe the durable change, not the session that produced it. Follow the format in [CONTRIBUTING.md](CONTRIBUTING.md#commit-messages).
-
-- Make the title cover the whole commit. Split unrelated work when one honest title cannot cover it.
-- Add a body only when the title needs context.
-- Explain the resulting change; omit implementation narration, file or member inventories, test counts and routine verification.
-- Do not add attribution trailers such as `Co-Authored-By`.
+Write each commit as [FormaUI Versioning's commits](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/commits.md) set out, its scope `domql`.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 83fdebf..562f4f7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,7 +2,7 @@
Thanks for helping improve DOMQL. Bug reports, documentation fixes and code contributions are welcome.
-For a small fix, you can open a pull request directly. For a larger change, open an issue first so we can agree on the approach before you spend time implementing it. Until 1.0, DOMQL takes fixes rather than features, as [what 1.0 requires](docs/features-status.md#what-1-0-requires) sets out. Report vulnerabilities privately using [SECURITY.md](SECURITY.md).
+For a small fix, you can open a pull request into `dev` directly. For a larger change, open an issue first so we can agree on the approach before you spend time implementing it. Until 1.0, DOMQL takes fixes rather than features, as [what 1.0 requires](docs/features-status.md#what-1-0-requires) sets out. Report vulnerabilities privately using [SECURITY.md](SECURITY.md).
## Set up
@@ -54,6 +54,8 @@ The [Nexo specification](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec
Keep each change focused, and follow the surrounding code's conventions. Use `.editorconfig` for formatting and style.
+A change lands on `dev`, from a branch of its own, `feature/` or `fix/`, as [landing work](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/branches.md#landing-work) sets out; `main` holds the latest release, and advances only by promotion.
+
Since DOMQL's beta, two rules hold for a change its callers can notice:
- **A break says how to migrate.** A version that breaks what the one before it allowed says how to migrate, beside the break, in its entry in the [version history](VERSION-HISTORY.md).
@@ -85,30 +87,72 @@ Two details to keep in mind:
For performance changes, run `npm run bench` from `tests/` for simulated-DOM benchmarks and `npm run scale` for Chromium workloads: a watch of 1,000 to 100,000 rows, a drag through owned writes, an edit in a large editor, a behavior's deliveries and owners, and transient measurements beside many observers. Name a file to run one workload, as `npm run scale -- dom/OwnedWrites.scale.js`; each reports the machine's load as it ran, its own included, so compare runs made at a low load alone. Compare against a baseline, keep gains that repeat beyond measurement noise, and record a conclusion that decides something in the [design](docs/domql-design.md), beside the decision it settles. Report the memory a change retains apart from what it allocates: a bound can slow a case's allocation and still end growth that outlived disposal, as [D84](docs/decisions.md#d84) did. Benchmarks are separate from the build gate.
+
+
+## Versions and releases
+
+DOMQL follows [FormaUI Versioning `v1.0.0-preview.1`](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/README.md), the rules every FormaUI project versions, branches, commits, releases and packages by. DOMQL states here what those rules leave to a project.
+
+**The public contract,** which the [stages](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/versions.md#stages)' promises cover:
+
+- the [specification](spec/README.md): the DOM's vocabulary, the module that declares it, and DOMQL as the host that carries queries out, one document per subject;
+- the runtime's API, as the specification's [API](spec/api.md) states it and `src/domql.d.ts` declares it.
+
+The language a query is written in is Nexo's, and its contract is Nexo's.
+
+**The versions,** each declared once, in `src/Versions.mjs`:
+
+| Version | Declared as | What carries it | Its history |
+| --- | --- | --- | --- |
+| The package version | `runtime` | The package, the bundle, the release's tag and `domql.info.versions.runtime` | The [changelog](CHANGELOG.md) |
+| The specification version | `specification` | DOMQL's contract, the [specification](spec/README.md) | The [version history](VERSION-HISTORY.md) |
+| The language version | `language`, read from the Nexo runtime DOMQL runs on | Nothing of DOMQL's: it names the Nexo language DOMQL runs on, the release `nexo.release` pins | Nexo's |
+
+**The gates.** The fast gate, `./build.ps1 -Browser`, runs the tests, the tests in a real browser, the bundle, the package project's build with no warnings and the format check. The full gate, `./build.ps1 -Browser -Full`, runs it, then packs the package and its symbols into `artifacts/`, checks each holds exactly the files its list in `scripts/packages/` names, and installs the package outside the repository from a local feed into a web application whose published `domql.js` resolves a query.
+
+**The workflows:**
+
+| Workflow | Runs on | What it does |
+| --- | --- | --- |
+| `ci.yml` | Every push but `main`'s, and every pull request | The fast gate, and on a push to `candidate` the full gate, which keeps the packages it verified as its `packages` artifact |
+| `promotion.yml` | A pull request into `main` | The [promotion check](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/releases.md#promotion) |
+| `release.yml` | A `v*` tag's push, in the `release` environment, which only `v*` tags deploy to | The [release check](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/releases.md#the-release-check), then the full gate's packages attached to the tag's GitHub release with their digests, and the NuGet package published through trusted publishing |
+
+`dev` and `main` require `ci.yml`'s `Gate`, and `main` the `Promotion` check too.
+
+**The packages:**
+
+| Package | What it holds | Its targets | Its feed | Depends on |
+| --- | --- | --- | --- | --- |
+| NuGet, `formaui-net.DOMQL` | The bundle, `domql.js`, with Nexo inside it, and its declarations, served at `_content/domql/`, with the README, license and notice, as `scripts/packages/nuget.files` lists them, and its symbols beside it, as `scripts/packages/nuget-symbols.files` lists them | `net11.0` applications | nuget.org | Nothing: it carries the Nexo release `nexo.release` pins inside its bundle |
+
+DOMQL publishes no npm package yet: `package.json` is private, and the npm package waits for DOMQL to consume Nexo's published packages, as the status's [packages](docs/features-status.md#packages) set out. A package of DOMQL's that depends on Nexo's names the lowest Nexo version DOMQL works with.
+
+The [changelog](CHANGELOG.md) records each release, and the [version history](VERSION-HISTORY.md) each specification version, by their own rules.
+
## Cut a release
-A release is a signed tag on the commit that dates it. The [changelog](CHANGELOG.md) says what each release changed in the implementation, and the [version history](VERSION-HISTORY.md) what each specification version changed in DOMQL's contract.
+A release is a candidate that passed its full gate, promoted to `main` and tagged there, as [FormaUI Versioning's releases](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/releases.md) set out. Publishing its package is the step after it.
-1. Date the changelog's newest entry by the day of the release, and the version history's newest entry where it reads *Unreleased*.
-2. Pass the gate, `./build.ps1 -Browser`, and commit.
-3. Tag the commit with a signed tag named for the release, as `git tag -s v1.0.0-beta.1`, and push the tag.
-4. Pack the packages from the tag with `./build.ps1 -Browser -Full`, which verifies them as consumers install them, and publish them.
+1. **Set the release on `dev`.** Pause merges unrelated to it, as [stabilizing a candidate](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/branches.md#stabilizing-a-candidate) sets out. Check that `src/Versions.mjs` declares the release's version and `nexo.release` the Nexo release it builds against, date the changelog's newest entry by the day of the release, and date the version history's newest entry where it reads *Unreleased*.
+2. **Select the candidate.** Fast-forward `candidate` to `dev`'s tip, `git push origin dev:candidate`. `ci.yml` runs the full gate on it. A fix lands on `dev`, and `candidate` moves to the corrected tip.
+3. **Promote it.** Open a pull request from `candidate` into `main`, which `promotion.yml` checks. Once the check passes, a release signer fast-forwards `main` to it, `git push origin candidate:main`.
+4. **Tag it.** A release signer tags `main`'s commit with an annotated, signed tag, `git tag -s v1.0.0-preview.1 -m "DOMQL 1.0.0-preview.1"`, and pushes it, `git push origin v1.0.0-preview.1`. A pushed tag is never moved or deleted.
+5. **Publish it.** The tag's push runs `release.yml`, which publishes the package. A run that fails runs again for the same tag, and publishes what the feed lacks.
-After a release, the next change a caller can notice opens the changelog's next entry, and the next change to DOMQL's contract the version history's.
+After a release, the next change a caller can notice opens the changelog's next entry, and the next change to DOMQL's contract the version history's, as [advancing a version](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/versions.md#advancing-a-version) sets out.
## Before opening a pull request
-Run `./build.ps1` from the repository root. This is the build gate: it runs tests, bundles the library, builds the package without warnings and checks formatting. Include the browser tests when your change affects browser behavior. CI runs the gate with browser tests on Linux for every pull request and push to `main`.
+Run `./build.ps1` from the repository root. This is the build gate: it runs tests, bundles the library, builds the package without warnings and checks formatting. Include the browser tests when your change affects browser behavior. CI runs the gate with browser tests on Linux for every pull request and every push but `main`'s, and the full gate on a push to `candidate`.
In your pull request, explain the problem, the resulting behavior and how you verified the change. Mention any related issue and any checks you could not run.
## Commit messages
-Use [Conventional Commits](https://www.conventionalcommits.org): `type(scope): description`.
-
-Keep the subject under 50 characters. Add a body when the change needs context, wrap it at 72 characters, and explain what changes for the user and why. Avoid a file-by-file account of the implementation. Each commit should cover one coherent change and pass the build on its own. Leave out attribution trailers.
+Write each commit as [FormaUI Versioning's commits](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/commits.md) set out: one purpose, passing the gate on its own, its message a Conventional Commit, `type(domql): description`, with no attribution trailer.
## Report a bug
diff --git a/VERSION-HISTORY.md b/VERSION-HISTORY.md
index 586249a..2d814e0 100644
--- a/VERSION-HISTORY.md
+++ b/VERSION-HISTORY.md
@@ -10,8 +10,8 @@ Each version of DOMQL, newest first, with the features it added and what it chan
Each entry says what its version breaks:
- **Before the beta,** a version could break what the one before it allowed, with no guidance on migrating.
-- **From `1.0.0-beta.1` until the first release candidate,** a decision may be replaced where a demonstrated fault, an ambiguous contract or a measured cost justifies it, whether or not Forma has met it, as [D100](docs/decisions.md#d100) records. A version that breaks what the one before it allowed says, beside each break, how a query, a caller or a module migrates.
-- **From `1.0.0-rc.1` on,** nothing breaks before 2.0.
+- **From `1.0.0-beta.1` until the first release candidate,** through the betas and the previews, a decision may be replaced where a demonstrated fault, an ambiguous contract or a measured cost justifies it, whether or not Forma has met it, as [D100](docs/decisions.md#d100) records. A version that breaks what the one before it allowed says, beside each break, how a query, a caller or a module migrates.
+- **From `1.0.0-rc.1` on,** nothing breaks before 2.0, as [FormaUI Versioning's stages](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/versions.md#stages) promise.
diff --git a/docs/decisions.md b/docs/decisions.md
index 69a0b62..d211640 100644
--- a/docs/decisions.md
+++ b/docs/decisions.md
@@ -1626,3 +1626,24 @@ Each entry is one of three kinds:
- The preview's promise is the beta's, as [D75](#d75) and [D100](#d100) set it: a decision may be replaced until `1.0.0-rc.1`, a break says how to migrate, and from `1.0.0-rc.1` on nothing breaks before 2.0. Only the name changes.
- DOMQL has never been released, so no tag or published version carries a beta.
- **Declined:** Keeping the betas until the release candidate, which would leave DOMQL outside the rules Nexo and Forma follow.
+
+
+
+## D107 — DOMQL releases by FormaUI Versioning's path
+
+*November 5, 2026*
+
+- **Kind:** Process, approved.
+- **Decision:** DOMQL follows [FormaUI Versioning `v1.0.0-preview.1`](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/README.md) for its branches, commits, releases and packages, as it does for its stages ([D106](#d106)). [Contributing](../CONTRIBUTING.md#versions-and-releases) states what the rules leave to DOMQL.
+ - **Branches.** `dev` holds the integrated work, `candidate` the release's candidate, and `main` the latest release, advancing only by promotion. `dev` and `main` require `ci.yml`'s `Gate`, and `main` the `Promotion` check too, as Nexo's do.
+ - **Gates.** The fast gate, `./build.ps1 -Browser`, runs on every push but `main`'s and on every pull request. The full gate, `./build.ps1 -Browser -Full`, runs on a push to `candidate`: it packs the package and its symbols, checks each against the files `scripts/packages` lists, installs the package outside the repository from a local feed, and keeps them for the release.
+ - **Releases.** A pull request into `main` runs Versioning's promotion check, and a release tag's push its release check. `release.yml` then publishes the package the full gate built, attached to the tag's GitHub release with its digest, to nuget.org through trusted publishing, from the `release` environment, which only `v*` tags deploy to.
+ - **Packages.** The NuGet package records its source through Source Link, ships its symbols, links its release notes to its changelog entry and validates itself. DOMQL publishes no npm package until it consumes Nexo's published packages, and a package of DOMQL's that depends on Nexo's names the lowest Nexo version it works with, since Versioning asks an exact version only of a package of the same project.
+ - **Links.** A document links into Versioning at its release's tag, and a workflow calls its actions by that release's commit, with the tag beside it; the link test holds every one to one release.
+- **Why:**
+ - The owner's call: every FormaUI project releases by one set of rules, and works the same way.
+ - Verifying the package as consumers receive it found it delivering the build's `global.json` to every consumer as content.
+ - The bundle carries Nexo inside it, so the NuGet package needs nothing of Nexo's published, and DOMQL's first release need not wait for Nexo's.
+- **Declined:**
+ - Publishing an npm package now, whose sources import `@formaui-net/nexo` by name and would need DOMQL's bundle to stop carrying the language, the work [consuming the language](features-status.md#consuming-nexo) plans.
+ - Keeping `publish.ps1` beside the full gate: one command packs and verifies what a release publishes.
diff --git a/docs/features-status.md b/docs/features-status.md
index ad339e0..cc80364 100644
--- a/docs/features-status.md
+++ b/docs/features-status.md
@@ -271,7 +271,14 @@ None remains: T1 to T3 are implemented, as [the features](#the-host) show: an im
## Release
-Consume Nexo's published packages before publishing DOMQL's.
+DOMQL releases as [cutting a release](../CONTRIBUTING.md#cut-a-release) sets out, by FormaUI Versioning's path, as [D107](decisions.md#d107) records. Its first release, `1.0.0-preview.1`, publishes the NuGet package with Nexo inside its bundle, and consuming Nexo's published packages follows it.
+
+**Remaining for `1.0.0-preview.1`:**
+
+1. Create `dev` and `candidate` from `main`'s tip. The organization's linear-history rule refuses a new branch holding `main`'s one merge commit, `3c68220`, made before the rules, so the owner lifts it for DOMQL while they're made.
+2. Move `nexo.release` to Nexo's `1.0.0-preview.1`, once Nexo tags it, and link Nexo's documents at that tag.
+3. Create nuget.org's trusted-publishing policy for `release.yml` in the `release` environment, which needs the owner's account.
+4. Release `1.0.0-preview.1`.
@@ -282,7 +289,7 @@ Consume Nexo's published packages before publishing DOMQL's.
**Remaining:**
-1. Depend on Nexo's released packages, `@formaui-net/nexo` and `formaui-net.Nexo`, each of an exact version.
+1. Depend on Nexo's released packages, `@formaui-net/nexo` and `formaui-net.Nexo`, each naming the lowest Nexo version DOMQL works with.
2. Write the NuGet bundle with `../nexo/nexo.js` as an import, and the npm bundle with `@formaui-net/nexo`, rather than carrying the language inside.
3. Have the gate check that DOMQL's packages depend on Nexo's and Nexo's on nothing of DOMQL's, and run DOMQL's tests against the packaged Nexo.
@@ -298,10 +305,9 @@ Needs Nexo's packages, which its [release](https://github.com/FormaUI/Nexo/blob/
**Remaining:**
-1. Make the npm package, `@formaui-net/domql`, carrying the runtime version as the NuGet package does, its bundle importing `@formaui-net/nexo`, as [consuming the language](#consuming-nexo) sets out.
-2. Publish both, once DOMQL consumes Nexo's published packages, from the tag of a release [cut](../CONTRIBUTING.md#cut-a-release) as contributing sets out, which dates its entry in the changelog.
+1. Make the npm package, `@formaui-net/domql`, carrying the runtime version as the NuGet package does, its bundle importing `@formaui-net/nexo`, as [consuming the language](#consuming-nexo) sets out, and have `release.yml` publish it beside the NuGet package.
-Both wait for Nexo's published packages, and publishing stays with the maintainer.
+It waits for Nexo's published packages. `release.yml` publishes the NuGet package from each release's tag, as [contributing](../CONTRIBUTING.md#cut-a-release) sets out.
### Preview
diff --git a/tests/DocumentLinks.test.js b/tests/DocumentLinks.test.js
index f49d850..01ad849 100644
--- a/tests/DocumentLinks.test.js
+++ b/tests/DocumentLinks.test.js
@@ -165,6 +165,12 @@ const ownProblemsOf = file => {
return reportOf(file, found, target => ownProblemOf(file, target));
};
+/** A link into FormaUI Versioning's documents, by the tag of the release it names. */
+const VERSIONING_ADDRESS = /https:\/\/github\.com\/FormaUI\/Versioning\/blob\/([^/]+)\//g;
+
+/** An action of FormaUI Versioning's a workflow calls, by the commit it pins and the release its comment names. */
+const VERSIONING_ACTION = /uses: FormaUI\/Versioning\/\S+@(\S+) # (\S+)/g;
+
describe('the links of DOMQL\'s documents', () => {
const files = filesOf('.');
@@ -179,6 +185,18 @@ describe('the links of DOMQL\'s documents', () => {
expect(files.filter(file => extname(file) === '.md').flatMap(ownProblemsOf)).toEqual([]);
});
+ it('name one release of FormaUI Versioning, the one DOMQL follows: a document by its tag, and a workflow by its full commit, with the tag beside it', () => {
+ const read = file => readFileSync(resolve(root, file), 'utf8');
+ const tags = files.flatMap(file => [...read(file).matchAll(VERSIONING_ADDRESS)].map(([, tag]) => tag));
+ const actions = readdirSync(resolve(root, '.github/workflows')).flatMap(name => [...read(join('.github/workflows', name)).matchAll(VERSIONING_ACTION)].map(([, commit, tag]) => ({ commit, tag })));
+ const [tag] = tags;
+
+ expect(new Set(tags)).toEqual(new Set([tag]));
+ expect(actions.length).toBeGreaterThan(0);
+ expect(new Set(actions.map(({ commit }) => commit)).size).toBe(1);
+ actions.forEach(action => expect(action).toEqual({ commit: expect.stringMatching(/^[0-9a-f]{40}$/), tag }));
+ });
+
it('read a heading\'s anchor as GitHub writes it, a repeated heading\'s numbered', () => {
expect([...anchorsOf('# Nexo `1.0` and DOMQL\n\n## Queries\n\n## Queries\n\n\n\n```md\n## Not a heading\n```')]).toEqual(['nexo-10-and-domql', 'queries', 'queries-1', 'd76']);
expect(slugOf('[Selecting](queries.md) a result')).toBe('selecting-a-result');
From 8a6e9c040d82d9ff91ea03848ba7e93452d1a2eb Mon Sep 17 00:00:00 2001
From: Eyal Alon <3756641+soyeyalon@users.noreply.github.com>
Date: Thu, 5 Nov 2026 17:16:33 +0200
Subject: [PATCH 08/13] build(domql): let editors load the NuGet consumer
The consumer referenced the package at the version the full gate
gives, so an editor, which loads it with none, couldn't restore it:
'[]' is not a valid version string. It references the package only
where a version is given, and a build without one stops with an error
naming the gate, rather than publishing an application with no
package.
---
scripts/packages/nuget-consumer/Consumer.csproj | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/scripts/packages/nuget-consumer/Consumer.csproj b/scripts/packages/nuget-consumer/Consumer.csproj
index 7b7f75c..17b0765 100644
--- a/scripts/packages/nuget-consumer/Consumer.csproj
+++ b/scripts/packages/nuget-consumer/Consumer.csproj
@@ -1,14 +1,18 @@
-
+
net11.0
enable
enable
-
+
+
+
+
+
From aa56fe20b788c05fab8b4b8a30c7a63e3a407247 Mon Sep 17 00:00:00 2001
From: Eyal Alon <3756641+soyeyalon@users.noreply.github.com>
Date: Thu, 5 Nov 2026 17:34:09 +0200
Subject: [PATCH 09/13] feat(domql): run on Nexo's first preview
DOMQL builds against Nexo's release 1.0.0-preview.1 and describes
itself on that language. domql.format now sets a body's return apart
with an empty line, at every level, so a body with locals formats to
new text that reads back as the same definition. Every link into
Nexo's documents follows the pin to the preview's tag, and the status
overview no longer says the pin is 1.0.0-beta.1.
---
CHANGELOG.md | 4 +--
CLAUDE.md | 6 ++--
CONTRIBUTING.md | 4 +--
README.md | 6 ++--
VERSION-HISTORY.md | 17 ++++++------
docs/decisions.md | 31 +++++++++++++++------
docs/domql-design.md | 4 +--
docs/features-status.md | 27 +++++++++---------
nexo.release | 2 +-
nuget/README.md | 10 +++----
spec/README.md | 8 +++---
spec/api.md | 4 +--
spec/errors.md | 4 +--
spec/evaluation.md | 8 +++---
spec/events.md | 6 ++--
spec/executions.md | 6 ++--
spec/nodes-and-shadow-trees.md | 2 +-
spec/queries.md | 12 ++++----
spec/results.md | 4 +--
spec/terms.md | 4 +--
spec/vocabulary.md | 50 +++++++++++++++++-----------------
spec/watches.md | 6 ++--
tests/Domql.test.js | 24 ++++++++--------
23 files changed, 131 insertions(+), 118 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4ba9367..d32667f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,11 +9,11 @@ Each release of DOMQL's packages, newest first. The NuGet package `formaui-net.D
## `1.0.0-preview.1`
-*Unreleased · specification `1.0.0-preview.1` · Nexo language `1.0.0-beta.41` · definition format 38*
+*Unreleased · specification `1.0.0-preview.1` · Nexo language `1.0.0-preview.1` · definition format 38*
- The first preview, and the first release, as [FormaUI Versioning's stages](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/versions.md#stages) name it: the runtime and the specification take `1.0.0-preview.1`, with the beta's promise. The [version history](VERSION-HISTORY.md) records what came before it.
- The NuGet package links its release notes to its changelog entry at its tag, records its repository and commit through Source Link, and ships its symbols beside it as a `.snupkg`. It no longer holds the build's `global.json`, which it delivered to a consumer as content.
-- Runs on Nexo's language `1.0.0-beta.41`, from Nexo's release `1.0.0-beta.2`, as the [version history](VERSION-HISTORY.md#v1-0-0-preview-1) sets out: `and` and `or` typed where their value is used, a selection into a dictionary's `entries` and a pair's `key` and `value`, a module's maintained members declaring nullable results, and the members that make a value of their receiver called as functions, `round()` and `trim()` among them, among the rest.
+- Runs on Nexo's language `1.0.0-preview.1`, from Nexo's release `1.0.0-preview.1`, as the [version history](VERSION-HISTORY.md#v1-0-0-preview-1) sets out: `and` and `or` typed where their value is used, a selection into a dictionary's `entries` and a pair's `key` and `value`, a module's maintained members declaring nullable results, the members that make a value of their receiver called as functions, `round()` and `trim()` among them, and an empty line before a body's `return` in `domql.format`'s text, among the rest.
- Each state DOMQL declares is a Boolean property, read without a call, `it.checked`, where it was a function, `it.checked()`. An element's `hover` and `focus`, the document's `focus`, and the window's `share` and `clipboard` are `hovered`, `focused`, `canShare` and `hasClipboard`.
- Each built-in execution is named by its verb: `takeFocus`, `writeClipboard`, `readClipboard`, `writeValue` and `writeSelection` are `focus`, `writeToClipboard`, `readFromClipboard`, `replaceValue` and `select`, and `writeMuted(muted)` and `writeIndeterminate(indeterminate)` are `mute()` and `unmute()`, and `markIndeterminate()` and `clearIndeterminate()`.
- A watch of `focused`, `focusWithin`, `activeElement` or a selector testing focus follows the focus moving inside an open shadow root, and the focused element removed, in every engine.
diff --git a/CLAUDE.md b/CLAUDE.md
index 35b6652..f0ebdfa 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -10,9 +10,9 @@ Read the documents that govern the affected contract:
| Document | Authority |
| --- | --- |
-| [Nexo specification](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md) | Nexo's two contracts, at the release DOMQL builds against: the language's, what a query means, and the runtime's, how DOMQL as its host binds, resolves, evaluates and registers modules |
+| [Nexo specification](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md) | Nexo's two contracts, at the release DOMQL builds against: the language's, what a query means, and the runtime's, how DOMQL as its host binds, resolves, evaluates and registers modules |
| [DOMQL specification](spec/README.md) | DOMQL's module and DOMQL as host: queries, nodes and shadow trees, the built-in vocabulary, evaluation, watching, results, events, executions, and the public API, one document per subject |
-| [Nexo design](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/nexo-design.md) | How Nexo is built: its stages, modules, evaluation and tooling |
+| [Nexo design](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/nexo-design.md) | How Nexo is built: its stages, modules, evaluation and tooling |
| [DOMQL design](docs/domql-design.md) | How DOMQL is built: its architecture, resolution, sessions, watching, comparing and patching, the C# half, and the decisions not taken |
| [Status](docs/features-status.md) | What is implemented, the migration to Nexo, the planned capabilities, open decisions and deferred work |
| [Decisions](docs/decisions.md) | Each decision taken without stopping to ask, with why and what was declined, for review |
@@ -47,7 +47,7 @@ Add a folder when a new responsibility needs one. Keep dependencies in this dire
- `dom/` may depend on Nexo and `snapshots/`.
- `snapshots/` may depend on Nexo.
-The language is Nexo, the package `@formaui-net/nexo`, which DOMQL imports by its name and depends on through `file:.nexo`, until it consumes a published package. `build.ps1` fills `.nexo` with the release `nexo.release` pins, the tree of its tag, taken from a checkout of [FormaUI/Nexo](https://github.com/FormaUI/Nexo) beside this one, named `formaui-net.Nexo`, so a change reaches DOMQL only when `nexo.release` moves to a release that holds it; with `NEXO_SOURCE` naming a checkout, `.nexo` links to that checkout's working tree instead. A change to the language is made there, and a change DOMQL needs of it in both repositories together, with `NEXO_SOURCE` set, moving `nexo.release` once Nexo releases it. Link Nexo's documents at the pinned release's tag, as `https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md`, so they move with the pin.
+The language is Nexo, the package `@formaui-net/nexo`, which DOMQL imports by its name and depends on through `file:.nexo`, until it consumes a published package. `build.ps1` fills `.nexo` with the release `nexo.release` pins, the tree of its tag, taken from a checkout of [FormaUI/Nexo](https://github.com/FormaUI/Nexo) beside this one, named `formaui-net.Nexo`, so a change reaches DOMQL only when `nexo.release` moves to a release that holds it; with `NEXO_SOURCE` naming a checkout, `.nexo` links to that checkout's working tree instead. A change to the language is made there, and a change DOMQL needs of it in both repositories together, with `NEXO_SOURCE` set, moving `nexo.release` once Nexo releases it. Link Nexo's documents at the pinned release's tag, as `https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md`, so they move with the pin.
Pass the window and document into DOM code; do not read globals there. Importing the language layer and resolving a query must work without a DOM.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 562f4f7..31c0a05 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -14,7 +14,7 @@ You'll need:
- PowerShell to run the build scripts.
- The .NET SDK pinned in `nuget/global.json`.
-DOMQL is written in [Nexo](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md), which it builds against at the release `nexo.release` pins, taken from its tag in a checkout of [FormaUI/Nexo](https://github.com/FormaUI/Nexo) beside this one, until it consumes a published package. Clone it beside this repository under the name the build looks for:
+DOMQL is written in [Nexo](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md), which it builds against at the release `nexo.release` pins, taken from its tag in a checkout of [FormaUI/Nexo](https://github.com/FormaUI/Nexo) beside this one, until it consumes a published package. Clone it beside this repository under the name the build looks for:
```sh
git clone https://github.com/FormaUI/Nexo.git formaui-net.Nexo
@@ -48,7 +48,7 @@ Run the full build from the repository root:
| `VERSION-HISTORY.md` | Each DOMQL version and what it changed |
| `CHANGELOG.md` | Each release of the packages and what it changed |
-The [Nexo specification](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md) defines the language and its runtime, and the [DOMQL specification](spec/README.md) the DOM vocabulary, how queries are carried out, and the public API. The [Nexo design](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/nexo-design.md) and the [DOMQL design](docs/domql-design.md) set out how each is built. If a change affects either contract, update the relevant document before implementing it. The [status overview](docs/features-status.md) tracks what is implemented, what is being built, and what remains.
+The [Nexo specification](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md) defines the language and its runtime, and the [DOMQL specification](spec/README.md) the DOM vocabulary, how queries are carried out, and the public API. The [Nexo design](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/nexo-design.md) and the [DOMQL design](docs/domql-design.md) set out how each is built. If a change affects either contract, update the relevant document before implementing it. The [status overview](docs/features-status.md) tracks what is implemented, what is being built, and what remains.
## Develop a change
diff --git a/README.md b/README.md
index 51db157..fa5941d 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,9 @@
**A declarative approach to managing the DOM.**
-DOMQL is a JavaScript library for querying the DOM, allowing you to read information from a document once or observe it as it changes. Its queries are written in [Nexo](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md).
+DOMQL is a JavaScript library for querying the DOM, allowing you to read information from a document once or observe it as it changes. Its queries are written in [Nexo](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md).
-> **Preview.** No breaking redesign is planned, and a version that breaks what the one before it allowed says how to migrate. The runtime, `1.0.0-preview.1`, implements DOMQL's specification `1.0.0-preview.1` on Nexo's language `1.0.0-beta.41`, definition version 38. DOMQL declares the DOM as types of its own. It is not yet published to npm or NuGet; you can [build and try it locally](#build-and-try-it). See [the status overview](docs/features-status.md), and [what 1.0 requires](docs/features-status.md#what-1-0-requires).
+> **Preview.** No breaking redesign is planned, and a version that breaks what the one before it allowed says how to migrate. The runtime, `1.0.0-preview.1`, implements DOMQL's specification `1.0.0-preview.1` on Nexo's language `1.0.0-preview.1`, definition version 38. DOMQL declares the DOM as types of its own. It is not yet published to npm or NuGet; you can [build and try it locally](#build-and-try-it). See [the status overview](docs/features-status.md), and [what 1.0 requires](docs/features-status.md#what-1-0-requires).
## Features
@@ -98,7 +98,7 @@ The source import above works when serving the repository; the [library guide](n
| --- | --- |
| [Library guide](nuget/README.md) | Install DOMQL, learn the language by example and use the API |
| [DOMQL specification](spec/README.md) | Queries, the DOM's vocabulary, evaluating and watching a query, its results, events, executions, and the API |
-| [Nexo specification](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md) | The language DOMQL is written in, and its runtime, at the release DOMQL builds against |
+| [Nexo specification](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md) | The language DOMQL is written in, and its runtime, at the release DOMQL builds against |
| [Version history](VERSION-HISTORY.md) | Each version of DOMQL, with the features it added and what it changed |
| [Changelog](CHANGELOG.md) | Each release of the packages and what it changed |
| [Design](docs/domql-design.md) | How DOMQL is built, and the decisions it did not take |
diff --git a/VERSION-HISTORY.md b/VERSION-HISTORY.md
index 2d814e0..a2f46aa 100644
--- a/VERSION-HISTORY.md
+++ b/VERSION-HISTORY.md
@@ -17,7 +17,7 @@ Each entry says what its version breaks:
## `1.0.0-preview.1`
-*Unreleased · Nexo language `1.0.0-beta.41` · definition format 38*
+*Unreleased · Nexo language `1.0.0-preview.1` · definition format 38*
```domql
input.disabled // a state, a Boolean property; input.disabled() before, NEXO3017 now
@@ -56,6 +56,7 @@ query.select('counts', 'entries', 1, 'value').evaluate(); // 2; NEXO3602 before
query.select('counts', 'b').evaluate(); // NEXO3602: a dictionary holds its entries
domql.query('import Routes\nRoutes.first(routes)', { routes }, { types: { routes: 'List' } }); // routes captured as routes; NEXO3042 before
domql.format('-(-1)'); // '1'; '-(-1)' before
+domql.format('let n = 1\nreturn n'); // 'let n = 1\n\nreturn n'; 'let n = 1\nreturn n' before
```
```js
@@ -74,13 +75,13 @@ const updates = { changes: 'observable', reads: 'maintained', observations: [{ t
typeOf: value => undefined // NEXO5002 as a binding asks it; answer null
```
-DOMQL moves to Nexo's language `1.0.0-beta.41`, by way of `1.0.0-beta.40`, as [D76](docs/decisions.md#d76) and [D87](docs/decisions.md#d87) record, and follows its rule that a property names what its receiver is, has or is in, and a function does work: DOMQL's states are properties, as D87 records, and its executions are named by their verbs, as [D88](docs/decisions.md#d88) records. Nexo's [language history](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/LANGUAGE-HISTORY.md#v1-0-0-beta-41) sets out its own changes by version; those below are the ones a query, a caller and a module meet.
+DOMQL moves to Nexo's language `1.0.0-preview.1`, by way of `1.0.0-beta.40` and `1.0.0-beta.41`, as [D76](docs/decisions.md#d76), [D87](docs/decisions.md#d87) and [D108](docs/decisions.md#d108) record, and follows its rule that a property names what its receiver is, has or is in, and a function does work: DOMQL's states are properties, as D87 records, and its executions are named by their verbs, as [D88](docs/decisions.md#d88) records. Nexo's [language history](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/LANGUAGE-HISTORY.md#v1-0-0-preview-1) sets out its own changes by version; those below are the ones a query, a caller and a module meet.
**Vocabulary**
- [Focus is followed into open shadow roots](spec/vocabulary.md#observations-types): `focused`, `focusWithin`, `activeElement` and a selector testing focus report a move between two elements of one open shadow root, which they missed, since its events reach no further than the root, and the focused element's removal, which Firefox and WebKit fire no event for, as [D90](docs/decisions.md#d90) records.
- [`scroll`'s offset](spec/vocabulary.md#property-element-scroll) runs as the box's style says, a reversed flex container's included, and stays within its range, so an elastic overscroll past either end reads as that end.
-- [States](spec/vocabulary.md#states) are Boolean properties, read without a call, as Nexo's [states and tests](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/vocabulary.md#vocabulary-boolean-functions) set out: an element's `disabled`, `readonly`, `textEditable`, `focusWithin`, `displayed`, `focusable`, `popoverOpen`, `checked`, `indeterminate` and `autofilled`, the document's `visible`, and the ARIA view's `checked` and `disabled`, each a function before.
+- [States](spec/vocabulary.md#states) are Boolean properties, read without a call, as Nexo's [states and tests](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/vocabulary.md#vocabulary-boolean-functions) set out: an element's `disabled`, `readonly`, `textEditable`, `focusWithin`, `displayed`, `focusable`, `popoverOpen`, `checked`, `indeterminate` and `autofilled`, the document's `visible`, and the ARIA view's `checked` and `disabled`, each a function before.
- Five states take new names as they become properties: an element's `hover` and `focus` are `hovered` and `focused`, the document's `focus` is `focused`, and the window's `share` and `clipboard` are `canShare` and `hasClipboard`.
- A state is read through its module as before, `Domql.checked(it)`, and filtered by with a body, `rows.where(it.checked)`; a reference to one, `rows.where(Domql.checked)`, is refused (NEXO3076), since only a function has one.
@@ -89,7 +90,7 @@ DOMQL moves to Nexo's language `1.0.0-beta.41`, by way of `1.0.0-beta.40`, as [D
- Nexo's own members that make a value of their receiver are functions: a number's `round()`, `floor()`, `ceiling()`, `truncate()` and `abs()`, a text's `trim()`, `lowercase()` and `uppercase()`, and a list's `reverse()`, `distinct()` and `flatten()`, each a property before.
- A letter right after a number makes one invalid token, NEXO1000, so `1else` is refused, where it read as `1` and `else`.
- A number is written in hexadecimal, octal or binary too, `0xFF`, `0o17` and `0b1010`, and a `_` may stand between two digits of any number, `1_000_000`, where `0xFF` read as `0` and a member written without its dot, NEXO1011.
-- [`and` and `or`](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/expressions.md#logical-expressions-negations-and-groups-type) share a type only where their value is used: `it.attached and "here" or "away"` is a `String`, where it was refused.
+- [`and` and `or`](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/expressions.md#logical-expressions-negations-and-groups-type) share a type only where their value is used: `it.attached and "here" or "away"` is a `String`, where it was refused.
- A conversion of a value of `Any` converts by the type the value turns out to be, failing with NEXO5053 where nothing converts it, where it was refused at resolution.
- A computed name through a namespace reads as it does after `@`: `Domql.["window"]` is `Domql.window`.
- [A query declares its bindings' types](spec/queries.md#making-a-query-declared-types), `domql.query(text, bindings, { types })`, capturing data as a module's structured type, a map as a dictionary, where every binding was typed from its value.
@@ -115,7 +116,7 @@ DOMQL moves to Nexo's language `1.0.0-beta.41`, by way of `1.0.0-beta.40`, as [D
**Results**
- [A selection](spec/queries.md#selecting-a-result) steps into a dictionary's `entries` and a pair's `key` and `value`, the form [a result holds them](spec/results.md#results-collections) in, where a path into either was refused.
-- `domql.format` writes a negated number literal as the number, `-(-1)` as `1`, and a call's arguments after a block's `end` on lines of their own.
+- `domql.format` writes a negated number literal as the number, `-(-1)` as `1`, a call's arguments after a block's `end` on lines of their own, and an empty line between a body's last local and its `return`, at every level, as Nexo's [canonical bodies](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/definition.md#bodies-definition-and-canonical-text) set out.
- Data a result holds nesting deeper than 1,000 levels is refused, NEXO5052, and a `sum` or a `sequence` no finite number holds, NEXO5020.
**Modules**
@@ -123,7 +124,7 @@ DOMQL moves to Nexo's language `1.0.0-beta.41`, by way of `1.0.0-beta.40`, as [D
- [A delivery inside a handler](spec/behaviors.md#behaviors-occurrences) reaches every subscription before the one around it goes on, so a later subscription hears it first, and [an acknowledgment](spec/behaviors.md#behaviors-acknowledgment) rejects at the first failure while others may still be applying the occurrence, as [D93](docs/decisions.md#d93) records; neither changed, the specification promised more.
- [A kept value beside an outside writer](spec/vocabulary.md#execution-element-owned-writes-yielding) is judged by a heuristic, and [a committed position](spec/vocabulary.md#execution-element-owned-writes-framework) is let go of once its host confirms the render, not the occurrence's acknowledgment, as [D94](docs/decisions.md#d94) records.
- [A transient measurement's read](spec/vocabulary.md#extension-modules-environment) is synchronous and writes nothing, and [a module's state per document](spec/vocabulary.md#extension-modules-state-per-document) is one for each copy of its code, as [D98](docs/decisions.md#d98) and [D99](docs/decisions.md#d99) record.
-- [A member reading maintained values](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/members.md) declares a result that can be null, NEXO4071, since it reads as null until its first sample arrives.
+- [A member reading maintained values](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/members.md) declares a result that can be null, NEXO4071, since it reads as null until its first sample arrives.
- A module's `typeOf` answering nothing is a fault, NEXO5002.
- A fixed parameter is required and takes no default, NEXO4072, and an observation takes no expression or predicate parameter, NEXO4055.
- A module error names a declaration only by a name that is a string.
@@ -149,7 +150,7 @@ DOMQL moves to Nexo's language `1.0.0-beta.41`, by way of `1.0.0-beta.40`, as [D
- `value and x`, where `value` is of `Any`, is of `Any`. Give it a fallback, or test it where one type is needed.
- An object expression after a member declared `Any` that answers a list applies to the list once. Declare the member's result as a list, `List`, so it applies to each item.
- A query nesting deeper than 256 levels, summing more than 256 terms, or holding a string with a surrogate standing alone, is refused. Group part of a long chain, as `a + b + (c + d)` does, and write the whole character.
-- A caller that compared `domql.format`'s text for such a negation or such a call reads the new text, which parses to the same definition.
+- A caller that compared `domql.format`'s text for such a negation, such a call or a body with locals reads the new text, which parses to the same definition.
- A holder that keeps its value writes it again against a writer that answers with a new value each time, as code animating the property it holds does, where it yielded. Hold the target with `keep = false`, or end the holding while the other writer writes it.
- A module member's implementation is no longer promised a call at each evaluation of a watch, though it still gets one. Count nothing on its calls, and keep what must follow every evaluation out of it: a member reads alone.
@@ -644,7 +645,7 @@ DOMQL moves to Nexo's language `1.0.0-beta.15`, which settles what Nexo's status
- **Membership compares by key equality alone.** `contains`, `indexOf`, `distinct` and `distinctBy` take numbers, strings, Booleans, references and null, so a list of elements works as before, and one of objects, lists or values of `Any` is refused (NEXO3083), where it was compared by identity.
- **A result path is checked wherever it is given,** so `select` refuses a malformed path as it did, and steps into an object's own fields and a list's items alone.
- **A module's declarations name Nexo's own types qualified,** as `Nexo.Number`, where the module declares a type of that name.
-- **Conditions Nexo told apart by message have codes of their own,** NEXO5043 to NEXO5050 among them, as [Nexo's language history](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/LANGUAGE-HISTORY.md) records.
+- **Conditions Nexo told apart by message have codes of their own,** NEXO5043 to NEXO5050 among them, as [Nexo's language history](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/LANGUAGE-HISTORY.md) records.
**Breaking:** a query that tested membership in a list of objects, lists or values of `Any` is refused; test a key field instead, as `items.any(it.id == id)`.
diff --git a/docs/decisions.md b/docs/decisions.md
index d211640..c30067e 100644
--- a/docs/decisions.md
+++ b/docs/decisions.md
@@ -409,7 +409,7 @@ Each entry is one of three kinds:
- **Kind:** Contract.
- **Decision:** `on(type, options?)` takes a second, optional positional argument, a `Listening { capture }`, so `on("click", { capture = true })` listens as the event is captured on its way to its target, and `on("click")` as before, at the target and as it bubbles. It listens passively either way, for observing alone, as [D2](#d2) has it.
- **Why:**
- - A member's argument form is positional or options, never both, and `on("click")` keeps its form, so the option is a structured value its parameter constructs from the object expression written there, as Nexo's [constructing a structure](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/types.md#types-constructing-a-structure) sets out.
+ - A member's argument form is positional or options, never both, and `on("click")` keeps its form, so the option is a structured value its parameter constructs from the object expression written there, as Nexo's [constructing a structure](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/types.md#types-constructing-a-structure) sets out.
- A structure leaves room for another listening option without changing the argument form, which would break every subscription.
- Listening in the capture phase at an ancestor observes an event before any listener nearer its target runs, so a listener there that stops it hides nothing.
- **Declined:**
@@ -930,7 +930,7 @@ Each entry is one of three kinds:
*November 2, 2026*
- **Kind:** Contract.
-- **Decision:** A host call's function argument reaches its implementation as a kept function, which Nexo's language `1.0.0-beta.20` designed for DOMQL ([C13](features-status.md#planned-extension-contract)), as its [decisions](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/decisions.md#d49) record. DOMQL ends it as the execution keeping it ends: a continuous execution's instance ending or accepting other arguments, a once execution's answer settling, a subscription ending. Each call counts as an evaluation of the instance's, so what it reads reads alone.
+- **Decision:** A host call's function argument reaches its implementation as a kept function, which Nexo's language `1.0.0-beta.20` designed for DOMQL ([C13](features-status.md#planned-extension-contract)), as its [decisions](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/decisions.md#d49) record. DOMQL ends it as the execution keeping it ends: a continuous execution's instance ending or accepting other arguments, a once execution's answer settling, a subscription ending. Each call counts as an evaluation of the instance's, so what it reads reads alone.
- **Why:**
- A running behavior keeps a test of what it hears, as a route's condition, and calls it inside each event's dispatch; data alone left every such test a protocol of the module's own.
- DOMQL alone knows when what it started ends, so it disposes each prepared call then, and a call after that fails with Nexo's code, where it would read a page the caller has moved on from.
@@ -1156,7 +1156,7 @@ Each entry is one of three kinds:
- **Why:**
- Every planned capability is implemented or declined but A1 and A5's queue. What callers use today, the JavaScript half, is complete.
- The C# half is a client of that contract. It maps results onto records, drives the operations the JavaScript half offers, and carries across the boundary the order that half already keeps ([D69](#d69)). The questions D46 leaves open are its own: a host's own transport, records a field discriminates, and checking text without a parser in .NET. Should its design need more of the JavaScript half, that is an addition, which a beta allows.
- - Nexo holds the same stance: it is in its beta, as its [decisions](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/decisions.md#d27) record, while its tooling waits for its design, as its [status](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/features-status.md#tooling) records.
+ - Nexo holds the same stance: it is in its beta, as its [decisions](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/decisions.md#d27) record, while its tooling waits for its design, as its [status](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/features-status.md#tooling) records.
- A caller reads `domql.info.versions` to learn what it can rely on. A beta runtime implementing an alpha specification would promise a stability its contract's version denies.
- **Declined:**
- Waiting for the C# half. Its design has not started, and the JavaScript half would go without a promise until it ends.
@@ -1190,7 +1190,7 @@ Each entry is one of three kinds:
- **Kind:** Process.
- **Decision:** `nexo.release` pins a release of Nexo, `1.0.0-beta.1` first, and the build extracts the tree of its tag, `v1.0.0-beta.1`, where `nexo.commit` pinned a commit. Every link into Nexo names that tag, so the links move with the pin, `main` among the links it replaces. A link to another commit is a record of the past.
- **Why:**
- - Nexo now advances its language once per release and cuts each release as a signed tag, as its [D66](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/decisions.md#d66) records, so a release is what DOMQL can rely on.
+ - Nexo now advances its language once per release and cuts each release as a signed tag, as its [D66](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/decisions.md#d66) records, so a release is what DOMQL can rely on.
- A commit pin named one fix, and moving it rewrote a hash in 81 places across 21 documents.
- A link to Nexo's `main` changes under DOMQL's documents, unseen.
- **Declined:** Waiting for Nexo's packages on a registry, which would keep DOMQL on a commit until they are published; the packages remain the next step, as [consuming the language](features-status.md#consuming-nexo) sets out.
@@ -1220,7 +1220,7 @@ Each entry is one of three kinds:
- A release is a signed tag, `v` and its version, on the commit that dates its changelog entry. Its packages are published from that tag.
- `1.0.0-beta.2` is the first version collected so. The versions before it stand as they were declared.
- **Why:**
- - A version a caller relies on is one a release fixes, and DOMQL's version history and Nexo's language history now follow one rule, as Nexo's [D66](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/decisions.md#d66) records.
+ - A version a caller relies on is one a release fixes, and DOMQL's version history and Nexo's language history now follow one rule, as Nexo's [D66](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/decisions.md#d66) records.
- It narrows [D75](#d75)'s rule that each version advances for its own reason: the specification version's reason is now a release whose contract changed.
- **Declined:** Dating a release when its packages are published, which leaves a caller nothing to pin until a registry holds them; DOMQL's packages wait for Nexo's anyway.
@@ -1236,7 +1236,7 @@ Each entry is one of three kinds:
- Until then, a change fixes, explains, speeds up or documents, or meets a requirement. A feature lands only where Forma's scripts need it, as a decision records.
- **Why:**
- The beta promised no breaking redesign, but said nothing about when breaks end.
- - DOMQL's contract holds Nexo's language, so it can be no more settled than Nexo, which waits for its own 1.0 as its [D67](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/decisions.md#d67) records.
+ - DOMQL's contract holds Nexo's language, so it can be no more settled than Nexo, which waits for its own 1.0 as its [D67](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/decisions.md#d67) records.
- The planned capabilities came from reading Forma's scripts, so running them is the test of DOMQL's contract.
- **Declined:**
- Making the C# half a requirement, which would hold 1.0 for a design the owner hasn't decided is needed.
@@ -1252,7 +1252,7 @@ Each entry is one of three kinds:
- **Decision:** From `1.0.0-beta.1` on, each entry of the [version history](../VERSION-HISTORY.md) leads with examples of what its version changed: a query's in a `domql` block, a caller's or a module's in a `js` block. Each line's comment says what it does at that version and what it did before. The entry's list follows them as the reference. Each example is run at its version when its entry is written; the gate doesn't run them.
- **Why:**
- The list states each change precisely, but a caller migrating needs the line to write.
- - Nexo's language history follows the same rule, as its [D70](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/decisions.md#d70) records, and running its examples found what `1.0.0-beta.2`'s entry here misstated: a chain's limit counts terms, and a grouped chain is written `a + b + (c + d)`.
+ - Nexo's language history follows the same rule, as its [D70](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/decisions.md#d70) records, and running its examples found what `1.0.0-beta.2`'s entry here misstated: a chain's limit counts terms, and a grouped chain is written `a + b + (c + d)`.
- **Declined:** Running the history's examples in the gate, which would make a record of the past change with later versions.
@@ -1262,7 +1262,7 @@ Each entry is one of three kinds:
*November 3, 2026*
- **Kind:** Contract.
-- **Decision:** `domql.query(text, bindings, { types })` declares the type of a top-level binding by its notation, which Nexo's `createBindings` binds as its [declared types](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/bindings.md#runtime-bindings) do. Every binding made from the query keeps the types, `with`'s, an execution's update and a reaction's, and the query keeps a copy of them.
+- **Decision:** `domql.query(text, bindings, { types })` declares the type of a top-level binding by its notation, which Nexo's `createBindings` binds as its [declared types](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/bindings.md#runtime-bindings) do. Every binding made from the query keeps the types, `with`'s, an execution's update and a reaction's, and the query keeps a copy of them.
- **Why:**
- It is the feature the 1.0 freeze allows, as [D80](#d80) records: replacing Forma's scripts needs it. Forma's input router binds its routes as `List` and its overrides as a dictionary of structures, and its culture coordinator binds its starting state as a structure. Data typed from itself is of no module's type, so each was refused (NEXO3042), and routes whose families carry different fields could not be bound at all.
- Nexo already captures data as a declared type, a map as a dictionary and a set as a list, and checks it, so DOMQL passes the types through and adds no rule of its own.
@@ -1344,7 +1344,7 @@ Each entry is one of three kinds:
- **Kind:** Contract, approved by the owner.
- **Decision:**
- - DOMQL moves to Nexo's language `1.0.0-beta.41`, whose release is Nexo's `1.0.0-beta.2`, and follows its rule that a property names what its receiver is, has or is in, and a function does work, as Nexo's [D77](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/decisions.md#d77) records.
+ - DOMQL moves to Nexo's language `1.0.0-beta.41`, whose release is Nexo's `1.0.0-beta.2`, and follows its rule that a property names what its receiver is, has or is in, and a function does work, as Nexo's [D77](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/decisions.md#d77) records.
- Every state DOMQL declares is a Boolean property, read without a call, `it.checked`: an element's `disabled`, `readonly`, `textEditable`, `focused`, `focusWithin`, `displayed`, `focusable`, `hovered`, `popoverOpen`, `checked`, `indeterminate` and `autofilled`, the document's `visible` and `focused`, the window's `canShare` and `hasClipboard`, and the ARIA view's `checked` and `disabled`. Each was a Boolean function.
- Five take new names as they become properties:
@@ -1647,3 +1647,16 @@ Each entry is one of three kinds:
- **Declined:**
- Publishing an npm package now, whose sources import `@formaui-net/nexo` by name and would need DOMQL's bundle to stop carrying the language, the work [consuming the language](features-status.md#consuming-nexo) plans.
- Keeping `publish.ps1` beside the full gate: one command packs and verifies what a release publishes.
+
+
+
+## D108 — DOMQL builds against Nexo's first preview
+
+*November 5, 2026*
+
+- **Kind:** Contract, approved.
+- **Decision:** `nexo.release` pins Nexo's release `1.0.0-preview.1`, of language `1.0.0-preview.1`, and DOMQL's documents link to Nexo's at its tag. DOMQL's `1.0.0-preview.1` describes DOMQL on that language, so `domql.format` writes an empty line between a body's last local and its `return`, as Nexo's [D83](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/decisions.md#d83) records.
+- **Why:**
+ - DOMQL's first release runs on a released Nexo, and Nexo's first preview is its newest release.
+ - The language changed nothing a query relies on: a body's canonical text changes, and reads back as the same definition.
+- **Declined:** Releasing DOMQL on Nexo's `1.0.0-beta.2`, a stage FormaUI Versioning no longer names, beside a DOMQL in its preview.
diff --git a/docs/domql-design.md b/docs/domql-design.md
index 59b0367..72b0a97 100644
--- a/docs/domql-design.md
+++ b/docs/domql-design.md
@@ -1,6 +1,6 @@
# DOMQL Design v1.0.0-preview.1
-The [DOMQL specification](../spec/README.md) is the contract: DOMQL's module, which declares the DOM as Nexo's domain, and the host that carries queries out against a document. This design sets out how this implementation is built to meet it, and the reasons behind the choices that shape it. It describes DOMQL's version `1.0.0-beta.2` on Nexo's definition version 38, as the specification does, and an outline of the C# half, which waits for its design; [the status overview](features-status.md) says where the implementation still differs. [Nexo's design](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/nexo-design.md), at the release DOMQL builds against, sets out how the language and its runtime are built.
+The [DOMQL specification](../spec/README.md) is the contract: DOMQL's module, which declares the DOM as Nexo's domain, and the host that carries queries out against a document. This design sets out how this implementation is built to meet it, and the reasons behind the choices that shape it. It describes DOMQL's version `1.0.0-beta.2` on Nexo's definition version 38, as the specification does, and an outline of the C# half, which waits for its design; [the status overview](features-status.md) says where the implementation still differs. [Nexo's design](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/nexo-design.md), at the release DOMQL builds against, sets out how the language and its runtime are built.
In this document:
@@ -64,7 +64,7 @@ A selector is read for what it tests by `Selectors`, a scan of its text that nee
## Comparing and patching
-The comparer reads what Nexo's [result metadata](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/evaluation.md#runtime-results) records beside each value: the provenance of each item, the source the earliest projection it descends from read, by which a list is matched where Nexo classifies every item's provenance as a reference, each standing once; the origin of each value, which tells whether a number came from the same branch, operand or property as the number before it; and the tolerance it compares within. A result therefore holds data alone, and a change set never names an element.
+The comparer reads what Nexo's [result metadata](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/evaluation.md#runtime-results) records beside each value: the provenance of each item, the source the earliest projection it descends from read, by which a list is matched where Nexo classifies every item's provenance as a reference, each standing once; the origin of each value, which tells whether a number came from the same branch, operand or property as the number before it; and the tolerance it compares within. A result therefore holds data alone, and a change set never names an element.
The patcher computes the change set that takes one reconciled snapshot to the next, and applies change sets in place to live state. A watch keeps the metadata of the snapshot it holds for the next comparison, so `sourceOf` reads an item's provenance from it, walking the records of the fields and items along the path, and allocates nothing until a caller asks.
diff --git a/docs/features-status.md b/docs/features-status.md
index cc80364..0f58be3 100644
--- a/docs/features-status.md
+++ b/docs/features-status.md
@@ -2,15 +2,15 @@
## Current state
-**DOMQL is in its preview, `1.0.0-preview.1`. Its vocabulary, queries, watches, events, executions and behaviors are implemented on Nexo's language `1.0.0-beta.41`, definition version 38. The specification describes DOMQL's `1.0.0-preview.1`, which the implementation follows: the DOM declared as DOMQL's own types, read through the `Domql` module every query imports. Every [planned capability](#planned-capabilities) is implemented or declined but the C# half's, A1 and A5's queue, which wait for its design.**
+**DOMQL is in its preview, `1.0.0-preview.1`. Its vocabulary, queries, watches, events, executions and behaviors are implemented on Nexo's language `1.0.0-preview.1`, definition version 38. The specification describes DOMQL's `1.0.0-preview.1`, which the implementation follows: the DOM declared as DOMQL's own types, read through the `Domql` module every query imports. Every [planned capability](#planned-capabilities) is implemented or declined but the C# half's, A1 and A5's queue, which wait for its design.**
| Version | Implementation | Specification |
| --- | --- | --- |
| DOMQL specification | `1.0.0-preview.1` | `1.0.0-preview.1` |
-| Nexo language | `1.0.0-beta.41` | `1.0.0-beta.41` |
+| Nexo language | `1.0.0-preview.1` | `1.0.0-preview.1` |
| Definition format | 38 | 38 |
-- **The language DOMQL runs on.** DOMQL follows Nexo's language `1.0.0-beta.41`, which Nexo's release `1.0.0-beta.2` carries, so it builds against that release once `nexo.release` pins it, through a checkout `NEXO_SOURCE` names until then; `nexo.release` pins `1.0.0-beta.1` now, of language `1.0.0-beta.40`, and its documents link to [Nexo's documents at that tag](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md), moving with the pin. The language was called Lexica before the [migration](#migration-to-nexo).
+- **The language DOMQL runs on.** DOMQL follows Nexo's language `1.0.0-preview.1`, which Nexo's release `1.0.0-preview.1` carries and `nexo.release` pins, as [D108](decisions.md#d108) records, and its documents link to [Nexo's documents at that tag](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md), moving with the pin. The language was called Lexica before the [migration](#migration-to-nexo).
- **Packages.** The bundle and type declarations are built, with Nexo bundled inside `domql.js`. The NuGet package is packed locally, carrying the runtime version `1.0.0-preview.1`, and is unpublished. The npm package is not made yet: `package.json` is private and carries no version.
- **The C# half** waits for its design, as [D46](decisions.md#d46) records.
@@ -24,7 +24,7 @@ The [specification](../spec/README.md) defines the contract, and the [design](do
| --- | --- |
| [The C# half](#the-c-half) | Waits for its design |
| [Planned capabilities](#planned-capabilities) | The C# half's alone remain, waiting for its design |
-| [Release](#release) | The preview is declared, `1.0.0-preview.1`, DOMQL's first release; it waits for Nexo's first preview, which it builds against |
+| [Release](#release) | The preview is declared, `1.0.0-preview.1`, DOMQL's first release, on Nexo's first preview; nuget.org's trusted publishing remains before it's cut |
| [What 1.0 requires](#what-1-0-requires) | Six requirements, one met in part |
- **A specification version collects the changes between two releases.** A change to DOMQL's contract joins the [version history](../VERSION-HISTORY.md)'s newest entry while it reads *Unreleased*, and opens the next version's entry once it is released, as [D79](decisions.md#d79) records.
@@ -143,9 +143,9 @@ DOMQL moved from Lexica at `0e98b3e`, language `1.0.0-alpha.33`, to Nexo's langu
- **One pin.** The migration was planned in checkpoints, each on a Nexo commit pinned as Nexo's work landed. Nexo reached its beta first, and its checklists describe the beta, so DOMQL moved to the beta at one pin, its checkpoints the order of the work, and passed its gate once on the beta: pinning a commit for each checkpoint would have meant writing against interfaces Nexo had already changed again.
- **Imports.** DOMQL supplies its own module, `Domql`, as every query's import, and a query writes its other imports. An application configures no imports of its own, so a query's text means the same whatever was configured, as [D4](decisions.md#d4) records.
- **Errors.** DOMQL's own conditions take `DOMQL` codes, catalogued in [errors](../spec/errors.md), bounded to the conditions it reports today; an error of Nexo's passing through DOMQL keeps its own code.
-- **Module errors.** A module error of DOMQL's own, as its dispatch table's refusals are, is built with `NexoError.module`, which Nexo declared for its hosts in language `1.0.0-beta.2` for DOMQL's migration, as its [decisions](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/decisions.md#d29) record.
-- **Host calls on a receiver of unknown type.** What such a call requests is read from the candidates Nexo answers for it, every declaration that takes the call as it is written, which Nexo answers from language `1.0.0-beta.3` for DOMQL, as its [decisions](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/decisions.md#d30) record. DOMQL read them from an index of its own before, which counted host calls a query could not reach.
-- **What the migration found in Nexo since,** fixed in Nexo's languages `1.0.0-beta.4` to `1.0.0-beta.8`, as its [decisions](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/decisions.md#d31) record: a host call on a value of `Any` is refused as Nexo resolves it, where DOMQL refused it as a value to evaluate; a module's own type named `Pair` is named by that name in its declarations; `@Domql` standing alone gives `~Domql`; a watch made stale by a module recognizing values compares within each value's tolerance, as Nexo keeps origins across resolutions of one definition; and a member read through a value of `Any` is compared within the tolerance it declares.
+- **Module errors.** A module error of DOMQL's own, as its dispatch table's refusals are, is built with `NexoError.module`, which Nexo declared for its hosts in language `1.0.0-beta.2` for DOMQL's migration, as its [decisions](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/decisions.md#d29) record.
+- **Host calls on a receiver of unknown type.** What such a call requests is read from the candidates Nexo answers for it, every declaration that takes the call as it is written, which Nexo answers from language `1.0.0-beta.3` for DOMQL, as its [decisions](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/decisions.md#d30) record. DOMQL read them from an index of its own before, which counted host calls a query could not reach.
+- **What the migration found in Nexo since,** fixed in Nexo's languages `1.0.0-beta.4` to `1.0.0-beta.8`, as its [decisions](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/decisions.md#d31) record: a host call on a value of `Any` is refused as Nexo resolves it, where DOMQL refused it as a value to evaluate; a module's own type named `Pair` is named by that name in its declarations; `@Domql` standing alone gives `~Domql`; a watch made stale by a module recognizing values compares within each value's tolerance, as Nexo keeps origins across resolutions of one definition; and a member read through a value of `Any` is compared within the tolerance it declares.
Contracts: [Queries](../spec/queries.md), [types](../spec/vocabulary.md#vocabulary-types), [extension modules](../spec/vocabulary.md#extension-modules), [results](../spec/results.md), [errors](../spec/errors.md).
@@ -276,16 +276,15 @@ DOMQL releases as [cutting a release](../CONTRIBUTING.md#cut-a-release) sets out
**Remaining for `1.0.0-preview.1`:**
1. Create `dev` and `candidate` from `main`'s tip. The organization's linear-history rule refuses a new branch holding `main`'s one merge commit, `3c68220`, made before the rules, so the owner lifts it for DOMQL while they're made.
-2. Move `nexo.release` to Nexo's `1.0.0-preview.1`, once Nexo tags it, and link Nexo's documents at that tag.
-3. Create nuget.org's trusted-publishing policy for `release.yml` in the `release` environment, which needs the owner's account.
-4. Release `1.0.0-preview.1`.
+2. Create nuget.org's trusted-publishing policy for `release.yml` in the `release` environment, which needs the owner's account.
+3. Release `1.0.0-preview.1`.
### Consuming the language
-**Current:** DOMQL depends on `@formaui-net/nexo` through `file:.nexo`, which the build fills with Nexo's release `nexo.release` pins, `1.0.0-beta.1`, the tree of its tag, taken from a checkout beside this one named `formaui-net.Nexo`, or links to the checkout `NEXO_SOURCE` names; CI checks Nexo out at the same tag. It imports the language's entry point alone, and bundles it into `domql.js`. The language's tests that run through DOMQL's entry point are DOMQL's integration tests.
+**Current:** DOMQL depends on `@formaui-net/nexo` through `file:.nexo`, which the build fills with Nexo's release `nexo.release` pins, `1.0.0-preview.1`, the tree of its tag, taken from a checkout beside this one named `formaui-net.Nexo`, or links to the checkout `NEXO_SOURCE` names; CI checks Nexo out at the same tag. It imports the language's entry point alone, and bundles it into `domql.js`. The language's tests that run through DOMQL's entry point are DOMQL's integration tests.
**Remaining:**
@@ -293,7 +292,7 @@ DOMQL releases as [cutting a release](../CONTRIBUTING.md#cut-a-release) sets out
2. Write the NuGet bundle with `../nexo/nexo.js` as an import, and the npm bundle with `@formaui-net/nexo`, rather than carrying the language inside.
3. Have the gate check that DOMQL's packages depend on Nexo's and Nexo's on nothing of DOMQL's, and run DOMQL's tests against the packaged Nexo.
-Needs Nexo's packages, which its [release](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/features-status.md#release) publishes.
+Needs Nexo's packages, which its [release](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/features-status.md#release) publishes.
### Packages
@@ -326,7 +325,7 @@ It waits for Nexo's published packages. `release.yml` publishes the NuGet packag
| Requirement | Why | State |
| --- | --- | --- |
-| **Nexo's 1.0.** DOMQL runs on Nexo's 1.0, from its published packages. | DOMQL's contract holds the language its queries are written in, so it promises no more than Nexo does. | Nexo is in its beta, at `1.0.0-beta.1`, as [what Nexo's 1.0 requires](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/features-status.md#what-1-0-requires) sets out. |
+| **Nexo's 1.0.** DOMQL runs on Nexo's 1.0, from its published packages. | DOMQL's contract holds the language its queries are written in, so it promises no more than Nexo does. | Nexo is in its preview, at `1.0.0-preview.1`, as [what Nexo's 1.0 requires](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/features-status.md#what-1-0-requires) sets out. |
| **Contracts settled.** No decision is open, and each [deferred](#deferred) item and [decision not taken](domql-design.md#decisions-not-taken) is shown to land without a break. | What may still change after 1.0 must be able to change compatibly. | Holds: no decision is open, and each [deferred](#deferred) item and [decision not taken](domql-design.md#decisions-not-taken) lands as an addition or within the implementation. A watch's promise to evaluate its whole query each time was the one that would have made evaluating less a break; [what an evaluation gives](../spec/watches.md#watching-what-an-evaluation-gives) now leaves it to DOMQL. |
| **The C# half decided.** It is designed, or decided to follow 1.0 as an addition. | It waits for the owner's design, as [D46](decisions.md#d46) records, and a .NET application may need it to drive DOMQL. | Waits for its design. |
| **Published.** DOMQL's packages are on npm and NuGet, tested as consumers install them. | A caller pins a release it can install. | The NuGet package is packed locally, and the npm package is not made yet. |
@@ -351,7 +350,7 @@ This work is separate from the plan above. No order is assigned here.
| Work | Status | Remaining |
| --- | --- | --- |
-| Editor tooling | Waits for Nexo's design | Nexo's, through its syntax tree, in its [tooling](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/features-status.md#tooling), which waits for its design |
+| Editor tooling | Waits for Nexo's design | Nexo's, through its syntax tree, in its [tooling](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/features-status.md#tooling), which waits for its design |
**Verification outside the gate.** Performance is measured outside the gate, by `npm run bench` and `npm run scale` from `tests/`. `Domql.window.size` following a scrollbar that appears or goes runs in the gate, as a browser test with a launch of its own.
diff --git a/nexo.release b/nexo.release
index 7e0b231..5fd7619 100644
--- a/nexo.release
+++ b/nexo.release
@@ -1 +1 @@
-1.0.0-beta.2
+1.0.0-preview.1
diff --git a/nuget/README.md b/nuget/README.md
index 46130e8..e5368fb 100644
--- a/nuget/README.md
+++ b/nuget/README.md
@@ -2,9 +2,9 @@
**A declarative approach to managing the DOM.**
-DOMQL is a JavaScript library for querying the DOM, allowing you to read information from a document once or observe it as it changes. This guide takes you from your first query to watching results, handling events and extending the library. Its queries are written in [Nexo](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md).
+DOMQL is a JavaScript library for querying the DOM, allowing you to read information from a document once or observe it as it changes. This guide takes you from your first query to watching results, handling events and extending the library. Its queries are written in [Nexo](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md).
-> **Preview:** no breaking redesign is planned, and a version that breaks what the one before it allowed says how to migrate. `formaui-net.DOMQL` is not yet published to NuGet. [Build the package locally](#install-and-load) to try it. The package distributes a JavaScript ES module; the API in this guide runs in JavaScript. Every example here runs on this preview. The runtime, `1.0.0-preview.1`, implements DOMQL's specification `1.0.0-preview.1` on Nexo's language `1.0.0-beta.41`, definition version 38. [The status overview](https://github.com/FormaUI/DOMQL/blob/main/docs/features-status.md) says what is implemented and what is being built.
+> **Preview:** no breaking redesign is planned, and a version that breaks what the one before it allowed says how to migrate. `formaui-net.DOMQL` is not yet published to NuGet. [Build the package locally](#install-and-load) to try it. The package distributes a JavaScript ES module; the API in this guide runs in JavaScript. Every example here runs on this preview. The runtime, `1.0.0-preview.1`, implements DOMQL's specification `1.0.0-preview.1` on Nexo's language `1.0.0-preview.1`, definition version 38. [The status overview](https://github.com/FormaUI/DOMQL/blob/main/docs/features-status.md) says what is implemented and what is being built.
## In this guide
@@ -998,7 +998,7 @@ Modules can also declare Boolean members, properties and functions whose result
A member the host invokes, `invokedBy: 'host'`, is a host call that DOMQL carries out: an event source, `requestKind: 'subscription'`, or an execution, `requestKind: 'execution'`, which runs `once` or `continuous` as its `executionMode` says. An event source's implementation receives the receiver, arguments, environment and an event-delivery callback, as `{ receiver, args, env, deliver }`, and returns an object with a `stop` method to end listening. Each event is captured as the type its declaration's result names, and a module adds event types of its own as mappings of DOMQL's type selector `event`, `{ selector: 'event', key, type }`, each naming the type its events are captured as.
-[Nexo's modules](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/modules.md#modules) specify the full extension contracts. The next section shows execution modules.
+[Nexo's modules](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/modules.md#modules) specify the full extension contracts. The next section shows execution modules.
### Bind data as a module's type
@@ -1540,9 +1540,9 @@ filtered.dispose();
## Learn more
- [Repository README](https://github.com/FormaUI/DOMQL): what DOMQL is for, what is built, and how to build and test it.
-- [Nexo specification](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md): the language DOMQL is written in, its syntax, types, null semantics, imports and extensions, and the runtime contracts of its modules.
+- [Nexo specification](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md): the language DOMQL is written in, its syntax, types, null semantics, imports and extensions, and the runtime contracts of its modules.
- [DOMQL specification](https://github.com/FormaUI/DOMQL/blob/main/spec/README.md): queries, the DOM's vocabulary, evaluating and watching a query, its results, events, executions, and the API.
-- [DOMQL design](https://github.com/FormaUI/DOMQL/blob/main/docs/domql-design.md): how DOMQL is built, and the decisions it did not take, and the [Nexo design](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/docs/nexo-design.md): how the language and its runtime are built.
+- [DOMQL design](https://github.com/FormaUI/DOMQL/blob/main/docs/domql-design.md): how DOMQL is built, and the decisions it did not take, and the [Nexo design](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/nexo-design.md): how the language and its runtime are built.
- [Changelog](https://github.com/FormaUI/DOMQL/blob/main/CHANGELOG.md): each release of the package and what it changed.
- [Status](https://github.com/FormaUI/DOMQL/blob/main/docs/features-status.md): what is implemented, what is being built, and what remains.
diff --git a/spec/README.md b/spec/README.md
index b8ff321..976c363 100644
--- a/spec/README.md
+++ b/spec/README.md
@@ -1,12 +1,12 @@
# DOMQL Specification v1.0.0-preview.1
-DOMQL reads the DOM and shapes what it reads as data, keeps that data current as the document changes, delivers the page's events as data, and carries out the executions its own module and its extensions declare. Its queries are scripts written in [Nexo](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md), whose specification holds two contracts: the language's, what a script means, and the runtime's, how a host binds, resolves and evaluates a script. DOMQL declares the DOM as Nexo's domain, in a module like any other, and is the host that carries each query out against a document. It adds no language rule: a rule of the language or of its runtime is Nexo's, and this specification links to it.
+DOMQL reads the DOM and shapes what it reads as data, keeps that data current as the document changes, delivers the page's events as data, and carries out the executions its own module and its extensions declare. Its queries are scripts written in [Nexo](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md), whose specification holds two contracts: the language's, what a script means, and the runtime's, how a host binds, resolves and evaluates a script. DOMQL declares the DOM as Nexo's domain, in a module like any other, and is the host that carries each query out against a document. It adds no language rule: a rule of the language or of its runtime is Nexo's, and this specification links to it.
This specification is the authoritative contract for DOMQL. It states what DOMQL is, not how far its implementation has come: [the status overview](../docs/features-status.md) says what this repository implements, and [the design](../docs/domql-design.md) how it is built.
-**Version.** This specification describes DOMQL's version `1.0.0-preview.1`, which changes as DOMQL's contract does, apart from its runtime's version and from Nexo's language. It describes DOMQL on Nexo's language version `1.0.0-beta.41`, of [definition version 38](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md#version). An implementation says which specification it follows, and which language version its Nexo runtime follows, in `domql.info.versions`, as [the API](api.md#api-entry-points-and-operations) sets out.
+**Version.** This specification describes DOMQL's version `1.0.0-preview.1`, which changes as DOMQL's contract does, apart from its runtime's version and from Nexo's language. It describes DOMQL on Nexo's language version `1.0.0-preview.1`, of [definition version 38](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md#version). An implementation says which specification it follows, and which language version its Nexo runtime follows, in `domql.info.versions`, as [the API](api.md#api-entry-points-and-operations) sets out.
## What it covers
@@ -14,8 +14,8 @@ Five layers meet whenever a query runs. Nexo's specification covers the first tw
| Layer | What it owns | Documents |
| --- | --- | --- |
-| The language | What a query means: its imports, syntax, names and scope, values and types, expressions and functions, members, extensions, and the contracts a vocabulary keeps | [Nexo's language](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/README.md) |
-| The runtime | Binding, resolving and evaluating a script for a host, the modules it registers, its definitions and its results | [Nexo's runtime](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/hosting.md) |
+| The language | What a query means: its imports, syntax, names and scope, values and types, expressions and functions, members, extensions, and the contracts a vocabulary keeps | [Nexo's language](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md) |
+| The runtime | Binding, resolving and evaluating a script for a host, the modules it registers, its definitions and its results | [Nexo's runtime](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/hosting.md) |
| DOMQL's module | The DOM as Nexo's domain: its nodes and shadow trees, its members, its states among them, its event sources and event types, its executions, and the observations that follow its changes | [Nodes and shadow trees](nodes-and-shadow-trees.md), [vocabulary](vocabulary.md), [events](events.md) |
| DOMQL, the host | Carrying a query out against a document: evaluating it, watching it, and invoking its host calls, delivering its events, carrying out its executions and keeping its behaviors where their module reaches them, through the API a caller uses | [Queries](queries.md), [evaluation](evaluation.md), [watches](watches.md), [results](results.md), [events](events.md), [executions](executions.md), [behaviors](behaviors.md), [the API](api.md), [errors](errors.md) |
| The caller | The application around DOMQL: which queries it makes, when it carries each out, and what it does with each result | The caller's own |
diff --git a/spec/api.md b/spec/api.md
index 6f74a21..d756dc1 100644
--- a/spec/api.md
+++ b/spec/api.md
@@ -81,7 +81,7 @@ Each entry point and operation is listed here with what it takes, and the sectio
| `query.subscribe(handler, options?)` | Subscribes to a subscription, answering a `DomqlEventListener`, as [subscribing](events.md#subscribing) sets out |
| `query.executeAsync(options?)` | Carries out a once execution, answering a promise of its result, as [executing once](executions.md#executions-executing-once) sets out |
| `query.run(options?)` | Starts a continuous execution, answering a `DomqlExecutionHandle`, as [running continuously](executions.md#executions-running-continuously) sets out |
-| `domql.format(source)` | The canonical text of a text, a definition or a query object, as [formatting](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/definition.md#definition-canonical-text) sets out |
+| `domql.format(source)` | The canonical text of a text, a definition or a query object, as [formatting](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/definition.md#definition-canonical-text) sets out |
| `domql.createModule(name, contents)` | Creates a module from its declarations, each that runs code carrying its implementation, as [extension modules](vocabulary.md#extension-modules) set out |
| `domql.registerModule(module)` | Registers a module's declarations in the instance's registry, as [extension modules](vocabulary.md#extension-modules) set out |
| `domql.registerModuleLoader(name, load)` | Registers the loader of a module loaded on request, as [loading a module on request](vocabulary.md#extension-modules-loading) sets out |
@@ -177,6 +177,6 @@ An operation that answers a handle, given a signal already aborted, answers a di
## Errors
-Every failure is a `NexoError` with its `code`, its `kind`, its `message` and the `location` it concerns, as Nexo's [errors](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/errors.md) set out, and a caller reads the code, the kind and the location rather than the message. A condition of Nexo's keeps its `NEXO` code, and one of DOMQL's own takes a `DOMQL` code, as [errors](errors.md) catalog them. A failure is reported where it arises: a syntax or structure failure as the query is made; a module failure as a module is created or registered, or as a request that uses a declaration without an implementation is carried out; a validation failure as the request is resolved; and an evaluation failure as it is carried out, a missing window among them.
+Every failure is a `NexoError` with its `code`, its `kind`, its `message` and the `location` it concerns, as Nexo's [errors](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/errors.md) set out, and a caller reads the code, the kind and the location rather than the message. A condition of Nexo's keeps its `NEXO` code, and one of DOMQL's own takes a `DOMQL` code, as [errors](errors.md) catalog them. A failure is reported where it arises: a syntax or structure failure as the query is made; a module failure as a module is created or registered, or as a request that uses a declaration without an implementation is carried out; a validation failure as the request is resolved; and an evaluation failure as it is carried out, a missing window among them.
A failure no handler or caller receives, as an `"error"` event no listener receives, a failure of an `"error"` handler or of a subscription's handler, or one a once execution reports after its caller stopped waiting, goes to the **window's error reporting**, its `reportError`, or the console where the window has none. A watch, an event listener and a waiting evaluation let go of every observation they hold even where letting go of one fails: each attempts every cleanup, reports a failure of one to the window's error reporting, and never lets it replace its result, its error or its cancellation.
diff --git a/spec/errors.md b/spec/errors.md
index 4a03401..fc596b5 100644
--- a/spec/errors.md
+++ b/spec/errors.md
@@ -2,9 +2,9 @@
-Every failure DOMQL reports is a `NexoError`, with its `code`, its `kind`, its `message` and the `location` it concerns, as Nexo's [errors](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/errors.md#diagnostics-codes) set out. A caller reads the code, the kind and the location, never the message.
+Every failure DOMQL reports is a `NexoError`, with its `code`, its `kind`, its `message` and the `location` it concerns, as Nexo's [errors](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/errors.md#diagnostics-codes) set out. A caller reads the code, the kind and the location, never the message.
-- **Nexo's conditions** keep their codes, `NEXO` and four digits, as Nexo's catalogs give them: [the language's](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/errors.md) for what a query may express, and [the runtime's](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/errors.md) for definitions, bindings, declarations and the API. A Nexo error passing through DOMQL keeps its code and takes no second one.
+- **Nexo's conditions** keep their codes, `NEXO` and four digits, as Nexo's catalogs give them: [the language's](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/errors.md) for what a query may express, and [the runtime's](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/errors.md) for definitions, bindings, declarations and the API. A Nexo error passing through DOMQL keeps its code and takes no second one.
- **DOMQL's own conditions** take codes of DOMQL's prefix, `DOMQL` and four digits, in the ranges Nexo's kinds use, as the tables below give them.
- **A code is stable.** It names its condition, never its wording. A new condition takes a new code, and a retired code is never reused.
diff --git a/spec/evaluation.md b/spec/evaluation.md
index f8a5e40..de8f39a 100644
--- a/spec/evaluation.md
+++ b/spec/evaluation.md
@@ -3,7 +3,7 @@
-**Evaluating** a query reads the document once and answers its result. DOMQL evaluates a query as Nexo's [runtime](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/evaluation.md#runtime-evaluation) evaluates a script, synchronously, against the document it runs against, and each member declares how it reads. A caller evaluates with `evaluate`, which answers at once, or with `evaluateAsync`, which also waits for the browser's first report of what a maintained member reads.
+**Evaluating** a query reads the document once and answers its result. DOMQL evaluates a query as Nexo's [runtime](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/evaluation.md#runtime-evaluation) evaluates a script, synchronously, against the document it runs against, and each member declares how it reads. A caller evaluates with `evaluate`, which answers at once, or with `evaluateAsync`, which also waits for the browser's first report of what a maintained member reads.
```js
const query = domql.query('{ size = panel.size, nearEnd = sentinel.intersects({ root = panel }) }', { panel, sentinel });
@@ -12,7 +12,7 @@ query.evaluate(); // Throws an evaluation error: intersects is mainta
await query.evaluateAsync(); // { size: { width: 640, height: 480 }, nearEnd: false }
```
-Evaluating a query is read-only, as [Nexo requires](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/members.md#how-a-member-reads) of every vocabulary. A measurement that needs the document changed first, such as measuring columns at their intrinsic widths under a temporary class, is an [execution](executions.md) of its own.
+Evaluating a query is read-only, as [Nexo requires](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/members.md#how-a-member-reads) of every vocabulary. A measurement that needs the document changed first, such as measuring columns at their intrinsic widths under a temporary class, is an [execution](executions.md) of its own.
In this document:
@@ -28,7 +28,7 @@ In this document:
`query.evaluate(options?)` resolves the query, then evaluates it once against the document in a single synchronous pass, following the resolution rather than looking names up again. What an evaluation reads is always the document as it is. Its options are `window` and [`owner`](api.md#api-the-owner).
- **The result** is a detached copy, frozen, that holds nothing of the document. A structure a member answers is taken by its data shape alone, the properties its type declares, each read as the value offers it, a getter's included, so a property beside them never reaches a result and an instance of a class answers as the properties its type declares.
-- **A member that breaks its contract.** A member whose function answers a type other than the one it declares has broken its contract, and the evaluation fails with an evaluation error naming the member and where it stands in the query; so does a member whose function throws, with the thrown error as its cause. A request that uses a member a module declares and does not implement is refused before anything is evaluated, with a module error naming the declaration, as Nexo's [declarations without an implementation](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/modules.md#modules-declarations-without-an-implementation) set out.
+- **A member that breaks its contract.** A member whose function answers a type other than the one it declares has broken its contract, and the evaluation fails with an evaluation error naming the member and where it stands in the query; so does a member whose function throws, with the thrown error as its cause. A request that uses a member a module declares and does not implement is refused before anything is evaluated, with a module error naming the declaration, as Nexo's [declarations without an implementation](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/modules.md#modules-declarations-without-an-implementation) set out.
- **A maintained member** cannot be read in a single synchronous pass and fails `evaluate`, with an evaluation error naming the member; `evaluateAsync` waits for it.
- **A request of another kind** is refused, as [request kinds and their operations](queries.md#operations-and-request-kinds) set out.
@@ -36,7 +36,7 @@ In this document:
## How DOMQL's members read
-Each member declares how it reads by [Nexo's contract](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/members.md#how-a-member-reads): DOMQL's members read fresh from the document, as an attribute or a box is, maintained by a browser observation, as `intersects` is, captured, as an event's data is, or derived, as a list's `count` is.
+Each member declares how it reads by [Nexo's contract](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/members.md#how-a-member-reads): DOMQL's members read fresh from the document, as an attribute or a box is, maintained by a browser observation, as `intersects` is, captured, as an event's data is, or derived, as a list's `count` is.
A member whose result depends on what happened before, as well as on the document as it is, is captured: it keeps that history while a watch or an event listener holds it, and documents what an evaluation once reports without it.
diff --git a/spec/events.md b/spec/events.md
index 8f10043..c2aff96 100644
--- a/spec/events.md
+++ b/spec/events.md
@@ -3,7 +3,7 @@
-An **event source** delivers things that happened, as a click or a key pressed, and a **subscription** shapes each event it delivers into data, read as the event is dispatched. An event source is a [host call](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/members.md#members-host-calls) DOMQL carries out by subscribing to it, and a subscription is a query whose chain ends in one: a caller subscribes to it, and the caller's handler receives one result for each event, immutable data that holds no event object and no element.
+An **event source** delivers things that happened, as a click or a key pressed, and a **subscription** shapes each event it delivers into data, read as the event is dispatched. An event source is a [host call](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/members.md#members-host-calls) DOMQL carries out by subscribing to it, and a subscription is a query whose chain ends in one: a caller subscribes to it, and the caller's handler receives one result for each event, immutable data that holds no event object and no element.
```js
const clicks = domql.query(`
@@ -30,7 +30,7 @@ In this document:
## Event sources
-An event source is subscribed to, and never read or watched: DOMQL starts it as its caller subscribes, and has each event it delivers projected through the object expression that follows it, as Nexo [projects a value its host supplies](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/host-calls.md#runtime-host-calls), each event captured as the members of the type its event type maps to.
+An event source is subscribed to, and never read or watched: DOMQL starts it as its caller subscribes, and has each event it delivers projected through the object expression that follows it, as Nexo [projects a value its host supplies](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/host-calls.md#runtime-host-calls), each event captured as the members of the type its event type maps to.
| Available on | Source | Delivers | Fixed |
| --- | --- | --- | --- |
@@ -50,7 +50,7 @@ A subscription listening in the capture phase observes alone, as every subscript
## Event types
-DOMQL's module declares the [type selector](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/vocabulary.md#vocabulary-type-selectors) `event`, whose keys are the event types, and a module extends it with event types of its own as it extends DOMQL's types. The built-in event types, the type each maps to, and the members each event offers:
+DOMQL's module declares the [type selector](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/vocabulary.md#vocabulary-type-selectors) `event`, whose keys are the event types, and a module extends it with event types of its own as it extends DOMQL's types. The built-in event types, the type each maps to, and the members each event offers:
| Event types | Type | Members |
| --- | --- | --- |
diff --git a/spec/executions.md b/spec/executions.md
index de49813..69b86c3 100644
--- a/spec/executions.md
+++ b/spec/executions.md
@@ -3,7 +3,7 @@
-An **execution** is a [host call](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/members.md#members-host-calls) DOMQL carries out to change the page. A **once execution** changes it once and answers its result; a **continuous execution** starts something that runs on the page until it is updated or disposed, and has no result, a [behavior](behaviors.md) whose running instance the commands of its module reach. DOMQL's module declares its [built-in executions](vocabulary.md#built-in-executions), each one platform call named by the verb it carries out, as [properties and functions](vocabulary.md#vocabulary-properties-and-functions) set out, and an [extension module](vocabulary.md#extension-modules) declares its own, each with its execution mode and the implementation that carries it out. `executeAsync` carries out a once execution and `run` a continuous one, and no other operation carries out either, as [request kinds and their operations](queries.md#operations-and-request-kinds) set out.
+An **execution** is a [host call](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/members.md#members-host-calls) DOMQL carries out to change the page. A **once execution** changes it once and answers its result; a **continuous execution** starts something that runs on the page until it is updated or disposed, and has no result, a [behavior](behaviors.md) whose running instance the commands of its module reach. DOMQL's module declares its [built-in executions](vocabulary.md#built-in-executions), each one platform call named by the verb it carries out, as [properties and functions](vocabulary.md#vocabulary-properties-and-functions) set out, and an [extension module](vocabulary.md#extension-modules) declares its own, each with its execution mode and the implementation that carries it out. `executeAsync` carries out a once execution and `run` a continuous one, and no other operation carries out either, as [request kinds and their operations](queries.md#operations-and-request-kinds) set out.
```js
// A built-in once execution, answering whether focus landed on the field.
@@ -33,8 +33,8 @@ In this document:
`query.executeAsync(options?)` carries out a once execution and answers a promise of its result; its options are `window`, [`owner`](api.md#api-the-owner) and `signal`. Each call executes it again. One carried out while a query is evaluated, by a member's implementation, rejects with `DOMQL5021`, executing nothing, since a member reads alone; `run` throws it alike.
- **Order.** An execution's implementation is invoked within the call that carries it out, once its preparation has run, so executions carried out in one task, once or continuous, are invoked in the order they are carried out, each seeing what the ones before it changed, as opening a dialog and then focusing a field within it.
-- **Preparation first.** Its receiver and its arguments are prepared first, synchronously, as [Nexo's preparation](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/host-calls.md#runtime-host-calls) evaluates them; a failure there rejects the promise and executes nothing. A skipped preparation, where the receiver is null, or an argument whose parameter propagates null is null, executes nothing, and the promise resolves to null, as a member's null is; a null argument whose parameter accepts null is passed as it stands, as [Nexo's null arguments](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/members.md#nullability-a-null-argument-follows-the-parameter) set out.
-- **The result.** The execution's implementation receives the receiver, the arguments, the environment and the signal, and may answer its result or a promise of it. The result must be of the type the execution declares, as Nexo [captures a supplied value](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/host-calls.md#runtime-host-calls-capturing), and data alone; a result of another type rejects the promise with an evaluation error naming the execution, and an execution that declares no result resolves to null. An object expression that follows the execution is evaluated against the result once it arrives, as `evaluate` evaluates a query, so a member maintained by an observation fails it, and the promise answers detached, immutable data.
+- **Preparation first.** Its receiver and its arguments are prepared first, synchronously, as [Nexo's preparation](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/host-calls.md#runtime-host-calls) evaluates them; a failure there rejects the promise and executes nothing. A skipped preparation, where the receiver is null, or an argument whose parameter propagates null is null, executes nothing, and the promise resolves to null, as a member's null is; a null argument whose parameter accepts null is passed as it stands, as [Nexo's null arguments](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/members.md#nullability-a-null-argument-follows-the-parameter) set out.
+- **The result.** The execution's implementation receives the receiver, the arguments, the environment and the signal, and may answer its result or a promise of it. The result must be of the type the execution declares, as Nexo [captures a supplied value](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/host-calls.md#runtime-host-calls-capturing), and data alone; a result of another type rejects the promise with an evaluation error naming the execution, and an execution that declares no result resolves to null. An object expression that follows the execution is evaluated against the result once it arrives, as `evaluate` evaluates a query, so a member maintained by an observation fails it, and the promise answers detached, immutable data.
- **Failure.** A failure of the execution, whatever it throws, rejects the promise with an evaluation error naming the execution, whose cause is what was thrown; nothing goes to the error reporting while the caller holds the promise.
- **Cancellation.** A signal already aborted rejects with its reason and executes nothing. A signal that aborts while the execution runs rejects the promise with its reason at once, and the execution learns of it through the signal it was given; what it does after that is its own, its result is discarded, and a failure it reports afterwards goes to the window's error reporting, since no caller waits for it.
- **No rollback.** An execution can change the document before it fails or is canceled, and DOMQL never undoes what it did; an execution that can be undone offers that as an execution of its own.
diff --git a/spec/nodes-and-shadow-trees.md b/spec/nodes-and-shadow-trees.md
index 27adcb3..a7320a5 100644
--- a/spec/nodes-and-shadow-trees.md
+++ b/spec/nodes-and-shadow-trees.md
@@ -14,7 +14,7 @@ In this document:
## Nodes
-A node is a value of the DOM tree. DOMQL's module declares the nodes as [reference types](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/types.md#reference-types): `Node`, abstract, and beneath it its kinds, `Element`, `Document`, `DocumentFragment`, a document fragment that is no shadow root, and `ShadowRoot`. DOMQL's `typeOf` recognizes a bound node as the kind it is, never as `Node` itself, and each type's `isInstance` checks membership, so a host may still bind a node declared as a `Node`. `Window` is a reference type of a hierarchy of its own, no node, and so is `Range`, a range of a document a selection holds. Text and comment nodes are none of these kinds, and are refused as bindings.
+A node is a value of the DOM tree. DOMQL's module declares the nodes as [reference types](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/types.md#reference-types): `Node`, abstract, and beneath it its kinds, `Element`, `Document`, `DocumentFragment`, a document fragment that is no shadow root, and `ShadowRoot`. DOMQL's `typeOf` recognizes a bound node as the kind it is, never as `Node` itself, and each type's `isInstance` checks membership, so a host may still bind a node declared as a `Node`. `Window` is a reference type of a hierarchy of its own, no node, and so is `Range`, a range of a document a selection holds. Text and comment nodes are none of these kinds, and are refused as bindings.
diff --git a/spec/queries.md b/spec/queries.md
index 3167843..a1b9a1a 100644
--- a/spec/queries.md
+++ b/spec/queries.md
@@ -82,7 +82,7 @@ const fromDefinition = domql.query(panelQuery.definition, { panel });
### Its imports
-A query uses the vocabulary of the modules it imports, as Nexo's [imports](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/modules.md#scripts-imports) set out, and DOMQL's own module, `Domql`, is imported by every query.
+A query uses the vocabulary of the modules it imports, as Nexo's [imports](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/modules.md#scripts-imports) set out, and DOMQL's own module, `Domql`, is imported by every query.
- **DOMQL supplies `Domql`.** DOMQL reads every query's text with the import `Domql` supplied, so a query reads the DOM's members, `Domql.document` and `Domql.window`, and names DOMQL's types, as `Element`, without writing `import Domql`. Writing it as well is harmless.
- **Another module is imported by the query.** A query that uses a module its caller registered begins with that module's import, `import Charts`, and reads the members its extensions add to DOMQL's types with `:`, as `panel:palette`, as [extension modules](vocabulary.md#extension-modules) set out. Registering a module adds nothing to a query's imports, so a query that does not import a module reads the same before the module is registered and after. A module [loaded on request](vocabulary.md#extension-modules-loading) is loaded before a query importing it is carried out, which its imports name.
@@ -93,7 +93,7 @@ A query uses the vocabulary of the modules it imports, as Nexo's [imports](https
### Binding its parameters
-Each parameter is bound under the name the query uses, with a value Nexo's [script parameters and bindings](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/scripts.md#scripts-script-parameters) allow, and a result is data, which a caller receives in its own language's form. `with` answers a new query whose bindings replace the old ones whole, of the types the query declares; the query it was called on, and every operation running from it, are unaffected. A query can be made without its bindings and bound afterwards, and a required binding that is missing fails before anything is carried out.
+Each parameter is bound under the name the query uses, with a value Nexo's [script parameters and bindings](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/scripts.md#scripts-script-parameters) allow, and a result is data, which a caller receives in its own language's form. `with` answers a new query whose bindings replace the old ones whole, of the types the query declares; the query it was called on, and every operation running from it, are unaffected. A query can be made without its bindings and bound afterwards, and a required binding that is missing fails before anything is carried out.
A binding is typed from its value, unless the query [declares its type](#making-a-query-declared-types): every value is typed from itself, a null, an empty list and a list holding nulls among them, so a query is made for an element that is not there yet as it is for one that is.
@@ -105,7 +105,7 @@ const another = query.with({ panel: otherPanel, ids: [1, 2] });
-**Declared types.** `domql.query(text, bindings, { types })` declares the type of a top-level binding by its notation, as Nexo's [declared types](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/bindings.md#runtime-bindings) bind it, where data typed from itself would be of no module's type:
+**Declared types.** `domql.query(text, bindings, { types })` declares the type of a top-level binding by its notation, as Nexo's [declared types](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/bindings.md#runtime-bindings) bind it, where data typed from itself would be of no module's type:
```js
const routed = domql.query("import Forma\nForma.firstKey(routes)", { routes: [{ key: "Enter" }] }, { types: { routes: "List" } });
@@ -134,7 +134,7 @@ A query belongs to the instance of the library that made it, and an instance ref
## Resolution
-A request is resolved before it is first carried out, and resolution validates it against the vocabulary its imports make available, as Nexo's [resolution](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/resolution.md#runtime-bindings-and-resolution) sets out; a module a request imports is registered by its caller beforehand. A resolution is kept while Nexo says it is current, so a module registered later leaves a running watch, subscription or execution as it was, unless the module recognizes values its resolution may meet, as [registering a module while requests run](vocabulary.md#extension-modules-registering) sets out. A misspelling or a wrong argument is an error before anything is evaluated; a member's fit to its receiver is checked once the receiver's type is specific enough, which a null receiver's is not; null is always a result.
+A request is resolved before it is first carried out, and resolution validates it against the vocabulary its imports make available, as Nexo's [resolution](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/resolution.md#runtime-bindings-and-resolution) sets out; a module a request imports is registered by its caller beforehand. A resolution is kept while Nexo says it is current, so a module registered later leaves a running watch, subscription or execution as it was, unless the module recognizes values its resolution may meet, as [registering a module while requests run](vocabulary.md#extension-modules-registering) sets out. A misspelling or a wrong argument is an error before anything is evaluated; a member's fit to its receiver is checked once the receiver's type is specific enough, which a null receiver's is not; null is always a result.
`query.resolve(options?)` resolves a request without evaluating anything, and answers its kind, `value`, `subscription` or `execution`, an execution's `executionMode`, null for a request of another kind, and its type, null for an execution that answers no result; it needs no browser. It answers its definition and the declarations it uses as well, each with its `qualifiedName`, `typeAt(path)`, the type a path reaches, and `getLocation(pointer)`, where a pointer into its definition stands in its text. Its options `watch` and `acceptPartialObservation` resolve it as a watch would, so a watch's refusal of a partly observable member, as [accepting partial observation](watches.md#accepting-partial-observation) sets out, is found before a watch starts.
@@ -142,7 +142,7 @@ A request is resolved before it is first carried out, and resolution validates i
## Request kinds and their operations
-Evaluating, watching or subscribing to a request reads the document and changes nothing, whatever vocabulary it uses; an [execution](executions.md) explicitly requests effects, carried out only when its caller executes or runs it. The request's source decides its kind: a query gives a value, or ends in a [host call](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/members.md#members-host-calls), which DOMQL carries out as its declaration says, by subscribing to an event source, or by executing once or running continuously an execution of that mode. The one entry point serves every request kind, and resolution refuses an operation the kind does not take before anything is evaluated or started, with a validation error that says what the request does and names the operation it takes:
+Evaluating, watching or subscribing to a request reads the document and changes nothing, whatever vocabulary it uses; an [execution](executions.md) explicitly requests effects, carried out only when its caller executes or runs it. The request's source decides its kind: a query gives a value, or ends in a [host call](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/members.md#members-host-calls), which DOMQL carries out as its declaration says, by subscribing to an event source, or by executing once or running continuously an execution of that mode. The one entry point serves every request kind, and resolution refuses an operation the kind does not take before anything is evaluated or started, with a validation error that says what the request does and names the operation it takes:
```text
Cannot execute 'panel.size': it produces a value.
@@ -175,6 +175,6 @@ rowsQuery.select(0, "height");
- **A path's shape is checked at once.** `select` refuses, without resolving anything, a path item that is neither a written field's name nor an index that is a whole number and not negative, as `-1` and `1.5` are not.
- **A path's fit is checked at resolution.** Whether a field exists, and whether an index applies to a list, is checked when an operation resolves the query, before anything is evaluated or observed; a selection of a query whose vocabulary is not yet registered is therefore made without failing.
- **What it gives.** A nullable ancestor and a list index out of range give null, and a list index follows a position, never a particular element.
-- **Dictionaries and pairs** are selected in the form a [result holds them](results.md#results-collections), as Nexo's [result paths](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/resolution.md#runtime-result-paths) step into them: `select("counts", "entries")` gives a dictionary's entries, `select("counts", "entries", 0, "value")` the value of its first, and `select("range", "key")` a pair's key. Any other name after a dictionary or a pair is refused at resolution.
+- **Dictionaries and pairs** are selected in the form a [result holds them](results.md#results-collections), as Nexo's [result paths](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/resolution.md#runtime-result-paths) step into them: `select("counts", "entries")` gives a dictionary's entries, `select("counts", "entries", 0, "value")` the value of its first, and `select("range", "key")` a pair's key. Any other name after a dictionary or a pair is refused at resolution.
- **The whole query.** A selection reads the whole query's result, so the whole query decides its dependencies, its failures and its readiness.
- **Its watch** delivers its first value, each change to that value, and its value again after a failed evaluation. It watches snapshots alone; a caller that wants live state of a smaller result writes that result in DOMQL.
diff --git a/spec/results.md b/spec/results.md
index 00c44db..c8a0c62 100644
--- a/spec/results.md
+++ b/spec/results.md
@@ -48,7 +48,7 @@ A snapshot never changes once delivered. A new snapshot reuses every immutable b
- **What a change set is.** A change set is a [JSON Patch](https://www.rfc-editor.org/rfc/rfc6902) document limited to `replace`, `add`, `remove` and `move`, whose paths are JSON Pointers into the result; applying it to the result it was computed against gives the new result. A field the change set leaves out is unchanged, and a field that became null is replaced with null. An object expression's fields are fixed, so `add` and `remove` apply to list items alone.
- **Lists.** A list whose items descend from elements changes by element: an element entering is added, one leaving is removed, one changing position is moved, and one whose result changed is changed inside its item. Any other list changes by position.
-- **Identity.** Two elements can project to the same data, so the identity of each item cannot be read back from a snapshot. Each item is matched by the reference it descends from, its provenance, which Nexo's [result metadata](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/evaluation.md#runtime-results-provenance) records beside the result and which neither a result nor a change set ever holds: the source the earliest projection the item descends from read, which Nexo classifies as a reference or as data. A list projected from elements is matched by element, and so are a projection of its items and a list filtered, sliced or ordered from it, each by the element its item first came from.
+- **Identity.** Two elements can project to the same data, so the identity of each item cannot be read back from a snapshot. Each item is matched by the reference it descends from, its provenance, which Nexo's [result metadata](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/evaluation.md#runtime-results-provenance) records beside the result and which neither a result nor a change set ever holds: the source the earliest projection the item descends from read, which Nexo classifies as a reference or as data. A list projected from elements is matched by element, and so are a projection of its items and a list filtered, sliced or ordered from it, each by the element its item first came from.
- **Its source in the browser.** A watch answers the reference an item descends from to a caller in the browser, through [`sourceOf`](watches.md#watching-source-elements), and never in the result.
- **Matched by position.** A list no projection built, one an item of which descends from data or from null, and one in which an element stands twice, are matched by position. DOMQL reads the classification Nexo reports, never inferring a reference from the value.
- **What a change set reproduces.** A change set takes the result it was computed against to the reconciled snapshot, the one the watch reports, with every comparison and tolerance applied; it never describes a different, raw evaluation.
@@ -89,7 +89,7 @@ A number a conditional gave compares within the tolerance of the member its bran
## Dictionaries and pairs
-A result holds a dictionary or a pair as data, in the form Nexo [exports](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/evaluation.md#runtime-host-forms) them: a dictionary as `{ entries: [{ key, value }, …] }`, its entries in their order, and a pair as `{ key, value }`.
+A result holds a dictionary or a pair as data, in the form Nexo [exports](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/evaluation.md#runtime-host-forms) them: a dictionary as `{ entries: [{ key, value }, …] }`, its entries in their order, and a pair as `{ key, value }`.
- **Compared and changed as data.** A watch compares them as it compares any object and list, and a change set addresses them in that form: an entry's value is changed at `/counts/entries/0/value`, and an entry entering or leaving is added or removed at its position in `entries`.
- **A key is data.** A numeric key is an entry's `key`, never a list index, and a change set reaches an entry by its position in `entries`, never by its key. A [selection](queries.md#selecting-a-result) steps into them in that form, as `select("counts", "entries", 0, "value")`.
diff --git a/spec/terms.md b/spec/terms.md
index 77ac208..6a97702 100644
--- a/spec/terms.md
+++ b/spec/terms.md
@@ -2,7 +2,7 @@
-Each term this specification uses, what it means, and where its authoritative explanation is. A term here defines nothing its linked document does not, and a term of the language, as a script, a binding, a member, an import, a module or a host call, is [the language's](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/terms.md), and one of the runtime, as a registry, a resolution or a module key, is [the runtime's](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/terms.md), each Nexo's.
+Each term this specification uses, what it means, and where its authoritative explanation is. A term here defines nothing its linked document does not, and a term of the language, as a script, a binding, a member, an import, a module or a host call, is [the language's](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/terms.md), and one of the runtime, as a registry, a resolution or a module key, is [the runtime's](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/terms.md), each Nexo's.
In this document:
@@ -72,7 +72,7 @@ In this document:
| Term | Meaning | Reference |
| --- | --- | --- |
-| Host call | Nexo's call of a function the host invokes, which ends a query; DOMQL carries each out as an event source or an execution | [Host calls](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/members.md#members-host-calls) |
+| Host call | Nexo's call of a function the host invokes, which ends a query; DOMQL carries each out as an event source or an execution | [Host calls](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/members.md#members-host-calls) |
| Event source | A host call that delivers things that happened, as `on(type)` does | [Event sources](events.md#event-sources) |
| Event type | A key of DOMQL's type selector `event`, which names the type its events are captured as | [Event types](events.md#event-types) |
| Subscription | A query whose chain ends in an event source, which shapes each event into data | [Events](events.md#events) |
diff --git a/spec/vocabulary.md b/spec/vocabulary.md
index ba654be..e87f7ed 100644
--- a/spec/vocabulary.md
+++ b/spec/vocabulary.md
@@ -17,7 +17,7 @@ Properties and functions are named in camelCase, and names are case-sensitive. B
-**Properties and functions.** The vocabulary follows Nexo's rule for [states and tests](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/vocabulary.md#vocabulary-boolean-functions): a property names what its receiver is, has or is in, and a function does work or takes what it needs.
+**Properties and functions.** The vocabulary follows Nexo's rule for [states and tests](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/vocabulary.md#vocabulary-boolean-functions): a property names what its receiver is, has or is in, and a function does work or takes what it needs.
- **A state is a property.** What the user, the browser or the page sets and clears, as whether an element is checked, focused or hovered, is a Boolean property read without a call, `panel.checked`, as [states](#states) set out.
- **An execution is a function.** A change DOMQL makes is named by the verb it carries out and called with its parentheses, whether or not it takes an argument, `panel.focus()`, as [executions](#built-in-executions) set out.
@@ -42,7 +42,7 @@ In this document:
## Module members
-DOMQL's module, `Domql`, declares two [module members](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/modules.md#namespaces-module-members), read through its namespace, each with no receiver:
+DOMQL's module, `Domql`, declares two [module members](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/modules.md#namespaces-module-members), read through its namespace, each with no receiver:
| Member | Type | Reads | Changes |
| --- | --- | --- | --- |
@@ -55,7 +55,7 @@ Neither needs a binding, and a caller's binding named `Domql` is read as `~Domql
## Types
-DOMQL's module declares each of its types with its members, as Nexo's [declaring a type](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/modules.md#modules-declaring-a-type) sets out: its reference types, which a query reads through and a result never holds, and its structured types, which hold data. Its `typeOf` recognizes the values a host binds, and each reference type's `isInstance` checks membership:
+DOMQL's module declares each of its types with its members, as Nexo's [declaring a type](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/modules.md#modules-declaring-a-type) sets out: its reference types, which a query reads through and a result never holds, and its structured types, which hold data. Its `typeOf` recognizes the values a host binds, and each reference type's `isInstance` checks membership:
| Reference type | Supertype | What it is | Where a value has the type |
| --- | --- | --- | --- |
@@ -98,11 +98,11 @@ An element with a layout box whose dimensions are zero has actual measurements o
-**Tolerance.** A member that measures layout in CSS pixels declares a [tolerance](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/members.md#what-a-member-declares-numeric-tolerance) of 0.05, a twentieth of a pixel, for every number it answers, so a watch reports a measurement only once it moves by more than that from the one it last reported, as [comparing snapshots](results.md#comparing-snapshots) sets out:
+**Tolerance.** A member that measures layout in CSS pixels declares a [tolerance](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/members.md#what-a-member-declares-numeric-tolerance) of 0.05, a twentieth of a pixel, for every number it answers, so a watch reports a measurement only once it moves by more than that from the one it last reported, as [comparing snapshots](results.md#comparing-snapshots) sets out:
- **What it absorbs.** A box settling by a unit of the browser's layout, 1/64 of a pixel in Chromium and WebKit and 1/60 in Firefox, and the rounding of the arithmetic that answers a measurement, as `right` is `left` and `width` added.
- **What it reports.** Any move a device pixel shows, which is a quarter of a pixel at a device pixel ratio of 4. A move made in steps smaller than the tolerance is reported once the steps add up to more, since each is compared with the measurement last reported.
-- **Who declares it.** `rect`, `clientRect`, `rectRelativeTo`, `size`, `clientSize`, `scroll` and `grid` of an element, and `size` and `scroll` of the window. A number computed from one, as `it.rect?.width / 2`, compares exactly, as Nexo's [arithmetic](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/expressions.md#arithmetic-watching) sets out, and an evaluation once is never rounded.
+- **Who declares it.** `rect`, `clientRect`, `rectRelativeTo`, `size`, `clientSize`, `scroll` and `grid` of an element, and `size` and `scroll` of the window. A number computed from one, as `it.rect?.width / 2`, compares exactly, as Nexo's [arithmetic](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/expressions.md#arithmetic-watching) sets out, and an evaluation once is never rounded.
Scrolling reads the same way, along the axes of a box's writing mode:
@@ -608,7 +608,7 @@ An element that is no scroll container is scrolled by 0. Null while it has no la
### List: count, first, last
-`count`, `first` and `last` are properties [Nexo's own module](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/collections.md#collections-list-members) declares, which owns lists, and Nexo's specification defines.
+`count`, `first` and `last` are properties [Nexo's own module](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/collections.md#collections-list-members) declares, which owns lists, and Nexo's specification defines.
@@ -850,7 +850,7 @@ A box whose overflow is not `visible` along one axis computes `visible` as `auto
### List: item
-The unnamed indexer, `[index]`, is an indexer [Nexo's own module](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/collections.md#collections-list-members) declares, which owns lists, and Nexo's specification defines.
+The unnamed indexer, `[index]`, is an indexer [Nexo's own module](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/collections.md#collections-list-members) declares, which owns lists, and Nexo's specification defines.
@@ -858,7 +858,7 @@ The unnamed indexer, `[index]`, is an indexer [Nexo's own module](https://github
### List: max, min, sum
-`max`, `min` and `sum` are functions [Nexo's own module](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/collections.md#collections-list-members) declares, which owns lists, and Nexo's specification defines.
+`max`, `min` and `sum` are functions [Nexo's own module](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/collections.md#collections-list-members) declares, which owns lists, and Nexo's specification defines.
@@ -866,7 +866,7 @@ The unnamed indexer, `[index]`, is an indexer [Nexo's own module](https://github
### List: where
-`where` is a function [Nexo's own module](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/collections.md#collections-list-members) declares, which owns lists, and Nexo's specification defines.
+`where` is a function [Nexo's own module](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/collections.md#collections-list-members) declares, which owns lists, and Nexo's specification defines.
@@ -878,7 +878,7 @@ The unnamed indexer, `[index]`, is an indexer [Nexo's own module](https://github
## States
-A **state** is what the user, the browser or the page sets and clears over time, as whether an element is checked; a presence, as whether it is focused; or a capability the browser offers, as whether it can share. Each is a Boolean property, as Nexo's [states and tests](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/vocabulary.md#vocabulary-boolean-functions) set out:
+A **state** is what the user, the browser or the page sets and clears over time, as whether an element is checked; a presence, as whether it is focused; or a capability the browser offers, as whether it can share. Each is a Boolean property, as Nexo's [states and tests](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/vocabulary.md#vocabulary-boolean-functions) set out:
- **Reading one.** A query reads a state where it stands, `it.checked`, or through its module, its receiver first, `Domql.checked(it)`, and each way reaches the one declaration, whose observations follow it.
- **Filtering by one.** A query filters by a state with a body, `rows.where(it.checked)`. Only a function has a reference, so `rows.where(Domql.checked)` is refused (NEXO3076).
@@ -1210,7 +1210,7 @@ Each reads the element's own attribute under a contract of its own, falling back
So `it.checked or it.aria.checked` is whether either says checked, and `it.aria["checked"] == "mixed"` tells a mixed state, which the ARIA view's `checked` answers false for, from the others. The ARIA view's unnamed indexer reads the attribute written on the element, as `it["aria-checked"]` does, and never the element's effective accessibility state.
-No other ARIA attribute has a state until one is declared, each with a contract of its own, since not every ARIA attribute is a Boolean; an extension declares one on the ARIA view, a type it does not own, as the [rules for extensions](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/extensions.md#extensions) let any module do.
+No other ARIA attribute has a state until one is declared, each with a contract of its own, since not every ARIA attribute is a Boolean; an extension declares one on the ARIA view, a type it does not own, as the [rules for extensions](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/extensions.md#extensions) let any module do.
@@ -1495,7 +1495,7 @@ Module code holds a target the same way, through an owned write it runs with [`e
## Built-in conversions
-A query converts with the four conversions [Nexo's own module](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/modules.md#vocabulary-conversions) declares between the language's types of data, which DOMQL's module, owning none of those types, declares none of; each rejects a value it cannot convert:
+A query converts with the four conversions [Nexo's own module](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/modules.md#vocabulary-conversions) declares between the language's types of data, which DOMQL's module, owning none of those types, declares none of; each rejects a value it cannot convert:
| From | To | Converts |
| --- | --- | --- |
@@ -1508,7 +1508,7 @@ A query converts with the four conversions [Nexo's own module](https://github.co
## Observations
-A member names the [observations](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/observations.md#observations) that cover its changes, each by its type and its target, and DOMQL starts each one that a watch, a waiting evaluation or an event's object expression needs, and stops it once nothing needs it. DOMQL's module declares the browser's observations as eleven observation types, each animation frame as a twelfth, and the state a behavior offers as a thirteenth, which the members of any module and module code through its [environment](#extension-modules-environment) can name, and five observation targets.
+A member names the [observations](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/observations.md#observations) that cover its changes, each by its type and its target, and DOMQL starts each one that a watch, a waiting evaluation or an event's object expression needs, and stops it once nothing needs it. DOMQL's module declares the browser's observations as eleven observation types, each animation frame as a twelfth, and the state a behavior offers as a thirteenth, which the members of any module and module code through its [environment](#extension-modules-environment) can name, and five observation targets.
@@ -1536,7 +1536,7 @@ Each type is shared by equivalent requests, those of the same target and the sam
### Observation targets
-An observation observes its member's receiver, an argument, `{ argument }`, or a target DOMQL's module declares, as Nexo's [observation targets](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/observations.md#observations-targets) set out:
+An observation observes its member's receiver, an argument, `{ argument }`, or a target DOMQL's module declares, as Nexo's [observation targets](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/observations.md#observations-targets) set out:
| Target | Found from the receiver | Observes |
| --- | --- | --- |
@@ -1552,7 +1552,7 @@ DOMQL resolves each target as it starts an observation, and each evaluation that
## Extension modules
-A module extends the built-in vocabulary as Nexo's [modules](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/modules.md#modules) set out: it declares types of its own, each with its members and operators, states among them, and event types, executions and observation types, and adds members to DOMQL's types in its [extensions](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/extensions.md#extensions), each naming the one type it extends qualified, as `{ name: 'ChartElements', kind: 'extension', target: 'Domql.Element', members: [/* … */] }` adds members to elements. `domql.createModule(name, contents)` creates one from its declarations, each that runs code carrying its implementation as its `impl`, and `domql.registerModule(module)` registers it in the instance's registry, which holds DOMQL's module and every module registered with it. A request is resolved against the modules it imports, registered by then, so a module a query imports is registered beforehand, once, rather than for every evaluation.
+A module extends the built-in vocabulary as Nexo's [modules](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/modules.md#modules) set out: it declares types of its own, each with its members and operators, states among them, and event types, executions and observation types, and adds members to DOMQL's types in its [extensions](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/extensions.md#extensions), each naming the one type it extends qualified, as `{ name: 'ChartElements', kind: 'extension', target: 'Domql.Element', members: [/* … */] }` adds members to elements. `domql.createModule(name, contents)` creates one from its declarations, each that runs code carrying its implementation as its `impl`, and `domql.registerModule(module)` registers it in the instance's registry, which holds DOMQL's module and every module registered with it. A request is resolved against the modules it imports, registered by then, so a module a query imports is registered beforehand, once, rather than for every evaluation.
```js
domql.registerModule(domql.createModule("Charts", {
@@ -1573,15 +1573,15 @@ domql.registerModule(domql.createModule("Charts", {
domql.query("import Charts\npanel:palette", { panel }).evaluate();
```
-- **A query imports it, and reads its extensions with `:`.** A query that uses a module's vocabulary imports the module, `import Charts`, as [its imports](queries.md#making-a-query-imports) set out, and reads a member an extension adds with `:`, never `.`: `panel:palette`, or `panel:ChartElements.palette` where two of its extensions declare one name, as Nexo's [extension access](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/extensions.md#extensions-access) sets out. DOMQL's own members stand within its types, so a query reads them with `.`.
+- **A query imports it, and reads its extensions with `:`.** A query that uses a module's vocabulary imports the module, `import Charts`, as [its imports](queries.md#making-a-query-imports) set out, and reads a member an extension adds with `:`, never `.`: `panel:palette`, or `panel:ChartElements.palette` where two of its extensions declare one name, as Nexo's [extension access](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/extensions.md#extensions-access) sets out. DOMQL's own members stand within its types, so a query reads them with `.`.
- **DOMQL's members win on its types.** A name DOMQL's type declares is read with `.` as DOMQL's, and an extension's member of that name is read with `:` alone. Two modules' extensions declaring one name both register, and a query that reads the name where neither is more specific is refused where it does so (NEXO3024), naming the extensions to write.
- **States and work.** A module declares a state as a Boolean property, and a member that does work or takes an argument as a function, as [properties and functions](#vocabulary-properties-and-functions) set out; Nexo refuses neither form, so a module follows the rule itself.
-- **What an implementation receives.** Every implementation receives the one object Nexo's [implementations](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/members.md#members-what-an-implementation-receives) receive, whose `env` is the [environment](#extension-modules-environment) of the operation that reaches it.
-- **Arguments.** A host call's implementation receives its arguments as Nexo prepares them, by parameter name. A null argument whose parameter accepts null is passed as it stands, as a bound of null meaning the viewport, and one whose parameter propagates null skips the call, as [Nexo's null arguments](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/members.md#nullability-a-null-argument-follows-the-parameter) set out. An option of a structured type, written in place as an object expression, as `buttons = { container = viewport, step = 3 }`, is [constructed](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/types.md#types-constructing-a-structure) as that type's data, a field of a reference type holding the element it names, and reaches the implementation as a frozen structure.
+- **What an implementation receives.** Every implementation receives the one object Nexo's [implementations](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/members.md#members-what-an-implementation-receives) receive, whose `env` is the [environment](#extension-modules-environment) of the operation that reaches it.
+- **Arguments.** A host call's implementation receives its arguments as Nexo prepares them, by parameter name. A null argument whose parameter accepts null is passed as it stands, as a bound of null meaning the viewport, and one whose parameter propagates null skips the call, as [Nexo's null arguments](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/members.md#nullability-a-null-argument-follows-the-parameter) set out. An option of a structured type, written in place as an object expression, as `buttons = { container = viewport, step = 3 }`, is [constructed](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/types.md#types-constructing-a-structure) as that type's data, a field of a reference type holding the element it names, and reaches the implementation as a frozen structure.
-- **Kept functions.** A host call's function argument, as a test of what a behavior hears, `when = it.matches(".pick")`, reaches its implementation as a function it keeps and calls later, a [kept function](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/host-calls.md#runtime-host-calls-kept-functions): each call reads the page as it is then, through the locals and the bindings the call was prepared with, as a query evaluated once reads, so a member it reads reads alone, and is checked against the parameter's contract. DOMQL ends the functions an execution keeps as the execution ends: a continuous execution's as its instance ends, and as an update gives its instance others, once the instance accepted them; a once execution's as its implementation's answer settles, a canceled one's among them; and an event source's as its subscription ends. A call of one afterwards fails with Nexo's NEXO5051, which the implementation receives as it does any failure of the call.
+- **Kept functions.** A host call's function argument, as a test of what a behavior hears, `when = it.matches(".pick")`, reaches its implementation as a function it keeps and calls later, a [kept function](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/host-calls.md#runtime-host-calls-kept-functions): each call reads the page as it is then, through the locals and the bindings the call was prepared with, as a query evaluated once reads, so a member it reads reads alone, and is checked against the parameter's contract. DOMQL ends the functions an execution keeps as the execution ends: a continuous execution's as its instance ends, and as an update gives its instance others, once the instance accepted them; a once execution's as its implementation's answer settles, a canceled one's among them; and an event source's as its subscription ends. A call of one afterwards fails with Nexo's NEXO5051, which the implementation receives as it does any failure of the call.
- **Reading.** A member's implementation is synchronous and reads alone, as Nexo requires of every vocabulary, so evaluating, watching and subscribing change nothing; a change to the page is an [execution](executions.md).
- **Event types.** A module adds event types of its own as keys of DOMQL's type selector `event`, each a mapping, `{ selector: 'event', key, type }`, naming the type its events are captured as, so `on` listens to them as it listens to the built-in ones.
- **Observations.** A member of any module names DOMQL's observation types and targets as DOMQL's own members do. DOMQL resolves the targets its own module declares alone, so a module declaring observation targets of its own is refused when it is registered, and an observation type a module declares, which owns no target, observes the receiver or an argument. An observation type a module declares is started by its implementation, which receives `request`, the observation's `type`, its `target` and its `arguments`, each argument the member names resolved to its value; `notify`, which it calls when what it observes may have changed; and `env`, [an observation's environment](#extension-modules-observation-environment). It answers an object whose `stop()` ends the observation and, for a maintained observation, whose `sample()` answers its latest sample, `{ pending, value }`. A maintained observation whose sample can lag behind the page, as one the browser reports after it lays a frame out, offers `resampleAsync()` too: it takes a new sample and answers a promise that settles once that sample has arrived, which a [refresh that resamples](watches.md#watching-resampling) waits for. One that offers none is read as it stands, its sample taken to be current whenever `sample()` answers it.
@@ -1606,7 +1606,7 @@ An operation gives every implementation it reaches one environment, its `env`, m
-**History per holder.** The environment is one per operation, so a member that reads captured values, keeping what it measured before as Nexo's [captured reading](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/members.md#how-a-member-reads) has its holder keep it, keys that history by its environment and its receiver, in a `WeakMap` of its own: each watch, wait and subscription keeps its own, from its start to its end, and lets it go with the operation, and an evaluation once, whose environment is its own, reports what it sees with none.
+**History per holder.** The environment is one per operation, so a member that reads captured values, keeping what it measured before as Nexo's [captured reading](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/members.md#how-a-member-reads) has its holder keep it, keys that history by its environment and its receiver, in a `WeakMap` of its own: each watch, wait and subscription keeps its own, from its start to its end, and lets it go with the operation, and an evaluation once, whose environment is its own, reports what it sees with none.
@@ -1620,10 +1620,10 @@ An operation gives every implementation it reaches one environment, its `env`, m
### Registering a module while requests run
-A query's imports decide what it resolves against, so a module registered later changes no resolution's meaning: a running watch, subscription or continuous execution keeps the resolution it has, and goes on evaluating and delivering, as Nexo keeps a resolution [current](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/resolution.md#runtime-reuse).
+A query's imports decide what it resolves against, so a module registered later changes no resolution's meaning: a running watch, subscription or continuous execution keeps the resolution it has, and goes on evaluating and delivering, as Nexo keeps a resolution [current](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/resolution.md#runtime-reuse).
-- **A module that recognizes values.** A module declaring a `typeOf` may recognize values a resolution captures, so it makes stale the resolutions that may meet such a value, as Nexo's [reusing a resolution](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/resolution.md#runtime-reuse) sets out: one whose host call supplies `DomEvent`, whose `target` is a nullable reference, among them. An operation started after it resolves its request again.
-- **A running watch or a waiting evaluation made stale** resolves its request again at its next evaluation, which evaluates the whole query anew, as each of its evaluations does, so it goes on as before. A watch compares that evaluation's result as it compares any, within each value's tolerance: Nexo gives every resolution of one definition the same [origins](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/evaluation.md#runtime-results) where it selects the same declarations. Resolving again checks what starting the watch checked, and its refusal is that evaluation's failure.
+- **A module that recognizes values.** A module declaring a `typeOf` may recognize values a resolution captures, so it makes stale the resolutions that may meet such a value, as Nexo's [reusing a resolution](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/resolution.md#runtime-reuse) sets out: one whose host call supplies `DomEvent`, whose `target` is a nullable reference, among them. An operation started after it resolves its request again.
+- **A running watch or a waiting evaluation made stale** resolves its request again at its next evaluation, which evaluates the whole query anew, as each of its evaluations does, so it goes on as before. A watch compares that evaluation's result as it compares any, within each value's tolerance: Nexo gives every resolution of one definition the same [origins](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/evaluation.md#runtime-results) where it selects the same declarations. Resolving again checks what starting the watch checked, and its refusal is that evaluation's failure.
- **A subscription or a once execution made stale** prepares its request again where a value its host call supplies is next projected: at the next event, or as the execution's result arrives. Where that preparation reaches the declaration it was carried out through, the value is projected through it, its locals and the object expression evaluated as that preparation finds them, and a subscription goes on listening with the receiver and the arguments its event source started with. Where it reaches none, or another, the subscription hands its handler the failure `DOMQL5015` and ends, and the once execution rejects with it, its effect standing. Where preparing it again fails, the subscription hands its handler that failure and ends, and the once execution rejects with it.
@@ -1652,7 +1652,7 @@ chart.evaluate();
### Host calls DOMQL carries out
-A module declares an event source or an execution as a [host call](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/members.md#members-host-calls), a function with `invokedBy: 'host'`, within a type, within an extension, or among its module members, and gives DOMQL what Nexo leaves to its host: the `requestKind` the call makes, `subscription` for an event source or `execution`; an execution's `executionMode`, `once` or `continuous`; and the `impl` that carries it out. `domql.createModule` keeps these in DOMQL's own catalog, and gives Nexo the declaration without them, so Nexo resolves and prepares the call and DOMQL alone invokes it. One declaration standing within several types, as DOMQL's `on` does within `Element`, `Document` and `Window`, is kept for each.
+A module declares an event source or an execution as a [host call](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/members.md#members-host-calls), a function with `invokedBy: 'host'`, within a type, within an extension, or among its module members, and gives DOMQL what Nexo leaves to its host: the `requestKind` the call makes, `subscription` for an event source or `execution`; an execution's `executionMode`, `once` or `continuous`; and the `impl` that carries it out. `domql.createModule` keeps these in DOMQL's own catalog, and gives Nexo the declaration without them, so Nexo resolves and prepares the call and DOMQL alone invokes it. One declaration standing within several types, as DOMQL's `on` does within `Element`, `Document` and `Window`, is kept for each.
| Host call | `requestKind` | `executionMode` | Its `result` | Its implementation receives | It answers |
| --- | --- | --- | --- | --- | --- |
@@ -1666,4 +1666,4 @@ A [command](behaviors.md#behaviors-commands) and an [event source of occurrences
`domql.createModule` refuses, with a module error naming the declaration, the type it stands within and the key, of the code [errors](errors.md#errors-module) give, a host call whose `requestKind` is missing or neither `subscription` nor `execution`; an execution whose `executionMode` is missing or neither `once` nor `continuous`; an event source given an `executionMode`, or declaring no result, since each event it delivers is the value its subscription projects; a member the evaluator invokes given either key, an unnamed indexer named `[]`, as Nexo names it; a continuous execution that declares a result; a `behavior` on a continuous execution, or naming no behavior by a name; one naming no continuous execution of its module; and an event source of a behavior declaring an `impl` or parameters. `domql.registerModule` refuses a module declaring a host call its catalog holds nothing of, as a module `domql.createModule` did not make. So an execution whose mode was left out is refused as an execution missing its mode.
-On a receiver of unknown type, a host call has no declaration yet, so its [candidates](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/host-calls.md#runtime-host-calls), every declaration that takes the call as it is written, say what it does, as they say who invokes it. Where they disagree on what they request, the request is refused as ambiguous with a validation error, located at the call.
+On a receiver of unknown type, a host call has no declaration yet, so its [candidates](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/host-calls.md#runtime-host-calls), every declaration that takes the call as it is written, say what it does, as they say who invokes it. Where they disagree on what they request, the request is refused as ambiguous with a validation error, located at the call.
diff --git a/spec/watches.md b/spec/watches.md
index 2023c3f..367dbee 100644
--- a/spec/watches.md
+++ b/spec/watches.md
@@ -69,7 +69,7 @@ In this document:
## How a member changes
-Every member declares how its result changes, by the categories [Nexo defines](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/members.md#how-a-member-changes), and a watch decides by each what it may follow:
+Every member declares how its result changes, by the categories [Nexo defines](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/members.md#how-a-member-changes), and a watch decides by each what it may follow:
| Category | As in DOMQL | In a watch |
| --- | --- | --- |
@@ -78,7 +78,7 @@ Every member declares how its result changes, by the categories [Nexo defines](h
| Partly observable | A computed style, which a rule outside the element can change unobserved | Allowed when the caller accepts partial observation for that watch; a change the observations miss reaches the watch at its next evaluation, which `refreshAsync` or another observed change causes. |
| Unobserved | A member that names no observations | A validation error. |
-A watch is checked against every member its query may read. A member of a value of `Any` is selected as the query is evaluated, so the watch is checked against every declaration of its name Nexo could select, as Nexo's [candidate declarations](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/runtime/resolution.md) overestimate them: a watch over `panel:bag.rect`, where a module's extension member `bag` answers `Any`, takes `acceptPartialObservation`, as one over `panel.rect` does.
+A watch is checked against every member its query may read. A member of a value of `Any` is selected as the query is evaluated, so the watch is checked against every declaration of its name Nexo could select, as Nexo's [candidate declarations](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/runtime/resolution.md) overestimate them: a watch over `panel:bag.rect`, where a module's extension member `bag` answers `Any`, takes `acceptPartialObservation`, as one over `panel.rect` does.
| Derived | A list's `first` or `where` | Allowed wherever what it derives from is. |
A literal is constant, so a watched object expression can carry one: `viewport { kind = "viewport", width = it.size?.width }`.
@@ -105,7 +105,7 @@ A watch's dependencies are what its last evaluation actually read: each member a
### Following a change a member misses
-A query follows a change its members miss by reading a member that observes it. A body's local runs whether or not anything uses it, as Nexo's [ordered evaluation](https://github.com/FormaUI/Nexo/blob/v1.0.0-beta.2/spec/language/scripts.md#bodies-ordered-evaluation) sets out, so it adds the dependency without adding to the result. A row a sibling's edit moves, which `rectRelativeTo` misses, is followed by reading the text around it:
+A query follows a change its members miss by reading a member that observes it. A body's local runs whether or not anything uses it, as Nexo's [ordered evaluation](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/language/scripts.md#bodies-ordered-evaluation) sets out, so it adds the dependency without adding to the result. A row a sibling's edit moves, which `rectRelativeTo` misses, is followed by reading the text around it:
```domql
let edited = panel.text
diff --git a/tests/Domql.test.js b/tests/Domql.test.js
index 305e4f9..e27dbc7 100644
--- a/tests/Domql.test.js
+++ b/tests/Domql.test.js
@@ -4106,9 +4106,9 @@ describe('domql bodies', () => {
});
it.each([
- ['a query that is a body', 'let a=1\nlet b=a*2\nreturn b', 'let a = 1\nlet b = a * 2\nreturn b'],
- ['a do block in a field', '{ doubled = do\nlet width = w\nreturn width * 2\nend }', '{\n doubled = do\n let width = w\n return width * 2\n end\n}'],
- ['a conditional of explicit results, each on its own lines', 'if a then\nlet x = 1\nreturn x\nelseif b then\nreturn 2\nelse\nreturn 3\nend', 'if a then\n let x = 1\n return x\nelseif b then\n return 2\nelse\n return 3\nend'],
+ ['a query that is a body', 'let a=1\nlet b=a*2\nreturn b', 'let a = 1\nlet b = a * 2\n\nreturn b'],
+ ['a do block in a field', '{ doubled = do\nlet width = w\nreturn width * 2\nend }', '{\n doubled = do\n let width = w\n\n return width * 2\n end\n}'],
+ ['a conditional of explicit results, each on its own lines', 'if a then\nlet x = 1\nreturn x\nelseif b then\nreturn 2\nelse\nreturn 3\nend', 'if a then\n let x = 1\n\n return x\nelseif b then\n return 2\nelse\n return 3\nend'],
['a conditional of implicit results, on one line', 'if a then 1 else 2 end', 'if a then 1 else 2 end'],
['an implicit conditional whose alternative is an explicit one, kept apart', 'if a then\n1\nelse\nif b then\nreturn 2\nelse\nreturn 3\nend\nend', 'if a then\n 1\nelse\n if b then\n return 2\n else\n return 3\n end\nend'],
['a conditional on one line where a hole holds it', '$"{if a then 1 else 2 end}"', '$"{if a then 1 else 2 end}"'],
@@ -4221,9 +4221,9 @@ describe('domql functions', () => {
});
it.each([
- ['a function of one expression, on its line', 'let f=function(x)x*2 end\nreturn f(1)', 'let f = function(x) x * 2 end\nreturn f(1)'],
- ['a function whose body returns, on the lines within it', 'let f = function(x)\nlet d = x * 2\nreturn d\nend\nreturn f(1)', 'let f = function(x)\n let d = x * 2\n return d\nend\nreturn f(1)'],
- ['a function whose one expression spans lines', 'let f = function(x)\nif x < 0 then\nreturn 0\nelse\nreturn x\nend\nend\nreturn f(1)', 'let f = function(x)\n if x < 0 then\n return 0\n else\n return x\n end\nend\nreturn f(1)'],
+ ['a function of one expression, on its line', 'let f=function(x)x*2 end\nreturn f(1)', 'let f = function(x) x * 2 end\n\nreturn f(1)'],
+ ['a function whose body returns, on the lines within it', 'let f = function(x)\nlet d = x * 2\nreturn d\nend\nreturn f(1)', 'let f = function(x)\n let d = x * 2\n\n return d\nend\n\nreturn f(1)'],
+ ['a function whose one expression spans lines', 'let f = function(x)\nif x < 0 then\nreturn 0\nelse\nreturn x\nend\nend\nreturn f(1)', 'let f = function(x)\n if x < 0 then\n return 0\n else\n return x\n end\nend\n\nreturn f(1)'],
['a function in an object local', '{ let f = function(a, b) a + b end, s = f(1, 2) }', '{\n let f = function(a, b) a + b end,\n s = f(1, 2)\n}'],
])('writes %s', (_, text, formatted) => {
expect(domql.format(text)).toBe(formatted);
@@ -4389,7 +4389,7 @@ describe('domql reserved names', () => {
it('calls a function a reserved word names after @', () => {
expect(evaluate('let end = function(x) x + 1 end\nreturn @end(1)')).toBe(2);
- expect(domql.format('let end = function(x) x + 1 end\nreturn @end(1)')).toBe('let end = function(x) x + 1 end\nreturn @end(1)');
+ expect(domql.format('let end = function(x) x + 1 end\nreturn @end(1)')).toBe('let end = function(x) x + 1 end\n\nreturn @end(1)');
});
it('takes to as a declared name, a reference, a field, a member and a conversion in one query', () => {
@@ -4419,7 +4419,7 @@ describe('domql reserved names', () => {
['an ordinary binding nothing hides, bare', parameter('panel'), 'panel'],
['a reserved binding, after ~', parameter('to'), '~to'],
['a binding a field hides, after ~', { kind: 'object', objectFields: [{ name: 'panel', value: literal(1) }, { name: 'a', value: parameter('panel') }] }, '{\n panel = 1,\n a = ~panel\n}'],
- ['a reserved local, after @', { kind: 'body', locals: [{ name: 'to', value: literal(1) }], result: { kind: 'local', name: 'to' } }, 'let to = 1\nreturn @to'],
+ ['a reserved local, after @', { kind: 'body', locals: [{ name: 'to', value: literal(1) }], result: { kind: 'local', name: 'to' } }, 'let to = 1\n\nreturn @to'],
['a member of a module, through its namespace', domqlMember('document'), 'Domql.document'],
['a binding named after a module, after ~', parameter('Domql'), '~Domql'],
])('writes %s', (_, query, text) => {
@@ -4604,10 +4604,10 @@ describe('domql function values and arrow functions', () => {
const { definition } = domql.query('let double = (row) => row * 2\nreturn double(4)');
expect(definition.expression.locals[0].value).toEqual({ kind: 'function', parameters: ['row'], body: { kind: 'arithmetic', operator: '*', left: { kind: 'local', name: 'row' }, right: literal(2) }, arrow: true });
- expect(domql.format(definition)).toBe('let double = row => row * 2\nreturn double(4)');
- expect(domql.format('let f = (a, b) => a\nreturn f(1, 2)')).toBe('let f = (a, b) => a\nreturn f(1, 2)');
- expect(domql.format('let f = () => 1\nreturn f()')).toBe('let f = () => 1\nreturn f()');
- expect(domql.format('let f = it => @it + 1\nreturn f(1)')).toBe('let f = it => @it + 1\nreturn f(1)');
+ expect(domql.format(definition)).toBe('let double = row => row * 2\n\nreturn double(4)');
+ expect(domql.format('let f = (a, b) => a\nreturn f(1, 2)')).toBe('let f = (a, b) => a\n\nreturn f(1, 2)');
+ expect(domql.format('let f = () => 1\nreturn f()')).toBe('let f = () => 1\n\nreturn f()');
+ expect(domql.format('let f = it => @it + 1\nreturn f(1)')).toBe('let f = it => @it + 1\n\nreturn f(1)');
expect(domql.query(domql.format(definition)).definition).toEqual(definition);
});
From fb23c59702ae1b6ac26585fbbb493da551fa7367 Mon Sep 17 00:00:00 2001
From: Eyal Alon <3756641+soyeyalon@users.noreply.github.com>
Date: Thu, 5 Nov 2026 17:35:19 +0200
Subject: [PATCH 10/13] docs(domql): name the preview in the design
The design said it describes DOMQL's 1.0.0-beta.2, which the preview
replaced: it describes 1.0.0-preview.1, as the specification does.
---
docs/domql-design.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/domql-design.md b/docs/domql-design.md
index 72b0a97..fa15934 100644
--- a/docs/domql-design.md
+++ b/docs/domql-design.md
@@ -1,6 +1,6 @@
# DOMQL Design v1.0.0-preview.1
-The [DOMQL specification](../spec/README.md) is the contract: DOMQL's module, which declares the DOM as Nexo's domain, and the host that carries queries out against a document. This design sets out how this implementation is built to meet it, and the reasons behind the choices that shape it. It describes DOMQL's version `1.0.0-beta.2` on Nexo's definition version 38, as the specification does, and an outline of the C# half, which waits for its design; [the status overview](features-status.md) says where the implementation still differs. [Nexo's design](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/nexo-design.md), at the release DOMQL builds against, sets out how the language and its runtime are built.
+The [DOMQL specification](../spec/README.md) is the contract: DOMQL's module, which declares the DOM as Nexo's domain, and the host that carries queries out against a document. This design sets out how this implementation is built to meet it, and the reasons behind the choices that shape it. It describes DOMQL's version `1.0.0-preview.1` on Nexo's definition version 38, as the specification does, and an outline of the C# half, which waits for its design; [the status overview](features-status.md) says where the implementation still differs. [Nexo's design](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/nexo-design.md), at the release DOMQL builds against, sets out how the language and its runtime are built.
In this document:
From b54ae9cffdcffe1f106f6f070a114cb890cc9a25 Mon Sep 17 00:00:00 2001
From: Eyal Alon <3756641+soyeyalon@users.noreply.github.com>
Date: Thu, 5 Nov 2026 17:36:22 +0200
Subject: [PATCH 11/13] docs(domql): record dev and candidate made
The status overview no longer lists making dev and candidate among
what the first preview's release waits for: both stand at main's tip,
and dev holds the work since.
---
docs/features-status.md | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/docs/features-status.md b/docs/features-status.md
index 0f58be3..9df9402 100644
--- a/docs/features-status.md
+++ b/docs/features-status.md
@@ -275,9 +275,8 @@ DOMQL releases as [cutting a release](../CONTRIBUTING.md#cut-a-release) sets out
**Remaining for `1.0.0-preview.1`:**
-1. Create `dev` and `candidate` from `main`'s tip. The organization's linear-history rule refuses a new branch holding `main`'s one merge commit, `3c68220`, made before the rules, so the owner lifts it for DOMQL while they're made.
-2. Create nuget.org's trusted-publishing policy for `release.yml` in the `release` environment, which needs the owner's account.
-3. Release `1.0.0-preview.1`.
+1. Create nuget.org's trusted-publishing policy for `release.yml` in the `release` environment, which needs the owner's account.
+2. Release `1.0.0-preview.1`.
From d641cd17f795a6974b9a09bd66ded1752e0a43bb Mon Sep 17 00:00:00 2001
From: Eyal Alon <3756641+soyeyalon@users.noreply.github.com>
Date: Thu, 5 Nov 2026 18:17:14 +0200
Subject: [PATCH 12/13] docs(domql): note Nexo's packages published
Consuming Nexo's packages no longer waits for them: Nexo publishes
them from its 1.0.0-preview.1, so the status overview says that work
can start, and that DOMQL's npm package follows it.
---
docs/features-status.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/features-status.md b/docs/features-status.md
index 9df9402..3fd0799 100644
--- a/docs/features-status.md
+++ b/docs/features-status.md
@@ -291,7 +291,7 @@ DOMQL releases as [cutting a release](../CONTRIBUTING.md#cut-a-release) sets out
2. Write the NuGet bundle with `../nexo/nexo.js` as an import, and the npm bundle with `@formaui-net/nexo`, rather than carrying the language inside.
3. Have the gate check that DOMQL's packages depend on Nexo's and Nexo's on nothing of DOMQL's, and run DOMQL's tests against the packaged Nexo.
-Needs Nexo's packages, which its [release](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/features-status.md#release) publishes.
+Nexo's packages are published from its `1.0.0-preview.1`, as its [release](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/features-status.md#release) records, so this work can start.
### Packages
@@ -305,7 +305,7 @@ Needs Nexo's packages, which its [release](https://github.com/FormaUI/Nexo/blob/
1. Make the npm package, `@formaui-net/domql`, carrying the runtime version as the NuGet package does, its bundle importing `@formaui-net/nexo`, as [consuming the language](#consuming-nexo) sets out, and have `release.yml` publish it beside the NuGet package.
-It waits for Nexo's published packages. `release.yml` publishes the NuGet package from each release's tag, as [contributing](../CONTRIBUTING.md#cut-a-release) sets out.
+It follows [consuming the language](#consuming-nexo). `release.yml` publishes the NuGet package from each release's tag, as [contributing](../CONTRIBUTING.md#cut-a-release) sets out.
### Preview
From 302a561c43afa272ad73f9bc5f99ddb4f738af4a Mon Sep 17 00:00:00 2001
From: Eyal Alon <3756641+soyeyalon@users.noreply.github.com>
Date: Thu, 5 Nov 2026 18:19:10 +0200
Subject: [PATCH 13/13] chore(domql): release 1.0.0-preview.1
The first preview, and DOMQL's first release, implementing its
specification 1.0.0-preview.1 on Nexo's language 1.0.0-preview.1. It
dates the changelog's entry and the version history's, and is tagged
v1.0.0-preview.1, whose release publishes the NuGet package. The
package's guide now installs it from nuget.org, a local build being
the way to try a change before it's released.
---
CHANGELOG.md | 2 +-
README.md | 2 +-
VERSION-HISTORY.md | 2 +-
docs/features-status.md | 15 +++++----------
nuget/README.md | 13 ++++++++-----
5 files changed, 16 insertions(+), 18 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d32667f..66cb772 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,7 +9,7 @@ Each release of DOMQL's packages, newest first. The NuGet package `formaui-net.D
## `1.0.0-preview.1`
-*Unreleased · specification `1.0.0-preview.1` · Nexo language `1.0.0-preview.1` · definition format 38*
+*November 5, 2026 · specification `1.0.0-preview.1` · Nexo language `1.0.0-preview.1` · definition format 38*
- The first preview, and the first release, as [FormaUI Versioning's stages](https://github.com/FormaUI/Versioning/blob/v1.0.0-preview.1/docs/versions.md#stages) name it: the runtime and the specification take `1.0.0-preview.1`, with the beta's promise. The [version history](VERSION-HISTORY.md) records what came before it.
- The NuGet package links its release notes to its changelog entry at its tag, records its repository and commit through Source Link, and ships its symbols beside it as a `.snupkg`. It no longer holds the build's `global.json`, which it delivered to a consumer as content.
diff --git a/README.md b/README.md
index fa5941d..4c11b18 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
DOMQL is a JavaScript library for querying the DOM, allowing you to read information from a document once or observe it as it changes. Its queries are written in [Nexo](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md).
-> **Preview.** No breaking redesign is planned, and a version that breaks what the one before it allowed says how to migrate. The runtime, `1.0.0-preview.1`, implements DOMQL's specification `1.0.0-preview.1` on Nexo's language `1.0.0-preview.1`, definition version 38. DOMQL declares the DOM as types of its own. It is not yet published to npm or NuGet; you can [build and try it locally](#build-and-try-it). See [the status overview](docs/features-status.md), and [what 1.0 requires](docs/features-status.md#what-1-0-requires).
+> **Preview.** No breaking redesign is planned, and a version that breaks what the one before it allowed says how to migrate. The runtime, `1.0.0-preview.1`, implements DOMQL's specification `1.0.0-preview.1` on Nexo's language `1.0.0-preview.1`, definition version 38. DOMQL declares the DOM as types of its own. It is published to NuGet as `formaui-net.DOMQL`, and not yet to npm; you can also [build and try it locally](#build-and-try-it). See [the status overview](docs/features-status.md), and [what 1.0 requires](docs/features-status.md#what-1-0-requires).
## Features
diff --git a/VERSION-HISTORY.md b/VERSION-HISTORY.md
index a2f46aa..c4403a4 100644
--- a/VERSION-HISTORY.md
+++ b/VERSION-HISTORY.md
@@ -17,7 +17,7 @@ Each entry says what its version breaks:
## `1.0.0-preview.1`
-*Unreleased · Nexo language `1.0.0-preview.1` · definition format 38*
+*November 5, 2026 · Nexo language `1.0.0-preview.1` · definition format 38*
```domql
input.disabled // a state, a Boolean property; input.disabled() before, NEXO3017 now
diff --git a/docs/features-status.md b/docs/features-status.md
index 3fd0799..8fc1f52 100644
--- a/docs/features-status.md
+++ b/docs/features-status.md
@@ -11,7 +11,7 @@
| Definition format | 38 | 38 |
- **The language DOMQL runs on.** DOMQL follows Nexo's language `1.0.0-preview.1`, which Nexo's release `1.0.0-preview.1` carries and `nexo.release` pins, as [D108](decisions.md#d108) records, and its documents link to [Nexo's documents at that tag](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md), moving with the pin. The language was called Lexica before the [migration](#migration-to-nexo).
-- **Packages.** The bundle and type declarations are built, with Nexo bundled inside `domql.js`. The NuGet package is packed locally, carrying the runtime version `1.0.0-preview.1`, and is unpublished. The npm package is not made yet: `package.json` is private and carries no version.
+- **Packages.** The bundle and type declarations are built, with Nexo bundled inside `domql.js`. The NuGet package carries the runtime version `1.0.0-preview.1`, and `release.yml` publishes it to nuget.org from the release's tag. The npm package is not made yet: `package.json` is private and carries no version.
- **The C# half** waits for its design, as [D46](decisions.md#d46) records.
The [specification](../spec/README.md) defines the contract, and the [design](domql-design.md) explains the architecture. The [version history](../VERSION-HISTORY.md) records what each version changed, and the [changelog](../CHANGELOG.md) each release of the packages. This file tracks DOMQL's implementation and its remaining work. "Implemented" means built and tested in the gate for the current implementation version; it does not imply that later specification changes are implemented.
@@ -24,7 +24,7 @@ The [specification](../spec/README.md) defines the contract, and the [design](do
| --- | --- |
| [The C# half](#the-c-half) | Waits for its design |
| [Planned capabilities](#planned-capabilities) | The C# half's alone remain, waiting for its design |
-| [Release](#release) | The preview is declared, `1.0.0-preview.1`, DOMQL's first release, on Nexo's first preview; nuget.org's trusted publishing remains before it's cut |
+| [Release](#release) | Done: `1.0.0-preview.1`, DOMQL's first release, is released, on Nexo's first preview |
| [What 1.0 requires](#what-1-0-requires) | Six requirements, one met in part |
- **A specification version collects the changes between two releases.** A change to DOMQL's contract joins the [version history](../VERSION-HISTORY.md)'s newest entry while it reads *Unreleased*, and opens the next version's entry once it is released, as [D79](decisions.md#d79) records.
@@ -271,12 +271,7 @@ None remains: T1 to T3 are implemented, as [the features](#the-host) show: an im
## Release
-DOMQL releases as [cutting a release](../CONTRIBUTING.md#cut-a-release) sets out, by FormaUI Versioning's path, as [D107](decisions.md#d107) records. Its first release, `1.0.0-preview.1`, publishes the NuGet package with Nexo inside its bundle, and consuming Nexo's published packages follows it.
-
-**Remaining for `1.0.0-preview.1`:**
-
-1. Create nuget.org's trusted-publishing policy for `release.yml` in the `release` environment, which needs the owner's account.
-2. Release `1.0.0-preview.1`.
+DOMQL releases as [cutting a release](../CONTRIBUTING.md#cut-a-release) sets out, by FormaUI Versioning's path, as [D107](decisions.md#d107) records. Its first release, `1.0.0-preview.1`, is released, tagged `v1.0.0-preview.1`, and `release.yml` publishes its NuGet package, with Nexo inside its bundle, to nuget.org through trusted publishing. nuget.org's policy names `FormaUI/DOMQL`, `release.yml` and the `release` environment. Consuming Nexo's published packages follows it.
@@ -297,7 +292,7 @@ Nexo's packages are published from its `1.0.0-preview.1`, as its [release](https
**Current:**
-- **NuGet:** the full gate, `./build.ps1 -Full`, packs `formaui-net.DOMQL` locally, checks it holds exactly the files `scripts/packages` lists, and installs it into a web application outside the repository, whose published `domql.js` resolves a query. It carries the runtime version `src/Versions.mjs` declares, `1.0.0-preview.1`, and is unpublished.
+- **NuGet:** the full gate, `./build.ps1 -Full`, packs `formaui-net.DOMQL` locally, checks it holds exactly the files `scripts/packages` lists, and installs it into a web application outside the repository, whose published `domql.js` resolves a query. It carries the runtime version `src/Versions.mjs` declares, `1.0.0-preview.1`, and `release.yml` publishes it to nuget.org from each release's tag.
- **npm:** not made yet. `package.json` is private and carries no version.
- **The gate** holds the NuGet package, both READMEs, the [changelog](../CHANGELOG.md) and `domql.info.versions` to the versions the sources declare. The sources declare the version due at the next release, so nothing advances before a release is cut, as [D75](decisions.md#d75) and [D79](decisions.md#d79) record.
@@ -327,7 +322,7 @@ It follows [consuming the language](#consuming-nexo). `release.yml` publishes th
| **Nexo's 1.0.** DOMQL runs on Nexo's 1.0, from its published packages. | DOMQL's contract holds the language its queries are written in, so it promises no more than Nexo does. | Nexo is in its preview, at `1.0.0-preview.1`, as [what Nexo's 1.0 requires](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/docs/features-status.md#what-1-0-requires) sets out. |
| **Contracts settled.** No decision is open, and each [deferred](#deferred) item and [decision not taken](domql-design.md#decisions-not-taken) is shown to land without a break. | What may still change after 1.0 must be able to change compatibly. | Holds: no decision is open, and each [deferred](#deferred) item and [decision not taken](domql-design.md#decisions-not-taken) lands as an addition or within the implementation. A watch's promise to evaluate its whole query each time was the one that would have made evaluating less a break; [what an evaluation gives](../spec/watches.md#watching-what-an-evaluation-gives) now leaves it to DOMQL. |
| **The C# half decided.** It is designed, or decided to follow 1.0 as an addition. | It waits for the owner's design, as [D46](decisions.md#d46) records, and a .NET application may need it to drive DOMQL. | Waits for its design. |
-| **Published.** DOMQL's packages are on npm and NuGet, tested as consumers install them. | A caller pins a release it can install. | The NuGet package is packed locally, and the npm package is not made yet. |
+| **Published.** DOMQL's packages are on npm and NuGet, tested as consumers install them. | A caller pins a release it can install. | In part: the NuGet package is published from `1.0.0-preview.1`, and the npm package is not made yet. |
| **Used for real.** Forma's own scripts run as DOMQL queries, watches, subscriptions and executions on a published release. | The [planned capabilities](#planned-capabilities) came from reading those scripts, and only running them settles the contract. | Planned. |
| **A release candidate that breaks nothing.** `1.0.0-rc.1` is released once the rest hold, and Forma takes it with no change but its version. `1.0.0` is its contract, unchanged. | It is the last check that nothing still needs to break. | Waits for the rest. |
diff --git a/nuget/README.md b/nuget/README.md
index e5368fb..af3f11c 100644
--- a/nuget/README.md
+++ b/nuget/README.md
@@ -4,7 +4,7 @@
DOMQL is a JavaScript library for querying the DOM, allowing you to read information from a document once or observe it as it changes. This guide takes you from your first query to watching results, handling events and extending the library. Its queries are written in [Nexo](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md).
-> **Preview:** no breaking redesign is planned, and a version that breaks what the one before it allowed says how to migrate. `formaui-net.DOMQL` is not yet published to NuGet. [Build the package locally](#install-and-load) to try it. The package distributes a JavaScript ES module; the API in this guide runs in JavaScript. Every example here runs on this preview. The runtime, `1.0.0-preview.1`, implements DOMQL's specification `1.0.0-preview.1` on Nexo's language `1.0.0-preview.1`, definition version 38. [The status overview](https://github.com/FormaUI/DOMQL/blob/main/docs/features-status.md) says what is implemented and what is being built.
+> **Preview:** no breaking redesign is planned, and a version that breaks what the one before it allowed says how to migrate. `formaui-net.DOMQL` is published to NuGet as a pre-release, which you [install by name](#install-and-load). The package distributes a JavaScript ES module; the API in this guide runs in JavaScript. Every example here runs on this preview. The runtime, `1.0.0-preview.1`, implements DOMQL's specification `1.0.0-preview.1` on Nexo's language `1.0.0-preview.1`, definition version 38. [The status overview](https://github.com/FormaUI/DOMQL/blob/main/docs/features-status.md) says what is implemented and what is being built.
## In this guide
@@ -22,14 +22,17 @@ DOMQL is a JavaScript library for querying the DOM, allowing you to read informa
## Install and load
-Build the repository with `./build.ps1 -Full`. This writes the local NuGet package to `artifacts/`, verified as an application installs it; see the [repository setup instructions](https://github.com/FormaUI/DOMQL#build-and-try-it) for prerequisites.
-
-From your application's project directory, add the package using that folder as the source. Adjust the path to your local `artifacts/` directory:
+From your application's project directory, add the package from nuget.org. It's a pre-release, so `dotnet add package` needs `--prerelease`:
```sh
-dotnet add package formaui-net.DOMQL --prerelease --source ./artifacts
+dotnet add package formaui-net.DOMQL --prerelease
```
+To try a change before it's released, build the package yourself:
+
+1. Run `./build.ps1 -Full` in the repository. It writes the package to `artifacts/`, verified as an application installs it. The [repository setup instructions](https://github.com/FormaUI/DOMQL#build-and-try-it) list the prerequisites.
+2. Add it from there, adjusting the path to your `artifacts/` directory: `dotnet add package formaui-net.DOMQL --prerelease --source ./artifacts`.
+
In a .NET web application hosted at the site root, import DOMQL from a JavaScript module:
```js