Skip to content

SchemaRegistry.findDuplicates

Declaration

ts
registry.findDuplicates(): ReadonlyArray<{
  schemaId: string;
  pointer: string;
  equivalentTo: string;
  shape: Record<string, unknown>;
}>

Returns a report of inline shapes that structurally match a registered top-level schema. Pure - does not mutate the registry. Run on demand at any point after registration.

Use this when

You want to audit an existing schema set for inline shapes that duplicate a named schema. The output drives an extract-and-$ref-replace refactor: each entry tells you exactly which schema, which JSON pointer, and which named schema the inline shape would be equivalent to.

/**
 * findDuplicates — Example 1: One-shot audit of the bookstore registry
 * Demonstrates: findDuplicates() returns an array, each entry has schemaId/pointer/equivalentTo
 *
 * The canonical bookstore registry is structured to avoid inline shapes that
 * duplicate named schemas — all primitives are extracted and $ref'd. Running
 * findDuplicates() confirms the registry is clean. The result type is shown
 * via console.assert on the array.
 */

import { bookstoreEntities } from '../bookstore/index.js';

const dups = bookstoreEntities.registry.findDuplicates();

// The bookstore registry uses named $ref schemas throughout — no inline duplicates.
for (const dup of dups) {
  console.log(`${dup.schemaId}#${dup.pointer} duplicates ${dup.equivalentTo}`);
}

console.assert(Array.isArray(dups));
// A well-structured registry with all shapes extracted should have zero duplicates.
console.assert(dups.length === 0);

console.log('duplicate count:', dups.length);
console.log('registry is clean:', dups.length === 0);
Output
Press Execute to run this example against the real library.

Don't use this when

You want continuous enforcement at registration time - prefer enableDuplicateDetection (warn) or enableStrictGraph (throw) instead. Don't use it as a validator for instance data; it inspects schema structure, not values.

Examples

Example 1: One-shot audit

/**
 * findDuplicates — Example 1: One-shot audit of the bookstore registry
 * Demonstrates: findDuplicates() returns an array, each entry has schemaId/pointer/equivalentTo
 *
 * The canonical bookstore registry is structured to avoid inline shapes that
 * duplicate named schemas — all primitives are extracted and $ref'd. Running
 * findDuplicates() confirms the registry is clean. The result type is shown
 * via console.assert on the array.
 */

import { bookstoreEntities } from '../bookstore/index.js';

const dups = bookstoreEntities.registry.findDuplicates();

// The bookstore registry uses named $ref schemas throughout — no inline duplicates.
for (const dup of dups) {
  console.log(`${dup.schemaId}#${dup.pointer} duplicates ${dup.equivalentTo}`);
}

console.assert(Array.isArray(dups));
// A well-structured registry with all shapes extracted should have zero duplicates.
console.assert(dups.length === 0);

console.log('duplicate count:', dups.length);
console.log('registry is clean:', dups.length === 0);
Output
Press Execute to run this example against the real library.

Example 2: CI gate

/**
 * findDuplicates — Example 2: CI gate — exit non-zero when duplicates found
 * Demonstrates: using findDuplicates() as a quality gate in a build script
 *
 * In a real CI pipeline a non-empty result would log each duplicate and
 * call `process.exit(1)`. This file mirrors that shape without actually
 * exiting so the docs smoke suite can import it.
 */

import { bookstoreEntities } from '../bookstore/index.js';

const dups = bookstoreEntities.registry.findDuplicates();

const lines: string[] = [];

for (const dup of dups) {
  lines.push(`  ${dup.schemaId}#${dup.pointer} duplicates ${dup.equivalentTo}`);
}

// In a CI script: `if (dups.length > 0) process.exit(1)`. The example
// captures the boolean instead so importing the file is safe.
const shouldFail = dups.length > 0;

console.assert(typeof shouldFail === 'boolean', 'CI gate result is a boolean');
console.assert(Array.isArray(lines), 'lines is the array a CI script would print');

console.log('duplicates found:', dups.length);
console.log('CI gate would fail:', shouldFail);
if (lines.length > 0) {
  for (const line of lines) {
    console.log(line);
  }
} else {
  console.log('no duplicates - registry is clean');
}
Output
Press Execute to run this example against the real library.

Comparison

ts
const dups = jt.registry.findDuplicates();
// Returns [{ schemaId, pointer, equivalentTo, shape }] — structural, JSON Pointer-addressed.
// Pure — no mutation. Run at any point after registration.
ts
// Zod has no built-in duplicate-detection. All schemas are independent runtime
// objects; structural equivalence is not tracked. You would need to implement
// a manual deep-equal check across all schema definitions.
// Limitation: no registry; no JSON Pointer addresses; no concept of inline vs. named.
ts
// Valibot has no duplicate-detection. Schemas are plain objects; no registry
// maintains structural identity. Manual comparison requires traversing the
// schema tree yourself.
// Limitation: no first-class registry; no inline-vs-named concept.
ts
// AJV does not track structural equivalence across registered schemas.
// You can inspect ajv.schemas (internal map), but there is no API to detect
// inline shapes that duplicate a named schema.
// Limitation: no findDuplicates equivalent; structural comparison must be
// hand-rolled against the raw schema objects.
ts
// TypeBox schemas are plain JSON Schema objects. TypeBox has no registry
// and no duplicate-detection API. A CI lint script must compare schema
// definitions manually via deep-equal.
// Limitation: no registry; no pointer-addressed duplicate report.
ts
// json-schema-to-typescript generates TypeScript types but does not detect
// duplicate inline shapes. Structural drift between inline definitions and
// named schemas is invisible until generated types diverge.
// Limitation: no runtime registry; no findDuplicates API.
py
# Limitation: feature not directly supported in Pydantic. See /comparisons for the matrix.
ts
// Limitation: feature not directly supported in Yup. See /comparisons for the matrix.
ts
// Limitation: feature not directly supported in Joi. See /comparisons for the matrix.
ts
// Limitation: feature not directly supported in io-ts. See /comparisons for the matrix.
ts
// Limitation: feature not directly supported in Effect Schema. See /comparisons for the matrix.
ts
// Limitation: feature not directly supported in ArkType. See /comparisons for the matrix.
ts
// Limitation: feature not directly supported in Runtypes. See /comparisons for the matrix.

See also

Released under the MIT License.