use-voice-control 0.1.95 → 0.1.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/markdown.js CHANGED
@@ -1,213 +1,186 @@
1
- const A = {
2
- headings: "text",
3
- codeBlocks: "announce",
4
- links: "text",
5
- images: "alt",
6
- frontMatter: !1,
7
- tables: "rows",
8
- addTerminalPunctuation: !0
9
- }, x = {
10
- js: "JavaScript",
11
- jsx: "JavaScript",
12
- mjs: "JavaScript",
13
- cjs: "JavaScript",
14
- ts: "TypeScript",
15
- tsx: "TypeScript",
16
- py: "Python",
17
- rb: "Ruby",
18
- rs: "Rust",
19
- sh: "shell",
20
- bash: "shell",
21
- zsh: "shell",
22
- shell: "shell",
23
- console: "shell",
24
- yml: "YAML",
25
- yaml: "YAML",
26
- md: "Markdown",
27
- json: "JSON",
28
- html: "HTML",
29
- css: "CSS",
30
- sql: "SQL",
31
- go: "Go",
32
- java: "Java",
33
- c: "C",
34
- cpp: "C plus plus",
35
- cs: "C sharp",
36
- php: "PHP",
37
- swift: "Swift",
38
- kt: "Kotlin",
39
- diff: "diff",
40
- text: "",
41
- txt: "",
42
- plaintext: ""
43
- }, T = {
44
- amp: "&",
45
- lt: "<",
46
- gt: ">",
47
- quot: '"',
48
- apos: "'",
49
- nbsp: " ",
50
- mdash: "—",
51
- ndash: "–",
52
- hellip: "…",
53
- ldquo: '"',
54
- rdquo: '"',
55
- lsquo: "'",
56
- rsquo: "'"
57
- }, L = /^ {0,3}(#{1,6})(?:\s+(.*?))?\s*$/, R = /^ {0,3}(=+|-+)\s*$/, C = /^ {0,3}([-*_])[ \t]*(?:\1[ \t]*){2,}$/, I = /^ {0,3}(`{3,}|~{3,})\s*([^`]*)$/, N = /^ *(?:[-+*]|\d{1,9}[.)])(?:\s+(.*))?$/, w = /^ *(\d{1,9})[.)]\s+(.*)$/, P = /^\[([ xX])\]\s+/, b = /^ {0,3}\[[^\]]+\]:\s*\S+.*$/, y = /^[\s|:-]*-[\s|:-]*$/, M = "\0", O = "", j = /\u0000(\d+)\u0001/g;
58
- function D(i) {
59
- return /[.!?:;,…]["')\]]?$/.test(i) ? i : `${i}.`;
1
+ //#region speech/utils/markdown-to-speech.ts
2
+ var e = {
3
+ headings: "text",
4
+ codeBlocks: "announce",
5
+ links: "text",
6
+ images: "alt",
7
+ frontMatter: !1,
8
+ tables: "rows",
9
+ addTerminalPunctuation: !0
10
+ }, t = {
11
+ js: "JavaScript",
12
+ jsx: "JavaScript",
13
+ mjs: "JavaScript",
14
+ cjs: "JavaScript",
15
+ ts: "TypeScript",
16
+ tsx: "TypeScript",
17
+ py: "Python",
18
+ rb: "Ruby",
19
+ rs: "Rust",
20
+ sh: "shell",
21
+ bash: "shell",
22
+ zsh: "shell",
23
+ shell: "shell",
24
+ console: "shell",
25
+ yml: "YAML",
26
+ yaml: "YAML",
27
+ md: "Markdown",
28
+ json: "JSON",
29
+ html: "HTML",
30
+ css: "CSS",
31
+ sql: "SQL",
32
+ go: "Go",
33
+ java: "Java",
34
+ c: "C",
35
+ cpp: "C plus plus",
36
+ cs: "C sharp",
37
+ php: "PHP",
38
+ swift: "Swift",
39
+ kt: "Kotlin",
40
+ diff: "diff",
41
+ text: "",
42
+ txt: "",
43
+ plaintext: ""
44
+ }, n = {
45
+ amp: "&",
46
+ lt: "<",
47
+ gt: ">",
48
+ quot: "\"",
49
+ apos: "'",
50
+ nbsp: " ",
51
+ mdash: "—",
52
+ ndash: "–",
53
+ hellip: "…",
54
+ ldquo: "\"",
55
+ rdquo: "\"",
56
+ lsquo: "'",
57
+ rsquo: "'"
58
+ }, r = /^ {0,3}(#{1,6})(?:\s+(.*?))?\s*$/, i = /^ {0,3}(=+|-+)\s*$/, a = /^ {0,3}([-*_])[ \t]*(?:\1[ \t]*){2,}$/, o = /^ {0,3}(`{3,}|~{3,})\s*([^`]*)$/, s = /^ *(?:[-+*]|\d{1,9}[.)])(?:\s+(.*))?$/, c = /^ *(\d{1,9})[.)]\s+(.*)$/, l = /^\[([ xX])\]\s+/, u = /^ {0,3}\[[^\]]+\]:\s*\S+.*$/, d = /^[\s|:-]*-[\s|:-]*$/, f = "\0", p = "", m = /\u0000(\d+)\u0001/g;
59
+ function h(e) {
60
+ return /[.!?:;,…]["')\]]?$/.test(e) ? e : `${e}.`;
60
61
  }
61
- function H(i) {
62
- return i.replace(/&#(\d{1,7});/g, (r, t) => String.fromCodePoint(Number(t))).replace(
63
- /&#[xX]([0-9a-fA-F]{1,6});/g,
64
- (r, t) => String.fromCodePoint(parseInt(t, 16))
65
- ).replace(/&([a-zA-Z]+);/g, (r, t) => T[t.toLowerCase()] ?? r);
62
+ function g(e) {
63
+ return e.replace(/&#(\d{1,7});/g, (e, t) => String.fromCodePoint(Number(t))).replace(/&#[xX]([0-9a-fA-F]{1,6});/g, (e, t) => String.fromCodePoint(parseInt(t, 16))).replace(/&([a-zA-Z]+);/g, (e, t) => n[t.toLowerCase()] ?? e);
66
64
  }
67
- function _(i, r = {}) {
68
- const t = { ...A, ...r }, a = [], l = (o) => `${M}${a.push(o) - 1}${O}`;
69
- let e = i;
70
- return e = e.replace(/\\([\\`*_{}[\]()#+\-.!>~|])/g, (o, n) => l(n)), e = e.replace(
71
- /(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/g,
72
- (o, n, p) => l(String(p).trim())
73
- ), e = e.replace(/<!--[\s\S]*?-->/g, ""), e = e.replace(
74
- /!\[([^\]]*)\]\([^)]*\)/g,
75
- (o, n) => t.images === "skip" ? "" : String(n)
76
- ), e = e.replace(
77
- /!\[([^\]]*)\]\[[^\]]*\]/g,
78
- (o, n) => t.images === "skip" ? "" : String(n)
79
- ), e = e.replace(/\[\^[^\]]+\]/g, ""), e = e.replace(
80
- /\[([^\]]*)\]\(\s*<?([^\s)]*)>?[^)]*\)/g,
81
- (o, n, p) => t.links === "text-and-url" && p ? `${n}, ${p}` : String(n)
82
- ), e = e.replace(/\[([^\]]*)\]\[[^\]]*\]/g, "$1"), e = e.replace(
83
- /<((?:https?|mailto):[^>\s]+)>/gi,
84
- (o, n) => t.links === "text-and-url" ? String(n) : String(n).replace(/^mailto:/i, "")
85
- ), e = e.replace(/<\/?[a-zA-Z][^>]*>/g, ""), e = e.replace(/\*\*\*(?=\S)([\s\S]*?\S)\*\*\*/g, "$1"), e = e.replace(/\*\*(?=\S)([\s\S]*?\S)\*\*/g, "$1"), e = e.replace(new RegExp("(?<![A-Za-z0-9_])__(?=\\S)([\\s\\S]*?\\S)__(?![A-Za-z0-9_])", "g"), "$1"), e = e.replace(/~~(?=\S)([\s\S]*?\S)~~/g, "$1"), e = e.replace(/\*(?=\S)([^*\n]*?\S)\*/g, "$1"), e = e.replace(new RegExp("(?<![A-Za-z0-9_])_(?=\\S)([^_\\n]*?\\S)_(?![A-Za-z0-9_])", "g"), "$1"), e = H(e), e = e.replace(
86
- j,
87
- (o, n) => a[Number(n)] ?? ""
88
- ), e.replace(/[ \t]+/g, " ").trim();
65
+ function _(t, n = {}) {
66
+ let r = {
67
+ ...e,
68
+ ...n
69
+ }, i = [], a = (e) => `${f}${i.push(e) - 1}${p}`, o = t;
70
+ return o = o.replace(/\\([\\`*_{}[\]()#+\-.!>~|])/g, (e, t) => a(t)), o = o.replace(/(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/g, (e, t, n) => a(String(n).trim())), o = o.replace(/<!--[\s\S]*?-->/g, ""), o = o.replace(/!\[([^\]]*)\]\([^)]*\)/g, (e, t) => r.images === "skip" ? "" : String(t)), o = o.replace(/!\[([^\]]*)\]\[[^\]]*\]/g, (e, t) => r.images === "skip" ? "" : String(t)), o = o.replace(/\[\^[^\]]+\]/g, ""), o = o.replace(/\[([^\]]*)\]\(\s*<?([^\s)]*)>?[^)]*\)/g, (e, t, n) => r.links === "text-and-url" && n ? `${t}, ${n}` : String(t)), o = o.replace(/\[([^\]]*)\]\[[^\]]*\]/g, "$1"), o = o.replace(/<((?:https?|mailto):[^>\s]+)>/gi, (e, t) => r.links === "text-and-url" ? String(t) : String(t).replace(/^mailto:/i, "")), o = o.replace(/<\/?[a-zA-Z][^>]*>/g, ""), o = o.replace(/\*\*\*(?=\S)([\s\S]*?\S)\*\*\*/g, "$1"), o = o.replace(/\*\*(?=\S)([\s\S]*?\S)\*\*/g, "$1"), o = o.replace(/(?<![A-Za-z0-9_])__(?=\S)([\s\S]*?\S)__(?![A-Za-z0-9_])/g, "$1"), o = o.replace(/~~(?=\S)([\s\S]*?\S)~~/g, "$1"), o = o.replace(/\*(?=\S)([^*\n]*?\S)\*/g, "$1"), o = o.replace(/(?<![A-Za-z0-9_])_(?=\S)([^_\n]*?\S)_(?![A-Za-z0-9_])/g, "$1"), o = g(o), o = o.replace(m, (e, t) => i[Number(t)] ?? ""), o.replace(/[ \t]+/g, " ").trim();
89
71
  }
90
- function q(i) {
91
- var a;
92
- const r = ((a = i.trim().split(/[\s,{]/)[0]) == null ? void 0 : a.toLowerCase()) ?? "", t = r in x ? x[r] : r;
93
- return t ? `${t} code block.` : "Code block.";
72
+ function v(e) {
73
+ let n = e.trim().split(/[\s,{]/)[0]?.toLowerCase() ?? "", r = n in t ? t[n] : n;
74
+ return r ? `${r} code block.` : "Code block.";
94
75
  }
95
- function z(i, r = {}) {
96
- const t = { ...A, ...r }, a = [];
97
- let l = (i ?? "").replace(/\r\n?/g, `
98
- `).replace(/\t/g, " ");
99
- l = l.replace(/<!--[\s\S]*?-->/g, "");
100
- const e = l.split(`
101
- `);
102
- let o = 0;
103
- if (!t.frontMatter && /^---\s*$/.test(e[0] ?? "")) {
104
- const s = e.findIndex((u, f) => f > 0 && /^(---|\.\.\.)\s*$/.test(u));
105
- s > 0 && (o = s + 1);
106
- }
107
- let n = [], p = !1;
108
- const d = (s, u, f) => {
109
- const S = u.trim();
110
- if (!S) return;
111
- const m = t.addTerminalPunctuation ? D(S) : S;
112
- a.push(f === void 0 ? { type: s, text: m } : { type: s, text: m, level: f });
113
- }, g = () => {
114
- if (n.length === 0) return;
115
- const s = _(n.join(" "), t);
116
- n = [];
117
- const u = p ? "quote" : "paragraph";
118
- p = !1, d(u, s);
119
- };
120
- for (; o < e.length; o += 1) {
121
- let s = e[o];
122
- const u = I.exec(s);
123
- if (u) {
124
- g();
125
- const c = u[1], h = u[2] ?? "", E = new RegExp(`^ {0,3}\\${c[0]}{${c.length},}\\s*$`), k = [];
126
- for (o += 1; o < e.length && !E.test(e[o]); o += 1)
127
- k.push(e[o]);
128
- t.codeBlocks === "announce" ? d("code", q(h)) : t.codeBlocks === "read" && d("code", k.join(" ").replace(/\s+/g, " "));
129
- continue;
130
- }
131
- if (s.trim() === "") {
132
- g();
133
- continue;
134
- }
135
- let f = !1;
136
- for (; /^ {0,3}>\s?/.test(s); )
137
- s = s.replace(/^ {0,3}>\s?/, ""), f = !0;
138
- if (f && (n.length === 0 && (p = !0), s.trim() === "")) {
139
- g();
140
- continue;
141
- }
142
- if (C.test(s)) {
143
- g();
144
- continue;
145
- }
146
- const S = L.exec(s);
147
- if (S) {
148
- if (g(), t.headings === "skip") continue;
149
- const c = _((S[2] ?? "").replace(/\s+#+$/, ""), t);
150
- if (!c) continue;
151
- d("heading", t.headings === "announce" ? `Heading: ${c}` : c, S[1].length);
152
- continue;
153
- }
154
- const m = R.exec(s);
155
- if (m && n.length > 0 && t.headings !== "skip") {
156
- const c = _(n.join(" "), t);
157
- n = [], p = !1, c && d(
158
- "heading",
159
- t.headings === "announce" ? `Heading: ${c}` : c,
160
- m[1].startsWith("=") ? 1 : 2
161
- );
162
- continue;
163
- }
164
- if (b.test(s) && n.length === 0) continue;
165
- if (s.trimStart().startsWith("|")) {
166
- if (g(), t.tables === "skip" || y.test(s)) continue;
167
- const c = s.trim().replace(/^\|/, "").replace(/\|$/, "").split(new RegExp("(?<!\\\\)\\|")).map((h) => _(h, t)).filter((h) => h.length > 0);
168
- c.length > 0 && d("table-row", c.join(", "));
169
- continue;
170
- }
171
- const $ = N.exec(s);
172
- if ($) {
173
- g();
174
- const c = w.exec(s), h = (c ? c[2] : $[1] ?? "").replace(P, ""), E = _(h, t);
175
- if (!E) continue;
176
- d("list-item", c ? `${c[1]}. ${E}` : E);
177
- continue;
178
- }
179
- n.push(s.trim());
180
- }
181
- return g(), a;
76
+ function y(t, n = {}) {
77
+ let f = {
78
+ ...e,
79
+ ...n
80
+ }, p = [], m = (t ?? "").replace(/\r\n?/g, "\n").replace(/\t/g, " ");
81
+ m = m.replace(/<!--[\s\S]*?-->/g, "");
82
+ let g = m.split("\n"), y = 0;
83
+ if (!f.frontMatter && /^---\s*$/.test(g[0] ?? "")) {
84
+ let e = g.findIndex((e, t) => t > 0 && /^(---|\.\.\.)\s*$/.test(e));
85
+ e > 0 && (y = e + 1);
86
+ }
87
+ let b = [], x = !1, S = (e, t, n) => {
88
+ let r = t.trim();
89
+ if (!r) return;
90
+ let i = f.addTerminalPunctuation ? h(r) : r;
91
+ p.push(n === void 0 ? {
92
+ type: e,
93
+ text: i
94
+ } : {
95
+ type: e,
96
+ text: i,
97
+ level: n
98
+ });
99
+ }, C = () => {
100
+ if (b.length === 0) return;
101
+ let e = _(b.join(" "), f);
102
+ b = [];
103
+ let t = x ? "quote" : "paragraph";
104
+ x = !1, S(t, e);
105
+ };
106
+ for (; y < g.length; y += 1) {
107
+ let e = g[y], t = o.exec(e);
108
+ if (t) {
109
+ C();
110
+ let e = t[1], n = t[2] ?? "", r = RegExp(`^ {0,3}\\${e[0]}{${e.length},}\\s*$`), i = [];
111
+ for (y += 1; y < g.length && !r.test(g[y]); y += 1) i.push(g[y]);
112
+ f.codeBlocks === "announce" ? S("code", v(n)) : f.codeBlocks === "read" && S("code", i.join(" ").replace(/\s+/g, " "));
113
+ continue;
114
+ }
115
+ if (e.trim() === "") {
116
+ C();
117
+ continue;
118
+ }
119
+ let n = !1;
120
+ for (; /^ {0,3}>\s?/.test(e);) e = e.replace(/^ {0,3}>\s?/, ""), n = !0;
121
+ if (n && (b.length === 0 && (x = !0), e.trim() === "")) {
122
+ C();
123
+ continue;
124
+ }
125
+ if (a.test(e)) {
126
+ C();
127
+ continue;
128
+ }
129
+ let p = r.exec(e);
130
+ if (p) {
131
+ if (C(), f.headings === "skip") continue;
132
+ let e = _((p[2] ?? "").replace(/\s+#+$/, ""), f);
133
+ if (!e) continue;
134
+ S("heading", f.headings === "announce" ? `Heading: ${e}` : e, p[1].length);
135
+ continue;
136
+ }
137
+ let m = i.exec(e);
138
+ if (m && b.length > 0 && f.headings !== "skip") {
139
+ let e = _(b.join(" "), f);
140
+ b = [], x = !1, e && S("heading", f.headings === "announce" ? `Heading: ${e}` : e, m[1].startsWith("=") ? 1 : 2);
141
+ continue;
142
+ }
143
+ if (u.test(e) && b.length === 0) continue;
144
+ if (e.trimStart().startsWith("|")) {
145
+ if (C(), f.tables === "skip" || d.test(e)) continue;
146
+ let t = e.trim().replace(/^\|/, "").replace(/\|$/, "").split(/(?<!\\)\|/).map((e) => _(e, f)).filter((e) => e.length > 0);
147
+ t.length > 0 && S("table-row", t.join(", "));
148
+ continue;
149
+ }
150
+ let h = s.exec(e);
151
+ if (h) {
152
+ C();
153
+ let t = c.exec(e), n = _((t ? t[2] : h[1] ?? "").replace(l, ""), f);
154
+ if (!n) continue;
155
+ S("list-item", t ? `${t[1]}. ${n}` : n);
156
+ continue;
157
+ }
158
+ b.push(e.trim());
159
+ }
160
+ return C(), p;
182
161
  }
183
- function v(i, r = {}) {
184
- const t = z(i, r);
185
- return t.reduce((a, l, e) => {
186
- if (e === 0) return l.text;
187
- const o = t[e - 1].type, n = (l.type === "list-item" || l.type === "table-row") && o === l.type;
188
- return `${a}${n ? `
189
- ` : `
190
-
191
- `}${l.text}`;
192
- }, "");
162
+ function b(e, t = {}) {
163
+ let n = y(e, t);
164
+ return n.reduce((e, t, r) => {
165
+ if (r === 0) return t.text;
166
+ let i = n[r - 1].type;
167
+ return `${e}${(t.type === "list-item" || t.type === "table-row") && i === t.type ? "\n" : "\n\n"}${t.text}`;
168
+ }, "");
193
169
  }
194
- function Z(i) {
195
- if (!i) return !1;
196
- const r = i.slice(0, 2e4);
197
- return [
198
- /^ {0,3}#{1,6}\s+\S/m,
199
- /^ {0,3}(?:```|~~~)/m,
200
- /^ {0,3}[-+*]\s+\S/m,
201
- /^ {0,3}>\s+\S/m,
202
- /\[[^\]]+\]\([^)]+\)/,
203
- new RegExp("(?<![A-Za-z0-9])\\*\\*\\S[\\s\\S]*?\\S\\*\\*"),
204
- /^ {0,3}\|.*\|\s*$/m
205
- ].filter((a) => a.test(r)).length >= 2;
170
+ function x(e) {
171
+ if (!e) return !1;
172
+ let t = e.slice(0, 2e4);
173
+ return [
174
+ /^ {0,3}#{1,6}\s+\S/m,
175
+ /^ {0,3}(?:```|~~~)/m,
176
+ /^ {0,3}[-+*]\s+\S/m,
177
+ /^ {0,3}>\s+\S/m,
178
+ /\[[^\]]+\]\([^)]+\)/,
179
+ /(?<![A-Za-z0-9])\*\*\S[\s\S]*?\S\*\*/,
180
+ /^ {0,3}\|.*\|\s*$/m
181
+ ].filter((e) => e.test(t)).length >= 2;
206
182
  }
207
- export {
208
- Z as looksLikeMarkdown,
209
- v as markdownToSpeech,
210
- z as markdownToSpeechSegments,
211
- _ as stripInlineMarkdown
212
- };
213
- //# sourceMappingURL=markdown.js.map
183
+ //#endregion
184
+ export { x as looksLikeMarkdown, b as markdownToSpeech, y as markdownToSpeechSegments, _ as stripInlineMarkdown };
185
+
186
+ //# sourceMappingURL=markdown.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.js","sources":["../speech/utils/markdown-to-speech.ts"],"sourcesContent":["/**\n * @fileoverview Turns Markdown into text a speech synthesizer can read.\n *\n * Markdown handed straight to a TTS engine is read literally: \"hash hash Getting\n * started\", \"star star important star star\". This module parses the document\n * instead and emits only the words, keeping the *structure* the marks encoded —\n * a heading becomes its own spoken segment ending in a full stop so the\n * synthesizer pauses, a list item becomes one sentence, a fenced code block is\n * announced rather than spelled out.\n *\n * It is deliberately dependency-free and runs in the browser as well as Node, so\n * `ReadAloudController` and the CLI can share it.\n */\n\n/** Kind of block the converter recognised. */\nexport type SpeechSegmentType =\n | \"heading\"\n | \"paragraph\"\n | \"list-item\"\n | \"quote\"\n | \"code\"\n | \"table-row\";\n\nexport interface SpeechSegment {\n type: SpeechSegmentType;\n /** Spoken text of the block, with every Markdown mark already removed. */\n text: string;\n /** Heading level 1-6. Only set on `heading` segments. */\n level?: number;\n}\n\nexport interface MarkdownToSpeechOptions {\n /**\n * How headings are spoken. `text` (default) reads the heading words on their\n * own so they land between pauses; `announce` prefixes them with \"Heading:\";\n * `skip` drops them entirely.\n */\n headings?: \"text\" | \"announce\" | \"skip\";\n /**\n * What to do with fenced code blocks. `announce` (default) replaces the block\n * with a short spoken note, `read` reads the code verbatim, `skip` drops it.\n */\n codeBlocks?: \"announce\" | \"read\" | \"skip\";\n /** `text` (default) speaks the link text and drops the URL; `text-and-url` reads both. */\n links?: \"text\" | \"text-and-url\";\n /** `alt` (default) speaks the image's alt text; `skip` drops images. */\n images?: \"alt\" | \"skip\";\n /** Read the YAML front matter block. Off by default. */\n frontMatter?: boolean;\n /** `rows` (default) reads table rows as comma-separated cells; `skip` drops tables. */\n tables?: \"rows\" | \"skip\";\n /**\n * Append a full stop to blocks that do not end in punctuation, so the\n * synthesizer pauses between them instead of running them together.\n * Default true.\n */\n addTerminalPunctuation?: boolean;\n}\n\ntype ResolvedOptions = Required<MarkdownToSpeechOptions>;\n\nconst DEFAULTS: ResolvedOptions = {\n headings: \"text\",\n codeBlocks: \"announce\",\n links: \"text\",\n images: \"alt\",\n frontMatter: false,\n tables: \"rows\",\n addTerminalPunctuation: true,\n};\n\n/** Spoken names for code fence languages that would otherwise be read as letters. */\nconst LANGUAGE_NAMES: Record<string, string> = {\n js: \"JavaScript\",\n jsx: \"JavaScript\",\n mjs: \"JavaScript\",\n cjs: \"JavaScript\",\n ts: \"TypeScript\",\n tsx: \"TypeScript\",\n py: \"Python\",\n rb: \"Ruby\",\n rs: \"Rust\",\n sh: \"shell\",\n bash: \"shell\",\n zsh: \"shell\",\n shell: \"shell\",\n console: \"shell\",\n yml: \"YAML\",\n yaml: \"YAML\",\n md: \"Markdown\",\n json: \"JSON\",\n html: \"HTML\",\n css: \"CSS\",\n sql: \"SQL\",\n go: \"Go\",\n java: \"Java\",\n c: \"C\",\n cpp: \"C plus plus\",\n cs: \"C sharp\",\n php: \"PHP\",\n swift: \"Swift\",\n kt: \"Kotlin\",\n diff: \"diff\",\n text: \"\",\n txt: \"\",\n plaintext: \"\",\n};\n\nconst ENTITIES: Record<string, string> = {\n amp: \"&\",\n lt: \"<\",\n gt: \">\",\n quot: '\"',\n apos: \"'\",\n nbsp: \" \",\n mdash: \"—\",\n ndash: \"–\",\n hellip: \"…\",\n ldquo: '\"',\n rdquo: '\"',\n lsquo: \"'\",\n rsquo: \"'\",\n};\n\nconst ATX_HEADING = /^ {0,3}(#{1,6})(?:\\s+(.*?))?\\s*$/;\nconst SETEXT_UNDERLINE = /^ {0,3}(=+|-+)\\s*$/;\nconst THEMATIC_BREAK = /^ {0,3}([-*_])[ \\t]*(?:\\1[ \\t]*){2,}$/;\nconst FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})\\s*([^`]*)$/;\nconst LIST_ITEM = /^ *(?:[-+*]|\\d{1,9}[.)])(?:\\s+(.*))?$/;\nconst ORDERED_ITEM = /^ *(\\d{1,9})[.)]\\s+(.*)$/;\nconst TASK_MARKER = /^\\[([ xX])\\]\\s+/;\nconst LINK_REFERENCE_DEFINITION = /^ {0,3}\\[[^\\]]+\\]:\\s*\\S+.*$/;\nconst TABLE_DELIMITER_ROW = /^[\\s|:-]*-[\\s|:-]*$/;\n\n/** Marks the slot where a protected substring was lifted out of the line. */\nconst PLACEHOLDER_OPEN = \"\\u0000\";\nconst PLACEHOLDER_CLOSE = \"\\u0001\";\nconst PLACEHOLDER_PATTERN = /\\u0000(\\d+)\\u0001/g;\n\n/** Ends a block with a full stop unless it already ends in sentence punctuation. */\nfunction withTerminalPunctuation(text: string): string {\n return /[.!?:;,…][\"')\\]]?$/.test(text) ? text : `${text}.`;\n}\n\n/** Replaces `&amp;`-style entities with the characters they stand for. */\nfunction decodeEntities(text: string): string {\n return text\n .replace(/&#(\\d{1,7});/g, (_m, code) => String.fromCodePoint(Number(code)))\n .replace(/&#[xX]([0-9a-fA-F]{1,6});/g, (_m, code) =>\n String.fromCodePoint(parseInt(code, 16))\n )\n .replace(/&([a-zA-Z]+);/g, (match, name) => ENTITIES[name.toLowerCase()] ?? match);\n}\n\n/**\n * Strips the inline marks — emphasis, code spans, links, images, raw HTML — from\n * a single line, leaving the words behind.\n */\nexport function stripInlineMarkdown(\n input: string,\n options: MarkdownToSpeechOptions = {}\n): string {\n const opts: ResolvedOptions = { ...DEFAULTS, ...options };\n const protectedRuns: string[] = [];\n const hold = (value: string): string =>\n `${PLACEHOLDER_OPEN}${protectedRuns.push(value) - 1}${PLACEHOLDER_CLOSE}`;\n\n let text = input;\n\n // Backslash escapes and code spans come out first: whatever they contain must\n // survive the emphasis pass untouched.\n text = text.replace(/\\\\([\\\\`*_{}[\\]()#+\\-.!>~|])/g, (_m, char) => hold(char));\n text = text.replace(/(`+)([^`]|[^`][\\s\\S]*?[^`])\\1(?!`)/g, (_m, _ticks, code) =>\n hold(String(code).trim())\n );\n\n text = text.replace(/<!--[\\s\\S]*?-->/g, \"\");\n\n // Images before links: `![alt](src)` is a link whose text starts with `!`.\n text = text.replace(/!\\[([^\\]]*)\\]\\([^)]*\\)/g, (_m, alt) =>\n opts.images === \"skip\" ? \"\" : String(alt)\n );\n text = text.replace(/!\\[([^\\]]*)\\]\\[[^\\]]*\\]/g, (_m, alt) =>\n opts.images === \"skip\" ? \"\" : String(alt)\n );\n\n // Footnote references carry no spoken meaning.\n text = text.replace(/\\[\\^[^\\]]+\\]/g, \"\");\n\n text = text.replace(/\\[([^\\]]*)\\]\\(\\s*<?([^\\s)]*)>?[^)]*\\)/g, (_m, label, url) =>\n opts.links === \"text-and-url\" && url ? `${label}, ${url}` : String(label)\n );\n text = text.replace(/\\[([^\\]]*)\\]\\[[^\\]]*\\]/g, \"$1\");\n\n // Autolinks: `<https://example.com>` reads better as the bare address.\n text = text.replace(/<((?:https?|mailto):[^>\\s]+)>/gi, (_m, url) =>\n opts.links === \"text-and-url\"\n ? String(url)\n : String(url).replace(/^mailto:/i, \"\")\n );\n\n // Remaining angle brackets are raw HTML tags.\n text = text.replace(/<\\/?[a-zA-Z][^>]*>/g, \"\");\n\n text = text.replace(/\\*\\*\\*(?=\\S)([\\s\\S]*?\\S)\\*\\*\\*/g, \"$1\");\n text = text.replace(/\\*\\*(?=\\S)([\\s\\S]*?\\S)\\*\\*/g, \"$1\");\n text = text.replace(/(?<![A-Za-z0-9_])__(?=\\S)([\\s\\S]*?\\S)__(?![A-Za-z0-9_])/g, \"$1\");\n text = text.replace(/~~(?=\\S)([\\s\\S]*?\\S)~~/g, \"$1\");\n text = text.replace(/\\*(?=\\S)([^*\\n]*?\\S)\\*/g, \"$1\");\n // Underscores are only emphasis between word boundaries, so `snake_case` survives.\n text = text.replace(/(?<![A-Za-z0-9_])_(?=\\S)([^_\\n]*?\\S)_(?![A-Za-z0-9_])/g, \"$1\");\n\n text = decodeEntities(text);\n text = text.replace(\n PLACEHOLDER_PATTERN,\n (_m, index) => protectedRuns[Number(index)] ?? \"\"\n );\n\n return text.replace(/[ \\t]+/g, \" \").trim();\n}\n\n/** Spoken stand-in for a fenced code block, e.g. \"TypeScript code block.\" */\nfunction announceCode(language: string): string {\n const key = language.trim().split(/[\\s,{]/)[0]?.toLowerCase() ?? \"\";\n const name = key in LANGUAGE_NAMES ? LANGUAGE_NAMES[key] : key;\n return name ? `${name} code block.` : \"Code block.\";\n}\n\n/**\n * Parses Markdown into the blocks that should be spoken, in reading order.\n *\n * Use this when the caller wants the structure — to highlight the current\n * heading, say, or to skip to a section. Callers that only need something to\n * feed a synthesizer want {@link markdownToSpeech}.\n */\nexport function markdownToSpeechSegments(\n markdown: string,\n options: MarkdownToSpeechOptions = {}\n): SpeechSegment[] {\n const opts: ResolvedOptions = { ...DEFAULTS, ...options };\n const segments: SpeechSegment[] = [];\n\n let source = (markdown ?? \"\").replace(/\\r\\n?/g, \"\\n\").replace(/\\t/g, \" \");\n source = source.replace(/<!--[\\s\\S]*?-->/g, \"\");\n\n const lines = source.split(\"\\n\");\n let index = 0;\n\n // YAML front matter: only when it opens on the very first line.\n if (!opts.frontMatter && /^---\\s*$/.test(lines[0] ?? \"\")) {\n const closing = lines.findIndex((line, i) => i > 0 && /^(---|\\.\\.\\.)\\s*$/.test(line));\n if (closing > 0) index = closing + 1;\n }\n\n /** Soft-wrapped lines of the paragraph being accumulated. */\n let paragraph: string[] = [];\n let quoting = false;\n\n const push = (type: SpeechSegmentType, text: string, level?: number): void => {\n const trimmed = text.trim();\n if (!trimmed) return;\n const spoken = opts.addTerminalPunctuation ? withTerminalPunctuation(trimmed) : trimmed;\n segments.push(level === undefined ? { type, text: spoken } : { type, text: spoken, level });\n };\n\n const flushParagraph = (): void => {\n if (paragraph.length === 0) return;\n const text = stripInlineMarkdown(paragraph.join(\" \"), opts);\n paragraph = [];\n const type = quoting ? \"quote\" : \"paragraph\";\n quoting = false;\n push(type, text);\n };\n\n for (; index < lines.length; index += 1) {\n let line = lines[index];\n\n // A fence closes any paragraph before it and swallows lines until it ends.\n const fence = FENCE_OPEN.exec(line);\n if (fence) {\n flushParagraph();\n const marker = fence[1];\n const language = fence[2] ?? \"\";\n const closingFence = new RegExp(`^ {0,3}\\\\${marker[0]}{${marker.length},}\\\\s*$`);\n const body: string[] = [];\n index += 1;\n for (; index < lines.length; index += 1) {\n if (closingFence.test(lines[index])) break;\n body.push(lines[index]);\n }\n if (opts.codeBlocks === \"announce\") {\n push(\"code\", announceCode(language));\n } else if (opts.codeBlocks === \"read\") {\n push(\"code\", body.join(\" \").replace(/\\s+/g, \" \"));\n }\n continue;\n }\n\n if (line.trim() === \"\") {\n flushParagraph();\n continue;\n }\n\n // Blockquote markers are stripped so the quoted content is parsed normally.\n let isQuote = false;\n while (/^ {0,3}>\\s?/.test(line)) {\n line = line.replace(/^ {0,3}>\\s?/, \"\");\n isQuote = true;\n }\n if (isQuote) {\n if (paragraph.length === 0) quoting = true;\n if (line.trim() === \"\") {\n flushParagraph();\n continue;\n }\n }\n\n if (THEMATIC_BREAK.test(line)) {\n flushParagraph();\n continue;\n }\n\n const heading = ATX_HEADING.exec(line);\n if (heading) {\n flushParagraph();\n if (opts.headings === \"skip\") continue;\n // A closing run of hashes (`## Title ##`) is decoration, not content.\n const text = stripInlineMarkdown((heading[2] ?? \"\").replace(/\\s+#+$/, \"\"), opts);\n if (!text) continue;\n push(\"heading\", opts.headings === \"announce\" ? `Heading: ${text}` : text, heading[1].length);\n continue;\n }\n\n // Setext heading: the underline applies to the single line above it.\n const underline = SETEXT_UNDERLINE.exec(line);\n if (underline && paragraph.length > 0 && opts.headings !== \"skip\") {\n const text = stripInlineMarkdown(paragraph.join(\" \"), opts);\n paragraph = [];\n quoting = false;\n if (text) {\n push(\n \"heading\",\n opts.headings === \"announce\" ? `Heading: ${text}` : text,\n underline[1].startsWith(\"=\") ? 1 : 2\n );\n }\n continue;\n }\n\n if (LINK_REFERENCE_DEFINITION.test(line) && paragraph.length === 0) continue;\n\n if (line.trimStart().startsWith(\"|\")) {\n flushParagraph();\n if (opts.tables === \"skip\" || TABLE_DELIMITER_ROW.test(line)) continue;\n const cells = line\n .trim()\n .replace(/^\\|/, \"\")\n .replace(/\\|$/, \"\")\n .split(/(?<!\\\\)\\|/)\n .map((cell) => stripInlineMarkdown(cell, opts))\n .filter((cell) => cell.length > 0);\n if (cells.length > 0) push(\"table-row\", cells.join(\", \"));\n continue;\n }\n\n const item = LIST_ITEM.exec(line);\n if (item) {\n flushParagraph();\n const ordered = ORDERED_ITEM.exec(line);\n // Keep the number — a listener needs it — but drop bullets and checkboxes.\n const body = (ordered ? ordered[2] : (item[1] ?? \"\")).replace(TASK_MARKER, \"\");\n const text = stripInlineMarkdown(body, opts);\n if (!text) continue;\n push(\"list-item\", ordered ? `${ordered[1]}. ${text}` : text);\n continue;\n }\n\n paragraph.push(line.trim());\n }\n\n flushParagraph();\n return segments;\n}\n\n/**\n * Converts Markdown to plain text ready for a speech synthesizer.\n *\n * Blocks are separated by blank lines so downstream chunkers (`splitTextSmart`)\n * break on them; runs of list items and table rows stay in one block so a list\n * is not chopped into one request per bullet.\n */\nexport function markdownToSpeech(\n markdown: string,\n options: MarkdownToSpeechOptions = {}\n): string {\n const segments = markdownToSpeechSegments(markdown, options);\n\n return segments.reduce((out, segment, i) => {\n if (i === 0) return segment.text;\n const previous = segments[i - 1].type;\n const runsOn =\n (segment.type === \"list-item\" || segment.type === \"table-row\") &&\n previous === segment.type;\n return `${out}${runsOn ? \"\\n\" : \"\\n\\n\"}${segment.text}`;\n }, \"\");\n}\n\n/**\n * Guesses whether a blob of text is Markdown, for callers with no filename to go\n * on (piped stdin, a paste). Errs towards `false`: prose read as Markdown is\n * mostly unchanged anyway, so only reasonably clear signals count.\n */\nexport function looksLikeMarkdown(text: string): boolean {\n if (!text) return false;\n const sample = text.slice(0, 20000);\n const signals = [\n /^ {0,3}#{1,6}\\s+\\S/m,\n /^ {0,3}(?:```|~~~)/m,\n /^ {0,3}[-+*]\\s+\\S/m,\n /^ {0,3}>\\s+\\S/m,\n /\\[[^\\]]+\\]\\([^)]+\\)/,\n /(?<![A-Za-z0-9])\\*\\*\\S[\\s\\S]*?\\S\\*\\*/,\n /^ {0,3}\\|.*\\|\\s*$/m,\n ];\n return signals.filter((pattern) => pattern.test(sample)).length >= 2;\n}\n"],"names":["DEFAULTS","LANGUAGE_NAMES","ENTITIES","ATX_HEADING","SETEXT_UNDERLINE","THEMATIC_BREAK","FENCE_OPEN","LIST_ITEM","ORDERED_ITEM","TASK_MARKER","LINK_REFERENCE_DEFINITION","TABLE_DELIMITER_ROW","PLACEHOLDER_OPEN","PLACEHOLDER_CLOSE","PLACEHOLDER_PATTERN","withTerminalPunctuation","text","decodeEntities","_m","code","match","name","stripInlineMarkdown","input","options","opts","protectedRuns","hold","value","char","_ticks","alt","label","url","index","announceCode","language","_a","key","markdownToSpeechSegments","markdown","segments","source","lines","closing","line","i","paragraph","quoting","push","type","level","trimmed","spoken","flushParagraph","fence","marker","closingFence","body","isQuote","heading","underline","cells","cell","item","ordered","markdownToSpeech","out","segment","previous","runsOn","looksLikeMarkdown","sample","pattern"],"mappings":"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"}
1
+ {"version":3,"file":"markdown.js","names":[],"sources":["../speech/utils/markdown-to-speech.ts"],"sourcesContent":["/**\n * @fileoverview Turns Markdown into text a speech synthesizer can read.\n *\n * Markdown handed straight to a TTS engine is read literally: \"hash hash Getting\n * started\", \"star star important star star\". This module parses the document\n * instead and emits only the words, keeping the *structure* the marks encoded —\n * a heading becomes its own spoken segment ending in a full stop so the\n * synthesizer pauses, a list item becomes one sentence, a fenced code block is\n * announced rather than spelled out.\n *\n * It is deliberately dependency-free and runs in the browser as well as Node, so\n * `ReadAloudController` and the CLI can share it.\n */\n\n/** Kind of block the converter recognised. */\nexport type SpeechSegmentType =\n | \"heading\"\n | \"paragraph\"\n | \"list-item\"\n | \"quote\"\n | \"code\"\n | \"table-row\";\n\nexport interface SpeechSegment {\n type: SpeechSegmentType;\n /** Spoken text of the block, with every Markdown mark already removed. */\n text: string;\n /** Heading level 1-6. Only set on `heading` segments. */\n level?: number;\n}\n\nexport interface MarkdownToSpeechOptions {\n /**\n * How headings are spoken. `text` (default) reads the heading words on their\n * own so they land between pauses; `announce` prefixes them with \"Heading:\";\n * `skip` drops them entirely.\n */\n headings?: \"text\" | \"announce\" | \"skip\";\n /**\n * What to do with fenced code blocks. `announce` (default) replaces the block\n * with a short spoken note, `read` reads the code verbatim, `skip` drops it.\n */\n codeBlocks?: \"announce\" | \"read\" | \"skip\";\n /** `text` (default) speaks the link text and drops the URL; `text-and-url` reads both. */\n links?: \"text\" | \"text-and-url\";\n /** `alt` (default) speaks the image's alt text; `skip` drops images. */\n images?: \"alt\" | \"skip\";\n /** Read the YAML front matter block. Off by default. */\n frontMatter?: boolean;\n /** `rows` (default) reads table rows as comma-separated cells; `skip` drops tables. */\n tables?: \"rows\" | \"skip\";\n /**\n * Append a full stop to blocks that do not end in punctuation, so the\n * synthesizer pauses between them instead of running them together.\n * Default true.\n */\n addTerminalPunctuation?: boolean;\n}\n\ntype ResolvedOptions = Required<MarkdownToSpeechOptions>;\n\nconst DEFAULTS: ResolvedOptions = {\n headings: \"text\",\n codeBlocks: \"announce\",\n links: \"text\",\n images: \"alt\",\n frontMatter: false,\n tables: \"rows\",\n addTerminalPunctuation: true,\n};\n\n/** Spoken names for code fence languages that would otherwise be read as letters. */\nconst LANGUAGE_NAMES: Record<string, string> = {\n js: \"JavaScript\",\n jsx: \"JavaScript\",\n mjs: \"JavaScript\",\n cjs: \"JavaScript\",\n ts: \"TypeScript\",\n tsx: \"TypeScript\",\n py: \"Python\",\n rb: \"Ruby\",\n rs: \"Rust\",\n sh: \"shell\",\n bash: \"shell\",\n zsh: \"shell\",\n shell: \"shell\",\n console: \"shell\",\n yml: \"YAML\",\n yaml: \"YAML\",\n md: \"Markdown\",\n json: \"JSON\",\n html: \"HTML\",\n css: \"CSS\",\n sql: \"SQL\",\n go: \"Go\",\n java: \"Java\",\n c: \"C\",\n cpp: \"C plus plus\",\n cs: \"C sharp\",\n php: \"PHP\",\n swift: \"Swift\",\n kt: \"Kotlin\",\n diff: \"diff\",\n text: \"\",\n txt: \"\",\n plaintext: \"\",\n};\n\nconst ENTITIES: Record<string, string> = {\n amp: \"&\",\n lt: \"<\",\n gt: \">\",\n quot: '\"',\n apos: \"'\",\n nbsp: \" \",\n mdash: \"—\",\n ndash: \"–\",\n hellip: \"…\",\n ldquo: '\"',\n rdquo: '\"',\n lsquo: \"'\",\n rsquo: \"'\",\n};\n\nconst ATX_HEADING = /^ {0,3}(#{1,6})(?:\\s+(.*?))?\\s*$/;\nconst SETEXT_UNDERLINE = /^ {0,3}(=+|-+)\\s*$/;\nconst THEMATIC_BREAK = /^ {0,3}([-*_])[ \\t]*(?:\\1[ \\t]*){2,}$/;\nconst FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})\\s*([^`]*)$/;\nconst LIST_ITEM = /^ *(?:[-+*]|\\d{1,9}[.)])(?:\\s+(.*))?$/;\nconst ORDERED_ITEM = /^ *(\\d{1,9})[.)]\\s+(.*)$/;\nconst TASK_MARKER = /^\\[([ xX])\\]\\s+/;\nconst LINK_REFERENCE_DEFINITION = /^ {0,3}\\[[^\\]]+\\]:\\s*\\S+.*$/;\nconst TABLE_DELIMITER_ROW = /^[\\s|:-]*-[\\s|:-]*$/;\n\n/** Marks the slot where a protected substring was lifted out of the line. */\nconst PLACEHOLDER_OPEN = \"\\u0000\";\nconst PLACEHOLDER_CLOSE = \"\\u0001\";\nconst PLACEHOLDER_PATTERN = /\\u0000(\\d+)\\u0001/g;\n\n/** Ends a block with a full stop unless it already ends in sentence punctuation. */\nfunction withTerminalPunctuation(text: string): string {\n return /[.!?:;,…][\"')\\]]?$/.test(text) ? text : `${text}.`;\n}\n\n/** Replaces `&amp;`-style entities with the characters they stand for. */\nfunction decodeEntities(text: string): string {\n return text\n .replace(/&#(\\d{1,7});/g, (_m, code) => String.fromCodePoint(Number(code)))\n .replace(/&#[xX]([0-9a-fA-F]{1,6});/g, (_m, code) =>\n String.fromCodePoint(parseInt(code, 16))\n )\n .replace(/&([a-zA-Z]+);/g, (match, name) => ENTITIES[name.toLowerCase()] ?? match);\n}\n\n/**\n * Strips the inline marks — emphasis, code spans, links, images, raw HTML — from\n * a single line, leaving the words behind.\n */\nexport function stripInlineMarkdown(\n input: string,\n options: MarkdownToSpeechOptions = {}\n): string {\n const opts: ResolvedOptions = { ...DEFAULTS, ...options };\n const protectedRuns: string[] = [];\n const hold = (value: string): string =>\n `${PLACEHOLDER_OPEN}${protectedRuns.push(value) - 1}${PLACEHOLDER_CLOSE}`;\n\n let text = input;\n\n // Backslash escapes and code spans come out first: whatever they contain must\n // survive the emphasis pass untouched.\n text = text.replace(/\\\\([\\\\`*_{}[\\]()#+\\-.!>~|])/g, (_m, char) => hold(char));\n text = text.replace(/(`+)([^`]|[^`][\\s\\S]*?[^`])\\1(?!`)/g, (_m, _ticks, code) =>\n hold(String(code).trim())\n );\n\n text = text.replace(/<!--[\\s\\S]*?-->/g, \"\");\n\n // Images before links: `![alt](src)` is a link whose text starts with `!`.\n text = text.replace(/!\\[([^\\]]*)\\]\\([^)]*\\)/g, (_m, alt) =>\n opts.images === \"skip\" ? \"\" : String(alt)\n );\n text = text.replace(/!\\[([^\\]]*)\\]\\[[^\\]]*\\]/g, (_m, alt) =>\n opts.images === \"skip\" ? \"\" : String(alt)\n );\n\n // Footnote references carry no spoken meaning.\n text = text.replace(/\\[\\^[^\\]]+\\]/g, \"\");\n\n text = text.replace(/\\[([^\\]]*)\\]\\(\\s*<?([^\\s)]*)>?[^)]*\\)/g, (_m, label, url) =>\n opts.links === \"text-and-url\" && url ? `${label}, ${url}` : String(label)\n );\n text = text.replace(/\\[([^\\]]*)\\]\\[[^\\]]*\\]/g, \"$1\");\n\n // Autolinks: `<https://example.com>` reads better as the bare address.\n text = text.replace(/<((?:https?|mailto):[^>\\s]+)>/gi, (_m, url) =>\n opts.links === \"text-and-url\"\n ? String(url)\n : String(url).replace(/^mailto:/i, \"\")\n );\n\n // Remaining angle brackets are raw HTML tags.\n text = text.replace(/<\\/?[a-zA-Z][^>]*>/g, \"\");\n\n text = text.replace(/\\*\\*\\*(?=\\S)([\\s\\S]*?\\S)\\*\\*\\*/g, \"$1\");\n text = text.replace(/\\*\\*(?=\\S)([\\s\\S]*?\\S)\\*\\*/g, \"$1\");\n text = text.replace(/(?<![A-Za-z0-9_])__(?=\\S)([\\s\\S]*?\\S)__(?![A-Za-z0-9_])/g, \"$1\");\n text = text.replace(/~~(?=\\S)([\\s\\S]*?\\S)~~/g, \"$1\");\n text = text.replace(/\\*(?=\\S)([^*\\n]*?\\S)\\*/g, \"$1\");\n // Underscores are only emphasis between word boundaries, so `snake_case` survives.\n text = text.replace(/(?<![A-Za-z0-9_])_(?=\\S)([^_\\n]*?\\S)_(?![A-Za-z0-9_])/g, \"$1\");\n\n text = decodeEntities(text);\n text = text.replace(\n PLACEHOLDER_PATTERN,\n (_m, index) => protectedRuns[Number(index)] ?? \"\"\n );\n\n return text.replace(/[ \\t]+/g, \" \").trim();\n}\n\n/** Spoken stand-in for a fenced code block, e.g. \"TypeScript code block.\" */\nfunction announceCode(language: string): string {\n const key = language.trim().split(/[\\s,{]/)[0]?.toLowerCase() ?? \"\";\n const name = key in LANGUAGE_NAMES ? LANGUAGE_NAMES[key] : key;\n return name ? `${name} code block.` : \"Code block.\";\n}\n\n/**\n * Parses Markdown into the blocks that should be spoken, in reading order.\n *\n * Use this when the caller wants the structure — to highlight the current\n * heading, say, or to skip to a section. Callers that only need something to\n * feed a synthesizer want {@link markdownToSpeech}.\n */\nexport function markdownToSpeechSegments(\n markdown: string,\n options: MarkdownToSpeechOptions = {}\n): SpeechSegment[] {\n const opts: ResolvedOptions = { ...DEFAULTS, ...options };\n const segments: SpeechSegment[] = [];\n\n let source = (markdown ?? \"\").replace(/\\r\\n?/g, \"\\n\").replace(/\\t/g, \" \");\n source = source.replace(/<!--[\\s\\S]*?-->/g, \"\");\n\n const lines = source.split(\"\\n\");\n let index = 0;\n\n // YAML front matter: only when it opens on the very first line.\n if (!opts.frontMatter && /^---\\s*$/.test(lines[0] ?? \"\")) {\n const closing = lines.findIndex((line, i) => i > 0 && /^(---|\\.\\.\\.)\\s*$/.test(line));\n if (closing > 0) index = closing + 1;\n }\n\n /** Soft-wrapped lines of the paragraph being accumulated. */\n let paragraph: string[] = [];\n let quoting = false;\n\n const push = (type: SpeechSegmentType, text: string, level?: number): void => {\n const trimmed = text.trim();\n if (!trimmed) return;\n const spoken = opts.addTerminalPunctuation ? withTerminalPunctuation(trimmed) : trimmed;\n segments.push(level === undefined ? { type, text: spoken } : { type, text: spoken, level });\n };\n\n const flushParagraph = (): void => {\n if (paragraph.length === 0) return;\n const text = stripInlineMarkdown(paragraph.join(\" \"), opts);\n paragraph = [];\n const type = quoting ? \"quote\" : \"paragraph\";\n quoting = false;\n push(type, text);\n };\n\n for (; index < lines.length; index += 1) {\n let line = lines[index];\n\n // A fence closes any paragraph before it and swallows lines until it ends.\n const fence = FENCE_OPEN.exec(line);\n if (fence) {\n flushParagraph();\n const marker = fence[1];\n const language = fence[2] ?? \"\";\n const closingFence = new RegExp(`^ {0,3}\\\\${marker[0]}{${marker.length},}\\\\s*$`);\n const body: string[] = [];\n index += 1;\n for (; index < lines.length; index += 1) {\n if (closingFence.test(lines[index])) break;\n body.push(lines[index]);\n }\n if (opts.codeBlocks === \"announce\") {\n push(\"code\", announceCode(language));\n } else if (opts.codeBlocks === \"read\") {\n push(\"code\", body.join(\" \").replace(/\\s+/g, \" \"));\n }\n continue;\n }\n\n if (line.trim() === \"\") {\n flushParagraph();\n continue;\n }\n\n // Blockquote markers are stripped so the quoted content is parsed normally.\n let isQuote = false;\n while (/^ {0,3}>\\s?/.test(line)) {\n line = line.replace(/^ {0,3}>\\s?/, \"\");\n isQuote = true;\n }\n if (isQuote) {\n if (paragraph.length === 0) quoting = true;\n if (line.trim() === \"\") {\n flushParagraph();\n continue;\n }\n }\n\n if (THEMATIC_BREAK.test(line)) {\n flushParagraph();\n continue;\n }\n\n const heading = ATX_HEADING.exec(line);\n if (heading) {\n flushParagraph();\n if (opts.headings === \"skip\") continue;\n // A closing run of hashes (`## Title ##`) is decoration, not content.\n const text = stripInlineMarkdown((heading[2] ?? \"\").replace(/\\s+#+$/, \"\"), opts);\n if (!text) continue;\n push(\"heading\", opts.headings === \"announce\" ? `Heading: ${text}` : text, heading[1].length);\n continue;\n }\n\n // Setext heading: the underline applies to the single line above it.\n const underline = SETEXT_UNDERLINE.exec(line);\n if (underline && paragraph.length > 0 && opts.headings !== \"skip\") {\n const text = stripInlineMarkdown(paragraph.join(\" \"), opts);\n paragraph = [];\n quoting = false;\n if (text) {\n push(\n \"heading\",\n opts.headings === \"announce\" ? `Heading: ${text}` : text,\n underline[1].startsWith(\"=\") ? 1 : 2\n );\n }\n continue;\n }\n\n if (LINK_REFERENCE_DEFINITION.test(line) && paragraph.length === 0) continue;\n\n if (line.trimStart().startsWith(\"|\")) {\n flushParagraph();\n if (opts.tables === \"skip\" || TABLE_DELIMITER_ROW.test(line)) continue;\n const cells = line\n .trim()\n .replace(/^\\|/, \"\")\n .replace(/\\|$/, \"\")\n .split(/(?<!\\\\)\\|/)\n .map((cell) => stripInlineMarkdown(cell, opts))\n .filter((cell) => cell.length > 0);\n if (cells.length > 0) push(\"table-row\", cells.join(\", \"));\n continue;\n }\n\n const item = LIST_ITEM.exec(line);\n if (item) {\n flushParagraph();\n const ordered = ORDERED_ITEM.exec(line);\n // Keep the number — a listener needs it — but drop bullets and checkboxes.\n const body = (ordered ? ordered[2] : (item[1] ?? \"\")).replace(TASK_MARKER, \"\");\n const text = stripInlineMarkdown(body, opts);\n if (!text) continue;\n push(\"list-item\", ordered ? `${ordered[1]}. ${text}` : text);\n continue;\n }\n\n paragraph.push(line.trim());\n }\n\n flushParagraph();\n return segments;\n}\n\n/**\n * Converts Markdown to plain text ready for a speech synthesizer.\n *\n * Blocks are separated by blank lines so downstream chunkers (`splitTextSmart`)\n * break on them; runs of list items and table rows stay in one block so a list\n * is not chopped into one request per bullet.\n */\nexport function markdownToSpeech(\n markdown: string,\n options: MarkdownToSpeechOptions = {}\n): string {\n const segments = markdownToSpeechSegments(markdown, options);\n\n return segments.reduce((out, segment, i) => {\n if (i === 0) return segment.text;\n const previous = segments[i - 1].type;\n const runsOn =\n (segment.type === \"list-item\" || segment.type === \"table-row\") &&\n previous === segment.type;\n return `${out}${runsOn ? \"\\n\" : \"\\n\\n\"}${segment.text}`;\n }, \"\");\n}\n\n/**\n * Guesses whether a blob of text is Markdown, for callers with no filename to go\n * on (piped stdin, a paste). Errs towards `false`: prose read as Markdown is\n * mostly unchanged anyway, so only reasonably clear signals count.\n */\nexport function looksLikeMarkdown(text: string): boolean {\n if (!text) return false;\n const sample = text.slice(0, 20000);\n const signals = [\n /^ {0,3}#{1,6}\\s+\\S/m,\n /^ {0,3}(?:```|~~~)/m,\n /^ {0,3}[-+*]\\s+\\S/m,\n /^ {0,3}>\\s+\\S/m,\n /\\[[^\\]]+\\]\\([^)]+\\)/,\n /(?<![A-Za-z0-9])\\*\\*\\S[\\s\\S]*?\\S\\*\\*/,\n /^ {0,3}\\|.*\\|\\s*$/m,\n ];\n return signals.filter((pattern) => pattern.test(sample)).length >= 2;\n}\n"],"mappings":"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"}
package/dist/node.js CHANGED
@@ -1,27 +1,4 @@
1
- import { M as o, T as s, USAGE as r, d as t, a as n, e as S, formatVoiceList as d, l as i, parseArgs as m, r as T, b as p, runCli as l, t as c } from "./cli.js";
2
- import { l as h, r as f, a as u, s as E } from "./kokoro-node-DJ_Rxp_N.js";
3
- import { looksLikeMarkdown as N, markdownToSpeech as O, markdownToSpeechSegments as w, stripInlineMarkdown as M } from "./markdown.js";
4
- export {
5
- o as MARKDOWN_EXTENSIONS,
6
- s as TEXT_EXTENSIONS,
7
- r as USAGE,
8
- t as defaultOutputPath,
9
- n as detectFormat,
10
- S as extensionOf,
11
- d as formatVoiceList,
12
- i as loadDocument,
13
- h as loadKokoroTTS,
14
- N as looksLikeMarkdown,
15
- O as markdownToSpeech,
16
- w as markdownToSpeechSegments,
17
- m as parseArgs,
18
- T as readStdinToString,
19
- p as renderDocument,
20
- f as resetKokoroCache,
21
- l as runCli,
22
- M as stripInlineMarkdown,
23
- u as synthesizeSamples,
24
- E as synthesizeWav,
25
- c as toSpeechText
26
- };
27
- //# sourceMappingURL=node.js.map
1
+ import { i as e, n as t, r as n, t as r } from "./kokoro-node-CDhCeD6u.js";
2
+ import { looksLikeMarkdown as i, markdownToSpeech as a, markdownToSpeechSegments as o, stripInlineMarkdown as s } from "./markdown.js";
3
+ import { a as c, c as l, d as u, f as d, i as f, l as p, n as m, o as h, p as g, r as _, s as v, t as y, u as b } from "./cli-CXzTD4W4.js";
4
+ export { v as MARKDOWN_EXTENSIONS, l as TEXT_EXTENSIONS, y as USAGE, c as defaultOutputPath, p as detectFormat, b as extensionOf, m as formatVoiceList, u as loadDocument, r as loadKokoroTTS, i as looksLikeMarkdown, a as markdownToSpeech, o as markdownToSpeechSegments, _ as parseArgs, d as readStdinToString, h as renderDocument, t as resetKokoroCache, f as runCli, s as stripInlineMarkdown, n as synthesizeSamples, e as synthesizeWav, g as toSpeechText };