structural-codes-viewer 0.1.0-alpha.1 → 0.1.0-alpha.2

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.
Files changed (135) hide show
  1. package/LICENSE +501 -0
  2. package/NOTICE +16 -0
  3. package/README.md +119 -63
  4. package/package-dist/CorpusContent.d.ts +44 -9
  5. package/package-dist/CorpusContent.js +452 -26
  6. package/package-dist/CorpusContent.js.map +1 -1
  7. package/package-dist/NormativeViewer.d.ts +23 -2
  8. package/package-dist/NormativeViewer.js +1699 -234
  9. package/package-dist/NormativeViewer.js.map +1 -1
  10. package/package-dist/ReferenceTools.d.ts +49 -0
  11. package/package-dist/ReferenceTools.js +14 -0
  12. package/package-dist/ReferenceTools.js.map +1 -0
  13. package/package-dist/annotations/AnnotationUi.d.ts +57 -0
  14. package/package-dist/annotations/AnnotationUi.js +114 -0
  15. package/package-dist/annotations/AnnotationUi.js.map +1 -0
  16. package/package-dist/annotations/annotationTargets.d.ts +39 -0
  17. package/package-dist/annotations/annotationTargets.js +94 -0
  18. package/package-dist/annotations/annotationTargets.js.map +1 -0
  19. package/package-dist/annotations/exportImport.d.ts +6 -0
  20. package/package-dist/annotations/exportImport.js +30 -0
  21. package/package-dist/annotations/exportImport.js.map +1 -0
  22. package/package-dist/annotations/index.d.ts +4 -0
  23. package/package-dist/annotations/index.js +5 -0
  24. package/package-dist/annotations/index.js.map +1 -0
  25. package/package-dist/annotations/indexedDb.d.ts +21 -0
  26. package/package-dist/annotations/indexedDb.js +210 -0
  27. package/package-dist/annotations/indexedDb.js.map +1 -0
  28. package/package-dist/annotations/schema.d.ts +8 -0
  29. package/package-dist/annotations/schema.js +102 -0
  30. package/package-dist/annotations/schema.js.map +1 -0
  31. package/package-dist/annotations/types.d.ts +52 -0
  32. package/package-dist/annotations/types.js +18 -0
  33. package/package-dist/annotations/types.js.map +1 -0
  34. package/package-dist/chatntc/canonicalization.d.ts +15 -0
  35. package/package-dist/chatntc/canonicalization.js +107 -0
  36. package/package-dist/chatntc/canonicalization.js.map +1 -0
  37. package/package-dist/chatntc/directives.d.ts +2 -0
  38. package/package-dist/chatntc/directives.js +38 -0
  39. package/package-dist/chatntc/directives.js.map +1 -0
  40. package/package-dist/chatntc/evidence.d.ts +17 -0
  41. package/package-dist/chatntc/evidence.js +116 -0
  42. package/package-dist/chatntc/evidence.js.map +1 -0
  43. package/package-dist/chatntc/index.d.ts +10 -0
  44. package/package-dist/chatntc/index.js +9 -0
  45. package/package-dist/chatntc/index.js.map +1 -0
  46. package/package-dist/chatntc/issueCategories.d.ts +2 -0
  47. package/package-dist/chatntc/issueCategories.js +11 -0
  48. package/package-dist/chatntc/issueCategories.js.map +1 -0
  49. package/package-dist/chatntc/policy.d.ts +35 -0
  50. package/package-dist/chatntc/policy.js +36 -0
  51. package/package-dist/chatntc/policy.js.map +1 -0
  52. package/package-dist/chatntc/provider.d.ts +42 -0
  53. package/package-dist/chatntc/provider.js +2 -0
  54. package/package-dist/chatntc/provider.js.map +1 -0
  55. package/package-dist/chatntc/responseContract.d.ts +52 -0
  56. package/package-dist/chatntc/responseContract.js +73 -0
  57. package/package-dist/chatntc/responseContract.js.map +1 -0
  58. package/package-dist/chatntc/retrieval.d.ts +5 -0
  59. package/package-dist/chatntc/retrieval.js +220 -0
  60. package/package-dist/chatntc/retrieval.js.map +1 -0
  61. package/package-dist/chatntc/types.d.ts +240 -0
  62. package/package-dist/chatntc/types.js +2 -0
  63. package/package-dist/chatntc/types.js.map +1 -0
  64. package/package-dist/chatntc/validation.d.ts +8 -0
  65. package/package-dist/chatntc/validation.js +299 -0
  66. package/package-dist/chatntc/validation.js.map +1 -0
  67. package/package-dist/chatntc/viewerArtifacts.d.ts +14 -0
  68. package/package-dist/chatntc/viewerArtifacts.js +168 -0
  69. package/package-dist/chatntc/viewerArtifacts.js.map +1 -0
  70. package/package-dist/chatntc-history/index.d.ts +2 -0
  71. package/package-dist/chatntc-history/index.js +3 -0
  72. package/package-dist/chatntc-history/index.js.map +1 -0
  73. package/package-dist/chatntc-history/indexedDb.d.ts +27 -0
  74. package/package-dist/chatntc-history/indexedDb.js +258 -0
  75. package/package-dist/chatntc-history/indexedDb.js.map +1 -0
  76. package/package-dist/chatntc-history/schema.d.ts +5 -0
  77. package/package-dist/chatntc-history/schema.js +102 -0
  78. package/package-dist/chatntc-history/schema.js.map +1 -0
  79. package/package-dist/chatntc-history/types.d.ts +78 -0
  80. package/package-dist/chatntc-history/types.js +23 -0
  81. package/package-dist/chatntc-history/types.js.map +1 -0
  82. package/package-dist/chatntc-ui/ChatNTCHistoryPanel.d.ts +9 -0
  83. package/package-dist/chatntc-ui/ChatNTCHistoryPanel.js +239 -0
  84. package/package-dist/chatntc-ui/ChatNTCHistoryPanel.js.map +1 -0
  85. package/package-dist/chatntc-ui/ChatNTCIcons.d.ts +10 -0
  86. package/package-dist/chatntc-ui/ChatNTCIcons.js +20 -0
  87. package/package-dist/chatntc-ui/ChatNTCIcons.js.map +1 -0
  88. package/package-dist/chatntc-ui/ChatNTCLoadingSkeleton.d.ts +1 -0
  89. package/package-dist/chatntc-ui/ChatNTCLoadingSkeleton.js +5 -0
  90. package/package-dist/chatntc-ui/ChatNTCLoadingSkeleton.js.map +1 -0
  91. package/package-dist/chatntc-ui/ChatNTCMarkdown.d.ts +14 -0
  92. package/package-dist/chatntc-ui/ChatNTCMarkdown.js +112 -0
  93. package/package-dist/chatntc-ui/ChatNTCMarkdown.js.map +1 -0
  94. package/package-dist/chatntc-ui/ChatNTCPanel.d.ts +29 -0
  95. package/package-dist/chatntc-ui/ChatNTCPanel.js +241 -0
  96. package/package-dist/chatntc-ui/ChatNTCPanel.js.map +1 -0
  97. package/package-dist/chatntc-ui/historyMessages.d.ts +5 -0
  98. package/package-dist/chatntc-ui/historyMessages.js +53 -0
  99. package/package-dist/chatntc-ui/historyMessages.js.map +1 -0
  100. package/package-dist/chatntc-ui/index.d.ts +3 -0
  101. package/package-dist/chatntc-ui/index.js +4 -0
  102. package/package-dist/chatntc-ui/index.js.map +1 -0
  103. package/package-dist/chatntc-ui/transport.d.ts +51 -0
  104. package/package-dist/chatntc-ui/transport.js +9 -0
  105. package/package-dist/chatntc-ui/transport.js.map +1 -0
  106. package/package-dist/chunkNavigation.d.ts +12 -0
  107. package/package-dist/chunkNavigation.js +44 -0
  108. package/package-dist/chunkNavigation.js.map +1 -0
  109. package/package-dist/corpusData.d.ts +176 -33
  110. package/package-dist/corpusData.js +52 -0
  111. package/package-dist/corpusData.js.map +1 -1
  112. package/package-dist/crossReferences.d.ts +46 -0
  113. package/package-dist/crossReferences.js +198 -0
  114. package/package-dist/crossReferences.js.map +1 -0
  115. package/package-dist/generate-artifacts.mjs +47 -12
  116. package/package-dist/globalScrubber.d.ts +10 -0
  117. package/package-dist/globalScrubber.js +85 -0
  118. package/package-dist/globalScrubber.js.map +1 -0
  119. package/package-dist/permalinks.d.ts +22 -0
  120. package/package-dist/permalinks.js +36 -0
  121. package/package-dist/permalinks.js.map +1 -0
  122. package/package-dist/searchClient.d.ts +22 -0
  123. package/package-dist/searchClient.js +133 -0
  124. package/package-dist/searchClient.js.map +1 -0
  125. package/package-dist/searchEngine.d.ts +68 -0
  126. package/package-dist/searchEngine.js +558 -0
  127. package/package-dist/searchEngine.js.map +1 -0
  128. package/package-dist/searchWorker.d.ts +1 -0
  129. package/package-dist/searchWorker.js +32 -0
  130. package/package-dist/searchWorker.js.map +1 -0
  131. package/package-dist/styles.css +927 -182
  132. package/package-dist/tableCaptions.d.mts +3 -0
  133. package/package-dist/tableCaptions.mjs +35 -0
  134. package/package-dist/tableCaptions.mjs.map +1 -0
  135. package/package.json +61 -15
