From cce6008fef11ac1efb838032d6489418f6b9514b Mon Sep 17 00:00:00 2001 From: Shinrai Date: Fri, 2 Oct 2026 16:14:34 -0700 Subject: [PATCH 01/12] ci: run the in-repo PR mirror job instead of skipping it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Required PR Check mirror job was skipped on the `pull_request` run of an in-repo feature PR, with a conditional name keeping the skipped check off `✅ Required PR Check`. GitHub never evaluates a skipped job's `name:`, so every in-repo PR showed the raw expression as a check name. The job now uses `if: always()` and never skips, so its name is always evaluated. On the in-repo PR path it lands on `⏭️ Required PR Check (reported by the push run)` and passes as a no-op; the push run still posts `✅ Required PR Check`. Every path that posts the required name keeps `needs: ci`, so that check still only exists once the full test matrix for the SHA has finished. Synced from CLDMV/.github#351 (CLDMV/.github#350). --- .github/workflows/ci.yml | 63 +++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6162a31..2b5d385 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -302,37 +302,37 @@ jobs: # automatically — no `pull_request` round-trip needed for non-fork # non-release PRs. required-check: - # The name is conditional on purpose. On an in-repo feature PR the - # `pull_request` run skips this job (the push run owns the status), and - # a skipped job still posts a check run under its name. GitHub treats a - # SKIPPED required check as satisfied — so if the skipped job were named - # `✅ Required PR Check`, it would green-light the ruleset (and enable - # auto-merge) while the push run's real mirror hadn't been created yet - # (it only appears once `ci` finishes), letting a PR merge mid-test or - # even override a red result. An expression name keeps the skipped job - # off the required name: GitHub does not evaluate the name of a skipped - # job, so it shows up as the raw expression text (still not the - # required name), while every path that runs evaluates to - # `✅ Required PR Check`. The condition is written out anyway so the - # name stays correct if GitHub ever starts evaluating it, and must stay - # identical to the `if:` below. - name: ${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == true || github.event.pull_request.head.ref == 'next' || github.event.pull_request.head.ref == 'hotfixes') && '✅ Required PR Check' || '⏭️ Required PR Check (reported by the push run)' }} - needs: ci - # Mirror the `ci` job's gating exactly. The four cases that run: + # Which name this job reports under is the whole point of it. + # + # The ruleset gates merges on `✅ Required PR Check`, so a check with that + # name must only ever exist on a head SHA after the full test matrix for + # that SHA has finished, mirroring its result. `needs: ci` guarantees the + # timing: the job is only created once every Build & Test leg and the + # coverage job are done. + # + # On an in-repo feature PR the `pull_request` run does not own the status + # (the push run on the head branch does), so it must not post + # `✅ Required PR Check` at all. Two traps rule out the obvious shapes: + # - A job SKIPPED by `if:` still posts a check run under its name, and + # GitHub treats a skipped required check as satisfied. Under the real + # name that let PRs merge mid-test (CLDMV/slothlet#553). + # - GitHub does not evaluate the `name:` of a skipped job, so a + # conditional name on a skippable job shows up as the raw expression + # text (#350). + # So the job never skips: it runs on every path, the name expression is + # always evaluated, and the in-repo PR path lands on a readable, + # non-required name and passes as a no-op. The condition below is + # repeated in the step's OWNS_STATUS and must stay identical. The paths + # that own the status: # 1. push events (job needs CI run) # 2. fork PRs (push doesn't cover forks) # 3. release PRs from `next` → master/main (push covers SHA but commit-gate skips chore-bump) # 4. release PRs from `hotfixes` → master/main (same reason) - # In-repo feature PRs targeting `next` / `hotfixes` skip on - # pull_request — the push run on the head branch reports the status - # on the SHA. See the `name:` above for why the skipped job is renamed. - if: | - always() && ( - github.event_name != 'pull_request' || - github.event.pull_request.head.repo.fork == true || - github.event.pull_request.head.ref == 'next' || - github.event.pull_request.head.ref == 'hotfixes' - ) + name: ${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == true || github.event.pull_request.head.ref == 'next' || github.event.pull_request.head.ref == 'hotfixes') && '✅ Required PR Check' || '⏭️ Required PR Check (reported by the push run)' }} + needs: ci + # always(): run even when `ci` is skipped (the in-repo PR path) or failed + # (so the mirror can report red). + if: always() # Match the reusable's runner routing (workflow-ci.yml): private CLDMV # repos run on self-hosted cldmv-runners (GitHub-hosted Actions budget is # private-metered and exhausted), public repos use free GitHub-hosted, and @@ -346,10 +346,19 @@ jobs: steps: - name: Mirror reusable result env: + OWNS_STATUS: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == true || github.event.pull_request.head.ref == 'next' || github.event.pull_request.head.ref == 'hotfixes' }} IS_MASTER_SYNC: ${{ needs.ci.outputs.is_master_sync }} DOCS_ONLY: ${{ needs.ci.outputs.docs_only }} CI_RESULT: ${{ needs.ci.result }} run: | + # In-repo feature PR: the push run on the head branch reports + # `✅ Required PR Check`. This job runs under the + # `⏭️ Required PR Check (reported by the push run)` name and + # must not gate anything. + if [ "$OWNS_STATUS" != "true" ]; then + echo "In-repo PR event — the push run reports ✅ Required PR Check for this SHA." + exit 0 + fi echo "ci.result=$CI_RESULT docs_only=$DOCS_ONLY is_master_sync=$IS_MASTER_SYNC" # next/hotfixes was force-synced to master — head SHA matches the # default branch, nothing new to test, green-light without running CI. From 4ab9ee8f9247e00d7d4b20f058d86c68e9be28a9 Mon Sep 17 00:00:00 2001 From: "cldmv-bot[bot]" <230771808+cldmv-bot[bot]@users.noreply.github.com> Date: Sat, 3 Oct 2026 03:06:35 +0000 Subject: [PATCH 02/12] chore: bump version to 1.1.3 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index aa87693..08fcb0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cldmv/jsonv", - "version": "1.1.2", + "version": "1.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cldmv/jsonv", - "version": "1.1.2", + "version": "1.1.3", "license": "Apache-2.0", "devDependencies": { "@cldmv/configs": "^1.2.0", diff --git a/package.json b/package.json index 0ace1ba..eac629c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cldmv/jsonv", - "version": "1.1.2", + "version": "1.1.3", "description": "Modern JSON parser extending JSON5 with ES2015-2025 features, year-based API", "type": "module", "main": "./dist/cjs/index.cjs", From 5fe45e9ad59fafb25913a40483972442f630a022 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 3 Oct 2026 03:09:13 +0000 Subject: [PATCH 03/12] deps: bump the minor group across 1 directory with 2 updates Bumps the minor group with 2 updates in the / directory: [@cldmv/vitest-runner](https://github.com/CLDMV/vitest-runner) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint). Updates `@cldmv/vitest-runner` from 1.4.3 to 1.5.1 - [Release notes](https://github.com/CLDMV/vitest-runner/releases) - [Commits](https://github.com/CLDMV/vitest-runner/compare/v1.4.3...v1.5.1) Updates `typescript-eslint` from 8.70.1 to 8.71.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.71.0/packages/typescript-eslint) --- updated-dependencies: - dependency-name: "@cldmv/vitest-runner" dependency-version: 1.5.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: minor - dependency-name: typescript-eslint dependency-version: 8.71.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 128 +++++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/package-lock.json b/package-lock.json index 08fcb0d..c2d8255 100644 --- a/package-lock.json +++ b/package-lock.json @@ -194,9 +194,9 @@ } }, "node_modules/@cldmv/vitest-runner": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@cldmv/vitest-runner/-/vitest-runner-1.4.3.tgz", - "integrity": "sha512-sltvuUFEB2lWB3ADDiDGR2KJ+sZbZqD3rYkhFBhH+8xiMJtwqISQMOSW5x+J+E7Gd6KOu+7eXZ24VwLwvDMSIQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@cldmv/vitest-runner/-/vitest-runner-1.5.1.tgz", + "integrity": "sha512-Q64qMfJe9TbJOOKE382eqyJiEVbyc8ycfkPFheE4nMOUyV/z7+VRkE3K4viSlCAhUjmlFyU+oxD6DDkax84KDA==", "dev": true, "license": "MIT", "dependencies": { @@ -1151,17 +1151,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.70.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.70.1.tgz", - "integrity": "sha512-nDNrUQ/4ruSNYbu749TRY7cfrzPtoLHEXSNBI8aaNY32LlZCajixqRf3FqcKC4p5Cam4VOHYx/t+i5+nKXvrqA==", + "version": "8.71.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.71.0.tgz", + "integrity": "sha512-pqcS9c1HxZTHt7End4nXqd0s5lJrrFzrgCkKFJrsbUnaL6M3+6oBFZaslg6Gjsl3argl2DDRFROnXARaZ2e4Nw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.70.1", - "@typescript-eslint/type-utils": "8.70.1", - "@typescript-eslint/utils": "8.70.1", - "@typescript-eslint/visitor-keys": "8.70.1", + "@typescript-eslint/scope-manager": "8.71.0", + "@typescript-eslint/type-utils": "8.71.0", + "@typescript-eslint/utils": "8.71.0", + "@typescript-eslint/visitor-keys": "8.71.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -1174,7 +1174,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.70.1", + "@typescript-eslint/parser": "^8.71.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } @@ -1190,16 +1190,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.70.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.70.1.tgz", - "integrity": "sha512-nO974WLllwhSFWQXnMLj6nDGa8f0khKEz1JzpPJ1u7Vm/4X1X6ZHajpoknU4bb41vJyMB0HHVyS2GqdhWfIXZw==", + "version": "8.71.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.71.0.tgz", + "integrity": "sha512-CG4nPk1f2zc8yw4pALqHsFYH2hdo+h1T9daSp21+Hnxi9LOE3GT9hAfTKJCBXVNM2GmYs1eMEP615wPoeOgk3A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.70.1", - "@typescript-eslint/types": "8.70.1", - "@typescript-eslint/typescript-estree": "8.70.1", - "@typescript-eslint/visitor-keys": "8.70.1", + "@typescript-eslint/scope-manager": "8.71.0", + "@typescript-eslint/types": "8.71.0", + "@typescript-eslint/typescript-estree": "8.71.0", + "@typescript-eslint/visitor-keys": "8.71.0", "debug": "^4.4.3" }, "engines": { @@ -1215,14 +1215,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.70.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.70.1.tgz", - "integrity": "sha512-62xOgboPfwc3/IgPSX/W6oQR3ZbF04194FPGUGH8HL8iLFHbt/456/8Ph1wLNUgVF+s94FlHoipBsz+v7+LMnA==", + "version": "8.71.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.0.tgz", + "integrity": "sha512-aABjw5rjBacYONVPaPiWOCjJu0vEF4a25iQuodlmQYL1trtLZ0X/y+2Vzl3BKI1odM4LnwLE1oUDXYp1wzx1TQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.70.1", - "@typescript-eslint/types": "^8.70.1", + "@typescript-eslint/tsconfig-utils": "^8.71.0", + "@typescript-eslint/types": "^8.71.0", "debug": "^4.4.3" }, "engines": { @@ -1237,14 +1237,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.70.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.70.1.tgz", - "integrity": "sha512-Pa0EeSeAusQc1WbjQMac+YfenewYTBu0KjgYvkUKwhXaHUKbFog23Dm/rp0DX/6tyYOQ3Xl1a+3EcFNZynGHCw==", + "version": "8.71.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.71.0.tgz", + "integrity": "sha512-gWF0BhUcnjZxSpLE8ngS/59n2SB0J3YqRxvX1+2aoRJk9hNtHSLOV+TcarFiOr5ipXm3yc1QrI4c9YZc8zyCxw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.70.1", - "@typescript-eslint/visitor-keys": "8.70.1" + "@typescript-eslint/types": "8.71.0", + "@typescript-eslint/visitor-keys": "8.71.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1255,9 +1255,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.70.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.70.1.tgz", - "integrity": "sha512-jumze1fPI+sDOaM2TWGQdn39PDxTr7TZGeuyLkAbNyx2vtMT3uRnVKChN0hfht5V2TugphJzF6bYXvBcE09qqg==", + "version": "8.71.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.0.tgz", + "integrity": "sha512-Z1UlWHADEK2Mlb9NpWfDeSjqoZ5EyrOv4R3eQpbkzqn/EwaIdOpXXupEA1+0ZIOSJSZZDBHG0BrQyN8zUG6Pwg==", "dev": true, "license": "MIT", "engines": { @@ -1272,15 +1272,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.70.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.70.1.tgz", - "integrity": "sha512-7zKTnyvaVWqzLZHPFQtX1hVHqgkMC+WebPWakNCSyrQVbIP1AM0L0TlBZtACldIRb6PptI8Odk+jyZ5kP3B1VA==", + "version": "8.71.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.71.0.tgz", + "integrity": "sha512-i8uO1qbdxeKgRnS5sCRt6On3/nfo2d2DwQe3Yvjx543zLy7r8ySqRuPPiIIXAhS03U0v5NfAFx+rUgxFzKKwNw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.70.1", - "@typescript-eslint/typescript-estree": "8.70.1", - "@typescript-eslint/utils": "8.70.1", + "@typescript-eslint/types": "8.71.0", + "@typescript-eslint/typescript-estree": "8.71.0", + "@typescript-eslint/utils": "8.71.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -1297,9 +1297,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.70.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.70.1.tgz", - "integrity": "sha512-Dm1ypdhhrGCTyyehxElhgJ6kgk8MVCv5qXdoOVqPr1uqk42jX8KjrZqhROvdShczA8qrDoYiOWn1ykWlx2k81Q==", + "version": "8.71.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.71.0.tgz", + "integrity": "sha512-cJ4OoxPGWvFnBTnSZyaU+qJzGTqPTGJY+gDchj6cRyLRdmIdt4rcsE4twj+zPfrNiWuVi38wijHzShL++Z9atQ==", "dev": true, "license": "MIT", "engines": { @@ -1311,16 +1311,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.70.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.70.1.tgz", - "integrity": "sha512-TU8PwyGN0PQJUcE96mw8eCQ44SmxGdQlJmlWakHaHQ15eIuuvye5yNtmh/i6oS88jzXVQB71xdNkbkB/fMwL0g==", + "version": "8.71.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.0.tgz", + "integrity": "sha512-PEEF4G5sLLWAS5BpPrUvms4ySZkiBQQZM4z+3ReI46axK5Vqr/vXBQatJQIZZOYdGyPUAKTtsrWzpqKuU+3DEw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.70.1", - "@typescript-eslint/tsconfig-utils": "8.70.1", - "@typescript-eslint/types": "8.70.1", - "@typescript-eslint/visitor-keys": "8.70.1", + "@typescript-eslint/project-service": "8.71.0", + "@typescript-eslint/tsconfig-utils": "8.71.0", + "@typescript-eslint/types": "8.71.0", + "@typescript-eslint/visitor-keys": "8.71.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -1339,16 +1339,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.70.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.70.1.tgz", - "integrity": "sha512-Esgul8MsnKnRLdYU2Eb2cRV9bS5HJYtKj1ByJnOzzG2M58DGdSUQ1jUuILxipqcpB2h9WLrbD5GijIWUjX/Tqw==", + "version": "8.71.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.71.0.tgz", + "integrity": "sha512-pKR/tEMVrXZG23UFKUn5BQf3zfmfk7KQceI2cGzywZ5nxM5Eu3hEJU1utjWzydtzBbcJAQhHN8iPCxobHpPcZQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.70.1", - "@typescript-eslint/types": "8.70.1", - "@typescript-eslint/typescript-estree": "8.70.1" + "@typescript-eslint/scope-manager": "8.71.0", + "@typescript-eslint/types": "8.71.0", + "@typescript-eslint/typescript-estree": "8.71.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1363,13 +1363,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.70.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.70.1.tgz", - "integrity": "sha512-Vwj9lUIW5Xq3wQ9w6gv3R86g1hMK8f2zNOdGTAgeXUMMXFK78G9ruCjjqutHMNJc0+CH7LYRnHeUB9IT8wFmcw==", + "version": "8.71.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.71.0.tgz", + "integrity": "sha512-8eQ9R218XORK+KLosnf4bu/QsUXvUyVwTbArg7/0NMB1Pu87OJKvj4nhFblkYE8gQV73mW1dx1ptlPCkwRGa7A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/types": "8.71.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -3919,16 +3919,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.70.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.70.1.tgz", - "integrity": "sha512-AcWG7KDjZ2THNXsgwttMaGmzVi0VFRlFYfqFHYQRbDpF3owuYbuiL8c7UUrd2k8s3PoSfIQrWfrGXfcElrWLYA==", + "version": "8.71.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.71.0.tgz", + "integrity": "sha512-fBdHYiqQ14RW6mOMXD14Svn82ZsCYAoQSzGRzyEjR59S5A2Krh/l7fGTOQ7iCr8gGy/mHVXtEF7s5fgjEdV0Pw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.70.1", - "@typescript-eslint/parser": "8.70.1", - "@typescript-eslint/typescript-estree": "8.70.1", - "@typescript-eslint/utils": "8.70.1" + "@typescript-eslint/eslint-plugin": "8.71.0", + "@typescript-eslint/parser": "8.71.0", + "@typescript-eslint/typescript-estree": "8.71.0", + "@typescript-eslint/utils": "8.71.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" From 2e82985971f539adb78b5669b7f251b0f51fb7f0 Mon Sep 17 00:00:00 2001 From: Shinrai Date: Sat, 3 Oct 2026 10:38:59 -0700 Subject: [PATCH 04/12] fix(cjs): make require() a synchronous wrapper around the ESM build The CommonJS entry went through a generated loader.cjs that did `module.exports = (async () => await import("../index.mjs"))()`, so require("@cldmv/jsonv") - and every require("@cldmv/jsonv/") - returned a Promise of the ESM namespace instead of the API. - scripts/build-cjs.mjs: every generated .cjs file is now a thin wrapper, `module.exports = require("")`, loaded through Node's synchronous require(esm). require() returns the same exports as import. The async loader.cjs is no longer generated, dist/cjs is rebuilt from scratch, and dist/years/year-resolver.mjs now gets a CJS wrapper too (the "./*" export already pointed require at one that did not exist). - Where Node.js has no require(esm) (before 20.19 / 22.12) the wrappers throw ERR_REQUIRE_ESM with a message pointing to import() instead of a bare loader error. engines is unchanged. - tests/cjs: node:test checks against the built dist/, run by `npm test` and `npm run coverage` after Vitest: require() of the entry and of a year module returns the same exports as import, and the version check fires when require(esm) is off. - docs: note that require() is synchronous and its Node.js requirement. Existing `await require("@cldmv/jsonv")` code keeps working, since awaiting a non-promise returns it unchanged; only code that chained .then() on the require() result changes. --- docs/versioning-and-exports.md | 2 + package.json | 5 +- scripts/build-cjs.mjs | 164 +++++++++++++-------------------- tests/cjs/entry.test.cjs | 80 ++++++++++++++++ 4 files changed, 147 insertions(+), 104 deletions(-) create mode 100644 tests/cjs/entry.test.cjs diff --git a/docs/versioning-and-exports.md b/docs/versioning-and-exports.md index 31955a9..d0af54c 100644 --- a/docs/versioning-and-exports.md +++ b/docs/versioning-and-exports.md @@ -20,6 +20,8 @@ CJS: const { parse } = require("@cldmv/jsonv/2021"); ``` +`require()` is synchronous and returns the same exports as `import` (existing `await require(...)` code keeps working). It loads the ESM build through Node's `require(esm)`, so it needs Node.js ^20.19.0 or >=22.12.0; on older Node.js, use `import()`. + Root alias: ```js import { parse } from "@cldmv/jsonv"; // latest year diff --git a/package.json b/package.json index eac629c..44cc587 100644 --- a/package.json +++ b/package.json @@ -56,10 +56,11 @@ "build:plugin": "node scripts/build-plugin.mjs", "build:types": "tsc --project .configs/tsconfig.types.json", "build:ci": "npm run lint --if-present && npm run format:check --if-present && npm run build", - "test": "node tests/run-vitest.mjs", + "test": "node tests/run-vitest.mjs && npm run test:cjs", + "test:cjs": "npm run build && node --test tests/cjs/entry.test.cjs", "test:watch": "vitest --config .configs/vitest.config.mjs", "test:types": "tsc --project .configs/tsconfig.build.json --noEmit", - "coverage": "node tests/run-vitest.mjs --coverage-quiet", + "coverage": "node tests/run-vitest.mjs --coverage-quiet && npm run test:cjs", "ci:coverage": "npm run coverage", "lint": "eslint --config .configs/eslint.config.v9.mjs src tests", "lint:v8": "set ESLINT_USE_FLAT_CONFIG=true&& eslint --config .configs/eslint.config.mjs src tests", diff --git a/scripts/build-cjs.mjs b/scripts/build-cjs.mjs index 8627c7c..2a45275 100644 --- a/scripts/build-cjs.mjs +++ b/scripts/build-cjs.mjs @@ -14,11 +14,15 @@ */ /** - * Build CJS wrappers for CommonJS compatibility - * Creates .cjs files that load the ESM modules + * Build CJS wrappers for CommonJS compatibility. + * + * Each .cjs file is a thin wrapper that loads its ESM counterpart through Node's + * synchronous require(esm), so `require("@cldmv/jsonv")` returns the same module + * namespace object that `import` gives. The ESM graph therefore must not use + * top-level await (require(esm) rejects it with ERR_REQUIRE_ASYNC_MODULE). */ -import { mkdirSync, writeFileSync, existsSync, readdirSync } from "fs"; +import { mkdirSync, writeFileSync, readdirSync, rmSync } from "fs"; import { join, dirname } from "path"; import { fileURLToPath } from "url"; @@ -27,127 +31,83 @@ const __dirname = dirname(__filename); const rootDir = join(__dirname, ".."); const distDir = join(rootDir, "dist"); const cjsDir = join(distDir, "cjs"); - -console.log("\n📦 Building CJS wrappers...\n"); - -// Ensure CJS directory exists -if (!existsSync(cjsDir)) { - mkdirSync(cjsDir, { recursive: true }); -} - -// Create CJS loader that dynamically imports ESM -const loaderContent = `/** - * CommonJS loader for @cldmv/jsonv - * Dynamically imports ESM modules - */ - -module.exports = (async () => { - const esm = await import('../index.mjs'); - return esm; -})(); -`; - -const loaderFile = join(cjsDir, "loader.cjs"); -writeFileSync(loaderFile, loaderContent, "utf8"); -console.log(`✓ Created CJS loader → ${loaderFile}`); - -// Create main CJS entry point -const indexContent = `/** - * CommonJS entry point for @cldmv/jsonv - */ - -const loader = require('./loader.cjs'); - -module.exports = loader; -`; - -const indexFile = join(cjsDir, "index.cjs"); -writeFileSync(indexFile, indexContent, "utf8"); -console.log(`✓ Created CJS index → ${indexFile}`); - -// Prepare CJS types directory -const cjsTypesDir = join(distDir, "types", "cjs"); -if (!existsSync(cjsTypesDir)) { - mkdirSync(cjsTypesDir, { recursive: true }); -} - -// Create CJS wrappers for year modules const cjsYearsDir = join(cjsDir, "years"); +const cjsTypesDir = join(distDir, "types", "cjs"); const cjsYearsTypesDir = join(cjsTypesDir, "years"); -if (!existsSync(cjsYearsDir)) { - mkdirSync(cjsYearsDir, { recursive: true }); -} -if (!existsSync(cjsYearsTypesDir)) { - mkdirSync(cjsYearsTypesDir, { recursive: true }); -} +console.log("\n📦 Building CJS wrappers...\n"); -// Get all year .mjs files from dist/years/ -const distYearsDir = join(distDir, "years"); -const yearFiles = readdirSync(distYearsDir) - .filter((f) => f.match(/^\d{4}\.mjs$/)) - .map((f) => parseInt(f.replace(".mjs", ""))); +// Start from a clean dist/cjs so a wrapper removed here (e.g. the old async loader.cjs) +// never lingers from an earlier build. +rmSync(cjsDir, { recursive: true, force: true }); +mkdirSync(cjsYearsDir, { recursive: true }); +mkdirSync(cjsYearsTypesDir, { recursive: true }); -for (const year of yearFiles) { - const yearCjsContent = `/** - * CommonJS wrapper for @cldmv/jsonv/${year} +/** + * Source of a CJS wrapper that synchronously requires an ESM file. + * @param {string} specifier - Package specifier the wrapper stands for (for the comment and error message). + * @param {string} esmPath - Path of the ESM file, relative to the wrapper. + * @returns {string} The wrapper source. */ - -const loader = (async () => { - const esm = await import('../../years/${year}.mjs'); - return esm; -})(); - -module.exports = loader; -`; - - const yearFile = join(cjsYearsDir, `${year}.cjs`); - writeFileSync(yearFile, yearCjsContent, "utf8"); +function wrapper(specifier, esmPath) { + return `/** + * CommonJS entry for ${specifier} + */ +"use strict"; + +// A thin wrapper: it loads the ESM build through Node's synchronous require(esm), so +// require() returns the same module namespace object as import. Node.js versions without +// require(esm) would fail with a bare ERR_REQUIRE_ESM, so fail early with a message that +// says what to do instead. +if (!process.features?.require_module) { + const error = new Error( + \`@cldmv/jsonv: require() needs Node.js ^20.19.0 or >=22.12.0 (this is \${process.version}). On older Node.js, load the package with import() instead.\` + ); + error.code = "ERR_REQUIRE_ESM"; + throw error; } -console.log(`✓ Created ${yearFiles.length} CJS year modules`); -// Generate CJS type declarations for all years -for (const year of yearFiles) { - const yearDts = `export * from '../../years/${year}.mjs'; -import jsonv from '../../years/${year}.mjs'; -export default jsonv; +module.exports = require("${esmPath}"); `; - writeFileSync(join(cjsYearsTypesDir, `${year}.d.cts`), yearDts, "utf8"); } -console.log(`✓ Created ${yearFiles.length} CJS year types`); -// Create CJS loader utility -const loaderCjsContent = `/** - * CommonJS wrapper for @cldmv/jsonv/loader - */ +// Main CJS entry point +writeFileSync(join(cjsDir, "index.cjs"), wrapper("@cldmv/jsonv", "../index.mjs"), "utf8"); +console.log("✓ Created CJS index → dist/cjs/index.cjs"); -const loader = (async () => { - const esm = await import('../../years/loader.mjs'); - return esm; -})(); +// CJS wrappers for every module under dist/years/: the year modules plus the +// loader and year-resolver utilities, all reachable through the "./*" export. +const yearModules = readdirSync(join(distDir, "years")) + .filter((f) => f.endsWith(".mjs")) + .map((f) => f.slice(0, -".mjs".length)); -module.exports = loader; -`; - -const loaderYearFile = join(cjsYearsDir, "loader.cjs"); -writeFileSync(loaderYearFile, loaderCjsContent, "utf8"); -console.log(`✓ Created CJS loader → dist/cjs/years/loader.cjs`); +for (const name of yearModules) { + writeFileSync(join(cjsYearsDir, `${name}.cjs`), wrapper(`@cldmv/jsonv/${name}`, `../../years/${name}.mjs`), "utf8"); +} +console.log(`✓ Created ${yearModules.length} CJS year/utility wrappers → dist/cjs/years/`); -// Create .d.cts type declarations for CJS modules +// CJS type declarations. require(esm) returns the ESM namespace, so the +// declarations re-export the ESM types (default export included when present). console.log("\n📝 Generating CJS type declarations...\n"); -// Main index.d.cts const indexDts = `export * from '../index.mjs'; import jsonv from '../index.mjs'; export default jsonv; `; writeFileSync(join(cjsTypesDir, "index.d.cts"), indexDts, "utf8"); -console.log(`✓ Created CJS types → dist/types/cjs/index.d.cts`); +console.log("✓ Created CJS types → dist/types/cjs/index.d.cts"); -// Loader type -const loaderDts = `export * from '../../years/loader.mjs'; +for (const name of yearModules) { + const hasDefault = /^\d{4}$/.test(name); + const dts = hasDefault + ? `export * from '../../years/${name}.mjs'; +import jsonv from '../../years/${name}.mjs'; +export default jsonv; +` + : `export * from '../../years/${name}.mjs'; `; -writeFileSync(join(cjsYearsTypesDir, "loader.d.cts"), loaderDts, "utf8"); -console.log(`✓ Created CJS loader types → dist/types/cjs/years/loader.d.cts`); + writeFileSync(join(cjsYearsTypesDir, `${name}.d.cts`), dts, "utf8"); +} +console.log(`✓ Created ${yearModules.length} CJS year/utility types → dist/types/cjs/years/`); console.log("\n✅ CJS wrappers built successfully\n"); diff --git a/tests/cjs/entry.test.cjs b/tests/cjs/entry.test.cjs new file mode 100644 index 0000000..dca6d4b --- /dev/null +++ b/tests/cjs/entry.test.cjs @@ -0,0 +1,80 @@ +/** + * + * @Project: @cldmv/jsonv + * @Filename: /tests/cjs/entry.test.cjs + * @Date: 2026-10-03T10:28:33-07:00 (1791048513) + * @Author: Nate Corcoran + * @Email: + * ----- + * @Last modified by: Nate Corcoran (Shinrai@users.noreply.github.com) + * @Last modified time: 2026-10-03T10:29:28-07:00 (1791048568) + * ----- + * @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. + * + */ + +/** + * CommonJS entry tests. These run under Node's own test runner (`node --test`), not Vitest: + * Vitest loads files through its own module runner, so it cannot show whether a plain + * `require()` of the built package works the way it does for a CommonJS consumer. + * They test the built dist/ output, so `npm run test:cjs` builds first. + */ +"use strict"; + +const { test } = require("node:test"); +const assert = require("node:assert/strict"); +const { spawnSync } = require("node:child_process"); +const path = require("node:path"); + +const repoRoot = path.resolve(__dirname, "../.."); + +/** + * Assert that a require() result exposes exactly the ESM module's exports. Node's require(esm) + * returns the namespace itself, or - for a module with a default export - an object carrying + * the same bindings plus `__esModule: true` for bundler interop, so compare member by member. + * @param {object} required - What require() returned. + * @param {object} esm - The namespace import() returned. + */ +function assertSameExports(required, esm) { + assert.ok(Object.keys(esm).length > 0); + for (const key of Object.keys(esm)) { + assert.equal(required[key], esm[key], `export "${key}" differs`); + } + const extra = Object.keys(required).filter((key) => !(key in esm)); + assert.deepEqual( + extra.filter((key) => key !== "__esModule"), + [] + ); +} + +test("require() of the CJS entry returns the same namespace as import", async () => { + const required = require("../../dist/cjs/index.cjs"); + const esm = await import("../../dist/index.mjs"); + + assert.equal(typeof required.then, "undefined", "require() must not return a Promise"); + assertSameExports(required, esm); + assert.deepEqual(required.parse('{"a":1}'), { a: 1 }); +}); + +test("require() of a year wrapper returns the same namespace as import", async () => { + const required = require("../../dist/cjs/years/2021.cjs"); + const esm = await import("../../dist/years/2021.mjs"); + + assert.equal(typeof required.then, "undefined", "require() must not return a Promise"); + assertSameExports(required, esm); + assert.deepEqual(required.parse("{ value: 1_000 }"), { value: 1000 }); +}); + +test("require() fails with a clear message where Node.js has no require(esm)", () => { + // --no-experimental-require-module turns require(esm) off, which is what Node.js + // versions before 20.19 / 22.12 look like to the entry. + const res = spawnSync(process.execPath, ["--no-experimental-require-module", "-e", "require('./dist/cjs/index.cjs')"], { + cwd: repoRoot, + encoding: "utf8" + }); + + assert.notEqual(res.status, 0); + assert.match(res.stderr, /ERR_REQUIRE_ESM/); + assert.match(res.stderr, /require\(\) needs Node\.js \^20\.19\.0 or >=22\.12\.0/); + assert.match(res.stderr, /import\(\)/); +}); From b0e625bd41cdc6ec5b58f1605f43af31be6bb04b Mon Sep 17 00:00:00 2001 From: "cldmv-bot[bot]" <230771808+cldmv-bot[bot]@users.noreply.github.com> Date: Sat, 3 Oct 2026 18:13:57 +0000 Subject: [PATCH 05/12] chore: bump version to 1.1.4 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2c5a1e7..94e3215 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cldmv/jsonv", - "version": "1.1.3", + "version": "1.1.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cldmv/jsonv", - "version": "1.1.3", + "version": "1.1.4", "license": "Apache-2.0", "devDependencies": { "@cldmv/configs": "^1.2.0", diff --git a/package.json b/package.json index 44cc587..9e7a67c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cldmv/jsonv", - "version": "1.1.3", + "version": "1.1.4", "description": "Modern JSON parser extending JSON5 with ES2015-2025 features, year-based API", "type": "module", "main": "./dist/cjs/index.cjs", From 8efb572e4cfdb0c3b9e66a96b180f9b4a9f3ddb4 Mon Sep 17 00:00:00 2001 From: Shinrai Date: Sat, 3 Oct 2026 16:56:06 -0700 Subject: [PATCH 06/12] docs(changelog): backfill release notes for v1.0.0 through v1.1.3 Adds a per-version changelog under docs/changelog/v1/ for every shipped release that had none (v1.0.0-v1.0.10, v1.1.0, v1.1.2, v1.1.3), written from each release's diff against the previous one. v1.0.3-v1.0.6 were released on GitHub only and never published to npm; v1.0.4 has no tag. --- docs/changelog/v1/v1.0.0.md | 67 ++++++++++++++++++++++++++++++ docs/changelog/v1/v1.0.1.md | 40 ++++++++++++++++++ docs/changelog/v1/v1.0.10.md | 68 +++++++++++++++++++++++++++++++ docs/changelog/v1/v1.0.2.md | 28 +++++++++++++ docs/changelog/v1/v1.0.3.md | 31 ++++++++++++++ docs/changelog/v1/v1.0.4.md | 30 ++++++++++++++ docs/changelog/v1/v1.0.5.md | 31 ++++++++++++++ docs/changelog/v1/v1.0.6.md | 30 ++++++++++++++ docs/changelog/v1/v1.0.7.md | 53 ++++++++++++++++++++++++ docs/changelog/v1/v1.0.8.md | 23 +++++++++++ docs/changelog/v1/v1.0.9.md | 23 +++++++++++ docs/changelog/v1/v1.1.0.md | 79 ++++++++++++++++++++++++++++++++++++ docs/changelog/v1/v1.1.2.md | 36 ++++++++++++++++ docs/changelog/v1/v1.1.3.md | 34 ++++++++++++++++ 14 files changed, 573 insertions(+) create mode 100644 docs/changelog/v1/v1.0.0.md create mode 100644 docs/changelog/v1/v1.0.1.md create mode 100644 docs/changelog/v1/v1.0.10.md create mode 100644 docs/changelog/v1/v1.0.2.md create mode 100644 docs/changelog/v1/v1.0.3.md create mode 100644 docs/changelog/v1/v1.0.4.md create mode 100644 docs/changelog/v1/v1.0.5.md create mode 100644 docs/changelog/v1/v1.0.6.md create mode 100644 docs/changelog/v1/v1.0.7.md create mode 100644 docs/changelog/v1/v1.0.8.md create mode 100644 docs/changelog/v1/v1.0.9.md create mode 100644 docs/changelog/v1/v1.1.0.md create mode 100644 docs/changelog/v1/v1.1.2.md create mode 100644 docs/changelog/v1/v1.1.3.md diff --git a/docs/changelog/v1/v1.0.0.md b/docs/changelog/v1/v1.0.0.md new file mode 100644 index 0000000..452530f --- /dev/null +++ b/docs/changelog/v1/v1.0.0.md @@ -0,0 +1,67 @@ +# @cldmv/jsonv v1.0.0 Changelog + +**Release Date**: January 2026 +**Release Type**: Major (initial release) + +--- + +## Overview + +Version 1.0.0 is the first public release of `@cldmv/jsonv`, a hand-written, zero-dependency parser and serializer for **jsonv**: JSON5 extended with modern ECMAScript literals, internal references, and template interpolation, with features gated by ECMAScript year. jsonv is a static data format — it forbids executable syntax (no functions, classes, computed keys, or shorthand properties). + +--- + +## ✨ Features + +### JSON5 superset parser + +`parse()` and `parseWithOptions()` accept everything JSON5 does (comments, trailing commas, single-quoted strings, unquoted keys, hex numbers) plus modern literals: binary and octal integers, BigInt (`9007199254740992n`), and numeric separators (`1_000_000`). `parse()` is signature-compatible with `JSON.parse(text, reviver)`. + +`parseWithOptions()` takes a `ParseOptions` object: + +- `year` — 2011 through 2025; defaults to the latest. +- `mode` — `"jsonv"`, `"json5"`, or `"json"`. +- `allowInternalReferences` — defaults to `true`. +- `strictBigInt` — require the `n` suffix for unsafe integers (default `false`). +- `strictOctal` — require `0o` and reject legacy `0755` (default `false`). +- `tolerant` — collect multiple errors instead of stopping at the first. +- `preserveComments` — keep comment nodes in results. + +### Internal references and template interpolation + +Values can refer to earlier or later keys in the same document, and template literals can interpolate them: + +```jsonv +{ port: 8080, backup: port, url: `http://${host}:${port}` } +``` + +References are file-scoped only, forward references are supported, and circular references are rejected. + +### Year-pinned APIs + +Each ECMAScript year gates a feature set, exposed as its own entry point: `@cldmv/jsonv/2011` (JSON5 base), `@cldmv/jsonv/2015` (binary/octal literals and templates), `@cldmv/jsonv/2020` (BigInt), and `@cldmv/jsonv/2021` (numeric separators). Years 2022–2025 resolve to the 2021 module. `@cldmv/jsonv/loader` provides `loadYear()` and `getLoadedYear()` for dynamic loading, and `@cldmv/jsonv/year-resolver` provides `resolveYear()`, `isPublishedYear()`, and `getPublishedYears()`. + +### Stringify + +`stringify()` follows the `JSON.stringify(value, replacer, space)` signature; `stringifyWithOptions()` adds `mode` (`"jsonv"`, `"json5"`, `"json"`), a `bigint` strategy (`"native"`, `"string"`, `"object"`), `singleQuote`, `trailingComma`, `unquotedKeys`, and `preserveNumericFormatting`. `rawJSON()` and `isRawJSON()` implement raw-JSON passthrough compatible with the modern `JSON.rawJSON` API. + +### Diagnostics + +`diagnose()` reports the detected minimum year and features of a document plus `json` / `json5` compatibility flags. `info()` returns only the detected year and the parsed value. + +### Packaging + +Dual ESM/CJS build (the CommonJS entry exports a Promise of the ESM module, so CommonJS callers `await require("@cldmv/jsonv")`; v1.1.4 made it synchronous) with a `json-dev` export condition that resolves to `src/` for in-repo development, `.d.mts` type declarations, and a test suite with per-year `features/` and `violations/` fixtures run through Vitest. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.0.0.md](./v1.0.0.md) — this changelog. +- README, plus `docs/feature-matrix.md`, `docs/versioning-and-exports.md`, and `docs/json5-compatibility.md`. + +--- + +## Upgrade notes + +Initial release — nothing to migrate. Install with `npm install @cldmv/jsonv`. diff --git a/docs/changelog/v1/v1.0.1.md b/docs/changelog/v1/v1.0.1.md new file mode 100644 index 0000000..4d4b4b3 --- /dev/null +++ b/docs/changelog/v1/v1.0.1.md @@ -0,0 +1,40 @@ +# @cldmv/jsonv v1.0.1 Changelog + +**Release Date**: April 2026 +**Release Type**: Patch + +--- + +## Overview + +Version 1.0.1 fixes incorrect token start positions in the lexer for block comments and template literal tokens, and makes the parser skip comments that precede the root value. It also declares public publish access in `package.json`. + +--- + +## 🐛 Bug Fixes + +### Correct token start positions for block comments and templates + +The lexer derived every token's start position by subtracting the raw text length from the end position. That is wrong for tokens that span lines — a multi-line block comment or template literal reported a start line, column, and offset that did not match where the token actually began. `createToken` now accepts an explicit start position, and the block-comment, `TemplateHead`, template-literal, `TemplateMiddle`, and `TemplateTail` scanners record the real start line, column, and offset before consuming the token. + +### Parser skips leading comments before the root value + +A document that began with a comment before its root value could fail to parse, because the parser went straight to the root value without consuming comment tokens first. The parser now skips leading comments before parsing the root value. + +--- + +## 🔧 CI & tooling + +- `package.json` gains `publishConfig.access: "public"` so the scoped package publishes publicly (introduced in the preceding "Update package privacy" commit and first shipped in this release). + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.0.1.md](./v1.0.1.md) — this changelog. + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.0.0. Code that read token `loc`/offset values for multi-line block comments or templates will now see the corrected positions. diff --git a/docs/changelog/v1/v1.0.10.md b/docs/changelog/v1/v1.0.10.md new file mode 100644 index 0000000..e89f91d --- /dev/null +++ b/docs/changelog/v1/v1.0.10.md @@ -0,0 +1,68 @@ +# @cldmv/jsonv v1.0.10 Changelog + +**Release Date**: September 2026 +**Release Type**: Patch + +--- + +## Overview + +Version 1.0.10 gives parse errors a structured position. Every parse failure now throws `JsonvSyntaxError`, a `SyntaxError` subclass that carries `line`, `column`, `offset`, `code` and the full `loc` as properties, so tooling no longer has to pull the position out of the message text. + +The release also moves the test suite onto the `@cldmv/vitest-runner` harness with coverage reporting, syncs the v4 workflows with the `CLDMV/.github` v4.29.0 templates, and restores the verbatim Apache-2.0 license text. `name` stays `"SyntaxError"` and the message text is unchanged, so existing error handling keeps working. + +--- + +## 🐛 Bug Fixes + +### Parse errors expose `line`, `column` and `offset` ([#31](https://github.com/CLDMV/jsonv/pull/31)) + +Parse failures used to throw a plain `SyntaxError` whose only position information was the `at line X, column Y` suffix in the message. They now throw `JsonvSyntaxError` (new in `src/errors.mts`), exported from the package root and from the `@cldmv/jsonv/parser` subpath. It exposes: + +- `line` — 1-based line, matching the line in the message; +- `column` — the same column number the message reports; +- `offset` — 0-based character offset into the source; +- `code` — a machine-readable code such as `"PARSE_ERROR"` or `"UNTERMINATED_STRING"`; +- `loc` — the full start/end source location. + +This applies to every parse entry point, year-pinned APIs included, and to both lexer-level errors (unterminated strings, invalid escapes, year-gated features) and parser-level errors (unexpected tokens, strict-mode violations). Because `JsonvSyntaxError` extends `SyntaxError` and keeps `name === "SyntaxError"`, `instanceof SyntaxError` and `error.name` checks are unaffected. + +```js +import { parse, JsonvSyntaxError } from "@cldmv/jsonv"; + +try { + parse("{ a: 1, }"); +} catch (err) { + if (err instanceof JsonvSyntaxError) { + console.log(err.line, err.column, err.offset); + } +} +``` + +--- + +## 🔧 CI & tooling + +- **Test suite moved onto `@cldmv/vitest-runner`** ([#27](https://github.com/CLDMV/jsonv/pull/27)) — `npm test` now runs `tests/run-vitest.mjs`, test files were renamed from `*.test.ts` to `*.test.vitest.mjs` (TypeScript-only syntax stripped), and new `coverage`, `ci:coverage`, `test:types` and `build:ci` scripts were added. CI builds with `build:ci` in the publish and release workflows and turns on the coverage badge, the PR coverage comment and the type check. +- **v4 workflows synced with `CLDMV/.github` v4.29.0 templates** ([#26](https://github.com/CLDMV/jsonv/pull/26)), including corrected workflow header metadata and the new `provenance.yml` and `release-merge.yml` callers. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.0.10.md](./v1.0.10.md) — this changelog. +- README — new **Errors** section documenting `JsonvSyntaxError` and its position properties. +- LICENSE — restored to the verbatim Apache-2.0 text ([#25](https://github.com/CLDMV/jsonv/pull/25)). + +--- + +## 🔧 Dependencies + +- Added `@cldmv/vitest-runner` ^1.4.3 (dev). +- `vitest` and `@vitest/coverage-v8` ^5.0.0 → ^5.0.2 (dev). + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.0.9. Errors keep their `SyntaxError` type, `name` and message text; code that parsed the position out of the message can switch to `err.line`, `err.column` and `err.offset`. diff --git a/docs/changelog/v1/v1.0.2.md b/docs/changelog/v1/v1.0.2.md new file mode 100644 index 0000000..aa69d0e --- /dev/null +++ b/docs/changelog/v1/v1.0.2.md @@ -0,0 +1,28 @@ +# @cldmv/jsonv v1.0.2 Changelog + +**Release Date**: April 2026 +**Release Type**: Patch + +--- + +## Overview + +Version 1.0.2 is a build-script-only patch. No runtime code changed. + +--- + +## 🔧 CI & tooling + +- The `build` script no longer runs `build:plugin`. The published package is built from `clean`, `build:ts`, `build:types`, `generate:years`, and `build:cjs`; `build:plugin` remains available as its own script. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.0.2.md](./v1.0.2.md) — this changelog. + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.0.1. diff --git a/docs/changelog/v1/v1.0.3.md b/docs/changelog/v1/v1.0.3.md new file mode 100644 index 0000000..55a7a55 --- /dev/null +++ b/docs/changelog/v1/v1.0.3.md @@ -0,0 +1,31 @@ +# @cldmv/jsonv v1.0.3 Changelog + +**Release Date**: July 2026 +**Release Type**: Patch + +--- + +## Overview + +Version 1.0.3 moves the repository's CI and release automation onto the `CLDMV/.github` v4 staging-branch workflows ([#2](https://github.com/CLDMV/jsonv/pull/2)). This version was tagged and released on GitHub but not published to npm; v1.0.2 remained the latest npm version until v1.0.7. + +No runtime code changed. + +--- + +## 🔧 CI & tooling + +- **v4 workflow set adopted.** Added the `next` / `hotfixes` release-flow workflows (`feature-pr.yml`, `next-release.yml`, `hotfixes-release.yml`, `next-reset.yml`, `hotfix-redirector.yml`, `pr-title-normalizer.yml`, `master-commit-audit.yml`, `tag-health.yml`, `release-notify.yml`), plus `codeql.yml`, `scorecard.yml`, `dependency-review.yml`, `dependabot-auto-merge.yml`, `labeler.yml`, `stale.yml`, `welcome.yml`, `v4-bootstrap.yml`, and top-level `publish.yml` and `update-major-version-tags.yml`. +- **Removed the misplaced `.github/workflows/workflows/` directory** (stale `ci.yml`, `publish.yml`, `release.yml`, and `update-major-version-tags.yml` copies that GitHub never ran). + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.0.3.md](./v1.0.3.md) — this changelog. + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.0.2. diff --git a/docs/changelog/v1/v1.0.4.md b/docs/changelog/v1/v1.0.4.md new file mode 100644 index 0000000..6c9dd92 --- /dev/null +++ b/docs/changelog/v1/v1.0.4.md @@ -0,0 +1,30 @@ +# @cldmv/jsonv v1.0.4 Changelog + +**Release Date**: August 2026 +**Release Type**: Patch + +--- + +## Overview + +Version 1.0.4 changes the CI concurrency policy so release-relevant runs are never cancelled ([#4](https://github.com/CLDMV/jsonv/pull/4)). This version was released on GitHub but has no git tag and was not published to npm. + +No runtime code changed. + +--- + +## 🔧 CI & tooling + +- **Never-supersede concurrency for release contexts.** `ci.yml` previously cancelled in-progress runs on every ref except `master`/`main`. Pushes to the release base branch (derived from the `CLDMV_RELEASE_BASE` variable, falling back to the repository's default branch), pushes to `next` / `hotfixes`, and the `next` / `hotfixes` release PRs now each get a unique concurrency group per run (`run_id` appended), so every run completes and posts its check instead of being cancelled into a red X on the release PR. Feature branches and feature PRs still cancel superseded runs. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.0.4.md](./v1.0.4.md) — this changelog. + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.0.3. diff --git a/docs/changelog/v1/v1.0.5.md b/docs/changelog/v1/v1.0.5.md new file mode 100644 index 0000000..326ad26 --- /dev/null +++ b/docs/changelog/v1/v1.0.5.md @@ -0,0 +1,31 @@ +# @cldmv/jsonv v1.0.5 Changelog + +**Release Date**: August 2026 +**Release Type**: Patch + +--- + +## Overview + +Version 1.0.5 replaces the inlined release and feature-PR workflow logic with thin callers of the `CLDMV/.github` v4 reusable workflows ([#6](https://github.com/CLDMV/jsonv/pull/6)). This version was tagged and released on GitHub but not published to npm. + +No runtime code changed. + +--- + +## 🔧 CI & tooling + +- **`feature-pr.yml`, `next-release.yml`, and `hotfixes-release.yml` reduced to thin callers** pinned at `@v4`; target detection, changelog body generation, and PR creation/refresh now live in the reusable workflows (about 500 fewer lines across the three files). +- **`deps/**` branches** now auto-open a PR into `next`, matching the current branch-naming convention. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.0.5.md](./v1.0.5.md) — this changelog. + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.0.4. diff --git a/docs/changelog/v1/v1.0.6.md b/docs/changelog/v1/v1.0.6.md new file mode 100644 index 0000000..c1ed3fe --- /dev/null +++ b/docs/changelog/v1/v1.0.6.md @@ -0,0 +1,30 @@ +# @cldmv/jsonv v1.0.6 Changelog + +**Release Date**: September 2026 +**Release Type**: Patch + +--- + +## Overview + +Version 1.0.6 moves the hotfix redirector onto the v4 reusable workflow, which signs the security-fix cherry-pick ([#8](https://github.com/CLDMV/jsonv/pull/8)). This version was tagged and released on GitHub but not published to npm. + +No runtime code changed. + +--- + +## 🔧 CI & tooling + +- **`hotfix-redirector.yml` is now a thin caller** of `workflow-hotfix-redirector.yml@v4`. The reusable checks out `hotfixes` (a trusted base-repo branch, never the PR head) and cherry-picks the fix there with the bot's signing identity, passing the bot app and `BOT_NAME` / `BOT_EMAIL` secrets through. The inline App-token and `redirect-hotfix-pr` steps are removed. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.0.6.md](./v1.0.6.md) — this changelog. + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.0.5. diff --git a/docs/changelog/v1/v1.0.7.md b/docs/changelog/v1/v1.0.7.md new file mode 100644 index 0000000..5dc23d7 --- /dev/null +++ b/docs/changelog/v1/v1.0.7.md @@ -0,0 +1,53 @@ +# @cldmv/jsonv v1.0.7 Changelog + +**Release Date**: September 2026 +**Release Type**: Patch + +--- + +## Overview + +Version 1.0.7 fixes the development toolchain so it installs cleanly with Vitest 5 and uses the published ESLint plugin instead of a local checkout ([#14](https://github.com/CLDMV/jsonv/pull/14)). It is the first version published to npm since v1.0.2 (v1.0.3 through v1.0.6 were released on GitHub only). + +No behavior of the published package changed; the only `src/` edit renames an unused `catch` binding. + +--- + +## 🐛 Bug Fixes + +### Dev install resolves with Vitest 5 + +`vitest` and `@vitest/coverage-v8` are bumped to `^5.0.0`, resolving the peer-dependency `ERESOLVE` on install. The unused `CustomReporter` (a `DefaultReporter` subclass imported from `vitest/reporters`, already commented out of the config) is removed from `.configs/vitest.config.mjs`. + +### ESLint uses the published plugin + +Both ESLint configs imported the plugin from a sibling `plugins/eslint-plugin-jsonv/dist/` checkout that does not exist in CI or fresh clones. They now import `@cldmv/eslint-plugin-jsonv`, added as a devDependency (`^1.0.3`). `plugins/` is gitignored for local co-development. + +--- + +## 🔧 CI & tooling + +- CI and publish workflows default the matrix floor (`min_node_version`) to `22.12.0`, the lowest Node release Vitest 5 runs on, and the ceiling (`max_node_major`) to `26`. +- `src/diagnose.mts`: the unused `catch (error)` binding is renamed `catch (_)` to satisfy lint. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.0.7.md](./v1.0.7.md) — this changelog. +- README — Tooling section now points to the separately published `@cldmv/eslint-plugin-jsonv` and `jsonv-vscode` repositories and describes local co-development under the gitignored `plugins/` folder. + +--- + +## 🔧 Dependencies + +- `vitest` ^4.0.17 → ^5.0.0 +- `@vitest/coverage-v8` ^4.0.17 → ^5.0.0 +- `@types/node` ^20.19.29 → ^26.5.1 +- `@cldmv/eslint-plugin-jsonv` ^1.0.3 (new devDependency) + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.0.2. All dependency changes are dev-only. diff --git a/docs/changelog/v1/v1.0.8.md b/docs/changelog/v1/v1.0.8.md new file mode 100644 index 0000000..458786d --- /dev/null +++ b/docs/changelog/v1/v1.0.8.md @@ -0,0 +1,23 @@ +# @cldmv/jsonv v1.0.8 Changelog + +**Release Date**: September 2026 +**Release Type**: Patch + +--- + +## Overview + +Version 1.0.8 is a README-only release that adds a badge row, a contributors and sponsor line, and license badges ([#22](https://github.com/CLDMV/jsonv/pull/22)). No runtime code changed. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.0.8.md](./v1.0.8.md) — this changelog. +- README — badge row (npm version, npm downloads, GitHub downloads, last commit, npm last update), contributors and sponsor badges, and a License section with GitHub and npm license badges and a `Apache-2.0 © Shinrai / CLDMV` line. + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.0.7. diff --git a/docs/changelog/v1/v1.0.9.md b/docs/changelog/v1/v1.0.9.md new file mode 100644 index 0000000..e325f20 --- /dev/null +++ b/docs/changelog/v1/v1.0.9.md @@ -0,0 +1,23 @@ +# @cldmv/jsonv v1.0.9 Changelog + +**Release Date**: September 2026 +**Release Type**: Patch + +--- + +## Overview + +Version 1.0.9 is a one-line README follow-up to v1.0.8 ([#24](https://github.com/CLDMV/jsonv/pull/24)). No runtime code changed. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.0.9.md](./v1.0.9.md) — this changelog. +- README — Tooling section lists the separately published [`@cldmv/prettier-plugin-jsonv`](https://github.com/CLDMV/jsonv-prettier-plugin-jsonv) for formatting `.jsonv` files. + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.0.8. diff --git a/docs/changelog/v1/v1.1.0.md b/docs/changelog/v1/v1.1.0.md new file mode 100644 index 0000000..c5aad6e --- /dev/null +++ b/docs/changelog/v1/v1.1.0.md @@ -0,0 +1,79 @@ +# @cldmv/jsonv v1.1.0 Changelog + +**Release Date**: September 2026 +**Release Type**: Minor + +--- + +## Overview + +Version 1.1.0 opens the parser up to tooling. A new `parseToAst()` returns the positioned AST together with every comment and token, property keys become positioned nodes, and every node's span slices back to its exact source text. This is the surface `@cldmv/eslint-plugin-jsonv` and other editors and formatters build on. + +Internal-reference failures also gain a position: an unresolved or circular reference now throws `JsonvReferenceError` with the same `line` / `column` / `offset` / `code` shape that v1.0.10 gave syntax errors. The lint toolchain moves to ESLint 10 and TypeScript 6. + +--- + +## ✨ Features + +### `parseToAst()`: comments, tokens, positioned keys and corrected spans ([#39](https://github.com/CLDMV/jsonv/pull/39)) + +`parseToAst(text, options?)`, exported from the package root and from `@cldmv/jsonv/parser`, returns `{ program, comments, tokens, errors }` without evaluating the document. Every list is always present: + +- `comments` — every `Line` / `Block` comment in source order, with `value` (text without delimiters) and `loc`. Comments are now allowed between any two tokens, including between a key and its colon and inside template interpolations. +- `tokens` — every non-comment token in source order (EOF excluded), each `{ type, value, raw, loc }`. +- `errors` — collected parse errors; `[]` for clean input. With `tolerant: true` the parser recovers and keeps going. + +Every node, token and comment carries `loc: { start, end }` with `{ line, column, offset }` positions, and `text.slice(loc.start.offset, loc.end.offset)` is exactly the node's source. `\n`, `\r\n` (one break), a lone `\r`, U+2028 and U+2029 each count as one line break. `Program.loc` spans the whole input and `Property.loc` spans the key through the value. The AST node types (`Program`, `Property`, `PropertyKeyNode`, `TemplateLiteral`, `AstResult`, `Token` and the rest) are exported as TypeScript types. The lower-level `Parser#parse()` result gains a `tokens` list, and returns `comments` when `preserveComments` is set. + +See the new [docs/ast.md](https://github.com/CLDMV/jsonv/blob/master/docs/ast.md) for the node reference. + +--- + +## 🐛 Bug Fixes + +### Reference-resolution errors carry a position ([#38](https://github.com/CLDMV/jsonv/pull/38)) + +An unresolved or circular internal reference used to throw without structured position information. It now throws `JsonvReferenceError` (extends `ReferenceError`, `name` stays `"ReferenceError"`), exported from the package root and from `@cldmv/jsonv/parser`, with `line`, `column`, `offset`, `loc` and `code` (for example `"UNRESOLVED_REFERENCE"`) pointing at the offending reference. + +--- + +## 💥 Breaking Changes + +### `Property.key` from `Parser#parse()` is a node, not a string + +This affects only code that walks the raw AST from the `@cldmv/jsonv/parser` subpath; `parse()`, `parseWithOptions()` and the evaluated values are unchanged. Before 1.1.0, `Property.key` was a plain string for unquoted, quoted and numeric keys. It is now a positioned `Literal` (quoted and numeric keys) or `Identifier` (unquoted keys, including keyword keys such as `true` and `NaN`). Despite the minor version, AST consumers need to update: + +```js +// before +const name = property.key; + +// after +const name = property.key.type === "Identifier" ? property.key.name : String(property.key.value); +``` + +Template middle and tail tokens also start after the `}` that closes the preceding interpolation in this release (v1.1.1 later moved that `}` into the following token). + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.1.0.md](./v1.1.0.md) — this changelog. +- **NEW:** [docs/ast.md](https://github.com/CLDMV/jsonv/blob/master/docs/ast.md) — AST, tokens, comments and positions for tooling. +- README — new **AST for tooling** section, `JsonvReferenceError` documented under **Errors**, and `preserveComments` described accurately. +- `docs/feature-matrix.md` — documents the accepted line terminators. + +--- + +## 🔧 Dependencies + +All development-only: + +- `eslint` ^9.39.2 → ^10.11.0, with the lint config's own imports `@eslint/js` and `globals` now declared ([#43](https://github.com/CLDMV/jsonv/pull/43)). +- `typescript` ^5.9.3 → ^6.0.3, with Dependabot held below TypeScript 7 until `typescript-eslint` supports it ([#42](https://github.com/CLDMV/jsonv/pull/42)). +- `@html-eslint/eslint-plugin` and `@html-eslint/parser` ^0.53.0 → ^0.66.1, plus patch and minor group updates ([#41](https://github.com/CLDMV/jsonv/pull/41), [#36](https://github.com/CLDMV/jsonv/pull/36)). + +--- + +## Upgrade notes + +Drop-in for v1.0.10 for anyone using `parse()`, `parseWithOptions()`, `stringify()` or the year-pinned APIs. Code that catches reference errors with `instanceof ReferenceError` keeps working; switch to `instanceof JsonvReferenceError` to read the position. Code that walks `Parser#parse()` output must handle `Property.key` as a node (see **Breaking Changes** above). diff --git a/docs/changelog/v1/v1.1.2.md b/docs/changelog/v1/v1.1.2.md new file mode 100644 index 0000000..691a5d9 --- /dev/null +++ b/docs/changelog/v1/v1.1.2.md @@ -0,0 +1,36 @@ +# @cldmv/jsonv v1.1.2 Changelog + +**Release Date**: October 2026 +**Release Type**: Patch + +--- + +## Overview + +Version 1.1.2 is a maintenance release with no runtime code changes. Source, script, test, fixture and workflow files get uniform CLDMV file headers from the shared `@cldmv/fix-headers` config, the CI required-check mirror is fixed so a skipped run can no longer satisfy the merge ruleset, and `@types/node` takes a patch bump. + +--- + +## 🔧 CI & tooling + +- **Skipped PR-run mirror no longer satisfies `✅ Required PR Check`** ([#75](https://github.com/CLDMV/jsonv/pull/75)) — on in-repo feature PRs the `pull_request` run skips the mirror job, and GitHub counts a skipped required check as passing, which could let a PR merge before its tests finished. The job name is now an expression, so the skipped job no longer posts under the required name. +- **Uniform file headers** ([#74](https://github.com/CLDMV/jsonv/pull/74)) — adopts the shared CLDMV `fix-headers` config (`.configs/fix-headers.json`, new `fix:headers` script) and stamps headers across `src/`, `scripts/`, `tests/`, fixtures and workflows. Only comment headers changed. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.1.2.md](./v1.1.2.md) — this changelog. + +--- + +## 🔧 Dependencies + +- `@types/node` 26.6.2 → 26.6.3 (dev; [#72](https://github.com/CLDMV/jsonv/pull/72)). +- Added `@cldmv/configs` and `@cldmv/fix-headers` (dev). + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.1.1. No runtime code changed. diff --git a/docs/changelog/v1/v1.1.3.md b/docs/changelog/v1/v1.1.3.md new file mode 100644 index 0000000..c01d4d8 --- /dev/null +++ b/docs/changelog/v1/v1.1.3.md @@ -0,0 +1,34 @@ +# @cldmv/jsonv v1.1.3 Changelog + +**Release Date**: October 2026 +**Release Type**: Patch + +--- + +## Overview + +Version 1.1.3 is a CI-only release with no runtime code changes. It corrects v1.1.2's required-check fix so in-repo PRs report their status from a job that actually runs, and bumps the ESLint plugin used by the lint config. + +--- + +## 🔧 CI & tooling + +- **In-repo PR mirror job runs instead of being skipped** ([#78](https://github.com/CLDMV/jsonv/pull/78)) — the `✅ Required PR Check` mirror now runs on the `pull_request` event for in-repo PRs and reports the CI result, rather than relying on a renamed skipped job. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.1.3.md](./v1.1.3.md) — this changelog. + +--- + +## 🔧 Dependencies + +- `@cldmv/eslint-plugin-jsonv` 1.0.10 → 1.0.13 (dev; [#76](https://github.com/CLDMV/jsonv/pull/76)). + +--- + +## Upgrade notes + +No breaking changes — drop-in for v1.1.2. No runtime code changed. From a5fb29322780491bdc37a43fef043ba1ebd72380 Mon Sep 17 00:00:00 2001 From: Shinrai Date: Sat, 3 Oct 2026 16:59:46 -0700 Subject: [PATCH 07/12] docs: add v1.1.4 release notes and restructure the README Adds docs/changelog/v1/v1.1.4.md for the pending release (#80: require() returns the API synchronously; #77 dev dependency bumps) and reorganizes the README to the CLDMV layout: intro, badges incl. coverage, What's New (v1.1.4 Latest plus four recent releases linking their changelog files), key features, installation with Node.js requirements, quick start, the existing API/errors/AST/reference sections, a documentation index, contributing, links and license. The quick-start example now escapes its inner template literal, and the build-step list no longer names the plugin step that build stopped running in v1.0.2. --- README.md | 177 +++++++++++++++++++++++++----------- docs/changelog/v1/v1.1.4.md | 65 +++++++++++++ 2 files changed, 191 insertions(+), 51 deletions(-) create mode 100644 docs/changelog/v1/v1.1.4.md diff --git a/README.md b/README.md index 422c8ad..e8e643b 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,36 @@ # @cldmv/jsonv -[![npm version]][npm_version_url] [![npm downloads]][npm_downloads_url] [![GitHub downloads]][github_downloads_url] [![Last commit]][last_commit_url] [![npm last update]][npm_last_update_url] +**@cldmv/jsonv** is a modern JSON parser and serializer that extends JSON5 with ES2015–2025 literals and year-pinned APIs. It is a **static data** format: JSON5 plus binary/octal literals, BigInt, numeric separators and template literals, with every feature gated by the ECMAScript year that introduced it. + +On top of the literal syntax, jsonv adds **internal references** — file-scoped values that refer to other keys in the same document, forward references included — while forbidding executable syntax: no functions, classes, computed keys or shorthand properties. The parser is hand-written and has zero runtime dependencies. + +> _JSON5 with modern literals and internal references, pinned to the ECMAScript year you choose._ + +[![npm version]][npm_version_url] [![npm downloads]][npm_downloads_url] [![GitHub downloads]][github_downloads_url] [![Last commit]][last_commit_url] [![npm last update]][npm_last_update_url] [![coverage]][coverage_url] [![Contributors]][contributors_url] [![Sponsor shinrai]][sponsor_url] -Modern JSON parser extending JSON5 with ES2015–2025 features and year‑pinned APIs. +--- ## ✨ What's New -### Latest: v1.1.1 (September 2026) +### Latest: v1.1.4 (October 2026) -- **Nine correctness fixes in the template-literal, tolerant-parsing, and reference-resolution paths** — `mode: "json"` / `mode: "json5"` now actually enforce their feature sets, tolerant mode reports the syntax errors it collects instead of a misleading reference error, forward-reference chains of any length resolve, and `parseToAst()` tokens/quasis tile the source with no gaps around template interpolations. -- [View full v1.1.1 Changelog](https://github.com/CLDMV/jsonv/blob/master/docs/changelog/v1/v1.1.1.md) +- **`require()` returns the API synchronously** — `require("@cldmv/jsonv")` and `require("@cldmv/jsonv/")` used to return a Promise of the ESM module; they now return the same exports as `import`, loaded through Node's `require(esm)`. Existing `await require(...)` code keeps working, but code that chained `.then()` on the `require()` result must use the result directly. CommonJS needs Node.js ^20.19.0 or >=22.12.0; older Node.js gets a clear `ERR_REQUIRE_ESM` pointing to `import()`. `@cldmv/jsonv/year-resolver` also gains the CommonJS wrapper it was missing (#80). +- [View full v1.1.4 Changelog](https://github.com/CLDMV/jsonv/blob/master/docs/changelog/v1/v1.1.4.md) ### Recent Releases -- **v1.1.0** (September 2026) — `parseToAst()` returns comments and tokens with positioned keys and corrected spans; reference-resolution errors now carry a position ([Release](https://github.com/CLDMV/jsonv/releases/tag/v1.1.0)) -- **v1.0.10** (September 2026) — parse errors expose `line`, `column`, and `offset` ([Release](https://github.com/CLDMV/jsonv/releases/tag/v1.0.10)) -- **v1.0.9** (September 2026) — README doc link for the Prettier plugin in the Tooling section ([Release](https://github.com/CLDMV/jsonv/releases/tag/v1.0.9)) -- **v1.0.8** (September 2026) — README badge row, contributors/sponsor line, and license badges ([Release](https://github.com/CLDMV/jsonv/releases/tag/v1.0.8)) +- **v1.1.3** (October 2026) — CI only: the in-repo PR mirror job runs instead of being skipped; `@cldmv/eslint-plugin-jsonv` dev bump ([Changelog](https://github.com/CLDMV/jsonv/blob/master/docs/changelog/v1/v1.1.3.md)) +- **v1.1.2** (October 2026) — maintenance: uniform file headers, required-check mirror fix, `@types/node` bump; no runtime change ([Changelog](https://github.com/CLDMV/jsonv/blob/master/docs/changelog/v1/v1.1.2.md)) +- **v1.1.1** (September 2026) — nine correctness fixes: `mode: "json"` / `"json5"` enforce their feature sets, tolerant mode reports collected syntax errors, forward-reference chains of any length resolve, and template tokens tile the source ([Changelog](https://github.com/CLDMV/jsonv/blob/master/docs/changelog/v1/v1.1.1.md)) +- **v1.1.0** (September 2026) — `parseToAst()` returns comments and tokens with positioned keys and corrected spans; reference errors carry a position ([Changelog](https://github.com/CLDMV/jsonv/blob/master/docs/changelog/v1/v1.1.0.md)) -## What it is +📚 **For complete version history and detailed release notes, see the [docs/changelog/](https://github.com/CLDMV/jsonv/tree/master/docs/changelog/) folder.** -@cldmv/jsonv is a **static data** format: JSON5 plus modern literals, with features gated by ECMAScript year modules. It adds **internal references** (file‑scoped, defined‑before‑use) and forbids executable syntax (no functions, classes, computed keys, or shorthand props). +--- -## Core features +## 🚀 Key Features - JSON5 superset (comments, trailing commas, single quotes, hex, etc.) - Year‑pinned APIs: `@cldmv/jsonv/2011`, `/2015`, `/2020`, `/2021` (2022–2025 re‑export 2021) @@ -33,15 +39,27 @@ Modern JSON parser extending JSON5 with ES2015–2025 features and year‑pinned - Diagnostics: `diagnose()` and `info()` for year + feature detection - Stringify with json/json5/jsonv modes, BigInt strategies, and raw JSON passthrough - Dynamic year loading and resolver utilities (`loadYear`, `resolveYear`) +- Positioned AST, tokens and comments for tooling (`parseToAst()`) - Zero dependencies, hand‑written parser -## Install +--- + +## 📦 Installation + +### Requirements + +- **Node.js 18 or higher** for ESM `import` (the package's `engines` floor). +- **`require()`** loads the ESM build through Node's `require(esm)`, so it needs **Node.js ^20.19.0 or >=22.12.0**. On older Node.js, load the package with `import()` instead. + +### Install ```bash npm install @cldmv/jsonv ``` -## Quick start +--- + +## 🚀 Quick Start ```js import { parse, stringify } from "@cldmv/jsonv"; @@ -49,7 +67,7 @@ import { parse, stringify } from "@cldmv/jsonv"; const config = parse(`{ port: 8080, host: "localhost", - url: `http://${host}:${port}`, + url: \`http://\${host}:\${port}\`, maxConnections: 1_000_000, bigValue: 9007199254740992n }`); @@ -57,7 +75,17 @@ const config = parse(`{ const text = stringify(config); ``` -## Year‑pinned API +CommonJS works the same way, synchronously: + +```js +const { parse } = require("@cldmv/jsonv"); + +parse("{ a: 1 }"); // { a: 1 } +``` + +--- + +## 📅 Year‑Pinned API Pin a year for stable grammar rules: @@ -67,18 +95,13 @@ import { parse as parse2015 } from "@cldmv/jsonv/2015"; // binary/octal + templa import { parse as parse2011 } from "@cldmv/jsonv/2011"; // JSON5 base ``` -See [docs/feature-matrix.md](docs/feature-matrix.md) and [docs/versioning-and-exports.md](docs/versioning-and-exports.md). - -## Docs +See [docs/feature-matrix.md](https://github.com/CLDMV/jsonv/blob/master/docs/feature-matrix.md) and [docs/versioning-and-exports.md](https://github.com/CLDMV/jsonv/blob/master/docs/versioning-and-exports.md). -- [docs/feature-matrix.md](docs/feature-matrix.md) -- [docs/versioning-and-exports.md](docs/versioning-and-exports.md) -- [docs/json5-compatibility.md](docs/json5-compatibility.md) -- [docs/ast.md](docs/ast.md) — AST, tokens and comments for tooling +--- -## API surface +## 🔧 API Surface -Main entry: [src/index.mts](src/index.mts) +Main entry: [src/index.mts](https://github.com/CLDMV/jsonv/blob/master/src/index.mts) ### Parse options (selected) @@ -87,8 +110,8 @@ Main entry: [src/index.mts](src/index.mts) - `allowInternalReferences`: default `true` - `strictBigInt`: require `n` for unsafe integers (default `false`) - `strictOctal`: require `0o` (reject legacy `0755`, default `false`) -- `tolerant`: collect every syntax error instead of stopping at the first; `parseWithOptions` then throws them together as one `JsonvAggregateSyntaxError` (see [Errors](#errors)) -- `preserveComments`: return comments (with positions) from `Parser#parse()`; see [AST for tooling](#ast-for-tooling) +- `tolerant`: collect every syntax error instead of stopping at the first; `parseWithOptions` then throws them together as one `JsonvAggregateSyntaxError` (see [Errors](#-errors)) +- `preserveComments`: return comments (with positions) from `Parser#parse()`; see [AST for tooling](#-ast-for-tooling) ### Parse modes @@ -102,7 +125,7 @@ parse("{ a: 1, }", { mode: "json" }); // throws: Unquoted keys not allowed in JS parse("{ a: 1, b: a }", { mode: "json5" }); // throws: Internal references not allowed in JSON5 mode at line 1, column 11 ``` -The full feature × mode table is in [docs/json5-compatibility.md](docs/json5-compatibility.md#compatibility-modes). +The full feature × mode table is in [docs/json5-compatibility.md](https://github.com/CLDMV/jsonv/blob/master/docs/json5-compatibility.md#compatibility-modes). ### Stringify options (selected) @@ -111,9 +134,11 @@ The full feature × mode table is in [docs/json5-compatibility.md](docs/json5-co - `singleQuote`, `trailingComma`, `unquotedKeys` - `preserveNumericFormatting` -Full types: [src/api-types.mts](src/api-types.mts) +Full types: [src/api-types.mts](https://github.com/CLDMV/jsonv/blob/master/src/api-types.mts) -## Errors +--- + +## 🛡 Errors Parse failures throw `JsonvSyntaxError` (extends `SyntaxError`, `name` stays `"SyntaxError"`), with structured position info alongside the message: @@ -162,7 +187,9 @@ try { } ``` -## AST for tooling +--- + +## 🌳 AST for Tooling `parseToAst()` returns the positioned AST without evaluating it, for linters, formatters and editors: @@ -174,9 +201,11 @@ program.body.properties[0].key; // { type: "Identifier", name: "port", loc: { st comments[0].value; // " port" ``` -Every node, token and comment carries `loc: { start, end }` with `{ line, column, offset }` positions (`\n`, `\r\n`, `\r`, U+2028 and U+2029 each count as one line break). Property keys are positioned `Literal` / `Identifier` nodes, and `Property.loc` spans key through value. `parseToAst()` never throws for invalid input: lexical and parse errors are both collected in `errors` (with `code`, `line`, `column` and `offset`), and `tolerant: true` recovers from both and reports every one. See [docs/ast.md](docs/ast.md) for the node reference. +Every node, token and comment carries `loc: { start, end }` with `{ line, column, offset }` positions (`\n`, `\r\n`, `\r`, U+2028 and U+2029 each count as one line break). Property keys are positioned `Literal` / `Identifier` nodes, and `Property.loc` spans key through value. `parseToAst()` never throws for invalid input: lexical and parse errors are both collected in `errors` (with `code`, `line`, `column` and `offset`), and `tolerant: true` recovers from both and reports every one. See [docs/ast.md](https://github.com/CLDMV/jsonv/blob/master/docs/ast.md) for the node reference. + +--- -## Internal references +## 🔗 Internal References ```jsonv { port: 8080, backup: port, url: `http://${host}:${port}` } @@ -184,7 +213,9 @@ Every node, token and comment carries `loc: { start, end }` with `{ line, column Rules: file‑scoped only, forward references supported, no circular refs. -## Year utilities +--- + +## 🧰 Year Utilities ```js import { loadYear, getLoadedYear } from "@cldmv/jsonv/loader"; @@ -197,33 +228,65 @@ const isPublished = isPublishedYear(2021); // true const nearest = resolveYear(2024); // 2021 ``` -## Diagnostics +--- + +## 🔍 Diagnostics `diagnose()` returns detected year/features + compatibility flags (`json`, `json5`). `info()` returns only detected year + parsed value. -## Tests & fixtures - -- Test runner: `npm test` (Vitest) -- Fixtures: [tests/fixtures/](tests/fixtures/) with `features/` and `violations/` per year -- See [tests/fixtures/README.md](tests/fixtures/README.md) for layout +--- -## Tooling +## 🛠 Tooling - ESLint plugin: published separately as [`@cldmv/eslint-plugin-jsonv`](https://github.com/CLDMV/jsonv-eslint-plugin-jsonv) (this repo's lint config consumes the published package). For local co-development, clone that repo under the gitignored `plugins/eslint-plugin-jsonv/` path and run `npm run build:plugin` to link it against this repo's current build. - Prettier plugin: published separately as [`@cldmv/prettier-plugin-jsonv`](https://github.com/CLDMV/jsonv-prettier-plugin-jsonv) for formatting `.jsonv` files. - VS Code language support: published separately as [`jsonv-vscode`](https://github.com/CLDMV/jsonv-vscode); clone under the gitignored `plugins/vscode-jsonv/` for local co-development. -## Development +--- + +## 📚 Documentation + +- **[Feature Matrix](https://github.com/CLDMV/jsonv/blob/master/docs/feature-matrix.md)** — features by ECMAScript year, lexical rules and excluded syntax +- **[Versioning & Exports](https://github.com/CLDMV/jsonv/blob/master/docs/versioning-and-exports.md)** — year-pinned entry points, the root alias, and ESM / CommonJS loading +- **[JSON5 Compatibility](https://github.com/CLDMV/jsonv/blob/master/docs/json5-compatibility.md)** — how jsonv relates to JSON5 and the `json` / `json5` / `jsonv` parse modes +- **[AST and Parser API](https://github.com/CLDMV/jsonv/blob/master/docs/ast.md)** — `parseToAst()`, node types, positions, tokens and comments for tooling +- **[Test Fixtures](https://github.com/CLDMV/jsonv/blob/master/tests/fixtures/README.md)** — per-year `features/` and `violations/` fixture layout +- **[Changelog](https://github.com/CLDMV/jsonv/tree/master/docs/changelog/)** — release notes for every version + +[![CodeFactor]][codefactor_url] [![OpenSSF Scorecard]][ossf_scorecard_url] [![npms.io score]][npms_url] [![npm unpacked size]][npm_size_url] [![Repo size]][repo_size_url] + +--- + +## 🤝 Contributing + +Contributions are welcome — open an issue or a pull request on [GitHub](https://github.com/CLDMV/jsonv). ```bash npm run dev # uses src/ via json-dev condition -npm run build # clean → ts → types → years → cjs → plugin -npm test # Vitest +npm run build # clean → ts → types → years → cjs +npm test # Vitest, then the CommonJS entry tests npm run lint # ESLint v9 config ``` -## License +- Test runner: `npm test` (Vitest via `@cldmv/vitest-runner`, then `node:test` checks of the built CommonJS entry) +- Fixtures: [tests/fixtures/](https://github.com/CLDMV/jsonv/tree/master/tests/fixtures) with `features/` and `violations/` per year +- See [tests/fixtures/README.md](https://github.com/CLDMV/jsonv/blob/master/tests/fixtures/README.md) for layout + +[![Contributors]][contributors_url] [![Sponsor shinrai]][sponsor_url] + +--- + +## 🔗 Links + +- **npm**: [@cldmv/jsonv](https://www.npmjs.com/package/@cldmv/jsonv) +- **GitHub**: [CLDMV/jsonv](https://github.com/CLDMV/jsonv) +- **Issues**: [GitHub Issues](https://github.com/CLDMV/jsonv/issues) +- **Changelog**: [docs/changelog/](https://github.com/CLDMV/jsonv/tree/master/docs/changelog/) + +--- + +## 📄 License [![GitHub license]][github_license_url] [![npm license]][npm_license_url] @@ -231,18 +294,30 @@ Apache-2.0 © Shinrai / CLDMV [npm version]: https://img.shields.io/npm/v/%40cldmv%2Fjsonv.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837 [npm_version_url]: https://www.npmjs.com/package/@cldmv/jsonv -[npm downloads]: https://img.shields.io/npm/dm/%40cldmv%2Fjsonv.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837 -[npm_downloads_url]: https://www.npmjs.com/package/@cldmv/jsonv +[last commit]: https://img.shields.io/github/last-commit/CLDMV/jsonv?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 +[last_commit_url]: https://github.com/CLDMV/jsonv/commits [npm last update]: https://img.shields.io/npm/last-update/%40cldmv%2Fjsonv?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837 [npm_last_update_url]: https://www.npmjs.com/package/@cldmv/jsonv -[npm license]: https://img.shields.io/npm/l/%40cldmv%2Fjsonv.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837 -[npm_license_url]: https://www.npmjs.com/package/@cldmv/jsonv +[codefactor]: https://img.shields.io/codefactor/grade/github/CLDMV/jsonv?style=for-the-badge&logo=codefactor&logoColor=white&labelColor=F44A6A +[codefactor_url]: https://www.codefactor.io/repository/github/cldmv/jsonv +[openssf scorecard]: https://img.shields.io/ossf-scorecard/github.com/CLDMV/jsonv?style=for-the-badge&label=OpenSSF%20Scorecard +[ossf_scorecard_url]: https://scorecard.dev/viewer/?uri=github.com/CLDMV/jsonv +[npms.io score]: https://img.shields.io/npms-io/final-score/%40cldmv%2Fjsonv?style=for-the-badge&logo=npms&logoColor=white&labelColor=0B5D57 +[npms_url]: https://npms.io/search?q=%40cldmv%2Fjsonv +[npm downloads]: https://img.shields.io/npm/dm/%40cldmv%2Fjsonv.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837 +[npm_downloads_url]: https://www.npmjs.com/package/@cldmv/jsonv [github downloads]: https://img.shields.io/github/downloads/CLDMV/jsonv/total?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 [github_downloads_url]: https://github.com/CLDMV/jsonv/releases -[last commit]: https://img.shields.io/github/last-commit/CLDMV/jsonv?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 -[last_commit_url]: https://github.com/CLDMV/jsonv/commits +[npm unpacked size]: https://img.shields.io/npm/unpacked-size/%40cldmv%2Fjsonv.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837 +[npm_size_url]: https://www.npmjs.com/package/@cldmv/jsonv +[repo size]: https://img.shields.io/github/repo-size/CLDMV/jsonv?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 +[repo_size_url]: https://github.com/CLDMV/jsonv [github license]: https://img.shields.io/github/license/CLDMV/jsonv.svg?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 [github_license_url]: https://github.com/CLDMV/jsonv/blob/HEAD/LICENSE +[npm license]: https://img.shields.io/npm/l/%40cldmv%2Fjsonv.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837 +[npm_license_url]: https://www.npmjs.com/package/@cldmv/jsonv +[coverage]: https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2FCLDMV%2Fjsonv%2Fbadges%2Fcoverage.json&style=for-the-badge&logo=vitest&logoColor=white +[coverage_url]: https://github.com/CLDMV/jsonv/blob/badges/coverage.json [contributors]: https://img.shields.io/github/contributors/CLDMV/jsonv.svg?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 [contributors_url]: https://github.com/CLDMV/jsonv/graphs/contributors [sponsor shinrai]: https://img.shields.io/github/sponsors/shinrai?style=for-the-badge&logo=githubsponsors&logoColor=white&labelColor=EA4AAA&label=Sponsor diff --git a/docs/changelog/v1/v1.1.4.md b/docs/changelog/v1/v1.1.4.md new file mode 100644 index 0000000..4c45f48 --- /dev/null +++ b/docs/changelog/v1/v1.1.4.md @@ -0,0 +1,65 @@ +# @cldmv/jsonv v1.1.4 Changelog + +**Release Date**: October 2026 +**Release Type**: Patch +**Branch**: `release/1.1.4` + +--- + +## Overview + +Version 1.1.4 fixes the CommonJS entry points. Until now `require("@cldmv/jsonv")`, and every `require("@cldmv/jsonv/")`, returned a Promise of the ESM module rather than the API, so CommonJS code had to `await` it. `require()` now returns the same exports as `import`, synchronously, loaded through Node's `require(esm)`. + +Existing `await require("@cldmv/jsonv")` code keeps working unchanged. Two cases do change and are covered in the upgrade notes below: code that chained `.then()` on the `require()` result, and CommonJS code on Node.js versions without `require(esm)`. The ESM API is untouched. + +--- + +## 🐛 Bug Fixes + +### `require()` is a synchronous wrapper around the ESM build ([#80](https://github.com/CLDMV/jsonv/pull/80)) + +The CommonJS build went through a generated `loader.cjs` that did `module.exports = (async () => await import("../index.mjs"))()`, so `require()` handed back a Promise. Every generated `.cjs` file is now a thin wrapper, `module.exports = require("")`, so `require()` returns the same module namespace object as `import`: + +```js +const { parse } = require("@cldmv/jsonv"); +parse("{ a: 1 }"); // { a: 1 } + +const jsonv2021 = require("@cldmv/jsonv/2021"); +``` + +The rest of the CommonJS build was tidied along the way: + +- The async `loader.cjs` is no longer generated, and `dist/cjs` is rebuilt from scratch on every build so a removed wrapper can't linger. +- `@cldmv/jsonv/year-resolver` now has a CommonJS wrapper. The `"./*"` export already pointed `require` at `dist/cjs/years/year-resolver.cjs`, but that file was never built, so `require("@cldmv/jsonv/year-resolver")` failed outright. `@cldmv/jsonv/loader` and the year modules are wrapped the same way. +- On Node.js without `require(esm)` (before 20.19.0, or 22.0–22.11), the wrappers throw an `ERR_REQUIRE_ESM` error whose message names the required Node.js versions and points to `import()`, instead of failing with a bare loader error. + +--- + +## 🔧 CI & tooling + +- New `tests/cjs/entry.test.cjs` (`node:test`), run by `npm test` and `npm run coverage` after Vitest through a new `test:cjs` script. It checks against the built `dist/` that `require()` of the entry and of a year module returns the same exports as `import`, and that the Node.js version check fires when `require(esm)` is unavailable. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/v1.1.4.md](./v1.1.4.md) — this changelog. +- [docs/versioning-and-exports.md](https://github.com/CLDMV/jsonv/blob/master/docs/versioning-and-exports.md) — notes that `require()` is synchronous and states its Node.js requirement. +- README — restructured to the CLDMV README layout (badges, What's New, Installation with Node.js requirements, Documentation index, Links), with the changelog history backfilled for every earlier release under `docs/changelog/v1/`. + +--- + +## 🔧 Dependencies + +All development-only ([#77](https://github.com/CLDMV/jsonv/pull/77)): + +- `@cldmv/vitest-runner` 1.4.3 → 1.5.1 +- `typescript-eslint` 8.70.1 → 8.71.0 + +--- + +## Upgrade notes + +- **`await require(...)` keeps working.** Awaiting a non-Promise returns it unchanged, so CommonJS code written against the old Promise-returning entry needs no change. +- **`.then()` on the `require()` result no longer works.** `require("@cldmv/jsonv").then((jsonv) => ...)` now throws `TypeError: ... .then is not a function`, because the result is the module itself. Use the result directly (`const jsonv = require("@cldmv/jsonv")`), or `await` it. +- **CommonJS needs Node.js ^20.19.0 or >=22.12.0.** On older Node.js, where `await require("@cldmv/jsonv")` used to resolve through the async loader, `require()` now throws `ERR_REQUIRE_ESM` with a message pointing to `import()`. Load the package with `await import("@cldmv/jsonv")` there. The `engines` field (`>=18.0.0`) and ESM `import` support are unchanged. From 8a84d8bb519bd4b5e9fc1abe7b1448e2f5efbe1d Mon Sep 17 00:00:00 2001 From: Shinrai Date: Sat, 3 Oct 2026 20:01:47 -0700 Subject: [PATCH 08/12] deps: bump @cldmv/fix-headers to 2.1.4 Bumps @cldmv/fix-headers to 2.1.4 (JSON/Markdown/extension-less files never get a JS comment; dependency folders never walked). Ran fix:headers: 0 files restamped. --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 94e3215..4401747 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "devDependencies": { "@cldmv/configs": "^1.2.0", "@cldmv/eslint-plugin-jsonv": "^1.0.3", - "@cldmv/fix-headers": "^2.1.1", + "@cldmv/fix-headers": "^2.1.4", "@cldmv/vitest-runner": "^1.4.3", "@eslint/css": "^2.0.0", "@eslint/js": "^10.0.1", @@ -181,9 +181,9 @@ } }, "node_modules/@cldmv/fix-headers": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@cldmv/fix-headers/-/fix-headers-2.1.1.tgz", - "integrity": "sha512-08xW44RvtrKUCTOjUFKHyrDvx6rT70zGqgRR+tdW0R9ElZrHwSg25xCRrZD+U7Dmj5fK9KmtuOWPjZtJYSfzYA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@cldmv/fix-headers/-/fix-headers-2.1.4.tgz", + "integrity": "sha512-PvCKMztN9k+jOjEpMCANMaDIkNW7cs2qp5P73JVzResk1+DfqhoZVqT9jpTT8cUu+6OGszsNqj8/X0Q9IhfNtg==", "dev": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 9e7a67c..bf5c177 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,7 @@ "devDependencies": { "@cldmv/configs": "^1.2.0", "@cldmv/eslint-plugin-jsonv": "^1.0.3", - "@cldmv/fix-headers": "^2.1.1", + "@cldmv/fix-headers": "^2.1.4", "@cldmv/vitest-runner": "^1.4.3", "@eslint/css": "^2.0.0", "@eslint/js": "^10.0.1", From a729df66df8e102e7f171c5d6cf43b24e49f9914 Mon Sep 17 00:00:00 2001 From: Shinrai Date: Sat, 3 Oct 2026 20:42:09 -0700 Subject: [PATCH 09/12] docs: list the fix-headers 2.1.4 bump (#83) in the v1.1.4 notes --- docs/changelog/v1/v1.1.4.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/changelog/v1/v1.1.4.md b/docs/changelog/v1/v1.1.4.md index 4c45f48..8f20d31 100644 --- a/docs/changelog/v1/v1.1.4.md +++ b/docs/changelog/v1/v1.1.4.md @@ -51,10 +51,11 @@ The rest of the CommonJS build was tidied along the way: ## 🔧 Dependencies -All development-only ([#77](https://github.com/CLDMV/jsonv/pull/77)): +All development-only: -- `@cldmv/vitest-runner` 1.4.3 → 1.5.1 -- `typescript-eslint` 8.70.1 → 8.71.0 +- `@cldmv/vitest-runner` 1.4.3 → 1.5.1 ([#77](https://github.com/CLDMV/jsonv/pull/77)) +- `typescript-eslint` 8.70.1 → 8.71.0 ([#77](https://github.com/CLDMV/jsonv/pull/77)) +- `@cldmv/fix-headers` `^2.1.1` → `^2.1.4` ([#83](https://github.com/CLDMV/jsonv/pull/83)). Version 2.1.4 no longer writes a JavaScript comment into JSON or Markdown files, processes every repeated `--input`, and never walks dependency folders such as `node_modules`. Only `package.json` and the lockfile changed; no file headers were restamped. --- From 34f5e255a9f371fd275d725e131ec21b81e045ea Mon Sep 17 00:00:00 2001 From: Shinrai Date: Sun, 4 Oct 2026 19:03:44 -0700 Subject: [PATCH 10/12] deps: bump @cldmv/fix-headers to 2.2.0 Restamping the file headers under 2.2.0 changed no headers (0 files restamped). --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4401747..0febffb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "devDependencies": { "@cldmv/configs": "^1.2.0", "@cldmv/eslint-plugin-jsonv": "^1.0.3", - "@cldmv/fix-headers": "^2.1.4", + "@cldmv/fix-headers": "^2.2.0", "@cldmv/vitest-runner": "^1.4.3", "@eslint/css": "^2.0.0", "@eslint/js": "^10.0.1", @@ -181,9 +181,9 @@ } }, "node_modules/@cldmv/fix-headers": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@cldmv/fix-headers/-/fix-headers-2.1.4.tgz", - "integrity": "sha512-PvCKMztN9k+jOjEpMCANMaDIkNW7cs2qp5P73JVzResk1+DfqhoZVqT9jpTT8cUu+6OGszsNqj8/X0Q9IhfNtg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cldmv/fix-headers/-/fix-headers-2.2.0.tgz", + "integrity": "sha512-EQTAKCo0B639q2bde+vO5ciYbtvNgAJFm0DBthIJQnmTFJmQDUlObp5EsTRgg5CUlFoUnGMX+q35LC02QvYU4w==", "dev": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index bf5c177..168a3ad 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,7 @@ "devDependencies": { "@cldmv/configs": "^1.2.0", "@cldmv/eslint-plugin-jsonv": "^1.0.3", - "@cldmv/fix-headers": "^2.1.4", + "@cldmv/fix-headers": "^2.2.0", "@cldmv/vitest-runner": "^1.4.3", "@eslint/css": "^2.0.0", "@eslint/js": "^10.0.1", From d514303afa43035218ff28993dd23d9c6b62edf3 Mon Sep 17 00:00:00 2001 From: Shinrai Date: Sun, 4 Oct 2026 19:14:57 -0700 Subject: [PATCH 11/12] deps: bump @cldmv/configs to 1.2.4 Shared fix-headers config 1.2.4 no longer forces author updates. Restamping the file headers changed no headers (0 files restamped). --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0febffb..afb6524 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.1.4", "license": "Apache-2.0", "devDependencies": { - "@cldmv/configs": "^1.2.0", + "@cldmv/configs": "^1.2.4", "@cldmv/eslint-plugin-jsonv": "^1.0.3", "@cldmv/fix-headers": "^2.2.0", "@cldmv/vitest-runner": "^1.4.3", @@ -121,9 +121,9 @@ } }, "node_modules/@cldmv/configs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@cldmv/configs/-/configs-1.2.0.tgz", - "integrity": "sha512-FDmlxOx6ceKuD5zTamUy9XOfAC4opeOaLxWqZz9okKxj8TsTZP6dN7W0VccRYRdw4606NvXjhdZqOPibcNpXmQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@cldmv/configs/-/configs-1.2.4.tgz", + "integrity": "sha512-7HPqAgCKqol3fHpawEsXJ5ZqHxlDPZk1puoFu43f/gaNfhWwufDTzjkvLk90yVEumyz4N3pUwIxfbHUkUTpDEg==", "dev": true, "license": "Apache-2.0", "funding": { diff --git a/package.json b/package.json index 168a3ad..d1d1f00 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "dist/" ], "devDependencies": { - "@cldmv/configs": "^1.2.0", + "@cldmv/configs": "^1.2.4", "@cldmv/eslint-plugin-jsonv": "^1.0.3", "@cldmv/fix-headers": "^2.2.0", "@cldmv/vitest-runner": "^1.4.3", From 143a50b583dde60848f6d18242fa6c607fb38730 Mon Sep 17 00:00:00 2001 From: Shinrai Date: Sun, 4 Oct 2026 20:08:19 -0700 Subject: [PATCH 12/12] docs: update the v1.1.4 release notes --- README.md | 1 + docs/changelog/v1/v1.1.4.md | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e8e643b..fabaded 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ On top of the literal syntax, jsonv adds **internal references** — file-scoped ### Latest: v1.1.4 (October 2026) - **`require()` returns the API synchronously** — `require("@cldmv/jsonv")` and `require("@cldmv/jsonv/")` used to return a Promise of the ESM module; they now return the same exports as `import`, loaded through Node's `require(esm)`. Existing `await require(...)` code keeps working, but code that chained `.then()` on the `require()` result must use the result directly. CommonJS needs Node.js ^20.19.0 or >=22.12.0; older Node.js gets a clear `ERR_REQUIRE_ESM` pointing to `import()`. `@cldmv/jsonv/year-resolver` also gains the CommonJS wrapper it was missing (#80). +- **Dev toolchain** — `@cldmv/fix-headers` 2.2.0 (`@Last modified by` now follows content edits only), `@cldmv/configs` 1.2.4, `@cldmv/vitest-runner` 1.5.1 and `typescript-eslint` 8.71.0, all dev-only; nothing was restamped (#77, #83, #85). - [View full v1.1.4 Changelog](https://github.com/CLDMV/jsonv/blob/master/docs/changelog/v1/v1.1.4.md) ### Recent Releases diff --git a/docs/changelog/v1/v1.1.4.md b/docs/changelog/v1/v1.1.4.md index 8f20d31..1e44aeb 100644 --- a/docs/changelog/v1/v1.1.4.md +++ b/docs/changelog/v1/v1.1.4.md @@ -10,7 +10,7 @@ Version 1.1.4 fixes the CommonJS entry points. Until now `require("@cldmv/jsonv")`, and every `require("@cldmv/jsonv/")`, returned a Promise of the ESM module rather than the API, so CommonJS code had to `await` it. `require()` now returns the same exports as `import`, synchronously, loaded through Node's `require(esm)`. -Existing `await require("@cldmv/jsonv")` code keeps working unchanged. Two cases do change and are covered in the upgrade notes below: code that chained `.then()` on the `require()` result, and CommonJS code on Node.js versions without `require(esm)`. The ESM API is untouched. +Existing `await require("@cldmv/jsonv")` code keeps working unchanged. Two cases do change and are covered in the upgrade notes below: code that chained `.then()` on the `require()` result, and CommonJS code on Node.js versions without `require(esm)`. The ESM API is untouched. The dev toolchain is also refreshed (`@cldmv/fix-headers` 2.2.0, `@cldmv/configs` 1.2.4, `@cldmv/vitest-runner` 1.5.1, `typescript-eslint` 8.71.0); none of it ships in the package. --- @@ -55,7 +55,9 @@ All development-only: - `@cldmv/vitest-runner` 1.4.3 → 1.5.1 ([#77](https://github.com/CLDMV/jsonv/pull/77)) - `typescript-eslint` 8.70.1 → 8.71.0 ([#77](https://github.com/CLDMV/jsonv/pull/77)) -- `@cldmv/fix-headers` `^2.1.1` → `^2.1.4` ([#83](https://github.com/CLDMV/jsonv/pull/83)). Version 2.1.4 no longer writes a JavaScript comment into JSON or Markdown files, processes every repeated `--input`, and never walks dependency folders such as `node_modules`. Only `package.json` and the lockfile changed; no file headers were restamped. +- `@cldmv/fix-headers` `^2.1.1` → `^2.2.0`, resolved to 2.2.0. The range was first raised to `^2.1.4` ([#83](https://github.com/CLDMV/jsonv/pull/83)) and then to `^2.2.0` ([#85](https://github.com/CLDMV/jsonv/pull/85)). Version 2.1.4 no longer writes a JavaScript comment into JSON or Markdown files, processes every repeated `--input`, and never walks dependency folders such as `node_modules`. Version 2.2.0 changes `@Last modified by` only when a file's content was edited, so header-only rewrites keep the recorded editor. +- `@cldmv/configs` `^1.2.0` → `^1.2.4`, resolved to 1.2.4. The shared fix-headers config now sets `forceAuthorUpdate` and `forceLastModifiedAuthorUpdate` to false ([#85](https://github.com/CLDMV/jsonv/pull/85)). +- No file headers were restamped: each fix-headers bump changed only `package.json` and the lockfile. ---