agent-sanitizer 2.61.0 → 2.61.2

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.
@@ -0,0 +1,365 @@
1
+ /**
2
+ * GENERATED by scripts/gen-unicode-properties.mjs from the pinned UCD 17.0.0 — DO NOT EDIT.
3
+ *
4
+ * The Unicode properties src/invisible.mjs's carve-out reads, PINNED so the
5
+ * carve-out answers the same on every Node whatever its ICU's Unicode version.
6
+ * Regenerate with `node scripts/gen-unicode-properties.mjs`;
7
+ * test/unicode-properties.test.mjs fails if this drifts from the pinned package.
8
+ */
9
+
10
+ export const UNICODE_VERSION = "17.0.0";
11
+
12
+ // GENERATED UCD data, not hand-written logic: each table is the sorted, merged
13
+ // [start, end] spans of one property. Pinned by the SSOT round-trip in
14
+ // test/unicode-properties.test.mjs, so Stryker skips the numeric literals.
15
+ // Stryker disable all
16
+ /** @type {ReadonlyArray<readonly [number, number]>} */
17
+ export const EXTENDED_PICTOGRAPHIC = [
18
+ [0xa9, 0xa9],
19
+ [0xae, 0xae],
20
+ [0x203c, 0x203c],
21
+ [0x2049, 0x2049],
22
+ [0x2122, 0x2122],
23
+ [0x2139, 0x2139],
24
+ [0x2194, 0x2199],
25
+ [0x21a9, 0x21aa],
26
+ [0x231a, 0x231b],
27
+ [0x2328, 0x2328],
28
+ [0x23cf, 0x23cf],
29
+ [0x23e9, 0x23f3],
30
+ [0x23f8, 0x23fa],
31
+ [0x24c2, 0x24c2],
32
+ [0x25aa, 0x25ab],
33
+ [0x25b6, 0x25b6],
34
+ [0x25c0, 0x25c0],
35
+ [0x25fb, 0x25fe],
36
+ [0x2600, 0x2604],
37
+ [0x260e, 0x260e],
38
+ [0x2611, 0x2611],
39
+ [0x2614, 0x2615],
40
+ [0x2618, 0x2618],
41
+ [0x261d, 0x261d],
42
+ [0x2620, 0x2620],
43
+ [0x2622, 0x2623],
44
+ [0x2626, 0x2626],
45
+ [0x262a, 0x262a],
46
+ [0x262e, 0x262f],
47
+ [0x2638, 0x263a],
48
+ [0x2640, 0x2640],
49
+ [0x2642, 0x2642],
50
+ [0x2648, 0x2653],
51
+ [0x265f, 0x2660],
52
+ [0x2663, 0x2663],
53
+ [0x2665, 0x2666],
54
+ [0x2668, 0x2668],
55
+ [0x267b, 0x267b],
56
+ [0x267e, 0x267f],
57
+ [0x2692, 0x2697],
58
+ [0x2699, 0x2699],
59
+ [0x269b, 0x269c],
60
+ [0x26a0, 0x26a1],
61
+ [0x26a7, 0x26a7],
62
+ [0x26aa, 0x26ab],
63
+ [0x26b0, 0x26b1],
64
+ [0x26bd, 0x26be],
65
+ [0x26c4, 0x26c5],
66
+ [0x26c8, 0x26c8],
67
+ [0x26ce, 0x26cf],
68
+ [0x26d1, 0x26d1],
69
+ [0x26d3, 0x26d4],
70
+ [0x26e9, 0x26ea],
71
+ [0x26f0, 0x26f5],
72
+ [0x26f7, 0x26fa],
73
+ [0x26fd, 0x26fd],
74
+ [0x2702, 0x2702],
75
+ [0x2705, 0x2705],
76
+ [0x2708, 0x270d],
77
+ [0x270f, 0x270f],
78
+ [0x2712, 0x2712],
79
+ [0x2714, 0x2714],
80
+ [0x2716, 0x2716],
81
+ [0x271d, 0x271d],
82
+ [0x2721, 0x2721],
83
+ [0x2728, 0x2728],
84
+ [0x2733, 0x2734],
85
+ [0x2744, 0x2744],
86
+ [0x2747, 0x2747],
87
+ [0x274c, 0x274c],
88
+ [0x274e, 0x274e],
89
+ [0x2753, 0x2755],
90
+ [0x2757, 0x2757],
91
+ [0x2763, 0x2764],
92
+ [0x2795, 0x2797],
93
+ [0x27a1, 0x27a1],
94
+ [0x27b0, 0x27b0],
95
+ [0x27bf, 0x27bf],
96
+ [0x2934, 0x2935],
97
+ [0x2b05, 0x2b07],
98
+ [0x2b1b, 0x2b1c],
99
+ [0x2b50, 0x2b50],
100
+ [0x2b55, 0x2b55],
101
+ [0x3030, 0x3030],
102
+ [0x303d, 0x303d],
103
+ [0x3297, 0x3297],
104
+ [0x3299, 0x3299],
105
+ [0x1f004, 0x1f004],
106
+ [0x1f02c, 0x1f02f],
107
+ [0x1f094, 0x1f09f],
108
+ [0x1f0af, 0x1f0b0],
109
+ [0x1f0c0, 0x1f0c0],
110
+ [0x1f0cf, 0x1f0d0],
111
+ [0x1f0f6, 0x1f0ff],
112
+ [0x1f170, 0x1f171],
113
+ [0x1f17e, 0x1f17f],
114
+ [0x1f18e, 0x1f18e],
115
+ [0x1f191, 0x1f19a],
116
+ [0x1f1ae, 0x1f1e5],
117
+ [0x1f201, 0x1f20f],
118
+ [0x1f21a, 0x1f21a],
119
+ [0x1f22f, 0x1f22f],
120
+ [0x1f232, 0x1f23a],
121
+ [0x1f23c, 0x1f23f],
122
+ [0x1f249, 0x1f25f],
123
+ [0x1f266, 0x1f321],
124
+ [0x1f324, 0x1f393],
125
+ [0x1f396, 0x1f397],
126
+ [0x1f399, 0x1f39b],
127
+ [0x1f39e, 0x1f3f0],
128
+ [0x1f3f3, 0x1f3f5],
129
+ [0x1f3f7, 0x1f3fa],
130
+ [0x1f400, 0x1f4fd],
131
+ [0x1f4ff, 0x1f53d],
132
+ [0x1f549, 0x1f54e],
133
+ [0x1f550, 0x1f567],
134
+ [0x1f56f, 0x1f570],
135
+ [0x1f573, 0x1f57a],
136
+ [0x1f587, 0x1f587],
137
+ [0x1f58a, 0x1f58d],
138
+ [0x1f590, 0x1f590],
139
+ [0x1f595, 0x1f596],
140
+ [0x1f5a4, 0x1f5a5],
141
+ [0x1f5a8, 0x1f5a8],
142
+ [0x1f5b1, 0x1f5b2],
143
+ [0x1f5bc, 0x1f5bc],
144
+ [0x1f5c2, 0x1f5c4],
145
+ [0x1f5d1, 0x1f5d3],
146
+ [0x1f5dc, 0x1f5de],
147
+ [0x1f5e1, 0x1f5e1],
148
+ [0x1f5e3, 0x1f5e3],
149
+ [0x1f5e8, 0x1f5e8],
150
+ [0x1f5ef, 0x1f5ef],
151
+ [0x1f5f3, 0x1f5f3],
152
+ [0x1f5fa, 0x1f64f],
153
+ [0x1f680, 0x1f6c5],
154
+ [0x1f6cb, 0x1f6d2],
155
+ [0x1f6d5, 0x1f6e5],
156
+ [0x1f6e9, 0x1f6e9],
157
+ [0x1f6eb, 0x1f6f0],
158
+ [0x1f6f3, 0x1f6ff],
159
+ [0x1f7da, 0x1f7ff],
160
+ [0x1f80c, 0x1f80f],
161
+ [0x1f848, 0x1f84f],
162
+ [0x1f85a, 0x1f85f],
163
+ [0x1f888, 0x1f88f],
164
+ [0x1f8ae, 0x1f8af],
165
+ [0x1f8bc, 0x1f8bf],
166
+ [0x1f8c2, 0x1f8cf],
167
+ [0x1f8d9, 0x1f8ff],
168
+ [0x1f90c, 0x1f93a],
169
+ [0x1f93c, 0x1f945],
170
+ [0x1f947, 0x1f9ff],
171
+ [0x1fa58, 0x1fa5f],
172
+ [0x1fa6e, 0x1faff],
173
+ [0x1fc00, 0x1fffd],
174
+ ];
175
+
176
+ /** @type {ReadonlyArray<readonly [number, number]>} */
177
+ export const EMOJI_MODIFIER = [
178
+ [0x1f3fb, 0x1f3ff],
179
+ ];
180
+
181
+ /** @type {ReadonlyArray<readonly [number, number]>} */
182
+ export const EMOJI_TEXT_DEFAULT = [
183
+ [0x23, 0x23],
184
+ [0x2a, 0x2a],
185
+ [0x30, 0x39],
186
+ [0xa9, 0xa9],
187
+ [0xae, 0xae],
188
+ [0x203c, 0x203c],
189
+ [0x2049, 0x2049],
190
+ [0x2122, 0x2122],
191
+ [0x2139, 0x2139],
192
+ [0x2194, 0x2199],
193
+ [0x21a9, 0x21aa],
194
+ [0x2328, 0x2328],
195
+ [0x23cf, 0x23cf],
196
+ [0x23ed, 0x23ef],
197
+ [0x23f1, 0x23f2],
198
+ [0x23f8, 0x23fa],
199
+ [0x24c2, 0x24c2],
200
+ [0x25aa, 0x25ab],
201
+ [0x25b6, 0x25b6],
202
+ [0x25c0, 0x25c0],
203
+ [0x25fb, 0x25fc],
204
+ [0x2600, 0x2604],
205
+ [0x260e, 0x260e],
206
+ [0x2611, 0x2611],
207
+ [0x2618, 0x2618],
208
+ [0x261d, 0x261d],
209
+ [0x2620, 0x2620],
210
+ [0x2622, 0x2623],
211
+ [0x2626, 0x2626],
212
+ [0x262a, 0x262a],
213
+ [0x262e, 0x262f],
214
+ [0x2638, 0x263a],
215
+ [0x2640, 0x2640],
216
+ [0x2642, 0x2642],
217
+ [0x265f, 0x2660],
218
+ [0x2663, 0x2663],
219
+ [0x2665, 0x2666],
220
+ [0x2668, 0x2668],
221
+ [0x267b, 0x267b],
222
+ [0x267e, 0x267e],
223
+ [0x2692, 0x2692],
224
+ [0x2694, 0x2697],
225
+ [0x2699, 0x2699],
226
+ [0x269b, 0x269c],
227
+ [0x26a0, 0x26a0],
228
+ [0x26a7, 0x26a7],
229
+ [0x26b0, 0x26b1],
230
+ [0x26c8, 0x26c8],
231
+ [0x26cf, 0x26cf],
232
+ [0x26d1, 0x26d1],
233
+ [0x26d3, 0x26d3],
234
+ [0x26e9, 0x26e9],
235
+ [0x26f0, 0x26f1],
236
+ [0x26f4, 0x26f4],
237
+ [0x26f7, 0x26f9],
238
+ [0x2702, 0x2702],
239
+ [0x2708, 0x2709],
240
+ [0x270c, 0x270d],
241
+ [0x270f, 0x270f],
242
+ [0x2712, 0x2712],
243
+ [0x2714, 0x2714],
244
+ [0x2716, 0x2716],
245
+ [0x271d, 0x271d],
246
+ [0x2721, 0x2721],
247
+ [0x2733, 0x2734],
248
+ [0x2744, 0x2744],
249
+ [0x2747, 0x2747],
250
+ [0x2763, 0x2764],
251
+ [0x27a1, 0x27a1],
252
+ [0x2934, 0x2935],
253
+ [0x2b05, 0x2b07],
254
+ [0x3030, 0x3030],
255
+ [0x303d, 0x303d],
256
+ [0x3297, 0x3297],
257
+ [0x3299, 0x3299],
258
+ [0x1f170, 0x1f171],
259
+ [0x1f17e, 0x1f17f],
260
+ [0x1f202, 0x1f202],
261
+ [0x1f237, 0x1f237],
262
+ [0x1f321, 0x1f321],
263
+ [0x1f324, 0x1f32c],
264
+ [0x1f336, 0x1f336],
265
+ [0x1f37d, 0x1f37d],
266
+ [0x1f396, 0x1f397],
267
+ [0x1f399, 0x1f39b],
268
+ [0x1f39e, 0x1f39f],
269
+ [0x1f3cb, 0x1f3ce],
270
+ [0x1f3d4, 0x1f3df],
271
+ [0x1f3f3, 0x1f3f3],
272
+ [0x1f3f5, 0x1f3f5],
273
+ [0x1f3f7, 0x1f3f7],
274
+ [0x1f43f, 0x1f43f],
275
+ [0x1f441, 0x1f441],
276
+ [0x1f4fd, 0x1f4fd],
277
+ [0x1f549, 0x1f54a],
278
+ [0x1f56f, 0x1f570],
279
+ [0x1f573, 0x1f579],
280
+ [0x1f587, 0x1f587],
281
+ [0x1f58a, 0x1f58d],
282
+ [0x1f590, 0x1f590],
283
+ [0x1f5a5, 0x1f5a5],
284
+ [0x1f5a8, 0x1f5a8],
285
+ [0x1f5b1, 0x1f5b2],
286
+ [0x1f5bc, 0x1f5bc],
287
+ [0x1f5c2, 0x1f5c4],
288
+ [0x1f5d1, 0x1f5d3],
289
+ [0x1f5dc, 0x1f5de],
290
+ [0x1f5e1, 0x1f5e1],
291
+ [0x1f5e3, 0x1f5e3],
292
+ [0x1f5e8, 0x1f5e8],
293
+ [0x1f5ef, 0x1f5ef],
294
+ [0x1f5f3, 0x1f5f3],
295
+ [0x1f5fa, 0x1f5fa],
296
+ [0x1f6cb, 0x1f6cb],
297
+ [0x1f6cd, 0x1f6cf],
298
+ [0x1f6e0, 0x1f6e5],
299
+ [0x1f6e9, 0x1f6e9],
300
+ [0x1f6f0, 0x1f6f0],
301
+ [0x1f6f3, 0x1f6f3],
302
+ ];
303
+
304
+ /** @type {ReadonlyArray<readonly [number, number]>} */
305
+ export const UNIFIED_IDEOGRAPH = [
306
+ [0x3400, 0x4dbf],
307
+ [0x4e00, 0x9fff],
308
+ [0xfa0e, 0xfa0f],
309
+ [0xfa11, 0xfa11],
310
+ [0xfa13, 0xfa14],
311
+ [0xfa1f, 0xfa1f],
312
+ [0xfa21, 0xfa21],
313
+ [0xfa23, 0xfa24],
314
+ [0xfa27, 0xfa29],
315
+ [0x20000, 0x2a6df],
316
+ [0x2a700, 0x2b81d],
317
+ [0x2b820, 0x2cead],
318
+ [0x2ceb0, 0x2ebe0],
319
+ [0x2ebf0, 0x2ee5d],
320
+ [0x30000, 0x3134a],
321
+ [0x31350, 0x33479],
322
+ ];
323
+
324
+ /** @type {ReadonlyArray<readonly [number, number]>} */
325
+ export const SCRIPT_BRAILLE = [
326
+ [0x2800, 0x28ff],
327
+ ];
328
+
329
+ /** @type {ReadonlyArray<readonly [number, number]>} */
330
+ export const SCRIPT_HANGUL = [
331
+ [0x1100, 0x11ff],
332
+ [0x302e, 0x302f],
333
+ [0x3131, 0x318e],
334
+ [0x3200, 0x321e],
335
+ [0x3260, 0x327e],
336
+ [0xa960, 0xa97c],
337
+ [0xac00, 0xd7a3],
338
+ [0xd7b0, 0xd7c6],
339
+ [0xd7cb, 0xd7fb],
340
+ [0xffa0, 0xffbe],
341
+ [0xffc2, 0xffc7],
342
+ [0xffca, 0xffcf],
343
+ [0xffd2, 0xffd7],
344
+ [0xffda, 0xffdc],
345
+ ];
346
+ // Stryker restore all
347
+
348
+ /**
349
+ * True when `cp` lies in one of `spans` (sorted, non-overlapping). A negative
350
+ * `cp` — the "no neighbour" sentinel — lies in none.
351
+ * @param {ReadonlyArray<readonly [number, number]>} spans
352
+ * @param {number} cp
353
+ * @returns {boolean}
354
+ */
355
+ export function inSpans(spans, cp) {
356
+ let lo = 0;
357
+ let hi = spans.length - 1;
358
+ while (lo <= hi) {
359
+ const mid = (lo + hi) >> 1;
360
+ if (cp < spans[mid][0]) hi = mid - 1;
361
+ else if (cp > spans[mid][1]) lo = mid + 1;
362
+ else return true;
363
+ }
364
+ return false;
365
+ }
package/types/ansi.d.mts CHANGED
@@ -49,15 +49,12 @@ export function isCancelledOrphan(text: string, token: AnsiToken): boolean;
49
49
  */
