{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "source-evidence",
  "title": "Source evidence",
  "description": "Projection helpers that convert document sources, source maps, and source fields into evidence rows with resolved document anchors.",
  "registryDependencies": [
    "@retab/document-evidence",
    "@retab/document-source",
    "@retab/source-anchor"
  ],
  "files": [
    {
      "path": "registry/new-york-v4/ui/source-evidence.ts",
      "content": "import type * as React from \"react\";\nimport type { JSONSchema7 } from \"json-schema\";\n\nimport type { Source, SourceMap } from \"@/lib/document-source\";\n\nimport {\n  invalidEvidenceAnchor,\n  missingEvidenceAnchor,\n  resolvedEvidenceAnchor,\n  type AnchorResolution,\n  type EvidenceItem,\n} from \"./document-evidence\";\nimport { sourceToDocumentAnchor as sourceToResolvedDocumentAnchor } from \"./source-anchor\";\n\nexport type SourceEvidencePayload = {\n  label: string;\n  value?: React.ReactNode;\n  hint?: string;\n  sourceKind: Source[\"anchor\"][\"kind\"] | null;\n};\n\nexport type SourceEvidenceItem = EvidenceItem<SourceEvidencePayload>;\n\nexport type SourceEvidenceField = {\n  key: string;\n  label: string;\n  value: React.ReactNode;\n  hint?: string;\n  source?: Source | null;\n};\n\nexport type SourceEvidenceModel = {\n  evidenceItems: SourceEvidenceItem[];\n};\n\nexport function sourceToDocumentAnchor(\n  source: Source | null | undefined,\n): AnchorResolution {\n  if (!source) return missingEvidenceAnchor();\n\n  const anchor = sourceToResolvedDocumentAnchor(source);\n  if (anchor) return resolvedEvidenceAnchor(anchor);\n\n  return invalidEvidenceAnchor(`Unsupported or invalid ${source.anchor.kind}`);\n}\n\nexport function sourceFieldToEvidenceItem(\n  field: SourceEvidenceField,\n): SourceEvidenceItem {\n  return {\n    id: field.key,\n    anchor: sourceToDocumentAnchor(field.source),\n    payload: {\n      label: field.label,\n      value: field.value,\n      hint: field.hint,\n      sourceKind: field.source?.anchor.kind ?? null,\n    },\n  };\n}\n\nexport function sourceFieldsToEvidenceModel(\n  fields: readonly SourceEvidenceField[],\n): SourceEvidenceModel {\n  const evidenceItems = fields.map(sourceFieldToEvidenceItem);\n  return {\n    evidenceItems,\n  };\n}\n\nexport function sourceMapToEvidenceModel(input: {\n  sourceMap: SourceMap;\n  values?: Record<string, unknown>;\n  schema?: JSONSchema7;\n}): SourceEvidenceModel {\n  const evidenceItems = sourceMapToEvidenceItems(input);\n  return {\n    evidenceItems,\n  };\n}\n\nexport function sourceMapToEvidenceItems({\n  sourceMap,\n  values,\n  schema,\n}: {\n  sourceMap: SourceMap;\n  values?: Record<string, unknown>;\n  schema?: JSONSchema7;\n}): SourceEvidenceItem[] {\n  return Object.entries(sourceMap).map(([path, source]) => ({\n    id: path,\n    anchor: sourceToDocumentAnchor(source),\n    payload: {\n      label: (schemaLabel(schema, path) ?? path) || \"Value\",\n      value: values\n        ? sourceEvidenceValue(valueAtPath(values, path))\n        : undefined,\n      hint: source.anchor.kind,\n      sourceKind: source.anchor.kind,\n    },\n  }));\n}\n\nfunction schemaLabel(schema: JSONSchema7 | undefined, path: string) {\n  const properties = schema?.properties;\n  if (!properties || !path || path.includes(\".\")) return null;\n  const property = properties[path];\n  if (!property || typeof property === \"boolean\") return null;\n  return typeof property.title === \"string\" ? property.title : null;\n}\n\nfunction valueAtPath(values: Record<string, unknown>, path: string) {\n  if (!path) return values;\n  return path.split(\".\").reduce<unknown>((current, segment) => {\n    if (current == null) return undefined;\n    if (Array.isArray(current)) return current[Number(segment)];\n    if (typeof current === \"object\") {\n      return (current as Record<string, unknown>)[segment];\n    }\n    return undefined;\n  }, values);\n}\n\nfunction sourceEvidenceValue(value: unknown): React.ReactNode {\n  if (value == null) return undefined;\n  if (\n    typeof value === \"string\" ||\n    typeof value === \"number\" ||\n    typeof value === \"boolean\"\n  ) {\n    return value;\n  }\n  return JSON.stringify(value);\n}\n",
      "type": "registry:ui",
      "target": "@ui/source-evidence.ts"
    }
  ],
  "type": "registry:ui"
}