Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
617a645
ci: remove the Dependabot rebase workflow
4Luke4 Sep 23, 2026
7c2387e
fix(ci): keep duplicate Dependabot runs from failing required checks
4Luke4 Sep 23, 2026
d5cacc9
fix(tools): generate every API section from pinned inputs with exact …
4Luke4 Sep 23, 2026
4e69e18
fix(tools): show published EE signatures verbatim and drop entry sepa…
4Luke4 Sep 23, 2026
baaf7a0
fix(shared): resolve EEex base types as inheritance, not baseclass fi…
4Luke4 Sep 23, 2026
519f306
fix: render documentation HTML in hovers and send offset parameter la…
4Luke4 Sep 23, 2026
77e338a
test: hold API hovers to the pinned upstream text in the feature gates
4Luke4 Sep 23, 2026
ec80546
docs: record pinned documentation inputs, hover fidelity and inheritance
4Luke4 Sep 23, 2026
13347a4
fix(tools): parse :ref: targets that contain angle brackets
4Luke4 Sep 23, 2026
20d01cb
fix(tools): keep list code blocks, bold spacing and literal angle bra…
4Luke4 Sep 23, 2026
e392333
test: cover a mid-entry rule and section heading in the EEex fixture
4Luke4 Sep 23, 2026
56e14ab
test: treat backslash-escaped angle brackets as text in the hover audit
4Luke4 Sep 23, 2026
79d277c
chore(data): regenerate API data from pinned inputs with exact hover …
4Luke4 Sep 23, 2026
fc3ff1f
style: apply the Prettier formatting produced by the CI maintenance run
4Luke4 Sep 23, 2026
79cf1ad
fix(tools): escape Markdown without incomplete backslash handling
4Luke4 Sep 23, 2026
b44c7f9
chore(data): write literal angle brackets in EEex prose as <
4Luke4 Sep 23, 2026
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
89 changes: 89 additions & 0 deletions .github/actions/upstream-docs/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Pinned upstream documentation
description: >-
Materialises every pinned upstream documentation input that API regeneration reads, as inert data
under .cache/, and exports the IE_LUA_* variables that point the ingestion tool at it.

# Why this exists: regeneration used to call the GitHub REST API and raw.githubusercontent.com
# anonymously, and hosted runners share the 60-requests-per-hour anonymous REST limit per IP, so the
# required "Pinned API regeneration" job failed at random with "403 rate limit exceeded". Git
# checkouts and one release download are not subject to that limit, and nothing here hands a token
# to repository code: actions/checkout consumes the job token itself and persist-credentials: false
# removes it again before any later step runs.
#
# Trust boundary: everything fetched here is third-party documentation. It is parsed as data by
# packages/tools/src/ingest-docs.ts and is never executed, built, or sourced. The Lua archive is
# accepted only after its SHA-256 matches the pin recorded in packages/tools/upstream-pins.json,
# and only the manual page is extracted from it.

inputs:
eeex-commit:
description: Full 40-character Bubb13/EEex-Docs commit to check out.
required: true

runs:
using: composite
steps:
- name: Resolve pinned revisions
id: pins
shell: bash
env:
EEEX_COMMIT: ${{ inputs.eeex-commit }}
run: |
set -euo pipefail
# Every value below reaches a checkout ref, a URL, or a path, so each one is validated
# against its exact expected shape before it is used anywhere.
pins=packages/tools/upstream-pins.json
luajit_repository="$(jq -er '.luajit.repository' "$pins")"
luajit_commit="$(jq -er '.luajit.commit' "$pins")"
lua52_url="$(jq -er '.lua52.url' "$pins")"
lua52_sha256="$(jq -er '.lua52.sha256' "$pins")"
[[ "$EEEX_COMMIT" =~ ^[0-9a-f]{40}$ ]]
[[ "$luajit_repository" == LuaJIT/LuaJIT ]]
[[ "$luajit_commit" =~ ^[0-9a-f]{40}$ ]]
[[ "$lua52_url" =~ ^https://www\.lua\.org/ftp/lua-5\.2\.[0-9]+\.tar\.gz$ ]]
[[ "$lua52_sha256" =~ ^[0-9a-f]{64}$ ]]
{
echo "luajit-repository=$luajit_repository"
echo "luajit-commit=$luajit_commit"
echo "lua52-url=$lua52_url"
echo "lua52-sha256=$lua52_sha256"
} >> "$GITHUB_OUTPUT"

- name: Check out EEex-Docs at the pinned commit
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: Bubb13/EEex-Docs
ref: ${{ inputs.eeex-commit }}
path: .cache/eeex-docs
persist-credentials: false

- name: Check out the LuaJIT documentation at the pinned commit
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ steps.pins.outputs.luajit-repository }}
ref: ${{ steps.pins.outputs.luajit-commit }}
path: .cache/luajit
persist-credentials: false
# Only the HTML documentation is read; the sources are never needed.
sparse-checkout: doc

