Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 the job checks out both, Nexo at that tag.
# DOMQL builds against Nexo's npm package, and its link test reads Nexo's documents at the release's tag from a checkout beside its own, formaui-net.Nexo beside formaui-net.DOMQL, so the job checks out both, Nexo at that tag.
defaults:
run:
working-directory: formaui-net.DOMQL
Expand All @@ -36,12 +36,12 @@ jobs:
with:
path: formaui-net.DOMQL

# The tag of the Nexo release DOMQL builds against, which nexo.release pins.
- name: Read the pinned Nexo release
# The tag of the Nexo release DOMQL builds against, the version of Nexo's package the lock installs.
- name: Read the Nexo release
id: nexo
run: echo "tag=v$(tr -d '[:space:]' < nexo.release)" >> "$GITHUB_OUTPUT"
run: echo "tag=v$(jq -r '.packages["node_modules/@formaui-net/nexo"].version' package-lock.json)" >> "$GITHUB_OUTPUT"

# Nexo's whole history, since DOMQL's documents link to commits a record of the past names, which the link test reads.
# Nexo's whole history, since DOMQL's documents link to the release's tag and to commits a record of the past names, which the link test reads.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: FormaUI/Nexo
Expand Down Expand Up @@ -90,6 +90,7 @@ jobs:
with:
name: packages
path: |
formaui-net.DOMQL/artifacts/*.tgz
formaui-net.DOMQL/artifacts/*.nupkg
formaui-net.DOMQL/artifacts/*.snupkg
if-no-files-found: error
Expand Down
27 changes: 26 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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.
# 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 and npm through trusted publishing. A run that fails runs again for the same tag, publishing what each feed lacks.
on:
push:
tags: ['v*']
Expand Down Expand Up @@ -42,6 +42,12 @@ jobs:
packages-artifact: packages
name: DOMQL

# Node's npm, 11.5.1 or later, which trusted publishing needs.
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24
registry-url: https://registry.npmjs.org

- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
global-json-file: nuget/global.json
Expand All @@ -64,3 +70,22 @@ jobs:
if ($LASTEXITCODE -ne 0) {
throw 'Publishing to nuget.org failed.'
}

# The npm package, under the dist-tag of its stage, past a version npm holds already; trusted publishing records its provenance. It depends on Nexo's npm package, which Nexo's own release published.
- name: Publish to npm
shell: pwsh
env:
PACKAGES: ${{ steps.packages.outputs.directory }}
VERSION: ${{ steps.check.outputs.version }}
run: |
$held = npm view "@formaui-net/domql@$env:VERSION" version 2>$null
if ($held -eq $env:VERSION) {
Write-Host "npm holds @formaui-net/domql $env:VERSION already."
exit 0
}

$tag = if ($env:VERSION -match '-(preview|rc)\.') { $Matches[1] } else { 'latest' }
npm publish (Join-Path $env:PACKAGES "formaui-net-domql-$env:VERSION.tgz") --tag $tag --access public
if ($LASTEXITCODE -ne 0) {
throw 'Publishing to npm failed.'
}
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
# Dependencies, installed by npm in the repository root and in tests/.
node_modules/

# Nexo at the release nexo.release pins, or a link to the checkout NEXO_SOURCE names, which build.ps1 prepares; without a trailing slash, so a link is ignored as a folder is.
/.nexo

# The package project's build output and the packed package.
nuget/bin/
nuget/obj/
Expand Down
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
# Changelog

Each release of DOMQL's packages, newest first. The NuGet package `formaui-net.DOMQL` carries the runtime version, and the npm package `@formaui-net/domql` will carry the same once it is made. An entry names the version of DOMQL's specification the release implements, the Nexo language and definition format it runs on, and what changed in the implementation. What changed in DOMQL's contract is in the [version history](VERSION-HISTORY.md).
Each release of DOMQL's packages, newest first. The npm package `@formaui-net/domql` and the NuGet package `formaui-net.DOMQL` carry the runtime version. An entry names the version of DOMQL's specification the release implements, the Nexo language and definition format it runs on, and what changed in the implementation. What changed in DOMQL's contract is in the [version history](VERSION-HISTORY.md).

- **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.

<a id="v1-0-0-preview-2"></a>

## `1.0.0-preview.2`

*November 5, 2026 · specification `1.0.0-preview.1` · Nexo language `1.0.0-preview.1` · definition format 38*

- DOMQL is published to npm, as `@formaui-net/domql`: its ES module sources and their declarations, which import Nexo from its own package, `@formaui-net/nexo`, from `1.0.0-preview.1` on. A host that installs both loads one Nexo, and catches Nexo's own `NexoError`. Install it with `npm install @formaui-net/domql@preview`.

<a id="v1-0-0-preview-1"></a>

## `1.0.0-preview.1`
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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-preview.1/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 installs from npm, at the release `package.json` declares as the lowest it works with and its lock installs, so a change reaches DOMQL only when that version moves to a release that holds it; with `NEXO_SOURCE` naming a checkout, `build.ps1` links that checkout's working tree in the package's place 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 the version once Nexo releases it. Link Nexo's documents at the release's tag, as `https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md`, so they move with it; the link test reads them from a checkout of [FormaUI/Nexo](https://github.com/FormaUI/Nexo) beside this one, named `formaui-net.Nexo`.

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.

Expand Down
21 changes: 11 additions & 10 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ 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-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:
DOMQL is written in [Nexo](https://github.com/FormaUI/Nexo/blob/v1.0.0-preview.1/spec/README.md), which it installs from npm, `@formaui-net/nexo`, at the release `package.json` declares and its lock installs. Its link test reads Nexo's documents at that release's tag from a checkout of [FormaUI/Nexo](https://github.com/FormaUI/Nexo) beside this one, so clone it beside this repository under the name the build looks for:

```sh
git clone https://github.com/FormaUI/Nexo.git formaui-net.Nexo
```

After cloning the repositories, run the build, which extracts the pinned Nexo into `.nexo`, installs the dependencies and runs the unit tests:
After cloning the repositories, run the build, which installs the dependencies, Nexo's package among them, and runs the unit tests:

```sh
pwsh ./build.ps1
```

To work on Nexo and DOMQL together, set `NEXO_SOURCE` to a Nexo checkout, and the build links `.nexo` to its working tree; unset it to build against the pinned release again.
To work on Nexo and DOMQL together, set `NEXO_SOURCE` to a Nexo checkout, and the build links its working tree in the package's place; unset it to build against the release again. To move to another release, run `npm install @formaui-net/nexo@^<version>`, which declares it as the lowest version DOMQL works with, and move every link into Nexo to its tag in the same commit.

Run the full build from the repository root:

Expand Down Expand Up @@ -104,29 +104,30 @@ The language a query is written in is Nexo's, and its contract is Nexo's.

| 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 package version | `runtime` | The packages, 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 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 `package.json` declares | 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 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 npm package, the NuGet package and its symbols into `artifacts/`, checks each holds exactly the files its list in `scripts/packages/` names, and installs each outside the repository from a local feed: the npm package into a Node project, with Nexo's package from npm, which resolves a query and type-checks against its declarations, and the NuGet package 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 |
| `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 packages published to nuget.org and npm 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 |
| npm, `@formaui-net/domql` | The ES module sources and their declarations, `src/domql.d.ts`, with the README, license and notice, as `scripts/packages/npm.files` lists them | ES2022 JavaScript: browsers, as modules a bundler or an import map resolves | npm, under the dist-tag of its stage, `preview` or `rc`, and `latest` for a stable release | `@formaui-net/nexo`, from the release `package.json` declares |
| 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 `package.json` declares 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.
A package of DOMQL's that depends on Nexo's names the lowest Nexo version DOMQL works with, as `package.json` does.

The [changelog](CHANGELOG.md) records each release, and the [version history](VERSION-HISTORY.md) each specification version, by their own rules.

Expand All @@ -136,7 +137,7 @@ The [changelog](CHANGELOG.md) records each release, and the [version history](VE

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. **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*.
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 `package.json` 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.
Expand Down
Loading