Use strict typecheck mode & fix issues
Tiny behaviour changes:
- highlightRange now returns a noop function when the range is empty,
instead of returning undefined.
- passing null as scope to describeTextQuote no longer works (pass
undefined instead).
diff --git a/packages/dom/src/cartesian.ts b/packages/dom/src/cartesian.ts
index 35424e8..256e313 100644
--- a/packages/dom/src/cartesian.ts
+++ b/packages/dom/src/cartesian.ts
@@ -30,7 +30,16 @@
// Initialise an empty log for each iterable.
const logs: T[][] = iterables.map(() => []);
- const nextValuePromises = iterators.map((iterator, iterableNr) =>
+ type NumberedResultPromise = Promise<{
+ nextResult: IteratorResult<T>,
+ iterableNr: number
+ }>;
+
+ function notNull(p: NumberedResultPromise | null): p is NumberedResultPromise {
+ return p !== null
+ }
+
+ const nextValuePromises: Array<NumberedResultPromise | null> = iterators.map((iterator, iterableNr) =>
iterator
.next()
.then(
@@ -41,10 +50,10 @@
);
// Keep listening as long as any of the iterables is not yet exhausted.
- while (nextValuePromises.some(p => p !== null)) {
+ while (nextValuePromises.some(notNull)) {
// Wait until any of the active iterators has produced a new value.
const { nextResult, iterableNr } = await Promise.race(
- nextValuePromises.filter(p => p !== null),
+ nextValuePromises.filter(notNull),
);
// If this iterable was exhausted, stop listening to it and move on.
diff --git a/packages/dom/src/highlight-range.ts b/packages/dom/src/highlight-range.ts
index d46cead..7f76e40 100644
--- a/packages/dom/src/highlight-range.ts
+++ b/packages/dom/src/highlight-range.ts
@@ -33,8 +33,6 @@
tagName: string = 'mark',
attributes: Record<string, string> = {}
): () => void {
- if (range.collapsed) return;
-
// First put all nodes in an array (splits start and end nodes if needed)
const nodes = textNodesInRange(range);
@@ -57,6 +55,9 @@
// Return an array of the text nodes in the range. Split the start and end nodes if required.
function textNodesInRange(range: Range): Text[] {
+ // If the range is empty, avoid creating and returning an empty text node.
+ if (range.collapsed) return [];
+
// If the start or end node is a text node and only partly in the range, split it.
if (
isTextNode(range.startContainer) &&
@@ -78,6 +79,8 @@
}
// Collect the text nodes.
+ if (!range.startContainer.ownerDocument)
+ throw new TypeError('range.startContainer lacks an ownerDocument');
const walker = range.startContainer.ownerDocument.createTreeWalker(
range.commonAncestorContainer,
NodeFilter.SHOW_TEXT,
@@ -114,6 +117,7 @@
// Replace [node] with <tagName ...attributes>[node]</tagName>
function wrapNodeInHighlight(node: Node, tagName: string, attributes: Record<string, string>): HTMLElement {
+ if (!node.ownerDocument) throw new TypeError('Node to be highlighted lacks an ownerDocument');
const highlightElement = node.ownerDocument.createElement(tagName);
Object.keys(attributes).forEach(key => {
highlightElement.setAttribute(key, attributes[key]);
@@ -130,7 +134,7 @@
if (!highlightElement.parentNode) return;
if (highlightElement.childNodes.length === 1) {
highlightElement.parentNode.replaceChild(
- highlightElement.firstChild,
+ highlightElement.firstChild as ChildNode,
highlightElement,
);
} else {
diff --git a/packages/dom/src/scope.ts b/packages/dom/src/scope.ts
index 2b112ff..24c9b26 100644
--- a/packages/dom/src/scope.ts
+++ b/packages/dom/src/scope.ts
@@ -21,18 +21,22 @@
import { DomScope } from './types';
export function ownerDocument(scope: DomScope): Document {
+ let document;
if ('commonAncestorContainer' in scope)
- return scope.commonAncestorContainer.ownerDocument;
+ document = scope.commonAncestorContainer.ownerDocument;
else
- return scope.ownerDocument;
+ document = scope.ownerDocument;
+ if (!document) throw new TypeError('scope lacks an ownerDocument');
+ return document;
}
-export function rangeFromScope(scope: DomScope | null): Range {
+export function rangeFromScope(scope: DomScope): Range {
if ('commonAncestorContainer' in scope) {
return scope;
}
const document = scope.ownerDocument;
+ if (!document) throw new TypeError('scope lacks an ownerDocument');
const range = document.createRange();
range.selectNodeContents(scope);
diff --git a/packages/dom/src/text-quote/describe.ts b/packages/dom/src/text-quote/describe.ts
index d5168ca..ef7eb53 100644
--- a/packages/dom/src/text-quote/describe.ts
+++ b/packages/dom/src/text-quote/describe.ts
@@ -38,7 +38,7 @@
export async function describeTextQuote(
range: Range,
- scope: DomScope = null
+ scope: DomScope = ownerDocument(range).documentElement,
): Promise<TextQuoteSelector> {
const exact = range.toString();
@@ -54,9 +54,9 @@
async function calculateContextForDisambiguation(
range: Range,
selector: TextQuoteSelector,
- scope: DomScope
+ scope: DomScope,
): Promise<{ prefix?: string, suffix?: string }> {
- const scopeAsRange = rangeFromScope(scope || ownerDocument(range).documentElement);
+ const scopeAsRange = rangeFromScope(scope);
const root = scopeAsRange.commonAncestorContainer;
const text = scopeAsRange.toString();
diff --git a/packages/dom/src/text-quote/match.ts b/packages/dom/src/text-quote/match.ts
index e6e26fc..2657a6f 100644
--- a/packages/dom/src/text-quote/match.ts
+++ b/packages/dom/src/text-quote/match.ts
@@ -62,7 +62,7 @@
if (!iter.pointerBeforeReferenceNode) {
// Peek forward and skip over any empty nodes.
if (iter.nextNode()) {
- while (iter.referenceNode.nodeValue.length === 0) {
+ while ((iter.referenceNode.nodeValue as String).length === 0) {
iter.nextNode();
}
@@ -82,7 +82,7 @@
if (!iter.pointerBeforeReferenceNode) {
// Peek forward and skip over any empty nodes.
if (iter.nextNode()) {
- while (iter.referenceNode.nodeValue.length === 0) {
+ while ((iter.referenceNode.nodeValue as String).length === 0) {
iter.nextNode();
}
diff --git a/test/data-model.ts b/test/data-model.ts
index 975b361..c52f4e1 100644
--- a/test/data-model.ts
+++ b/test/data-model.ts
@@ -21,7 +21,7 @@
/* global process */
import fs from 'fs';
-import URL from 'url';
+import { URL } from 'url';
import Ajv from 'ajv';
import META_SCHEMA from 'ajv/lib/refs/json-schema-draft-04.json';
@@ -76,13 +76,13 @@
this.skip();
} else {
// load the data from the file or URL
- let url_parsed = URL.parse(url);
- if (url_parsed.path !== url_parsed.href) {
+ let url_parsed = new URL(url);
+ if (url_parsed.pathname !== url_parsed.href) {
const data_response = await fetch(url_parsed.href);
data = await data_response.json();
} else {
// assume we have a local file and use that
- data = JSON.parse(fs.readFileSync(url_parsed.path, 'utf8'));
+ data = JSON.parse(fs.readFileSync(url_parsed.pathname, 'utf8'));
}
if (data === '') {
this.skip();
diff --git a/tsconfig.json b/tsconfig.json
index 8ca98e8..49400f2 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,6 @@
{
"compilerOptions": {
- "noImplicitAny": true,
+ "strict": true,
"noEmit": true,
"target": "ES2017",
"lib": [