ssml-builder-js 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +149 -3
- package/dist/{chunk-RUIEMCWP.mjs → chunk-4RHHW33A.mjs} +111 -15
- package/dist/chunk-4RHHW33A.mjs.map +1 -0
- package/dist/{chunk-I3BR2WCQ.mjs → chunk-ALFYHSCR.mjs} +1 -1
- package/dist/chunk-ALFYHSCR.mjs.map +1 -0
- package/dist/core.d.mts +18 -4
- package/dist/core.d.ts +18 -4
- package/dist/core.js +110 -14
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +1 -1
- package/dist/elements.js.map +1 -1
- package/dist/elements.mjs +1 -1
- package/dist/index.d.mts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +138 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +29 -3
- package/dist/index.mjs.map +1 -1
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +1 -1
- package/package.json +3 -3
- package/dist/chunk-I3BR2WCQ.mjs.map +0 -1
- package/dist/chunk-RUIEMCWP.mjs.map +0 -1
package/dist/core.d.mts
CHANGED
|
@@ -158,10 +158,18 @@ declare function validateSsml(xmlString: string): SsmlValidationError | null;
|
|
|
158
158
|
|
|
159
159
|
interface SsmlTextNodeContext {
|
|
160
160
|
parentTag: string;
|
|
161
|
+
parentAttributes: Record<string, string>;
|
|
162
|
+
ancestorTags: string[];
|
|
161
163
|
path: string[];
|
|
162
164
|
}
|
|
165
|
+
interface MapSsmlTextNodesOptions {
|
|
166
|
+
/** Element names whose text should not be passed to the transform. */
|
|
167
|
+
skipTags?: readonly string[];
|
|
168
|
+
/** Decides whether an individual text node should be passed to the transform. */
|
|
169
|
+
filter?: (context: SsmlTextNodeContext) => boolean;
|
|
170
|
+
}
|
|
163
171
|
declare function extractSsmlText(ssml: string): string[];
|
|
164
|
-
declare function mapSsmlTextNodes(ssml: string, transform: (text: string, context: SsmlTextNodeContext) => string | Promise<string
|
|
172
|
+
declare function mapSsmlTextNodes(ssml: string, transform: (text: string, context: SsmlTextNodeContext) => string | Promise<string>, options?: MapSsmlTextNodesOptions): Promise<string>;
|
|
165
173
|
|
|
166
174
|
type SsmlDiagnosticSeverity = "error" | "warning";
|
|
167
175
|
interface SsmlDiagnostic {
|
|
@@ -170,11 +178,17 @@ interface SsmlDiagnostic {
|
|
|
170
178
|
message: string;
|
|
171
179
|
severity: SsmlDiagnosticSeverity;
|
|
172
180
|
}
|
|
173
|
-
interface
|
|
181
|
+
interface AzureValidationOptions {
|
|
174
182
|
allowedAudioOrigins?: readonly string[];
|
|
183
|
+
allowExternalAudio?: boolean;
|
|
175
184
|
allowHttpAudio?: boolean;
|
|
185
|
+
customVoiceStyleMap?: Record<string, readonly string[]>;
|
|
176
186
|
maxLength?: number;
|
|
187
|
+
unknownVoicePolicy?: "error" | "warn" | "ignore";
|
|
188
|
+
validateNestedVoices?: boolean;
|
|
177
189
|
}
|
|
178
|
-
|
|
190
|
+
/** @deprecated Use AzureValidationOptions instead. */
|
|
191
|
+
type AzureSsmlValidationOptions = AzureValidationOptions;
|
|
192
|
+
declare function validateAzureSsml(ssml: string, options?: AzureValidationOptions): SsmlDiagnostic[];
|
|
179
193
|
|
|
180
|
-
export { type AudioElement, type AzureSsmlValidationOptions, type BookmarkElement, type BreakElement, type BuildPartialSsmlOptions, type CustomElement, type EmphasisElement, type ExpressAsElement, type LangElement, type LexiconElement, type MarkElement, type MsttsSilenceElement, type MsttsVisemeElement, type NamedElement, type ParagraphElement, type PhonemeElement, type ProsodyElement, type SayAsElement, type SentenceElement, type SsmlAttributeValue, type SsmlAttributes, type SsmlBreakElement, type SsmlDiagnostic, type SsmlDiagnosticSeverity, type SsmlDocument, type SsmlElement, type SsmlElementBase, type SsmlExpressAsElement, type SsmlNode, type SsmlPartialContext, type SsmlPartialProsody, type SsmlPartialVoice, type SsmlPhonemeElement, type SsmlProsodyElement, type SsmlSayAsElement, type SsmlText, type SsmlTextNodeContext, type SsmlValidationError, type SsmlVoiceElement, type SubElement, type VoiceElement, type WordElement, buildPartialSsml, buildSsml, extractSsmlText, mapSsmlTextNodes, parseSsml, validateAzureSsml, validateSsml };
|
|
194
|
+
export { type AudioElement, type AzureSsmlValidationOptions, type AzureValidationOptions, type BookmarkElement, type BreakElement, type BuildPartialSsmlOptions, type CustomElement, type EmphasisElement, type ExpressAsElement, type LangElement, type LexiconElement, type MapSsmlTextNodesOptions, type MarkElement, type MsttsSilenceElement, type MsttsVisemeElement, type NamedElement, type ParagraphElement, type PhonemeElement, type ProsodyElement, type SayAsElement, type SentenceElement, type SsmlAttributeValue, type SsmlAttributes, type SsmlBreakElement, type SsmlDiagnostic, type SsmlDiagnosticSeverity, type SsmlDocument, type SsmlElement, type SsmlElementBase, type SsmlExpressAsElement, type SsmlNode, type SsmlPartialContext, type SsmlPartialProsody, type SsmlPartialVoice, type SsmlPhonemeElement, type SsmlProsodyElement, type SsmlSayAsElement, type SsmlText, type SsmlTextNodeContext, type SsmlValidationError, type SsmlVoiceElement, type SubElement, type VoiceElement, type WordElement, buildPartialSsml, buildSsml, extractSsmlText, mapSsmlTextNodes, parseSsml, validateAzureSsml, validateSsml };
|
package/dist/core.d.ts
CHANGED
|
@@ -158,10 +158,18 @@ declare function validateSsml(xmlString: string): SsmlValidationError | null;
|
|
|
158
158
|
|
|
159
159
|
interface SsmlTextNodeContext {
|
|
160
160
|
parentTag: string;
|
|
161
|
+
parentAttributes: Record<string, string>;
|
|
162
|
+
ancestorTags: string[];
|
|
161
163
|
path: string[];
|
|
162
164
|
}
|
|
165
|
+
interface MapSsmlTextNodesOptions {
|
|
166
|
+
/** Element names whose text should not be passed to the transform. */
|
|
167
|
+
skipTags?: readonly string[];
|
|
168
|
+
/** Decides whether an individual text node should be passed to the transform. */
|
|
169
|
+
filter?: (context: SsmlTextNodeContext) => boolean;
|
|
170
|
+
}
|
|
163
171
|
declare function extractSsmlText(ssml: string): string[];
|
|
164
|
-
declare function mapSsmlTextNodes(ssml: string, transform: (text: string, context: SsmlTextNodeContext) => string | Promise<string
|
|
172
|
+
declare function mapSsmlTextNodes(ssml: string, transform: (text: string, context: SsmlTextNodeContext) => string | Promise<string>, options?: MapSsmlTextNodesOptions): Promise<string>;
|
|
165
173
|
|
|
166
174
|
type SsmlDiagnosticSeverity = "error" | "warning";
|
|
167
175
|
interface SsmlDiagnostic {
|
|
@@ -170,11 +178,17 @@ interface SsmlDiagnostic {
|
|
|
170
178
|
message: string;
|
|
171
179
|
severity: SsmlDiagnosticSeverity;
|
|
172
180
|
}
|
|
173
|
-
interface
|
|
181
|
+
interface AzureValidationOptions {
|
|
174
182
|
allowedAudioOrigins?: readonly string[];
|
|
183
|
+
allowExternalAudio?: boolean;
|
|
175
184
|
allowHttpAudio?: boolean;
|
|
185
|
+
customVoiceStyleMap?: Record<string, readonly string[]>;
|
|
176
186
|
maxLength?: number;
|
|
187
|
+
unknownVoicePolicy?: "error" | "warn" | "ignore";
|
|
188
|
+
validateNestedVoices?: boolean;
|
|
177
189
|
}
|
|
178
|
-
|
|
190
|
+
/** @deprecated Use AzureValidationOptions instead. */
|
|
191
|
+
type AzureSsmlValidationOptions = AzureValidationOptions;
|
|
192
|
+
declare function validateAzureSsml(ssml: string, options?: AzureValidationOptions): SsmlDiagnostic[];
|
|
179
193
|
|
|
180
|
-
export { type AudioElement, type AzureSsmlValidationOptions, type BookmarkElement, type BreakElement, type BuildPartialSsmlOptions, type CustomElement, type EmphasisElement, type ExpressAsElement, type LangElement, type LexiconElement, type MarkElement, type MsttsSilenceElement, type MsttsVisemeElement, type NamedElement, type ParagraphElement, type PhonemeElement, type ProsodyElement, type SayAsElement, type SentenceElement, type SsmlAttributeValue, type SsmlAttributes, type SsmlBreakElement, type SsmlDiagnostic, type SsmlDiagnosticSeverity, type SsmlDocument, type SsmlElement, type SsmlElementBase, type SsmlExpressAsElement, type SsmlNode, type SsmlPartialContext, type SsmlPartialProsody, type SsmlPartialVoice, type SsmlPhonemeElement, type SsmlProsodyElement, type SsmlSayAsElement, type SsmlText, type SsmlTextNodeContext, type SsmlValidationError, type SsmlVoiceElement, type SubElement, type VoiceElement, type WordElement, buildPartialSsml, buildSsml, extractSsmlText, mapSsmlTextNodes, parseSsml, validateAzureSsml, validateSsml };
|
|
194
|
+
export { type AudioElement, type AzureSsmlValidationOptions, type AzureValidationOptions, type BookmarkElement, type BreakElement, type BuildPartialSsmlOptions, type CustomElement, type EmphasisElement, type ExpressAsElement, type LangElement, type LexiconElement, type MapSsmlTextNodesOptions, type MarkElement, type MsttsSilenceElement, type MsttsVisemeElement, type NamedElement, type ParagraphElement, type PhonemeElement, type ProsodyElement, type SayAsElement, type SentenceElement, type SsmlAttributeValue, type SsmlAttributes, type SsmlBreakElement, type SsmlDiagnostic, type SsmlDiagnosticSeverity, type SsmlDocument, type SsmlElement, type SsmlElementBase, type SsmlExpressAsElement, type SsmlNode, type SsmlPartialContext, type SsmlPartialProsody, type SsmlPartialVoice, type SsmlPhonemeElement, type SsmlProsodyElement, type SsmlSayAsElement, type SsmlText, type SsmlTextNodeContext, type SsmlValidationError, type SsmlVoiceElement, type SubElement, type VoiceElement, type WordElement, buildPartialSsml, buildSsml, extractSsmlText, mapSsmlTextNodes, parseSsml, validateAzureSsml, validateSsml };
|
package/dist/core.js
CHANGED
|
@@ -897,6 +897,9 @@ function decodeXmlText(value) {
|
|
|
897
897
|
function encodeXmlText(value) {
|
|
898
898
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
899
899
|
}
|
|
900
|
+
function decodeXmlAttribute(value) {
|
|
901
|
+
return decodeXmlText(value);
|
|
902
|
+
}
|
|
900
903
|
function findTagEnd(source, start) {
|
|
901
904
|
let quote = "";
|
|
902
905
|
for (let index = start; index < source.length; index += 1) {
|
|
@@ -915,14 +918,31 @@ function readTagName(tag) {
|
|
|
915
918
|
const match = /^<\s*([A-Za-z_][A-Za-z0-9_.:-]*)/.exec(tag);
|
|
916
919
|
return match?.[1];
|
|
917
920
|
}
|
|
921
|
+
function readTagAttributes(tag, name) {
|
|
922
|
+
const attributes = {};
|
|
923
|
+
const nameStart = tag.indexOf(name);
|
|
924
|
+
const attributeSource = tag.slice(nameStart + name.length, tag.length - 1).replace(/\/\s*$/, "");
|
|
925
|
+
const attributePattern = /([A-Za-z_][A-Za-z0-9_.:-]*)\s*=\s*(["'])([\s\S]*?)\2/g;
|
|
926
|
+
for (const match of attributeSource.matchAll(attributePattern)) {
|
|
927
|
+
attributes[match[1].toLowerCase()] = decodeXmlAttribute(match[3]);
|
|
928
|
+
}
|
|
929
|
+
return attributes;
|
|
930
|
+
}
|
|
918
931
|
function collectTextNodes(source) {
|
|
919
932
|
const nodes = [];
|
|
920
|
-
const
|
|
933
|
+
const elements = [];
|
|
921
934
|
let index = 0;
|
|
922
935
|
const addText = (start, end, rawText, sourceStart = start, sourceEnd = end) => {
|
|
923
936
|
if (!rawText) return;
|
|
937
|
+
const path = elements.map((element) => element.name);
|
|
938
|
+
const parent = elements[elements.length - 1];
|
|
924
939
|
nodes.push({
|
|
925
|
-
context: {
|
|
940
|
+
context: {
|
|
941
|
+
ancestorTags: path.slice(0, -1),
|
|
942
|
+
parentAttributes: { ...parent?.attributes ?? {} },
|
|
943
|
+
parentTag: parent?.name ?? "",
|
|
944
|
+
path
|
|
945
|
+
},
|
|
926
946
|
decodedText: decodeXmlText(rawText),
|
|
927
947
|
end,
|
|
928
948
|
sourceEnd,
|
|
@@ -964,14 +984,14 @@ function collectTextNodes(source) {
|
|
|
964
984
|
}
|
|
965
985
|
if (source.startsWith("</", index)) {
|
|
966
986
|
const end2 = findTagEnd(source, index + 2);
|
|
967
|
-
|
|
987
|
+
elements.pop();
|
|
968
988
|
index = end2 + 1;
|
|
969
989
|
continue;
|
|
970
990
|
}
|
|
971
991
|
const end = findTagEnd(source, index + 1);
|
|
972
992
|
const tag = source.slice(index, end + 1);
|
|
973
993
|
const name = readTagName(tag);
|
|
974
|
-
if (name && !/\/\s*>$/.test(tag))
|
|
994
|
+
if (name && !/\/\s*>$/.test(tag)) elements.push({ attributes: readTagAttributes(tag, name), name });
|
|
975
995
|
index = end + 1;
|
|
976
996
|
}
|
|
977
997
|
return nodes;
|
|
@@ -980,15 +1000,21 @@ function extractSsmlText(ssml) {
|
|
|
980
1000
|
parseSsml(ssml);
|
|
981
1001
|
return collectTextNodes(ssml).map((node) => node.decodedText);
|
|
982
1002
|
}
|
|
983
|
-
async function mapSsmlTextNodes(ssml, transform) {
|
|
1003
|
+
async function mapSsmlTextNodes(ssml, transform, options = {}) {
|
|
984
1004
|
parseSsml(ssml);
|
|
985
1005
|
const nodes = collectTextNodes(ssml);
|
|
1006
|
+
const skipTags = new Set((options.skipTags ?? ["phoneme", "say-as", "sub"]).map((tag) => tag.toLowerCase()));
|
|
986
1007
|
const replacements = await Promise.all(
|
|
987
1008
|
nodes.map(async (node) => {
|
|
988
|
-
const
|
|
1009
|
+
const context = {
|
|
1010
|
+
ancestorTags: [...node.context.ancestorTags],
|
|
1011
|
+
parentAttributes: { ...node.context.parentAttributes },
|
|
989
1012
|
parentTag: node.context.parentTag,
|
|
990
1013
|
path: [...node.context.path]
|
|
991
|
-
}
|
|
1014
|
+
};
|
|
1015
|
+
const shouldTransform = !skipTags.has(context.parentTag.toLowerCase()) && (options.filter?.(context) ?? true);
|
|
1016
|
+
if (!shouldTransform) return ssml.slice(node.sourceStart, node.sourceEnd);
|
|
1017
|
+
const transformed = await transform(node.decodedText, context);
|
|
992
1018
|
if (typeof transformed !== "string") {
|
|
993
1019
|
throw new TypeError("SSML text node transform must return a string");
|
|
994
1020
|
}
|
|
@@ -1145,6 +1171,7 @@ function findTagEnd2(source, start) {
|
|
|
1145
1171
|
}
|
|
1146
1172
|
function tokenizeElements(source) {
|
|
1147
1173
|
const tokens = [];
|
|
1174
|
+
const openElements = [];
|
|
1148
1175
|
let index = 0;
|
|
1149
1176
|
while (index < source.length) {
|
|
1150
1177
|
const start = source.indexOf("<", index);
|
|
@@ -1166,8 +1193,13 @@ function tokenizeElements(source) {
|
|
|
1166
1193
|
}
|
|
1167
1194
|
const end = findTagEnd2(source, start + 1);
|
|
1168
1195
|
const raw = source.slice(start, end + 1);
|
|
1196
|
+
if (raw.startsWith("</")) {
|
|
1197
|
+
openElements.pop();
|
|
1198
|
+
index = end + 1;
|
|
1199
|
+
continue;
|
|
1200
|
+
}
|
|
1169
1201
|
const nameMatch = /^<\s*([A-Za-z_][A-Za-z0-9_.:-]*)/.exec(raw);
|
|
1170
|
-
if (!nameMatch?.[1]
|
|
1202
|
+
if (!nameMatch?.[1]) {
|
|
1171
1203
|
index = end + 1;
|
|
1172
1204
|
continue;
|
|
1173
1205
|
}
|
|
@@ -1177,7 +1209,15 @@ function tokenizeElements(source) {
|
|
|
1177
1209
|
for (const match of attributeSource.matchAll(attributePattern)) {
|
|
1178
1210
|
attributes.set(match[1].toLowerCase(), decodeAttribute(match[3]));
|
|
1179
1211
|
}
|
|
1180
|
-
|
|
1212
|
+
const selfClosing = /\/\s*>$/.test(raw);
|
|
1213
|
+
const parentVoiceName = [...openElements].reverse().find((element) => element.voiceName)?.voiceName;
|
|
1214
|
+
tokens.push({ attributes, end, name: nameMatch[1], parentVoiceName, selfClosing, start });
|
|
1215
|
+
if (!selfClosing) {
|
|
1216
|
+
openElements.push({
|
|
1217
|
+
name: nameMatch[1],
|
|
1218
|
+
voiceName: nameMatch[1].toLowerCase() === "voice" ? attributes.get("name") : parentVoiceName
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1181
1221
|
index = end + 1;
|
|
1182
1222
|
}
|
|
1183
1223
|
return tokens;
|
|
@@ -1193,7 +1233,23 @@ function addDiagnostic(diagnostics, source, offset, message, severity = "error")
|
|
|
1193
1233
|
function attr(token, name) {
|
|
1194
1234
|
return token.attributes.get(name.toLowerCase());
|
|
1195
1235
|
}
|
|
1196
|
-
function
|
|
1236
|
+
function normalizeVoiceStyleMap(customVoiceStyleMap) {
|
|
1237
|
+
const map = new Map(
|
|
1238
|
+
Object.entries(EXPRESS_AS_STYLES).map(([voiceName, styles]) => [voiceName.toLowerCase(), styles])
|
|
1239
|
+
);
|
|
1240
|
+
for (const [voiceName, styles] of Object.entries(customVoiceStyleMap ?? {})) {
|
|
1241
|
+
map.set(
|
|
1242
|
+
voiceName.toLowerCase(),
|
|
1243
|
+
styles.map((style) => style.toLowerCase())
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
return map;
|
|
1247
|
+
}
|
|
1248
|
+
function diagnosticSeverity(policy) {
|
|
1249
|
+
if (policy === "ignore") return void 0;
|
|
1250
|
+
return policy === "error" ? "error" : "warning";
|
|
1251
|
+
}
|
|
1252
|
+
function validateElement(token, source, diagnostics, voiceName, options, voiceStyleMap) {
|
|
1197
1253
|
const name = token.name.toLowerCase();
|
|
1198
1254
|
if (name === "voice" && !attr(token, "name")?.trim())
|
|
1199
1255
|
addDiagnostic(diagnostics, source, token.start, '<voice> requires a non-empty "name" attribute.');
|
|
@@ -1235,9 +1291,24 @@ function validateElement(token, source, diagnostics, voiceName, options) {
|
|
|
1235
1291
|
const role = attr(token, "role");
|
|
1236
1292
|
if (role && !ALLOWED_ROLES.has(role))
|
|
1237
1293
|
addDiagnostic(diagnostics, source, token.start, `Unsupported <mstts:express-as role> value "${role}".`);
|
|
1238
|
-
const supportedStyles = voiceName ?
|
|
1239
|
-
|
|
1240
|
-
|
|
1294
|
+
const supportedStyles = voiceName ? voiceStyleMap.get(voiceName.toLowerCase()) : void 0;
|
|
1295
|
+
const severity = diagnosticSeverity(options.unknownVoicePolicy ?? "warn");
|
|
1296
|
+
if (style && supportedStyles && !supportedStyles.includes(style.toLowerCase()) && severity)
|
|
1297
|
+
addDiagnostic(
|
|
1298
|
+
diagnostics,
|
|
1299
|
+
source,
|
|
1300
|
+
token.start,
|
|
1301
|
+
`Unknown style "${style}" is not supported by voice "${voiceName}" according to the configured voice style map.`,
|
|
1302
|
+
severity
|
|
1303
|
+
);
|
|
1304
|
+
if (style && voiceName && !supportedStyles && severity)
|
|
1305
|
+
addDiagnostic(
|
|
1306
|
+
diagnostics,
|
|
1307
|
+
source,
|
|
1308
|
+
token.start,
|
|
1309
|
+
`Unknown style "${style}" cannot be verified because voice "${voiceName}" is not registered in the voice style map.`,
|
|
1310
|
+
severity
|
|
1311
|
+
);
|
|
1241
1312
|
}
|
|
1242
1313
|
if (name === "say-as" || name === "sayas") {
|
|
1243
1314
|
const interpretAs = attr(token, "interpret-as");
|
|
@@ -1297,6 +1368,14 @@ function validateElement(token, source, diagnostics, voiceName, options) {
|
|
|
1297
1368
|
addDiagnostic(diagnostics, source, token.start, "<audio src> must use HTTPS.");
|
|
1298
1369
|
if (options.allowedAudioOrigins && !options.allowedAudioOrigins.includes(parsed.origin))
|
|
1299
1370
|
addDiagnostic(diagnostics, source, token.start, `<audio src> origin "${parsed.origin}" is not allowed.`);
|
|
1371
|
+
else if (!options.allowExternalAudio)
|
|
1372
|
+
addDiagnostic(
|
|
1373
|
+
diagnostics,
|
|
1374
|
+
source,
|
|
1375
|
+
token.start,
|
|
1376
|
+
`<audio src> external origin "${parsed.origin}" is blocked by default; set allowExternalAudio to true or provide allowedAudioOrigins.`,
|
|
1377
|
+
"error"
|
|
1378
|
+
);
|
|
1300
1379
|
}
|
|
1301
1380
|
}
|
|
1302
1381
|
}
|
|
@@ -1327,7 +1406,24 @@ function validateAzureSsml(ssml, options = {}) {
|
|
|
1327
1406
|
"Azure SSML requires at least one <voice> element under <speak>."
|
|
1328
1407
|
);
|
|
1329
1408
|
const voiceName = voices[0] ? attr(voices[0], "name") : void 0;
|
|
1330
|
-
|
|
1409
|
+
const voiceStyleMap = normalizeVoiceStyleMap(options.customVoiceStyleMap);
|
|
1410
|
+
const policySeverity = diagnosticSeverity(options.unknownVoicePolicy ?? "warn");
|
|
1411
|
+
const voicesToValidate = options.validateNestedVoices === false ? voices.slice(0, 1) : voices;
|
|
1412
|
+
for (const token of voicesToValidate) {
|
|
1413
|
+
const name = attr(token, "name")?.trim();
|
|
1414
|
+
if (name && !voiceStyleMap.has(name.toLowerCase()) && policySeverity)
|
|
1415
|
+
addDiagnostic(
|
|
1416
|
+
diagnostics,
|
|
1417
|
+
ssml,
|
|
1418
|
+
token.start,
|
|
1419
|
+
`Unknown voice "${name}" is not registered in the voice style map.`,
|
|
1420
|
+
policySeverity
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1423
|
+
for (const token of tokens) {
|
|
1424
|
+
const tokenVoiceName = options.validateNestedVoices === false ? voiceName : token.parentVoiceName;
|
|
1425
|
+
validateElement(token, ssml, diagnostics, tokenVoiceName, options, voiceStyleMap);
|
|
1426
|
+
}
|
|
1331
1427
|
return diagnostics;
|
|
1332
1428
|
}
|
|
1333
1429
|
// Annotate the CommonJS export names for ESM import in node:
|