ssml-builder-js 2.15.0 → 2.16.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.
@@ -2015,6 +2015,7 @@ function tokenizeElements(source) {
2015
2015
  if (parent) parent.childElementCount += 1;
2016
2016
  const parentVoiceName = [...openElements].reverse().find((element) => element.voiceName)?.voiceName;
2017
2017
  const tokenName = nameMatch[1];
2018
+ const path = parent ? [...parent.path, `${tokenName}[${childElementIndex ?? 0}]`] : [tokenName];
2018
2019
  const tokenVoiceName = tokenName.toLowerCase() === "voice" ? attributes.get("name") : tokenName.toLowerCase() === "mstts:turn" ? attributes.get("voice") ?? parentVoiceName : parentVoiceName;
2019
2020
  tokens.push({
2020
2021
  attributes,
@@ -2025,12 +2026,14 @@ function tokenizeElements(source) {
2025
2026
  parentName: parent?.name,
2026
2027
  parentVoiceName,
2027
2028
  selfClosing,
2028
- start
2029
+ start,
2030
+ path
2029
2031
  });
2030
2032
  if (!selfClosing) {
2031
2033
  openElements.push({
2032
2034
  childElementCount: 0,
2033
2035
  name: tokenName,
2036
+ path,
2034
2037
  voiceName: tokenVoiceName
2035
2038
  });
2036
2039
  }
@@ -2043,13 +2046,14 @@ function location(source, offset) {
2043
2046
  const line = before.split("\n").length;
2044
2047
  return { line, column: before.length - (before.lastIndexOf("\n") + 1) + 1 };
2045
2048
  }
2046
- function addDiagnostic(diagnostics, source, offset, message, severity = "error", code) {
2049
+ function addDiagnostic(diagnostics, source, offset, message, severity = "error", code, metadata = {}) {
2047
2050
  diagnostics.push({
2048
2051
  ...location(source, offset),
2049
2052
  message,
2050
2053
  severity,
2051
2054
  source: "ssml-static-validator",
2052
- ...code ? { code } : {}
2055
+ ...code ? { code } : {},
2056
+ ...metadata
2053
2057
  });
2054
2058
  }
2055
2059
  function isSupportedProsodyRate(value) {
@@ -2522,9 +2526,11 @@ function validateAzureSsmlStatic(ssml, options = {}) {
2522
2526
  for (const token of tokens) {
2523
2527
  const tokenName = token.name.toLowerCase();
2524
2528
  const tokenVoiceName = tokenName === "voice" ? attr(token, "name")?.trim() : tokenName === "mstts:turn" ? attr(token, "voice")?.trim() || token.parentVoiceName : options.validateNestedVoices === false ? voiceName : token.parentVoiceName;
2529
+ const tokenDiagnosticStart = diagnostics.length;
2525
2530
  validateElement(token, ssml, diagnostics, tokenVoiceName, options, voiceCatalog);
2526
2531
  const definition = tokenVoiceName ? voiceCatalog.get(tokenVoiceName.toLowerCase()) : void 0;
2527
2532
  validateVoiceFeatureMatrix(token, ssml, diagnostics, tokenVoiceName, definition);
2533
+ annotateTokenDiagnostics(diagnostics, tokenDiagnosticStart, token, options, tokenVoiceName);
2528
2534
  if (tokenName === "voice" && options.model && definition?.models && !definition.models.some((model) => model.toLowerCase() === options.model?.toLowerCase())) {
2529
2535
  addDiagnostic(
2530
2536
  diagnostics,
@@ -2546,12 +2552,30 @@ function urlAttributes(token) {
2546
2552
  return value === void 0 ? [] : [{ attribute, value }];
2547
2553
  });
2548
2554
  }
2555
+ function annotateTokenDiagnostics(diagnostics, startIndex, token, options, voiceName) {
2556
+ const attributes = [...token.attributes.keys()];
2557
+ for (const diagnostic of diagnostics.slice(startIndex)) {
2558
+ const attributeName = attributes.find(
2559
+ (attribute) => new RegExp(`(?:<[^> ]+\\s+|")${attribute}(?:"|>|\\s)`, "i").test(diagnostic.message)
2560
+ );
2561
+ const nodePath = options.sourceNodePath ? [...options.sourceNodePath] : [...token.path];
2562
+ Object.assign(diagnostic, {
2563
+ range: { start: token.start, end: token.end + 1 },
2564
+ tagName: token.name,
2565
+ ...attributeName ? { attributeName } : {},
2566
+ ...voiceName ? { voiceName } : {},
2567
+ ...options.chunkIndex !== void 0 ? { chunkIndex: options.chunkIndex } : {},
2568
+ nodePath,
2569
+ targetNodePath: [...token.path]
2570
+ });
2571
+ }
2572
+ }
2549
2573
  function validateAzureSsml(ssml, options = {}) {
2550
2574
  const diagnostics = validateAzureSsmlStatic(ssml, options);
2551
2575
  const validator = options.urlValidator ?? options.customUrlValidator;
2552
2576
  if (!validator || typeof ssml !== "string") return diagnostics;
2553
2577
  const runnerOptions = options.urlValidation ?? {};
2554
- const boundedValidator = createAzureUrlValidatorRunner(validator, {
2578
+ const boundedValidator = options.urlValidatorRunner ?? createAzureUrlValidatorRunner(validator, {
2555
2579
  ...runnerOptions,
2556
2580
  ...options.urlValidatorConcurrency !== void 0 ? { concurrency: options.urlValidatorConcurrency } : {},
2557
2581
  ...options.urlValidatorTimeoutMs !== void 0 ? { timeoutMs: options.urlValidatorTimeoutMs } : {},
@@ -2576,26 +2600,46 @@ function validateAzureSsml(ssml, options = {}) {
2576
2600
  const valid = typeof result === "boolean" ? result : result.valid;
2577
2601
  if (!valid) {
2578
2602
  const reason = typeof result === "boolean" ? void 0 : result.reason;
2603
+ const diagnosticStart = diagnostics.length;
2579
2604
  addDiagnostic(
2580
2605
  diagnostics,
2581
2606
  ssml,
2582
2607
  token.start,
2583
2608
  `<${token.name} ${attribute}> was rejected by the custom URL validator${reason ? `: ${reason}` : "."}`
2584
2609
  );
2610
+ annotateTokenDiagnostics(diagnostics, diagnosticStart, token, options, token.parentVoiceName);
2585
2611
  }
2586
2612
  } catch (error) {
2587
2613
  const reason = error instanceof Error ? error.message : String(error);
2614
+ const diagnosticStart = diagnostics.length;
2588
2615
  addDiagnostic(
2589
2616
  diagnostics,
2590
2617
  ssml,
2591
2618
  token.start,
2592
2619
  `<${token.name} ${attribute}> could not be validated by the custom URL validator: ${reason}`
2593
2620
  );
2621
+ annotateTokenDiagnostics(diagnostics, diagnosticStart, token, options, token.parentVoiceName);
2594
2622
  }
2595
2623
  })
2596
2624
  );
2597
2625
  return Promise.all(checks).then(() => diagnostics);
2598
2626
  }
2627
+ async function validateAzureSsmlChunks(chunks, options = {}) {
2628
+ const validator = options.urlValidator ?? options.customUrlValidator;
2629
+ const sharedOptions = validator ? {
2630
+ ...options,
2631
+ urlValidatorRunner: options.urlValidatorRunner ?? createAzureUrlValidatorRunner(validator, {
2632
+ ...options.urlValidation ?? {},
2633
+ ...options.urlValidatorConcurrency !== void 0 ? { concurrency: options.urlValidatorConcurrency } : {},
2634
+ ...options.urlValidatorTimeoutMs !== void 0 ? { timeoutMs: options.urlValidatorTimeoutMs } : {},
2635
+ ...options.urlValidatorSignal ? { signal: options.urlValidatorSignal } : {},
2636
+ ...options.urlValidatorCache ? { cache: options.urlValidatorCache } : {}
2637
+ })
2638
+ } : options;
2639
+ return Promise.all(
2640
+ chunks.map((chunk, chunkIndex) => Promise.resolve(validateAzureSsml(chunk, { ...sharedOptions, chunkIndex })))
2641
+ );
2642
+ }
2599
2643
 
2600
2644
  // packages/ssml-core/src/generated/azureVoiceCatalog.ts
2601
2645
  var AZURE_VOICE_CATALOG_METADATA = {
@@ -2631,7 +2675,8 @@ export {
2631
2675
  normalizeAzureLanguage,
2632
2676
  areAzureLanguagesEquivalent,
2633
2677
  validateAzureSsml,
2678
+ validateAzureSsmlChunks,
2634
2679
  getAzureVoiceCatalogMetadata,
2635
2680
  getBuiltInVoiceCatalogMetadata
2636
2681
  };
2637
- //# sourceMappingURL=chunk-FXUM45ZY.mjs.map
2682
+ //# sourceMappingURL=chunk-NKLZGITR.mjs.map