From de5c33117a6d78806f0275d623b4a18345856a8e Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 12 Mar 2026 17:09:00 +0000 Subject: [PATCH 1/3] Modernize project structure to match jsonicjs/ini conventions - Move source from root to src/ with dedicated tsconfig.json - Build output to dist/ and dist-test/ directories - Replace Jest with Node native test runner + @hapi/code - Remove unnecessary devDeps: browserify, esbuild, es-jest, jest, prettier - Add @hapi/code, @types/node; update TypeScript to ^5.8.2 - Update TS target from ES2019 to ES2021 - Update CI: Node 22.x, actions/checkout@v4, actions/setup-node@v4, remove Coveralls - Update package.json main/types to dist/, add files field - Clean compiled artifacts from root and test/ https://claude.ai/code/session_012dToG4AUYryeoDwpaR7dV2 --- .github/workflows/build.yml | 19 +- .gitignore | 5 +- jest.config.js | 9 - package.json | 35 ++- path.d.ts | 5 - path.js | 53 ---- path.js.map | 1 - path.min.js | 53 ---- path.ts => src/path.ts | 0 tsconfig.json => src/tsconfig.json | 14 +- test/path.test.d.ts | 1 - test/path.test.js | 392 ----------------------------- test/path.test.js.map | 1 - test/path.test.ts | 84 +++---- test/quick.js | 5 - test/tsconfig.json | 17 ++ 16 files changed, 87 insertions(+), 607 deletions(-) delete mode 100644 jest.config.js delete mode 100644 path.d.ts delete mode 100644 path.js delete mode 100644 path.js.map delete mode 100644 path.min.js rename path.ts => src/path.ts (100%) rename tsconfig.json => src/tsconfig.json (57%) delete mode 100644 test/path.test.d.ts delete mode 100644 test/path.test.js delete mode 100644 test/path.test.js.map delete mode 100644 test/quick.js create mode 100644 test/tsconfig.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 54879bb..d2bb2b5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,23 +16,16 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [18.x, 20.x, 22.x] + node-version: [22.x] + + runs-on: ${{ matrix.os }} - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm i - - run: npm run build --if-present + - run: npm run build - run: npm test - - - name: Coveralls - uses: coverallsapp/github-action@main - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - path-to-lcov: ./coverage/lcov.info - diff --git a/.gitignore b/.gitignore index 925f435..c070307 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,6 @@ node_modules .idea/ - trial test/coverage.html @@ -28,4 +27,6 @@ coverage package-lock.json yarn.lock - +dist +dist-test +*.tsbuildinfo diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index b923f60..0000000 --- a/jest.config.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - coveragePathIgnorePatterns: ['test'], - testEnvironment: 'node', - testMatch: ['**/test/**/*.test.ts'], - watchPathIgnorePatterns: ['.*.js$'], - transform: { - "^.+\\.tsx?$": "es-jest" - }, -} diff --git a/package.json b/package.json index 1ea48f1..8f39e4a 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,9 @@ "name": "@jsonic/path", "version": "1.5.1", "description": "This plugin allows the [Jsonic](https://jsonic.senecajs.org) JSON parser to determine the path to values.", - "main": "path.js", + "main": "dist/path.js", "type": "commonjs", - "types": "path.d.ts", + "types": "dist/path.d.ts", "homepage": "https://github.com/jsonicjs/path", "keywords": [ "pattern", @@ -19,36 +19,29 @@ "url": "git://github.com/jsonicjs/path.git" }, "scripts": { - "test": "jest --coverage", - "test-some": "jest -t", - "test-watch": "jest --coverage --watchAll", - "watch": "tsc -w -d", + "test": "node --enable-source-maps --test \"dist-test/*.test.js\"", + "test-some": "node --enable-source-maps --test --test-name-pattern", + "watch": "tsc --build src test -w", "doc": "jsonic-doc", - "build": "tsc -d", - "prettier": "prettier --write --no-semi --single-quote *.ts test/*.js", - "clean": "rm -rf node_modules yarn.lock package-lock.json", + "build": "tsc --build src test", + "clean": "rm -rf dist dist-test node_modules yarn.lock package-lock.json", "reset": "npm run clean && npm i && npm run build && npm test", "repo-tag": "REPO_VERSION=`node -e \"console.log(require('./package').version)\"` && echo TAG: v$REPO_VERSION && git commit -a -m v$REPO_VERSION && git push && git tag v$REPO_VERSION && git push --tags;", "repo-publish": "npm run clean && npm i && npm run repo-publish-quick", - "repo-publish-quick": "npm run prettier && npm run build && npm run test && npm run doc && npm run repo-tag && npm publish --access public --registry https://registry.npmjs.org " + "repo-publish-quick": "npm run build && npm run test && npm run doc && npm run repo-tag && npm publish --access public --registry https://registry.npmjs.org " }, "license": "MIT", "files": [ - "*.ts", - "*.js", - "*.map", + "src/", + "dist/", "LICENSE" ], "devDependencies": { + "@hapi/code": "^9.0.3", "@jsonic/doc": "^0.0.9", - "@types/jest": "^29.5.14", - "browserify": "^17.0.1", - "esbuild": "^0.24.2", - "es-jest": "^2.1.0", - "jest": "^29.7.0", - "prettier": "^3.4.2", - "typescript": "^5.7.3", - "@jsonic/expr": ">=1" + "@jsonic/expr": ">=1", + "@types/node": "^22.13.10", + "typescript": "^5.8.2" }, "peerDependencies": { "jsonic": ">=2" diff --git a/path.d.ts b/path.d.ts deleted file mode 100644 index efc7752..0000000 --- a/path.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Plugin } from 'jsonic'; -type PathOptions = {}; -declare const Path: Plugin; -export { Path }; -export type { PathOptions }; diff --git a/path.js b/path.js deleted file mode 100644 index 5b7ae93..0000000 --- a/path.js +++ /dev/null @@ -1,53 +0,0 @@ -"use strict"; -/* Copyright (c) 2022-2024 Richard Rodger, MIT License */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.Path = void 0; -/* Keeps track of the property path to the current location. - * Example: {a:{b:1 ## path=["a","b"] - * Use the Rule.k key-value store so that the path is propagated to children and followers. - * Depth must be greater than 0 - ensures path only starts once top level implicit is set up. - */ -const Path = (jsonic, _options) => { - jsonic.rule('val', (rs) => { - rs.bo((r, ctx) => { - var _a, _b; - // At top level, create path array, or inherit from meta context. - if (0 === r.d) { - r.k.path = ((_b = (_a = ctx.meta.path) === null || _a === void 0 ? void 0 : _a.base) === null || _b === void 0 ? void 0 : _b.slice(0)) || []; - } - }); - }); - jsonic.rule('map', (rs) => { - rs.bo((r) => { - // Not in an array, so no need to track element index. - delete r.k.index; - }); - }); - jsonic.rule('pair', (rs) => { - rs.ao((r) => { - if (0 < r.d && r.u.pair) { - r.child.k.path = [...r.k.path, r.u.key]; - r.child.k.key = r.u.key; - } - }); - }); - jsonic.rule('list', (rs) => { - rs.bo((r) => { - // In array, the path property is the element index. - r.k.index = -1; - }); - }); - jsonic.rule('elem', (rs) => { - rs.ao((r) => { - if (0 < r.d) { - r.k.index = 1 + r.k.index; - r.child.k.path = [...r.k.path, r.k.index]; - r.child.k.key = r.k.index; - r.child.k.index = r.k.index; - } - }); - }); -}; -exports.Path = Path; -Path.defaults = {}; -//# sourceMappingURL=path.js.map \ No newline at end of file diff --git a/path.js.map b/path.js.map deleted file mode 100644 index 0db2809..0000000 --- a/path.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"path.js","sourceRoot":"","sources":["path.ts"],"names":[],"mappings":";AAAA,yDAAyD;;;AAMzD;;;;GAIG;AACH,MAAM,IAAI,GAAW,CAAC,MAAc,EAAE,QAAqB,EAAE,EAAE;IAC7D,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE;QACxB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;;YACf,iEAAiE;YACjE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;gBACd,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAA,MAAA,MAAA,GAAG,CAAC,IAAI,CAAC,IAAI,0CAAE,IAAI,0CAAE,KAAK,CAAC,CAAC,CAAC,KAAI,EAAE,CAAA;YAChD,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE;QACxB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;YACV,sDAAsD;YACtD,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;QAClB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE;QACzB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;YACV,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBACxB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;gBACvC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;YACzB,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE;QACzB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;YACV,oDAAoD;YACpD,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAA;QAChB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE;QACzB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;YACV,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBACZ,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;gBACzB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;gBACzC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;gBACzB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;YAC7B,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA;AAIQ,oBAAI;AAFb,IAAI,CAAC,QAAQ,GAAG,EAAiB,CAAA"} \ No newline at end of file diff --git a/path.min.js b/path.min.js deleted file mode 100644 index 5b7ae93..0000000 --- a/path.min.js +++ /dev/null @@ -1,53 +0,0 @@ -"use strict"; -/* Copyright (c) 2022-2024 Richard Rodger, MIT License */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.Path = void 0; -/* Keeps track of the property path to the current location. - * Example: {a:{b:1 ## path=["a","b"] - * Use the Rule.k key-value store so that the path is propagated to children and followers. - * Depth must be greater than 0 - ensures path only starts once top level implicit is set up. - */ -const Path = (jsonic, _options) => { - jsonic.rule('val', (rs) => { - rs.bo((r, ctx) => { - var _a, _b; - // At top level, create path array, or inherit from meta context. - if (0 === r.d) { - r.k.path = ((_b = (_a = ctx.meta.path) === null || _a === void 0 ? void 0 : _a.base) === null || _b === void 0 ? void 0 : _b.slice(0)) || []; - } - }); - }); - jsonic.rule('map', (rs) => { - rs.bo((r) => { - // Not in an array, so no need to track element index. - delete r.k.index; - }); - }); - jsonic.rule('pair', (rs) => { - rs.ao((r) => { - if (0 < r.d && r.u.pair) { - r.child.k.path = [...r.k.path, r.u.key]; - r.child.k.key = r.u.key; - } - }); - }); - jsonic.rule('list', (rs) => { - rs.bo((r) => { - // In array, the path property is the element index. - r.k.index = -1; - }); - }); - jsonic.rule('elem', (rs) => { - rs.ao((r) => { - if (0 < r.d) { - r.k.index = 1 + r.k.index; - r.child.k.path = [...r.k.path, r.k.index]; - r.child.k.key = r.k.index; - r.child.k.index = r.k.index; - } - }); - }); -}; -exports.Path = Path; -Path.defaults = {}; -//# sourceMappingURL=path.js.map \ No newline at end of file diff --git a/path.ts b/src/path.ts similarity index 100% rename from path.ts rename to src/path.ts diff --git a/tsconfig.json b/src/tsconfig.json similarity index 57% rename from tsconfig.json rename to src/tsconfig.json index 115b82e..72f2e0b 100644 --- a/tsconfig.json +++ b/src/tsconfig.json @@ -1,17 +1,15 @@ { "compilerOptions": { - "isolatedModules": true, "esModuleInterop": true, "module": "nodenext", "noEmitOnError": true, - "noImplicitAny": true, + "outDir": "../dist", + "rootDir": ".", + "declaration": true, "resolveJsonModule": true, "sourceMap": true, "strict": true, - "target": "ES2019" - }, - "exclude": [ - "dist", - "node_modules" - ] + "target": "ES2021", + "composite": true + } } diff --git a/test/path.test.d.ts b/test/path.test.d.ts deleted file mode 100644 index cb0ff5c..0000000 --- a/test/path.test.d.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/test/path.test.js b/test/path.test.js deleted file mode 100644 index 2f7c3f0..0000000 --- a/test/path.test.js +++ /dev/null @@ -1,392 +0,0 @@ -"use strict"; -/* Copyright (c) 2022-2025 Richard Rodger and other contributors, MIT License */ -Object.defineProperty(exports, "__esModule", { value: true }); -const jsonic_1 = require("jsonic"); -const expr_1 = require("@jsonic/expr"); -const path_1 = require("../path"); -describe('path', () => { - test('happy', () => { - const j = jsonic_1.Jsonic.make().use(path_1.Path); - expect(j('{a:{b:1,c:[2,3]}}')).toEqual({ a: { b: 1, c: [2, 3] } }); - }); - test('basic', () => { - const j = jsonic_1.Jsonic.make().use(path_1.Path).use((jsonic) => { - jsonic.rule('val', rs => { - rs - .ac(false, (r) => { - if ('object' !== typeof (r.node)) { - r.node = `<${r.node}:${r.k.path}>`; - } - else { - r.node.$ = `<${r.k.path}>`; - } - }); - }); - }); - let c = [ - '<2:a,c,0>', - '<3:a,c,1>', - ]; - c.$ = ''; - expect(j('{a:{b:1,c:[2,3]}}')).toEqual({ - $: '<>', - a: { - $: '', - b: '<1:a,b>', - c - } - }); - }); - test('meta', () => { - const j = jsonic_1.Jsonic.make().use(path_1.Path).use((jsonic) => { - jsonic.rule('val', rs => { - rs - .ac(false, (r) => { - if ('object' === typeof (r.node)) { - r.node.$ = `<${r.k.path}>`; - } - }); - }); - }); - expect(j('a:b:c:1,d:e:2', { path: { base: ['x', 'y'] } })).toEqual({ - $: '', - a: { - $: '', - b: { - $: '', - c: 1 - } - }, - d: { - $: '', - e: 2 - } - }); - }); - test('object', () => { - const j = jsonic_1.Jsonic.make().use(path_1.Path).use((jsonic) => { - jsonic.rule('val', rs => { - rs - .ac(false, (r) => { - if ('object' !== typeof (r.node)) { - r.node = `<${r.node}:${r.k.path}>`; - } - else { - r.node.$ = `<${r.k.path}>`; - } - }); - }); - }); - expect(j('a:1')).toEqual({ $: '<>', a: '<1:a>' }); - expect(j('a:1,b:B')).toEqual({ $: '<>', a: '<1:a>', b: '' }); - expect(j('a:1,b:B,c:true')) - .toEqual({ $: '<>', a: '<1:a>', b: '', c: '' }); - expect(j('{a:1}')).toEqual({ $: '<>', a: '<1:a>' }); - expect(j('{a:1,b:B}')).toEqual({ $: '<>', a: '<1:a>', b: '' }); - expect(j('{a:1,b:B,c:true}')) - .toEqual({ $: '<>', a: '<1:a>', b: '', c: '' }); - expect(j('x:{a:1}')).toEqual({ $: '<>', x: { $: '', a: '<1:x,a>' } }); - expect(j('x:{a:1,b:B}')) - .toEqual({ $: '<>', x: { $: '', a: '<1:x,a>', b: '' } }); - expect(j('x:{a:1,b:B,c:true}')) - .toEqual({ - $: '<>', - x: { $: '', a: '<1:x,a>', b: '', c: '' } - }); - expect(j('y:x:{a:1}')) - .toEqual({ $: '<>', y: { $: '', x: { $: '', a: '<1:y,x,a>' } } }); - expect(j('y:x:{a:1,b:B}')) - .toEqual({ - $: '<>', - y: { $: '', x: { $: '', a: '<1:y,x,a>', b: '' } } - }); - expect(j('y:x:{a:1,b:B,c:true}')) - .toEqual({ - $: '<>', y: { - $: '', - x: { $: '', a: '<1:y,x,a>', b: '', c: '' } - } - }); - expect(j('z:y:x:{a:1}')) - .toEqual({ - $: '<>', - z: { $: '', y: { $: '', x: { $: '', a: '<1:z,y,x,a>' } } } - }); - expect(j('z:y:x:{a:1,b:B}')) - .toEqual({ - $: '<>', - z: { - $: '', - y: { $: '', x: { $: '', a: '<1:z,y,x,a>', b: '' } } - } - }); - expect(j('z:y:x:{a:1,b:B,c:true}')) - .toEqual({ - $: '<>', - z: { - $: '', - y: { - $: '', - x: { - $: '', - a: '<1:z,y,x,a>', b: '', c: '' - } - } - } - }); - }); - test('array', () => { - const j = jsonic_1.Jsonic.make().use(path_1.Path).use((jsonic) => { - jsonic.rule('val', rs => { - rs - .ac(false, (r) => { - if ('object' !== typeof (r.node)) { - r.node = `<${r.node}:${r.k.path}>`; - } - else { - r.node = { ...r.node }; - r.node.$ = `<${r.k.path}>`; - } - }); - }); - }); - expect(j('[]')).toEqual({ $: '<>' }); - expect(j('[1]')).toEqual({ $: '<>', 0: '<1:0>' }); - expect(j('[1,2]')).toEqual({ $: '<>', 0: '<1:0>', 1: '<2:1>' }); - expect(j('[1,2,3]')).toEqual({ $: '<>', 0: '<1:0>', 1: '<2:1>', 2: '<3:2>' }); - expect(j('[[]]')).toEqual({ $: '<>', 0: { $: '<0>' } }); - expect(j('[[1]]')).toEqual({ $: '<>', 0: { $: '<0>', 0: '<1:0,0>' } }); - expect(j('[[1,2]]')) - .toEqual({ $: '<>', 0: { $: '<0>', 0: '<1:0,0>', 1: '<2:0,1>' } }); - expect(j('[[1,2,3]]')) - .toEqual({ $: '<>', 0: { $: '<0>', 0: '<1:0,0>', 1: '<2:0,1>', 2: '<3:0,2>' } }); - expect(j('[[[]]]')).toEqual({ $: '<>', 0: { $: '<0>', 0: { $: '<0,0>' } } }); - expect(j('[[[1]]]')) - .toEqual({ $: '<>', 0: { $: '<0>', 0: { $: '<0,0>', 0: '<1:0,0,0>' } } }); - expect(j('[[[1,2]]]')) - .toEqual({ - $: '<>', - 0: { $: '<0>', 0: { $: '<0,0>', 0: '<1:0,0,0>', 1: '<2:0,0,1>' } } - }); - expect(j('[[[1,2,3]]]')) - .toEqual({ - $: '<>', - 0: { - $: '<0>', - 0: { $: '<0,0>', 0: '<1:0,0,0>', 1: '<2:0,0,1>', 2: '<3:0,0,2>' } - } - }); - }); - test('transform', () => { - const j = jsonic_1.Jsonic.make().use(path_1.Path).use((jsonic) => { - jsonic.rule('val', rs => { - rs - .ac(false, (r) => { - if ('object' !== typeof (r.node)) { - r.node = { - o: 'val', - v: r.node, - p: r.k.path, - // k: null == r.k.key ? r.k.index : r.k.key - k: r.k.key, - }; - } - else { - r.node = { - o: Array.isArray(r.node) ? 'arr' : 'obj', - v: { ...r.node }, - p: r.k.path, - // k: null == r.k.key ? r.k.index : r.k.key - k: r.k.key, - }; - } - }); - }); - }); - expect(j('{a:{b:1}}')).toEqual({ - k: undefined, - o: 'obj', - p: [], - v: { - a: { - k: 'a', - o: 'obj', - p: ['a',], - v: { - b: { - k: 'b', - o: 'val', - p: ['a', 'b',], - v: 1, - }, - }, - }, - }, - }); - expect(j('{a:{b:1,c:{d:{e:2}}},f:4}')).toEqual({ - k: undefined, - o: 'obj', - p: [], - v: { - a: { - k: 'a', - o: 'obj', - p: ['a',], - v: { - b: { - k: 'b', - o: 'val', - p: ['a', 'b',], - v: 1, - }, - c: { - k: 'c', - o: 'obj', - p: ['a', 'c'], - v: { - d: { - k: 'd', - o: 'obj', - p: ['a', 'c', 'd'], - v: { - e: { - k: 'e', - o: 'val', - p: ['a', 'c', 'd', 'e'], - v: 2 - } - } - } - } - } - }, - }, - f: { - k: 'f', - o: 'val', - p: ['f',], - v: 4, - }, - }, - }); - expect(j('[a,b,c]')).toEqual({ - k: undefined, - o: 'arr', - p: [], - v: { - 0: { - k: 0, - o: 'val', - p: [0], - v: 'a', - }, - 1: { - k: 1, - o: 'val', - p: [1], - v: 'b', - }, - 2: { - k: 2, - o: 'val', - p: [2], - v: 'c', - }, - } - }); - expect(j('[a,[b],{c:1,d:[2,3]}]')).toEqual({ - k: undefined, - o: 'arr', - p: [], - v: { - 0: { - k: 0, - o: 'val', - p: [0], - v: 'a', - }, - 1: { - k: 1, - o: 'arr', - p: [1], - v: { - 0: { - k: 0, - o: 'val', - p: [1, 0], - v: 'b', - } - } - }, - 2: { - k: 2, - o: 'obj', - p: [2], - v: { - c: { - k: 'c', - o: 'val', - p: [2, 'c'], - v: 1, - }, - d: { - k: 'd', - o: 'arr', - p: [2, 'd'], - v: { - 0: { - k: 0, - o: 'val', - p: [2, 'd', 0], - v: 2, - }, - 1: { - k: 1, - o: 'val', - p: [2, 'd', 1], - v: 3, - }, - } - }, - } - }, - } - }); - }); - test('value', () => { - const j = jsonic_1.Jsonic.make() - .use(path_1.Path) - .use((jsonic) => { - jsonic.options({ - value: { - def: { - AAA: { - val: (r) => { - return { AAA: 1, k: r.k.key, p: r.k.path }; - } - } - } - } - }); - }); - expect(j('a:AAA')).toEqual({ a: { AAA: 1, k: 'a', p: ['a'] } }); - }); - test('expr', () => { - const j = jsonic_1.Jsonic.make() - .use(path_1.Path) - .use(expr_1.Expr, { - op: { - 'foo': { - infix: true, src: '%', left: 14000, right: 15000 - }, - }, - evaluate: (r, _c, _op, terms) => { - // console.log('TERMS', terms) - return { foo: terms[0] * terms[1], k: r.k.key, p: r.k.path }; - } - }); - expect(j('{a:2%3}')).toEqual({ a: { foo: 6, k: 'a', p: ['a'] } }); - expect(j('a:2%3')).toEqual({ a: { foo: 6, k: 'a', p: ['a'] } }); - }); -}); -//# sourceMappingURL=path.test.js.map \ No newline at end of file diff --git a/test/path.test.js.map b/test/path.test.js.map deleted file mode 100644 index b658b01..0000000 --- a/test/path.test.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"path.test.js","sourceRoot":"","sources":["path.test.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/test/path.test.ts b/test/path.test.ts index f8ce16e..c9be393 100644 --- a/test/path.test.ts +++ b/test/path.test.ts @@ -1,6 +1,9 @@ /* Copyright (c) 2022-2025 Richard Rodger and other contributors, MIT License */ +import { test, describe } from 'node:test' +import { expect } from '@hapi/code' + import { Jsonic, Rule, Context } from 'jsonic' import { Expr, @@ -9,7 +12,7 @@ import { -import { Path } from '../path' +import { Path } from '../dist/path' @@ -18,7 +21,7 @@ describe('path', () => { test('happy', () => { const j = Jsonic.make().use(Path) - expect(j('{a:{b:1,c:[2,3]}}')).toEqual({ a: { b: 1, c: [2, 3] } }) + expect(j('{a:{b:1,c:[2,3]}}')).to.equal({ a: { b: 1, c: [2, 3] } }) }) @@ -42,7 +45,7 @@ describe('path', () => { '<3:a,c,1>', ] c.$ = '' - expect(j('{a:{b:1,c:[2,3]}}')).toEqual({ + expect(j('{a:{b:1,c:[2,3]}}')).to.equal({ $: '<>', a: { $: '', @@ -65,7 +68,7 @@ describe('path', () => { }) }) - expect(j('a:b:c:1,d:e:2', { path: { base: ['x', 'y'] } })).toEqual({ + expect(j('a:b:c:1,d:e:2', { path: { base: ['x', 'y'] } })).to.equal({ $: '', a: { $: '', @@ -98,34 +101,34 @@ describe('path', () => { }) }) - expect(j('a:1')).toEqual({ $: '<>', a: '<1:a>' }) - expect(j('a:1,b:B')).toEqual({ $: '<>', a: '<1:a>', b: '' }) + expect(j('a:1')).to.equal({ $: '<>', a: '<1:a>' }) + expect(j('a:1,b:B')).to.equal({ $: '<>', a: '<1:a>', b: '' }) expect(j('a:1,b:B,c:true')) - .toEqual({ $: '<>', a: '<1:a>', b: '', c: '' }) + .to.equal({ $: '<>', a: '<1:a>', b: '', c: '' }) - expect(j('{a:1}')).toEqual({ $: '<>', a: '<1:a>' }) - expect(j('{a:1,b:B}')).toEqual({ $: '<>', a: '<1:a>', b: '' }) + expect(j('{a:1}')).to.equal({ $: '<>', a: '<1:a>' }) + expect(j('{a:1,b:B}')).to.equal({ $: '<>', a: '<1:a>', b: '' }) expect(j('{a:1,b:B,c:true}')) - .toEqual({ $: '<>', a: '<1:a>', b: '', c: '' }) + .to.equal({ $: '<>', a: '<1:a>', b: '', c: '' }) - expect(j('x:{a:1}')).toEqual({ $: '<>', x: { $: '', a: '<1:x,a>' } }) + expect(j('x:{a:1}')).to.equal({ $: '<>', x: { $: '', a: '<1:x,a>' } }) expect(j('x:{a:1,b:B}')) - .toEqual({ $: '<>', x: { $: '', a: '<1:x,a>', b: '' } }) + .to.equal({ $: '<>', x: { $: '', a: '<1:x,a>', b: '' } }) expect(j('x:{a:1,b:B,c:true}')) - .toEqual({ + .to.equal({ $: '<>', x: { $: '', a: '<1:x,a>', b: '', c: '' } }) expect(j('y:x:{a:1}')) - .toEqual({ $: '<>', y: { $: '', x: { $: '', a: '<1:y,x,a>' } } }) + .to.equal({ $: '<>', y: { $: '', x: { $: '', a: '<1:y,x,a>' } } }) expect(j('y:x:{a:1,b:B}')) - .toEqual({ + .to.equal({ $: '<>', y: { $: '', x: { $: '', a: '<1:y,x,a>', b: '' } } }) expect(j('y:x:{a:1,b:B,c:true}')) - .toEqual({ + .to.equal({ $: '<>', y: { $: '', x: { $: '', a: '<1:y,x,a>', b: '', c: '' } @@ -133,12 +136,12 @@ describe('path', () => { }) expect(j('z:y:x:{a:1}')) - .toEqual({ + .to.equal({ $: '<>', z: { $: '', y: { $: '', x: { $: '', a: '<1:z,y,x,a>' } } } }) expect(j('z:y:x:{a:1,b:B}')) - .toEqual({ + .to.equal({ $: '<>', z: { $: '', @@ -146,7 +149,7 @@ describe('path', () => { } }) expect(j('z:y:x:{a:1,b:B,c:true}')) - .toEqual({ + .to.equal({ $: '<>', z: { $: '', @@ -179,28 +182,28 @@ describe('path', () => { }) }) - expect(j('[]')).toEqual({ $: '<>' }) - expect(j('[1]')).toEqual({ $: '<>', 0: '<1:0>' }) - expect(j('[1,2]')).toEqual({ $: '<>', 0: '<1:0>', 1: '<2:1>' }) - expect(j('[1,2,3]')).toEqual({ $: '<>', 0: '<1:0>', 1: '<2:1>', 2: '<3:2>' }) + expect(j('[]')).to.equal({ $: '<>' }) + expect(j('[1]')).to.equal({ $: '<>', 0: '<1:0>' }) + expect(j('[1,2]')).to.equal({ $: '<>', 0: '<1:0>', 1: '<2:1>' }) + expect(j('[1,2,3]')).to.equal({ $: '<>', 0: '<1:0>', 1: '<2:1>', 2: '<3:2>' }) - expect(j('[[]]')).toEqual({ $: '<>', 0: { $: '<0>' } }) - expect(j('[[1]]')).toEqual({ $: '<>', 0: { $: '<0>', 0: '<1:0,0>' } }) + expect(j('[[]]')).to.equal({ $: '<>', 0: { $: '<0>' } }) + expect(j('[[1]]')).to.equal({ $: '<>', 0: { $: '<0>', 0: '<1:0,0>' } }) expect(j('[[1,2]]')) - .toEqual({ $: '<>', 0: { $: '<0>', 0: '<1:0,0>', 1: '<2:0,1>' } }) + .to.equal({ $: '<>', 0: { $: '<0>', 0: '<1:0,0>', 1: '<2:0,1>' } }) expect(j('[[1,2,3]]')) - .toEqual({ $: '<>', 0: { $: '<0>', 0: '<1:0,0>', 1: '<2:0,1>', 2: '<3:0,2>' } }) + .to.equal({ $: '<>', 0: { $: '<0>', 0: '<1:0,0>', 1: '<2:0,1>', 2: '<3:0,2>' } }) - expect(j('[[[]]]')).toEqual({ $: '<>', 0: { $: '<0>', 0: { $: '<0,0>' } } }) + expect(j('[[[]]]')).to.equal({ $: '<>', 0: { $: '<0>', 0: { $: '<0,0>' } } }) expect(j('[[[1]]]')) - .toEqual({ $: '<>', 0: { $: '<0>', 0: { $: '<0,0>', 0: '<1:0,0,0>' } } }) + .to.equal({ $: '<>', 0: { $: '<0>', 0: { $: '<0,0>', 0: '<1:0,0,0>' } } }) expect(j('[[[1,2]]]')) - .toEqual({ + .to.equal({ $: '<>', 0: { $: '<0>', 0: { $: '<0,0>', 0: '<1:0,0,0>', 1: '<2:0,0,1>' } } }) expect(j('[[[1,2,3]]]')) - .toEqual({ + .to.equal({ $: '<>', 0: { $: '<0>', @@ -221,7 +224,6 @@ describe('path', () => { o: 'val', v: r.node, p: r.k.path, - // k: null == r.k.key ? r.k.index : r.k.key k: r.k.key, } } @@ -230,7 +232,6 @@ describe('path', () => { o: Array.isArray(r.node) ? 'arr' : 'obj', v: { ...r.node }, p: r.k.path, - // k: null == r.k.key ? r.k.index : r.k.key k: r.k.key, } } @@ -238,7 +239,7 @@ describe('path', () => { }) }) - expect(j('{a:{b:1}}')).toEqual({ + expect(j('{a:{b:1}}')).to.equal({ k: undefined, o: 'obj', p: [], @@ -259,7 +260,7 @@ describe('path', () => { }, }) - expect(j('{a:{b:1,c:{d:{e:2}}},f:4}')).toEqual({ + expect(j('{a:{b:1,c:{d:{e:2}}},f:4}')).to.equal({ k: undefined, o: 'obj', p: [], @@ -306,7 +307,7 @@ describe('path', () => { }, }) - expect(j('[a,b,c]')).toEqual({ + expect(j('[a,b,c]')).to.equal({ k: undefined, o: 'arr', p: [], @@ -332,7 +333,7 @@ describe('path', () => { } }) - expect(j('[a,[b],{c:1,d:[2,3]}]')).toEqual({ + expect(j('[a,[b],{c:1,d:[2,3]}]')).to.equal({ k: undefined, o: 'arr', p: [], @@ -412,7 +413,7 @@ describe('path', () => { }) }) - expect(j('a:AAA')).toEqual({ a: { AAA: 1, k: 'a', p: ['a'] } }) + expect(j('a:AAA')).to.equal({ a: { AAA: 1, k: 'a', p: ['a'] } }) }) @@ -426,15 +427,12 @@ describe('path', () => { }, }, evaluate: (r: Rule, _c: Context, _op: Op, terms: any) => { - // console.log('TERMS', terms) return { foo: terms[0] * terms[1], k: r.k.key, p: r.k.path } } }) - expect(j('{a:2%3}')).toEqual({ a: { foo: 6, k: 'a', p: ['a'] } }) - expect(j('a:2%3')).toEqual({ a: { foo: 6, k: 'a', p: ['a'] } }) + expect(j('{a:2%3}')).to.equal({ a: { foo: 6, k: 'a', p: ['a'] } }) + expect(j('a:2%3')).to.equal({ a: { foo: 6, k: 'a', p: ['a'] } }) }) }) - - diff --git a/test/quick.js b/test/quick.js deleted file mode 100644 index 437c8d4..0000000 --- a/test/quick.js +++ /dev/null @@ -1,5 +0,0 @@ -const { Jsonic } = require('jsonic') -const { Debug } = require('jsonic/debug') - -console.log(Jsonic) -console.log(Debug) diff --git a/test/tsconfig.json b/test/tsconfig.json new file mode 100644 index 0000000..8e048ae --- /dev/null +++ b/test/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "esModuleInterop": true, + "module": "nodenext", + "noEmitOnError": true, + "outDir": "../dist-test", + "rootDir": ".", + "declaration": true, + "resolveJsonModule": true, + "sourceMap": true, + "strict": true, + "target": "ES2021" + }, + "references": [ + { "path": "../src" } + ] +} From 43f8413f0ac21a0c729971d08351289e02bf71d9 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 12 Mar 2026 17:13:22 +0000 Subject: [PATCH 2/3] Update CI to Node 24.x and bump deps to latest - CI matrix: Node 22.x -> 24.x - typescript: ^5.8.2 -> ^5.9.3 - @types/node: ^22.13.10 -> ^25.5.0 https://claude.ai/code/session_012dToG4AUYryeoDwpaR7dV2 --- .github/workflows/build.yml | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d2bb2b5..27266f4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [22.x] + node-version: [24.x] runs-on: ${{ matrix.os }} diff --git a/package.json b/package.json index 8f39e4a..c0bc87d 100644 --- a/package.json +++ b/package.json @@ -40,8 +40,8 @@ "@hapi/code": "^9.0.3", "@jsonic/doc": "^0.0.9", "@jsonic/expr": ">=1", - "@types/node": "^22.13.10", - "typescript": "^5.8.2" + "@types/node": "^25.5.0", + "typescript": "^5.9.3" }, "peerDependencies": { "jsonic": ">=2" From 354448a7376c559355ce5b36b16d21aa9bd5d688 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 12 Mar 2026 17:29:44 +0000 Subject: [PATCH 3/3] Add Go implementation of Path plugin with CI - go/path.go: Path plugin tracking property paths during parsing - go/path_test.go: Tests for path tracking, meta base, objects, arrays - CI: Add build-go job with Go 1.24 on all platforms https://claude.ai/code/session_012dToG4AUYryeoDwpaR7dV2 --- .github/workflows/build.yml | 23 ++++ go/go.mod | 5 + go/go.sum | 2 + go/path.go | 94 ++++++++++++++++ go/path_test.go | 212 ++++++++++++++++++++++++++++++++++++ 5 files changed, 336 insertions(+) create mode 100644 go/go.mod create mode 100644 go/go.sum create mode 100644 go/path.go create mode 100644 go/path_test.go diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 27266f4..8b95975 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,3 +29,26 @@ jobs: - run: npm i - run: npm run build - run: npm test + + build-go: + + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + go-version: ['1.24'] + + runs-on: ${{ matrix.os }} + + defaults: + run: + working-directory: go + + steps: + - uses: actions/checkout@v4 + - name: Use Go ${{ matrix.go-version }} + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go-version }} + - run: go build ./... + - run: go test -v ./... diff --git a/go/go.mod b/go/go.mod new file mode 100644 index 0000000..c3652a5 --- /dev/null +++ b/go/go.mod @@ -0,0 +1,5 @@ +module github.com/jsonicjs/path/go + +go 1.24.7 + +require github.com/jsonicjs/jsonic/go v0.1.4 diff --git a/go/go.sum b/go/go.sum new file mode 100644 index 0000000..dc99d17 --- /dev/null +++ b/go/go.sum @@ -0,0 +1,2 @@ +github.com/jsonicjs/jsonic/go v0.1.4 h1:V1KEzmg/jIwk25+JYj8ig1+B7190rHmH8WqZbT7XlgA= +github.com/jsonicjs/jsonic/go v0.1.4/go.mod h1:ObNKlCG7esWoi4AHCpdgkILvPINV8bpvkbCd4llGGUg= diff --git a/go/path.go b/go/path.go new file mode 100644 index 0000000..8c46f4f --- /dev/null +++ b/go/path.go @@ -0,0 +1,94 @@ +/* Copyright (c) 2022-2025 Richard Rodger and other contributors, MIT License */ + +package path + +import ( + jsonic "github.com/jsonicjs/jsonic/go" +) + +type PathOptions struct{} + +// Path is a Jsonic plugin that tracks the property path to the current +// location during parsing. The path is stored in Rule.K["path"] as a +// []any slice of string keys and int indices. +func Path(j *jsonic.Jsonic, opts map[string]any) { + + j.Rule("val", func(rs *jsonic.RuleSpec) { + rs.BO = append(rs.BO, func(r *jsonic.Rule, ctx *jsonic.Context) { + if r.D == 0 { + var base []any + if ctx.Meta != nil { + if pm, ok := ctx.Meta["path"].(map[string]any); ok { + if b, ok := pm["base"].([]any); ok { + base = make([]any, len(b)) + copy(base, b) + } + } + } + if base == nil { + base = []any{} + } + r.K["path"] = base + } + }) + }) + + j.Rule("map", func(rs *jsonic.RuleSpec) { + rs.BO = append(rs.BO, func(r *jsonic.Rule, ctx *jsonic.Context) { + delete(r.K, "index") + }) + }) + + j.Rule("pair", func(rs *jsonic.RuleSpec) { + rs.AO = append(rs.AO, func(r *jsonic.Rule, ctx *jsonic.Context) { + if r.D > 0 && r.U["pair"] != nil { + key := r.U["key"] + parentPath := toPathSlice(r.K["path"]) + childPath := make([]any, len(parentPath)+1) + copy(childPath, parentPath) + childPath[len(parentPath)] = key + r.Child.K["path"] = childPath + r.Child.K["key"] = key + } + }) + }) + + j.Rule("list", func(rs *jsonic.RuleSpec) { + rs.BO = append(rs.BO, func(r *jsonic.Rule, ctx *jsonic.Context) { + r.K["index"] = -1 + }) + }) + + j.Rule("elem", func(rs *jsonic.RuleSpec) { + rs.AO = append(rs.AO, func(r *jsonic.Rule, ctx *jsonic.Context) { + if r.D > 0 { + idx := 0 + if v, ok := r.K["index"].(int); ok { + idx = v + 1 + } + r.K["index"] = idx + parentPath := toPathSlice(r.K["path"]) + childPath := make([]any, len(parentPath)+1) + copy(childPath, parentPath) + childPath[len(parentPath)] = idx + r.Child.K["path"] = childPath + r.Child.K["key"] = idx + r.Child.K["index"] = idx + } + }) + }) +} + +// MakeJsonic creates a Jsonic parser instance with the Path plugin. +func MakeJsonic() *jsonic.Jsonic { + j := jsonic.Make() + j.Use(Path, nil) + return j +} + +func toPathSlice(v any) []any { + if p, ok := v.([]any); ok { + return p + } + return []any{} +} diff --git a/go/path_test.go b/go/path_test.go new file mode 100644 index 0000000..ccbd478 --- /dev/null +++ b/go/path_test.go @@ -0,0 +1,212 @@ +/* Copyright (c) 2022-2025 Richard Rodger and other contributors, MIT License */ + +package path + +import ( + "fmt" + "reflect" + "strings" + "testing" + + jsonic "github.com/jsonicjs/jsonic/go" +) + +func assert(t *testing.T, name string, got, want any) { + t.Helper() + if !reflect.DeepEqual(got, want) { + t.Errorf("%s:\n got: %#v\n want: %#v", name, got, want) + } +} + +// addPathCapture adds a val AC callback that annotates nodes with path info. +func addPathCapture(j *jsonic.Jsonic) { + j.Rule("val", func(rs *jsonic.RuleSpec) { + rs.AC = append(rs.AC, func(r *jsonic.Rule, ctx *jsonic.Context) { + path := toPathSlice(r.K["path"]) + switch node := r.Node.(type) { + case map[string]any: + node["$"] = fmtPath(path) + case []any: + // Leave arrays as-is; elements are already annotated. + default: + r.Node = fmtValPath(r.Node, path) + } + }) + }) +} + +func TestHappy(t *testing.T) { + j := MakeJsonic() + result, err := j.Parse("{a:{b:1,c:[2,3]}}") + if err != nil { + t.Fatal(err) + } + m := result.(map[string]any) + a := m["a"].(map[string]any) + assert(t, "b", a["b"], float64(1)) +} + +func TestPathTracking(t *testing.T) { + j := jsonic.Make() + j.Use(Path, nil) + addPathCapture(j) + + result, err := j.Parse("{a:{b:1}}") + if err != nil { + t.Fatal(err) + } + + m := result.(map[string]any) + assert(t, "root-path", m["$"], "<>") + + a := m["a"].(map[string]any) + assert(t, "a-path", a["$"], "") + assert(t, "b-val", a["b"], "<1:a,b>") +} + +func TestMetaBasePath(t *testing.T) { + j := jsonic.Make() + j.Use(Path, nil) + + j.Rule("val", func(rs *jsonic.RuleSpec) { + rs.AC = append(rs.AC, func(r *jsonic.Rule, ctx *jsonic.Context) { + path := toPathSlice(r.K["path"]) + if node, ok := r.Node.(map[string]any); ok { + node["$"] = fmtPath(path) + } + }) + }) + + result, err := j.ParseMeta("{a:1}", map[string]any{ + "path": map[string]any{ + "base": []any{"x", "y"}, + }, + }) + if err != nil { + t.Fatal(err) + } + + m := result.(map[string]any) + assert(t, "root", m["$"], "") +} + +func TestObjectPaths(t *testing.T) { + j := jsonic.Make() + j.Use(Path, nil) + addPathCapture(j) + + result, err := j.Parse("{a:1}") + if err != nil { + t.Fatal(err) + } + m := result.(map[string]any) + assert(t, "root", m["$"], "<>") + assert(t, "a", m["a"], "<1:a>") + + result, err = j.Parse("{a:1,b:B}") + if err != nil { + t.Fatal(err) + } + m = result.(map[string]any) + assert(t, "root2", m["$"], "<>") + assert(t, "a2", m["a"], "<1:a>") + assert(t, "b2", m["b"], "") +} + +func TestNestedObjectPaths(t *testing.T) { + j := jsonic.Make() + j.Use(Path, nil) + addPathCapture(j) + + result, err := j.Parse("{x:{a:1}}") + if err != nil { + t.Fatal(err) + } + m := result.(map[string]any) + assert(t, "root", m["$"], "<>") + x := m["x"].(map[string]any) + assert(t, "x", x["$"], "") + assert(t, "x-a", x["a"], "<1:x,a>") +} + +func TestArrayPaths(t *testing.T) { + j := jsonic.Make() + j.Use(Path, nil) + addPathCapture(j) + + result, err := j.Parse("[1,2,3]") + if err != nil { + t.Fatal(err) + } + + arr, ok := result.([]any) + if !ok { + t.Fatalf("expected []any, got %T", result) + } + assert(t, "elem-0", arr[0], "<1:0>") + assert(t, "elem-1", arr[1], "<2:1>") + assert(t, "elem-2", arr[2], "<3:2>") +} + +func TestMakeJsonic(t *testing.T) { + j := MakeJsonic() + result, err := j.Parse("{a:1}") + if err != nil { + t.Fatal(err) + } + m, ok := result.(map[string]any) + if !ok { + t.Fatalf("expected map, got %T", result) + } + assert(t, "a", m["a"], float64(1)) +} + +// fmtPath formats a path slice as "". +func fmtPath(path []any) string { + parts := make([]string, len(path)) + for i, p := range path { + parts[i] = fmtKey(p) + } + return "<" + strings.Join(parts, ",") + ">" +} + +// fmtValPath formats a value with its path as "". +func fmtValPath(val any, path []any) string { + parts := make([]string, len(path)) + for i, p := range path { + parts[i] = fmtKey(p) + } + return "<" + fmtVal(val) + ":" + strings.Join(parts, ",") + ">" +} + +func fmtKey(v any) string { + switch k := v.(type) { + case string: + return k + case int: + return fmt.Sprintf("%d", k) + case float64: + if k == float64(int64(k)) { + return fmt.Sprintf("%d", int64(k)) + } + return fmt.Sprintf("%g", k) + default: + return fmt.Sprintf("%v", v) + } +} + +func fmtVal(v any) string { + switch val := v.(type) { + case string: + return val + case float64: + if val == float64(int64(val)) { + return fmt.Sprintf("%d", int64(val)) + } + return fmt.Sprintf("%g", val) + case bool: + return fmt.Sprintf("%t", val) + default: + return fmt.Sprintf("%v", v) + } +}