@prose-reader/enhancer-search 1.265.0 → 1.267.0
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.d.ts +13 -0
- package/dist/index.js +172 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.umd.cjs +178 -0
- package/dist/index.umd.cjs.map +1 -0
- package/dist/report.d.ts +2 -0
- package/dist/search.d.ts +5 -0
- package/dist/types.d.ts +11 -0
- package/package.json +6 -3
- package/src/index.test.ts +0 -5
- package/src/index.ts +0 -84
- package/src/report.ts +0 -6
- package/src/search.ts +0 -65
- package/src/types.ts +0 -13
- package/tsconfig.json +0 -19
- package/vite.config.ts +0 -31
- package/vitest.config.ts +0 -9
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Reader } from '@prose-reader/core';
|
|
2
|
+
import { SearchResult } from './search';
|
|
3
|
+
import { ResultItem, SearchEnhancerAPI } from './types';
|
|
4
|
+
export type { SearchEnhancerAPI, ResultItem, SearchResult };
|
|
5
|
+
/**
|
|
6
|
+
* Contract of search enhancer.
|
|
7
|
+
*
|
|
8
|
+
* - At best a result match should be navigable. It means the search needs to
|
|
9
|
+
* be done on a rendered document. This is because rendering can differ from the original
|
|
10
|
+
* item resource. A resource can be something non digestible and very specific (.pdf). The search
|
|
11
|
+
* enhancer is agnostic and can only search into documents.
|
|
12
|
+
*/
|
|
13
|
+
export declare const searchEnhancer: <InheritOptions, InheritOutput extends Reader>(next: (options: InheritOptions) => InheritOutput) => (options: InheritOptions) => InheritOutput & SearchEnhancerAPI;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { deferIdle } from '@prose-reader/core';
|
|
2
|
+
import { of, defer, forkJoin } from 'rxjs';
|
|
3
|
+
import { map, switchMap, finalize, catchError } from 'rxjs/operators';
|
|
4
|
+
|
|
5
|
+
const h = () => {
|
|
6
|
+
if (!(typeof window > "u"))
|
|
7
|
+
return window;
|
|
8
|
+
};
|
|
9
|
+
function $() {
|
|
10
|
+
const o = h()?.__PROSE_READER_DEBUG;
|
|
11
|
+
return o === true || o === "true";
|
|
12
|
+
}
|
|
13
|
+
const u = (o, n = $(), e) => ({
|
|
14
|
+
namespace: (t, l) => u(`${o} [${t}]`, l, e),
|
|
15
|
+
debug: n ? o ? Function.prototype.bind.call(
|
|
16
|
+
console.debug,
|
|
17
|
+
console,
|
|
18
|
+
o,
|
|
19
|
+
`%c${o}`,
|
|
20
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
21
|
+
) : Function.prototype.bind.call(
|
|
22
|
+
console.debug,
|
|
23
|
+
console,
|
|
24
|
+
`%c${o}`,
|
|
25
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
26
|
+
) : () => {
|
|
27
|
+
},
|
|
28
|
+
info: n ? o ? Function.prototype.bind.call(
|
|
29
|
+
console.info,
|
|
30
|
+
console,
|
|
31
|
+
`%c${o}`,
|
|
32
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
33
|
+
) : Function.prototype.bind.call(
|
|
34
|
+
console.info,
|
|
35
|
+
console,
|
|
36
|
+
`%c${o}`,
|
|
37
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
38
|
+
) : () => {
|
|
39
|
+
},
|
|
40
|
+
log: n ? o ? Function.prototype.bind.call(
|
|
41
|
+
console.log,
|
|
42
|
+
console,
|
|
43
|
+
`%c${o}`,
|
|
44
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
45
|
+
) : Function.prototype.bind.call(console.log, console) : () => {
|
|
46
|
+
},
|
|
47
|
+
warn: n ? o ? Function.prototype.bind.call(
|
|
48
|
+
console.warn,
|
|
49
|
+
console,
|
|
50
|
+
`%c${o}`,
|
|
51
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
52
|
+
) : Function.prototype.bind.call(
|
|
53
|
+
console.warn,
|
|
54
|
+
console,
|
|
55
|
+
`%c${o}`,
|
|
56
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
57
|
+
) : () => {
|
|
58
|
+
},
|
|
59
|
+
error: n ? o ? Function.prototype.bind.call(
|
|
60
|
+
console.error,
|
|
61
|
+
console,
|
|
62
|
+
`%c${o}`,
|
|
63
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
64
|
+
) : Function.prototype.bind.call(
|
|
65
|
+
console.error,
|
|
66
|
+
console,
|
|
67
|
+
`%c${o}`,
|
|
68
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
69
|
+
) : () => {
|
|
70
|
+
}
|
|
71
|
+
}), _ = {
|
|
72
|
+
...u(),
|
|
73
|
+
namespace: (o, n, e) => u(`[${o}]`, n, e)
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const name = "@prose-reader/enhancer-search";
|
|
77
|
+
|
|
78
|
+
const IS_DEBUG_ENABLED = true;
|
|
79
|
+
const report = _.namespace(name, IS_DEBUG_ENABLED);
|
|
80
|
+
|
|
81
|
+
const searchNodeContainingText = (node, text) => {
|
|
82
|
+
const nodeList = node.childNodes;
|
|
83
|
+
if (node.nodeName === `head`) return [];
|
|
84
|
+
const rangeList = [];
|
|
85
|
+
for (let i = 0; i < nodeList.length; i++) {
|
|
86
|
+
const subNode = nodeList[i];
|
|
87
|
+
if (!subNode) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (subNode?.hasChildNodes()) {
|
|
91
|
+
rangeList.push(...searchNodeContainingText(subNode, text));
|
|
92
|
+
}
|
|
93
|
+
if (subNode.nodeType === 3) {
|
|
94
|
+
const content = subNode.data.toLowerCase();
|
|
95
|
+
if (content) {
|
|
96
|
+
let match = null;
|
|
97
|
+
const regexp = RegExp(`(${text})`, `gi`);
|
|
98
|
+
while ((match = regexp.exec(content)) !== null) {
|
|
99
|
+
if (match.index >= 0 && subNode.ownerDocument) {
|
|
100
|
+
const range = subNode.ownerDocument.createRange();
|
|
101
|
+
range.setStart(subNode, match.index);
|
|
102
|
+
range.setEnd(subNode, match.index + text.length);
|
|
103
|
+
rangeList.push(range);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return rangeList;
|
|
110
|
+
};
|
|
111
|
+
const searchInDocument = (reader, item, doc, text) => {
|
|
112
|
+
const ranges = searchNodeContainingText(doc, text);
|
|
113
|
+
const newResults = ranges.map((range) => {
|
|
114
|
+
const cfi = reader.cfi.generateCfiFromRange(range, item.item);
|
|
115
|
+
return {
|
|
116
|
+
cfi
|
|
117
|
+
};
|
|
118
|
+
});
|
|
119
|
+
return of(newResults);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const searchEnhancer = (next) => (options) => {
|
|
123
|
+
const reader = next(options);
|
|
124
|
+
const searchForItem = (index, text) => {
|
|
125
|
+
const item = reader.spineItemsManager.get(index);
|
|
126
|
+
if (!item) {
|
|
127
|
+
return of([]);
|
|
128
|
+
}
|
|
129
|
+
return deferIdle(() => reader.renderHeadless(index)).pipe(
|
|
130
|
+
switchMap((result) => {
|
|
131
|
+
const { doc, release } = result || {};
|
|
132
|
+
if (!doc) return of([]);
|
|
133
|
+
return deferIdle(
|
|
134
|
+
() => searchInDocument(reader, item, doc, text)
|
|
135
|
+
).pipe(
|
|
136
|
+
finalize(() => {
|
|
137
|
+
release?.();
|
|
138
|
+
}),
|
|
139
|
+
catchError((e) => {
|
|
140
|
+
report.error(e);
|
|
141
|
+
return of([]);
|
|
142
|
+
})
|
|
143
|
+
);
|
|
144
|
+
})
|
|
145
|
+
);
|
|
146
|
+
};
|
|
147
|
+
const search = (text) => defer(() => {
|
|
148
|
+
if (text === ``) {
|
|
149
|
+
return of([]);
|
|
150
|
+
}
|
|
151
|
+
const searches$ = reader.context.manifest?.spineItems.map(
|
|
152
|
+
(_, index) => searchForItem(index, text)
|
|
153
|
+
) || [];
|
|
154
|
+
return forkJoin([...searches$, of([])]);
|
|
155
|
+
}).pipe(
|
|
156
|
+
map((results) => {
|
|
157
|
+
const flattenedResults = results.flat();
|
|
158
|
+
report.debug("results", flattenedResults);
|
|
159
|
+
return flattenedResults;
|
|
160
|
+
})
|
|
161
|
+
);
|
|
162
|
+
return {
|
|
163
|
+
...reader,
|
|
164
|
+
__PROSE_READER_ENHANCER_SEARCH: true,
|
|
165
|
+
search: {
|
|
166
|
+
search
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export { searchEnhancer };
|
|
172
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../shared/dist/index.js","../src/report.ts","../src/search.ts","../src/index.ts"],"sourcesContent":["const a = (o, n) => o === n ? !0 : o.length !== n.length ? !1 : o.every((e, t) => e === n[t]), f = (o) => o.split(/[#?]/)[0]?.split(\".\").pop()?.trim() || \"\";\nfunction s(o) {\n const n = [];\n if (o.length === 0)\n return \"\";\n if (typeof o[0] != \"string\")\n throw new TypeError(`Url must be a string. Received ${o[0]}`);\n o[0].match(/^[^/:]+:\\/*$/) && o.length > 1 && (o[0] = o.shift() + o[0]), o[0].match(/^file:\\/\\/\\//) ? o[0] = o[0].replace(/^([^/:]+):\\/*/, \"$1:///\") : o[0] = o[0].replace(/^([^/:]+):\\/*/, \"$1://\");\n for (let l = 0; l < o.length; l++) {\n let r = o[l];\n if (typeof r != \"string\")\n throw new TypeError(`Url must be a string. Received ${r}`);\n r !== \"\" && (l > 0 && (r = r.replace(/^[/]+/, \"\")), l < o.length - 1 ? r = r.replace(/[/]+$/, \"\") : r = r.replace(/[/]+$/, \"/\"), n.push(r));\n }\n let e = n.join(\"/\");\n e = e.replace(/\\/(\\?|&|#[^!])/g, \"$1\");\n const t = e.split(\"?\");\n return e = t.shift() + (t.length > 0 ? \"?\" : \"\") + t.join(\"&\"), e;\n}\nfunction E(...o) {\n const n = Array.from(Array.isArray(o[0]) ? o[0] : o);\n return s(n);\n}\nfunction y(o) {\n const n = o.split(\"/\");\n return n.pop(), n.join(\"/\");\n}\nconst p = (o) => {\n switch (f(o)) {\n case \"png\":\n return \"image/png\";\n case \"jpg\":\n return \"image/jpg\";\n case \"jpeg\":\n return \"image/jpeg\";\n case \"txt\":\n return \"text/plain\";\n case \"webp\":\n return \"image/webp\";\n case \"xhtml\":\n return \"application/xhtml+xml\";\n }\n}, w = ({\n mimeType: o,\n uri: n\n}) => (o ?? p(n ?? \"\"))?.startsWith(\"application/xhtml+xml\"), R = (o) => o.length ? o.indexOf(\";\") ? o.substring(0, o.indexOf(\";\")) : o : void 0, g = Object.prototype.hasOwnProperty, d = (o, n) => o === n ? o !== 0 || n !== 0 || 1 / o === 1 / n : !1, m = (o, n, e) => {\n if (o === n)\n return !0;\n if (typeof o != \"object\" || o === null || typeof n != \"object\" || n === null)\n return !1;\n const t = Object.keys(o), l = Object.keys(n);\n if (t.length !== l.length)\n return !1;\n const r = e && typeof e.customEqual == \"function\" ? e.customEqual : d;\n for (let c = 0; c < t.length; c++) {\n const i = t[c] || \"\";\n if (!g.call(n, i) || !r(o[i], n[i]))\n return !1;\n }\n return !0;\n}, v = (o, n) => o.reduce(\n (e, t) => {\n const l = n(t);\n return e[l] || (e[l] = []), e[l].push(t), e;\n },\n {}\n);\nfunction O(o, n) {\n const e = { ...o };\n for (const t in n)\n if (Object.hasOwn(n, t)) {\n const l = n[t];\n (l !== void 0 || !(t in o)) && (e[t] = l);\n }\n return e;\n}\nconst h = () => {\n if (!(typeof window > \"u\"))\n return window;\n};\nfunction $() {\n const o = h()?.__PROSE_READER_DEBUG;\n return o === !0 || o === \"true\";\n}\nconst u = (o, n = $(), e) => ({\n namespace: (t, l) => u(`${o} [${t}]`, l, e),\n debug: n ? o ? Function.prototype.bind.call(\n console.debug,\n console,\n o,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : Function.prototype.bind.call(\n console.debug,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : () => {\n },\n info: n ? o ? Function.prototype.bind.call(\n console.info,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : Function.prototype.bind.call(\n console.info,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : () => {\n },\n log: n ? o ? Function.prototype.bind.call(\n console.log,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : Function.prototype.bind.call(console.log, console) : () => {\n },\n warn: n ? o ? Function.prototype.bind.call(\n console.warn,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : Function.prototype.bind.call(\n console.warn,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : () => {\n },\n error: n ? o ? Function.prototype.bind.call(\n console.error,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : Function.prototype.bind.call(\n console.error,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : () => {\n }\n}), _ = {\n ...u(),\n namespace: (o, n, e) => u(`[${o}]`, n, e)\n}, x = \"prose-reader-resource-error\";\nexport {\n x as PROSE_READER_RESOURCE_ERROR_INJECTED_META_NAME,\n _ as Report,\n a as arrayEqual,\n p as detectMimeTypeFromName,\n y as getParentPath,\n f as getUrlExtension,\n v as groupBy,\n d as is,\n m as isShallowEqual,\n w as isXmlBasedMimeType,\n R as parseContentType,\n O as shallowMergeIfDefined,\n E as urlJoin\n};\n//# sourceMappingURL=index.js.map\n","import { Report } from \"@prose-reader/shared\"\nimport { name } from \"../package.json\"\n\nconst IS_DEBUG_ENABLED = true\n\nexport const report = Report.namespace(name, IS_DEBUG_ENABLED)\n","import type { Reader, SpineItem } from \"@prose-reader/core\"\nimport { type Observable, of } from \"rxjs\"\nimport type { ResultItem } from \"./types\"\n\nexport type SearchResult = ResultItem[]\n\nconst searchNodeContainingText = (node: Node, text: string) => {\n const nodeList = node.childNodes\n\n if (node.nodeName === `head`) return []\n\n const rangeList: Range[] = []\n\n for (let i = 0; i < nodeList.length; i++) {\n const subNode = nodeList[i]\n\n if (!subNode) {\n continue\n }\n\n if (subNode?.hasChildNodes()) {\n rangeList.push(...searchNodeContainingText(subNode, text))\n }\n\n if (subNode.nodeType === 3) {\n const content = (subNode as Text).data.toLowerCase()\n if (content) {\n let match: RegExpExecArray | null = null\n const regexp = RegExp(`(${text})`, `gi`)\n\n // biome-ignore lint/suspicious/noAssignInExpressions: TODO\n while ((match = regexp.exec(content)) !== null) {\n if (match.index >= 0 && subNode.ownerDocument) {\n const range = subNode.ownerDocument.createRange()\n range.setStart(subNode, match.index)\n range.setEnd(subNode, match.index + text.length)\n\n rangeList.push(range)\n }\n }\n }\n }\n }\n\n return rangeList\n}\n\nexport const searchInDocument = (\n reader: Reader,\n item: SpineItem,\n doc: Document,\n text: string,\n): Observable<SearchResult> => {\n const ranges = searchNodeContainingText(doc, text)\n\n const newResults = ranges.map((range) => {\n const cfi = reader.cfi.generateCfiFromRange(range, item.item)\n\n return {\n cfi,\n } satisfies ResultItem\n })\n\n return of(newResults)\n}\n","import { deferIdle, type Reader } from \"@prose-reader/core\"\nimport { defer, forkJoin, of } from \"rxjs\"\nimport { catchError, finalize, map, switchMap } from \"rxjs/operators\"\nimport { report } from \"./report\"\nimport type { SearchResult } from \"./search\"\nimport { searchInDocument } from \"./search\"\nimport type { ResultItem, SearchEnhancerAPI } from \"./types\"\n\nexport type { SearchEnhancerAPI, ResultItem, SearchResult }\n\n/**\n * Contract of search enhancer.\n *\n * - At best a result match should be navigable. It means the search needs to\n * be done on a rendered document. This is because rendering can differ from the original\n * item resource. A resource can be something non digestible and very specific (.pdf). The search\n * enhancer is agnostic and can only search into documents.\n */\nexport const searchEnhancer =\n <InheritOptions, InheritOutput extends Reader>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput & SearchEnhancerAPI => {\n const reader = next(options)\n\n const searchForItem = (index: number, text: string) => {\n const item = reader.spineItemsManager.get(index)\n\n if (!item) {\n return of([])\n }\n\n return deferIdle(() => reader.renderHeadless(index)).pipe(\n switchMap((result) => {\n const { doc, release } = result || {}\n\n if (!doc) return of([])\n\n return deferIdle(() =>\n searchInDocument(reader, item, doc, text),\n ).pipe(\n finalize(() => {\n release?.()\n }),\n catchError((e) => {\n report.error(e)\n\n return of([])\n }),\n )\n }),\n )\n }\n\n const search = (text: string) =>\n defer(() => {\n if (text === ``) {\n return of([])\n }\n\n const searches$ =\n reader.context.manifest?.spineItems.map((_, index) =>\n searchForItem(index, text),\n ) || []\n\n return forkJoin([...searches$, of([])])\n }).pipe(\n map((results) => {\n const flattenedResults = results.flat()\n\n report.debug(\"results\", flattenedResults)\n\n return flattenedResults\n }),\n )\n\n return {\n ...reader,\n __PROSE_READER_ENHANCER_SEARCH: true,\n search: {\n search,\n },\n }\n }\n"],"names":["Report"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
(function (global, factory) {
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@prose-reader/core'), require('rxjs'), require('rxjs/operators')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', '@prose-reader/core', 'rxjs', 'rxjs/operators'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["prose-reader-enhancer-search"] = {}, global.core, global.rxjs, global.operators));
|
|
5
|
+
})(this, (function (exports, core, rxjs, operators) { 'use strict';
|
|
6
|
+
|
|
7
|
+
const h = () => {
|
|
8
|
+
if (!(typeof window > "u"))
|
|
9
|
+
return window;
|
|
10
|
+
};
|
|
11
|
+
function $() {
|
|
12
|
+
const o = h()?.__PROSE_READER_DEBUG;
|
|
13
|
+
return o === true || o === "true";
|
|
14
|
+
}
|
|
15
|
+
const u = (o, n = $(), e) => ({
|
|
16
|
+
namespace: (t, l) => u(`${o} [${t}]`, l, e),
|
|
17
|
+
debug: n ? o ? Function.prototype.bind.call(
|
|
18
|
+
console.debug,
|
|
19
|
+
console,
|
|
20
|
+
o,
|
|
21
|
+
`%c${o}`,
|
|
22
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
23
|
+
) : Function.prototype.bind.call(
|
|
24
|
+
console.debug,
|
|
25
|
+
console,
|
|
26
|
+
`%c${o}`,
|
|
27
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
28
|
+
) : () => {
|
|
29
|
+
},
|
|
30
|
+
info: n ? o ? Function.prototype.bind.call(
|
|
31
|
+
console.info,
|
|
32
|
+
console,
|
|
33
|
+
`%c${o}`,
|
|
34
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
35
|
+
) : Function.prototype.bind.call(
|
|
36
|
+
console.info,
|
|
37
|
+
console,
|
|
38
|
+
`%c${o}`,
|
|
39
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
40
|
+
) : () => {
|
|
41
|
+
},
|
|
42
|
+
log: n ? o ? Function.prototype.bind.call(
|
|
43
|
+
console.log,
|
|
44
|
+
console,
|
|
45
|
+
`%c${o}`,
|
|
46
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
47
|
+
) : Function.prototype.bind.call(console.log, console) : () => {
|
|
48
|
+
},
|
|
49
|
+
warn: n ? o ? Function.prototype.bind.call(
|
|
50
|
+
console.warn,
|
|
51
|
+
console,
|
|
52
|
+
`%c${o}`,
|
|
53
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
54
|
+
) : Function.prototype.bind.call(
|
|
55
|
+
console.warn,
|
|
56
|
+
console,
|
|
57
|
+
`%c${o}`,
|
|
58
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
59
|
+
) : () => {
|
|
60
|
+
},
|
|
61
|
+
error: n ? o ? Function.prototype.bind.call(
|
|
62
|
+
console.error,
|
|
63
|
+
console,
|
|
64
|
+
`%c${o}`,
|
|
65
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
66
|
+
) : Function.prototype.bind.call(
|
|
67
|
+
console.error,
|
|
68
|
+
console,
|
|
69
|
+
`%c${o}`,
|
|
70
|
+
e?.color ? `color: ${e.color}` : void 0
|
|
71
|
+
) : () => {
|
|
72
|
+
}
|
|
73
|
+
}), _ = {
|
|
74
|
+
...u(),
|
|
75
|
+
namespace: (o, n, e) => u(`[${o}]`, n, e)
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const name = "@prose-reader/enhancer-search";
|
|
79
|
+
|
|
80
|
+
const IS_DEBUG_ENABLED = true;
|
|
81
|
+
const report = _.namespace(name, IS_DEBUG_ENABLED);
|
|
82
|
+
|
|
83
|
+
const searchNodeContainingText = (node, text) => {
|
|
84
|
+
const nodeList = node.childNodes;
|
|
85
|
+
if (node.nodeName === `head`) return [];
|
|
86
|
+
const rangeList = [];
|
|
87
|
+
for (let i = 0; i < nodeList.length; i++) {
|
|
88
|
+
const subNode = nodeList[i];
|
|
89
|
+
if (!subNode) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (subNode?.hasChildNodes()) {
|
|
93
|
+
rangeList.push(...searchNodeContainingText(subNode, text));
|
|
94
|
+
}
|
|
95
|
+
if (subNode.nodeType === 3) {
|
|
96
|
+
const content = subNode.data.toLowerCase();
|
|
97
|
+
if (content) {
|
|
98
|
+
let match = null;
|
|
99
|
+
const regexp = RegExp(`(${text})`, `gi`);
|
|
100
|
+
while ((match = regexp.exec(content)) !== null) {
|
|
101
|
+
if (match.index >= 0 && subNode.ownerDocument) {
|
|
102
|
+
const range = subNode.ownerDocument.createRange();
|
|
103
|
+
range.setStart(subNode, match.index);
|
|
104
|
+
range.setEnd(subNode, match.index + text.length);
|
|
105
|
+
rangeList.push(range);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return rangeList;
|
|
112
|
+
};
|
|
113
|
+
const searchInDocument = (reader, item, doc, text) => {
|
|
114
|
+
const ranges = searchNodeContainingText(doc, text);
|
|
115
|
+
const newResults = ranges.map((range) => {
|
|
116
|
+
const cfi = reader.cfi.generateCfiFromRange(range, item.item);
|
|
117
|
+
return {
|
|
118
|
+
cfi
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
return rxjs.of(newResults);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const searchEnhancer = (next) => (options) => {
|
|
125
|
+
const reader = next(options);
|
|
126
|
+
const searchForItem = (index, text) => {
|
|
127
|
+
const item = reader.spineItemsManager.get(index);
|
|
128
|
+
if (!item) {
|
|
129
|
+
return rxjs.of([]);
|
|
130
|
+
}
|
|
131
|
+
return core.deferIdle(() => reader.renderHeadless(index)).pipe(
|
|
132
|
+
operators.switchMap((result) => {
|
|
133
|
+
const { doc, release } = result || {};
|
|
134
|
+
if (!doc) return rxjs.of([]);
|
|
135
|
+
return core.deferIdle(
|
|
136
|
+
() => searchInDocument(reader, item, doc, text)
|
|
137
|
+
).pipe(
|
|
138
|
+
operators.finalize(() => {
|
|
139
|
+
release?.();
|
|
140
|
+
}),
|
|
141
|
+
operators.catchError((e) => {
|
|
142
|
+
report.error(e);
|
|
143
|
+
return rxjs.of([]);
|
|
144
|
+
})
|
|
145
|
+
);
|
|
146
|
+
})
|
|
147
|
+
);
|
|
148
|
+
};
|
|
149
|
+
const search = (text) => rxjs.defer(() => {
|
|
150
|
+
if (text === ``) {
|
|
151
|
+
return rxjs.of([]);
|
|
152
|
+
}
|
|
153
|
+
const searches$ = reader.context.manifest?.spineItems.map(
|
|
154
|
+
(_, index) => searchForItem(index, text)
|
|
155
|
+
) || [];
|
|
156
|
+
return rxjs.forkJoin([...searches$, rxjs.of([])]);
|
|
157
|
+
}).pipe(
|
|
158
|
+
operators.map((results) => {
|
|
159
|
+
const flattenedResults = results.flat();
|
|
160
|
+
report.debug("results", flattenedResults);
|
|
161
|
+
return flattenedResults;
|
|
162
|
+
})
|
|
163
|
+
);
|
|
164
|
+
return {
|
|
165
|
+
...reader,
|
|
166
|
+
__PROSE_READER_ENHANCER_SEARCH: true,
|
|
167
|
+
search: {
|
|
168
|
+
search
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
exports.searchEnhancer = searchEnhancer;
|
|
174
|
+
|
|
175
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
176
|
+
|
|
177
|
+
}));
|
|
178
|
+
//# sourceMappingURL=index.umd.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.umd.cjs","sources":["../../shared/dist/index.js","../src/report.ts","../src/search.ts","../src/index.ts"],"sourcesContent":["const a = (o, n) => o === n ? !0 : o.length !== n.length ? !1 : o.every((e, t) => e === n[t]), f = (o) => o.split(/[#?]/)[0]?.split(\".\").pop()?.trim() || \"\";\nfunction s(o) {\n const n = [];\n if (o.length === 0)\n return \"\";\n if (typeof o[0] != \"string\")\n throw new TypeError(`Url must be a string. Received ${o[0]}`);\n o[0].match(/^[^/:]+:\\/*$/) && o.length > 1 && (o[0] = o.shift() + o[0]), o[0].match(/^file:\\/\\/\\//) ? o[0] = o[0].replace(/^([^/:]+):\\/*/, \"$1:///\") : o[0] = o[0].replace(/^([^/:]+):\\/*/, \"$1://\");\n for (let l = 0; l < o.length; l++) {\n let r = o[l];\n if (typeof r != \"string\")\n throw new TypeError(`Url must be a string. Received ${r}`);\n r !== \"\" && (l > 0 && (r = r.replace(/^[/]+/, \"\")), l < o.length - 1 ? r = r.replace(/[/]+$/, \"\") : r = r.replace(/[/]+$/, \"/\"), n.push(r));\n }\n let e = n.join(\"/\");\n e = e.replace(/\\/(\\?|&|#[^!])/g, \"$1\");\n const t = e.split(\"?\");\n return e = t.shift() + (t.length > 0 ? \"?\" : \"\") + t.join(\"&\"), e;\n}\nfunction E(...o) {\n const n = Array.from(Array.isArray(o[0]) ? o[0] : o);\n return s(n);\n}\nfunction y(o) {\n const n = o.split(\"/\");\n return n.pop(), n.join(\"/\");\n}\nconst p = (o) => {\n switch (f(o)) {\n case \"png\":\n return \"image/png\";\n case \"jpg\":\n return \"image/jpg\";\n case \"jpeg\":\n return \"image/jpeg\";\n case \"txt\":\n return \"text/plain\";\n case \"webp\":\n return \"image/webp\";\n case \"xhtml\":\n return \"application/xhtml+xml\";\n }\n}, w = ({\n mimeType: o,\n uri: n\n}) => (o ?? p(n ?? \"\"))?.startsWith(\"application/xhtml+xml\"), R = (o) => o.length ? o.indexOf(\";\") ? o.substring(0, o.indexOf(\";\")) : o : void 0, g = Object.prototype.hasOwnProperty, d = (o, n) => o === n ? o !== 0 || n !== 0 || 1 / o === 1 / n : !1, m = (o, n, e) => {\n if (o === n)\n return !0;\n if (typeof o != \"object\" || o === null || typeof n != \"object\" || n === null)\n return !1;\n const t = Object.keys(o), l = Object.keys(n);\n if (t.length !== l.length)\n return !1;\n const r = e && typeof e.customEqual == \"function\" ? e.customEqual : d;\n for (let c = 0; c < t.length; c++) {\n const i = t[c] || \"\";\n if (!g.call(n, i) || !r(o[i], n[i]))\n return !1;\n }\n return !0;\n}, v = (o, n) => o.reduce(\n (e, t) => {\n const l = n(t);\n return e[l] || (e[l] = []), e[l].push(t), e;\n },\n {}\n);\nfunction O(o, n) {\n const e = { ...o };\n for (const t in n)\n if (Object.hasOwn(n, t)) {\n const l = n[t];\n (l !== void 0 || !(t in o)) && (e[t] = l);\n }\n return e;\n}\nconst h = () => {\n if (!(typeof window > \"u\"))\n return window;\n};\nfunction $() {\n const o = h()?.__PROSE_READER_DEBUG;\n return o === !0 || o === \"true\";\n}\nconst u = (o, n = $(), e) => ({\n namespace: (t, l) => u(`${o} [${t}]`, l, e),\n debug: n ? o ? Function.prototype.bind.call(\n console.debug,\n console,\n o,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : Function.prototype.bind.call(\n console.debug,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : () => {\n },\n info: n ? o ? Function.prototype.bind.call(\n console.info,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : Function.prototype.bind.call(\n console.info,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : () => {\n },\n log: n ? o ? Function.prototype.bind.call(\n console.log,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : Function.prototype.bind.call(console.log, console) : () => {\n },\n warn: n ? o ? Function.prototype.bind.call(\n console.warn,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : Function.prototype.bind.call(\n console.warn,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : () => {\n },\n error: n ? o ? Function.prototype.bind.call(\n console.error,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : Function.prototype.bind.call(\n console.error,\n console,\n `%c${o}`,\n e?.color ? `color: ${e.color}` : void 0\n ) : () => {\n }\n}), _ = {\n ...u(),\n namespace: (o, n, e) => u(`[${o}]`, n, e)\n}, x = \"prose-reader-resource-error\";\nexport {\n x as PROSE_READER_RESOURCE_ERROR_INJECTED_META_NAME,\n _ as Report,\n a as arrayEqual,\n p as detectMimeTypeFromName,\n y as getParentPath,\n f as getUrlExtension,\n v as groupBy,\n d as is,\n m as isShallowEqual,\n w as isXmlBasedMimeType,\n R as parseContentType,\n O as shallowMergeIfDefined,\n E as urlJoin\n};\n//# sourceMappingURL=index.js.map\n","import { Report } from \"@prose-reader/shared\"\nimport { name } from \"../package.json\"\n\nconst IS_DEBUG_ENABLED = true\n\nexport const report = Report.namespace(name, IS_DEBUG_ENABLED)\n","import type { Reader, SpineItem } from \"@prose-reader/core\"\nimport { type Observable, of } from \"rxjs\"\nimport type { ResultItem } from \"./types\"\n\nexport type SearchResult = ResultItem[]\n\nconst searchNodeContainingText = (node: Node, text: string) => {\n const nodeList = node.childNodes\n\n if (node.nodeName === `head`) return []\n\n const rangeList: Range[] = []\n\n for (let i = 0; i < nodeList.length; i++) {\n const subNode = nodeList[i]\n\n if (!subNode) {\n continue\n }\n\n if (subNode?.hasChildNodes()) {\n rangeList.push(...searchNodeContainingText(subNode, text))\n }\n\n if (subNode.nodeType === 3) {\n const content = (subNode as Text).data.toLowerCase()\n if (content) {\n let match: RegExpExecArray | null = null\n const regexp = RegExp(`(${text})`, `gi`)\n\n // biome-ignore lint/suspicious/noAssignInExpressions: TODO\n while ((match = regexp.exec(content)) !== null) {\n if (match.index >= 0 && subNode.ownerDocument) {\n const range = subNode.ownerDocument.createRange()\n range.setStart(subNode, match.index)\n range.setEnd(subNode, match.index + text.length)\n\n rangeList.push(range)\n }\n }\n }\n }\n }\n\n return rangeList\n}\n\nexport const searchInDocument = (\n reader: Reader,\n item: SpineItem,\n doc: Document,\n text: string,\n): Observable<SearchResult> => {\n const ranges = searchNodeContainingText(doc, text)\n\n const newResults = ranges.map((range) => {\n const cfi = reader.cfi.generateCfiFromRange(range, item.item)\n\n return {\n cfi,\n } satisfies ResultItem\n })\n\n return of(newResults)\n}\n","import { deferIdle, type Reader } from \"@prose-reader/core\"\nimport { defer, forkJoin, of } from \"rxjs\"\nimport { catchError, finalize, map, switchMap } from \"rxjs/operators\"\nimport { report } from \"./report\"\nimport type { SearchResult } from \"./search\"\nimport { searchInDocument } from \"./search\"\nimport type { ResultItem, SearchEnhancerAPI } from \"./types\"\n\nexport type { SearchEnhancerAPI, ResultItem, SearchResult }\n\n/**\n * Contract of search enhancer.\n *\n * - At best a result match should be navigable. It means the search needs to\n * be done on a rendered document. This is because rendering can differ from the original\n * item resource. A resource can be something non digestible and very specific (.pdf). The search\n * enhancer is agnostic and can only search into documents.\n */\nexport const searchEnhancer =\n <InheritOptions, InheritOutput extends Reader>(\n next: (options: InheritOptions) => InheritOutput,\n ) =>\n (options: InheritOptions): InheritOutput & SearchEnhancerAPI => {\n const reader = next(options)\n\n const searchForItem = (index: number, text: string) => {\n const item = reader.spineItemsManager.get(index)\n\n if (!item) {\n return of([])\n }\n\n return deferIdle(() => reader.renderHeadless(index)).pipe(\n switchMap((result) => {\n const { doc, release } = result || {}\n\n if (!doc) return of([])\n\n return deferIdle(() =>\n searchInDocument(reader, item, doc, text),\n ).pipe(\n finalize(() => {\n release?.()\n }),\n catchError((e) => {\n report.error(e)\n\n return of([])\n }),\n )\n }),\n )\n }\n\n const search = (text: string) =>\n defer(() => {\n if (text === ``) {\n return of([])\n }\n\n const searches$ =\n reader.context.manifest?.spineItems.map((_, index) =>\n searchForItem(index, text),\n ) || []\n\n return forkJoin([...searches$, of([])])\n }).pipe(\n map((results) => {\n const flattenedResults = results.flat()\n\n report.debug(\"results\", flattenedResults)\n\n return flattenedResults\n }),\n )\n\n return {\n ...reader,\n __PROSE_READER_ENHANCER_SEARCH: true,\n search: {\n search,\n },\n }\n }\n"],"names":["Report","of","deferIdle","switchMap","finalize","catchError","defer","forkJoin","map"],"mappings":"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"}
|
package/dist/report.d.ts
ADDED
package/dist/search.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Reader, SpineItem } from '@prose-reader/core';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { ResultItem } from './types';
|
|
4
|
+
export type SearchResult = ResultItem[];
|
|
5
|
+
export declare const searchInDocument: (reader: Reader, item: SpineItem, doc: Document, text: string) => Observable<SearchResult>;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { SearchResult } from './search';
|
|
3
|
+
export type ResultItem = {
|
|
4
|
+
cfi: string;
|
|
5
|
+
};
|
|
6
|
+
export type SearchEnhancerAPI = {
|
|
7
|
+
readonly __PROSE_READER_ENHANCER_SEARCH: boolean;
|
|
8
|
+
search: {
|
|
9
|
+
search: (text: string) => Observable<SearchResult>;
|
|
10
|
+
};
|
|
11
|
+
};
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prose-reader/enhancer-search",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.267.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.umd.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"/dist"
|
|
10
|
+
],
|
|
8
11
|
"exports": {
|
|
9
12
|
".": {
|
|
10
13
|
"import": "./dist/index.js",
|
|
@@ -17,10 +20,10 @@
|
|
|
17
20
|
"test": "vitest run --coverage"
|
|
18
21
|
},
|
|
19
22
|
"dependencies": {
|
|
20
|
-
"@prose-reader/core": "^1.
|
|
23
|
+
"@prose-reader/core": "^1.267.0"
|
|
21
24
|
},
|
|
22
25
|
"peerDependencies": {
|
|
23
26
|
"rxjs": "*"
|
|
24
27
|
},
|
|
25
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "e5f85deb4ba626a43cf9b7853f8527e5e171eee8"
|
|
26
29
|
}
|
package/src/index.test.ts
DELETED
package/src/index.ts
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { deferIdle, type Reader } from "@prose-reader/core"
|
|
2
|
-
import { defer, forkJoin, of } from "rxjs"
|
|
3
|
-
import { catchError, finalize, map, switchMap } from "rxjs/operators"
|
|
4
|
-
import { report } from "./report"
|
|
5
|
-
import type { SearchResult } from "./search"
|
|
6
|
-
import { searchInDocument } from "./search"
|
|
7
|
-
import type { ResultItem, SearchEnhancerAPI } from "./types"
|
|
8
|
-
|
|
9
|
-
export type { SearchEnhancerAPI, ResultItem, SearchResult }
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Contract of search enhancer.
|
|
13
|
-
*
|
|
14
|
-
* - At best a result match should be navigable. It means the search needs to
|
|
15
|
-
* be done on a rendered document. This is because rendering can differ from the original
|
|
16
|
-
* item resource. A resource can be something non digestible and very specific (.pdf). The search
|
|
17
|
-
* enhancer is agnostic and can only search into documents.
|
|
18
|
-
*/
|
|
19
|
-
export const searchEnhancer =
|
|
20
|
-
<InheritOptions, InheritOutput extends Reader>(
|
|
21
|
-
next: (options: InheritOptions) => InheritOutput,
|
|
22
|
-
) =>
|
|
23
|
-
(options: InheritOptions): InheritOutput & SearchEnhancerAPI => {
|
|
24
|
-
const reader = next(options)
|
|
25
|
-
|
|
26
|
-
const searchForItem = (index: number, text: string) => {
|
|
27
|
-
const item = reader.spineItemsManager.get(index)
|
|
28
|
-
|
|
29
|
-
if (!item) {
|
|
30
|
-
return of([])
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return deferIdle(() => reader.renderHeadless(index)).pipe(
|
|
34
|
-
switchMap((result) => {
|
|
35
|
-
const { doc, release } = result || {}
|
|
36
|
-
|
|
37
|
-
if (!doc) return of([])
|
|
38
|
-
|
|
39
|
-
return deferIdle(() =>
|
|
40
|
-
searchInDocument(reader, item, doc, text),
|
|
41
|
-
).pipe(
|
|
42
|
-
finalize(() => {
|
|
43
|
-
release?.()
|
|
44
|
-
}),
|
|
45
|
-
catchError((e) => {
|
|
46
|
-
report.error(e)
|
|
47
|
-
|
|
48
|
-
return of([])
|
|
49
|
-
}),
|
|
50
|
-
)
|
|
51
|
-
}),
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const search = (text: string) =>
|
|
56
|
-
defer(() => {
|
|
57
|
-
if (text === ``) {
|
|
58
|
-
return of([])
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const searches$ =
|
|
62
|
-
reader.context.manifest?.spineItems.map((_, index) =>
|
|
63
|
-
searchForItem(index, text),
|
|
64
|
-
) || []
|
|
65
|
-
|
|
66
|
-
return forkJoin([...searches$, of([])])
|
|
67
|
-
}).pipe(
|
|
68
|
-
map((results) => {
|
|
69
|
-
const flattenedResults = results.flat()
|
|
70
|
-
|
|
71
|
-
report.debug("results", flattenedResults)
|
|
72
|
-
|
|
73
|
-
return flattenedResults
|
|
74
|
-
}),
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
...reader,
|
|
79
|
-
__PROSE_READER_ENHANCER_SEARCH: true,
|
|
80
|
-
search: {
|
|
81
|
-
search,
|
|
82
|
-
},
|
|
83
|
-
}
|
|
84
|
-
}
|
package/src/report.ts
DELETED
package/src/search.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import type { Reader, SpineItem } from "@prose-reader/core"
|
|
2
|
-
import { type Observable, of } from "rxjs"
|
|
3
|
-
import type { ResultItem } from "./types"
|
|
4
|
-
|
|
5
|
-
export type SearchResult = ResultItem[]
|
|
6
|
-
|
|
7
|
-
const searchNodeContainingText = (node: Node, text: string) => {
|
|
8
|
-
const nodeList = node.childNodes
|
|
9
|
-
|
|
10
|
-
if (node.nodeName === `head`) return []
|
|
11
|
-
|
|
12
|
-
const rangeList: Range[] = []
|
|
13
|
-
|
|
14
|
-
for (let i = 0; i < nodeList.length; i++) {
|
|
15
|
-
const subNode = nodeList[i]
|
|
16
|
-
|
|
17
|
-
if (!subNode) {
|
|
18
|
-
continue
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (subNode?.hasChildNodes()) {
|
|
22
|
-
rangeList.push(...searchNodeContainingText(subNode, text))
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (subNode.nodeType === 3) {
|
|
26
|
-
const content = (subNode as Text).data.toLowerCase()
|
|
27
|
-
if (content) {
|
|
28
|
-
let match: RegExpExecArray | null = null
|
|
29
|
-
const regexp = RegExp(`(${text})`, `gi`)
|
|
30
|
-
|
|
31
|
-
// biome-ignore lint/suspicious/noAssignInExpressions: TODO
|
|
32
|
-
while ((match = regexp.exec(content)) !== null) {
|
|
33
|
-
if (match.index >= 0 && subNode.ownerDocument) {
|
|
34
|
-
const range = subNode.ownerDocument.createRange()
|
|
35
|
-
range.setStart(subNode, match.index)
|
|
36
|
-
range.setEnd(subNode, match.index + text.length)
|
|
37
|
-
|
|
38
|
-
rangeList.push(range)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return rangeList
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export const searchInDocument = (
|
|
49
|
-
reader: Reader,
|
|
50
|
-
item: SpineItem,
|
|
51
|
-
doc: Document,
|
|
52
|
-
text: string,
|
|
53
|
-
): Observable<SearchResult> => {
|
|
54
|
-
const ranges = searchNodeContainingText(doc, text)
|
|
55
|
-
|
|
56
|
-
const newResults = ranges.map((range) => {
|
|
57
|
-
const cfi = reader.cfi.generateCfiFromRange(range, item.item)
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
cfi,
|
|
61
|
-
} satisfies ResultItem
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
return of(newResults)
|
|
65
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { Observable } from "rxjs"
|
|
2
|
-
import type { SearchResult } from "./search"
|
|
3
|
-
|
|
4
|
-
export type ResultItem = {
|
|
5
|
-
cfi: string
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export type SearchEnhancerAPI = {
|
|
9
|
-
readonly __PROSE_READER_ENHANCER_SEARCH: boolean
|
|
10
|
-
search: {
|
|
11
|
-
search: (text: string) => Observable<SearchResult>
|
|
12
|
-
}
|
|
13
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"useDefineForClassFields": true,
|
|
5
|
-
"module": "ESNext",
|
|
6
|
-
"lib": ["ESNext", "DOM"],
|
|
7
|
-
"moduleResolution": "Node",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"resolveJsonModule": true,
|
|
10
|
-
"isolatedModules": true,
|
|
11
|
-
"esModuleInterop": true,
|
|
12
|
-
"noEmit": true,
|
|
13
|
-
"noUnusedLocals": true,
|
|
14
|
-
"noUnusedParameters": true,
|
|
15
|
-
"noImplicitReturns": true,
|
|
16
|
-
"skipLibCheck": true
|
|
17
|
-
},
|
|
18
|
-
"include": ["src"]
|
|
19
|
-
}
|
package/vite.config.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { resolve } from "node:path"
|
|
2
|
-
import externals from "rollup-plugin-node-externals"
|
|
3
|
-
import { defineConfig } from "vite"
|
|
4
|
-
import dts from "vite-plugin-dts"
|
|
5
|
-
import { name } from "./package.json"
|
|
6
|
-
|
|
7
|
-
const libName = name.replace(`@`, ``).replace(`/`, `-`)
|
|
8
|
-
|
|
9
|
-
export default defineConfig(({ mode }) => ({
|
|
10
|
-
build: {
|
|
11
|
-
minify: false,
|
|
12
|
-
target: "esnext",
|
|
13
|
-
lib: {
|
|
14
|
-
entry: resolve(__dirname, `src/index.ts`),
|
|
15
|
-
name: libName,
|
|
16
|
-
fileName: `index`,
|
|
17
|
-
},
|
|
18
|
-
emptyOutDir: mode !== `development`,
|
|
19
|
-
sourcemap: true,
|
|
20
|
-
},
|
|
21
|
-
plugins: [
|
|
22
|
-
externals({
|
|
23
|
-
peerDeps: true,
|
|
24
|
-
deps: true,
|
|
25
|
-
devDeps: true,
|
|
26
|
-
}),
|
|
27
|
-
dts({
|
|
28
|
-
entryRoot: "src",
|
|
29
|
-
}),
|
|
30
|
-
],
|
|
31
|
-
}))
|