@dev-pi2pie/word-counter 0.0.6

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,754 @@
1
+ let yaml = require("yaml");
2
+
3
+ //#region src/wc/segmenter.ts
4
+ const segmenterCache = /* @__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 countWordsForLocale(text, locale) {
13
+ const segmenter = getSegmenter(locale);
14
+ let count = 0;
15
+ for (const segment of segmenter.segment(text)) if (segment.isWordLike) count++;
16
+ return count;
17
+ }
18
+
19
+ //#endregion
20
+ //#region src/wc/analyze.ts
21
+ function analyzeChunk(chunk) {
22
+ const segmenter = getSegmenter(chunk.locale);
23
+ const segments = [];
24
+ for (const part of segmenter.segment(chunk.text)) if (part.isWordLike) segments.push(part.segment);
25
+ return {
26
+ locale: chunk.locale,
27
+ text: chunk.text,
28
+ segments,
29
+ words: segments.length
30
+ };
31
+ }
32
+ function aggregateByLocale(chunks) {
33
+ const order = [];
34
+ const map = /* @__PURE__ */ new Map();
35
+ for (const chunk of chunks) {
36
+ const existing = map.get(chunk.locale);
37
+ if (existing) {
38
+ existing.words += chunk.words;
39
+ existing.segments.push(...chunk.segments);
40
+ continue;
41
+ }
42
+ order.push(chunk.locale);
43
+ map.set(chunk.locale, {
44
+ locale: chunk.locale,
45
+ words: chunk.words,
46
+ segments: [...chunk.segments]
47
+ });
48
+ }
49
+ return order.map((locale) => map.get(locale));
50
+ }
51
+
52
+ //#endregion
53
+ //#region src/wc/locale-detect.ts
54
+ const DEFAULT_LOCALE = "und-Latn";
55
+ const regex = {
56
+ hiragana: /\p{Script=Hiragana}/u,
57
+ katakana: /\p{Script=Katakana}/u,
58
+ hangul: /\p{Script=Hangul}/u,
59
+ han: /\p{Script=Han}/u,
60
+ latin: /\p{Script=Latin}/u,
61
+ arabic: /\p{Script=Arabic}/u,
62
+ cyrillic: /\p{Script=Cyrillic}/u,
63
+ devanagari: /\p{Script=Devanagari}/u,
64
+ thai: /\p{Script=Thai}/u
65
+ };
66
+ const latinLocaleHints = [
67
+ {
68
+ locale: "de",
69
+ regex: /[äöüÄÖÜß]/
70
+ },
71
+ {
72
+ locale: "es",
73
+ regex: /[ñÑ¿¡]/
74
+ },
75
+ {
76
+ locale: "pt",
77
+ regex: /[ãõÃÕ]/
78
+ },
79
+ {
80
+ locale: "fr",
81
+ regex: /[œŒæÆ]/
82
+ }
83
+ ];
84
+ const latinLocales = new Set([DEFAULT_LOCALE, ...latinLocaleHints.map((hint) => hint.locale)]);
85
+ function isLatinLocale(locale) {
86
+ return latinLocales.has(locale);
87
+ }
88
+ function detectLatinLocale(char) {
89
+ for (const hint of latinLocaleHints) if (hint.regex.test(char)) return hint.locale;
90
+ return DEFAULT_LOCALE;
91
+ }
92
+ function detectLocaleForChar(char, previousLocale) {
93
+ if (regex.hiragana.test(char) || regex.katakana.test(char)) return "ja";
94
+ if (regex.hangul.test(char)) return "ko";
95
+ if (regex.arabic.test(char)) return "ar";
96
+ if (regex.cyrillic.test(char)) return "ru";
97
+ if (regex.devanagari.test(char)) return "hi";
98
+ if (regex.thai.test(char)) return "th";
99
+ if (regex.han.test(char)) {
100
+ if (previousLocale && previousLocale.startsWith("ja")) return previousLocale;
101
+ return "zh-Hans";
102
+ }
103
+ if (regex.latin.test(char)) {
104
+ const hintedLocale = detectLatinLocale(char);
105
+ if (hintedLocale !== DEFAULT_LOCALE) return hintedLocale;
106
+ if (previousLocale && isLatinLocale(previousLocale)) return previousLocale;
107
+ return DEFAULT_LOCALE;
108
+ }
109
+ return null;
110
+ }
111
+
112
+ //#endregion
113
+ //#region src/wc/segment.ts
114
+ function segmentTextByLocale(text) {
115
+ const chunks = [];
116
+ let currentLocale = DEFAULT_LOCALE;
117
+ let buffer = "";
118
+ for (const char of text) {
119
+ const detected = detectLocaleForChar(char, currentLocale);
120
+ const targetLocale = detected ?? currentLocale;
121
+ if (buffer === "") {
122
+ currentLocale = targetLocale;
123
+ buffer = char;
124
+ continue;
125
+ }
126
+ if (targetLocale !== currentLocale && detected !== null) {
127
+ if (currentLocale === DEFAULT_LOCALE && isLatinLocale(targetLocale)) {
128
+ currentLocale = targetLocale;
129
+ buffer += char;
130
+ continue;
131
+ }
132
+ chunks.push({
133
+ locale: currentLocale,
134
+ text: buffer
135
+ });
136
+ currentLocale = targetLocale;
137
+ buffer = char;
138
+ continue;
139
+ }
140
+ buffer += char;
141
+ }
142
+ if (buffer.length > 0) chunks.push({
143
+ locale: currentLocale,
144
+ text: buffer
145
+ });
146
+ return mergeAdjacentChunks(chunks);
147
+ }
148
+ function mergeAdjacentChunks(chunks) {
149
+ if (chunks.length === 0) return chunks;
150
+ const merged = [];
151
+ let last = chunks[0];
152
+ for (let i = 1; i < chunks.length; i++) {
153
+ const chunk = chunks[i];
154
+ if (chunk.locale === last.locale) last = {
155
+ locale: last.locale,
156
+ text: last.text + chunk.text
157
+ };
158
+ else {
159
+ merged.push(last);
160
+ last = chunk;
161
+ }
162
+ }
163
+ merged.push(last);
164
+ return merged;
165
+ }
166
+
167
+ //#endregion
168
+ //#region src/wc/wc.ts
169
+ function wordCounter(text, options = {}) {
170
+ const mode = options.mode ?? "chunk";
171
+ const analyzed = segmentTextByLocale(text).map(analyzeChunk);
172
+ const total = analyzed.reduce((sum, chunk) => sum + chunk.words, 0);
173
+ if (mode === "segments") return {
174
+ total,
175
+ breakdown: {
176
+ mode,
177
+ items: analyzed.map((chunk) => ({
178
+ locale: chunk.locale,
179
+ text: chunk.text,
180
+ words: chunk.words,
181
+ segments: chunk.segments
182
+ }))
183
+ }
184
+ };
185
+ if (mode === "collector") return {
186
+ total,
187
+ breakdown: {
188
+ mode,
189
+ items: aggregateByLocale(analyzed)
190
+ }
191
+ };
192
+ return {
193
+ total,
194
+ breakdown: {
195
+ mode,
196
+ items: analyzed.map((chunk) => ({
197
+ locale: chunk.locale,
198
+ text: chunk.text,
199
+ words: chunk.words
200
+ }))
201
+ }
202
+ };
203
+ }
204
+
205
+ //#endregion
206
+ //#region src/wc/index.ts
207
+ var wc_default = wordCounter;
208
+
209
+ //#endregion
210
+ //#region src/markdown/toml/arrays.ts
211
+ function ensureArrayContainer(result, key) {
212
+ const existing = result[key];
213
+ if (Array.isArray(existing)) return existing;
214
+ const list = [];
215
+ result[key] = list;
216
+ return list;
217
+ }
218
+ function flattenArrayTables(result) {
219
+ for (const [key, value] of Object.entries(result)) {
220
+ if (!Array.isArray(value)) continue;
221
+ result[key] = value.map((entry) => Object.entries(entry).map(([entryKey, entryValue]) => `${entryKey}=${entryValue}`).join(", ")).join(" | ");
222
+ }
223
+ }
224
+
225
+ //#endregion
226
+ //#region src/markdown/toml/keys.ts
227
+ function stripKeyQuotes(key) {
228
+ const trimmed = key.trim();
229
+ if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1);
230
+ return trimmed;
231
+ }
232
+ function normalizeKeyPath(key) {
233
+ const trimmed = key.trim();
234
+ if (!trimmed) return null;
235
+ if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) {
236
+ const unquoted = stripKeyQuotes(trimmed);
237
+ return unquoted ? unquoted : null;
238
+ }
239
+ const segments = trimmed.split(".").map((segment) => segment.trim());
240
+ if (segments.some((segment) => !segment)) return null;
241
+ return segments.join(".");
242
+ }
243
+
244
+ //#endregion
245
+ //#region src/markdown/toml/strings.ts
246
+ function stripInlineComment(line) {
247
+ let inString = null;
248
+ let escaped = false;
249
+ for (let i = 0; i < line.length; i += 1) {
250
+ const char = line[i] ?? "";
251
+ if (inString) {
252
+ if (escaped) {
253
+ escaped = false;
254
+ continue;
255
+ }
256
+ if (char === "\\" && inString === "double") {
257
+ escaped = true;
258
+ continue;
259
+ }
260
+ if (inString === "double" && char === "\"") {
261
+ inString = null;
262
+ continue;
263
+ }
264
+ if (inString === "single" && char === "'") {
265
+ inString = null;
266
+ continue;
267
+ }
268
+ continue;
269
+ }
270
+ if (char === "\"") {
271
+ inString = "double";
272
+ continue;
273
+ }
274
+ if (char === "'") {
275
+ inString = "single";
276
+ continue;
277
+ }
278
+ if (char === "#") return line.slice(0, i).trimEnd();
279
+ }
280
+ return line;
281
+ }
282
+ function unescapeBasic(input) {
283
+ return input.replace(/\\\\/g, "\\").replace(/\\"/g, "\"").replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\r/g, "\r");
284
+ }
285
+ function parseStringLiteral(value) {
286
+ if (value.startsWith("\"\"\"") && value.endsWith("\"\"\"")) return unescapeBasic(value.slice(3, -3));
287
+ if (value.startsWith("'''") && value.endsWith("'''")) return value.slice(3, -3);
288
+ if (value.startsWith("\"") && value.endsWith("\"")) return unescapeBasic(value.slice(1, -1));
289
+ if (value.startsWith("'") && value.endsWith("'")) return value.slice(1, -1);
290
+ return null;
291
+ }
292
+
293
+ //#endregion
294
+ //#region src/markdown/toml/values.ts
295
+ function parsePrimitive(raw) {
296
+ const value = raw.trim();
297
+ if (!value) return null;
298
+ const stringLiteral = parseStringLiteral(value);
299
+ if (stringLiteral !== null) return stringLiteral;
300
+ if (value === "true") return true;
301
+ if (value === "false") return false;
302
+ if (/^[+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(value)) return Number(value);
303
+ if (/^\d{4}-\d{2}-\d{2}/.test(value)) return value;
304
+ return value;
305
+ }
306
+ function parseArray(raw) {
307
+ const value = raw.trim();
308
+ if (!value.startsWith("[") || !value.endsWith("]")) return null;
309
+ const inner = value.slice(1, -1).trim();
310
+ if (!inner) return [];
311
+ const items = [];
312
+ let current = "";
313
+ let inString = null;
314
+ let escaped = false;
315
+ for (let i = 0; i < inner.length; i += 1) {
316
+ const char = inner[i] ?? "";
317
+ if (inString) {
318
+ current += char;
319
+ if (escaped) {
320
+ escaped = false;
321
+ continue;
322
+ }
323
+ if (char === "\\" && inString === "double") {
324
+ escaped = true;
325
+ continue;
326
+ }
327
+ if (inString === "double" && char === "\"") inString = null;
328
+ else if (inString === "single" && char === "'") inString = null;
329
+ continue;
330
+ }
331
+ if (char === "\"") {
332
+ inString = "double";
333
+ current += char;
334
+ continue;
335
+ }
336
+ if (char === "'") {
337
+ inString = "single";
338
+ current += char;
339
+ continue;
340
+ }
341
+ if (char === ",") {
342
+ const item = parsePrimitive(current);
343
+ if (item === null) return null;
344
+ items.push(item);
345
+ current = "";
346
+ continue;
347
+ }
348
+ current += char;
349
+ }
350
+ const finalItem = parsePrimitive(current);
351
+ if (finalItem === null) return null;
352
+ items.push(finalItem);
353
+ return items;
354
+ }
355
+ function parseInlineTable(raw) {
356
+ const trimmed = raw.trim();
357
+ if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return null;
358
+ const inner = trimmed.slice(1, -1).trim();
359
+ if (!inner) return {};
360
+ const pairs = [];
361
+ let current = "";
362
+ let inString = null;
363
+ let escaped = false;
364
+ let bracketDepth = 0;
365
+ let braceDepth = 0;
366
+ for (let i = 0; i < inner.length; i += 1) {
367
+ const char = inner[i] ?? "";
368
+ if (inString) {
369
+ current += char;
370
+ if (escaped) {
371
+ escaped = false;
372
+ continue;
373
+ }
374
+ if (char === "\\" && inString === "double") {
375
+ escaped = true;
376
+ continue;
377
+ }
378
+ if (inString === "double" && char === "\"") inString = null;
379
+ else if (inString === "single" && char === "'") inString = null;
380
+ continue;
381
+ }
382
+ if (char === "\"") {
383
+ inString = "double";
384
+ current += char;
385
+ continue;
386
+ }
387
+ if (char === "'") {
388
+ inString = "single";
389
+ current += char;
390
+ continue;
391
+ }
392
+ if (char === "[") {
393
+ bracketDepth += 1;
394
+ current += char;
395
+ continue;
396
+ }
397
+ if (char === "]") {
398
+ if (bracketDepth > 0) bracketDepth -= 1;
399
+ current += char;
400
+ continue;
401
+ }
402
+ if (char === "{") {
403
+ braceDepth += 1;
404
+ current += char;
405
+ continue;
406
+ }
407
+ if (char === "}") {
408
+ if (braceDepth > 0) braceDepth -= 1;
409
+ current += char;
410
+ continue;
411
+ }
412
+ if (char === "," && bracketDepth === 0 && braceDepth === 0) {
413
+ pairs.push(current);
414
+ current = "";
415
+ continue;
416
+ }
417
+ current += char;
418
+ }
419
+ if (current.trim()) pairs.push(current);
420
+ const output = {};
421
+ for (const pair of pairs) {
422
+ const separatorIndex = pair.indexOf("=");
423
+ if (separatorIndex === -1) return null;
424
+ const key = normalizeKeyPath(pair.slice(0, separatorIndex));
425
+ if (!key) return null;
426
+ const valueRaw = pair.slice(separatorIndex + 1).trim();
427
+ if (!valueRaw) return null;
428
+ if (valueRaw.startsWith("{")) return null;
429
+ const normalized = normalizeValue(valueRaw);
430
+ if (normalized === null) return null;
431
+ if (typeof normalized === "object" && !Array.isArray(normalized)) return null;
432
+ output[key] = normalized;
433
+ }
434
+ return output;
435
+ }
436
+ function normalizeValue(value) {
437
+ if (!value) return null;
438
+ const trimmed = value.trim();
439
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) return parseInlineTable(trimmed);
440
+ const array = parseArray(trimmed);
441
+ if (array) return array;
442
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) return null;
443
+ return parsePrimitive(trimmed);
444
+ }
445
+ function toPlainText(value) {
446
+ if (value == null) return "";
447
+ if (Array.isArray(value)) return value.map((item) => String(item)).join(", ");
448
+ return String(value);
449
+ }
450
+
451
+ //#endregion
452
+ //#region src/markdown/toml/parse-frontmatter.ts
453
+ function parseTomlFrontmatter(frontmatter) {
454
+ const result = {};
455
+ const lines = frontmatter.split("\n");
456
+ let tablePrefix = "";
457
+ let tableTarget = null;
458
+ let tablePrefixInList = false;
459
+ for (let index = 0; index < lines.length; index += 1) {
460
+ const rawLine = lines[index] ?? "";
461
+ const trimmedLine = rawLine.trim();
462
+ if (!trimmedLine || trimmedLine.startsWith("#")) continue;
463
+ if (trimmedLine.startsWith("[[")) {
464
+ const match = trimmedLine.match(/^\[\[([^\]]+)]]$/);
465
+ if (!match) return null;
466
+ const normalizedTable = normalizeKeyPath(match[1] ?? "");
467
+ if (!normalizedTable) return null;
468
+ const list = ensureArrayContainer(result, normalizedTable);
469
+ const newEntry = {};
470
+ list.push(newEntry);
471
+ tableTarget = newEntry;
472
+ tablePrefix = normalizedTable;
473
+ tablePrefixInList = true;
474
+ continue;
475
+ }
476
+ const tableMatch = trimmedLine.match(/^\[([^\]]+)]$/);
477
+ if (tableMatch) {
478
+ const normalizedTable = normalizeKeyPath(tableMatch[1] ?? "");
479
+ if (!normalizedTable) return null;
480
+ tablePrefix = normalizedTable;
481
+ tablePrefixInList = false;
482
+ tableTarget = null;
483
+ continue;
484
+ }
485
+ const lineForParsing = /("""|''')/.test(rawLine) ? rawLine : stripInlineComment(rawLine);
486
+ const separatorIndex = lineForParsing.indexOf("=");
487
+ if (separatorIndex === -1) return null;
488
+ const key = normalizeKeyPath(lineForParsing.slice(0, separatorIndex));
489
+ let valueRaw = lineForParsing.slice(separatorIndex + 1).trim();
490
+ if (!key) return null;
491
+ const tripleDelimiter = valueRaw.startsWith("\"\"\"") ? "\"\"\"" : valueRaw.startsWith("'''") ? "'''" : null;
492
+ if (tripleDelimiter) {
493
+ const closingIndex = valueRaw.indexOf(tripleDelimiter, tripleDelimiter.length);
494
+ if (closingIndex !== -1) {
495
+ const strippedAfter = stripInlineComment(valueRaw.slice(closingIndex + tripleDelimiter.length));
496
+ valueRaw = `${valueRaw.slice(0, closingIndex + tripleDelimiter.length)}${strippedAfter}`;
497
+ } else {
498
+ const delimiter = tripleDelimiter;
499
+ let combined = valueRaw;
500
+ let closed = false;
501
+ while (index + 1 < lines.length) {
502
+ index += 1;
503
+ const nextLine = lines[index] ?? "";
504
+ combined += `\n${nextLine}`;
505
+ if ((/* @__PURE__ */ new RegExp(`${delimiter}\\s*$`)).test(nextLine)) {
506
+ closed = true;
507
+ break;
508
+ }
509
+ }
510
+ if (!closed) return null;
511
+ valueRaw = combined;
512
+ }
513
+ }
514
+ const normalized = normalizeValue(valueRaw);
515
+ if (normalized === null) return null;
516
+ const fullKey = tablePrefix ? `${tablePrefix}.${key}` : key;
517
+ if (typeof normalized === "object" && !Array.isArray(normalized)) {
518
+ for (const [inlineKey, inlineValue] of Object.entries(normalized)) {
519
+ const entryKey = tablePrefixInList ? `${key}.${inlineKey}` : `${fullKey}.${inlineKey}`;
520
+ if (tablePrefixInList && tableTarget) tableTarget[entryKey] = toPlainText(inlineValue);
521
+ else result[entryKey] = toPlainText(inlineValue);
522
+ }
523
+ continue;
524
+ }
525
+ if (tablePrefixInList && tableTarget) {
526
+ tableTarget[key] = toPlainText(normalized);
527
+ continue;
528
+ }
529
+ result[fullKey] = toPlainText(normalized);
530
+ }
531
+ flattenArrayTables(result);
532
+ return result;
533
+ }
534
+
535
+ //#endregion
536
+ //#region src/markdown/parse-markdown.ts
537
+ const FENCE_TO_TYPE = {
538
+ "---": "yaml",
539
+ "+++": "toml",
540
+ ";;;": "json"
541
+ };
542
+ function normalizeNewlines(input) {
543
+ return input.replace(/\r\n/g, "\n");
544
+ }
545
+ function stripBom(line) {
546
+ return line.startsWith("") ? line.slice(1) : line;
547
+ }
548
+ function getFenceType(line) {
549
+ const match = line.match(/^[\t ]*(---|\+\+\+|;;;)[\t ]*$/);
550
+ if (!match) return null;
551
+ return FENCE_TO_TYPE[match[1] ?? ""] ?? null;
552
+ }
553
+ function parseFrontmatter(frontmatter, type) {
554
+ if (!type) return null;
555
+ if (type === "json") try {
556
+ return JSON.parse(frontmatter);
557
+ } catch {
558
+ return null;
559
+ }
560
+ if (type === "yaml") {
561
+ const doc = (0, yaml.parseDocument)(frontmatter, { prettyErrors: false });
562
+ if (doc.errors.length > 0) return null;
563
+ const data = doc.toJSON();
564
+ if (!data || typeof data !== "object" || Array.isArray(data)) return null;
565
+ return data;
566
+ }
567
+ if (type === "toml") return parseTomlFrontmatter(frontmatter);
568
+ return null;
569
+ }
570
+ function extractJsonBlock(text, startIndex) {
571
+ let depth = 0;
572
+ let inString = false;
573
+ let escaped = false;
574
+ for (let i = startIndex; i < text.length; i += 1) {
575
+ const char = text[i] ?? "";
576
+ if (inString) {
577
+ if (escaped) {
578
+ escaped = false;
579
+ continue;
580
+ }
581
+ if (char === "\\") {
582
+ escaped = true;
583
+ continue;
584
+ }
585
+ if (char === "\"") inString = false;
586
+ continue;
587
+ }
588
+ if (char === "\"") {
589
+ inString = true;
590
+ continue;
591
+ }
592
+ if (char === "{") {
593
+ depth += 1;
594
+ continue;
595
+ }
596
+ if (char === "}") {
597
+ depth -= 1;
598
+ if (depth === 0) return {
599
+ jsonText: text.slice(startIndex, i + 1),
600
+ endIndex: i
601
+ };
602
+ }
603
+ }
604
+ return null;
605
+ }
606
+ function parseMarkdown(input) {
607
+ const normalized = normalizeNewlines(input);
608
+ const lines = normalized.split("\n");
609
+ if (lines.length === 0) return {
610
+ frontmatter: null,
611
+ content: normalized,
612
+ data: null,
613
+ frontmatterType: null
614
+ };
615
+ lines[0] = stripBom(lines[0] ?? "");
616
+ const normalizedWithoutBom = lines.join("\n");
617
+ const openingType = getFenceType(lines[0] ?? "");
618
+ if (!openingType) {
619
+ const jsonStart = (normalizedWithoutBom.match(/^[\t \n]*/)?.[0] ?? "").length;
620
+ if (normalizedWithoutBom[jsonStart] !== "{") return {
621
+ frontmatter: null,
622
+ content: normalizedWithoutBom,
623
+ data: null,
624
+ frontmatterType: null
625
+ };
626
+ const jsonBlock = extractJsonBlock(normalizedWithoutBom, jsonStart);
627
+ if (!jsonBlock) return {
628
+ frontmatter: null,
629
+ content: normalizedWithoutBom,
630
+ data: null,
631
+ frontmatterType: null
632
+ };
633
+ const frontmatter$1 = jsonBlock.jsonText;
634
+ let content = normalizedWithoutBom.slice(jsonBlock.endIndex + 1);
635
+ if (content.startsWith("\n")) content = content.slice(1);
636
+ const data = parseFrontmatter(frontmatter$1, "json");
637
+ if (!data) return {
638
+ frontmatter: null,
639
+ content: normalizedWithoutBom,
640
+ data: null,
641
+ frontmatterType: null
642
+ };
643
+ return {
644
+ frontmatter: frontmatter$1,
645
+ content,
646
+ data,
647
+ frontmatterType: "json"
648
+ };
649
+ }
650
+ let closingIndex = -1;
651
+ for (let i = 1; i < lines.length; i += 1) if (getFenceType(lines[i] ?? "") === openingType) {
652
+ closingIndex = i;
653
+ break;
654
+ }
655
+ if (closingIndex === -1) return {
656
+ frontmatter: null,
657
+ content: normalizedWithoutBom,
658
+ data: null,
659
+ frontmatterType: null
660
+ };
661
+ const frontmatter = lines.slice(1, closingIndex).join("\n");
662
+ return {
663
+ frontmatter,
664
+ content: lines.slice(closingIndex + 1).join("\n"),
665
+ data: parseFrontmatter(frontmatter, openingType),
666
+ frontmatterType: openingType
667
+ };
668
+ }
669
+
670
+ //#endregion
671
+ //#region src/markdown/section-count.ts
672
+ function normalizeText(value) {
673
+ if (value == null) return "";
674
+ if (typeof value === "string") return value;
675
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
676
+ try {
677
+ return JSON.stringify(value);
678
+ } catch {
679
+ return String(value);
680
+ }
681
+ }
682
+ function buildPerKeyItems(data, mode) {
683
+ if (!data || typeof data !== "object" || Array.isArray(data)) return [];
684
+ return Object.entries(data).map(([key, value]) => {
685
+ const valueText = normalizeText(value);
686
+ return {
687
+ name: key,
688
+ source: "frontmatter",
689
+ result: wc_default(valueText ? `${key}: ${valueText}` : key, { mode })
690
+ };
691
+ });
692
+ }
693
+ function buildSingleItem(name, text, mode, source) {
694
+ return [{
695
+ name,
696
+ source,
697
+ result: wc_default(text, { mode })
698
+ }];
699
+ }
700
+ function sumTotals(items) {
701
+ return items.reduce((sum, item) => sum + item.result.total, 0);
702
+ }
703
+ function countSections(input, section, mode) {
704
+ if (section === "all") {
705
+ const result = wc_default(input, { mode });
706
+ return {
707
+ section,
708
+ total: result.total,
709
+ frontmatterType: null,
710
+ items: [{
711
+ name: "all",
712
+ source: "content",
713
+ result
714
+ }]
715
+ };
716
+ }
717
+ const parsed = parseMarkdown(input);
718
+ const frontmatterText = parsed.frontmatter ?? "";
719
+ const contentText = parsed.content ?? "";
720
+ let items = [];
721
+ if (section === "frontmatter") items = buildSingleItem("frontmatter", frontmatterText, mode, "frontmatter");
722
+ else if (section === "content") items = buildSingleItem("content", contentText, mode, "content");
723
+ else if (section === "split") items = [...buildSingleItem("frontmatter", frontmatterText, mode, "frontmatter"), ...buildSingleItem("content", contentText, mode, "content")];
724
+ else if (section === "per-key") items = buildPerKeyItems(parsed.data, mode);
725
+ else if (section === "split-per-key") items = [...buildPerKeyItems(parsed.data, mode), ...buildSingleItem("content", contentText, mode, "content")];
726
+ return {
727
+ section,
728
+ total: sumTotals(items),
729
+ frontmatterType: parsed.frontmatterType,
730
+ items
731
+ };
732
+ }
733
+
734
+ //#endregion
735
+ //#region src/utils/show-singular-or-plural-word.ts
736
+ function showSingularOrPluralWord(count, word) {
737
+ return `${count} ${word}${count === 1 ? "" : "s"}`;
738
+ }
739
+
740
+ //#endregion
741
+ //#region src/index.cjs.ts
742
+ const cjsExports = Object.assign(wc_default, {
743
+ default: wc_default,
744
+ wordCounter: wc_default,
745
+ countWordsForLocale,
746
+ segmentTextByLocale,
747
+ parseMarkdown,
748
+ countSections,
749
+ showSingularOrPluralWord
750
+ });
751
+ module.exports = cjsExports;
752
+
753
+ //#endregion
754
+ //# sourceMappingURL=index.cjs.map