@dev-pi2pie/word-counter 0.1.4 → 0.1.5-canary.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,1318 @@
1
+ let yaml = require("yaml");
2
+ //#region src/wc/segmenter.ts
3
+ const segmenterCache = /* @__PURE__ */ new Map();
4
+ const graphemeSegmenterCache = /* @__PURE__ */ new Map();
5
+ function getSegmenter(locale) {
6
+ const cached = segmenterCache.get(locale);
7
+ if (cached) return cached;
8
+ const segmenter = new Intl.Segmenter(locale, { granularity: "word" });
9
+ segmenterCache.set(locale, segmenter);
10
+ return segmenter;
11
+ }
12
+ function getGraphemeSegmenter(locale) {
13
+ const cached = graphemeSegmenterCache.get(locale);
14
+ if (cached) return cached;
15
+ const segmenter = new Intl.Segmenter(locale, { granularity: "grapheme" });
16
+ graphemeSegmenterCache.set(locale, segmenter);
17
+ return segmenter;
18
+ }
19
+ function supportsSegmenter() {
20
+ return typeof Intl !== "undefined" && typeof Intl.Segmenter === "function";
21
+ }
22
+ function countWordsForLocale(text, locale) {
23
+ const segmenter = getSegmenter(locale);
24
+ let count = 0;
25
+ for (const segment of segmenter.segment(text)) if (segment.isWordLike) count++;
26
+ return count;
27
+ }
28
+ function countCharsForLocale(text, locale) {
29
+ if (!supportsSegmenter()) return Array.from(text).length;
30
+ const segmenter = getGraphemeSegmenter(locale);
31
+ let count = 0;
32
+ for (const _segment of segmenter.segment(text)) count++;
33
+ return count;
34
+ }
35
+ //#endregion
36
+ //#region src/utils/append-all.ts
37
+ function appendAll(target, source) {
38
+ for (const item of source) target.push(item);
39
+ }
40
+ //#endregion
41
+ //#region src/wc/non-words.ts
42
+ const emojiRegex = /(?:\p{Extended_Pictographic}|\p{Emoji_Presentation})/u;
43
+ const emojiPresentationRegex = /\p{Emoji_Presentation}/u;
44
+ const keycapEmojiRegex = /[0-9#*]\uFE0F?\u20E3/u;
45
+ const symbolRegex = /\p{S}/u;
46
+ const punctuationRegex = /\p{P}/u;
47
+ const whitespaceRegex = /\s/u;
48
+ const newlineChars = new Set([
49
+ "\n",
50
+ "\r",
51
+ "\u2028",
52
+ "\u2029"
53
+ ]);
54
+ function createNonWordCollection() {
55
+ return {
56
+ emoji: [],
57
+ symbols: [],
58
+ punctuation: [],
59
+ counts: {
60
+ emoji: 0,
61
+ symbols: 0,
62
+ punctuation: 0
63
+ }
64
+ };
65
+ }
66
+ function addNonWord(collection, category, segment) {
67
+ if (category === "emoji") {
68
+ collection.emoji.push(segment);
69
+ collection.counts.emoji += 1;
70
+ return;
71
+ }
72
+ if (category === "symbol") {
73
+ collection.symbols.push(segment);
74
+ collection.counts.symbols += 1;
75
+ return;
76
+ }
77
+ collection.punctuation.push(segment);
78
+ collection.counts.punctuation += 1;
79
+ }
80
+ function addWhitespace(collection, segment) {
81
+ let whitespace = collection.whitespace;
82
+ let count = 0;
83
+ for (const char of segment) {
84
+ if (char === " ") {
85
+ whitespace = whitespace ?? createWhitespaceCounts();
86
+ whitespace.spaces += 1;
87
+ count += 1;
88
+ continue;
89
+ }
90
+ if (char === " ") {
91
+ whitespace = whitespace ?? createWhitespaceCounts();
92
+ whitespace.tabs += 1;
93
+ count += 1;
94
+ continue;
95
+ }
96
+ if (newlineChars.has(char)) {
97
+ whitespace = whitespace ?? createWhitespaceCounts();
98
+ whitespace.newlines += 1;
99
+ count += 1;
100
+ continue;
101
+ }
102
+ if (whitespaceRegex.test(char)) {
103
+ whitespace = whitespace ?? createWhitespaceCounts();
104
+ whitespace.other += 1;
105
+ count += 1;
106
+ }
107
+ }
108
+ if (count > 0) {
109
+ collection.whitespace = whitespace ?? createWhitespaceCounts();
110
+ collection.counts.whitespace = (collection.counts.whitespace ?? 0) + count;
111
+ }
112
+ return count;
113
+ }
114
+ function classifyNonWordSegment(segment) {
115
+ const hasEmojiVariationSelector = segment.includes("️");
116
+ if (keycapEmojiRegex.test(segment) || emojiPresentationRegex.test(segment) || hasEmojiVariationSelector && emojiRegex.test(segment)) return "emoji";
117
+ if (symbolRegex.test(segment)) return "symbol";
118
+ if (punctuationRegex.test(segment)) return "punctuation";
119
+ return null;
120
+ }
121
+ function mergeNonWordCollections(target, source) {
122
+ if (source.counts.emoji > 0) {
123
+ appendAll(target.emoji, source.emoji);
124
+ target.counts.emoji += source.counts.emoji;
125
+ }
126
+ if (source.counts.symbols > 0) {
127
+ appendAll(target.symbols, source.symbols);
128
+ target.counts.symbols += source.counts.symbols;
129
+ }
130
+ if (source.counts.punctuation > 0) {
131
+ appendAll(target.punctuation, source.punctuation);
132
+ target.counts.punctuation += source.counts.punctuation;
133
+ }
134
+ if (source.counts.whitespace && source.counts.whitespace > 0 && source.whitespace) {
135
+ const whitespace = target.whitespace ?? createWhitespaceCounts();
136
+ whitespace.spaces += source.whitespace.spaces;
137
+ whitespace.tabs += source.whitespace.tabs;
138
+ whitespace.newlines += source.whitespace.newlines;
139
+ whitespace.other += source.whitespace.other;
140
+ target.whitespace = whitespace;
141
+ target.counts.whitespace = (target.counts.whitespace ?? 0) + source.counts.whitespace;
142
+ }
143
+ return target;
144
+ }
145
+ function createWhitespaceCounts() {
146
+ return {
147
+ spaces: 0,
148
+ tabs: 0,
149
+ newlines: 0,
150
+ other: 0
151
+ };
152
+ }
153
+ //#endregion
154
+ //#region src/wc/analyze.ts
155
+ function analyzeChunk(chunk, collectNonWords, includeWhitespace) {
156
+ const segmenter = getSegmenter(chunk.locale);
157
+ const segments = [];
158
+ const nonWords = collectNonWords ? createNonWordCollection() : null;
159
+ for (const part of segmenter.segment(chunk.text)) if (part.isWordLike) segments.push(part.segment);
160
+ else if (collectNonWords && nonWords) {
161
+ if (includeWhitespace) addWhitespace(nonWords, part.segment);
162
+ const category = classifyNonWordSegment(part.segment);
163
+ if (category) addNonWord(nonWords, category, part.segment);
164
+ }
165
+ return {
166
+ locale: chunk.locale,
167
+ text: chunk.text,
168
+ segments,
169
+ words: segments.length,
170
+ nonWords: nonWords ?? void 0
171
+ };
172
+ }
173
+ function analyzeCharChunk(chunk, collectNonWords, includeWhitespace) {
174
+ const segmenter = getSegmenter(chunk.locale);
175
+ const nonWords = collectNonWords ? createNonWordCollection() : null;
176
+ let chars = 0;
177
+ let wordChars = 0;
178
+ let nonWordChars = 0;
179
+ for (const part of segmenter.segment(chunk.text)) {
180
+ if (part.isWordLike) {
181
+ const count = countCharsForLocale(part.segment, chunk.locale);
182
+ chars += count;
183
+ wordChars += count;
184
+ continue;
185
+ }
186
+ if (collectNonWords && nonWords) {
187
+ let whitespaceCount = 0;
188
+ if (includeWhitespace) whitespaceCount = addWhitespace(nonWords, part.segment);
189
+ const category = classifyNonWordSegment(part.segment);
190
+ if (category) addNonWord(nonWords, category, part.segment);
191
+ if (category || whitespaceCount > 0) {
192
+ const count = countCharsForLocale(part.segment, chunk.locale);
193
+ chars += count;
194
+ nonWordChars += count;
195
+ }
196
+ }
197
+ }
198
+ return {
199
+ locale: chunk.locale,
200
+ text: chunk.text,
201
+ chars,
202
+ wordChars,
203
+ nonWordChars,
204
+ nonWords: nonWords ?? void 0
205
+ };
206
+ }
207
+ function aggregateCharsByLocale(chunks) {
208
+ const order = [];
209
+ const map = /* @__PURE__ */ new Map();
210
+ for (const chunk of chunks) {
211
+ const existing = map.get(chunk.locale);
212
+ if (existing) {
213
+ existing.chars += chunk.chars;
214
+ existing.wordChars += chunk.wordChars;
215
+ existing.nonWordChars += chunk.nonWordChars;
216
+ if (chunk.nonWords) {
217
+ if (!existing.nonWords) existing.nonWords = createNonWordCollection();
218
+ mergeNonWordCollections(existing.nonWords, chunk.nonWords);
219
+ }
220
+ continue;
221
+ }
222
+ order.push(chunk.locale);
223
+ map.set(chunk.locale, {
224
+ locale: chunk.locale,
225
+ chars: chunk.chars,
226
+ wordChars: chunk.wordChars,
227
+ nonWordChars: chunk.nonWordChars,
228
+ nonWords: chunk.nonWords ? mergeNonWordCollections(createNonWordCollection(), chunk.nonWords) : void 0
229
+ });
230
+ }
231
+ return order.map((locale) => map.get(locale));
232
+ }
233
+ function aggregateByLocale(chunks) {
234
+ const order = [];
235
+ const map = /* @__PURE__ */ new Map();
236
+ for (const chunk of chunks) {
237
+ const existing = map.get(chunk.locale);
238
+ if (existing) {
239
+ existing.words += chunk.words;
240
+ appendAll(existing.segments, chunk.segments);
241
+ continue;
242
+ }
243
+ order.push(chunk.locale);
244
+ map.set(chunk.locale, {
245
+ locale: chunk.locale,
246
+ words: chunk.words,
247
+ segments: [...chunk.segments]
248
+ });
249
+ }
250
+ return order.map((locale) => map.get(locale));
251
+ }
252
+ //#endregion
253
+ //#region src/wc/mode.ts
254
+ const MODE_ALIASES = {
255
+ chunk: "chunk",
256
+ chunks: "chunk",
257
+ segments: "segments",
258
+ segment: "segments",
259
+ seg: "segments",
260
+ collector: "collector",
261
+ collect: "collector",
262
+ colle: "collector",
263
+ char: "char",
264
+ chars: "char",
265
+ character: "char",
266
+ characters: "char",
267
+ "char-collector": "char-collector"
268
+ };
269
+ const CHAR_MODE_ALIASES = new Set([
270
+ "char",
271
+ "chars",
272
+ "character",
273
+ "characters"
274
+ ]);
275
+ const COLLECTOR_MODE_ALIASES = new Set([
276
+ "collector",
277
+ "collect",
278
+ "colle",
279
+ "col"
280
+ ]);
281
+ function collapseSeparators(value) {
282
+ return value.replace(/[-_\s]+/g, "");
283
+ }
284
+ function isComposedCharCollectorFromTokens(value) {
285
+ const tokens = value.split(/[-_\s]+/).map((token) => token.trim()).filter((token) => token.length > 0);
286
+ if (tokens.length < 2) return false;
287
+ let hasCharAlias = false;
288
+ let hasCollectorAlias = false;
289
+ for (const token of tokens) {
290
+ if (CHAR_MODE_ALIASES.has(token)) {
291
+ hasCharAlias = true;
292
+ continue;
293
+ }
294
+ if (COLLECTOR_MODE_ALIASES.has(token)) {
295
+ hasCollectorAlias = true;
296
+ continue;
297
+ }
298
+ return false;
299
+ }
300
+ return hasCharAlias && hasCollectorAlias;
301
+ }
302
+ function isComposedCharCollectorCompact(value) {
303
+ for (const charAlias of CHAR_MODE_ALIASES) for (const collectorAlias of COLLECTOR_MODE_ALIASES) if (value === `${charAlias}${collectorAlias}` || value === `${collectorAlias}${charAlias}`) return true;
304
+ return false;
305
+ }
306
+ function normalizeMode(input) {
307
+ if (!input) return null;
308
+ const normalized = input.trim().toLowerCase();
309
+ const direct = MODE_ALIASES[normalized];
310
+ if (direct) return direct;
311
+ if (isComposedCharCollectorFromTokens(normalized)) return "char-collector";
312
+ const compact = collapseSeparators(normalized);
313
+ if (isComposedCharCollectorCompact(compact)) return "char-collector";
314
+ return MODE_ALIASES[compact] ?? null;
315
+ }
316
+ function resolveMode(input, fallback = "chunk") {
317
+ return normalizeMode(input) ?? fallback;
318
+ }
319
+ const DEFAULT_LATIN_HINT_RULES = Object.freeze([
320
+ {
321
+ tag: "de",
322
+ pattern: "[äöüÄÖÜß]"
323
+ },
324
+ {
325
+ tag: "es",
326
+ pattern: "[ñÑ¿¡]"
327
+ },
328
+ {
329
+ tag: "pt",
330
+ pattern: "[ãõÃÕ]"
331
+ },
332
+ {
333
+ tag: "fr",
334
+ pattern: "[œŒæÆ]"
335
+ },
336
+ {
337
+ tag: "pl",
338
+ pattern: "[ąćęłńśźżĄĆĘŁŃŚŹŻ]"
339
+ },
340
+ {
341
+ tag: "tr",
342
+ pattern: "[ıİğĞşŞ]"
343
+ },
344
+ {
345
+ tag: "ro",
346
+ pattern: "[ăĂâÂîÎșȘțȚ]"
347
+ },
348
+ {
349
+ tag: "hu",
350
+ pattern: "[őŐűŰ]"
351
+ },
352
+ {
353
+ tag: "is",
354
+ pattern: "[ðÐþÞ]"
355
+ }
356
+ ].map((rule) => Object.freeze({ ...rule })));
357
+ //#endregion
358
+ //#region src/wc/locale-detect.ts
359
+ const DEFAULT_LOCALE = "und-Latn";
360
+ const DEFAULT_HAN_TAG = "und-Hani";
361
+ const MAX_LATIN_HINT_PATTERN_LENGTH = 256;
362
+ const regex = {
363
+ hiragana: /\p{Script=Hiragana}/u,
364
+ katakana: /\p{Script=Katakana}/u,
365
+ hangul: /\p{Script=Hangul}/u,
366
+ han: /\p{Script=Han}/u,
367
+ latin: /\p{Script=Latin}/u,
368
+ arabic: /\p{Script=Arabic}/u,
369
+ cyrillic: /\p{Script=Cyrillic}/u,
370
+ devanagari: /\p{Script=Devanagari}/u,
371
+ thai: /\p{Script=Thai}/u
372
+ };
373
+ const defaultLatinLocales = new Set([DEFAULT_LOCALE, ...DEFAULT_LATIN_HINT_RULES.map((hint) => hint.tag)]);
374
+ function isLatinLocale(locale, context) {
375
+ if (context) return context.latinLocales.has(locale);
376
+ return defaultLatinLocales.has(locale);
377
+ }
378
+ function resolveLatinHint(options) {
379
+ const latinTagHint = options.latinTagHint?.trim();
380
+ if (latinTagHint) return latinTagHint;
381
+ const latinLanguageHint = options.latinLanguageHint?.trim();
382
+ if (latinLanguageHint) return latinLanguageHint;
383
+ const latinLocaleHint = options.latinLocaleHint?.trim();
384
+ if (latinLocaleHint) return latinLocaleHint;
385
+ }
386
+ function resolveHanHint(options) {
387
+ const hanTagHint = options.hanTagHint?.trim();
388
+ if (hanTagHint) return hanTagHint;
389
+ const hanLanguageHint = options.hanLanguageHint?.trim();
390
+ if (hanLanguageHint) return hanLanguageHint;
391
+ }
392
+ function compileLatinHintPattern(pattern, label) {
393
+ const source = typeof pattern === "string" ? pattern : pattern.source;
394
+ const hasUnicodeMode = typeof pattern !== "string" && (pattern.flags.includes("u") || pattern.flags.includes("v"));
395
+ const flags = typeof pattern === "string" ? "u" : hasUnicodeMode ? pattern.flags : `${pattern.flags}u`;
396
+ if (source.length === 0) throw new Error(`${label}: pattern must not be empty.`);
397
+ if (source.length > MAX_LATIN_HINT_PATTERN_LENGTH) throw new Error(`${label}: pattern must be at most ${MAX_LATIN_HINT_PATTERN_LENGTH} characters.`);
398
+ try {
399
+ return new RegExp(source, flags);
400
+ } catch (error) {
401
+ const message = error instanceof Error ? error.message : String(error);
402
+ throw new Error(`${label}: invalid Unicode regex pattern (${message}).`);
403
+ }
404
+ }
405
+ function normalizeLatinHintPriority(priority, label) {
406
+ if (priority === void 0) return 0;
407
+ if (typeof priority !== "number" || !Number.isFinite(priority)) throw new Error(`${label}: priority must be a finite number when provided.`);
408
+ return priority;
409
+ }
410
+ function compileLatinHintRule(rule, order, label) {
411
+ const tag = typeof rule.tag === "string" ? rule.tag.trim() : "";
412
+ if (!tag) throw new Error(`${label}: tag must be a non-empty string.`);
413
+ return {
414
+ tag,
415
+ pattern: compileLatinHintPattern(rule.pattern, label),
416
+ priority: normalizeLatinHintPriority(rule.priority, label),
417
+ order
418
+ };
419
+ }
420
+ function resolveLatinHintRules(options) {
421
+ const useDefaultLatinHints = options.useDefaultLatinHints !== false;
422
+ const customRules = options.latinHintRules ?? [];
423
+ const combinedRules = [];
424
+ for (let index = 0; index < customRules.length; index += 1) {
425
+ const rule = customRules[index];
426
+ if (!rule) continue;
427
+ combinedRules.push({
428
+ rule,
429
+ label: `Invalid custom Latin hint rule at index ${index}`
430
+ });
431
+ }
432
+ if (useDefaultLatinHints) for (let index = 0; index < DEFAULT_LATIN_HINT_RULES.length; index += 1) {
433
+ const rule = DEFAULT_LATIN_HINT_RULES[index];
434
+ if (!rule) continue;
435
+ combinedRules.push({
436
+ rule,
437
+ label: `Invalid default Latin hint rule at index ${index}`
438
+ });
439
+ }
440
+ const resolvedRules = combinedRules.map((entry, index) => compileLatinHintRule(entry.rule, index, entry.label));
441
+ resolvedRules.sort((left, right) => {
442
+ if (left.priority !== right.priority) return right.priority - left.priority;
443
+ return left.order - right.order;
444
+ });
445
+ return resolvedRules;
446
+ }
447
+ function resolveLocaleDetectContext(options = {}) {
448
+ const latinHint = resolveLatinHint(options);
449
+ const latinHintRules = resolveLatinHintRules(options);
450
+ const latinLocales = new Set([DEFAULT_LOCALE]);
451
+ for (const rule of latinHintRules) latinLocales.add(rule.tag);
452
+ if (latinHint) latinLocales.add(latinHint);
453
+ return {
454
+ latinHint,
455
+ hanHint: resolveHanHint(options),
456
+ latinHintRules,
457
+ latinLocales
458
+ };
459
+ }
460
+ function detectLatinLocale(char, context) {
461
+ for (const hint of context.latinHintRules) {
462
+ hint.pattern.lastIndex = 0;
463
+ if (hint.pattern.test(char)) return hint.tag;
464
+ }
465
+ return DEFAULT_LOCALE;
466
+ }
467
+ function detectLocaleForChar(char, previousLocale, options = {}, context = resolveLocaleDetectContext(options), allowLatinLocaleCarry = true, allowJapaneseHanCarry = true) {
468
+ if (regex.hiragana.test(char) || regex.katakana.test(char)) return "ja";
469
+ if (regex.hangul.test(char)) return "ko";
470
+ if (regex.arabic.test(char)) return "ar";
471
+ if (regex.cyrillic.test(char)) return "ru";
472
+ if (regex.devanagari.test(char)) return "hi";
473
+ if (regex.thai.test(char)) return "th";
474
+ if (regex.han.test(char)) {
475
+ if (allowJapaneseHanCarry && previousLocale && previousLocale.startsWith("ja")) return previousLocale;
476
+ return context.hanHint ?? "und-Hani";
477
+ }
478
+ if (regex.latin.test(char)) {
479
+ const hintedLocale = detectLatinLocale(char, context);
480
+ if (hintedLocale !== "und-Latn") return hintedLocale;
481
+ if (allowLatinLocaleCarry && previousLocale && isLatinLocale(previousLocale, context) && previousLocale !== "und-Latn") return previousLocale;
482
+ if (context.latinHint) return context.latinHint;
483
+ return DEFAULT_LOCALE;
484
+ }
485
+ return null;
486
+ }
487
+ //#endregion
488
+ //#region src/wc/segment.ts
489
+ const HARD_BOUNDARY_REGEX = /[\r\n,.!?;:,、。!?;:.。、]/u;
490
+ const LATIN_PROMOTION_BREAK_REGEX = /[\s,.!?;:,、。!?;:.。、]/u;
491
+ function segmentTextByLocale(text, options = {}) {
492
+ const context = resolveLocaleDetectContext(options);
493
+ const chunks = [];
494
+ let currentLocale = DEFAULT_LOCALE;
495
+ let buffer = "";
496
+ let bufferHasScript = false;
497
+ let sawCarryBoundary = false;
498
+ const updateCarryBoundaryState = (detected, char) => {
499
+ if (detected !== null) {
500
+ sawCarryBoundary = false;
501
+ return;
502
+ }
503
+ if (HARD_BOUNDARY_REGEX.test(char)) sawCarryBoundary = true;
504
+ };
505
+ for (const char of text) {
506
+ const detected = detectLocaleForChar(char, currentLocale, options, context, !sawCarryBoundary, !sawCarryBoundary);
507
+ const targetLocale = detected ?? currentLocale;
508
+ if (buffer === "") {
509
+ currentLocale = targetLocale;
510
+ buffer = char;
511
+ bufferHasScript = detected !== null;
512
+ updateCarryBoundaryState(detected, char);
513
+ continue;
514
+ }
515
+ if (detected !== null && !bufferHasScript) {
516
+ currentLocale = targetLocale;
517
+ buffer += char;
518
+ bufferHasScript = true;
519
+ updateCarryBoundaryState(detected, char);
520
+ continue;
521
+ }
522
+ if (targetLocale !== currentLocale && detected !== null) {
523
+ if (currentLocale === "und-Latn" && isLatinLocale(targetLocale, context)) {
524
+ const promotionBreakIndex = findLastLatinPromotionBreakIndex(buffer);
525
+ if (promotionBreakIndex === -1) {
526
+ currentLocale = targetLocale;
527
+ buffer += char;
528
+ bufferHasScript = true;
529
+ updateCarryBoundaryState(detected, char);
530
+ continue;
531
+ }
532
+ const prefix = buffer.slice(0, promotionBreakIndex + 1);
533
+ const suffix = buffer.slice(promotionBreakIndex + 1);
534
+ if (prefix.length > 0) chunks.push({
535
+ locale: currentLocale,
536
+ text: prefix
537
+ });
538
+ currentLocale = targetLocale;
539
+ buffer = `${suffix}${char}`;
540
+ bufferHasScript = true;
541
+ updateCarryBoundaryState(detected, char);
542
+ continue;
543
+ }
544
+ chunks.push({
545
+ locale: currentLocale,
546
+ text: buffer
547
+ });
548
+ currentLocale = targetLocale;
549
+ buffer = char;
550
+ bufferHasScript = true;
551
+ updateCarryBoundaryState(detected, char);
552
+ continue;
553
+ }
554
+ buffer += char;
555
+ if (detected !== null) bufferHasScript = true;
556
+ updateCarryBoundaryState(detected, char);
557
+ }
558
+ if (buffer.length > 0) chunks.push({
559
+ locale: currentLocale,
560
+ text: buffer
561
+ });
562
+ return mergeAdjacentChunks(chunks);
563
+ }
564
+ function findLastLatinPromotionBreakIndex(buffer) {
565
+ for (let index = buffer.length - 1; index >= 0; index -= 1) {
566
+ const char = buffer[index];
567
+ if (!char) continue;
568
+ if (LATIN_PROMOTION_BREAK_REGEX.test(char)) return index;
569
+ }
570
+ return -1;
571
+ }
572
+ function mergeAdjacentChunks(chunks) {
573
+ if (chunks.length === 0) return chunks;
574
+ const merged = [];
575
+ let last = chunks[0];
576
+ for (let i = 1; i < chunks.length; i++) {
577
+ const chunk = chunks[i];
578
+ if (chunk.locale === last.locale) last = {
579
+ locale: last.locale,
580
+ text: last.text + chunk.text
581
+ };
582
+ else {
583
+ merged.push(last);
584
+ last = chunk;
585
+ }
586
+ }
587
+ merged.push(last);
588
+ return merged;
589
+ }
590
+ //#endregion
591
+ //#region src/wc/wc.ts
592
+ function wordCounter(text, options = {}) {
593
+ const mode = resolveMode(options.mode, "chunk");
594
+ const collectNonWords = Boolean(options.nonWords);
595
+ const includeWhitespace = Boolean(options.includeWhitespace);
596
+ const chunks = segmentTextByLocale(text, {
597
+ latinLanguageHint: options.latinLanguageHint,
598
+ latinTagHint: options.latinTagHint,
599
+ latinLocaleHint: options.latinLocaleHint,
600
+ latinHintRules: options.latinHintRules,
601
+ useDefaultLatinHints: options.useDefaultLatinHints,
602
+ hanLanguageHint: options.hanLanguageHint,
603
+ hanTagHint: options.hanTagHint
604
+ });
605
+ if (mode === "char" || mode === "char-collector") {
606
+ const analyzed = chunks.map((chunk) => analyzeCharChunk(chunk, collectNonWords, includeWhitespace));
607
+ const total = analyzed.reduce((sum, chunk) => sum + chunk.chars, 0);
608
+ const counts = collectNonWords ? {
609
+ words: analyzed.reduce((sum, chunk) => sum + chunk.wordChars, 0),
610
+ nonWords: analyzed.reduce((sum, chunk) => sum + chunk.nonWordChars, 0),
611
+ total
612
+ } : void 0;
613
+ if (mode === "char") return {
614
+ total,
615
+ counts,
616
+ breakdown: {
617
+ mode,
618
+ items: analyzed.map((chunk) => ({
619
+ locale: chunk.locale,
620
+ text: chunk.text,
621
+ chars: chunk.chars,
622
+ nonWords: chunk.nonWords
623
+ }))
624
+ }
625
+ };
626
+ return {
627
+ total,
628
+ counts,
629
+ breakdown: {
630
+ mode,
631
+ items: aggregateCharsByLocale(analyzed).map((chunk) => ({
632
+ locale: chunk.locale,
633
+ chars: chunk.chars,
634
+ nonWords: chunk.nonWords
635
+ }))
636
+ }
637
+ };
638
+ }
639
+ const analyzed = chunks.map((chunk) => analyzeChunk(chunk, collectNonWords, includeWhitespace));
640
+ const wordsTotal = analyzed.reduce((sum, chunk) => sum + chunk.words, 0);
641
+ const nonWordsTotal = collectNonWords ? analyzed.reduce((sum, chunk) => {
642
+ if (!chunk.nonWords) return sum;
643
+ return sum + getNonWordTotal(chunk.nonWords);
644
+ }, 0) : 0;
645
+ const total = analyzed.reduce((sum, chunk) => {
646
+ let chunkTotal = chunk.words;
647
+ if (collectNonWords && chunk.nonWords) chunkTotal += getNonWordTotal(chunk.nonWords);
648
+ return sum + chunkTotal;
649
+ }, 0);
650
+ const counts = collectNonWords ? {
651
+ words: wordsTotal,
652
+ nonWords: nonWordsTotal,
653
+ total
654
+ } : void 0;
655
+ if (mode === "segments") return {
656
+ total,
657
+ counts,
658
+ breakdown: {
659
+ mode,
660
+ items: analyzed.map((chunk) => ({
661
+ locale: chunk.locale,
662
+ text: chunk.text,
663
+ words: chunk.words,
664
+ segments: chunk.segments,
665
+ nonWords: chunk.nonWords
666
+ }))
667
+ }
668
+ };
669
+ if (mode === "collector") return {
670
+ total,
671
+ counts,
672
+ breakdown: {
673
+ mode,
674
+ items: aggregateByLocale(analyzed),
675
+ nonWords: collectNonWordsAggregate(analyzed, collectNonWords)
676
+ }
677
+ };
678
+ return {
679
+ total,
680
+ counts,
681
+ breakdown: {
682
+ mode,
683
+ items: analyzed.map((chunk) => ({
684
+ locale: chunk.locale,
685
+ text: chunk.text,
686
+ words: chunk.words,
687
+ nonWords: chunk.nonWords
688
+ }))
689
+ }
690
+ };
691
+ }
692
+ function getNonWordTotal(nonWords) {
693
+ return nonWords.counts.emoji + nonWords.counts.symbols + nonWords.counts.punctuation + (nonWords.counts.whitespace ?? 0);
694
+ }
695
+ function collectNonWordsAggregate(analyzed, enabled) {
696
+ if (!enabled) return;
697
+ const collection = createNonWordCollection();
698
+ for (const chunk of analyzed) {
699
+ if (!chunk.nonWords) continue;
700
+ mergeNonWordCollections(collection, chunk.nonWords);
701
+ }
702
+ return collection;
703
+ }
704
+ //#endregion
705
+ //#region src/wc/index.ts
706
+ var wc_default = wordCounter;
707
+ //#endregion
708
+ //#region src/markdown/toml/arrays.ts
709
+ function ensureArrayContainer(result, key) {
710
+ const existing = result[key];
711
+ if (Array.isArray(existing)) return existing;
712
+ const list = [];
713
+ result[key] = list;
714
+ return list;
715
+ }
716
+ function flattenArrayTables(result) {
717
+ for (const [key, value] of Object.entries(result)) {
718
+ if (!Array.isArray(value)) continue;
719
+ result[key] = value.map((entry) => Object.entries(entry).map(([entryKey, entryValue]) => `${entryKey}=${entryValue}`).join(", ")).join(" | ");
720
+ }
721
+ }
722
+ //#endregion
723
+ //#region src/markdown/toml/keys.ts
724
+ function stripKeyQuotes(key) {
725
+ const trimmed = key.trim();
726
+ if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1);
727
+ return trimmed;
728
+ }
729
+ function normalizeKeyPath(key) {
730
+ const trimmed = key.trim();
731
+ if (!trimmed) return null;
732
+ if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) {
733
+ const unquoted = stripKeyQuotes(trimmed);
734
+ return unquoted ? unquoted : null;
735
+ }
736
+ const segments = trimmed.split(".").map((segment) => segment.trim());
737
+ if (segments.some((segment) => !segment)) return null;
738
+ return segments.join(".");
739
+ }
740
+ //#endregion
741
+ //#region src/markdown/toml/strings.ts
742
+ function stripInlineComment(line) {
743
+ let inString = null;
744
+ let escaped = false;
745
+ for (let i = 0; i < line.length; i += 1) {
746
+ const char = line[i] ?? "";
747
+ if (inString) {
748
+ if (escaped) {
749
+ escaped = false;
750
+ continue;
751
+ }
752
+ if (char === "\\" && inString === "double") {
753
+ escaped = true;
754
+ continue;
755
+ }
756
+ if (inString === "double" && char === "\"") {
757
+ inString = null;
758
+ continue;
759
+ }
760
+ if (inString === "single" && char === "'") {
761
+ inString = null;
762
+ continue;
763
+ }
764
+ continue;
765
+ }
766
+ if (char === "\"") {
767
+ inString = "double";
768
+ continue;
769
+ }
770
+ if (char === "'") {
771
+ inString = "single";
772
+ continue;
773
+ }
774
+ if (char === "#") return line.slice(0, i).trimEnd();
775
+ }
776
+ return line;
777
+ }
778
+ function unescapeBasic(input) {
779
+ return input.replace(/\\\\/g, "\\").replace(/\\"/g, "\"").replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\r/g, "\r");
780
+ }
781
+ function parseStringLiteral(value) {
782
+ if (value.startsWith("\"\"\"") && value.endsWith("\"\"\"")) return unescapeBasic(value.slice(3, -3));
783
+ if (value.startsWith("'''") && value.endsWith("'''")) return value.slice(3, -3);
784
+ if (value.startsWith("\"") && value.endsWith("\"")) return unescapeBasic(value.slice(1, -1));
785
+ if (value.startsWith("'") && value.endsWith("'")) return value.slice(1, -1);
786
+ return null;
787
+ }
788
+ //#endregion
789
+ //#region src/markdown/toml/values.ts
790
+ function parsePrimitive(raw) {
791
+ const value = raw.trim();
792
+ if (!value) return null;
793
+ const stringLiteral = parseStringLiteral(value);
794
+ if (stringLiteral !== null) return stringLiteral;
795
+ if (value === "true") return true;
796
+ if (value === "false") return false;
797
+ if (/^[+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(value)) return Number(value);
798
+ if (/^\d{4}-\d{2}-\d{2}/.test(value)) return value;
799
+ return value;
800
+ }
801
+ function parseArray(raw) {
802
+ const value = raw.trim();
803
+ if (!value.startsWith("[") || !value.endsWith("]")) return null;
804
+ const inner = value.slice(1, -1).trim();
805
+ if (!inner) return [];
806
+ const items = [];
807
+ let current = "";
808
+ let inString = null;
809
+ let escaped = false;
810
+ for (let i = 0; i < inner.length; i += 1) {
811
+ const char = inner[i] ?? "";
812
+ if (inString) {
813
+ current += char;
814
+ if (escaped) {
815
+ escaped = false;
816
+ continue;
817
+ }
818
+ if (char === "\\" && inString === "double") {
819
+ escaped = true;
820
+ continue;
821
+ }
822
+ if (inString === "double" && char === "\"") inString = null;
823
+ else if (inString === "single" && char === "'") inString = null;
824
+ continue;
825
+ }
826
+ if (char === "\"") {
827
+ inString = "double";
828
+ current += char;
829
+ continue;
830
+ }
831
+ if (char === "'") {
832
+ inString = "single";
833
+ current += char;
834
+ continue;
835
+ }
836
+ if (char === ",") {
837
+ const item = parsePrimitive(current);
838
+ if (item === null) return null;
839
+ items.push(item);
840
+ current = "";
841
+ continue;
842
+ }
843
+ current += char;
844
+ }
845
+ const finalItem = parsePrimitive(current);
846
+ if (finalItem === null) return null;
847
+ items.push(finalItem);
848
+ return items;
849
+ }
850
+ function parseInlineTable(raw) {
851
+ const trimmed = raw.trim();
852
+ if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return null;
853
+ const inner = trimmed.slice(1, -1).trim();
854
+ if (!inner) return {};
855
+ const pairs = [];
856
+ let current = "";
857
+ let inString = null;
858
+ let escaped = false;
859
+ let bracketDepth = 0;
860
+ let braceDepth = 0;
861
+ for (let i = 0; i < inner.length; i += 1) {
862
+ const char = inner[i] ?? "";
863
+ if (inString) {
864
+ current += char;
865
+ if (escaped) {
866
+ escaped = false;
867
+ continue;
868
+ }
869
+ if (char === "\\" && inString === "double") {
870
+ escaped = true;
871
+ continue;
872
+ }
873
+ if (inString === "double" && char === "\"") inString = null;
874
+ else if (inString === "single" && char === "'") inString = null;
875
+ continue;
876
+ }
877
+ if (char === "\"") {
878
+ inString = "double";
879
+ current += char;
880
+ continue;
881
+ }
882
+ if (char === "'") {
883
+ inString = "single";
884
+ current += char;
885
+ continue;
886
+ }
887
+ if (char === "[") {
888
+ bracketDepth += 1;
889
+ current += char;
890
+ continue;
891
+ }
892
+ if (char === "]") {
893
+ if (bracketDepth > 0) bracketDepth -= 1;
894
+ current += char;
895
+ continue;
896
+ }
897
+ if (char === "{") {
898
+ braceDepth += 1;
899
+ current += char;
900
+ continue;
901
+ }
902
+ if (char === "}") {
903
+ if (braceDepth > 0) braceDepth -= 1;
904
+ current += char;
905
+ continue;
906
+ }
907
+ if (char === "," && bracketDepth === 0 && braceDepth === 0) {
908
+ pairs.push(current);
909
+ current = "";
910
+ continue;
911
+ }
912
+ current += char;
913
+ }
914
+ if (current.trim()) pairs.push(current);
915
+ const output = {};
916
+ for (const pair of pairs) {
917
+ const separatorIndex = pair.indexOf("=");
918
+ if (separatorIndex === -1) return null;
919
+ const key = normalizeKeyPath(pair.slice(0, separatorIndex));
920
+ if (!key) return null;
921
+ const valueRaw = pair.slice(separatorIndex + 1).trim();
922
+ if (!valueRaw) return null;
923
+ if (valueRaw.startsWith("{")) return null;
924
+ const normalized = normalizeValue(valueRaw);
925
+ if (normalized === null) return null;
926
+ if (typeof normalized === "object" && !Array.isArray(normalized)) return null;
927
+ output[key] = normalized;
928
+ }
929
+ return output;
930
+ }
931
+ function normalizeValue(value) {
932
+ if (!value) return null;
933
+ const trimmed = value.trim();
934
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) return parseInlineTable(trimmed);
935
+ const array = parseArray(trimmed);
936
+ if (array) return array;
937
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) return null;
938
+ return parsePrimitive(trimmed);
939
+ }
940
+ function toPlainText(value) {
941
+ if (value == null) return "";
942
+ if (Array.isArray(value)) return value.map((item) => String(item)).join(", ");
943
+ return String(value);
944
+ }
945
+ //#endregion
946
+ //#region src/markdown/toml/parse-frontmatter.ts
947
+ function parseTomlFrontmatter(frontmatter) {
948
+ const result = {};
949
+ const lines = frontmatter.split("\n");
950
+ let tablePrefix = "";
951
+ let tableTarget = null;
952
+ let tablePrefixInList = false;
953
+ for (let index = 0; index < lines.length; index += 1) {
954
+ const rawLine = lines[index] ?? "";
955
+ const trimmedLine = rawLine.trim();
956
+ if (!trimmedLine || trimmedLine.startsWith("#")) continue;
957
+ if (trimmedLine.startsWith("[[")) {
958
+ const match = trimmedLine.match(/^\[\[([^\]]+)]]$/);
959
+ if (!match) return null;
960
+ const normalizedTable = normalizeKeyPath(match[1] ?? "");
961
+ if (!normalizedTable) return null;
962
+ const list = ensureArrayContainer(result, normalizedTable);
963
+ const newEntry = {};
964
+ list.push(newEntry);
965
+ tableTarget = newEntry;
966
+ tablePrefix = normalizedTable;
967
+ tablePrefixInList = true;
968
+ continue;
969
+ }
970
+ const tableMatch = trimmedLine.match(/^\[([^\]]+)]$/);
971
+ if (tableMatch) {
972
+ const normalizedTable = normalizeKeyPath(tableMatch[1] ?? "");
973
+ if (!normalizedTable) return null;
974
+ tablePrefix = normalizedTable;
975
+ tablePrefixInList = false;
976
+ tableTarget = null;
977
+ continue;
978
+ }
979
+ const lineForParsing = /("""|''')/.test(rawLine) ? rawLine : stripInlineComment(rawLine);
980
+ const separatorIndex = lineForParsing.indexOf("=");
981
+ if (separatorIndex === -1) return null;
982
+ const key = normalizeKeyPath(lineForParsing.slice(0, separatorIndex));
983
+ let valueRaw = lineForParsing.slice(separatorIndex + 1).trim();
984
+ if (!key) return null;
985
+ const tripleDelimiter = valueRaw.startsWith("\"\"\"") ? "\"\"\"" : valueRaw.startsWith("'''") ? "'''" : null;
986
+ if (tripleDelimiter) {
987
+ const closingIndex = valueRaw.indexOf(tripleDelimiter, tripleDelimiter.length);
988
+ if (closingIndex !== -1) {
989
+ const strippedAfter = stripInlineComment(valueRaw.slice(closingIndex + tripleDelimiter.length));
990
+ valueRaw = `${valueRaw.slice(0, closingIndex + tripleDelimiter.length)}${strippedAfter}`;
991
+ } else {
992
+ const delimiter = tripleDelimiter;
993
+ let combined = valueRaw;
994
+ let closed = false;
995
+ while (index + 1 < lines.length) {
996
+ index += 1;
997
+ const nextLine = lines[index] ?? "";
998
+ combined += `\n${nextLine}`;
999
+ if (new RegExp(`${delimiter}\\s*$`).test(nextLine)) {
1000
+ closed = true;
1001
+ break;
1002
+ }
1003
+ }
1004
+ if (!closed) return null;
1005
+ valueRaw = combined;
1006
+ }
1007
+ }
1008
+ const normalized = normalizeValue(valueRaw);
1009
+ if (normalized === null) return null;
1010
+ const fullKey = tablePrefix ? `${tablePrefix}.${key}` : key;
1011
+ if (typeof normalized === "object" && !Array.isArray(normalized)) {
1012
+ for (const [inlineKey, inlineValue] of Object.entries(normalized)) {
1013
+ const entryKey = tablePrefixInList ? `${key}.${inlineKey}` : `${fullKey}.${inlineKey}`;
1014
+ if (tablePrefixInList && tableTarget) tableTarget[entryKey] = toPlainText(inlineValue);
1015
+ else result[entryKey] = toPlainText(inlineValue);
1016
+ }
1017
+ continue;
1018
+ }
1019
+ if (tablePrefixInList && tableTarget) {
1020
+ tableTarget[key] = toPlainText(normalized);
1021
+ continue;
1022
+ }
1023
+ result[fullKey] = toPlainText(normalized);
1024
+ }
1025
+ flattenArrayTables(result);
1026
+ return result;
1027
+ }
1028
+ //#endregion
1029
+ //#region src/markdown/parse-markdown.ts
1030
+ const FENCE_TO_TYPE = {
1031
+ "---": "yaml",
1032
+ "+++": "toml",
1033
+ ";;;": "json"
1034
+ };
1035
+ function normalizeNewlines(input) {
1036
+ return input.replace(/\r\n/g, "\n");
1037
+ }
1038
+ function stripBom(line) {
1039
+ return line.startsWith("") ? line.slice(1) : line;
1040
+ }
1041
+ function getFenceType(line) {
1042
+ const match = line.match(/^[\t ]*(---|\+\+\+|;;;)[\t ]*$/);
1043
+ if (!match) return null;
1044
+ return FENCE_TO_TYPE[match[1] ?? ""] ?? null;
1045
+ }
1046
+ function parseFrontmatter(frontmatter, type) {
1047
+ if (!type) return null;
1048
+ if (type === "json") try {
1049
+ return JSON.parse(frontmatter);
1050
+ } catch {
1051
+ return null;
1052
+ }
1053
+ if (type === "yaml") {
1054
+ const doc = (0, yaml.parseDocument)(frontmatter, { prettyErrors: false });
1055
+ if (doc.errors.length > 0) return null;
1056
+ const data = doc.toJSON();
1057
+ if (!data || typeof data !== "object" || Array.isArray(data)) return null;
1058
+ return data;
1059
+ }
1060
+ if (type === "toml") return parseTomlFrontmatter(frontmatter);
1061
+ return null;
1062
+ }
1063
+ function extractJsonBlock(text, startIndex) {
1064
+ let depth = 0;
1065
+ let inString = false;
1066
+ let escaped = false;
1067
+ for (let i = startIndex; i < text.length; i += 1) {
1068
+ const char = text[i] ?? "";
1069
+ if (inString) {
1070
+ if (escaped) {
1071
+ escaped = false;
1072
+ continue;
1073
+ }
1074
+ if (char === "\\") {
1075
+ escaped = true;
1076
+ continue;
1077
+ }
1078
+ if (char === "\"") inString = false;
1079
+ continue;
1080
+ }
1081
+ if (char === "\"") {
1082
+ inString = true;
1083
+ continue;
1084
+ }
1085
+ if (char === "{") {
1086
+ depth += 1;
1087
+ continue;
1088
+ }
1089
+ if (char === "}") {
1090
+ depth -= 1;
1091
+ if (depth === 0) return {
1092
+ jsonText: text.slice(startIndex, i + 1),
1093
+ endIndex: i
1094
+ };
1095
+ }
1096
+ }
1097
+ return null;
1098
+ }
1099
+ function parseMarkdown(input) {
1100
+ const normalized = normalizeNewlines(input);
1101
+ const lines = normalized.split("\n");
1102
+ if (lines.length === 0) return {
1103
+ frontmatter: null,
1104
+ content: normalized,
1105
+ data: null,
1106
+ frontmatterType: null
1107
+ };
1108
+ lines[0] = stripBom(lines[0] ?? "");
1109
+ const normalizedWithoutBom = lines.join("\n");
1110
+ const openingType = getFenceType(lines[0] ?? "");
1111
+ if (!openingType) {
1112
+ const jsonStart = (normalizedWithoutBom.match(/^[\t \n]*/)?.[0] ?? "").length;
1113
+ if (normalizedWithoutBom[jsonStart] !== "{") return {
1114
+ frontmatter: null,
1115
+ content: normalizedWithoutBom,
1116
+ data: null,
1117
+ frontmatterType: null
1118
+ };
1119
+ const jsonBlock = extractJsonBlock(normalizedWithoutBom, jsonStart);
1120
+ if (!jsonBlock) return {
1121
+ frontmatter: null,
1122
+ content: normalizedWithoutBom,
1123
+ data: null,
1124
+ frontmatterType: null
1125
+ };
1126
+ const frontmatter = jsonBlock.jsonText;
1127
+ let content = normalizedWithoutBom.slice(jsonBlock.endIndex + 1);
1128
+ if (content.startsWith("\n")) content = content.slice(1);
1129
+ const data = parseFrontmatter(frontmatter, "json");
1130
+ if (!data) return {
1131
+ frontmatter: null,
1132
+ content: normalizedWithoutBom,
1133
+ data: null,
1134
+ frontmatterType: null
1135
+ };
1136
+ return {
1137
+ frontmatter,
1138
+ content,
1139
+ data,
1140
+ frontmatterType: "json"
1141
+ };
1142
+ }
1143
+ let closingIndex = -1;
1144
+ for (let i = 1; i < lines.length; i += 1) if (getFenceType(lines[i] ?? "") === openingType) {
1145
+ closingIndex = i;
1146
+ break;
1147
+ }
1148
+ if (closingIndex === -1) return {
1149
+ frontmatter: null,
1150
+ content: normalizedWithoutBom,
1151
+ data: null,
1152
+ frontmatterType: null
1153
+ };
1154
+ const frontmatter = lines.slice(1, closingIndex).join("\n");
1155
+ return {
1156
+ frontmatter,
1157
+ content: lines.slice(closingIndex + 1).join("\n"),
1158
+ data: parseFrontmatter(frontmatter, openingType),
1159
+ frontmatterType: openingType
1160
+ };
1161
+ }
1162
+ //#endregion
1163
+ //#region src/markdown/section-count.ts
1164
+ function normalizeText(value) {
1165
+ if (value == null) return "";
1166
+ if (typeof value === "string") return value;
1167
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
1168
+ try {
1169
+ return JSON.stringify(value);
1170
+ } catch {
1171
+ return String(value);
1172
+ }
1173
+ }
1174
+ function buildPerKeyItems(data, mode, options) {
1175
+ if (!data || typeof data !== "object" || Array.isArray(data)) return [];
1176
+ return Object.entries(data).map(([key, value]) => {
1177
+ const valueText = normalizeText(value);
1178
+ return {
1179
+ name: key,
1180
+ source: "frontmatter",
1181
+ result: wc_default(valueText ? `${key}: ${valueText}` : key, options)
1182
+ };
1183
+ });
1184
+ }
1185
+ function buildSingleItem(name, text, mode, options, source) {
1186
+ return [{
1187
+ name,
1188
+ source,
1189
+ result: wc_default(text, options)
1190
+ }];
1191
+ }
1192
+ function sumTotals(items) {
1193
+ return items.reduce((sum, item) => sum + item.result.total, 0);
1194
+ }
1195
+ function countSections(input, section, options = {}) {
1196
+ const mode = options.mode ?? "chunk";
1197
+ if (section === "all") {
1198
+ const result = wc_default(input, options);
1199
+ return {
1200
+ section,
1201
+ total: result.total,
1202
+ frontmatterType: null,
1203
+ items: [{
1204
+ name: "all",
1205
+ source: "content",
1206
+ result
1207
+ }]
1208
+ };
1209
+ }
1210
+ const parsed = parseMarkdown(input);
1211
+ const frontmatterText = parsed.frontmatter ?? "";
1212
+ const contentText = parsed.content ?? "";
1213
+ let items = [];
1214
+ if (section === "frontmatter") items = buildSingleItem("frontmatter", frontmatterText, mode, options, "frontmatter");
1215
+ else if (section === "content") items = buildSingleItem("content", contentText, mode, options, "content");
1216
+ else if (section === "split") items = [...buildSingleItem("frontmatter", frontmatterText, mode, options, "frontmatter"), ...buildSingleItem("content", contentText, mode, options, "content")];
1217
+ else if (section === "per-key") items = buildPerKeyItems(parsed.data, mode, options);
1218
+ else if (section === "split-per-key") items = [...buildPerKeyItems(parsed.data, mode, options), ...buildSingleItem("content", contentText, mode, options, "content")];
1219
+ return {
1220
+ section,
1221
+ total: sumTotals(items),
1222
+ frontmatterType: parsed.frontmatterType,
1223
+ items
1224
+ };
1225
+ }
1226
+ //#endregion
1227
+ Object.defineProperty(exports, "DEFAULT_HAN_TAG", {
1228
+ enumerable: true,
1229
+ get: function() {
1230
+ return DEFAULT_HAN_TAG;
1231
+ }
1232
+ });
1233
+ Object.defineProperty(exports, "DEFAULT_LOCALE", {
1234
+ enumerable: true,
1235
+ get: function() {
1236
+ return DEFAULT_LOCALE;
1237
+ }
1238
+ });
1239
+ Object.defineProperty(exports, "aggregateByLocale", {
1240
+ enumerable: true,
1241
+ get: function() {
1242
+ return aggregateByLocale;
1243
+ }
1244
+ });
1245
+ Object.defineProperty(exports, "aggregateCharsByLocale", {
1246
+ enumerable: true,
1247
+ get: function() {
1248
+ return aggregateCharsByLocale;
1249
+ }
1250
+ });
1251
+ Object.defineProperty(exports, "analyzeCharChunk", {
1252
+ enumerable: true,
1253
+ get: function() {
1254
+ return analyzeCharChunk;
1255
+ }
1256
+ });
1257
+ Object.defineProperty(exports, "analyzeChunk", {
1258
+ enumerable: true,
1259
+ get: function() {
1260
+ return analyzeChunk;
1261
+ }
1262
+ });
1263
+ Object.defineProperty(exports, "countCharsForLocale", {
1264
+ enumerable: true,
1265
+ get: function() {
1266
+ return countCharsForLocale;
1267
+ }
1268
+ });
1269
+ Object.defineProperty(exports, "countSections", {
1270
+ enumerable: true,
1271
+ get: function() {
1272
+ return countSections;
1273
+ }
1274
+ });
1275
+ Object.defineProperty(exports, "countWordsForLocale", {
1276
+ enumerable: true,
1277
+ get: function() {
1278
+ return countWordsForLocale;
1279
+ }
1280
+ });
1281
+ Object.defineProperty(exports, "createNonWordCollection", {
1282
+ enumerable: true,
1283
+ get: function() {
1284
+ return createNonWordCollection;
1285
+ }
1286
+ });
1287
+ Object.defineProperty(exports, "mergeNonWordCollections", {
1288
+ enumerable: true,
1289
+ get: function() {
1290
+ return mergeNonWordCollections;
1291
+ }
1292
+ });
1293
+ Object.defineProperty(exports, "parseMarkdown", {
1294
+ enumerable: true,
1295
+ get: function() {
1296
+ return parseMarkdown;
1297
+ }
1298
+ });
1299
+ Object.defineProperty(exports, "resolveMode", {
1300
+ enumerable: true,
1301
+ get: function() {
1302
+ return resolveMode;
1303
+ }
1304
+ });
1305
+ Object.defineProperty(exports, "segmentTextByLocale", {
1306
+ enumerable: true,
1307
+ get: function() {
1308
+ return segmentTextByLocale;
1309
+ }
1310
+ });
1311
+ Object.defineProperty(exports, "wc_default", {
1312
+ enumerable: true,
1313
+ get: function() {
1314
+ return wc_default;
1315
+ }
1316
+ });
1317
+
1318
+ //# sourceMappingURL=markdown.cjs.map