Add comprehensive documentation and improve cross-language parity#3
Merged
Conversation
Document TypeScript (src/util.ts) as the canonical implementation in a new CLAUDE.md and bring the Go port (go/util.go) into parity with it. Dependencies: - typescript ^5.9.3 -> ^6.0.3, @types/node 25.5.0 -> 25.9.2 (dist rebuilt) - go directive 1.21 -> 1.23 Go parity fixes: - toString: replace broken float formatting (it always produced "") and the hand-rolled intToString with strconv; render floats with FormatFloat 'f' to match JS String(); nil -> "" like Array.join - Pinify: keep the trailing ':' after a final even index, matching TS - GetPath: index []any via canonical non-negative integer segments only (rejects "01", "+1", ... like JS array indexing) - Stringify: de-cycle via Decircular first, matching TS stringify - human$ ordering: measure title padding in runes, not bytes - add DiveMap (the mapper form of TS dive) TypeScript: - order: drop unknown sort keys instead of leaving null holes in the result Tests added on both sides to lock the shared contract. Remaining intrinsic divergences (map iteration order, malformed-input handling) are documented in CLAUDE.md. https://claude.ai/code/session_01MWuia2drUKR7xEmhkpip3X
Documentation (docs/), organised so each section answers one kind of question:
- getting-started.md : guided, hands-on tutorial
- how-to-guides.md : task-focused recipes
- api-typescript.md : full TypeScript API reference
- api-go.md : full Go API reference
- explanation.md : design, the canonical/parity model, and the divergences
- README.md : documentation index
Agent files:
- AGENTS.md : repository conventions plus a scannable API quick-reference for AI
coding agents (single source of truth)
- CLAUDE.md : now defers to AGENTS.md
- README.md : rewritten from a stub into a real entry point
CI:
- ci/ci.yml : canonical workflow (Node 24+latest matrix and a Go build/vet/test job)
- ci/README.md: how to sync ci/ into .github/workflows/, working around the
workflow-scope restriction on direct pushes
https://claude.ai/code/session_01MWuia2drUKR7xEmhkpip3X
The two implementations now sit side by side: - ts/ TypeScript package (src, test, dist, dist-test, package.json, LICENSE) - go/ Go module Relative paths still resolve (tsconfig outDir ../dist, the test's '../' import), verified by installing, building, and testing from ts/. A LICENSE copy is kept in the package directory so it stays self-contained for npm publish. Updated to match: - ci/ci.yml : the Node job now runs with working-directory: ts - AGENTS.md, CLAUDE.md, README.md, docs/ : repository paths point at ts/... - .gitignore : anchored coverage paths moved under ts/ Note: the deployed .github/workflows/ci.yml still runs npm from the repo root and must be synced from ci/ci.yml (now working-directory: ts) or CI on main will fail after this move. https://claude.ai/code/session_01MWuia2drUKR7xEmhkpip3X
Determinism (the priority): - dive/Dive now iterate keys in sorted order in BOTH languages, so output is deterministic and byte-identical across the ports (Go map iteration was random). DiveMap and Entity inherit deterministic key-collision resolution, and Go's order sorts use SliceStable so ties break by (key-sorted) order. Correctness: - Go Entity: guard path length < 2 (was an index-out-of-range panic on a $-shaped ent); such entries are skipped, matching TS. - TS getdlog().log(file): filter on the file field, not the timestamp field (the filtered form previously always returned []). - TS dive: real overloads so the mapper form is typed Record<string,any>, not any[]. Robustness / no input mutation: - TS order and entity copy items before adding key/title$ (caller input is no longer mutated); both treat a missing title as empty rather than throwing. - TS decircular clones Errors (same prototype) instead of mutating them. - Go Decircular skips empty containers, removing the pointer-0 aliasing trap. Cleanup: - Go orderSort: single key lookup instead of an O(n^2) title$ rescan; drop the now-unused itemMap param. CamelifySlice drops a redundant copy. Fix the misleading Order comment and collapse Decircular's contradictory doc comment. - TS: remove the no-op padStart in prettyPino and the redundant seps guard. Tests: dive determinism (exact sorted order, stable under -count/-shuffle), getdlog filter, entity malformed-skip, order no-mutation, decircular empties. Docs updated throughout to describe deterministic, sorted dive. https://claude.ai/code/session_01MWuia2drUKR7xEmhkpip3X
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds extensive user-facing documentation for
@voxgiq/utiland improves the TypeScript and Go implementations to ensure deterministic, cross-language-identical behaviour. The library now ships with four documentation sections covering getting started, how-to guides, API references for both languages, and implementation details.Key Changes
Documentation (new)
docs/getting-started.md— hands-on walkthrough covering path helpers, tree traversal, collection ordering, and serializationdocs/how-to-guides.md— focused recipes for common tasks (flattening maps, reading nested values, sorting collections, etc.)docs/api-typescript.md— complete TypeScript API reference with examples for all exportsdocs/api-go.md— complete Go API reference with examples for all exportsdocs/explanation.md— background on the canonical/parity model, deliberate divergences between languages, and design rationaledocs/README.md— documentation indexAGENTS.md— dense guidance for AI coding agents and developers working in the repoCLAUDE.md— quick reference for Claude Codeci/README.md— explanation of CI workflow source-of-truth patternREADME.mdwith install instructions, quick examples, and documentation linksTypeScript (
ts/src/util.ts)dive()to iterate keys in sorted order for deterministic output matching Godive()to support both array and mapper return forms with proper typingprettyPino()formatting: removed incorrect.padStart()call that was breaking alignmentdiveInternal()to explicitly sort keys before iterationentity()for safer property accessGo (
go/util.go)Dive()to iterate keys in sorted order (previously randomized due to Go map iteration)DiveMap()function — the mapper form ofDive()that transforms entries through a callbackGetPath()to support array indexing via numeric path segments, matching TypeScript behaviourtoString()to handlenil,int64, andfloat64types correctly, matching JavaScript'sArray.join()semantics"01","+1","-1")CamelifySlice()to avoid unnecessary slice copyingTests
ts/test/util.test.tswith new test cases for:pinify()with odd-length paths (trailing:behaviour)joins()with various types (floats, booleans, null)dive()with mapper functionget()with array indexinggo/util_test.goto verify sorted key order inDive()output and added tests forDiveMap(), array indexing, and human-sort paddingts/dist-test/util.test.js)Build & CI
ci/ci.yml— GitHub Actions workflow testing Node 24 and latest, plus Go 1.23go/go.modto require Go 1.23@types/node25.9.2,typescript6.0.3ts/LICENSE(MIT).gitignorepaths to reflectts/subdirectory structureNotable Implementation Details
dive()implementations now sort keys before iteration, ensuring identical output across TypeScript and Go regardless of insertion order or map randomizationGetPath()in Go now supports array indexing with the same validation rules as TypeScript (canonical non-negative integers only)toString()in Go now matches JavaScript'sArray.join()semantics for all primitive types, ensuringjoins()output is identicalhttps://claude.ai/code/session_01MWuia2drUKR7xEmhkpip3X