50
50
  export function scanAnsi(text: string): AnsiToken[];
51
51
  /**
52
- * The CONCEAL state after the SGR token `token` is applied to a terminal already
53
- * in state `concealed` — the state in which a terminal renders what follows as
54
- * blank while its bytes stay readable to anything reading the file.
52
+ * The rendition after the SGR token `token` is applied to a terminal already in
53
+ * `state`.
55
54
  *
56
- * A TRANSITION, not a property of the token: conceal is terminal state that
55
+ * A TRANSITION, not a property of the token: rendition is terminal state that
57
56
  * outlives the sequence that set it, so `ESC[8m` followed by `ESC[31m` is still
58
- * concealed — a per-token predicate would read the second token as "no conceal
59
- * here" and lose the state. Only `8` (set), `28` (reveal) and `0` (reset all)
60
- * move it, and the token's parameters are applied in order, so a later reveal or
57
+ * concealed. The token's parameters are applied in order, so a later reveal or
61
58
  * reset in the SAME token cancels an earlier `8`: `ESC[8;28;31m` renders red and
62
59
  * visible.
63
60
  *
@@ -65,18 +62,26 @@ export function scanAnsi(text: string): AnsiToken[];
65
62
  * the digit. `38`/`48`/`58` take their colour arguments from the parameters that
66
63
  * FOLLOW them in the semicolon form, so `ESC[38;5;8m` is bright-black foreground
67
64
  * and its `8` is a palette index; a parameter carrying its arguments as ITU T.416
68
- * sub-parameters (`38:5:8`) is self-contained, so only its head counts and
69
- * nothing after it is consumed. A colour-space selector T.416 gives no argument
70
- * count for is malformed, and a terminal that ignores the colour form still
71
- * applies what follows it, so the scan CONTINUES from the next parameter rather
72
- * than consuming arguments it cannot size — reading one parameter too many costs
73
- * a token shape no emitter produces, while stopping there would hand
74
- * `ESC[38;9;8m` a pass.
65
+ * sub-parameters (`38:5:8`) is self-contained, so nothing after it is consumed.
66
+ * A colour-space selector T.416 gives no argument count for is malformed, and a
67
+ * terminal that ignores the colour form still applies what follows it, so the
68
+ * scan CONTINUES from the next parameter rather than consuming arguments it
69
+ * cannot size — stopping there would hand `ESC[38;9;8m` a pass.
75
70
  * @param {string} token a token {@link scanAnsi} classified {@link TOKEN_KIND.SGR}
76
- * @param {boolean} concealed the state before this token
71
+ * @param {Readonly<SgrRendition>} state the rendition before this token
72
+ * @returns {SgrRendition}
73
+ */
74
+ export function sgrRendition(token: string, state: Readonly<SgrRendition>): SgrRendition;
75
+ /**
76
+ * True when text drawn in `rendition` is invisible to a human because its
77
+ * foreground IS its background (`ESC[30;40m`, `ESC[38;5;7;48;5;7m`). Only an
78
+ * unambiguous match counts: a default colour is unknown, so it matches nothing,
79
+ * and BOLD over a basic colour is drawn brighter by many terminals, so
80
+ * `ESC[1;30;40m` is not called hidden — the precision direction.
81
+ * @param {Readonly<SgrRendition>} rendition
77
82
  * @returns {boolean}
78
83
  */
