@claritylabs/cl-sdk 3.0.14 → 3.0.16

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/dist/index.mjs CHANGED
@@ -2345,7 +2345,7 @@ function isDiscardableBoilerplate(text, unit) {
2345
2345
  }
2346
2346
  function isBoilerplateLine(line) {
2347
2347
  const cleaned = normalizeWhitespace(line.replace(/\bColumn\s+\d+:\s*/gi, ""));
2348
- return isDiscardableBoilerplate(cleaned) || /^IMPORTANT NOTICE\s*[-—]\s*/i.test(cleaned) || /^THIS IS A CLAIMS-MADE AND REPORTED POLICY\.? PLEASE READ IT CAREFULLY\.?$/i.test(cleaned);
2348
+ return isDiscardableBoilerplate(cleaned) || /^THIS IS A CLAIMS-MADE AND REPORTED POLICY\.? PLEASE READ IT CAREFULLY\.?$/i.test(cleaned);
2349
2349
  }
2350
2350
  function removedBoilerplateLines(text) {
2351
2351
  return text.split(/\s{2,}|\r?\n/).map(normalizeWhitespace).filter((line) => line && isBoilerplateLine(line));
@@ -2644,7 +2644,19 @@ function metadataString(metadata, key) {
2644
2644
  }
2645
2645
  function isTitleContentNode(node) {
2646
2646
  if (node.kind !== "text") return false;
2647
- return metadataString(node.metadata, "elementType") === "title" || metadataString(node.metadata, "sourceUnit") === "title";
2647
+ const isMarkedTitle = metadataString(node.metadata, "elementType") === "title" || metadataString(node.metadata, "sourceUnit") === "title";
2648
+ if (!isMarkedTitle) return false;
2649
+ const text = normalizeWhitespace2(node.textExcerpt ?? node.title);
2650
+ if (!text || text.length > 140) return false;
2651
+ const words = text.split(/\s+/);
2652
+ if (words.length > 14) return false;
2653
+ const startsWithStructuredHeading = /^(section|item|part|endorsement|schedule|article)\b|^[A-Z]\.\s|\b[IVX]+\.\s/i.test(text);
2654
+ const uppercaseLetters = [...text].filter((char) => /[A-Z]/.test(char)).length;
2655
+ const lowercaseLetters = [...text].filter((char) => /[a-z]/.test(char)).length;
2656
+ const mostlyUppercase = uppercaseLetters > 0 && uppercaseLetters >= lowercaseLetters * 1.6;
2657
+ const containsSentencePunctuation = /[.;:]\s+\S/.test(text) || /[.;:]$/.test(text);
2658
+ const sentenceLike = /\b(is|are|was|were|will|shall|may|must|means|includes|provided|subject|available|attached|remain|constitutes)\b/i.test(text) && /[a-z]/.test(text);
2659
+ return startsWithStructuredHeading || mostlyUppercase && !sentenceLike && !containsSentencePunctuation;
2648
2660
  }
2649
2661
  function nodePageEnd(node) {
2650
2662
  return node.pageEnd ?? node.pageStart;
@@ -2684,10 +2696,10 @@ function groupPageContentByTitles(nodes) {
2684
2696
  const bbox = evidenceNodes.flatMap((node) => node.bbox ?? []).slice(0, 12);
2685
2697
  byId.set(activeTitle.id, {
2686
2698
  ...activeTitle,
2687
- kind: "section",
2699
+ kind: "text",
2688
2700
  title,
2689
2701
  description: nodeTextDescription({
2690
- kind: "section",
2702
+ kind: "text",
2691
2703
  title,
2692
2704
  text: evidenceNodes.map((node) => node.textExcerpt).filter(Boolean).join("\n\n"),
2693
2705
  page: activeTitle.pageStart
@@ -9216,12 +9228,28 @@ function nodePageEnd2(node) {
9216
9228
  return node.pageEnd ?? node.pageStart;
9217
9229
  }
9218
9230
  function pageRangeForNodes(nodes) {
9219
- const pageStarts = nodes.map((node) => node.pageStart).filter((page) => typeof page === "number");
9220
- const pageEnds = nodes.map(nodePageEnd2).filter((page) => typeof page === "number");
9221
- if (pageStarts.length === 0 || pageEnds.length === 0) return void 0;
9222
- const start = Math.min(...pageStarts);
9223
- const end = Math.max(...pageEnds);
9224
- return start === end ? `page ${start}` : `pages ${start}-${end}`;
9231
+ const pages = [...new Set(nodes.flatMap((node) => {
9232
+ if (typeof node.pageStart !== "number") return [];
9233
+ const end = nodePageEnd2(node) ?? node.pageStart;
9234
+ const values = [];
9235
+ for (let page = node.pageStart; page <= end; page += 1) values.push(page);
9236
+ return values;
9237
+ }))].sort((left, right) => left - right);
9238
+ if (pages.length === 0) return void 0;
9239
+ const ranges = [];
9240
+ let start = pages[0];
9241
+ let previous = pages[0];
9242
+ for (const page of pages.slice(1)) {
9243
+ if (page === previous + 1) {
9244
+ previous = page;
9245
+ continue;
9246
+ }
9247
+ ranges.push(start === previous ? String(start) : `${start}-${previous}`);
9248
+ start = page;
9249
+ previous = page;
9250
+ }
9251
+ ranges.push(start === previous ? String(start) : `${start}-${previous}`);
9252
+ return ranges.length === 1 && !ranges[0].includes("-") ? `page ${ranges[0]}` : `pages ${ranges.join(", ")}`;
9225
9253
  }
9226
9254
  function descriptionWithPages(description, nodes) {
9227
9255
  const range = pageRangeForNodes(nodes);
@@ -9252,6 +9280,7 @@ function looksLikeDeclarationsContinuation(node) {
9252
9280
  function looksLikePolicyFormStart(node) {
9253
9281
  const text = sourceNodeText(node);
9254
9282
  const excerpt = cleanText(node.textExcerpt, "");
9283
+ if (isAdministrativeNoticeNode(node) || looksLikeDeclarationsStart(node)) return false;
9255
9284
  return /\bpolicy form\b/i.test(node.title) || /^policy\s+form\b/i.test(excerpt) || /\btechnology errors?\s*&?\s*omissions\b/i.test(text) && /\bplease read this entire policy carefully\b/i.test(text) || /\bform\s+[A-Z]{2,}-[A-Z0-9-]+\s+\d{2}\s+\d{2}\b/i.test(text);
9256
9285
  }
9257
9286
  function looksLikePolicyFormContinuation(node) {
@@ -9260,9 +9289,9 @@ function looksLikePolicyFormContinuation(node) {
9260
9289
  return /\b(insuring agreement|definitions?|exclusions?|conditions?|claim means|insured means|wrongful act means|limits of liability|notice of claim|cancellation by|action against the company)\b/i.test(text);
9261
9290
  }
9262
9291
  function groupAdjacentChildren(params) {
9263
- if (params.childIds.length < 2) return params.sourceTree;
9292
+ if (params.childIds.length < 1) return params.sourceTree;
9264
9293
  const children = params.childIds.map((id2) => params.children.find((child) => child.id === id2)).filter((child) => Boolean(child));
9265
- if (children.length < 2) return params.sourceTree;
9294
+ if (children.length < 1) return params.sourceTree;
9266
9295
  const parentId = children[0].parentId;
9267
9296
  if (!children.every((child) => child.parentId === parentId)) return params.sourceTree;
9268
9297
  const documentId = children[0].documentId;
@@ -9371,6 +9400,11 @@ function applySemanticPageGrouping(sourceTree) {
9371
9400
  for (let index = policyStartIndex; index < children.length; index += 1) {
9372
9401
  const child = children[index];
9373
9402
  if (index > policyStartIndex && looksLikeEndorsementStart(child)) break;
9403
+ if (isAdministrativeNoticeNode(child) || looksLikeDeclarationsStart(child)) break;
9404
+ if (index > policyStartIndex && child.kind === "page") {
9405
+ policyIds.push(child.id);
9406
+ continue;
9407
+ }
9374
9408
  if (!looksLikePolicyFormContinuation(child)) break;
9375
9409
  policyIds.push(child.id);
9376
9410
  }
@@ -9562,6 +9596,10 @@ function normalizeContainerEvidenceFromChildren(sourceTree) {
9562
9596
  pageEnd: pageEnds.length ? Math.max(...pageEnds) : currentNode.pageEnd,
9563
9597
  bbox,
9564
9598
  order: Math.min(currentNode.order, ...children.map((child) => child.order)),
9599
+ description: descriptionWithPages(
9600
+ currentNode.description.replace(/;\s*pages?\s+[0-9,\s-]+$/i, ""),
9601
+ evidenceNodes
9602
+ ),
9565
9603
  textExcerpt: shouldUseOwnEvidenceForContainer(currentNode) ? currentNode.textExcerpt : childText || currentNode.textExcerpt
9566
9604
  });
9567
9605
  }