- name: Download and verify the Lua 5.2 reference manual
shell: bash
env:
LUA52_URL: ${{ steps.pins.outputs.lua52-url }}
LUA52_SHA256: ${{ steps.pins.outputs.lua52-sha256 }}
run: |
set -euo pipefail
mkdir -p .cache/lua52
archive=.cache/lua52/lua.tar.gz
# No redirect following: the pinned URL must answer directly, and the digest below is the
# identity check regardless of what the server returns.
curl --fail --silent --show-error --retry 3 --output "$archive" "$LUA52_URL"
echo "$LUA52_SHA256 $archive" | sha256sum --check --strict -
release="$(basename "$LUA52_URL" .tar.gz)"
tar -xzf "$archive" -C .cache/lua52 "$release/doc/manual.html"
{
echo "IE_LUA_EEEX_DOCS_ROOT=$GITHUB_WORKSPACE/.cache/eeex-docs"
echo "IE_LUA_LUAJIT_DOCS_ROOT=$GITHUB_WORKSPACE/.cache/luajit"
echo "IE_LUA_LUA52_MANUAL=$GITHUB_WORKSPACE/.cache/lua52/$release/doc/manual.html"
} >> "$GITHUB_ENV"
17 changes: 13 additions & 4 deletions .github/workflows/conventional-commits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ permissions:
contents: read
pull-requests: read

concurrency:
group: conventional-commits-${{ github.event.pull_request.number }}
cancel-in-progress: true
# No concurrency group on purpose. Dependabot force-pushes (synchronize) and edits the pull request
# (edited) within the same second; with cancel-in-progress one of the two runs was cancelled after
# its check run already existed, leaving a CANCELLED "Validate commit messages" entry beside the
# SUCCESS one and failing the required-check rollup. This job is read-only, idempotent and takes
# seconds, so letting every run finish is cheaper than any cancellation scheme.

jobs:
validate:
Expand Down Expand Up @@ -42,7 +44,14 @@ jobs:
: [`${commit.sha.slice(0, 7)} ${header || '<empty message>'}`];
});

const title = context.payload.pull_request.title;
// Read the title as it is now rather than from the event payload, so overlapping runs for
// one head all judge the same title and cannot leave a stale verdict behind.
const { data: pull } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
});
const title = pull.title;
if (title.length > 100 || !conventionalHeader.test(title)) invalid.push(`PR title: ${title}`);

if (invalid.length > 0) {
Expand Down
56 changes: 40 additions & 16 deletions .github/workflows/dependabot-automerge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,31 +37,55 @@ jobs:
run: |
set -euo pipefail

# Lists every run of one workflow for the pull request's current head.
runs_for() {
gh run list \
--repo "$GITHUB_REPOSITORY" \
--workflow "$1" \
--event pull_request \
--commit "$PR_HEAD_SHA" \
--limit 50 \
--json databaseId,status,conclusion
}

for workflow in ci.yml codeql.yml dependency-review.yml conventional-commits.yml; do
run_id=""
found=""
for _ in {1..30}; do
run_id="$(
gh run list \
--repo "$GITHUB_REPOSITORY" \
--workflow "$workflow" \
--event pull_request \
--commit "$PR_HEAD_SHA" \
--limit 1 \
--json databaseId \
--jq '.[0].databaseId // empty'
)"
if [[ -n "$run_id" ]]; then
found="$(runs_for "$workflow" | jq -r '.[].databaseId')"
if [[ -n "$found" ]]; then
break
fi
sleep 10
done

if [[ -z "$run_id" ]]; then
if [[ -z "$found" ]]; then
echo "No $workflow run found for commit $PR_HEAD_SHA." >&2
exit 1
fi

gh run watch "$run_id" --repo "$GITHUB_REPOSITORY" --exit-status
# One head can have several runs of the same workflow, because Dependabot's push and its
# edit of the pull request arrive together. Judging whichever run a listing returned
# first is how a superseded, cancelled run once failed this job, so every run is awaited
# and the whole set is judged. gh run watch does its own polling until a run completes.
while :; do
pending="$(runs_for "$workflow" | jq -r '.[] | select(.status != "completed") | .databaseId')"
if [[ -z "$pending" ]]; then
break
fi
while read -r run_id; do
gh run watch "$run_id" --repo "$GITHUB_REPOSITORY" > /dev/null
done <<< "$pending"
done