79
- export function sgrConcealState(token: string, concealed: boolean): boolean;
84
+ export function foregroundMatchesBackground({ bold, fg, bg }: Readonly<SgrRendition>): boolean;
80
85
  /**
81
86
  * The ONE ANSI grammar: the raw control-introducer charset and the tokenizer
82
87
  * every consumer scans with.
@@ -170,6 +175,17 @@ export const TOKEN_KIND: Readonly<{
170
175
  */
171
176
  ORPHAN_C1: "orphan-c1-introducer";
172
177
  }>;
178
+ /**
179
+ * What a terminal's graphic rendition looks like after an SGR token: whether
180
+ * CONCEAL is on, whether BOLD is (which many terminals render as a brighter
181
+ * foreground), and the foreground/background colour as a comparable key — `i<n>`
182
+ * for a palette index (`31` and `38;5;1` are both `i1`), `rgb:<r>,<g>,<b>` for
183
+ * direct colour, `null` for the default or a colour this reader cannot size.
184
+ * @typedef {{ concealed: boolean, bold: boolean, fg: string | null, bg: string | null }} SgrRendition
185
+ */
186
+ /** The rendition of a terminal no SGR has touched (and of `ESC[0m`).
187
+ * @type {Readonly<SgrRendition>} */
188
+ export const DEFAULT_RENDITION: Readonly<SgrRendition>;
173
189
  export type AnsiToken = {
174
190
  /**
175
191
  * Index of the introducer.
@@ -184,3 +200,16 @@ export type AnsiToken = {
184
200
  */
185
201
  kind: string;
186
202
  };
