@eventcatalog/diff 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COMPATIBILITY.md +257 -0
- package/LICENSE +31 -0
- package/README.md +210 -0
- package/dist/index.d.mts +244 -0
- package/dist/index.d.ts +244 -0
- package/dist/index.js +851 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +820 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/diff.ts","../src/utils/entities.ts","../src/edges.ts","../src/impact.ts","../src/utils/versions.ts","../src/resources.ts","../src/json-schema/compare.ts","../src/json-schema/rules.ts","../src/json-schema/index.ts","../src/schemas.ts","../src/types.ts"],"sourcesContent":["export { diff, DEFAULT_STRATEGY } from './diff';\nexport type { DiffOptions } from './diff';\nexport * from './types';\nexport { checkJsonSchemaCompatibility, compareJsonSchemas } from './json-schema';\nexport type { JsonSchema, JsonSchemaChange, JsonSchemaChangeKind, JsonSchemaCompatibility } from './json-schema';\nexport type { Index, IndexResource, IndexResourceType, IndexSchema, EdgeDirection } from '@eventcatalog/sdk';\n","import type { Index } from '@eventcatalog/sdk';\nimport { resolve } from '@eventcatalog/sdk';\nimport { diffEdges } from './edges';\nimport { impactOf } from './impact';\nimport { diffResources } from './resources';\nimport { diffSchemas } from './schemas';\nimport type { ArchitectureDiff, CompatibilityStrategy } from './types';\nimport { ARCHITECTURE_DIFF_SCHEMA_VERSION } from './types';\n\nexport type DiffOptions = {\n /**\n * Compatibility strategy used when comparing schemas. Defaults to `full`, so a\n * change is breaking if it could break either producers or consumers.\n */\n strategy?: CompatibilityStrategy;\n /**\n * Copy the raw before and after schema text onto each schema change, so a\n * consumer can render a side-by-side diff without going back to the index.\n * Off by default to keep the document small.\n */\n includeSchemaContent?: boolean;\n};\n\nexport const DEFAULT_STRATEGY: CompatibilityStrategy = 'full';\n\n/**\n * Compare two catalog indexes and return a single ArchitectureDiff document.\n *\n * `a` is the baseline (e.g. `main`) and `b` is the candidate (e.g. a PR branch).\n * Both are SDK `Index` documents as returned by `buildIndex()`. Build them with\n * `includeSchemaContent: true` to get schema compatibility verdicts.\n */\nexport const diff = (a: Index, b: Index, options: DiffOptions = {}): ArchitectureDiff => {\n const strategy = options.strategy ?? DEFAULT_STRATEGY;\n\n // Each side is resolved on its own so pointers (e.g. `version: latest`) become concrete edges.\n const graphA = resolve([a]);\n const graphB = resolve([b]);\n\n const resources = diffResources(a, b);\n const edges = diffEdges(graphA, graphB);\n const schemaChanges = diffSchemas(a, b, { strategy, includeSchemaContent: options.includeSchemaContent ?? false });\n const impact = impactOf({ baseline: graphA, schemaChanges, resourcesRemoved: resources.removed, edgesRemoved: edges.removed });\n\n const schemaBreaking = schemaChanges.filter((change) => change.breaking === true).length;\n const schemaUnknown = schemaChanges.filter((change) => change.breaking === null).length;\n // A message that disappears while services still produce or consume it is breaking, whatever the schema said.\n const messageRemoved = impact.some((entry) => entry.reason === 'message_removed');\n\n return {\n schemaVersion: ARCHITECTURE_DIFF_SCHEMA_VERSION,\n refs: {\n a: { source: a.source, commit: a.commit },\n b: { source: b.source, commit: b.commit },\n },\n compatibility: { strategy },\n summary: {\n breaking: schemaBreaking > 0 || messageRemoved,\n resourcesAdded: resources.added.length,\n resourcesRemoved: resources.removed.length,\n resourcesChanged: resources.changed.length,\n edgesAdded: edges.added.length,\n edgesRemoved: edges.removed.length,\n schemaChanges: schemaChanges.length,\n schemaBreaking,\n schemaUnknown,\n },\n resources,\n edges,\n schemaChanges,\n impact,\n };\n};\n","import type { ResolvedEntity, ResolvedGraph } from '@eventcatalog/sdk';\n\n/**\n * Constant-time entity lookup by id and version, built once per graph so impact\n * and edge reporting stay linear on catalogs with thousands of resources.\n */\nexport type EntityIndex = {\n find: (id: string, version: string | null) => ResolvedEntity | undefined;\n};\n\nexport const indexEntities = (graph: ResolvedGraph): EntityIndex => {\n const byIdAndVersion = new Map<string, ResolvedEntity>();\n const firstById = new Map<string, ResolvedEntity>();\n\n for (const entity of graph.entities) {\n byIdAndVersion.set(`${entity.id}@${entity.version ?? ''}`, entity);\n if (!firstById.has(entity.id)) firstById.set(entity.id, entity);\n }\n\n return {\n find: (id, version) => (version === null ? firstById.get(id) : byIdAndVersion.get(`${id}@${version}`)),\n };\n};\n","import type { ResolvedEdge, ResolvedGraph } from '@eventcatalog/sdk';\nimport type { DiffEdge, EdgeEnd } from './types';\nimport { indexEntities } from './utils/entities';\nimport type { EntityIndex } from './utils/entities';\n\nexport type EdgeDiff = {\n added: DiffEdge[];\n removed: DiffEdge[];\n};\n\n/**\n * Compares the resolved edges of two graphs, across every direction the SDK\n * resolves (sends, receives, writesTo, readsFrom, contains, references, appliesTo,\n * relatesTo).\n *\n * Edge identity is direction + via + from id + to id. Versions are deliberately\n * left out: they are already resolved, and including them would report a removed\n * and an added edge every time a message is bumped, drowning the real changes.\n * The versions shown on an edge are the ones from the side it came from.\n *\n * Resolution matters, though. When a message is deleted but a service still\n * points at it, the SDK keeps the edge and marks it unresolved. That edge has\n * effectively been removed, and is reported as such. The reverse, a dangling\n * pointer that now resolves because the target was documented, is an added edge.\n */\nexport const diffEdges = (a: ResolvedGraph, b: ResolvedGraph): EdgeDiff => {\n const before = byIdentity(a);\n const after = byIdentity(b);\n const entitiesA = indexEntities(a);\n const entitiesB = indexEntities(b);\n const added: DiffEdge[] = [];\n const removed: DiffEdge[] = [];\n\n for (const key of new Set([...before.keys(), ...after.keys()])) {\n const edgeA = before.get(key);\n const edgeB = after.get(key);\n\n if (!edgeA) added.push(toDiffEdge(entitiesB, edgeB!));\n else if (!edgeB) removed.push(toDiffEdge(entitiesA, edgeA));\n else if (isResolved(edgeA) && !isResolved(edgeB)) removed.push(toDiffEdge(entitiesA, edgeA));\n else if (!isResolved(edgeA) && isResolved(edgeB)) added.push(toDiffEdge(entitiesB, edgeB));\n }\n\n return { added: sort(added), removed: sort(removed) };\n};\n\nconst identity = (edge: ResolvedEdge) => `${edge.direction}|${edge.via ?? ''}|${edge.from}|${edge.to}`;\n\nconst isResolved = (edge: ResolvedEdge) => edge.status === 'resolved';\n\nconst byIdentity = (graph: ResolvedGraph) => {\n const map = new Map<string, ResolvedEdge>();\n for (const edge of graph.edges) {\n // Several versions of the same service can carry the same edge; a resolved one wins.\n const existing = map.get(identity(edge));\n if (!existing || (!isResolved(existing) && isResolved(edge))) map.set(identity(edge), edge);\n }\n return map;\n};\n\nconst toDiffEdge = (entities: EntityIndex, edge: ResolvedEdge): DiffEdge => ({\n direction: edge.direction,\n from: end(entities, edge.from, edge.fromVersion),\n to: end(entities, edge.to, edge.resolved),\n ...(edge.via !== undefined ? { via: edge.via } : {}),\n});\n\nconst end = (entities: EntityIndex, id: string, version: string | null): EdgeEnd => {\n const entity = entities.find(id, version);\n return {\n ...(entity ? { type: entity.type } : {}),\n id,\n ...(version !== null ? { version } : {}),\n };\n};\n\nconst sort = (edges: DiffEdge[]) =>\n [...edges].sort(\n (left, right) =>\n left.direction.localeCompare(right.direction) ||\n left.from.id.localeCompare(right.from.id) ||\n left.to.id.localeCompare(right.to.id) ||\n (left.via ?? '').localeCompare(right.via ?? '')\n );\n","import type { ResolvedEdge, ResolvedEntity, ResolvedGraph } from '@eventcatalog/sdk';\nimport type { DiffEdge, Impact, ImpactedResource, MessageType, ResourceRemoved, SchemaChange } from './types';\nimport { indexEntities } from './utils/entities';\nimport type { EntityIndex } from './utils/entities';\n\nconst MESSAGE_TYPES: ReadonlySet<string> = new Set<MessageType>(['event', 'command', 'query']);\n\nconst isMessageType = (type: string | undefined): type is MessageType => type !== undefined && MESSAGE_TYPES.has(type);\n\nexport type ImpactInput = {\n /** The resolved baseline graph: who produces and consumes what today. */\n baseline: ResolvedGraph;\n schemaChanges: SchemaChange[];\n resourcesRemoved: ResourceRemoved[];\n edgesRemoved: DiffEdge[];\n};\n\n/**\n * Works out who is hurt by the changes, so consumers of the diff never walk edges.\n *\n * Producers and consumers always come from the BASELINE graph: they are the services\n * that exist today, on the message that is about to change or disappear.\n *\n * schema_breaking_change a message schema broke; lists everyone on the compared version\n * message_removed a message (or one version of it) is gone; lists everyone still using it\n * consumer_removed a service stopped receiving a message that still exists\n * producer_removed a service stopped sending a message that still exists\n */\nexport const impactOf = ({ baseline, schemaChanges, resourcesRemoved, edgesRemoved }: ImpactInput): Impact[] => {\n const graph: Graph = { edges: baseline.edges, entities: indexEntities(baseline) };\n return [\n ...impactOfSchemaChanges(graph, schemaChanges),\n ...impactOfRemovedMessages(graph, resourcesRemoved),\n ...impactOfRemovedEdges(graph, edgesRemoved, resourcesRemoved),\n ];\n};\n\n/** The baseline edges plus a constant-time entity lookup. */\ntype Graph = { edges: ResolvedEdge[]; entities: EntityIndex };\n\n// ---------------------------------------------------------------------------\n// schema_breaking_change\n// ---------------------------------------------------------------------------\n\nconst impactOfSchemaChanges = (baseline: Graph, schemaChanges: SchemaChange[]): Impact[] =>\n schemaChanges\n .filter((change) => change.breaking === true && change.direction !== null)\n .map((change) => ({\n message: { type: change.message.type, id: change.message.id, version: change.message.version.a },\n reason: 'schema_breaking_change' as const,\n direction: change.direction!,\n producers: partiesOf(baseline, change.message.id, change.message.version.a, 'sends'),\n consumers: partiesOf(baseline, change.message.id, change.message.version.a, 'receives'),\n }));\n\n// ---------------------------------------------------------------------------\n// message_removed\n// ---------------------------------------------------------------------------\n\n/** A removed message with nobody left pointing at it is a tidy-up, not an impact, so those are skipped. */\nconst impactOfRemovedMessages = (baseline: Graph, resourcesRemoved: ResourceRemoved[]): Impact[] =>\n resourcesRemoved\n .filter((resource) => isMessageType(resource.type))\n .map((resource) => ({\n message: { type: resource.type as MessageType, id: resource.id, version: resource.version },\n reason: 'message_removed' as const,\n producers: partiesOf(baseline, resource.id, resource.version, 'sends'),\n consumers: partiesOf(baseline, resource.id, resource.version, 'receives'),\n }))\n .filter((impact) => impact.producers.length > 0 || impact.consumers.length > 0);\n\n// ---------------------------------------------------------------------------\n// consumer_removed / producer_removed\n// ---------------------------------------------------------------------------\n\n/**\n * A removed direct sends/receives edge whose message still exists. Edges lost because\n * the message itself was removed are already covered by message_removed.\n */\nconst impactOfRemovedEdges = (baseline: Graph, edgesRemoved: DiffEdge[], resourcesRemoved: ResourceRemoved[]): Impact[] => {\n const removedMessages = new Set(resourcesRemoved.filter((r) => isMessageType(r.type)).map((r) => r.id));\n const byMessage = new Map<string, Impact>();\n\n for (const edge of edgesRemoved) {\n if (edge.via !== undefined || !isMessageType(edge.to.type) || removedMessages.has(edge.to.id)) continue;\n if (edge.direction !== 'sends' && edge.direction !== 'receives') continue;\n\n const reason = edge.direction === 'receives' ? 'consumer_removed' : 'producer_removed';\n const key = `${reason}|${edge.to.type}:${edge.to.id}`;\n const impact = byMessage.get(key) ?? {\n message: { type: edge.to.type, id: edge.to.id },\n reason,\n producers: [],\n consumers: [],\n };\n\n const party = baseline.entities.find(edge.from.id, edge.from.version ?? null);\n if (party) (edge.direction === 'receives' ? impact.consumers : impact.producers).push(toImpactedResource(party));\n byMessage.set(key, impact);\n }\n\n return [...byMessage.values()].map((impact) => ({\n ...impact,\n producers: sortParties(impact.producers),\n consumers: sortParties(impact.consumers),\n }));\n};\n\n// ---------------------------------------------------------------------------\n// helpers\n// ---------------------------------------------------------------------------\n\nconst partiesOf = (\n graph: Graph,\n messageId: string,\n messageVersion: string | undefined,\n direction: ResolvedEdge['direction']\n): ImpactedResource[] =>\n sortParties(\n graph.edges\n // `via` edges are indirect (e.g. `sends.to` a channel, `receives.from` a service); only direct message edges count.\n .filter(\n (edge) =>\n edge.direction === direction && edge.via === undefined && edge.to === messageId && pointsAt(edge, messageVersion)\n )\n .map((edge) => graph.entities.find(edge.from, edge.fromVersion))\n .filter((entity): entity is ResolvedEntity => entity !== undefined)\n .map(toImpactedResource)\n );\n\n/** An edge counts when it resolved to the compared version, or could not be resolved at all. */\nconst pointsAt = (edge: ResolvedEdge, version: string | undefined) =>\n edge.resolved === null || version === undefined || edge.resolved === version;\n\nconst toImpactedResource = (entity: ResolvedEntity): ImpactedResource => ({\n type: entity.type,\n id: entity.id,\n ...(entity.version !== undefined ? { version: entity.version } : {}),\n ...(entity.owners !== undefined ? { owners: entity.owners } : {}),\n});\n\nconst sortParties = (parties: ImpactedResource[]) =>\n [...parties].sort((left, right) => left.id.localeCompare(right.id) || (left.version ?? '').localeCompare(right.version ?? ''));\n","import { coerce, compare, valid } from 'semver';\n\n/** Accepts strict semver and number-like versions such as `1`, `v1`, `1.2`. */\nconst toComparable = (version: string) => valid(version) ?? coerce(version)?.version ?? undefined;\n\n/**\n * Orders two version strings. Semver-like versions are compared numerically,\n * anything else falls back to a plain string compare so the result is still stable.\n */\nexport const compareVersions = (left: string | undefined, right: string | undefined): number => {\n const a = left ? toComparable(left) : undefined;\n const b = right ? toComparable(right) : undefined;\n\n if (a && b) return compare(a, b);\n return (left ?? '').localeCompare(right ?? '');\n};\n\n/** Picks the item with the highest version. */\nexport const latest = <T extends { version?: string }>(items: T[]): T | undefined =>\n items.reduce<T | undefined>(\n (best, item) => (best && compareVersions(best.version, item.version) >= 0 ? best : item),\n undefined\n );\n","import type { Index, IndexResource } from '@eventcatalog/sdk';\nimport type { ResourceAdded, ResourceChanged, ResourceField, ResourceRemoved } from './types';\nimport { compareVersions, latest } from './utils/versions';\n\nexport type ResourceDiff = {\n added: ResourceAdded[];\n removed: ResourceRemoved[];\n changed: ResourceChanged[];\n};\n\n/**\n * Compares the resources of two indexes.\n *\n * A resource is identified by type and id. Because an index carries every version\n * of a resource, the rules are:\n * - id only in the candidate: added (every version listed)\n * - id only in the baseline: removed (every version listed)\n * - id on both sides and the latest version differs: changed, with `version: { a, b }`\n * - id on both sides, same latest version, but name / owners / deprecated differ: changed\n * - an individual old version that appears or disappears while the id survives: added / removed\n */\nexport const diffResources = (a: Index, b: Index): ResourceDiff => {\n const before = byKey(a);\n const after = byKey(b);\n const added: ResourceAdded[] = [];\n const removed: ResourceRemoved[] = [];\n const changed: ResourceChanged[] = [];\n\n for (const key of new Set([...before.keys(), ...after.keys()])) {\n const versionsA = before.get(key) ?? [];\n const versionsB = after.get(key) ?? [];\n\n if (versionsA.length === 0) {\n added.push(...versionsB.map(ref));\n continue;\n }\n if (versionsB.length === 0) {\n removed.push(...versionsA.map(ref));\n continue;\n }\n\n const latestA = latest(versionsA)!;\n const latestB = latest(versionsB)!;\n const fields = changedFields(latestA, latestB);\n if (fields.length > 0) {\n changed.push({ type: latestA.type, id: latestA.id, version: { a: latestA.version, b: latestB.version }, fields });\n }\n\n // Old versions that came or went while the id itself survived. The latest pair is\n // already covered by `changed`, so skip those two.\n const has = (list: IndexResource[], version: string | undefined) => list.some((resource) => resource.version === version);\n for (const resource of versionsB) {\n if (resource !== latestB && !has(versionsA, resource.version)) added.push(ref(resource));\n }\n for (const resource of versionsA) {\n if (resource !== latestA && !has(versionsB, resource.version)) removed.push(ref(resource));\n }\n }\n\n return { added: sort(added), removed: sort(removed), changed: sort(changed) };\n};\n\nconst byKey = (index: Index) => {\n const map = new Map<string, IndexResource[]>();\n for (const resource of index.resources) {\n const key = `${resource.type}:${resource.id}`;\n map.set(key, [...(map.get(key) ?? []), resource]);\n }\n return map;\n};\n\nconst ref = (resource: IndexResource): ResourceAdded => ({\n type: resource.type,\n id: resource.id,\n ...(resource.version !== undefined ? { version: resource.version } : {}),\n});\n\nconst changedFields = (before: IndexResource, after: IndexResource): ResourceField[] => {\n const fields: ResourceField[] = [];\n if (before.version !== after.version) fields.push('version');\n if (before.name !== after.name) fields.push('name');\n if (stable(before.owners) !== stable(after.owners)) fields.push('owners');\n if (stable(before.deprecated) !== stable(after.deprecated)) fields.push('deprecated');\n return fields;\n};\n\nconst stable = (value: unknown) => JSON.stringify(value ?? null);\n\nconst sort = <T extends { type: string; id: string; version?: string | { a?: string } }>(items: T[]): T[] =>\n [...items].sort(\n (left, right) =>\n left.type.localeCompare(right.type) ||\n left.id.localeCompare(right.id) ||\n compareVersions(versionOf(left.version), versionOf(right.version))\n );\n\nconst versionOf = (version: string | { a?: string } | undefined) => (typeof version === 'object' ? version.a : version);\n","import type { JsonSchema, JsonSchemaChange, JsonSchemaChangeKind } from './types';\n\n/**\n * Walks two JSON schemas side by side and emits every semantic change found.\n *\n * This is deliberately rule-free: it only says *what* changed, never whether\n * that matters. `rules.ts` decides what is breaking under each strategy.\n *\n * Supported: properties, required (with `default`), type (including `integer`\n * within `number` and nullable unions), enum and const, the min/max constraint\n * families, pattern, format, multipleOf, uniqueItems, additionalProperties,\n * items and tuples (`items` array or `prefixItems`), oneOf, anyOf, allOf, local\n * `$ref` (changes reported once, at the definition), and boolean schemas.\n *\n * Annotations (title, description, examples, $comment, default ...) are ignored.\n * Keywords we cannot reason about are reported as `keyword.changed` so they are\n * never silently passed.\n */\nexport const compareJsonSchemas = (before: JsonSchema, after: JsonSchema): JsonSchemaChange[] => {\n const context: Context = { rootBefore: before, rootAfter: after, changes: [], visitedRefs: new Set() };\n walk(before, after, '', context);\n return context.changes;\n};\n\ntype ObjectSchema = { [keyword: string]: unknown };\n\ntype Context = {\n rootBefore: JsonSchema;\n rootAfter: JsonSchema;\n changes: JsonSchemaChange[];\n visitedRefs: Set<string>;\n};\n\n// ---------------------------------------------------------------------------\n// walk\n// ---------------------------------------------------------------------------\n\nconst walk = (beforeInput: JsonSchema, afterInput: JsonSchema, pointerInput: string, context: Context): void => {\n const { before, after, pointer, skip } = dereference(beforeInput, afterInput, pointerInput, context);\n if (skip) return;\n\n if (typeof before === 'boolean' || typeof after === 'boolean') {\n compareBooleanSchemas(before, after, pointer, context);\n return;\n }\n\n compareDeprecated(before, after, pointer, context);\n compareType(before, after, pointer, context);\n compareEnum(before, after, pointer, context);\n compareConstraints(before, after, pointer, context);\n compareProperties(before, after, pointer, context);\n compareRequired(before, after, pointer, context);\n compareAdditionalProperties(before, after, pointer, context);\n compareItems(before, after, pointer, context);\n compareUnion(before, after, pointer, 'oneOf', context);\n compareUnion(before, after, pointer, 'anyOf', context);\n compareAllOf(before, after, pointer, context);\n compareUnsupportedKeywords(before, after, pointer, context);\n};\n\nconst emit = (context: Context, change: JsonSchemaChange) => {\n context.changes.push(change);\n};\n\n// ---------------------------------------------------------------------------\n// $ref\n// ---------------------------------------------------------------------------\n\n/**\n * Resolves local `$ref`s on either side. When both sides are refs the changes are\n * reported at the definition's own path, once, so a definition used by ten\n * properties does not produce ten copies of the same change and recursive\n * schemas terminate.\n */\nconst dereference = (before: JsonSchema, after: JsonSchema, pointer: string, context: Context) => {\n const refBefore = refOf(before);\n const refAfter = refOf(after);\n if (refBefore === undefined && refAfter === undefined) return { before, after, pointer, skip: false };\n\n if (refBefore !== undefined && refAfter !== undefined) {\n const key = `${refBefore}|${refAfter}`;\n if (context.visitedRefs.has(key)) return { before, after, pointer, skip: true };\n context.visitedRefs.add(key);\n return {\n before: resolveRef(context.rootBefore, refBefore),\n after: resolveRef(context.rootAfter, refAfter),\n pointer: refAfter.slice(1),\n skip: false,\n };\n }\n\n return {\n before: refBefore !== undefined ? resolveRef(context.rootBefore, refBefore) : before,\n after: refAfter !== undefined ? resolveRef(context.rootAfter, refAfter) : after,\n pointer,\n skip: false,\n };\n};\n\n/** Only local refs (`#/...`) are followed. Anything else is left in place and reported by the unsupported-keyword check. */\nconst refOf = (schema: JsonSchema): string | undefined =>\n isObjectSchema(schema) && typeof schema.$ref === 'string' && schema.$ref.startsWith('#/') ? schema.$ref : undefined;\n\nconst MAX_REF_HOPS = 32;\n\n/**\n * Follows a local JSON pointer such as `#/definitions/Address`, and keeps following\n * if the target is itself a local ref. Unknown targets resolve to `true` (anything).\n */\nconst resolveRef = (root: JsonSchema, ref: string): JsonSchema => {\n let target = resolvePointer(root, ref);\n for (let hop = 0; hop < MAX_REF_HOPS; hop++) {\n const next = refOf(target);\n if (next === undefined) return target;\n target = resolvePointer(root, next);\n }\n return true;\n};\n\nconst resolvePointer = (root: JsonSchema, ref: string): JsonSchema => {\n let current: unknown = root;\n for (const segment of ref.slice(2).split('/')) {\n if (!isObjectSchema(current as JsonSchema)) return true;\n current = (current as ObjectSchema)[unescapePointer(segment)];\n }\n return current === undefined ? true : (current as JsonSchema);\n};\n\n// ---------------------------------------------------------------------------\n// boolean schemas: `true` accepts anything, `false` accepts nothing\n// ---------------------------------------------------------------------------\n\nconst compareBooleanSchemas = (before: JsonSchema, after: JsonSchema, pointer: string, context: Context) => {\n if (before === after) return;\n const relaxed = before === false || after === true;\n emit(context, { kind: relaxed ? 'schema.relaxed' : 'schema.restricted', path: pointer, before, after });\n};\n\n// ---------------------------------------------------------------------------\n// type\n// ---------------------------------------------------------------------------\n\nconst compareType = (before: ObjectSchema, after: ObjectSchema, pointer: string, context: Context) => {\n const typesBefore = typesOf(before);\n const typesAfter = typesOf(after);\n const path = `${pointer}/type`;\n\n if (typesBefore === undefined && typesAfter === undefined) return;\n if (typesBefore === undefined) {\n emit(context, { kind: 'type.narrowed', path, before: 'any', after: after.type });\n return;\n }\n if (typesAfter === undefined) {\n emit(context, { kind: 'type.widened', path, before: before.type, after: 'any' });\n return;\n }\n\n const afterCoversBefore = covers(typesAfter, typesBefore);\n const beforeCoversAfter = covers(typesBefore, typesAfter);\n if (afterCoversBefore && beforeCoversAfter) return;\n\n const kind: JsonSchemaChangeKind = afterCoversBefore ? 'type.widened' : beforeCoversAfter ? 'type.narrowed' : 'type.changed';\n emit(context, { kind, path, before: before.type, after: after.type });\n};\n\nconst typesOf = (schema: ObjectSchema): Set<string> | undefined => {\n if (schema.type === undefined) return undefined;\n return new Set(Array.isArray(schema.type) ? (schema.type as string[]) : [schema.type as string]);\n};\n\n/** Does `outer` accept every value that `inner` accepts? `number` covers `integer`. */\nconst covers = (outer: Set<string>, inner: Set<string>) =>\n [...inner].every((type) => outer.has(type) || (type === 'integer' && outer.has('number')));\n\n// ---------------------------------------------------------------------------\n// enum and const\n// ---------------------------------------------------------------------------\n\nconst compareEnum = (before: ObjectSchema, after: ObjectSchema, pointer: string, context: Context) => {\n const valuesBefore = enumOf(before);\n const valuesAfter = enumOf(after);\n const path = `${pointer}/enum`;\n\n if (valuesBefore === undefined && valuesAfter === undefined) return;\n if (valuesBefore === undefined) {\n emit(context, { kind: 'enum.added', path, after: valuesAfter });\n return;\n }\n if (valuesAfter === undefined) {\n emit(context, { kind: 'enum.removed', path, before: valuesBefore });\n return;\n }\n\n const keysBefore = new Set(valuesBefore.map(stableStringify));\n const keysAfter = new Set(valuesAfter.map(stableStringify));\n\n for (const value of valuesAfter) {\n if (!keysBefore.has(stableStringify(value))) emit(context, { kind: 'enum.value.added', path, after: value });\n }\n for (const value of valuesBefore) {\n if (!keysAfter.has(stableStringify(value))) emit(context, { kind: 'enum.value.removed', path, before: value });\n }\n};\n\nconst enumOf = (schema: ObjectSchema): unknown[] | undefined => {\n if (Array.isArray(schema.enum)) return schema.enum;\n if ('const' in schema) return [schema.const];\n return undefined;\n};\n\n// ---------------------------------------------------------------------------\n// constraints\n// ---------------------------------------------------------------------------\n\n/** A higher value accepts less. */\nconst MIN_CONSTRAINTS = ['minLength', 'minimum', 'exclusiveMinimum', 'minItems', 'minProperties'];\n/** A lower value accepts less. */\nconst MAX_CONSTRAINTS = ['maxLength', 'maximum', 'exclusiveMaximum', 'maxItems', 'maxProperties'];\n/** Present means constrained; a different value is a different constraint. */\nconst PRESENCE_CONSTRAINTS = ['pattern', 'format', 'multipleOf'];\n/** `true` means constrained. */\nconst FLAG_CONSTRAINTS = ['uniqueItems'];\n\nconst compareConstraints = (before: ObjectSchema, after: ObjectSchema, pointer: string, context: Context) => {\n for (const keyword of MIN_CONSTRAINTS) compareBound(before, after, pointer, keyword, 'higher-is-tighter', context);\n for (const keyword of MAX_CONSTRAINTS) compareBound(before, after, pointer, keyword, 'lower-is-tighter', context);\n for (const keyword of PRESENCE_CONSTRAINTS) comparePresence(before, after, pointer, keyword, context);\n for (const keyword of FLAG_CONSTRAINTS) compareFlag(before, after, pointer, keyword, context);\n};\n\nconst compareBound = (\n before: ObjectSchema,\n after: ObjectSchema,\n pointer: string,\n keyword: string,\n mode: 'higher-is-tighter' | 'lower-is-tighter',\n context: Context\n) => {\n const valueBefore = numberOrUndefined(before[keyword]);\n const valueAfter = numberOrUndefined(after[keyword]);\n if (valueBefore === valueAfter) return;\n\n const path = `${pointer}/${keyword}`;\n const change = { path, keyword, before: valueBefore, after: valueAfter };\n\n if (valueBefore === undefined) return emit(context, { kind: 'constraint.tightened', ...change });\n if (valueAfter === undefined) return emit(context, { kind: 'constraint.loosened', ...change });\n\n const tighter = mode === 'higher-is-tighter' ? valueAfter > valueBefore : valueAfter < valueBefore;\n emit(context, { kind: tighter ? 'constraint.tightened' : 'constraint.loosened', ...change });\n};\n\nconst comparePresence = (before: ObjectSchema, after: ObjectSchema, pointer: string, keyword: string, context: Context) => {\n const valueBefore = before[keyword];\n const valueAfter = after[keyword];\n if (stableStringify(valueBefore) === stableStringify(valueAfter)) return;\n\n const change = { path: `${pointer}/${keyword}`, keyword, before: valueBefore, after: valueAfter };\n if (valueBefore === undefined) return emit(context, { kind: 'constraint.tightened', ...change });\n if (valueAfter === undefined) return emit(context, { kind: 'constraint.loosened', ...change });\n emit(context, { kind: 'constraint.changed', ...change });\n};\n\nconst compareFlag = (before: ObjectSchema, after: ObjectSchema, pointer: string, keyword: string, context: Context) => {\n const flagBefore = before[keyword] === true;\n const flagAfter = after[keyword] === true;\n if (flagBefore === flagAfter) return;\n\n emit(context, {\n kind: flagAfter ? 'constraint.tightened' : 'constraint.loosened',\n path: `${pointer}/${keyword}`,\n keyword,\n before: flagBefore,\n after: flagAfter,\n });\n};\n\n// ---------------------------------------------------------------------------\n// properties and required\n// ---------------------------------------------------------------------------\n\nconst compareProperties = (before: ObjectSchema, after: ObjectSchema, pointer: string, context: Context) => {\n const propsBefore = propertiesOf(before);\n const propsAfter = propertiesOf(after);\n const names = new Set([...Object.keys(propsBefore), ...Object.keys(propsAfter)]);\n\n for (const name of names) {\n const path = `${pointer}/properties/${escapePointer(name)}`;\n const inBefore = name in propsBefore;\n const inAfter = name in propsAfter;\n\n if (!inBefore && inAfter) {\n // An old reader on a CLOSED schema rejects the unknown property in new messages.\n const kind: JsonSchemaChangeKind = isClosed(before) ? 'property.added-to-closed-object' : 'property.added';\n emit(context, { kind, path, after: propsAfter[name] });\n } else if (inBefore && !inAfter) {\n // A new reader on a CLOSED schema rejects old messages that still carry the property.\n const kind: JsonSchemaChangeKind = isClosed(after) ? 'property.removed-from-closed-object' : 'property.removed';\n emit(context, { kind, path, before: propsBefore[name] });\n } else {\n walk(propsBefore[name]!, propsAfter[name]!, path, context);\n }\n }\n};\n\n/** `additionalProperties: false`. A schema-valued additionalProperties is treated as open (lenient). */\nconst isClosed = (schema: ObjectSchema) => schema.additionalProperties === false;\n\n// ---------------------------------------------------------------------------\n// deprecated: an annotation, never breaking, but worth surfacing\n// ---------------------------------------------------------------------------\n\nconst compareDeprecated = (before: ObjectSchema, after: ObjectSchema, pointer: string, context: Context) => {\n if (before.deprecated !== true && after.deprecated === true) {\n emit(context, { kind: 'schema.deprecated', path: pointer, before: false, after: true });\n }\n};\n\nconst compareRequired = (before: ObjectSchema, after: ObjectSchema, pointer: string, context: Context) => {\n const requiredBefore = requiredOf(before);\n const requiredAfter = requiredOf(after);\n const propsAfter = propertiesOf(after);\n\n for (const name of requiredAfter) {\n if (requiredBefore.has(name)) continue;\n const property = propsAfter[name];\n const hasDefault = isObjectSchema(property as JsonSchema) && (property as ObjectSchema).default !== undefined;\n emit(context, {\n kind: hasDefault ? 'required.added-with-default' : 'required.added',\n path: `${pointer}/properties/${escapePointer(name)}`,\n before: false,\n after: true,\n });\n }\n for (const name of requiredBefore) {\n if (!requiredAfter.has(name)) {\n emit(context, {\n kind: 'required.removed',\n path: `${pointer}/properties/${escapePointer(name)}`,\n before: true,\n after: false,\n });\n }\n }\n};\n\nconst propertiesOf = (schema: ObjectSchema): Record<string, JsonSchema> =>\n isObjectSchema(schema.properties as JsonSchema) ? (schema.properties as Record<string, JsonSchema>) : {};\n\nconst requiredOf = (schema: ObjectSchema): Set<string> =>\n new Set(Array.isArray(schema.required) ? (schema.required as string[]) : []);\n\n// ---------------------------------------------------------------------------\n// additionalProperties: absent or `true` is open, `false` is closed, a schema is partially open\n// ---------------------------------------------------------------------------\n\nconst compareAdditionalProperties = (before: ObjectSchema, after: ObjectSchema, pointer: string, context: Context) => {\n const apBefore = (before.additionalProperties ?? true) as JsonSchema;\n const apAfter = (after.additionalProperties ?? true) as JsonSchema;\n const path = `${pointer}/additionalProperties`;\n\n if (apBefore !== false && apAfter === false) return emit(context, { kind: 'additionalProperties.closed', path });\n if (apBefore === false && apAfter !== false) return emit(context, { kind: 'additionalProperties.opened', path });\n walk(apBefore, apAfter, path, context);\n};\n\n// ---------------------------------------------------------------------------\n// arrays: `items` (schema), tuples (`items` array in draft-07, `prefixItems` in 2020-12)\n// ---------------------------------------------------------------------------\n\nconst compareItems = (before: ObjectSchema, after: ObjectSchema, pointer: string, context: Context) => {\n const tupleBefore = tupleOf(before);\n const tupleAfter = tupleOf(after);\n\n if (tupleBefore || tupleAfter) {\n const keyword = Array.isArray(after.items) || Array.isArray(before.items) ? 'items' : 'prefixItems';\n const itemsBefore = tupleBefore ?? [];\n const itemsAfter = tupleAfter ?? [];\n const shared = Math.min(itemsBefore.length, itemsAfter.length);\n\n for (let i = 0; i < shared; i++) walk(itemsBefore[i]!, itemsAfter[i]!, `${pointer}/${keyword}/${i}`, context);\n for (let i = shared; i < itemsAfter.length; i++) {\n emit(context, { kind: 'tuple.item.added', path: `${pointer}/${keyword}/${i}`, after: itemsAfter[i] });\n }\n for (let i = shared; i < itemsBefore.length; i++) {\n emit(context, { kind: 'tuple.item.removed', path: `${pointer}/${keyword}/${i}`, before: itemsBefore[i] });\n }\n }\n\n const schemaBefore = itemsSchemaOf(before);\n const schemaAfter = itemsSchemaOf(after);\n if (schemaBefore === undefined && schemaAfter === undefined) return;\n walk(schemaBefore ?? true, schemaAfter ?? true, `${pointer}/items`, context);\n};\n\nconst tupleOf = (schema: ObjectSchema): JsonSchema[] | undefined => {\n if (Array.isArray(schema.items)) return schema.items as JsonSchema[];\n if (Array.isArray(schema.prefixItems)) return schema.prefixItems as JsonSchema[];\n return undefined;\n};\n\nconst itemsSchemaOf = (schema: ObjectSchema): JsonSchema | undefined =>\n schema.items !== undefined && !Array.isArray(schema.items) ? (schema.items as JsonSchema) : undefined;\n\n// ---------------------------------------------------------------------------\n// composition\n// ---------------------------------------------------------------------------\n\nconst compareUnion = (\n before: ObjectSchema,\n after: ObjectSchema,\n pointer: string,\n keyword: 'oneOf' | 'anyOf',\n context: Context\n) => {\n compareBranches(before, after, pointer, keyword, 'union.branch.added', 'union.branch.removed', context);\n};\n\nconst compareAllOf = (before: ObjectSchema, after: ObjectSchema, pointer: string, context: Context) => {\n compareBranches(before, after, pointer, 'allOf', 'allOf.branch.added', 'allOf.branch.removed', context);\n};\n\n/**\n * Identical branches are matched first, wherever they sit, so reordering is not a\n * change. What is left is paired by position and walked when the counts agree, so\n * an edit inside one branch is reported precisely. Otherwise the leftovers are\n * reported as added or removed.\n */\nconst compareBranches = (\n before: ObjectSchema,\n after: ObjectSchema,\n pointer: string,\n keyword: 'oneOf' | 'anyOf' | 'allOf',\n addedKind: JsonSchemaChangeKind,\n removedKind: JsonSchemaChangeKind,\n context: Context\n) => {\n const branchesBefore = Array.isArray(before[keyword]) ? (before[keyword] as JsonSchema[]) : undefined;\n const branchesAfter = Array.isArray(after[keyword]) ? (after[keyword] as JsonSchema[]) : undefined;\n const path = `${pointer}/${keyword}`;\n\n if (branchesBefore === undefined && branchesAfter === undefined) return;\n if (branchesBefore === undefined) {\n // A union that did not exist now restricts values to its branches; an allOf adds constraints. Both tighten.\n return emit(context, { kind: 'constraint.tightened', path, keyword, after: branchesAfter });\n }\n if (branchesAfter === undefined) {\n return emit(context, { kind: 'constraint.loosened', path, keyword, before: branchesBefore });\n }\n\n const keysBefore = branchesBefore.map(stableStringify);\n const keysAfter = branchesAfter.map(stableStringify);\n const matchedAfter = new Set<number>();\n const unmatchedBefore: number[] = [];\n\n branchesBefore.forEach((_branch, i) => {\n const j = keysAfter.findIndex((key, index) => key === keysBefore[i] && !matchedAfter.has(index));\n if (j >= 0) matchedAfter.add(j);\n else unmatchedBefore.push(i);\n });\n const unmatchedAfter = branchesAfter.map((_branch, j) => j).filter((j) => !matchedAfter.has(j));\n\n if (unmatchedBefore.length === unmatchedAfter.length) {\n unmatchedBefore.forEach((i, n) => {\n const j = unmatchedAfter[n]!;\n walk(branchesBefore[i]!, branchesAfter[j]!, `${path}/${j}`, context);\n });\n return;\n }\n\n for (const j of unmatchedAfter) emit(context, { kind: addedKind, path: `${path}/${j}`, keyword, after: branchesAfter[j] });\n for (const i of unmatchedBefore) emit(context, { kind: removedKind, path: `${path}/${i}`, keyword, before: branchesBefore[i] });\n};\n\n// ---------------------------------------------------------------------------\n// keywords we do not reason about: report, never silently pass\n// ---------------------------------------------------------------------------\n\nconst UNSUPPORTED_KEYWORDS = [\n // Any $ref still present here is external (local ones were resolved). We cannot see its target.\n '$ref',\n 'patternProperties',\n 'propertyNames',\n 'not',\n 'if',\n 'then',\n 'else',\n 'dependentRequired',\n 'dependentSchemas',\n 'dependencies',\n 'contains',\n 'minContains',\n 'maxContains',\n 'unevaluatedProperties',\n 'unevaluatedItems',\n 'additionalItems',\n];\n\nconst compareUnsupportedKeywords = (before: ObjectSchema, after: ObjectSchema, pointer: string, context: Context) => {\n for (const keyword of UNSUPPORTED_KEYWORDS) {\n if (stableStringify(before[keyword]) === stableStringify(after[keyword])) continue;\n emit(context, {\n kind: 'keyword.changed',\n path: `${pointer}/${keyword}`,\n keyword,\n before: before[keyword],\n after: after[keyword],\n });\n }\n};\n\n// ---------------------------------------------------------------------------\n// helpers\n// ---------------------------------------------------------------------------\n\nconst isObjectSchema = (schema: JsonSchema | undefined): schema is ObjectSchema => typeof schema === 'object' && schema !== null;\n\nconst numberOrUndefined = (value: unknown): number | undefined => (typeof value === 'number' ? value : undefined);\n\n/** Deterministic JSON so two structurally equal values compare equal regardless of key order. */\nconst stableStringify = (value: unknown): string =>\n JSON.stringify(value, (_key, item) =>\n item && typeof item === 'object' && !Array.isArray(item)\n ? Object.fromEntries(Object.entries(item as Record<string, unknown>).sort(([a], [b]) => a.localeCompare(b)))\n : item\n ) ?? 'undefined';\n\n/** RFC 6901: `~` becomes `~0` and `/` becomes `~1` inside a pointer segment. */\nconst escapePointer = (segment: string) => segment.replace(/~/g, '~0').replace(/\\//g, '~1');\nconst unescapePointer = (segment: string) => segment.replace(/~1/g, '/').replace(/~0/g, '~');\n","import type { CompatibilityStrategy } from '../types';\nimport type { JsonSchemaChange, JsonSchemaChangeKind } from './types';\n\n/**\n * The business rules: which changes break which compatibility strategy.\n *\n * Definitions (as used by Confluent Schema Registry, which Kafka users expect):\n *\n * backward a consumer using the NEW schema can read messages written with the OLD schema\n * (consumers upgrade first)\n * forward a consumer using the OLD schema can read messages written with the NEW schema\n * (producers upgrade first)\n * full both of the above\n * none nothing is ever breaking\n *\n * Every row answers one question per direction: does the reader's schema accept\n * everything the writer's schema could have produced? A change that makes the\n * schema accept MORE is safe for backward and breaking for forward. A change that\n * makes it accept LESS is the reverse.\n *\n * Schemas are treated as having an open content model (`additionalProperties` not\n * `false`), which is the JSON Schema default: unknown properties are accepted. We\n * take Confluent's lenient reading of that model: adding a property is safe, on the\n * assumption that producers do not emit undeclared properties.\n * See https://docs.confluent.io/platform/current/schema-registry/fundamentals/serdes-develop/serdes-json.html\n *\n * To add a rule: add the kind to `JsonSchemaChangeKind`, emit it from `compare.ts`,\n * add a row here, add explicit tests under each strategy in\n * `src/test/json-schema/json-schema.test.ts`, and update the rules table in the\n * package README.\n */\ntype Rule = {\n backward: boolean;\n forward: boolean;\n reason: (change: JsonSchemaChange) => string;\n};\n\n/** Accepts more than before: safe for backward, breaking for forward. */\nconst WIDENS = { backward: false, forward: true };\n/** Accepts less than before: breaking for backward, safe for forward. */\nconst NARROWS = { backward: true, forward: false };\n/** Neither side can be trusted to read the other. */\nconst INCOMPATIBLE = { backward: true, forward: true };\n/** Safe both ways. */\nconst SAFE = { backward: false, forward: false };\n\nconst RULES: Record<JsonSchemaChangeKind, Rule> = {\n // --- properties -----------------------------------------------------------\n // Old messages simply don't have the property; new messages carry an extra one.\n 'property.added': { ...SAFE, reason: () => 'property added' },\n // The old schema was closed (additionalProperties: false), so an old reader rejects the new property.\n 'property.added-to-closed-object': {\n ...WIDENS,\n reason: () => 'property added to a closed object (old readers reject unknown properties)',\n },\n // Old messages still carry the property but the new schema ignores it; new messages lack\n // a property the old schema knew about but did not require.\n 'property.removed': { ...SAFE, reason: () => 'property removed' },\n // The new schema is closed, so a new reader rejects old messages that still carry the property.\n 'property.removed-from-closed-object': {\n ...NARROWS,\n reason: () => 'property removed from a closed object (new readers reject old messages that still carry it)',\n },\n // Old messages were written without the property, so a new consumer that requires it cannot read them.\n 'required.added': { ...NARROWS, reason: () => 'property became required' },\n // The new consumer fills the gap with the default, so old messages still read.\n 'required.added-with-default': { ...SAFE, reason: () => 'property became required but has a default' },\n // New messages may omit the property, so an old consumer that requires it cannot read them.\n 'required.removed': { ...WIDENS, reason: () => 'property is no longer required' },\n\n // --- types ----------------------------------------------------------------\n 'type.widened': { ...WIDENS, reason: (c) => `type widened from ${show(c.before)} to ${show(c.after)}` },\n 'type.narrowed': { ...NARROWS, reason: (c) => `type narrowed from ${show(c.before)} to ${show(c.after)}` },\n 'type.changed': { ...INCOMPATIBLE, reason: (c) => `type changed from ${show(c.before)} to ${show(c.after)}` },\n\n // --- enum and const -------------------------------------------------------\n 'enum.added': { ...NARROWS, reason: (c) => `values restricted to ${show(c.after)}` },\n 'enum.removed': { ...WIDENS, reason: () => 'enum restriction removed' },\n 'enum.value.added': { ...WIDENS, reason: (c) => `enum value ${show(c.after)} added` },\n 'enum.value.removed': { ...NARROWS, reason: (c) => `enum value ${show(c.before)} removed` },\n\n // --- constraints ----------------------------------------------------------\n 'constraint.tightened': {\n ...NARROWS,\n reason: (c) =>\n c.before === undefined\n ? `${c.keyword} added (${show(c.after)})`\n : `${c.keyword} tightened from ${show(c.before)} to ${show(c.after)}`,\n },\n 'constraint.loosened': {\n ...WIDENS,\n reason: (c) =>\n c.after === undefined ? `${c.keyword} removed` : `${c.keyword} loosened from ${show(c.before)} to ${show(c.after)}`,\n },\n 'constraint.changed': { ...INCOMPATIBLE, reason: (c) => `${c.keyword} changed from ${show(c.before)} to ${show(c.after)}` },\n\n // --- content model --------------------------------------------------------\n 'additionalProperties.closed': { ...NARROWS, reason: () => 'additional properties are no longer allowed' },\n 'additionalProperties.opened': { ...WIDENS, reason: () => 'additional properties are now allowed' },\n\n // --- arrays ---------------------------------------------------------------\n 'tuple.item.added': { ...NARROWS, reason: () => 'tuple position is now constrained' },\n 'tuple.item.removed': { ...WIDENS, reason: () => 'tuple position is no longer constrained' },\n\n // --- composition ----------------------------------------------------------\n 'union.branch.added': { ...WIDENS, reason: (c) => `${c.keyword} branch added` },\n 'union.branch.removed': { ...NARROWS, reason: (c) => `${c.keyword} branch removed` },\n 'allOf.branch.added': { ...NARROWS, reason: () => 'allOf branch added' },\n 'allOf.branch.removed': { ...WIDENS, reason: () => 'allOf branch removed' },\n\n // --- boolean schemas ------------------------------------------------------\n 'schema.restricted': { ...NARROWS, reason: () => 'schema now accepts fewer values' },\n 'schema.relaxed': { ...WIDENS, reason: () => 'schema now accepts more values' },\n\n // --- annotations ----------------------------------------------------------\n // Changes nothing about accepted values, but consumers of the diff want to see it.\n 'schema.deprecated': { ...SAFE, reason: () => 'marked as deprecated' },\n\n // --- unknown --------------------------------------------------------------\n // We cannot reason about it, so we refuse to call it safe.\n 'keyword.changed': { ...INCOMPATIBLE, reason: (c) => `${c.keyword} changed, compatibility cannot be determined` },\n};\n\nexport const isBreaking = (change: JsonSchemaChange, strategy: CompatibilityStrategy): boolean => {\n const rule = RULES[change.kind];\n switch (strategy) {\n case 'backward':\n return rule.backward;\n case 'forward':\n return rule.forward;\n case 'full':\n return rule.backward || rule.forward;\n case 'none':\n return false;\n }\n};\n\nexport const reasonFor = (change: JsonSchemaChange): string => RULES[change.kind].reason(change);\n\nconst show = (value: unknown): string => (typeof value === 'string' ? value : JSON.stringify(value));\n","import type { BreakingDirection, CompatibilityStrategy, SchemaOp } from '../types';\nimport { compareJsonSchemas } from './compare';\nimport { isBreaking, reasonFor } from './rules';\nimport type { JsonSchema, JsonSchemaChange, JsonSchemaChangeKind } from './types';\n\nexport type { JsonSchema, JsonSchemaChange, JsonSchemaChangeKind } from './types';\nexport { compareJsonSchemas } from './compare';\n\nexport type JsonSchemaCompatibility = {\n breaking: boolean;\n /** Which side the change breaks under the strategy, or `null` when it is not breaking. */\n direction: BreakingDirection | null;\n ops: SchemaOp[];\n};\n\n/**\n * Compare two JSON schemas and judge the result under a compatibility strategy.\n *\n * Returns every change as an op (so consumers can show what happened), a single\n * verdict (breaking if at least one op is breaking under the strategy) and the\n * direction that broke, so impact can say who is hurt.\n */\nexport const checkJsonSchemaCompatibility = (\n before: JsonSchema,\n after: JsonSchema,\n strategy: CompatibilityStrategy\n): JsonSchemaCompatibility => {\n const changes = compareJsonSchemas(before, after);\n const ops = changes.map((change) => toOp(change, strategy));\n\n const checksBackward = strategy === 'backward' || strategy === 'full';\n const checksForward = strategy === 'forward' || strategy === 'full';\n const breaksBackward = checksBackward && changes.some((change) => isBreaking(change, 'backward'));\n const breaksForward = checksForward && changes.some((change) => isBreaking(change, 'forward'));\n\n const direction: BreakingDirection | null =\n breaksBackward && breaksForward ? 'both' : breaksBackward ? 'backward' : breaksForward ? 'forward' : null;\n\n return { breaking: direction !== null, direction, ops };\n};\n\n/** `add` when only an after value exists, `remove` when only a before value exists, otherwise `replace`. */\nconst opFor = (change: JsonSchemaChange): SchemaOp['op'] => {\n if (change.before === undefined && change.after !== undefined) return 'add';\n if (change.before !== undefined && change.after === undefined) return 'remove';\n return 'replace';\n};\n\nconst toOp = (change: JsonSchemaChange, strategy: CompatibilityStrategy): SchemaOp => ({\n op: opFor(change),\n path: change.path,\n kind: change.kind,\n reason: reasonFor(change),\n breaking: isBreaking(change, strategy),\n});\n","import type { Index, IndexResource, IndexSchema } from '@eventcatalog/sdk';\nimport { checkJsonSchemaCompatibility } from './json-schema';\nimport type { JsonSchema } from './json-schema';\nimport type { CompatibilityStrategy, MessageType, SchemaChange, SchemaPointer } from './types';\nimport { compareVersions, latest } from './utils/versions';\n\nconst MESSAGE_TYPES: ReadonlySet<string> = new Set<MessageType>(['event', 'command', 'query']);\n\ntype Message = IndexResource & { type: MessageType };\n\nconst isMessage = (resource: IndexResource): resource is Message => MESSAGE_TYPES.has(resource.type);\n\nexport type DiffSchemasOptions = {\n strategy: CompatibilityStrategy;\n /** Copy the raw schema text onto `before` and `after` of each change. */\n includeSchemaContent: boolean;\n};\n\n/**\n * Finds every message schema that changed between the two indexes and judges each\n * change under the strategy.\n *\n * Which versions are compared:\n * - every version that exists on both sides, against itself (an in-place edit)\n * - the latest version on each side, when they differ (a version bump)\n *\n * Which schemas within a message are compared: see `pairSchemas`. A schema file\n * that exists on only one side is reported as added or removed, with no verdict.\n */\nexport const diffSchemas = (a: Index, b: Index, options: DiffSchemasOptions): SchemaChange[] => {\n const before = messagesByKey(a);\n const after = messagesByKey(b);\n const changes: SchemaChange[] = [];\n\n for (const [key, versionsA] of before) {\n const versionsB = after.get(key);\n if (!versionsB) continue;\n\n for (const [messageA, messageB] of pairVersions(versionsA, versionsB)) {\n changes.push(...diffMessageSchemas(messageA, messageB, options));\n }\n }\n\n return changes;\n};\n\n// ---------------------------------------------------------------------------\n// versions\n// ---------------------------------------------------------------------------\n\n/** Every version of each message, keyed by `type:id`. */\nconst messagesByKey = (index: Index) => {\n const byKey = new Map<string, Message[]>();\n for (const resource of index.resources) {\n if (!isMessage(resource)) continue;\n const key = `${resource.type}:${resource.id}`;\n byKey.set(key, [...(byKey.get(key) ?? []), resource]);\n }\n return byKey;\n};\n\n/** Exact version matches first (ordered by version), then the latest-to-latest bump if the latest versions differ. */\nconst pairVersions = (versionsA: Message[], versionsB: Message[]): Array<[Message, Message]> => {\n const byVersionB = new Map(versionsB.map((message) => [message.version, message]));\n const pairs: Array<[Message, Message]> = [];\n\n for (const messageA of [...versionsA].sort((left, right) => compareVersions(left.version, right.version))) {\n const messageB = byVersionB.get(messageA.version);\n if (messageB) pairs.push([messageA, messageB]);\n }\n\n const latestA = latest(versionsA);\n const latestB = latest(versionsB);\n if (latestA && latestB && latestA.version !== latestB.version) pairs.push([latestA, latestB]);\n\n return pairs;\n};\n\n// ---------------------------------------------------------------------------\n// schemas within a message\n// ---------------------------------------------------------------------------\n\nconst diffMessageSchemas = (messageA: Message, messageB: Message, options: DiffSchemasOptions): SchemaChange[] => {\n const { strategy, includeSchemaContent } = options;\n const message = { type: messageA.type, id: messageA.id, version: { a: messageA.version, b: messageB.version } };\n const changes: SchemaChange[] = [];\n\n for (const { before, after } of pairSchemas(messageA.schemas ?? [], messageB.schemas ?? [])) {\n if (before && after) {\n if (before.hash !== undefined && before.hash === after.hash) continue;\n changes.push({\n message,\n change: 'modified',\n before: pointer(before, includeSchemaContent),\n after: pointer(after, includeSchemaContent),\n strategy,\n ...judge(before, after, strategy),\n });\n } else if (after) {\n changes.push({ message, change: 'added', after: pointer(after, includeSchemaContent), strategy, ...UNKNOWN });\n } else if (before) {\n changes.push({ message, change: 'removed', before: pointer(before, includeSchemaContent), strategy, ...UNKNOWN });\n }\n }\n\n return changes;\n};\n\ntype SchemaPair = { before?: IndexSchema; after?: IndexSchema };\n\n/**\n * Pairs the schema files of a message across the two sides. In order:\n * 1. same `id`\n * 2. same `path`\n * 3. both flagged `default`\n * 4. exactly one unmatched schema on each side (a renamed file)\n * Anything still unmatched is an added or removed schema.\n */\nconst pairSchemas = (schemasA: IndexSchema[], schemasB: IndexSchema[]): SchemaPair[] => {\n const pairs: SchemaPair[] = [];\n let remainingA = [...schemasA];\n let remainingB = [...schemasB];\n\n const matchBy = (key: (schema: IndexSchema) => string | undefined) => {\n for (const before of [...remainingA]) {\n const keyA = key(before);\n if (keyA === undefined) continue;\n const after = remainingB.find((candidate) => key(candidate) === keyA);\n if (!after) continue;\n pairs.push({ before, after });\n remainingA = remainingA.filter((schema) => schema !== before);\n remainingB = remainingB.filter((schema) => schema !== after);\n }\n };\n\n matchBy((schema) => schema.id);\n matchBy((schema) => schema.path);\n matchBy((schema) => (schema.default ? 'default' : undefined));\n\n if (remainingA.length === 1 && remainingB.length === 1) {\n pairs.push({ before: remainingA[0]!, after: remainingB[0]! });\n remainingA = [];\n remainingB = [];\n }\n\n for (const before of remainingA) pairs.push({ before });\n for (const after of remainingB) pairs.push({ after });\n\n return pairs;\n};\n\nconst pointer = (schema: IndexSchema, includeContent: boolean): SchemaPointer => ({\n path: schema.path ?? '',\n hash: schema.hash,\n ...(includeContent && schema.content !== undefined ? { content: schema.content } : {}),\n});\n\n// ---------------------------------------------------------------------------\n// verdict\n// ---------------------------------------------------------------------------\n\nconst UNKNOWN: Pick<SchemaChange, 'breaking' | 'direction' | 'ops'> = { breaking: null, direction: null, ops: [] };\n\n/**\n * Judge a changed schema. Returns `breaking: null` when no verdict is possible:\n * the index was built without schema content, the content is not valid JSON, or\n * the format is not one we can compare yet.\n */\nconst judge = (\n before: IndexSchema,\n after: IndexSchema,\n strategy: CompatibilityStrategy\n): Pick<SchemaChange, 'breaking' | 'direction' | 'ops'> => {\n const beforeContent = asJsonSchema(before);\n const afterContent = asJsonSchema(after);\n if (beforeContent === undefined || afterContent === undefined) return UNKNOWN;\n\n return checkJsonSchemaCompatibility(beforeContent, afterContent, strategy);\n};\n\n/**\n * The parsed schema, or undefined when this is not a JSON Schema we can compare.\n * `format: 'json-schema'` is trusted. Without a format, a `.json` file counts only\n * when its content uses JSON Schema keywords, so an example payload stored as\n * `schema.json` is not walked as if it were a schema.\n */\nconst asJsonSchema = (schema: IndexSchema): JsonSchema | undefined => {\n if (schema.format !== undefined && schema.format !== 'json-schema') return undefined;\n if (schema.format === undefined && !(schema.path ?? '').endsWith('.json')) return undefined;\n\n const parsed = parseJson(schema.content);\n if (parsed === undefined) return undefined;\n if (schema.format === undefined && !looksLikeJsonSchema(parsed)) return undefined;\n return parsed;\n};\n\nconst SCHEMA_KEYWORDS = [\n '$schema',\n 'type',\n 'properties',\n 'items',\n 'required',\n 'enum',\n 'oneOf',\n 'anyOf',\n 'allOf',\n '$ref',\n 'definitions',\n '$defs',\n];\n\nconst looksLikeJsonSchema = (value: JsonSchema): boolean =>\n typeof value === 'boolean' || SCHEMA_KEYWORDS.some((keyword) => keyword in value);\n\nconst parseJson = (content: string | undefined): JsonSchema | undefined => {\n if (content === undefined) return undefined;\n try {\n const parsed: unknown = JSON.parse(content);\n return typeof parsed === 'boolean' || (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed))\n ? (parsed as JsonSchema)\n : undefined;\n } catch {\n return undefined;\n }\n};\n","/**\n * ArchitectureDiff\n *\n * The single versioned document produced by `diff(a, b)`. Consumers (CI actions,\n * policy engines, notifiers, UIs) build on top of this and never re-walk the graph.\n *\n * Input is the SDK `Index` returned by `buildIndex()`. Vocabulary follows the SDK:\n * resources have a `type`, edges have a `direction`.\n */\n\nimport type { EdgeDirection, IndexResourceType } from '@eventcatalog/sdk';\n\nexport const ARCHITECTURE_DIFF_SCHEMA_VERSION = 1 as const;\n\nexport type CompatibilityStrategy = 'backward' | 'forward' | 'full' | 'none';\n\n/** Which side a breaking change hurts. `both` only occurs under the `full` strategy. */\nexport type BreakingDirection = 'backward' | 'forward' | 'both';\n\n/** Resource types that carry schemas and travel along sends/receives edges. */\nexport type MessageType = Extract<IndexResourceType, 'event' | 'command' | 'query'>;\n\n/** Where an index came from: the SDK index `source` and `commit`. */\nexport type DiffRef = {\n source: string;\n commit: string;\n};\n\n/** A value that differs between the baseline (a) and the candidate (b). */\nexport type Change<T> = {\n a: T;\n b: T;\n};\n\nexport type DiffSummary = {\n breaking: boolean;\n resourcesAdded: number;\n resourcesRemoved: number;\n resourcesChanged: number;\n edgesAdded: number;\n edgesRemoved: number;\n schemaChanges: number;\n schemaBreaking: number;\n /** Schema changes with no verdict (`breaking: null`). Policy should decide whether these warn or fail. */\n schemaUnknown: number;\n};\n\nexport type ResourceRef = {\n type: IndexResourceType;\n id: string;\n version?: string;\n};\n\nexport type ResourceAdded = ResourceRef;\n\nexport type ResourceRemoved = ResourceRef;\n\n/** The fields of a resource the diff compares. Markdown content and schema files are covered elsewhere. */\nexport type ResourceField = 'version' | 'name' | 'owners' | 'deprecated';\n\nexport type ResourceChanged = {\n type: IndexResourceType;\n id: string;\n /** Latest version on each side. Equal when only metadata changed. */\n version: Change<string | undefined>;\n /** Which fields differ between the latest version on each side. */\n fields: ResourceField[];\n};\n\n/** One end of an edge. `type` is absent when the target could not be resolved in the index. */\nexport type EdgeEnd = {\n type?: IndexResourceType;\n id: string;\n version?: string;\n};\n\n/**\n * An edge between two resources, as resolved by the SDK. Identity ignores versions,\n * so bumping a message does not churn every edge that points at it.\n */\nexport type DiffEdge = {\n direction: EdgeDirection;\n from: EdgeEnd;\n to: EdgeEnd;\n /** The field the pointer came from when it is not the direction itself, e.g. `steps`. */\n via?: string;\n};\n\nexport type SchemaPointer = {\n path: string;\n hash?: string;\n /** Raw schema text. Only present when `diff()` is called with `includeSchemaContent: true`. */\n content?: string;\n};\n\nexport type SchemaOp = {\n op: 'add' | 'remove' | 'replace';\n /** JSON pointer into the schema document, e.g. `/properties/customerId`. */\n path: string;\n /** Stable machine-readable change kind, e.g. `required.added`, for consumers that key on it. */\n kind: string;\n /** Human-readable explanation. */\n reason: string;\n /** Whether this op alone breaks the chosen strategy. */\n breaking: boolean;\n};\n\nexport type SchemaChange = {\n message: {\n type: MessageType;\n id: string;\n version: Change<string | undefined>;\n };\n /** `modified` when the same schema file changed; `added` / `removed` when a schema file appeared or disappeared. */\n change: 'modified' | 'added' | 'removed';\n /** Absent when the schema was added. */\n before?: SchemaPointer;\n /** Absent when the schema was removed. */\n after?: SchemaPointer;\n /**\n * `null` when no verdict was possible: the schema was added or removed, the index was\n * built without schema content, the content is not valid JSON, or the format is not\n * one we can compare yet. Counted in `summary.schemaUnknown` so it is never silent.\n */\n breaking: boolean | null;\n strategy: CompatibilityStrategy;\n /** Which side the change breaks. `null` when not breaking or when no verdict was possible. */\n direction: BreakingDirection | null;\n ops: SchemaOp[];\n};\n\nexport type ImpactReason =\n | 'schema_breaking_change'\n | 'schema_changed'\n | 'message_removed'\n | 'producer_removed'\n | 'consumer_removed';\n\nexport type ImpactedResource = {\n type: IndexResourceType;\n id: string;\n version?: string;\n owners?: string[];\n};\n\n/**\n * Who a change hurts, derived from the baseline graph so consumers of the diff\n * never have to walk edges themselves.\n *\n * - `forward` breaking: the consumers listed are on the old schema and will fail\n * to read new messages.\n * - `backward` breaking: the consumers listed will fail to read old messages once\n * they move to the new schema (e.g. when replaying history).\n * - `both`: both of the above.\n */\nexport type Impact = {\n message: {\n type: MessageType;\n id: string;\n version?: string;\n };\n reason: ImpactReason;\n /** Which direction broke. Only present for schema-related reasons. */\n direction?: BreakingDirection;\n producers: ImpactedResource[];\n consumers: ImpactedResource[];\n};\n\nexport type ArchitectureDiff = {\n schemaVersion: typeof ARCHITECTURE_DIFF_SCHEMA_VERSION;\n refs: {\n a: DiffRef;\n b: DiffRef;\n };\n compatibility: {\n strategy: CompatibilityStrategy;\n };\n summary: DiffSummary;\n resources: {\n added: ResourceAdded[];\n removed: ResourceRemoved[];\n changed: ResourceChanged[];\n };\n edges: {\n added: DiffEdge[];\n removed: DiffEdge[];\n };\n schemaChanges: SchemaChange[];\n impact: Impact[];\n};\n"],"mappings":"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","names":["sort","pointer","ref","MESSAGE_TYPES","byKey"]}
|