{"_id":"@accesslint/heal-diff","_rev":"2-d2fb1dd0f24d9d56f3c4b5dc70a5b1cc","name":"@accesslint/heal-diff","dist-tags":{"latest":"0.3.0"},"versions":{"0.2.1":{"name":"@accesslint/heal-diff","version":"0.2.1","keywords":["diff","baseline","snapshot","healing","selector","accesslint"],"license":"MIT","_id":"@accesslint/heal-diff@0.2.1","maintainers":[{"name":"ckundo","email":"cameron@accesslint.com"}],"homepage":"https://github.com/AccessLint/accesslint#readme","bugs":{"url":"https://github.com/AccessLint/accesslint/issues"},"dist":{"shasum":"9e668ce8771b52e1016a52cf508b2bfc2e2f8937","tarball":"https://registry.npmjs.org/@accesslint/heal-diff/-/heal-diff-0.2.1.tgz","fileCount":10,"integrity":"sha512-PCpfZpewCUIJCidU9MxgXWSvgehfpuv/v2QR6YPuSbwSaUc6MaDnaDsaxjk+CPnD5d10D6GErrqOvoQLC/QXpw==","signatures":[{"sig":"MEUCID7W1ludkwI2ML75za++gzSKYpROrJWZuRa51pyK/FBpAiEAyUpNiRRow3/Fmp5MTIX0BvBWkqbNxoCIsPJfdaqvDLw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":40240},"type":"module","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./normalize":{"import":{"types":"./dist/normalize.d.ts","default":"./dist/normalize.js"},"require":{"types":"./dist/normalize.d.cts","default":"./dist/normalize.cjs"}}},"gitHead":"0ccd291bd0e015931bf3105818db4b86f1a7263b","scripts":{"test":"vitest run","build":"tsdown","typecheck":"tsc --noEmit","prepublishOnly":"bun run build"},"_npmUser":{"name":"ckundo","email":"cameron@accesslint.com"},"repository":{"url":"git+https://github.com/AccessLint/accesslint.git","type":"git","directory":"heal-diff"},"_npmVersion":"11.9.0","description":"Multi-signal diff engine for baseline/current sets with tiered matching, auto-healing, and likely-moved detection.","directories":{},"_nodeVersion":"24.14.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsdown":"^0.21.9","vitest":"^3.0.0","typescript":"^5.7.0"},"_npmOperationalInternal":{"tmp":"tmp/heal-diff_0.2.1_1785109239355_0.48036731600216753","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@accesslint/heal-diff","version":"0.3.0","description":"Multi-signal diff engine for baseline/current sets with tiered matching, auto-healing, and likely-moved detection.","license":"MIT","type":"module","repository":{"type":"git","url":"git+https://github.com/AccessLint/accesslint.git","directory":"heal-diff"},"bugs":{"url":"https://github.com/AccessLint/accesslint/issues"},"publishConfig":{"access":"public"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./normalize":{"import":{"types":"./dist/normalize.d.ts","default":"./dist/normalize.js"},"require":{"types":"./dist/normalize.d.cts","default":"./dist/normalize.cjs"}}},"scripts":{"build":"tsdown","test":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"bun run build"},"devDependencies":{"tsdown":"^0.21.9","typescript":"^5.7.0","vitest":"^3.0.0"},"keywords":["diff","baseline","snapshot","healing","selector","accesslint"],"gitHead":"96d43dd4686a9adc41d312006dc9c922adcb8204","_id":"@accesslint/heal-diff@0.3.0","homepage":"https://github.com/AccessLint/accesslint#readme","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-nF5ceODFjiU6G90vteLjZuv5ADMelDjXDn1sgz49Dqh6HCVG2cScYj57t2cJt0wh0DpEQLHK930uYssPk6FkCQ==","shasum":"e51ea1ad94770a6e518bfff8bd9cb3b61663739a","tarball":"https://registry.npmjs.org/@accesslint/heal-diff/-/heal-diff-0.3.0.tgz","fileCount":10,"unpackedSize":47300,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@accesslint%2fheal-diff@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDnZYl6JVcJTK0nB4VDfeDb00/avXBJ2JZ1vXAN5gRpPQIgShcAX2r7b/GhBuE3tA1jyKCc3hjwjwCj+ae0Ub+Y5fs="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:ccec0d67-b2a3-46c6-99d8-00861a61a81d"}},"directories":{},"maintainers":[{"name":"ckundo","email":"cameron@accesslint.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/heal-diff_0.3.0_1785160511943_0.01201104240146278"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-26T23:40:39.221Z","modified":"2026-07-27T13:55:12.460Z","0.2.1":"2026-07-26T23:40:39.488Z","0.3.0":"2026-07-27T13:55:12.074Z"},"bugs":{"url":"https://github.com/AccessLint/accesslint/issues"},"license":"MIT","homepage":"https://github.com/AccessLint/accesslint#readme","keywords":["diff","baseline","snapshot","healing","selector","accesslint"],"repository":{"type":"git","url":"git+https://github.com/AccessLint/accesslint.git","directory":"heal-diff"},"description":"Multi-signal diff engine for baseline/current sets with tiered matching, auto-healing, and likely-moved detection.","maintainers":[{"name":"ckundo","email":"cameron@accesslint.com"}],"readme":"# @accesslint/heal-diff\n\nMulti-signal diff engine for baseline/current item sets. Given two lists of items and an ordered list of tiers, partition the union into `matched`, `healed`, `fixed`, `new`, and `likelyMoved`. Each tier names a subset of signal keys that must all match; matches at a heal-flagged tier land in `healed` alongside the replacement pair so callers can rewrite their baseline.\n\nIndependent of DOM, accessibility, file formats, and node builtins — every module is browser-safe and bundles into in-page scripts unchanged. Built for [`@accesslint/jest`](../jest), [`@accesslint/vitest`](../vitest), and [`@accesslint/playwright`](../playwright) snapshot baselines, but applicable to any \"identified set that drifts over time\" problem (visual regression baselines, performance budgets, anywhere you want selector healing).\n\n## Usage\n\n```ts\nimport { diff, buildTier, type DiffItem } from \"@accesslint/heal-diff\";\n\ntype Sig = \"selector\" | \"anchor\" | \"htmlFingerprint\";\n\nconst baseline: DiffItem<Sig>[] = [\n  { id: \"img-alt\", signals: { selector: \"body > img\", anchor: \"data-testid=hero\" } },\n];\nconst current: DiffItem<Sig>[] = [\n  { id: \"img-alt\", signals: { selector: \"main > figure > img\", anchor: \"data-testid=hero\" } },\n];\n\nconst result = diff(baseline, current, [\n  buildTier({ name: \"exact\", key: [\"id\", \"selector\"], heal: false }),\n  buildTier({ name: \"anchor\", key: [\"id\", \"anchor\"], heal: true }),\n]);\n\n// result.healed[0] = { baseline, current, tier: \"anchor\" }\n```\n\n## API\n\n- `diff(baseline, current, tiers, options?)` — main entry point.\n- `buildTier({ name, key, heal, uniquenessGated?, verifiedBy? })` — small tier constructor.\n- `normalizeHtml(html)` + `sha1Short(s)` — optional utilities for building HTML-fingerprint signals (import from `@accesslint/heal-diff/normalize`). `NORMALIZE_VERSION` identifies the normalization algorithm; fingerprints stored under an older version should be treated as cold. `isFingerprintableTag(tag)` names the elements whose snippets are page-scoped (`html`, `body`) and should not carry a fingerprint signal.\n\nEach tier walks the remaining (unmatched) baseline and current items in tandem. Matching is count-based, so duplicate items are preserved. A tier with `heal: true` rewrites the baseline entry to the current-run item when it matches; a tier with `uniquenessGated: true` only matches when exactly one baseline candidate shares the tier key.\n\nA tier with `verifiedBy: <signal>` refuses a candidate pair whose values for that signal both exist and disagree, releasing both items to later tiers (refuse-and-release). This catches impostors and swaps: two elements that exchanged addresses fail verification at the address tier and heal back to their true partners at a content tier. Either side lacking the signal leaves the match standing (missing-signal leniency), so signal-less baseline rows still match by the tier key alone.\n\nUnmatched current items that share two-or-more of `tag`, `htmlFingerprint`, or `relativeLocation` with any unmatched baseline item are returned as `likelyMoved` hints for downstream rendering. No pass/fail change.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}