203
+ /**
204
+ * What a terminal's graphic rendition looks like after an SGR token: whether
205
+ * CONCEAL is on, whether BOLD is (which many terminals render as a brighter
206
+ * foreground), and the foreground/background colour as a comparable key — `i<n>`
207
+ * for a palette index (`31` and `38;5;1` are both `i1`), `rgb:<r>,<g>,<b>` for
208
+ * direct colour, `null` for the default or a colour this reader cannot size.
209
+ */
210
+ export type SgrRendition = {
211
+ concealed: boolean;
212
+ bold: boolean;
213
+ fg: string | null;
214
+ bg: string | null;
215
+ };
@@ -1,14 +1,14 @@
1
1
  /**
2
- * GENERATED by scripts/gen-invisible-charset.mjs from Node's Unicode data
3
- * (\p{Cf}, Unicode 17.0) — DO NOT EDIT.
2
+ * GENERATED by scripts/gen-invisible-charset.mjs from the pinned UCD
3
+ * (General_Category=Cf, Unicode 17.0.0) — DO NOT EDIT.
4
4
  *
5
5
  * The general-category Cf code points, PINNED at generation time. invisible.mjs
6
- * strips exactly this set instead of testing \p{Cf} live, and the Python port
6
+ * strips exactly this set instead of asking the runtime for Cf, and the Python port
7
7
  * reads the SAME set from data/invisible-charset.json's `cf_codepoints`, so both
8
8
  * layers strip an identical Cf set regardless of each runtime's own Unicode
9
9
  * version. Regenerate with `node scripts/gen-invisible-charset.mjs`;
10
- * test/invisible-charset.test.mjs fails if this drifts from Node's \p{Cf}.
10
+ * test/invisible-charset.test.mjs fails if this drifts from the pinned UCD.
11
11
  */
