You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@annotator.apache.org by ge...@apache.org on 2020/11/20 12:26:25 UTC

[incubator-annotator] 02/19: Make abstract TextPosition matcher

This is an automated email from the ASF dual-hosted git repository.

gerben pushed a commit to branch import-dom-seek
in repository https://gitbox.apache.org/repos/asf/incubator-annotator.git

commit 25d753a973aae0566c4bb6a3e47de521a379744e
Author: Gerben <ge...@treora.com>
AuthorDate: Mon Nov 16 22:55:15 2020 +0100

    Make abstract TextPosition matcher
---
 packages/dom/src/text-position/match.ts | 51 +++++++++++++++++++++++----------
 packages/dom/src/text-quote/match.ts    | 13 +++++----
 2 files changed, 44 insertions(+), 20 deletions(-)

diff --git a/packages/dom/src/text-position/match.ts b/packages/dom/src/text-position/match.ts
index 7b9f1c5..985e278 100644
--- a/packages/dom/src/text-position/match.ts
+++ b/packages/dom/src/text-position/match.ts
@@ -20,32 +20,53 @@
 
 import type { Matcher, TextPositionSelector } from '@annotator/selector';
 import { ownerDocument } from '../owner-document';
-import { DomSeeker } from '../seek';
+import { TextSeeker, NonEmptyChunker } from '../seek';
 import { CodePointSeeker } from '../code-point-seeker';
+import { Chunk, ChunkRange, TextNodeChunker, PartialTextNode } from '../chunker';
 
 export function createTextPositionSelectorMatcher(
   selector: TextPositionSelector,
 ): Matcher<Range, Range> {
+
+  const abstractMatcher: AbstractMatcher<PartialTextNode> =
+    abstractTextPositionSelectorMatcher(selector);
+
   return async function* matchAll(scope) {
-    const document = ownerDocument(scope);
+    const textChunks = new TextNodeChunker(scope);
 
-    const { start, end } = selector;
+    if (textChunks.currentChunk === null)
+      throw new RangeError('Range does not contain any Text nodes.');
+    const matches = abstractMatcher(textChunks as NonEmptyChunker<PartialTextNode>);
 
-    const codeUnitSeeker = new DomSeeker(scope);
-    const codePointSeeker = new CodePointSeeker(codeUnitSeeker);
+    for await (const abstractMatch of matches) {
+      const match = ownerDocument(scope).createRange();
+      match.setStart(abstractMatch.startChunk.node, abstractMatch.startChunk.startOffset + abstractMatch.startIndex);
+      match.setEnd(abstractMatch.endChunk.node, abstractMatch.endChunk.startOffset + abstractMatch.endIndex);
+      yield match;
+    }
+  };
+}
 
-    // Create a range to represent the described text in the dom.
-    const match = document.createRange();
+type AbstractMatcher<TChunk extends Chunk<any>> =
+  Matcher<NonEmptyChunker<TChunk>, ChunkRange<TChunk>>
 
-    // Seek to the start of the match, make the range start there.
-    codePointSeeker.seekTo(start);
-    match.setStart(codeUnitSeeker.referenceNode, codeUnitSeeker.offsetInReferenceNode);
+export function abstractTextPositionSelectorMatcher<TChunk extends Chunk<string>>(
+  selector: TextPositionSelector,
+): AbstractMatcher<TChunk> {
+
+  const { start, end } = selector;
+
+  return async function* matchAll<TChunk extends Chunk<string>>(textChunks: NonEmptyChunker<TChunk>) {
+    const codeUnitSeeker = new TextSeeker(textChunks);
+    const codePointSeeker = new CodePointSeeker(codeUnitSeeker);
 
-    // Seek to the end of the match, make the range end there.
+    codePointSeeker.seekTo(start);
+    const startChunk = codeUnitSeeker.currentChunk;
+    const startIndex = codeUnitSeeker.offsetInChunk;
     codePointSeeker.seekTo(end);
-    match.setEnd(codeUnitSeeker.referenceNode, codeUnitSeeker.offsetInReferenceNode);
+    const endChunk = codeUnitSeeker.currentChunk;
+    const endIndex = codeUnitSeeker.offsetInChunk;
 
-    // Yield the match.
-    yield match;
-  };
+    yield { startChunk, startIndex, endChunk, endIndex };
+  }
 }
diff --git a/packages/dom/src/text-quote/match.ts b/packages/dom/src/text-quote/match.ts
index 5a4df52..f7c8da3 100644
--- a/packages/dom/src/text-quote/match.ts
+++ b/packages/dom/src/text-quote/match.ts
@@ -19,12 +19,15 @@
  */
 
 import type { Matcher, TextQuoteSelector } from '@annotator/selector';
-import { TextNodeChunker, Chunk, Chunker, ChunkRange } from '../chunker';
+import { TextNodeChunker, Chunk, Chunker, ChunkRange, PartialTextNode } from '../chunker';
 
 export function createTextQuoteSelectorMatcher(
   selector: TextQuoteSelector,
 ): Matcher<Range, Range> {
-  const abstractMatcher = abstractTextQuoteSelectorMatcher(selector);
+
+  const abstractMatcher: AbstractMatcher<PartialTextNode> =
+    abstractTextQuoteSelectorMatcher(selector);
+
   return async function* matchAll(scope) {
     const textChunks = new TextNodeChunker(scope);
 
@@ -41,12 +44,12 @@ export function createTextQuoteSelectorMatcher(
   }
 }
 
-type AbstractMatcher<TChunk extends Chunk<string>> =
+type AbstractMatcher<TChunk extends Chunk<any>> =
   Matcher<Chunker<TChunk>, ChunkRange<TChunk>>
 
-export function abstractTextQuoteSelectorMatcher(
+export function abstractTextQuoteSelectorMatcher<TChunk extends Chunk<string>>(
   selector: TextQuoteSelector,
-): AbstractMatcher<any> {
+): AbstractMatcher<TChunk> {
   return async function* matchAll<TChunk extends Chunk<string>>(textChunks: Chunker<TChunk>) {
     const exact = selector.exact;
     const prefix = selector.prefix || '';