@@ -3,6 +3,8 @@ import { createHash } from "node:crypto";
3
3
  import { copyFile, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
4
4
  import { dirname, join, relative, resolve } from "node:path";
5
5
  import { fileURLToPath, pathToFileURL } from "node:url";
6
+ import { buildSearchIndexPayload } from "./searchEngine.js";
7
+ import { buildCrossReferenceIndexPayload } from "./crossReferences.js";
6
8
 
7
9
  const documentOrder = ["ntc2018", "circ2019"];
8
10
  const maxInitialChunkBytes = 1_500_000;
@@ -61,8 +63,39 @@ function assignChunkKeys(units) {
61
63
  }
62
64
  function publicUnit(document, unit) { return { ...unit, document }; }
63
65
  function unitSummary(document, unit, chunkPath) {
64
- const openIssues = unit.workflow.openIssues ?? [];
65
- return { id: unit.id, document, kind: unit.kind, numbering: unit.numbering, title: unit.title, hierarchy: unit.hierarchy, validity: unit.validity, workflowStatus: unit.workflow.status, openIssueCount: openIssues.length, blockingIssueCount: openIssues.filter(({ severity }) => severity === "blocking").length, chunkPath };
66
+ return { id: unit.id, document, kind: unit.kind, numbering: unit.numbering, title: unit.title, hierarchy: unit.hierarchy, validity: unit.validity, reviewStatus: unit.review.status, chunkPath };
67
+ }
68
+
69
+ function compactSearchText(parts) {
70
+ const seen = new Set();
71
+ return parts.flatMap((part) => {
72
+ const text = String(part ?? "").replace(/\s+/gu, " ").trim();
73
+ const key = text.normalize("NFKC").toLocaleLowerCase("it");
74
+ if (!text || seen.has(key)) return [];
75
+ seen.add(key);
76
+ return [text];
77
+ }).join(" ");
78
+ }
79
+
80
+ function searchableAssetText(kind, asset) {
81
+ const label = kind === "formula" ? "Formula" : kind === "table" ? "Tabella" : "Figura";
82
+ const identity = asset.officialNumber ? `${label} ${asset.officialNumber}` : label;
83
+ if (kind === "formula") return identity;
84
+ if (kind === "figure") return compactSearchText([identity, asset.caption, asset.alt]);
85
+ const cells = [...asset.headers, ...asset.rows, ...(asset.footerRows ?? [])].flat().map((cell) => cell.text);
86
+ return compactSearchText([identity, asset.caption, ...cells, ...asset.notes]);
87
+ }
88
+
89
+ function searchSegments(unit, assetById) {
90
+ return unit.blocks.flatMap((block) => {
91
+ const segments = [];
92
+ if (block.text?.normalized && block.blockId !== unit.titleBlockId) segments.push({ blockId: block.blockId, text: block.text.normalized });
93
+ if (block.assetId) {
94
+ const found = assetById.get(block.assetId);
95
+ if (found) segments.push({ blockId: block.blockId, assetId: block.assetId, assetKind: found.kind, officialNumber: found.asset.officialNumber, text: searchableAssetText(found.kind, found.asset) });
96
+ }
97
+ return segments;
98
+ });
66
99
  }
67
100
 
68
101
  export async function generateArtifacts({ sourcePackage = "structural-codes", outputDirectory = join(process.cwd(), "public", "data", "codes"), assetOutputDirectory = join(process.cwd(), "public", "assets") } = {}) {
@@ -74,16 +107,16 @@ export async function generateArtifacts({ sourcePackage = "structural-codes", ou
74
107
  const assetManifestDirectory = join(sourceRoot, "corpus", "assets");
75
108
  const sourceRegistryFile = join(sourceRoot, "sources", "registry", "sources.v2.json");
76
109
  const packageFile = join(sourceRoot, "package.json");
77
- const legacyOutput = join(dirname(outputDirectory), "corpus.json");
78
110
  const figureOutput = assetOutputDirectory;
79
111
  const [corpusManifest, sourceRegistry, packageManifest] = await Promise.all([json(corpusManifestFile), json(sourceRegistryFile), json(packageFile)]);
80
112
  const assetManifestFiles = (await readdir(assetManifestDirectory, { recursive: true })).filter((file) => file.endsWith(".json")).sort((left, right) => left.localeCompare(right, "it", { numeric: true }));
81
113
  const assetManifests = await Promise.all(assetManifestFiles.map((file) => json(join(assetManifestDirectory, file))));
82
114
  const assetCollections = { formulas: assetManifests.flatMap(({ formulas }) => formulas), tables: assetManifests.flatMap(({ tables }) => tables), figures: assetManifests.flatMap(({ figures }) => figures) };
83
115
  const assetsById = Object.fromEntries(Object.entries(assetCollections).map(([kind, assets]) => [kind, new Map(assets.map((asset) => [asset.id, asset]))]));
116
+ const searchableAssetById = new Map(Object.entries(assetCollections).flatMap(([collection, assets]) => assets.map((asset) => [asset.id, { kind: collection === "formulas" ? "formula" : collection === "tables" ? "table" : "figure", asset }])));
84
117
  const unitsByDocument = Object.fromEntries(await Promise.all(documentOrder.map(async (document) => [document, await loadUnits(corpusRoot, document)])));
85
118
  const allUnits = documentOrder.flatMap((document) => unitsByDocument[document].map((unit) => publicUnit(document, unit)));
86
- await Promise.all([rm(outputDirectory, { recursive: true, force: true }), rm(legacyOutput, { force: true }), rm(figureOutput, { recursive: true, force: true })]);
119
+ await Promise.all([rm(outputDirectory, { recursive: true, force: true }), rm(figureOutput, { recursive: true, force: true })]);
87
120
  const chunkPathByUnit = new Map();
88
121
  const documentIndexes = {};
89
122
  const chunkInventory = [];
@@ -119,8 +152,9 @@ export async function generateArtifacts({ sourcePackage = "structural-codes", ou
119
152
  const relationsWritten = await writeJson(join(outputDirectory, "relations.json"), { formatVersion: 2, sourceOfTruth: "explicit-corpus-relations", inferredRelationsIncluded: false, relations });
120
153
  const ntcByNumber = new Map(unitsByDocument.ntc2018.map((unit) => [unit.numbering.official, unit]));
121
154
  const diagnostics = unitsByDocument.circ2019.flatMap((unit) => { const candidate = ntcByNumber.get(unit.numbering.official.replace(/^C/iu, "")); if (!candidate || unit.relations.some((relation) => relation.targetUnitId === candidate.id)) return []; return [{ kind: "suggested-relation", status: "diagnostic-only-not-canonical", reason: "same-numbering", sourceUnitId: unit.id, targetUnitId: candidate.id, sourceChunkPath: chunkPathByUnit.get(unit.id), targetChunkPath: chunkPathByUnit.get(candidate.id) }]; });
122
- const diagnosticsWritten = await writeJson(join(outputDirectory, "relation-diagnostics.json"), { formatVersion: 2, warning: "Suggerimenti diagnostici non revisionati: non sono usati dalla vista combinata.", suggestions: diagnostics });
123
- const searchWritten = await writeJson(join(outputDirectory, "search-index.json"), { formatVersion: 2, normalization: "NFKC lowercase it-IT at query time", units: allUnits.map((unit) => ({ id: unit.id, document: unit.document, numbering: unit.numbering.official, title: unit.title, chunkPath: chunkPathByUnit.get(unit.id), text: unit.blocks.flatMap((block) => block.text?.normalized ? [block.text.normalized] : []).join(" ") })) });
155
+ const diagnosticsWritten = await writeJson(join(outputDirectory, "relation-diagnostics.json"), { formatVersion: 2, warning: "Suggerimenti diagnostici non confermati: non sono usati dalla vista combinata.", suggestions: diagnostics });
156
+ const searchWritten = await writeJson(join(outputDirectory, "search-index.json"), buildSearchIndexPayload(allUnits.map((unit) => ({ id: unit.id, document: unit.document, numbering: unit.numbering.official, title: unit.title, titleBlockId: unit.titleBlockId, chunkPath: chunkPathByUnit.get(unit.id), segments: searchSegments(unit, searchableAssetById) }))));
157
+ const crossReferenceWritten = await writeJson(join(outputDirectory, "cross-reference-index.json"), buildCrossReferenceIndexPayload({ units: allUnits, assetCollections }));
124
158
  const manifestationBySourceId = new Map(sourceRegistry.works.flatMap((work) => work.manifestations.map((manifestation) => [manifestation.sourceId, { manifestation, work }])));
125
159
  for (const document of documentOrder) {
126
160
  const manifestDocument = corpusManifest.documents[document];
@@ -128,15 +162,16 @@ export async function generateArtifacts({ sourcePackage = "structural-codes", ou
128
162
  if (!source) throw new Error(`sourceId non risolto: ${manifestDocument.sourceId}`);
129
163
  Object.assign(documentIndexes[document], { sourceId: manifestDocument.sourceId, sourceUrl: source.manifestation.officialUrl, publicationUrl: source.work.publication.eliUri, localSourcePath: source.manifestation.localFile, sourceSha256: source.manifestation.sha256, pages: manifestDocument.pages, blocks: unitsByDocument[document].reduce((total, unit) => total + unit.blocks.filter((block) => block.text).length, 0) });
130
164
  }
131
- const reviewedStatuses = new Set(["source-checked", "double-reviewed", "published", "superseded"]);
132
165
  const corpusFingerprintSha256 = sha256(JSON.stringify({ corpusManifest, unitsByDocument, assetManifests }));
133
- const artifactFingerprintSha256 = sha256(JSON.stringify({ chunkInventory, indexes: documentIndexes, relations: relationsWritten.sha256, diagnostics: diagnosticsWritten.sha256, search: searchWritten.sha256 }));
134
- const manifest = { formatVersion: 2, generatedAt: corpusManifest.asOf, structuralCodesVersion: packageManifest.version, schemaVersion: allUnits[0]?.schemaVersion ?? null, assetSchemaVersion: assetManifests[0]?.schemaVersion ?? null, status: corpusManifest.status, disclaimer: corpusManifest.disclaimer, corpusFingerprintSha256, generatedArtifactFingerprintSha256: artifactFingerprintSha256, stats: { units: allUnits.length, blocks: allUnits.reduce((total, unit) => total + unit.blocks.filter((block) => block.text).length, 0), explicitRelations: relations.length, proposedRelations: relations.filter((relation) => relation.review.status === "proposed").length, suggestedRelationDiagnostics: diagnostics.length, reviewedUnits: allUnits.filter((unit) => reviewedStatuses.has(unit.workflow.status)).length, assetUnits: allUnits.filter((unit) => unit.assets.formulaIds.length > 0 || unit.assets.tableIds.length > 0 || unit.assets.figureIds.length > 0).length, formulas: assetCollections.formulas.length, tables: assetCollections.tables.length, figures: assetCollections.figures.length, chunks: chunkInventory.length }, documents: documentIndexes, relationsPath: "/data/codes/relations.json", relationDiagnosticsPath: "/data/codes/relation-diagnostics.json", searchIndexPath: "/data/codes/search-index.json", chunks: chunkInventory };
166
+ const artifactFingerprintSha256 = sha256(JSON.stringify({ chunkInventory, indexes: documentIndexes, relations: relationsWritten.sha256, diagnostics: diagnosticsWritten.sha256, search: searchWritten.sha256, crossReferences: crossReferenceWritten.sha256 }));
167
+ const manifest = { formatVersion: 2, generatedAt: corpusManifest.asOf, structuralCodesVersion: packageManifest.version, schemaVersion: allUnits[0]?.schemaVersion ?? null, assetSchemaVersion: assetManifests[0]?.schemaVersion ?? null, status: corpusManifest.status, disclaimer: corpusManifest.disclaimer, corpusFingerprintSha256, generatedArtifactFingerprintSha256: artifactFingerprintSha256, stats: { units: allUnits.length, blocks: allUnits.reduce((total, unit) => total + unit.blocks.filter((block) => block.text).length, 0), explicitRelations: relations.length, proposedRelations: relations.filter((relation) => relation.review.status === "proposed").length, suggestedRelationDiagnostics: diagnostics.length, assetUnits: allUnits.filter((unit) => unit.assets.formulaIds.length > 0 || unit.assets.tableIds.length > 0 || unit.assets.figureIds.length > 0).length, formulas: assetCollections.formulas.length, tables: assetCollections.tables.length, figures: assetCollections.figures.length, chunks: chunkInventory.length }, documents: documentIndexes, relationsPath: "/data/codes/relations.json", relationDiagnosticsPath: "/data/codes/relation-diagnostics.json", searchIndexPath: "/data/codes/search-index.json", crossReferenceIndexPath: "/data/codes/cross-reference-index.json", chunks: chunkInventory };
135
168
  const manifestWritten = await writeJson(join(outputDirectory, "manifest.json"), manifest);
136
169
  let copiedFigureBytes = 0;
137
- for (const figure of assetCollections.figures) {
138
- const source = join(sourceRoot, "corpus", "assets", figure.imagePath);
139
- const destination = join(figureOutput, figure.imagePath);
170
+ const tableCellImages = assetCollections.tables.flatMap((table) => [...table.headers, ...table.rows].flat().flatMap((cell) => cell.image ? [cell.image] : []));
171
+ const imagesByPath = new Map([...assetCollections.figures, ...tableCellImages].map((entry) => [entry.imagePath, entry]));
172
+ for (const image of imagesByPath.values()) {
173
+ const source = join(sourceRoot, "corpus", "assets", image.imagePath);
174
+ const destination = join(figureOutput, image.imagePath);
140
175
  await mkdir(dirname(destination), { recursive: true });
141
176
  await copyFile(source, destination);
142
177
  copiedFigureBytes += (await stat(source)).size;
@@ -0,0 +1,10 @@
1
+ export function buildGlobalScrubberEntries(entries: any, maximumLevel?: number): any;
2
+ export function globalScrubberEntryAtRatio(entries: any, ratio: any): any;
3
+ export function globalScrubberRatioForId(entries: any, id: any, fallbackRatio?: number): any;
4
+ export function resolveGlobalScrubberActiveId(entries: any, activeId: any, activeBaseNumber: any): any;
5
+ export function globalScrubberKeyboardIndex(currentIndex: any, key: any, entryCount: any): number;
6
+ export function createGlobalScrubberDragSession(entries: any, onCommit: any): {
7
+ preview(ratio: any): any;
8
+ commit(): any;
9
+ cancel(): void;
10
+ };
@@ -0,0 +1,85 @@
1
+ function clampRatio(value) {
2
+ if (!Number.isFinite(value))
3
+ return 0;
4
+ return Math.max(0, Math.min(1, value));
5
+ }
6
+ export function buildGlobalScrubberEntries(entries, maximumLevel = Number.POSITIVE_INFINITY) {
7
+ const visibleEntries = Number.isFinite(maximumLevel) ? entries.filter((entry) => entry.level <= maximumLevel) : entries;
8
+ const lastIndex = Math.max(0, visibleEntries.length - 1);
9
+ return visibleEntries.map((entry, index) => (Object.assign(Object.assign({}, entry), { index, ratio: lastIndex === 0 ? 0 : index / lastIndex })));
10
+ }
11
+ export function globalScrubberEntryAtRatio(entries, ratio) {
12
+ var _a;
13
+ if (entries.length === 0)
14
+ return null;
15
+ const index = Math.round(clampRatio(ratio) * (entries.length - 1));
16
+ return (_a = entries[index]) !== null && _a !== void 0 ? _a : null;
17
+ }
18
+ export function globalScrubberRatioForId(entries, id, fallbackRatio = 0) {
19
+ var _a;
20
+ if (entries.length < 2)
21
+ return 0;
22
+ const entry = entries.find((candidate) => candidate.id === id);
23
+ return (_a = entry === null || entry === void 0 ? void 0 : entry.ratio) !== null && _a !== void 0 ? _a : clampRatio(fallbackRatio);
24
+ }
25
+ export function resolveGlobalScrubberActiveId(entries, activeId, activeBaseNumber) {
26
+ var _a;
27
+ if (activeId && entries.some((entry) => entry.id === activeId))
28
+ return activeId;
29
+ if (!activeBaseNumber)
30
+ return null;
31
+ const exactEntry = entries.find((entry) => entry.baseNumber === activeBaseNumber);
32
+ if (exactEntry)
33
+ return exactEntry.id;
34
+ let closestAncestor = null;
35
+ for (const entry of entries) {
36
+ if (!activeBaseNumber.startsWith(`${entry.baseNumber}.`))
37
+ continue;
38
+ if (!closestAncestor || entry.baseNumber.length > closestAncestor.baseNumber.length)
39
+ closestAncestor = entry;
40
+ }
41
+ return (_a = closestAncestor === null || closestAncestor === void 0 ? void 0 : closestAncestor.id) !== null && _a !== void 0 ? _a : null;
42
+ }
43
+ export function globalScrubberKeyboardIndex(currentIndex, key, entryCount) {
44
+ if (entryCount <= 0)
45
+ return -1;
46
+ const lastIndex = entryCount - 1;
47
+ const safeIndex = Math.max(0, Math.min(lastIndex, currentIndex));
48
+ const pageStep = Math.max(1, Math.round(entryCount * 0.1));
49
+ if (key === "Home")
50
+ return 0;
51
+ if (key === "End")
52
+ return lastIndex;
53
+ if (key === "ArrowUp")
54
+ return Math.max(0, safeIndex - 1);
55
+ if (key === "ArrowDown")
56
+ return Math.min(lastIndex, safeIndex + 1);
57
+ if (key === "PageUp")
58
+ return Math.max(0, safeIndex - pageStep);
59
+ if (key === "PageDown")
60
+ return Math.min(lastIndex, safeIndex + pageStep);
61
+ return safeIndex;
62
+ }
63
+ export function createGlobalScrubberDragSession(entries, onCommit) {
64
+ let current = null;
65
+ let finished = false;
66
+ return {
67
+ preview(ratio) {
68
+ if (!finished)
69
+ current = globalScrubberEntryAtRatio(entries, ratio);
70
+ return current;
71
+ },
72
+ commit() {
73
+ if (finished)
74
+ return null;
75
+ finished = true;
76
+ if (current)
77
+ onCommit(current);
78
+ return current;
79
+ },
80
+ cancel() {
81
+ finished = true;
82
+ },
83
+ };
84
+ }
85
+ //# sourceMappingURL=globalScrubber.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"globalScrubber.js","sourceRoot":"","sources":["../shared/globalScrubber.js"],"names":[],"mappings":"AAAA,SAAS,UAAU,CAAC,KAAK;IACvB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACtC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAAC,iBAAiB;IACzF,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACxH,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzD,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,iCACvC,KAAK,KACR,KAAK,EACL,KAAK,EAAE,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,SAAS,IAC9C,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,OAAO,EAAE,KAAK;;IACvD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IACnE,OAAO,MAAA,OAAO,CAAC,KAAK,CAAC,mCAAI,IAAI,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,OAAO,EAAE,EAAE,EAAE,aAAa,GAAG,CAAC;;IACrE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,OAAO,MAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,KAAK,mCAAI,UAAU,CAAC,aAAa,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,OAAO,EAAE,QAAQ,EAAE,gBAAgB;;IAC/E,IAAI,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAChF,IAAI,CAAC,gBAAgB;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,KAAK,gBAAgB,CAAC,CAAC;IAClF,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC,EAAE,CAAC;IACrC,IAAI,eAAe,GAAG,IAAI,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC,UAAU,GAAG,CAAC;YAAE,SAAS;QACnE,IAAI,CAAC,eAAe,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,eAAe,CAAC,UAAU,CAAC,MAAM;YAAE,eAAe,GAAG,KAAK,CAAC;IAC/G,CAAC;IACD,OAAO,MAAA,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAE,EAAE,mCAAI,IAAI,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,YAAY,EAAE,GAAG,EAAE,UAAU;IACvE,IAAI,UAAU,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC,CAAC;IAC/B,MAAM,SAAS,GAAG,UAAU,GAAG,CAAC,CAAC;IACjC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;IACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC;IAC3D,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,CAAC,CAAC;IAC7B,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,SAAS,CAAC;IACpC,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC;IACzD,IAAI,GAAG,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC;IACnE,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC,CAAC;IAC/D,IAAI,GAAG,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,GAAG,QAAQ,CAAC,CAAC;IACzE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,+BAA+B,CAAC,OAAO,EAAE,QAAQ;IAC/D,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,OAAO;QACL,OAAO,CAAC,KAAK;YACX,IAAI,CAAC,QAAQ;gBAAE,OAAO,GAAG,0BAA0B,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACpE,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM;YACJ,IAAI,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAC1B,QAAQ,GAAG,IAAI,CAAC;YAChB,IAAI,OAAO;gBAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;YAC/B,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM;YACJ,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { ViewerMode } from "./corpusData";
2
+ export type ViewerTarget = {
3
+ kind: "unit";
4
+ unitId: string;
5
+ } | {
6
+ kind: "block";
7
+ unitId: string;
8
+ blockId: string;
9
+ } | {
10
+ kind: "asset";
11
+ unitId: string;
12
+ assetId: string;
13
+ assetKind?: "formula" | "table" | "figure";
14
+ };
15
+ export declare function targetFromUrl(url: URL): ViewerTarget | null;
16
+ export declare function urlForViewerTarget(currentUrl: string | URL, mode: ViewerMode, defaultMode: ViewerMode, target: ViewerTarget): URL;
17
+ export declare function citationForTarget({ documentLabel, unitNumber, targetLabel, permalink }: {
18
+ documentLabel: string;
19
+ unitNumber: string;
20
+ targetLabel?: string | null;
21
+ permalink: string;
22
+ }): string;
@@ -0,0 +1,36 @@
1
+ export function targetFromUrl(url) {
2
+ const unitId = url.searchParams.get("unit");
3
+ if (!unitId)
4
+ return null;
5
+ const assetId = url.searchParams.get("asset");
6
+ if (assetId) {
7
+ const kind = url.searchParams.get("assetKind");
8
+ const assetKind = kind === "formula" || kind === "table" || kind === "figure" ? kind : undefined;
9
+ return { kind: "asset", unitId, assetId, assetKind };
10
+ }
11
+ const blockId = url.searchParams.get("block");
12
+ return blockId ? { kind: "block", unitId, blockId } : { kind: "unit", unitId };
13
+ }
14
+ export function urlForViewerTarget(currentUrl, mode, defaultMode, target) {
15
+ const url = new URL(currentUrl);
16
+ if (mode === defaultMode)
17
+ url.searchParams.delete("mode");
18
+ else
19
+ url.searchParams.set("mode", mode);
20
+ url.searchParams.set("unit", target.unitId);
21
+ url.searchParams.delete("block");
22
+ url.searchParams.delete("asset");
23
+ url.searchParams.delete("assetKind");
24
+ if (target.kind === "block")
25
+ url.searchParams.set("block", target.blockId);
26
+ if (target.kind === "asset") {
27
+ url.searchParams.set("asset", target.assetId);
28
+ if (target.assetKind)
29
+ url.searchParams.set("assetKind", target.assetKind);
30
+ }
31
+ return url;
32
+ }
33
+ export function citationForTarget({ documentLabel, unitNumber, targetLabel, permalink }) {
34
+ return `${documentLabel}, § ${unitNumber}${targetLabel ? `, ${targetLabel}` : ""} — ${permalink}`;
35
+ }
36
+ //# sourceMappingURL=permalinks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permalinks.js","sourceRoot":"","sources":["../shared/permalinks.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,aAAa,CAAC,GAAQ;IACpC,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC9C,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACjG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IACvD,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC9C,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,UAAwB,EAAE,IAAgB,EAAE,WAAuB,EAAE,MAAoB;IAC1H,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,IAAI,KAAK,WAAW;QAAE,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;;QACrD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACxC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACrC,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;QAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3E,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC5B,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,MAAM,CAAC,SAAS;YAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAiG;IACpL,OAAO,GAAG,aAAa,OAAO,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,SAAS,EAAE,CAAC;AACpG,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { type CorpusManifest, type DocumentLookup, type SearchResult, type ViewerMode } from "./corpusData";
2
+ type SearchStatus = "idle" | "loading" | "ready" | "error";
3
+ export declare function resolveExactSearch(query: string, mode: ViewerMode, lookup: DocumentLookup | null, circLookup: DocumentLookup | null): SearchResult[] | null;
4
+ export declare function useViewerSearch({ query, mode, manifest, dataBaseUrl, lookup, circLookup, maxResults, debounceMs }: {
5
+ query: string;
6
+ mode: ViewerMode;
7
+ manifest: CorpusManifest | null;
8
+ dataBaseUrl: string;
9
+ lookup: DocumentLookup | null;
10
+ circLookup: DocumentLookup | null;
11
+ maxResults: number;
12
+ debounceMs?: number;
13
+ }): {
14
+ queryReady: boolean;
15
+ results: SearchResult[];
16
+ status: SearchStatus;
17
+ source: "exact" | "worker";
18
+ durationMs: number | null;
19
+ errorMessage: string | undefined;
20
+ indexRequested: boolean;
21
+ };
22
+ export {};
@@ -0,0 +1,133 @@
1
+ import { useEffect, useMemo, useRef, useState } from "react";
2
+ import { parseNormativeReference, resolveDataPath, } from "./corpusData";
3
+ function resultForSummary(summary) {
4
+ const prefix = summary.numbering.official;
5
+ return {
6
+ id: summary.id,
7
+ document: summary.document,
8
+ numbering: prefix,
9
+ title: summary.title,
10
+ chunkPath: summary.chunkPath,
11
+ snippet: `${prefix} — ${summary.title}`,
12
+ highlights: [[0, prefix.length]],
13
+ score: 9000000,
14
+ matchKind: "number-exact",
15
+ };
16
+ }
17
+ export function resolveExactSearch(query, mode, lookup, circLookup) {
18
+ var _a;
19
+ const reference = parseNormativeReference(query);
20
+ if (!reference)
21
+ return null;
22
+ let summary;
23
+ if (reference.documentHint === "circ2019") {
24
+ if (mode !== "ntc")
25
+ summary = circLookup === null || circLookup === void 0 ? void 0 : circLookup.unitByNumbering.get(reference.numbering);
26
+ }
27
+ else if (mode === "circ")
28
+ summary = circLookup === null || circLookup === void 0 ? void 0 : circLookup.unitByNumbering.get(reference.numbering);
29
+ else
30
+ summary = (_a = lookup === null || lookup === void 0 ? void 0 : lookup.unitByNumbering.get(reference.numbering)) !== null && _a !== void 0 ? _a : (mode === "combined" ? circLookup === null || circLookup === void 0 ? void 0 : circLookup.unitByNumbering.get(reference.numbering) : undefined);
31
+ return summary ? [resultForSummary(summary)] : [];
32
+ }
33
+ function useDebouncedValue(value, delayMs) {
34
+ const [debounced, setDebounced] = useState(value);
35
+ useEffect(() => {
36
+ const timer = window.setTimeout(() => setDebounced(value), delayMs);
37
+ return () => window.clearTimeout(timer);
38
+ }, [delayMs, value]);
39
+ return debounced;
40
+ }
41
+ export function useViewerSearch({ query, mode, manifest, dataBaseUrl, lookup, circLookup, maxResults, debounceMs = 80 }) {
42
+ const maximum = Math.max(1, Math.min(50, maxResults));
43
+ const debouncedQuery = useDebouncedValue(query, debounceMs);
44
+ const exactResults = useMemo(() => resolveExactSearch(query, mode, lookup, circLookup), [circLookup, lookup, mode, query]);
45
+ const [workerResponse, setWorkerResponse] = useState(null);
46
+ const [indexRequested, setIndexRequested] = useState(false);
47
+ const workerRef = useRef(null);
48
+ const requestIdRef = useRef(0);
49
+ useEffect(() => () => { var _a; return (_a = workerRef.current) === null || _a === void 0 ? void 0 : _a.terminate(); }, []);
50
+ useEffect(() => {
51
+ if (!manifest || exactResults !== null || debouncedQuery.trim().length < 2) {
52
+ requestIdRef.current += 1;
53
+ return;
54
+ }
55
+ const scheduleFailure = (errorMessage) => {
56
+ const timer = window.setTimeout(() => {
57
+ setWorkerResponse({ query: debouncedQuery, mode, status: "error", results: [], durationMs: null, errorMessage });
58
+ }, 0);
59
+ return () => window.clearTimeout(timer);
60
+ };
61
+ let worker = workerRef.current;
62
+ if (!worker) {
63
+ if (typeof Worker === "undefined") {
64
+ return scheduleFailure("Web Worker non disponibile in questo browser.");
65
+ }
66
+ try {
67
+ worker = new Worker(new URL("./searchWorker.js", import.meta.url), { type: "module", name: "structural-codes-search" });
68
+ }
69
+ catch (_a) {
70
+ return scheduleFailure("Avvio del Web Worker non riuscito.");
71
+ }
72
+ workerRef.current = worker;
73
+ }
74
+ const requestId = ++requestIdRef.current;
75
+ const activeWorker = worker;
76
+ const onMessage = ({ data }) => {
77
+ if (data.requestId !== requestIdRef.current || data.requestId !== requestId)
78
+ return;
79
+ setIndexRequested(true);
80
+ if (data.type === "error") {
81
+ setWorkerResponse({ query: debouncedQuery, mode, status: "error", results: [], durationMs: null, errorMessage: data.message });
82
+ return;
83
+ }
84
+ setWorkerResponse({ query: data.query, mode: data.mode, status: "ready", results: data.results, durationMs: data.durationMs });
85
+ };
86
+ const onError = () => {
87
+ if (requestId !== requestIdRef.current)
88
+ return;
89
+ activeWorker.terminate();
90
+ if (workerRef.current === activeWorker)
91
+ workerRef.current = null;
92
+ setIndexRequested(true);
93
+ setWorkerResponse({ query: debouncedQuery, mode, status: "error", results: [], durationMs: null, errorMessage: "Avvio del Web Worker non riuscito." });
94
+ };
95
+ activeWorker.addEventListener("message", onMessage);
96
+ activeWorker.addEventListener("error", onError);
97
+ let postFailureCleanup = null;
98
+ try {
99
+ activeWorker.postMessage({
100
+ type: "search",
101
+ requestId,
102
+ indexUrl: new URL(resolveDataPath(manifest.searchIndexPath, dataBaseUrl), window.location.href).href,
103
+ query: debouncedQuery,
104
+ mode,
105
+ limit: maximum,
106
+ });
107
+ }
108
+ catch (_b) {
109
+ activeWorker.terminate();
110
+ if (workerRef.current === activeWorker)
111
+ workerRef.current = null;
112
+ postFailureCleanup = scheduleFailure("Invio della ricerca al Web Worker non riuscito.");
113
+ }
114
+ return () => {
115
+ postFailureCleanup === null || postFailureCleanup === void 0 ? void 0 : postFailureCleanup();
116
+ activeWorker.removeEventListener("message", onMessage);
117
+ activeWorker.removeEventListener("error", onError);
118
+ };
119
+ }, [dataBaseUrl, debouncedQuery, exactResults, manifest, maximum, mode]);
120
+ const normalizedInputLength = query.trim().length;
121
+ const querySettled = debouncedQuery === query;
122
+ const fullTextCurrent = querySettled && (workerResponse === null || workerResponse === void 0 ? void 0 : workerResponse.query) === debouncedQuery && workerResponse.mode === mode;
123
+ return {
124
+ queryReady: normalizedInputLength >= 2,
125
+ results: exactResults !== null && exactResults !== void 0 ? exactResults : (fullTextCurrent ? workerResponse.results : []),
126
+ status: exactResults !== null ? "ready" : normalizedInputLength < 2 ? "idle" : fullTextCurrent ? workerResponse.status : "loading",
127
+ source: exactResults !== null ? "exact" : "worker",
128
+ durationMs: exactResults !== null ? 0 : fullTextCurrent ? workerResponse.durationMs : null,
129
+ errorMessage: exactResults === null && fullTextCurrent ? workerResponse.errorMessage : undefined,
130
+ indexRequested,
131
+ };
132
+ }
133
+ //# sourceMappingURL=searchClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchClient.js","sourceRoot":"","sources":["../shared/searchClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ export function normalizeSearchText(value: any): string;
2
+ export function tokenizeSearchText(value: any): [] | RegExpMatchArray;
3
+ export function parseNormativeReference(value: any): {
4
+ numbering: string;
5
+ documentHint: string | null;
6
+ } | null;
7
+ export function buildSearchIndexPayload(sourceUnits: any): {
8
+ formatVersion: number;
9
+ normalization: string;
10
+ units: any;
11
+ references: any;
12
+ assetReferences: any;
13
+ postings: any;
14
+ };
15
+ export function highlightedSnippet(value: any, normalizedQuery: any, queryTokens: any): {
16
+ snippet: string;
17
+ highlights: any[][];
18
+ };
19
+ export function createSearchEngine(index: any): {
20
+ search({ query, mode, limit }: {
21
+ query: any;
22
+ mode?: string | undefined;
23
+ limit?: number | undefined;
24
+ }): {
25
+ assetKind?: any;
26
+ assetId?: any;
27
+ blockId?: any;
28
+ score: number;
29
+ matchKind: any;
30
+ snippet: string;
31
+ highlights: any[][];
32
+ id: any;
33
+ document: any;
34
+ numbering: any;
35
+ title: any;
36
+ chunkPath: any;
37
+ }[];
38
+ };
39
+ export const searchIndexFormatVersion: 4;
40
+ export const searchRankingWeights: Readonly<{
41
+ priority: Readonly<{
42
+ numberExact: 9000000;
43
+ assetExact: 8000000;
44
+ titleExact: 7000000;
45
+ numberKeyword: 6000000;
46
+ titleTerms: 5000000;
47
+ phrase: 4000000;
48
+ proximity: 3000000;
49
+ allTerms: 2000000;
50
+ partial: 1000000;
51
+ }>;
52
+ field: Readonly<{
53
+ matchedTerm: 20000;
54
+ titleFrequency: 2000;
55
+ bodyRelevance: 420;
56
+ assetRelevance: 260;
57
+ exactNumberPrefix: 90000;
58
+ }>;
59
+ proximity: Readonly<{
60
+ sameBlock: 80000;
61
+ ordered: 35000;
62
+ window: 24;
63
+ perTokenSaved: 1500;
64
+ }>;
65
+ candidatePoolMinimum: 300;
66
+ candidatePoolPerResult: 28;
67
+ partialExpansionLimit: 8;
68
+ }>;