12
- export const UNICODE_VERSION: "17.0";
12
+ export const UNICODE_VERSION: "17.0.0";
13
13
  /** @type {readonly number[]} Sorted ascending. */
14
14
  export const CF_CODEPOINTS: readonly number[];
package/types/index.d.mts CHANGED
@@ -58,6 +58,6 @@ export function sanitize(text: string, options?: {
58
58
  original: string;
59
59
  }>;
60
60
  }>;
61
- export { applyLayer1, applyLayer1WellFormed, isBenignAnsi, isBenignAnsiKinds, normalizeLoneSurrogates, stripAnsiFully, sgrCarriesPayload, SGR_RUN_THRESHOLD, LONE_SURROGATE_RE } from "./layer1.mjs";
61
+ export { applyLayer1, applyLayer1WellFormed, escapesPreservable, isBenignAnsi, isBenignAnsiKinds, normalizeLoneSurrogates, stripAnsiFully, stripTerminalFully, sgrCarriesPayload, SGR_RUN_THRESHOLD, LONE_SURROGATE_RE } from "./layer1.mjs";
62
62
  export { stripInvisible, stripInvisibleWithReport, isSgrOnly, STRIP, SGR_RE, CHECKS, CATEGORY, CATEGORY_LABELS, LINGUISTIC_SCRIPTS, VS, BLANK_NON_CF, LONG_RUN_RE, LONG_RUN_THRESHOLD, SCATTERED_THRESHOLD, findLongRuns, hasLongRun } from "./invisible.mjs";
