diff --git a/.gitea/workflows/renovate.yml b/.gitea/workflows/renovate.yml deleted file mode 100644 index b8c9348..0000000 --- a/.gitea/workflows/renovate.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Renovate -on: - schedule: - - cron: '43 4 * * *' - workflow_dispatch: - -jobs: - renovate: - runs-on: docker-host - steps: - - name: Run Renovate against this repo - env: - GITHUB_COM_TOKEN: ${{ secrets.RENOVATE_GITHUB_TOKEN }} - RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }} - run: | - docker run --rm \ - -e GITHUB_COM_TOKEN \ - -e LOG_LEVEL=info \ - -e RENOVATE_ENDPOINT=https://gitea.larvit.se/api/v1 \ - -e RENOVATE_GIT_AUTHOR="Renovate Bot " \ - -e RENOVATE_PLATFORM=gitea \ - -e RENOVATE_REPOSITORIES=${{ github.repository }} \ - -e RENOVATE_TOKEN \ - renovate/renovate:44.39.2 diff --git a/.gitea/workflows/ci.yml b/.github/workflows/ci.yml similarity index 61% rename from .gitea/workflows/ci.yml rename to .github/workflows/ci.yml index b57a5d5..d781f6a 100644 --- a/.gitea/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,9 +1,15 @@ name: CI -on: push +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read jobs: gate: - runs-on: docker-host + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v7.0.1 - run: bash ci.sh @@ -12,9 +18,11 @@ jobs: concurrency: cancel-in-progress: false group: publish - if: github.ref == 'refs/heads/main' + if: github.event_name == 'push' needs: gate - runs-on: docker-host + permissions: + contents: write + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v7.0.1 - env: diff --git a/AGENTS.md b/AGENTS.md index 9e29223..084f7dd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -36,6 +36,7 @@ In `docs/decisions.md`: - ESM only - One built entrypoint - Public on npm +- GitHub is canonical, and Gitea a pull mirror of it - The formats are API - The code list - Which code a cause takes diff --git a/CHANGELOG.md b/CHANGELOG.md index d73fcc1..1e5903b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- The source moves to [github.com/larvit/adf-codec](https://github.com/larvit/adf-codec), where + issues and pull requests go; `package.json`'s `repository`, `bugs` and `homepage` point there. - **Breaking:** directives, the inline opaque carry among them (now `!adf:carry{json="…"}`), are spelled under an `!adf:` prefix (`!adf:name … !adf:/name`, `!adf:name[content]{attrs}`, `!adf:name arg {attrs}`) in place of the `:::`/`::`/`:name` forms: text holding an unescaped diff --git a/README.md b/README.md index 7e250dd..3b17b4f 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ an HTML dialect. **Status: published — the markdown round-trip (`adfToMarkdown`, `markdownToAdf`); HTML at `0.2.0`.** Plan: -[`todo.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/todo.md). Decisions: -[`docs/decisions.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/docs/decisions.md). Changes: -[`CHANGELOG.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/CHANGELOG.md). The lossless flavour's grammar: -[`spec/flavour.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/spec/flavour.md). -Upgrading from `0.1.0`: [convert your markdown first](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/MIGRATION.md). +[`todo.md`](https://github.com/larvit/adf-codec/blob/main/todo.md). Decisions: +[`docs/decisions.md`](https://github.com/larvit/adf-codec/blob/main/docs/decisions.md). Changes: +[`CHANGELOG.md`](https://github.com/larvit/adf-codec/blob/main/CHANGELOG.md). The lossless flavour's grammar: +[`spec/flavour.md`](https://github.com/larvit/adf-codec/blob/main/spec/flavour.md). +Upgrading from `0.1.0`: [convert your markdown first](https://github.com/larvit/adf-codec/blob/main/MIGRATION.md). ## What it is for @@ -152,7 +152,7 @@ read replaces mentions, attachments and macros with text. ## The errors Serves Goal 1. An ADF node type this version does not know is not an error: the lossless pair -carries it opaquely and restores it unchanged ([`docs/decisions.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/docs/decisions.md#unknown-nodes-ride-the-carry)). +carries it opaquely and restores it unchanged ([`docs/decisions.md`](https://github.com/larvit/adf-codec/blob/main/docs/decisions.md#unknown-nodes-ride-the-carry)). `ConvertError` is `{ code, message, path, position? }`. `code` is the exported `ConvertErrorCode`, stable across minors and safe to `switch` on exhaustively with no `default`; `message` is free text @@ -206,7 +206,7 @@ Serves Goals 1, 4 and 5. - `markdownToAdf(adfToMarkdown(doc))` deep-equals `doc` as JSON, for a document of plain objects as `JSON.parse` builds them — every key and value as `doc` holds it, adjacent text nodes, an empty `attrs`, `content` or `marks` and `-0` included, and unknown node types carried opaquely - ([`docs/decisions.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/docs/decisions.md#unknown-nodes-ride-the-carry)). + ([`docs/decisions.md`](https://github.com/larvit/adf-codec/blob/main/docs/decisions.md#unknown-nodes-ride-the-carry)). - Markdown this library reads, and markdown it writes, means what the CommonMark spec says; from `0.2.0`, well-formed HTML means what the HTML standard says, read or written. The bullets below name every exception. @@ -237,7 +237,7 @@ Serves Goals 1, 4 and 5. - A document nested deeper than 500 levels is an error result, not a stack overflow, and no call loops forever on a string, or on a value `JSON.parse` or `structuredClone` builds. - The emitted formats are semver surface - ([`docs/decisions.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/docs/decisions.md#the-formats-are-api)). + ([`docs/decisions.md`](https://github.com/larvit/adf-codec/blob/main/docs/decisions.md#the-formats-are-api)). - **`0.2.0`** — `htmlToAdf(adfToHtml(doc))` deep-equals `doc`; fidelity HTML cannot express rides `data-*` attributes. Foreign HTML maps a documented element set, which markdown's raw HTML reads through as well, and a construct outside it is an error; well-formed HTML only — no tag-soup @@ -248,5 +248,5 @@ Serves Goals 1, 4 and 5. Serves Goal 8. ESM only, no runtime dependencies, public npm. Built JavaScript with `.d.ts` beside it. Pure ECMAScript at an ES2022 baseline, reaching for no host API; the test suite runs under Node, Deno and Bun, and a headless Firefox converts the corpus through the built entrypoint. -Contract: [`docs/decisions.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/docs/decisions.md#any-es2022-engine), §Any +Contract: [`docs/decisions.md`](https://github.com/larvit/adf-codec/blob/main/docs/decisions.md#any-es2022-engine), §Any ES2022 engine to §Public on npm. diff --git a/docs/decisions.md b/docs/decisions.md index 4cd196e..e68b688 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -304,10 +304,20 @@ an npm consumer. 2026-08-23, the name 2026-09-01, the maintainer. Goals 2 and 8. Valid while the package's source stays public beside it. -Published to public npm as `@larvit/adf-codec`. Public source: the Gitea repo goes public, -LICENSE in place, before the first publish. A codec, since it converts both directions, and named +Published to public npm as `@larvit/adf-codec`. Public source: the GitHub repository, LICENSE in +place. A codec, since it converts both directions, and named for the hub rather than the formats around it. +## GitHub is canonical, and Gitea a pull mirror of it + +2026-10-04, the maintainer. Goal 3. Valid while developers search GitHub for a library. + +`github.com/larvit/adf-codec` owns the history, its issues and its CI, and publishes to npm with the +organization's `NPM_TOKEN` secret. `gitea.larvit.se/larvit/adf-codec` becomes a read-only pull +mirror of it, so the move back stays open and never a second owner. Until `todo.md` item 72 +re-creates it as that mirror, the Gitea copy holds the history before the move under its old hashes +and runs no workflow: push to GitHub only. + ## The formats are API 2026-08-23, strict input 2026-09-01, content models 2026-09-16, the maintainer. Goal 1. diff --git a/package.json b/package.json index be69669..8f9d38f 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,10 @@ "license": "MIT", "repository": { "type": "git", - "url": "git+https://gitea.larvit.se/larvit/adf-codec.git" + "url": "git+https://github.com/larvit/adf-codec.git" }, + "bugs": "https://github.com/larvit/adf-codec/issues", + "homepage": "https://github.com/larvit/adf-codec#readme", "type": "module", "exports": { ".": { diff --git a/renovate.json b/renovate.json index daf367a..a2cf84d 100644 --- a/renovate.json +++ b/renovate.json @@ -7,8 +7,12 @@ "datasourceTemplate": "docker", "depNameTemplate": "denoland/deno", "description": "Pin the Deno image the gate runs", - "managerFilePatterns": ["docker-runner.sh"], - "matchStrings": ["denoland/deno:(?[0-9][^\\s\"']*)"], + "managerFilePatterns": [ + "docker-runner.sh" + ], + "matchStrings": [ + "denoland/deno:(?[0-9][^\\s\"']*)" + ], "versioningTemplate": "docker" }, { @@ -16,8 +20,12 @@ "datasourceTemplate": "docker", "depNameTemplate": "node", "description": "Pin the node image the gate runs", - "managerFilePatterns": ["docker-runner.sh"], - "matchStrings": ["node_image=node:(?[0-9][^\\s\"']*)"], + "managerFilePatterns": [ + "docker-runner.sh" + ], + "matchStrings": [ + "node_image=node:(?[0-9][^\\s\"']*)" + ], "versioningTemplate": "docker" }, { @@ -25,8 +33,12 @@ "datasourceTemplate": "docker", "depNameTemplate": "node-floor", "description": "Pin the node image proving engines.node, held to that major", - "managerFilePatterns": ["docker-runner.sh"], - "matchStrings": ["floor_image=node:(?[0-9][^\\s\"']*)"], + "managerFilePatterns": [ + "docker-runner.sh" + ], + "matchStrings": [ + "floor_image=node:(?[0-9][^\\s\"']*)" + ], "packageNameTemplate": "node", "versioningTemplate": "docker" }, @@ -35,17 +47,12 @@ "datasourceTemplate": "docker", "depNameTemplate": "oven/bun", "description": "Pin the Bun image the gate runs", - "managerFilePatterns": ["docker-runner.sh"], - "matchStrings": ["oven/bun:(?[0-9][^\\s\"']*)"], - "versioningTemplate": "docker" - }, - { - "customType": "regex", - "datasourceTemplate": "docker", - "depNameTemplate": "renovate/renovate", - "description": "Pin the Renovate image the Renovate workflow runs", - "managerFilePatterns": [".gitea/workflows/renovate.yml"], - "matchStrings": ["renovate/renovate:(?[0-9][^\\s\"']*)"], + "managerFilePatterns": [ + "docker-runner.sh" + ], + "matchStrings": [ + "oven/bun:(?[0-9][^\\s\"']*)" + ], "versioningTemplate": "docker" }, { @@ -53,17 +60,25 @@ "datasourceTemplate": "docker", "depNameTemplate": "selenium/standalone-firefox", "description": "Pin the Firefox image the gate's browser leg runs", - "managerFilePatterns": ["docker-runner.sh"], - "matchStrings": ["selenium/standalone-firefox:(?[0-9][^\\s\"']*)"], + "managerFilePatterns": [ + "docker-runner.sh" + ], + "matchStrings": [ + "selenium/standalone-firefox:(?[0-9][^\\s\"']*)" + ], "versioningTemplate": "docker" } ], - "extends": ["config:recommended"], + "extends": [ + "config:recommended" + ], "packageRules": [ { "allowedVersions": "<19", "description": "engines.node states >=18, so the image proving it stays on 18", - "matchDepNames": ["node-floor"] + "matchDepNames": [ + "node-floor" + ] } ] } diff --git a/todo.md b/todo.md index cd35449..91ab136 100644 --- a/todo.md +++ b/todo.md @@ -6,7 +6,7 @@ `Bar = 9` -`Next ID = 74` +`Next ID = 75` | Goal | W | |---|---| @@ -36,10 +36,10 @@ | 68 | 0.2.0 | | **Carry a non-text inline node holding `content` or `text`, a block holding `text`, and a leaf block holding `content`.** | 3 | 3 | 4 | 7 | 1 | 18.2 | | 65 | 0.2.0 | defect | **Read an image not alone in its paragraph as its alt text linked to its URL, and a titled image alone in its paragraph as the image captioned with its title.** | 5 | 5 | 7 | 7 | 4, 5, 7 | 17.1 | | 70 | 0.2.0 | | **Give `package.json` the `keywords` someone searching npm for an ADF converter types.** | 1 | 1 | 4 | 6 | 3 | 16.1 | -| 72 | 0.2.0 | | **Make GitHub the canonical repository, with `gitea.larvit.se/larvit/adf-codec` a read-only pull mirror of it.** | 5 | 6 | 5 | 8 | 3 | 16.0 | | 49 | 0.2.0 | | **Read a list whose bullet or ordered delimiter changes as two lists, in both readers, and retire `!adf:listBreak`.** | 4 | 5 | 5 | 8 | 4, 5 | 15.5 | | 46 | 0.2.0 | | **Publish the bundle size in the README, failing the release pipeline when it drifts.** | 2 | 4 | 5 | 5 | 3, 8 | 14.8 | | 61 | 0.2.0 | decision | **Have the emitter ask the inline reader how a line reads back, in place of `line-escaping.ts` predicting it.** | 6 | 8 | 3 | 8 | 1 | 14.0 | +| 72 | 0.2.0 | decision | **Re-create `gitea.larvit.se/larvit/adf-codec` as a read-only pull mirror of GitHub, its issues off and its description pointing at GitHub.** | 2 | 1 | 3 | 6 | 3 | 13.1 | | 52 | 0.2.0 | | **Spell `colwidth` as a comma list, `colwidth="340,420"`.** | 3 | 3 | 5 | 6 | 6 | 11.5 | | 51 | 0.2.0 | | **Match a reference label to its definition under Unicode case folding.** | 2 | 2 | 2 | 7 | 4, 5 | 10.9 | | 60 | 0.2.0 | decision | **Collect the questions `parse/` asks `emit/` into one named module.** | 3 | 4 | 2 | 6 | 2 | 10.7 | @@ -50,6 +50,7 @@ | 73 | 0.3.0 | | **Announce the package where someone needing an ADF converter already reads: JRACLOUD-77436, the Atlassian developer community and Stack Overflow's ADF-to-markdown questions.** | 1 | 2 | 6 | 8 | 3 | 23.0 | | 9 | 0.3.0 | | **Ship an online sandbox: a web page with two textboxes converting between ADF and markdown on the library's browser build.** | 2 | 6 | 6 | 8 | 3 | 21.0 | | 38 | 0.3.0 | | **Spell a lone surrogate in a text node so it survives a UTF-8 encode.** | 2 | 2 | 4 | 7 | 1 | 19.5 | +| 74 | 0.3.0 | | **Keep the release path publishing past npm's bypass-2FA token retirement.** | 4 | 4 | 8 | 3 | 3 | 15.7 | | 34 | 0.3.0 | | **Read emphasis flanking by the whole character beside an astral symbol.** | 2 | 3 | 3 | 6 | 4, 5 | 11.3 | | 31 | 0.3.0 | | **Make the branch-coverage figure repeat across runs of an unchanged tree.** | 2 | 3 | 3 | 4 | 1 | 11.2 | | 42 | 0.3.0 | defect | **Trim a text leaf's trailing blanks in linear time.** | 1 | 2 | 5 | 9 | 9 | 10.5 | @@ -63,12 +64,12 @@ ### 47. Open the README with what the package is, what it does and for whom. -Lands after item 72: the badges are npm's version and the GitHub Actions status. Today the README -opens with the pre-launch rationale — Atlassian's REST APIs, `pf-editor-service/convert` being -decommissioned, a link to JRACLOUD-77436. The background goes entirely, no endpoint, ticket or "why" -note left. The README names the lossy pair, `adfToPlainMarkdown` and `plainMarkdownToAdf`, and the -flavours it writes and reads — GitHub Flavored Markdown's alerts and task lists, Obsidian Flavored -Markdown's callouts — so a search for any of these names finds the package. +The badges are npm's version and the GitHub Actions status. Today the README opens with the +pre-launch rationale — Atlassian's REST APIs, `pf-editor-service/convert` being decommissioned, a +link to JRACLOUD-77436. The background goes entirely, no endpoint, ticket or "why" note left. The +README names the lossy pair, `adfToPlainMarkdown` and `plainMarkdownToAdf`, and the flavours it +writes and reads — GitHub Flavored Markdown's alerts and task lists, Obsidian Flavored Markdown's +callouts — so a search for any of these names finds the package. ### 7. Ship HTML: `adfToHtml`, `htmlToAdf`, and `markdownToHtml` / `htmlToMarkdown` composed through ADF. @@ -155,22 +156,6 @@ npm list and the names the README uses — ADF, Atlassian Document Format, markd — so a search for any of them can reach the package. Found while planning discoverability, 2026-10-04. -### 72. Make GitHub the canonical repository, with `gitea.larvit.se/larvit/adf-codec` a read-only pull mirror of it. - -The maintainer's call, 2026-10-04: GitHub is where an ADF converter is searched for, and the Gitea -copy keeps the move back open. The workflows move to `.github/workflows/` with `ci.sh` unchanged. -Publishing moves to npm's trusted publishing over OIDC, which GitHub-hosted Actions support, and -which outlives the bypass-2FA token npm retires around January 2027: `publish.sh` drops `NPM_TOKEN` -for the Actions OIDC variables, and AGENTS.md §7 reserves the trusted-publisher setup in place of -the secret. `package.json`'s `repository` moves and it gains `bugs` and `homepage`. The links in -README, CHANGELOG and MIGRATION follow, as do AGENTS.md's forge commands and merge style. -`docs/decisions.md` gains the entry "GitHub is canonical, and Gitea a pull mirror of it" (Goal 3), -and §Public on npm and §Publish on a version bump are revised: the source is public on GitHub, and -CI publishes through npm's trusted publisher. Gitea's open issues and its releases move to GitHub -first, since a mirror carries only git refs; the mirror disables issues and its description points -at GitHub. Creating the GitHub repository, configuring npm's trusted publisher, and re-creating the -Gitea copy as a mirror (Gitea cannot convert an existing repository) are the maintainer's. - ### 49. Read a list whose bullet or ordered delimiter changes as two lists, in both readers, and retire `!adf:listBreak`. Lands after item 43. Today `- a` then `+ b`, or `1.` then `1)`, reads as one list; CommonMark reads @@ -200,6 +185,14 @@ only the property tests catch drift. It caps the panel's Locality score. The rep time linear in the line: today `mergesWithSyntax`, `touchesSyntax` and `closesHeading` rescan a run of one character from each of its characters. +### 72. Re-create `gitea.larvit.se/larvit/adf-codec` as a read-only pull mirror of GitHub, its issues off and its description pointing at GitHub. + +Lands after the maintainer confirms the GitHub repository's settings, history, CI gate and +publishing. The maintainer's: Gitea cannot convert an existing repository to a mirror, so the copy +is deleted and re-created, which drops its hashes from before the history rewrite of 2026-10-04 and +its Actions secrets. It holds no issues or releases to move. `docs/decisions.md` §GitHub is +canonical, and Gitea a pull mirror of it loses its interim sentence when this lands. + ### 52. Spell `colwidth` as a comma list, `colwidth="340,420"`. A writer panel chose it on 2026-10-03, 5 of 7, over today's `colwidth="[340,420]"`. Breaking: @@ -249,8 +242,8 @@ which counts one fewer. ### 73. Announce the package where someone needing an ADF converter already reads: JRACLOUD-77436, the Atlassian developer community and Stack Overflow's ADF-to-markdown questions. -Lands after `0.2.0` is published with items 47, 71 and 72, so each post links the GitHub repository, -the comparison and a README that opens with what the package is. We draft each post for the place it +Lands after `0.2.0` is published with items 47 and 71, so each post links the GitHub repository, the +comparison and a README that opens with what the package is. We draft each post for the place it goes; the maintainer posts them. Found while planning discoverability, 2026-10-04. ### 38. Spell a lone surrogate in a text node so it survives a UTF-8 encode. @@ -258,6 +251,20 @@ goes; the maintainer posts them. Found while planning discoverability, 2026-10-0 `adfToMarkdown` emits it verbatim, so markdown stored as UTF-8 reads back U+FFFD; attribute values already escape it. +### 74. Keep the release path publishing past npm's bypass-2FA token retirement. + +Lands after 2027-01-01, or after a release run fails on the token, whichever comes first: the +maintainer chose on 2026-10-02 to wait and see whether the retirement bites. It holds back no +release: when the rest of its release is done, it moves to the next. `0.1.0` published only once the +npm token carried **Bypass 2FA**: the account requiring no 2FA on writes was not enough, and npm +answered `EOTP` until the token itself bypassed. npm retires bypass-2FA tokens for direct publishing +around January 2027, leaving them `npm stage publish`, which a maintainer approves with 2FA. Its +replacement, trusted publishing over OIDC, supports GitHub-hosted Actions, where the release runs +since 2026-10-04 with the organization's `NPM_TOKEN` (the maintainer's choice). The trade is the +maintainer's: move `publish.sh` to trusted publishing, or to the staged publish, which fits badly +with publish-on-merge. The Goals and G cells are provisional: no README goal covers the release +path. + ### 34. Read emphasis flanking by the whole character beside an astral symbol. Check whether `line-escaping.ts`'s `charAt` and the parser's flanking read one UTF-16 unit beside an