@wdprlib/ast 4.3.0 → 5.0.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/THIRD-PARTY-LICENSES.md +8 -0
- package/dist/index.cjs +602 -306
- package/dist/index.d.cts +157 -70
- package/dist/index.d.ts +157 -70
- package/dist/index.js +602 -306
- package/licenses/re2js-MIT.txt +21 -0
- package/package.json +5 -1
- package/src/build-info.generated.ts +2 -2
- package/src/element.ts +4 -4
- package/src/index.ts +12 -0
- package/src/rating.ts +44 -0
- package/src/readable-text.ts +220 -0
- package/src/text-excerpt.ts +109 -0
package/dist/index.js
CHANGED
|
@@ -1,319 +1,42 @@
|
|
|
1
1
|
// packages/ast/src/build-info.generated.ts
|
|
2
2
|
var buildInfo = Object.freeze({
|
|
3
|
-
version: "
|
|
4
|
-
sha: "
|
|
3
|
+
version: "5.0.0",
|
|
4
|
+
sha: "705ff97e22abd7bfb49d7f8f30087e6f09654c91",
|
|
5
5
|
dirty: false
|
|
6
6
|
});
|
|
7
|
-
// packages/ast/src/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
function createPosition(start, end) {
|
|
12
|
-
return { start, end };
|
|
13
|
-
}
|
|
14
|
-
// packages/ast/src/element.ts
|
|
15
|
-
function isStringContainerType(type) {
|
|
16
|
-
return typeof type === "string";
|
|
17
|
-
}
|
|
18
|
-
function isHeaderType(type) {
|
|
19
|
-
return typeof type === "object" && type !== null && "header" in type;
|
|
20
|
-
}
|
|
21
|
-
function isAlignType(type) {
|
|
22
|
-
return typeof type === "object" && type !== null && "align" in type;
|
|
23
|
-
}
|
|
24
|
-
function text(value) {
|
|
25
|
-
return { element: "text", data: value };
|
|
26
|
-
}
|
|
27
|
-
function container(type, elements, attributes = {}) {
|
|
28
|
-
return {
|
|
29
|
-
element: "container",
|
|
30
|
-
data: { type, attributes, elements }
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
function paragraph(elements, attributes = {}) {
|
|
34
|
-
return container("paragraph", elements, attributes);
|
|
35
|
-
}
|
|
36
|
-
function bold(elements, attributes = {}) {
|
|
37
|
-
return container("bold", elements, attributes);
|
|
38
|
-
}
|
|
39
|
-
function italics(elements, attributes = {}) {
|
|
40
|
-
return container("italics", elements, attributes);
|
|
41
|
-
}
|
|
42
|
-
function heading(level, elements, hasToc = true, attributes = {}) {
|
|
43
|
-
return container({ header: { level, "has-toc": hasToc } }, elements, attributes);
|
|
7
|
+
// packages/ast/src/expr-eval.ts
|
|
8
|
+
var FALSE_VALUES = new Set(["false", "null", "", "0"]);
|
|
9
|
+
function isTruthy(value) {
|
|
10
|
+
return !FALSE_VALUES.has(value.toLowerCase().trim());
|
|
44
11
|
}
|
|
45
|
-
|
|
46
|
-
|
|
12
|
+
var MAX_EXPRESSION_LENGTH = 256;
|
|
13
|
+
function isTruthyNum(n) {
|
|
14
|
+
return n !== 0 && !Number.isNaN(n);
|
|
47
15
|
}
|
|
48
|
-
function
|
|
49
|
-
return
|
|
16
|
+
function formatExprValue(n) {
|
|
17
|
+
return String(n);
|
|
50
18
|
}
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
type: options.type ?? (typeof linkLocation === "string" ? "direct" : "page"),
|
|
56
|
-
link: linkLocation,
|
|
57
|
-
extra: options.extra ?? null,
|
|
58
|
-
label,
|
|
59
|
-
target: options.target ?? null
|
|
19
|
+
function evaluateExpression(expr) {
|
|
20
|
+
try {
|
|
21
|
+
if (expr.length > MAX_EXPRESSION_LENGTH) {
|
|
22
|
+
return { success: false, error: "expression too long" };
|
|
60
23
|
}
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
function list(type, items, attributes = {}) {
|
|
64
|
-
return {
|
|
65
|
-
element: "list",
|
|
66
|
-
data: { type, attributes, items }
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
function listItemElements(elements, attributes = {}) {
|
|
70
|
-
return {
|
|
71
|
-
"item-type": "elements",
|
|
72
|
-
attributes,
|
|
73
|
-
elements
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
function listItemSubList(data) {
|
|
77
|
-
return {
|
|
78
|
-
"item-type": "sub-list",
|
|
79
|
-
element: "list",
|
|
80
|
-
data
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
function isContainerTypeParagraphSafe(type) {
|
|
84
|
-
if (isHeaderType(type))
|
|
85
|
-
return false;
|
|
86
|
-
if (isAlignType(type))
|
|
87
|
-
return false;
|
|
88
|
-
switch (type) {
|
|
89
|
-
case "bold":
|
|
90
|
-
case "italics":
|
|
91
|
-
case "underline":
|
|
92
|
-
case "superscript":
|
|
93
|
-
case "subscript":
|
|
94
|
-
case "strikethrough":
|
|
95
|
-
case "monospace":
|
|
96
|
-
case "span":
|
|
97
|
-
case "size":
|
|
98
|
-
return true;
|
|
99
|
-
case "div":
|
|
100
|
-
case "note":
|
|
101
|
-
case "blockquote":
|
|
102
|
-
case "paragraph":
|
|
103
|
-
case "heading":
|
|
104
|
-
case "collapsible":
|
|
105
|
-
case "definition-list":
|
|
106
|
-
case "definition-list-item":
|
|
107
|
-
case "definition-list-key":
|
|
108
|
-
case "definition-list-value":
|
|
109
|
-
case "table-row":
|
|
110
|
-
case "table-cell":
|
|
111
|
-
return false;
|
|
112
|
-
default:
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
function isParagraphSafe(element) {
|
|
117
|
-
switch (element.element) {
|
|
118
|
-
case "container": {
|
|
119
|
-
const data = element.data;
|
|
120
|
-
return isContainerTypeParagraphSafe(data.type);
|
|
24
|
+
if (expr.trim() === "") {
|
|
25
|
+
return { success: false, error: "empty expression" };
|
|
121
26
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
case "raw":
|
|
126
|
-
case "variable":
|
|
127
|
-
case "email":
|
|
128
|
-
return true;
|
|
129
|
-
case "table":
|
|
130
|
-
return false;
|
|
131
|
-
case "tab-view":
|
|
132
|
-
return false;
|
|
133
|
-
case "anchor":
|
|
134
|
-
case "anchor-name":
|
|
135
|
-
case "link":
|
|
136
|
-
return true;
|
|
137
|
-
case "image":
|
|
138
|
-
return true;
|
|
139
|
-
case "list":
|
|
140
|
-
return false;
|
|
141
|
-
case "definition-list":
|
|
142
|
-
return false;
|
|
143
|
-
case "collapsible":
|
|
144
|
-
return false;
|
|
145
|
-
case "table-of-contents":
|
|
146
|
-
return false;
|
|
147
|
-
case "footnote":
|
|
148
|
-
return true;
|
|
149
|
-
case "footnote-ref":
|
|
150
|
-
return true;
|
|
151
|
-
case "footnote-block":
|
|
152
|
-
return false;
|
|
153
|
-
case "bibliography-cite":
|
|
154
|
-
return true;
|
|
155
|
-
case "bibliography-block":
|
|
156
|
-
return false;
|
|
157
|
-
case "user":
|
|
158
|
-
return true;
|
|
159
|
-
case "date":
|
|
160
|
-
case "social":
|
|
161
|
-
return true;
|
|
162
|
-
case "button":
|
|
163
|
-
return isPageButtonAction(element.data.action);
|
|
164
|
-
case "color":
|
|
165
|
-
return true;
|
|
166
|
-
case "code":
|
|
167
|
-
return false;
|
|
168
|
-
case "math":
|
|
169
|
-
return false;
|
|
170
|
-
case "math-inline":
|
|
171
|
-
return true;
|
|
172
|
-
case "embed":
|
|
173
|
-
return false;
|
|
174
|
-
case "embed-block":
|
|
175
|
-
return true;
|
|
176
|
-
case "html":
|
|
177
|
-
case "iframe":
|
|
178
|
-
return false;
|
|
179
|
-
case "include": {
|
|
180
|
-
const data = element.data;
|
|
181
|
-
return data["paragraph-safe"];
|
|
27
|
+
const tokens = tokenize(expr);
|
|
28
|
+
if (tokens.length <= 1) {
|
|
29
|
+
return { success: false, error: "empty expression" };
|
|
182
30
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
case "content-separator":
|
|
193
|
-
return false;
|
|
194
|
-
case "if-tags":
|
|
195
|
-
return false;
|
|
196
|
-
case "expr":
|
|
197
|
-
case "if":
|
|
198
|
-
case "ifexpr":
|
|
199
|
-
return true;
|
|
200
|
-
default:
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
function isPageButtonAction(action) {
|
|
205
|
-
switch (action) {
|
|
206
|
-
case "edit":
|
|
207
|
-
case "edit-append":
|
|
208
|
-
case "edit-sections":
|
|
209
|
-
case "history":
|
|
210
|
-
case "print":
|
|
211
|
-
case "files":
|
|
212
|
-
case "tags":
|
|
213
|
-
case "source":
|
|
214
|
-
case "backlinks":
|
|
215
|
-
case "talk":
|
|
216
|
-
case "delete":
|
|
217
|
-
case "rename":
|
|
218
|
-
case "site-tools":
|
|
219
|
-
case "edit-meta":
|
|
220
|
-
case "watchers":
|
|
221
|
-
case "parent":
|
|
222
|
-
case "lock-page":
|
|
223
|
-
return true;
|
|
224
|
-
default:
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
// packages/ast/src/constants.ts
|
|
229
|
-
var STYLE_SLOT_PREFIX = "\x00__IFTAGS_SLOT__";
|
|
230
|
-
var STYLE_ANCHOR_PREFIX = "\x00__STYLE_ANCHOR__";
|
|
231
|
-
// packages/ast/src/css.ts
|
|
232
|
-
var CSS_LENGTH_UNITS = [
|
|
233
|
-
"cqmax",
|
|
234
|
-
"cqmin",
|
|
235
|
-
"cqw",
|
|
236
|
-
"cqh",
|
|
237
|
-
"cqi",
|
|
238
|
-
"cqb",
|
|
239
|
-
"svmin",
|
|
240
|
-
"svmax",
|
|
241
|
-
"lvmin",
|
|
242
|
-
"lvmax",
|
|
243
|
-
"dvmin",
|
|
244
|
-
"dvmax",
|
|
245
|
-
"vmin",
|
|
246
|
-
"vmax",
|
|
247
|
-
"svw",
|
|
248
|
-
"svh",
|
|
249
|
-
"svi",
|
|
250
|
-
"svb",
|
|
251
|
-
"lvw",
|
|
252
|
-
"lvh",
|
|
253
|
-
"lvi",
|
|
254
|
-
"lvb",
|
|
255
|
-
"dvw",
|
|
256
|
-
"dvh",
|
|
257
|
-
"dvi",
|
|
258
|
-
"dvb",
|
|
259
|
-
"vw",
|
|
260
|
-
"vh",
|
|
261
|
-
"vi",
|
|
262
|
-
"vb",
|
|
263
|
-
"rcap",
|
|
264
|
-
"rem",
|
|
265
|
-
"rex",
|
|
266
|
-
"rch",
|
|
267
|
-
"ric",
|
|
268
|
-
"rlh",
|
|
269
|
-
"cap",
|
|
270
|
-
"em",
|
|
271
|
-
"ex",
|
|
272
|
-
"ch",
|
|
273
|
-
"ic",
|
|
274
|
-
"lh",
|
|
275
|
-
"cm",
|
|
276
|
-
"mm",
|
|
277
|
-
"in",
|
|
278
|
-
"pc",
|
|
279
|
-
"pt",
|
|
280
|
-
"px",
|
|
281
|
-
"q",
|
|
282
|
-
"%"
|
|
283
|
-
];
|
|
284
|
-
// packages/ast/src/expr-eval.ts
|
|
285
|
-
var FALSE_VALUES = new Set(["false", "null", "", "0"]);
|
|
286
|
-
function isTruthy(value) {
|
|
287
|
-
return !FALSE_VALUES.has(value.toLowerCase().trim());
|
|
288
|
-
}
|
|
289
|
-
var MAX_EXPRESSION_LENGTH = 256;
|
|
290
|
-
function isTruthyNum(n) {
|
|
291
|
-
return n !== 0 && !Number.isNaN(n);
|
|
292
|
-
}
|
|
293
|
-
function formatExprValue(n) {
|
|
294
|
-
return String(n);
|
|
295
|
-
}
|
|
296
|
-
function evaluateExpression(expr) {
|
|
297
|
-
try {
|
|
298
|
-
if (expr.length > MAX_EXPRESSION_LENGTH) {
|
|
299
|
-
return { success: false, error: "expression too long" };
|
|
300
|
-
}
|
|
301
|
-
if (expr.trim() === "") {
|
|
302
|
-
return { success: false, error: "empty expression" };
|
|
303
|
-
}
|
|
304
|
-
const tokens = tokenize(expr);
|
|
305
|
-
if (tokens.length <= 1) {
|
|
306
|
-
return { success: false, error: "empty expression" };
|
|
307
|
-
}
|
|
308
|
-
const parser = new ExprParser(tokens);
|
|
309
|
-
const result = parser.parse();
|
|
310
|
-
if (!Number.isFinite(result)) {
|
|
311
|
-
return { success: false, error: "division by zero" };
|
|
312
|
-
}
|
|
313
|
-
return { success: true, value: result };
|
|
314
|
-
} catch (e) {
|
|
315
|
-
const msg = e instanceof Error ? e.message : "unknown error";
|
|
316
|
-
return { success: false, error: msg };
|
|
31
|
+
const parser = new ExprParser(tokens);
|
|
32
|
+
const result = parser.parse();
|
|
33
|
+
if (!Number.isFinite(result)) {
|
|
34
|
+
return { success: false, error: "division by zero" };
|
|
35
|
+
}
|
|
36
|
+
return { success: true, value: result };
|
|
37
|
+
} catch (e) {
|
|
38
|
+
const msg = e instanceof Error ? e.message : "unknown error";
|
|
39
|
+
return { success: false, error: msg };
|
|
317
40
|
}
|
|
318
41
|
}
|
|
319
42
|
function tokenize(expr) {
|
|
@@ -669,6 +392,574 @@ class ExprParser {
|
|
|
669
392
|
}
|
|
670
393
|
}
|
|
671
394
|
}
|
|
395
|
+
|
|
396
|
+
// packages/ast/src/readable-text.ts
|
|
397
|
+
var segmenter = new Intl.Segmenter("und", { granularity: "grapheme" });
|
|
398
|
+
function countCharacters(text) {
|
|
399
|
+
let count = 0;
|
|
400
|
+
for (const _segment of segmenter.segment(text))
|
|
401
|
+
count++;
|
|
402
|
+
return count;
|
|
403
|
+
}
|
|
404
|
+
function extractReadableText(ast, options = {}) {
|
|
405
|
+
return extractText(ast, options, false);
|
|
406
|
+
}
|
|
407
|
+
function extractFirstParagraph(ast, options = {}) {
|
|
408
|
+
return extractText(ast, options, true);
|
|
409
|
+
}
|
|
410
|
+
function extractText(ast, options, firstParagraphOnly) {
|
|
411
|
+
const parts = [];
|
|
412
|
+
const notes = new Set;
|
|
413
|
+
let footnoteIndex = 0;
|
|
414
|
+
let firstParagraph;
|
|
415
|
+
const emit = (value, omit) => {
|
|
416
|
+
if (!omit)
|
|
417
|
+
parts.push(value);
|
|
418
|
+
};
|
|
419
|
+
const block = (elements, omit) => {
|
|
420
|
+
emit(`
|
|
421
|
+
|
|
422
|
+
`, omit);
|
|
423
|
+
visit(elements, omit);
|
|
424
|
+
emit(`
|
|
425
|
+
|
|
426
|
+
`, omit);
|
|
427
|
+
};
|
|
428
|
+
const visitBranch = (elements, omit) => {
|
|
429
|
+
const end = elements.findLastIndex((element) => element.element !== "text" || element.data.trim() !== "") + 1;
|
|
430
|
+
visit(elements.slice(0, end), omit);
|
|
431
|
+
};
|
|
432
|
+
const visit = (elements, inheritedOmit = false) => {
|
|
433
|
+
for (const element of elements) {
|
|
434
|
+
if (firstParagraphOnly && firstParagraph !== undefined)
|
|
435
|
+
return;
|
|
436
|
+
const omit = inheritedOmit || options.exclude?.(element) === true;
|
|
437
|
+
switch (element.element) {
|
|
438
|
+
case "text":
|
|
439
|
+
case "raw":
|
|
440
|
+
case "email":
|
|
441
|
+
emit(element.data, omit);
|
|
442
|
+
break;
|
|
443
|
+
case "container": {
|
|
444
|
+
const start = parts.length;
|
|
445
|
+
const type = element.data.type;
|
|
446
|
+
const kind = typeof type === "string" ? type : "block";
|
|
447
|
+
const hidden = omit || ["ruby-text", "hidden", "invisible"].includes(kind);
|
|
448
|
+
if ([
|
|
449
|
+
"paragraph",
|
|
450
|
+
"div",
|
|
451
|
+
"blockquote",
|
|
452
|
+
"note",
|
|
453
|
+
"heading",
|
|
454
|
+
"block",
|
|
455
|
+
"table-row",
|
|
456
|
+
"definition-list"
|
|
457
|
+
].includes(kind))
|
|
458
|
+
block(element.data.elements, hidden);
|
|
459
|
+
else
|
|
460
|
+
visit(element.data.elements, hidden);
|
|
461
|
+
if (firstParagraphOnly && kind === "paragraph" && firstParagraph === undefined) {
|
|
462
|
+
const text = normalizeText(parts.slice(start).join(""));
|
|
463
|
+
if (text)
|
|
464
|
+
firstParagraph = text;
|
|
465
|
+
}
|
|
466
|
+
break;
|
|
467
|
+
}
|
|
468
|
+
case "color":
|
|
469
|
+
case "anchor":
|
|
470
|
+
case "include":
|
|
471
|
+
visit(element.data.elements, omit);
|
|
472
|
+
break;
|
|
473
|
+
case "collapsible":
|
|
474
|
+
block(element.data.elements, omit);
|
|
475
|
+
break;
|
|
476
|
+
case "tab-view":
|
|
477
|
+
for (const tab of element.data) {
|
|
478
|
+
emit(`
|
|
479
|
+
|
|
480
|
+
${tab.label}
|
|
481
|
+
`, omit);
|
|
482
|
+
block(tab.elements, omit);
|
|
483
|
+
}
|
|
484
|
+
break;
|
|
485
|
+
case "table":
|
|
486
|
+
emit(`
|
|
487
|
+
|
|
488
|
+
`, omit);
|
|
489
|
+
for (const row of element.data.rows) {
|
|
490
|
+
for (const cell of row.cells) {
|
|
491
|
+
visit(cell.elements, omit);
|
|
492
|
+
emit(" ", omit);
|
|
493
|
+
}
|
|
494
|
+
emit(`
|
|
495
|
+
`, omit);
|
|
496
|
+
}
|
|
497
|
+
emit(`
|
|
498
|
+
`, omit);
|
|
499
|
+
break;
|
|
500
|
+
case "definition-list":
|
|
501
|
+
for (const entry of element.data) {
|
|
502
|
+
block(entry.key, omit);
|
|
503
|
+
visit(entry.value, omit);
|
|
504
|
+
}
|
|
505
|
+
break;
|
|
506
|
+
case "list":
|
|
507
|
+
for (const item of element.data.items) {
|
|
508
|
+
emit(`
|
|
509
|
+
`, omit);
|
|
510
|
+
if (item["item-type"] === "elements")
|
|
511
|
+
visit(item.elements, omit);
|
|
512
|
+
else
|
|
513
|
+
visit([{ element: "list", data: item.data }], omit);
|
|
514
|
+
}
|
|
515
|
+
emit(`
|
|
516
|
+
`, omit);
|
|
517
|
+
break;
|
|
518
|
+
case "link": {
|
|
519
|
+
const label = element.data.label;
|
|
520
|
+
const destination = typeof element.data.link === "string" ? element.data.link : element.data.link.page;
|
|
521
|
+
const fallback = label === "page" ? destination : ("text" in label) ? label.text : label.url ?? destination;
|
|
522
|
+
emit(options.resolveText?.(element) ?? fallback, omit);
|
|
523
|
+
break;
|
|
524
|
+
}
|
|
525
|
+
case "user":
|
|
526
|
+
emit(options.resolveText?.(element) ?? element.data.name, omit);
|
|
527
|
+
break;
|
|
528
|
+
case "date":
|
|
529
|
+
case "math":
|
|
530
|
+
case "math-inline":
|
|
531
|
+
emit(options.resolveText?.(element) ?? "", omit);
|
|
532
|
+
break;
|
|
533
|
+
case "image":
|
|
534
|
+
emit(element.data.attributes.alt ?? "", omit);
|
|
535
|
+
break;
|
|
536
|
+
case "gallery":
|
|
537
|
+
if (element.data.content.type === "items")
|
|
538
|
+
for (const item of element.data.content.items)
|
|
539
|
+
emit(`${item.alt ?? ""}
|
|
540
|
+
`, omit);
|
|
541
|
+
break;
|
|
542
|
+
case "code":
|
|
543
|
+
emit(`
|
|
544
|
+
|
|
545
|
+
${element.data.contents}
|
|
546
|
+
|
|
547
|
+
`, omit);
|
|
548
|
+
break;
|
|
549
|
+
case "footnote":
|
|
550
|
+
case "footnote-ref": {
|
|
551
|
+
const index = element.element === "footnote" ? footnoteIndex++ : element.data - 1;
|
|
552
|
+
if (!omit)
|
|
553
|
+
notes.add(index);
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
case "bibliography-block":
|
|
557
|
+
for (const entry of element.data.entries)
|
|
558
|
+
block(entry.value, omit);
|
|
559
|
+
break;
|
|
560
|
+
case "if":
|
|
561
|
+
visitBranch(isTruthy(element.data.condition) ? element.data.then : element.data.else, omit);
|
|
562
|
+
break;
|
|
563
|
+
case "ifexpr": {
|
|
564
|
+
const result = evaluateExpression(element.data.expression);
|
|
565
|
+
if (result.success)
|
|
566
|
+
visitBranch(result.value !== 0 ? element.data.then : element.data.else, omit);
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
569
|
+
case "expr": {
|
|
570
|
+
const result = evaluateExpression(element.data.expression);
|
|
571
|
+
if (result.success)
|
|
572
|
+
emit(formatExprValue(result.value), omit);
|
|
573
|
+
break;
|
|
574
|
+
}
|
|
575
|
+
case "line-break":
|
|
576
|
+
case "line-breaks":
|
|
577
|
+
emit(`
|
|
578
|
+
`, omit);
|
|
579
|
+
break;
|
|
580
|
+
case "horizontal-rule":
|
|
581
|
+
case "content-separator":
|
|
582
|
+
emit(`
|
|
583
|
+
|
|
584
|
+
`, omit);
|
|
585
|
+
break;
|
|
586
|
+
default:
|
|
587
|
+
break;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
visit(ast.elements);
|
|
592
|
+
if (firstParagraphOnly)
|
|
593
|
+
return firstParagraph ?? "";
|
|
594
|
+
for (const index of notes) {
|
|
595
|
+
const note = ast.footnotes?.[index];
|
|
596
|
+
if (note)
|
|
597
|
+
block(note, false);
|
|
598
|
+
}
|
|
599
|
+
return normalizeText(parts.join(""));
|
|
600
|
+
}
|
|
601
|
+
function normalizeText(text) {
|
|
602
|
+
return text.replace(/[^\S\n]+/g, " ").replace(/ ?\n ?/g, `
|
|
603
|
+
`).replace(/\n{3,}/g, `
|
|
604
|
+
|
|
605
|
+
`).trim();
|
|
606
|
+
}
|
|
607
|
+
// packages/ast/src/text-excerpt.ts
|
|
608
|
+
import { RE2JS } from "re2js";
|
|
609
|
+
var segmenter2 = new Intl.Segmenter("und", { granularity: "grapheme" });
|
|
610
|
+
var emptyExcerpt = (_text) => "";
|
|
611
|
+
var MAX_PATTERN_LENGTH = 4096;
|
|
612
|
+
var MAX_INPUT_LENGTH = 1e6;
|
|
613
|
+
var MAX_PROGRAM_SIZE = 4096;
|
|
614
|
+
var MAX_MATCHES = 1e4;
|
|
615
|
+
var SEARCH_BUDGET = 16000000;
|
|
616
|
+
function compileTextExcerpt(options = {}) {
|
|
617
|
+
const limit = options.maxLength ?? 200;
|
|
618
|
+
if (!Number.isSafeInteger(limit) || limit <= 0)
|
|
619
|
+
return emptyExcerpt;
|
|
620
|
+
if (options.pattern === undefined) {
|
|
621
|
+
if (options.flags !== undefined || options.group !== undefined || options.match !== undefined) {
|
|
622
|
+
return emptyExcerpt;
|
|
623
|
+
}
|
|
624
|
+
return (text) => truncateText(text, limit);
|
|
625
|
+
}
|
|
626
|
+
const occurrence = options.match ?? 1;
|
|
627
|
+
const group = options.group ?? 0;
|
|
628
|
+
if (options.pattern.length > MAX_PATTERN_LENGTH || !Number.isSafeInteger(occurrence) || occurrence < 1 || occurrence > MAX_MATCHES || typeof group === "number" && (!Number.isSafeInteger(group) || group < 0))
|
|
629
|
+
return emptyExcerpt;
|
|
630
|
+
let flags = 0;
|
|
631
|
+
const seenFlags = new Set;
|
|
632
|
+
for (const flag of options.flags ?? "") {
|
|
633
|
+
if (seenFlags.has(flag))
|
|
634
|
+
return emptyExcerpt;
|
|
635
|
+
seenFlags.add(flag);
|
|
636
|
+
switch (flag) {
|
|
637
|
+
case "i":
|
|
638
|
+
flags |= RE2JS.CASE_INSENSITIVE;
|
|
639
|
+
break;
|
|
640
|
+
case "m":
|
|
641
|
+
flags |= RE2JS.MULTILINE;
|
|
642
|
+
break;
|
|
643
|
+
case "s":
|
|
644
|
+
flags |= RE2JS.DOTALL;
|
|
645
|
+
break;
|
|
646
|
+
default:
|
|
647
|
+
return emptyExcerpt;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
let compiled;
|
|
651
|
+
try {
|
|
652
|
+
compiled = RE2JS.compile(options.pattern, flags);
|
|
653
|
+
} catch {
|
|
654
|
+
return emptyExcerpt;
|
|
655
|
+
}
|
|
656
|
+
const programSize = compiled.programSize();
|
|
657
|
+
const groupCount = compiled.groupCount();
|
|
658
|
+
if (programSize > MAX_PROGRAM_SIZE || (typeof group === "number" ? group > groupCount : !Object.hasOwn(compiled.namedGroups(), group)))
|
|
659
|
+
return emptyExcerpt;
|
|
660
|
+
return (text) => {
|
|
661
|
+
if (text.length > MAX_INPUT_LENGTH)
|
|
662
|
+
return "";
|
|
663
|
+
const matcher = compiled.matcher(text);
|
|
664
|
+
let budget = SEARCH_BUDGET;
|
|
665
|
+
let from = 0;
|
|
666
|
+
for (let index = 1;index <= occurrence; index++) {
|
|
667
|
+
budget -= programSize * (groupCount + 1) * (text.length - from + 1);
|
|
668
|
+
if (budget < 0 || !matcher.find())
|
|
669
|
+
return "";
|
|
670
|
+
from = matcher.end();
|
|
671
|
+
}
|
|
672
|
+
return truncateText(matcher.group(group) ?? "", limit);
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
function excerptText(text, options = {}) {
|
|
676
|
+
return compileTextExcerpt(options)(text);
|
|
677
|
+
}
|
|
678
|
+
function truncateText(text, limit) {
|
|
679
|
+
let count = 0;
|
|
680
|
+
for (const segment of segmenter2.segment(text)) {
|
|
681
|
+
if (count++ === limit)
|
|
682
|
+
return text.slice(0, segment.index);
|
|
683
|
+
}
|
|
684
|
+
return text;
|
|
685
|
+
}
|
|
686
|
+
// packages/ast/src/position.ts
|
|
687
|
+
function createPoint(line, column, offset) {
|
|
688
|
+
return { line, column, offset };
|
|
689
|
+
}
|
|
690
|
+
function createPosition(start, end) {
|
|
691
|
+
return { start, end };
|
|
692
|
+
}
|
|
693
|
+
// packages/ast/src/element.ts
|
|
694
|
+
function isStringContainerType(type) {
|
|
695
|
+
return typeof type === "string";
|
|
696
|
+
}
|
|
697
|
+
function isHeaderType(type) {
|
|
698
|
+
return typeof type === "object" && type !== null && "header" in type;
|
|
699
|
+
}
|
|
700
|
+
function isAlignType(type) {
|
|
701
|
+
return typeof type === "object" && type !== null && "align" in type;
|
|
702
|
+
}
|
|
703
|
+
function text(value) {
|
|
704
|
+
return { element: "text", data: value };
|
|
705
|
+
}
|
|
706
|
+
function container(type, elements, attributes = {}) {
|
|
707
|
+
return {
|
|
708
|
+
element: "container",
|
|
709
|
+
data: { type, attributes, elements }
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
function paragraph(elements, attributes = {}) {
|
|
713
|
+
return container("paragraph", elements, attributes);
|
|
714
|
+
}
|
|
715
|
+
function bold(elements, attributes = {}) {
|
|
716
|
+
return container("bold", elements, attributes);
|
|
717
|
+
}
|
|
718
|
+
function italics(elements, attributes = {}) {
|
|
719
|
+
return container("italics", elements, attributes);
|
|
720
|
+
}
|
|
721
|
+
function heading(level, elements, hasToc = true, attributes = {}) {
|
|
722
|
+
return container({ header: { level, "has-toc": hasToc } }, elements, attributes);
|
|
723
|
+
}
|
|
724
|
+
function lineBreak() {
|
|
725
|
+
return { element: "line-break" };
|
|
726
|
+
}
|
|
727
|
+
function horizontalRule() {
|
|
728
|
+
return { element: "horizontal-rule" };
|
|
729
|
+
}
|
|
730
|
+
function link(linkLocation, label, options = {}) {
|
|
731
|
+
return {
|
|
732
|
+
element: "link",
|
|
733
|
+
data: {
|
|
734
|
+
type: options.type ?? (typeof linkLocation === "string" ? "direct" : "page"),
|
|
735
|
+
link: linkLocation,
|
|
736
|
+
extra: options.extra ?? null,
|
|
737
|
+
label,
|
|
738
|
+
target: options.target ?? null
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
function list(type, items, attributes = {}) {
|
|
743
|
+
return {
|
|
744
|
+
element: "list",
|
|
745
|
+
data: { type, attributes, items }
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
function listItemElements(elements, attributes = {}) {
|
|
749
|
+
return {
|
|
750
|
+
"item-type": "elements",
|
|
751
|
+
attributes,
|
|
752
|
+
elements
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
function listItemSubList(data) {
|
|
756
|
+
return {
|
|
757
|
+
"item-type": "sub-list",
|
|
758
|
+
element: "list",
|
|
759
|
+
data
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
function isContainerTypeParagraphSafe(type) {
|
|
763
|
+
if (isHeaderType(type))
|
|
764
|
+
return false;
|
|
765
|
+
if (isAlignType(type))
|
|
766
|
+
return false;
|
|
767
|
+
switch (type) {
|
|
768
|
+
case "bold":
|
|
769
|
+
case "italics":
|
|
770
|
+
case "underline":
|
|
771
|
+
case "superscript":
|
|
772
|
+
case "subscript":
|
|
773
|
+
case "strikethrough":
|
|
774
|
+
case "monospace":
|
|
775
|
+
case "span":
|
|
776
|
+
case "size":
|
|
777
|
+
return true;
|
|
778
|
+
case "div":
|
|
779
|
+
case "note":
|
|
780
|
+
case "blockquote":
|
|
781
|
+
case "paragraph":
|
|
782
|
+
case "heading":
|
|
783
|
+
case "collapsible":
|
|
784
|
+
case "definition-list":
|
|
785
|
+
case "definition-list-item":
|
|
786
|
+
case "definition-list-key":
|
|
787
|
+
case "definition-list-value":
|
|
788
|
+
case "table-row":
|
|
789
|
+
case "table-cell":
|
|
790
|
+
return false;
|
|
791
|
+
default:
|
|
792
|
+
return false;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
function isParagraphSafe(element) {
|
|
796
|
+
switch (element.element) {
|
|
797
|
+
case "container": {
|
|
798
|
+
const data = element.data;
|
|
799
|
+
return isContainerTypeParagraphSafe(data.type);
|
|
800
|
+
}
|
|
801
|
+
case "module":
|
|
802
|
+
return false;
|
|
803
|
+
case "text":
|
|
804
|
+
case "raw":
|
|
805
|
+
case "variable":
|
|
806
|
+
case "email":
|
|
807
|
+
return true;
|
|
808
|
+
case "table":
|
|
809
|
+
return false;
|
|
810
|
+
case "tab-view":
|
|
811
|
+
return false;
|
|
812
|
+
case "anchor":
|
|
813
|
+
case "anchor-name":
|
|
814
|
+
case "link":
|
|
815
|
+
return true;
|
|
816
|
+
case "image":
|
|
817
|
+
return true;
|
|
818
|
+
case "list":
|
|
819
|
+
return false;
|
|
820
|
+
case "definition-list":
|
|
821
|
+
return false;
|
|
822
|
+
case "collapsible":
|
|
823
|
+
return false;
|
|
824
|
+
case "table-of-contents":
|
|
825
|
+
return false;
|
|
826
|
+
case "footnote":
|
|
827
|
+
return true;
|
|
828
|
+
case "footnote-ref":
|
|
829
|
+
return true;
|
|
830
|
+
case "footnote-block":
|
|
831
|
+
return false;
|
|
832
|
+
case "bibliography-cite":
|
|
833
|
+
return true;
|
|
834
|
+
case "bibliography-block":
|
|
835
|
+
return false;
|
|
836
|
+
case "user":
|
|
837
|
+
return true;
|
|
838
|
+
case "date":
|
|
839
|
+
case "social":
|
|
840
|
+
return true;
|
|
841
|
+
case "button":
|
|
842
|
+
return isPageButtonAction(element.data.action);
|
|
843
|
+
case "color":
|
|
844
|
+
return true;
|
|
845
|
+
case "code":
|
|
846
|
+
return false;
|
|
847
|
+
case "math":
|
|
848
|
+
return false;
|
|
849
|
+
case "math-inline":
|
|
850
|
+
return true;
|
|
851
|
+
case "embed":
|
|
852
|
+
return false;
|
|
853
|
+
case "embed-block":
|
|
854
|
+
return true;
|
|
855
|
+
case "html":
|
|
856
|
+
case "iframe":
|
|
857
|
+
return false;
|
|
858
|
+
case "include": {
|
|
859
|
+
const data = element.data;
|
|
860
|
+
return data["paragraph-safe"];
|
|
861
|
+
}
|
|
862
|
+
case "style":
|
|
863
|
+
return false;
|
|
864
|
+
case "line-break":
|
|
865
|
+
case "line-breaks":
|
|
866
|
+
return true;
|
|
867
|
+
case "clear-float":
|
|
868
|
+
return false;
|
|
869
|
+
case "horizontal-rule":
|
|
870
|
+
return false;
|
|
871
|
+
case "content-separator":
|
|
872
|
+
return false;
|
|
873
|
+
case "if-tags":
|
|
874
|
+
return false;
|
|
875
|
+
case "expr":
|
|
876
|
+
case "if":
|
|
877
|
+
case "ifexpr":
|
|
878
|
+
return true;
|
|
879
|
+
default:
|
|
880
|
+
return false;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
function isPageButtonAction(action) {
|
|
884
|
+
switch (action) {
|
|
885
|
+
case "edit":
|
|
886
|
+
case "edit-append":
|
|
887
|
+
case "edit-sections":
|
|
888
|
+
case "history":
|
|
889
|
+
case "print":
|
|
890
|
+
case "files":
|
|
891
|
+
case "tags":
|
|
892
|
+
case "source":
|
|
893
|
+
case "backlinks":
|
|
894
|
+
case "talk":
|
|
895
|
+
case "delete":
|
|
896
|
+
case "rename":
|
|
897
|
+
case "site-tools":
|
|
898
|
+
case "edit-meta":
|
|
899
|
+
case "watchers":
|
|
900
|
+
case "parent":
|
|
901
|
+
case "lock-page":
|
|
902
|
+
return true;
|
|
903
|
+
default:
|
|
904
|
+
return false;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
// packages/ast/src/constants.ts
|
|
908
|
+
var STYLE_SLOT_PREFIX = "\x00__IFTAGS_SLOT__";
|
|
909
|
+
var STYLE_ANCHOR_PREFIX = "\x00__STYLE_ANCHOR__";
|
|
910
|
+
// packages/ast/src/css.ts
|
|
911
|
+
var CSS_LENGTH_UNITS = [
|
|
912
|
+
"cqmax",
|
|
913
|
+
"cqmin",
|
|
914
|
+
"cqw",
|
|
915
|
+
"cqh",
|
|
916
|
+
"cqi",
|
|
917
|
+
"cqb",
|
|
918
|
+
"svmin",
|
|
919
|
+
"svmax",
|
|
920
|
+
"lvmin",
|
|
921
|
+
"lvmax",
|
|
922
|
+
"dvmin",
|
|
923
|
+
"dvmax",
|
|
924
|
+
"vmin",
|
|
925
|
+
"vmax",
|
|
926
|
+
"svw",
|
|
927
|
+
"svh",
|
|
928
|
+
"svi",
|
|
929
|
+
"svb",
|
|
930
|
+
"lvw",
|
|
931
|
+
"lvh",
|
|
932
|
+
"lvi",
|
|
933
|
+
"lvb",
|
|
934
|
+
"dvw",
|
|
935
|
+
"dvh",
|
|
936
|
+
"dvi",
|
|
937
|
+
"dvb",
|
|
938
|
+
"vw",
|
|
939
|
+
"vh",
|
|
940
|
+
"vi",
|
|
941
|
+
"vb",
|
|
942
|
+
"rcap",
|
|
943
|
+
"rem",
|
|
944
|
+
"rex",
|
|
945
|
+
"rch",
|
|
946
|
+
"ric",
|
|
947
|
+
"rlh",
|
|
948
|
+
"cap",
|
|
949
|
+
"em",
|
|
950
|
+
"ex",
|
|
951
|
+
"ch",
|
|
952
|
+
"ic",
|
|
953
|
+
"lh",
|
|
954
|
+
"cm",
|
|
955
|
+
"mm",
|
|
956
|
+
"in",
|
|
957
|
+
"pc",
|
|
958
|
+
"pt",
|
|
959
|
+
"px",
|
|
960
|
+
"q",
|
|
961
|
+
"%"
|
|
962
|
+
];
|
|
672
963
|
// packages/ast/src/settings.ts
|
|
673
964
|
function createSettings(mode) {
|
|
674
965
|
switch (mode) {
|
|
@@ -722,11 +1013,16 @@ export {
|
|
|
722
1013
|
horizontalRule,
|
|
723
1014
|
heading,
|
|
724
1015
|
formatExprValue,
|
|
1016
|
+
extractReadableText,
|
|
1017
|
+
extractFirstParagraph,
|
|
1018
|
+
excerptText,
|
|
725
1019
|
evaluateExpression,
|
|
726
1020
|
createSettings,
|
|
727
1021
|
createPosition,
|
|
728
1022
|
createPoint,
|
|
1023
|
+
countCharacters,
|
|
729
1024
|
container,
|
|
1025
|
+
compileTextExcerpt,
|
|
730
1026
|
buildInfo,
|
|
731
1027
|
bold,
|
|
732
1028
|
STYLE_SLOT_PREFIX,
|