63
63
  export { HTML_TAG_PRESENT, MD_LINK_HINT, SECRET_HINT, SECRET_HINT_EXT, matchesSecretHint } from "./gates.mjs";
@@ -14,9 +14,13 @@ export function decodeRun(run: string): {
14
14
  decoded: string;
15
15
  };
16
16
  /**
17
- * Scan a file's text for hidden-Unicode injection. Reports each long invisible
17
+ * Scan a file's text for hidden-Unicode injection. Reports each payload long
18
18
  * run (with its decoded payload) plus a single scattered-chars finding when the
19
- * non-run invisible count crosses the threshold-evasion floor.
19
+ * effective invisible count outside those runs crosses the threshold-evasion
20
+ * floor.
21
+ *
22
+ * Whether there is anything to report is {@link payloadVerdict}'s call, the
23
+ * one every other surface makes.
20
24
  * @param {string} content
21
25
  * @returns {Array<{ line: number | null, charCount: number, method: string, decoded: string }>}
22
26
  * `line` is the 1-based line of a long-run finding, or `null` for the
@@ -68,11 +68,13 @@ export function describeStripped(invisFound: string[], deAnsi: string): string;
68
68
  */
69
69
  export function countPayloadInvisible(text: string): number;
70
70
  /**
71
- * The `text` with every carve-out-PRESERVABLE invisible (joiners/selectors/tags/
72
- * blank fillers doing real rendering work) replaced by a space, leaving only the
73
- * PAYLOAD invisibles in place. The LONG_RUN injection probe runs over this so a
74
- * legitimate emoji/flag/variation sequence never trips the "possible injection
75
- * payload" marker (alert fatigue), while a genuine hidden run still surfaces.
71
+ * The `text` with every visible character and every carve-out-PRESERVABLE
72
+ * invisible (joiners/selectors/tags/blank fillers doing real rendering work)
73
+ * replaced by spaces — one per UTF-16 unit, so the view is index-aligned with
74
+ * `text` — leaving only the PAYLOAD invisibles in place. The LONG_RUN injection
75
+ * probe runs over this so a legitimate emoji/flag/variation sequence never trips
76
+ * the "possible injection payload" marker (alert fatigue), while a genuine
77
+ * hidden run still surfaces.
76
78
  * @param {string} text
77
79
  * @returns {string}
78
80
  */