# A cancelled run is only a superseded duplicate when a run for the same head succeeded;
# any other outcome, or no success at all, keeps the update out of the merge queue.
conclusions="$(runs_for "$workflow" | jq -r '.[].conclusion')"
unexpected="$(grep -vxE 'success|cancelled' <<< "$conclusions" || true)"
if [[ -n "$unexpected" ]] || ! grep -qx success <<< "$conclusions"; then
echo "$workflow did not pass for commit $PR_HEAD_SHA:" >&2
echo "$conclusions" >&2
exit 1
fi
done
- name: Squash-merge verified patch update
if: steps.metadata.outputs.update-type == 'version-update:semver-patch'
Expand All @@ -75,6 +99,6 @@ jobs:
test "$current_head" = "$PR_HEAD_SHA"
# The ruleset requires branches to be up to date, so an immediate merge is refused outright
# ("N of N required status checks are expected") whenever main has moved since these checks
# ran. Queueing the merge instead lets it complete once the branch is current, which the
# Dependabot rebase workflow arranges.
# ran. Queueing the merge instead lets it complete once the branch is current; a maintainer
# brings a behind update up to date with an "@dependabot rebase" comment.
gh pr merge "$PR_URL" --auto --squash --match-head-commit "$PR_HEAD_SHA"
90 changes: 0 additions & 90 deletions .github/workflows/dependabot-rebase.yml

This file was deleted.

7 changes: 7 additions & 0 deletions .github/workflows/update-eeex-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ jobs:
run: npm ci --no-audit --progress=false
- if: steps.revision.outputs.changed == 'true'
run: npm run compile
# The generator reads pinned local copies of every upstream input; see the action for why the
# network API is no longer used during generation.
- name: Fetch pinned upstream documentation
if: steps.revision.outputs.changed == 'true'
uses: ./.github/actions/upstream-docs
with:
eeex-commit: ${{ steps.revision.outputs.commit }}
- if: steps.revision.outputs.changed == 'true'
env:
IE_LUA_EEEX_COMMIT: ${{ steps.revision.outputs.commit }}
Expand Down
12 changes: 12 additions & 0 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,18 @@ jobs:
cache-dependency-path: package-lock.json
- run: npm ci --no-audit --progress=false
- run: npm run compile
# Regeneration reads every upstream input from a pinned local copy instead of the network API,
# so the job cannot fail on the anonymous REST rate limit and no token reaches PR code.
- name: Resolve the pinned EEex revision
id: eeex
run: |
commit="$(jq -er '.sources[] | select(.id == "ee-game-structures-x64") | .commit' resources/api/api-index.json)"
[[ "$commit" =~ ^[0-9a-f]{40}$ ]]
echo "commit=$commit" >> "$GITHUB_OUTPUT"
- name: Fetch pinned upstream documentation
uses: ./.github/actions/upstream-docs
with:
eeex-commit: ${{ steps.eeex.outputs.commit }}
- run: node scripts/regenerate.cjs
- run: npx --no-install prettier --write resources/api
- name: Require reproducible committed data
Expand Down
21 changes: 19 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- Verify every language service named in the README as its own case against the bundled stdio
server on Linux, Windows, and macOS, and fail the policy check when that list and the
verification inventory disagree.
- Ask out-of-date Dependabot pull requests to rebase when the base branch moves, so the
up-to-date merge requirement stops leaving them unmergeable.
- Ship client configurations and setup guides for Sublime Text, Neovim, Emacs, JetBrains IDEs,
Helix, Geany and Kate, and document what Zed and Notepad++ actually require. The policy check
validates every shipped configuration against the manifest in `editors/`.
- Hold hovers to the published documentation: the declared-feature and installed-extension suites
compare representative hovers from all six sources byte for byte with the pinned upstream text,
and every shipped hover is audited for Markdown that would render differently from its source.
- Complete and hover members that EEex structures inherit from the structures they extend.

### Fixed

Expand All @@ -29,6 +31,19 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
so embedded Lua analysis and the formatter boundary no longer depend on the editor's naming.
- Open an API symbol's upstream documentation externally on Go to Definition instead of returning a
location the editor cannot open.
- Stop the required Pinned API regeneration job from failing on the anonymous GitHub API rate
limit: it now reads every upstream input from pinned local checkouts and a verified archive.
- Keep Dependabot's simultaneous push and pull-request edit from leaving a cancelled required
commit-message check, and let the patch auto-merge judge every run for the head instead of
whichever run was listed first.
- Show published signatures verbatim, including `...` varargs and upstream's `???` markers,
instead of invented `arg1`-style names, with unambiguous signature-help parameter ranges.
- Render Lua 5.2 and LuaJIT help exactly as published: typographic characters, superscripts,
tables, alternative call forms, and links are kept instead of being flattened or dropped.
- Resolve every upstream cross-reference to its pinned source line instead of a dead in-page
link, drop the doubled rule before the source link, and let VS Code render the documentation's
inline HTML.
- Stop offering and hovering EEex `baseclass_<n>` layout rows as if they were readable members.

### Changed

Expand All @@ -40,6 +55,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- Remove unused shared exports and fold three hand-rolled offset/position conversions into the
indexed mapper that already backs analysis.
- Lint the CommonJS scripts and test harnesses, which no lint configuration previously matched.
- Generate Lua 5.2 help from the official 5.2.4 release archive and LuaJIT help from the LuaJIT
repository at a pinned commit, so all six sections are regenerated and verified reproducibly.

## [0.6.0] - 2026-09-08

Expand Down
Loading
Loading