webforai 4.0.0 → 4.1.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.
Files changed (113) hide show
  1. package/README.md +22 -0
  2. package/dist/bin.js +1895 -74
  3. package/dist/cjs/extract-mdast.js +58 -0
  4. package/dist/cjs/extractors/index.js +5 -0
  5. package/dist/cjs/extractors/lib/block-features.js +465 -0
  6. package/dist/cjs/extractors/lib/block-model.generated.js +45 -0
  7. package/dist/cjs/extractors/lib/block-model.js +72 -0
  8. package/dist/cjs/extractors/lib/blocks.js +212 -0
  9. package/dist/cjs/extractors/lib/code-tabs.js +191 -0
  10. package/dist/cjs/extractors/lib/constants.js +1 -1
  11. package/dist/cjs/extractors/lib/layout-tables.js +123 -0
  12. package/dist/cjs/extractors/lib/sanitize.js +144 -28
  13. package/dist/cjs/extractors/lib/takumi-signal.js +76 -0
  14. package/dist/cjs/extractors/lib/ui-chrome.js +7 -0
  15. package/dist/cjs/extractors/presets/auto.js +3 -3
  16. package/dist/cjs/extractors/presets/kiwame.js +231 -0
  17. package/dist/cjs/extractors/presets/takumi.js +34 -3
  18. package/dist/cjs/html-to-markdown.js +58 -4
  19. package/dist/cjs/html-to-mdast.js +2 -2
  20. package/dist/cjs/index.js +4 -0
  21. package/dist/cjs/mdast-handlers/custom-code-handler.js +16 -4
  22. package/dist/cjs/mdast-handlers/custom-div-handler.js +3 -3
  23. package/dist/cjs/mdast-handlers/custom-img-handler.js +10 -1
  24. package/dist/cjs/mdast-handlers/custom-table-handler.js +18 -1
  25. package/dist/cjs/mdast-handlers/table-cell-flatten.js +195 -0
  26. package/dist/cjs/mdast-handlers/twoslash.js +71 -0
  27. package/dist/cjs/metadata/index.js +4 -3
  28. package/dist/cjs/utils/hast-fast.js +1 -1
  29. package/dist/cjs/utils/parse-html.js +113 -0
  30. package/dist/cjs/utils/pre-text.js +104 -0
  31. package/dist/extract-mdast.js +58 -0
  32. package/dist/extractors/index.js +3 -0
  33. package/dist/extractors/lib/block-features.js +437 -0
  34. package/dist/extractors/lib/block-model.generated.js +21 -0
  35. package/dist/extractors/lib/block-model.js +48 -0
  36. package/dist/extractors/lib/blocks.js +185 -0
  37. package/dist/extractors/lib/code-tabs.js +168 -0
  38. package/dist/extractors/lib/constants.js +1 -1
  39. package/dist/extractors/lib/layout-tables.js +99 -0
  40. package/dist/extractors/lib/sanitize.js +142 -28
  41. package/dist/extractors/lib/takumi-signal.js +53 -0
  42. package/dist/extractors/lib/ui-chrome.js +5 -0
  43. package/dist/extractors/presets/auto.js +3 -3
  44. package/dist/extractors/presets/kiwame.js +206 -0
  45. package/dist/extractors/presets/takumi.js +34 -3
  46. package/dist/html-to-markdown.js +57 -4
  47. package/dist/html-to-mdast.js +2 -2
  48. package/dist/index.js +4 -0
  49. package/dist/mdast-handlers/custom-code-handler.js +15 -4
  50. package/dist/mdast-handlers/custom-div-handler.js +4 -4
  51. package/dist/mdast-handlers/custom-img-handler.js +10 -1
  52. package/dist/mdast-handlers/custom-table-handler.js +19 -2
  53. package/dist/mdast-handlers/table-cell-flatten.js +170 -0
  54. package/dist/mdast-handlers/twoslash.js +48 -0
  55. package/dist/metadata/index.js +4 -3
  56. package/dist/types/cli/commands/jobs/options.d.ts +2 -2
  57. package/dist/types/cli/commands/jobs/options.js.map +1 -1
  58. package/dist/types/cli/commands/webforai/options.js.map +1 -1
  59. package/dist/types/cli/commands/webforai/run.js.map +1 -1
  60. package/dist/types/cli/constants.d.ts +3 -1
  61. package/dist/types/cli/constants.js.map +1 -1
  62. package/dist/types/extract-mdast.js.map +1 -1
  63. package/dist/types/extractors/index.d.ts +1 -0
  64. package/dist/types/extractors/index.js.map +1 -1
  65. package/dist/types/extractors/lib/block-features.d.ts +43 -0
  66. package/dist/types/extractors/lib/block-features.js.map +1 -0
  67. package/dist/types/extractors/lib/block-model.d.ts +28 -0
  68. package/dist/types/extractors/lib/block-model.generated.d.ts +5 -0
  69. package/dist/types/extractors/lib/block-model.generated.js.map +1 -0
  70. package/dist/types/extractors/lib/block-model.js.map +1 -0
  71. package/dist/types/extractors/lib/blocks.d.ts +53 -0
  72. package/dist/types/extractors/lib/blocks.js.map +1 -0
  73. package/dist/types/extractors/lib/code-tabs.d.ts +30 -0
  74. package/dist/types/extractors/lib/code-tabs.js.map +1 -0
  75. package/dist/types/extractors/lib/constants.js.map +1 -1
  76. package/dist/types/extractors/lib/layout-tables.d.ts +17 -0
  77. package/dist/types/extractors/lib/layout-tables.js.map +1 -0
  78. package/dist/types/extractors/lib/sanitize.d.ts +33 -3
  79. package/dist/types/extractors/lib/sanitize.js.map +1 -1
  80. package/dist/types/extractors/lib/takumi-signal.d.ts +12 -0
  81. package/dist/types/extractors/lib/takumi-signal.js.map +1 -0
  82. package/dist/types/extractors/lib/ui-chrome.d.ts +8 -0
  83. package/dist/types/extractors/lib/ui-chrome.js.map +1 -1
  84. package/dist/types/extractors/presets/auto.d.ts +6 -1
  85. package/dist/types/extractors/presets/auto.js.map +1 -1
  86. package/dist/types/extractors/presets/kiwame.d.ts +31 -0
  87. package/dist/types/extractors/presets/kiwame.js.map +1 -0
  88. package/dist/types/extractors/presets/takumi.js.map +1 -1
  89. package/dist/types/html-to-markdown.d.ts +9 -0
  90. package/dist/types/html-to-markdown.js.map +1 -1
  91. package/dist/types/html-to-mdast.js.map +1 -1
  92. package/dist/types/index.d.ts +1 -1
  93. package/dist/types/index.js.map +1 -1
  94. package/dist/types/mdast-handlers/custom-code-handler.d.ts +7 -0
  95. package/dist/types/mdast-handlers/custom-code-handler.js.map +1 -1
  96. package/dist/types/mdast-handlers/custom-div-handler.js.map +1 -1
  97. package/dist/types/mdast-handlers/custom-img-handler.js.map +1 -1
  98. package/dist/types/mdast-handlers/custom-table-handler.js.map +1 -1
  99. package/dist/types/mdast-handlers/table-cell-flatten.d.ts +18 -0
  100. package/dist/types/mdast-handlers/table-cell-flatten.js.map +1 -0
  101. package/dist/types/mdast-handlers/twoslash.d.ts +14 -0
  102. package/dist/types/mdast-handlers/twoslash.js.map +1 -0
  103. package/dist/types/metadata/index.js.map +1 -1
  104. package/dist/types/utils/hast-fast.d.ts +1 -1
  105. package/dist/types/utils/hast-fast.js.map +1 -1
  106. package/dist/types/utils/parse-html.d.ts +33 -0
  107. package/dist/types/utils/parse-html.js.map +1 -0
  108. package/dist/types/utils/pre-text.d.ts +12 -0
  109. package/dist/types/utils/pre-text.js.map +1 -0
  110. package/dist/utils/hast-fast.js +1 -1
  111. package/dist/utils/parse-html.js +87 -0
  112. package/dist/utils/pre-text.js +81 -0
  113. package/package.json +3 -1