@@ -143,6 +145,25 @@ export function countEffectiveInvisible(text: string): number;
143
145
  * @returns {boolean}
144
146
  */
145
147
  export function isIncidentalInvisible(text: string): boolean;
148
+ /**
149
+ * THE decision whether `text` carries a payload-capable invisible channel: a
150
+ * payload LONG RUN, or {@link SCATTERED_THRESHOLD} or more effective payload
151
+ * invisibles. Every gate reads this one verdict, so a Persian paragraph cannot
152
+ * be a payload to one and clean to another. It stops at the first run, so an
153
+ * 8 MB field of short runs costs one record.
154
+ * @param {string} text the text a consumer acts on, ANSI-stripped where its
155
+ * surface can carry escapes (a sequence can hide invisibles)
156
+ * @returns {{ firstRun: { index: number, text: string, charCount: number } | null, invisibleCount: number, payloadCapable: boolean }}
157
+ */
158
+ export function payloadVerdict(text: string): {
159
+ firstRun: {
160
+ index: number;
161
+ text: string;
162
+ charCount: number;
163
+ } | null;
164
+ invisibleCount: number;
165
+ payloadCapable: boolean;
166
+ };
146
167
  /**
147
168
  * Strip payload-capable invisible chars and report which categories were
148
169
  * removed. A single leading U+FEFF (BOM) is preserved as a legitimate marker;
@@ -155,11 +176,17 @@ export function isIncidentalInvisible(text: string): boolean;
155
176
  * decide whether a leading BOM is genuinely leading: an interior BOM that an
156
177
  * ANSI-strip left at index 0 of `text` (e.g. `ESC[m + interior U+FEFF`) must NOT be treated as a
157
178
  * legitimate leading marker. Defaults to `text` for the common single-arg call.
179
+ *
180
+ * `carveOut: false` strips EVERY payload-capable invisible, preserved ones
181
+ * included — the monotone fallback for a composition that fails to converge.
158
182
  * @param {string} text
159
183
  * @param {string} [originalText]
184
+ * @param {{ carveOut?: boolean }} [options]
160
185
  * @returns {{ cleaned: string, found: string[] }}
161
186
  */
162
- export function stripInvisibleWithReport(text: string, originalText?: string): {
187
+ export function stripInvisibleWithReport(text: string, originalText?: string, { carveOut }?: {
188
+ carveOut?: boolean;
189
+ }): {
163
190
  cleaned: string;
164
191
  found: string[];
165
192
  };
@@ -215,3 +242,31 @@ export const TOTAL_PRESERVED_BLANK_BUDGET: 16;
215
242
  export const PRESERVED_BLANK_PER_ANCHOR: 2;
216
243
  export const LINGUISTIC_SCRIPTS: string[];
217
244
  export { BRAHMIC_CONSONANT_RANGES } from "./joining-type.mjs";
245
+ export type CarveEntry = {
246
+ body: string;
247
+ cps: Int32Array;
248
+ analysis: ReturnType<typeof analyzeCarve>;
249
+ strip: {
250
+ cleaned: string;
251
+ found: string[];
252
+ removed: number;
253
+ } | null;
254
+ removed: number | null;
255
+ };
256
+ /**
257
+ * Per-invisible carve-out analysis, shared by carveStrip and
258
+ * countPayloadInvisible: for each code point, its CODE_* class (CODE_VISIBLE
259
+ * when visible) and its preserve KIND_* (KIND_NONE when the char is payload).
260
+ * Everything invisible that is NOT preserve-eligible is payload; the scatter
261
+ * floor counts only that, so meaningful joiners/selectors never push honest
262
+ * prose over the threshold.
263
+ * @param {Int32Array} cps
264
+ * @returns {{ codes: Uint8Array, kind: Uint8Array, invisible: Int32Array, payloadInvis: number, visibleLen: number }}
265
+ */
266
+ declare function analyzeCarve(cps: Int32Array): {
267
+ codes: Uint8Array;
268
+ kind: Uint8Array;
269
+ invisible: Int32Array;
270
+ payloadInvis: number;
271
+ visibleLen: number;
272
+ };
@@ -15,13 +15,16 @@ export function isVirama(cp: number): boolean;
15
15
  /**
16
16
  * True when `cp` is a Brahmic consonant — the only base a virama attaches to,
17
17
  * and therefore the only base after which a ZWJ/ZWNJ is a real conjunct
18
- * request rather than a zero-width payload.
18
+ * request rather than a zero-width payload. A binary search, like
19
+ * `lookup`: the spans are sorted and disjoint, and the carve analysis asks
20
+ * this of every visible code point of a long document, where a scan of all the
21
+ * spans per code point was the dominant cost.
19
22
  * @param {number} cp
20
23
  * @returns {boolean}
21
24
  */
22
25
  export function isBrahmicConsonant(cp: number): boolean;
23
26
  /**
24
- * GENERATED by scripts/gen-joining-type.mjs from ucd-full@17.0.0 — DO NOT EDIT.
27
+ * GENERATED by scripts/gen-joining-type.mjs from the pinned UCD 17.0.0 — DO NOT EDIT.
25
28
  *
26
29
  * Unicode Joining_Type, Indic virama and Brahmic consonant range tables backing
27
30
  * the ZWNJ/ZWJ carve-out in invisible.mjs. Regenerate with `pnpm gen:joining-type`;