@@ -0,0 +1,437 @@
1
+ // src/extractors/lib/block-features.ts
2
+ import { classList, matchString, stringProperty } from "../../utils/hast-fast.js";
3
+ import { ancestorAt } from "./blocks.js";
4
+ import { CONTENT_ROLES, REGEXPS, UNLIKELY_ROLES } from "./constants.js";
5
+ import { findLandmarkChrome, unlikelyTier } from "./sanitize.js";
6
+ import { buildScoringContext, scoreCandidates } from "./score.js";
7
+ var FEATURE_NAMES = [
8
+ "bias",
9
+ "logLen",
10
+ "linkDensity",
11
+ "logLinks",
12
+ "hasImage",
13
+ "textless",
14
+ "punctDensity",
15
+ "digitRatio",
16
+ "sentenceEnds",
17
+ "tag_p",
18
+ "tag_li",
19
+ "tag_cell",
20
+ "tag_h1",
21
+ "tag_h2_6",
22
+ "tag_pre",
23
+ "tag_div",
24
+ "tag_dtdd",
25
+ "tag_blockquote",
26
+ "tag_figcaption",
27
+ "in_nav",
28
+ "in_header",
29
+ "in_footer",
30
+ "in_aside",
31
+ "in_article",
32
+ "in_main",
33
+ "in_form",
34
+ "in_table",
35
+ "in_list",
36
+ "role_chrome",
37
+ "role_content",
38
+ "cls_unlikely",
39
+ "cls_positive",
40
+ "cls_negative",
41
+ "cls_strong",
42
+ "cls_special",
43
+ "cls_byline",
44
+ "cls_comment",
45
+ "landmark",
46
+ "doom_strong",
47
+ "doom_weak",
48
+ "depth",
49
+ "relPos",
50
+ "relCharPos",
51
+ "prev_logLen",
52
+ "prev_linkDensity",
53
+ "next_logLen",
54
+ "next_linkDensity",
55
+ "win_linkDensity",
56
+ "win_logLen",
57
+ "parent_linkDensity",
58
+ "parent_logText",
59
+ "gparent_linkDensity",
60
+ "gparent_logText",
61
+ "inTopCandidate",
62
+ "candidateScore",
63
+ "inTopSibling",
64
+ "takumi_kept"
65
+ ];
66
+ var FEATURE_COUNT = FEATURE_NAMES.length;
67
+ var PUNCT = /* @__PURE__ */ new Set([...".,;:!?\u3001\u3002\uFF0C\uFF0E\uFF01\uFF1F\uFF1B\uFF1A"]);
68
+ var SENTENCE_END = /* @__PURE__ */ new Set([...".!?\u3002\uFF01\uFF1F"]);
69
+ var textStats = (text) => {
70
+ let punct = 0;
71
+ let digits = 0;
72
+ let sentences = 0;
73
+ for (let index = 0; index < text.length; index++) {
74
+ const char = text[index];
75
+ const code = text.charCodeAt(index);
76
+ if (code >= 48 && code <= 57) {
77
+ digits += 1;
78
+ } else if (PUNCT.has(char)) {
79
+ punct += 1;
80
+ const next = text.charCodeAt(index + 1);
81
+ if (SENTENCE_END.has(char) && (Number.isNaN(next) || next === 32 || next === 10 || code > 12288)) {
82
+ sentences += 1;
83
+ }
84
+ }
85
+ }
86
+ return { punct, digits, sentences };
87
+ };
88
+ var COMMENT = /comment|disqus|reply|respond/i;
89
+ var log1p = (value) => Math.log(1 + value);
90
+ var signalsOf = (element, cache) => {
91
+ let signals = cache.get(element);
92
+ if (signals) {
93
+ return signals;
94
+ }
95
+ const match = matchString(element);
96
+ const role = stringProperty(element, "role") ?? "";
97
+ const names = [...classList(element), stringProperty(element, "id") ?? ""];
98
+ signals = {
99
+ unlikely: REGEXPS.unlikelyCandidates.test(match) && !REGEXPS.okMaybeItsaCandidate.test(match),
100
+ positive: REGEXPS.positive.test(match),
101
+ negative: REGEXPS.negative.test(match),
102
+ strong: names.some((name) => REGEXPS.stronglyUnlikely.test(name)),
103
+ special: REGEXPS.specialUnlikelyCandidates.test(match),
104
+ byline: REGEXPS.byline.test(match),
105
+ comment: COMMENT.test(match),
106
+ roleChrome: UNLIKELY_ROLES.has(role),
107
+ roleContent: CONTENT_ROLES.has(role)
108
+ };
109
+ cache.set(element, signals);
110
+ return signals;
111
+ };
112
+ var SIGNAL_LEVELS = 6;
113
+ var SIGNAL_COUNT = 9;
114
+ var RowWriter = class {
115
+ constructor(out) {
116
+ this.out = out;
117
+ this.offset = 0;
118
+ }
119
+ push(value) {
120
+ this.out[this.offset++] = value;
121
+ }
122
+ flag(condition) {
123
+ this.out[this.offset++] = condition ? 1 : 0;
124
+ }
125
+ };
126
+ var EMPTY_CHAIN = {
127
+ inNav: 0,
128
+ inHeader: 0,
129
+ inFooter: 0,
130
+ inAside: 0,
131
+ inArticle: 0,
132
+ inMain: 0,
133
+ inForm: 0,
134
+ inTable: 0,
135
+ inList: 0,
136
+ landmark: 0,
137
+ doomStrong: 0,
138
+ doomWeak: 0,
139
+ inTop: 0,
140
+ inTopSibling: 0,
141
+ nearestScore: 0,
142
+ distance: new Array(SIGNAL_COUNT).fill(Number.POSITIVE_INFINITY)
143
+ };
144
+ var signalFlags = (signals) => [
145
+ signals.roleChrome,
146
+ signals.roleContent,
147
+ signals.unlikely,
148
+ signals.positive,
149
+ signals.negative,
150
+ signals.strong,
151
+ signals.special,
152
+ signals.byline,
153
+ signals.comment
154
+ ];
155
+ var any = (parent, condition) => parent || condition ? 1 : 0;
156
+ var ChainResolver = class {
157
+ constructor(landmarks, candidateScore, parents, top) {
158
+ this.landmarks = landmarks;
159
+ this.candidateScore = candidateScore;
160
+ this.parents = parents;
161
+ this.top = top;
162
+ }
163
+ #chains = /* @__PURE__ */ new Map();
164
+ #signals = /* @__PURE__ */ new WeakMap();
165
+ /** Iterative, so a deeply nested page cannot exhaust the call stack. */
166
+ resolve(frame) {
167
+ const pending = [];
168
+ let current = frame;
169
+ let chain = EMPTY_CHAIN;
170
+ while (current) {
171
+ const memo = this.#chains.get(current.element);
172
+ if (memo) {
173
+ chain = memo;
174
+ break;
175
+ }
176
+ pending.push(current);
177
+ current = current.parent;
178
+ }
179
+ for (let index = pending.length - 1; index >= 0; index--) {
180
+ chain = this.#derive(chain, pending[index].element);
181
+ this.#chains.set(pending[index].element, chain);
182
+ }
183
+ return chain;
184
+ }
185
+ #derive(parent, element) {
186
+ const tag = element.tagName;
187
+ const tier = unlikelyTier(element);
188
+ const flags = signalFlags(signalsOf(element, this.#signals));
189
+ const top = this.top;
190
+ const topParent = top ? this.parents.get(top) : void 0;
191
+ return {
192
+ inNav: any(parent.inNav, tag === "nav"),
193
+ inHeader: any(parent.inHeader, tag === "header"),
194
+ inFooter: any(parent.inFooter, tag === "footer"),
195
+ inAside: any(parent.inAside, tag === "aside"),
196
+ inArticle: any(parent.inArticle, tag === "article"),
197
+ inMain: any(parent.inMain, tag === "main"),
198
+ inForm: any(parent.inForm, tag === "form"),
199
+ inTable: any(parent.inTable, tag === "table"),
200
+ inList: any(parent.inList, tag === "ul" || tag === "ol"),
201
+ landmark: any(parent.landmark, this.landmarks.has(element)),
202
+ doomStrong: any(parent.doomStrong, tier === "strong"),
203
+ doomWeak: any(parent.doomWeak, tier === "weak"),
204
+ inTop: any(parent.inTop, element === top),
205
+ inTopSibling: any(
206
+ parent.inTopSibling,
207
+ topParent !== void 0 && element !== top && this.parents.get(element) === topParent
208
+ ),
209
+ nearestScore: this.candidateScore.get(element) ?? parent.nearestScore,
210
+ distance: parent.distance.map((distance, signal) => flags[signal] ? 0 : distance + 1)
211
+ };
212
+ }
213
+ };
214
+ var evidence = (distance) => distance < SIGNAL_LEVELS ? 1 / (1 + distance) : 0;
215
+ var writeText = (row, block, density) => {
216
+ const length = block.text.length;
217
+ const stats = textStats(block.text);
218
+ row.push(1);
219
+ row.push(log1p(length));
220
+ row.push(density);
221
+ row.push(log1p(block.links));
222
+ row.flag(block.images > 0);
223
+ row.flag(length === 0);
224
+ row.push(length === 0 ? 0 : stats.punct / length);
225
+ row.push(length === 0 ? 0 : stats.digits / length);
226
+ row.push(log1p(stats.sentences));
227
+ };
228
+ var writeTag = (row, tag) => {
229
+ row.flag(tag === "p");
230
+ row.flag(tag === "li");
231
+ row.flag(tag === "td" || tag === "th");
232
+ row.flag(tag === "h1");
233
+ row.flag(/^h[2-6]$/.test(tag));
234
+ row.flag(tag === "pre");
235
+ row.flag(tag === "div" || tag === "section");
236
+ row.flag(tag === "dt" || tag === "dd");
237
+ row.flag(tag === "blockquote");
238
+ row.flag(tag === "figcaption");
239
+ };
240
+ var writeChain = (row, chain) => {
241
+ for (const value of [
242
+ chain.inNav,
243
+ chain.inHeader,
244
+ chain.inFooter,
245
+ chain.inAside,
246
+ chain.inArticle,
247
+ chain.inMain,
248
+ chain.inForm,
249
+ chain.inTable,
250
+ chain.inList
251
+ ]) {
252
+ row.push(value);
253
+ }
254
+ for (const distance of chain.distance) {
255
+ row.push(evidence(distance));
256
+ }
257
+ row.push(chain.landmark);
258
+ row.push(chain.doomStrong);
259
+ row.push(chain.doomWeak);
260
+ };
261
+ var windowMeans = (textLen, density, index, radius) => {
262
+ let link = 0;
263
+ let len = 0;
264
+ let size = 0;
265
+ for (let near = Math.max(0, index - radius); near <= Math.min(textLen.length - 1, index + radius); near++) {
266
+ link += density[near];
267
+ len += log1p(textLen[near]);
268
+ size += 1;
269
+ }
270
+ return [link / size, len / size];
271
+ };
272
+ var writeNeighbourhood = (row, index, textLen, density) => {
273
+ const hasPrevious = index > 0;
274
+ const hasNext = index < textLen.length - 1;
275
+ row.push(hasPrevious ? log1p(textLen[index - 1]) : 0);
276
+ row.push(hasPrevious ? density[index - 1] : 0);
277
+ row.push(hasNext ? log1p(textLen[index + 1]) : 0);
278
+ row.push(hasNext ? density[index + 1] : 0);
279
+ const [windowLink, windowLen] = windowMeans(textLen, density, index, 2);
280
+ row.push(windowLink);
281
+ row.push(windowLen);
282
+ };
283
+ var writeContainers = (row, block, collector) => {
284
+ for (const container of [ancestorAt(block, 1), ancestorAt(block, 2)]) {
285
+ row.push(container ? collector.linkDensity(container) : 0);
286
+ row.push(container ? log1p(collector.textLength(container)) : 0);
287
+ }
288
+ };
289
+ var blockFeatures = ({ root, blocks, collector, lang, takumiKept }) => {
290
+ const count = blocks.length;
291
+ const out = new Float32Array(count * FEATURE_COUNT);
292
+ const context = buildScoringContext(root, collector, lang);
293
+ const candidates = scoreCandidates(root, context);
294
+ const topScore = candidates[0]?.score ?? 1;
295
+ const candidateScore = /* @__PURE__ */ new WeakMap();
296
+ for (const candidate of candidates) {
297
+ candidateScore.set(candidate.element, candidate.score / topScore);
298
+ }
299
+ const chains = new ChainResolver(findLandmarkChrome(root), candidateScore, context.parents, candidates[0]?.element);
300
+ const textLen = blocks.map((block) => block.text.length);
301
+ const density = blocks.map((block) => block.text.length === 0 ? 0 : block.linkChars / block.text.length);
302
+ const totalChars = textLen.reduce((sum, length) => sum + length, 0) || 1;
303
+ let charsBefore = 0;
304
+ for (let index = 0; index < count; index++) {
305
+ const block = blocks[index];
306
+ const row = new RowWriter(out.subarray(index * FEATURE_COUNT, (index + 1) * FEATURE_COUNT));
307
+ const chain = chains.resolve(block.frame);
308
+ writeText(row, block, density[index]);
309
+ writeTag(row, block.owner.tagName);
310
+ writeChain(row, chain);
311
+ row.push(Math.min(block.frame.depth, 40) / 40);
312
+ row.push(count <= 1 ? 0 : index / (count - 1));
313
+ row.push(charsBefore / totalChars);
314
+ charsBefore += textLen[index];
315
+ writeNeighbourhood(row, index, textLen, density);
316
+ writeContainers(row, block, collector);
317
+ row.push(chain.inTop);
318
+ row.push(chain.nearestScore);
319
+ row.push(chain.inTopSibling);
320
+ row.flag(takumiKept?.has(block.owner));
321
+ }
322
+ return out;
323
+ };
324
+ var STACK_FEATURE_NAMES = [
325
+ "s1_logit",
326
+ "s1_win1",
327
+ "s1_win3",
328
+ "s1_parent",
329
+ "s1_gparent",
330
+ "s1_ggparent",
331
+ "s1_parentShare",
332
+ "s1_distHigh",
333
+ "s1_docShare"
334
+ ];
335
+ var STACKED_FEATURE_COUNT = FEATURE_COUNT + STACK_FEATURE_NAMES.length;
336
+ var logit = (p) => Math.log(Math.max(1e-6, p) / Math.max(1e-6, 1 - p));
337
+ var ancestorMass = (blocks, probabilities) => {
338
+ const mass = /* @__PURE__ */ new Map();
339
+ const add = (element, p, weight) => {
340
+ if (!element) {
341
+ return;
342
+ }
343
+ const entry = mass.get(element);
344
+ if (entry) {
345
+ entry.p += p * weight;
346
+ entry.w += weight;
347
+ } else {
348
+ mass.set(element, { p: p * weight, w: weight });
349
+ }
350
+ };
351
+ let docP = 0;
352
+ let docW = 0;
353
+ for (const block of blocks) {
354
+ const weight = block.text.length + 10;
355
+ const p = probabilities[block.index];
356
+ add(ancestorAt(block, 1), p, weight);
357
+ add(ancestorAt(block, 2), p, weight);
358
+ add(ancestorAt(block, 3), p, weight);
359
+ docP += p * weight;
360
+ docW += weight;
361
+ }
362
+ const parentWeightShare = (element) => {
363
+ const entry = element ? mass.get(element) : void 0;
364
+ return entry && docW > 0 ? entry.w / docW : 0;
365
+ };
366
+ return { mass, docShare: docW === 0 ? 0 : docP / docW, parentWeightShare };
367
+ };
368
+ var distanceToHigh = (probabilities) => {
369
+ const count = probabilities.length;
370
+ const distance = new Float32Array(count).fill(count);
371
+ let last = -1;
372
+ for (let index = 0; index < count; index++) {
373
+ if (probabilities[index] >= 0.5) {
374
+ last = index;
375
+ }
376
+ if (last >= 0) {
377
+ distance[index] = index - last;
378
+ }
379
+ }
380
+ last = -1;
381
+ for (let index = count - 1; index >= 0; index--) {
382
+ if (probabilities[index] >= 0.5) {
383
+ last = index;
384
+ }
385
+ if (last >= 0) {
386
+ distance[index] = Math.min(distance[index], last - index);
387
+ }
388
+ }
389
+ return distance;
390
+ };
391
+ var stackedFeatures = (blocks, base, probabilities) => {
392
+ const count = blocks.length;
393
+ const stride = STACKED_FEATURE_COUNT;
394
+ const out = new Float32Array(count * stride);
395
+ const { mass, docShare, parentWeightShare } = ancestorMass(blocks, probabilities);
396
+ const meanOf = (element, fallback) => {
397
+ const entry = element ? mass.get(element) : void 0;
398
+ return entry ? entry.p / entry.w : fallback;
399
+ };
400
+ const distance = distanceToHigh(probabilities);
401
+ for (let index = 0; index < count; index++) {
402
+ const row = index * stride;
403
+ out.set(base.subarray(index * FEATURE_COUNT, (index + 1) * FEATURE_COUNT), row);
404
+ const p = probabilities[index];
405
+ const window = (radius) => {
406
+ let sum = 0;
407
+ let n = 0;
408
+ for (let near = Math.max(0, index - radius); near <= Math.min(count - 1, index + radius); near++) {
409
+ if (near !== index) {
410
+ sum += probabilities[near];
411
+ n += 1;
412
+ }
413
+ }
414
+ return n === 0 ? p : sum / n;
415
+ };
416
+ const block = blocks[index];
417
+ let f = row + FEATURE_COUNT;
418
+ out[f++] = logit(p);
419
+ out[f++] = window(1);
420
+ out[f++] = window(3);
421
+ out[f++] = meanOf(ancestorAt(block, 1), p);
422
+ out[f++] = meanOf(ancestorAt(block, 2), p);
423
+ out[f++] = meanOf(ancestorAt(block, 3), p);
424
+ out[f++] = parentWeightShare(ancestorAt(block, 1));
425
+ out[f++] = Math.log1p(distance[index]);
426
+ out[f++] = docShare;
427
+ }
428
+ return out;
429
+ };
430
+ export {
431
+ FEATURE_COUNT,
432
+ FEATURE_NAMES,
433
+ STACKED_FEATURE_COUNT,
434
+ STACK_FEATURE_NAMES,
435
+ blockFeatures,
436
+ stackedFeatures
437
+ };