| 1 | using System.Diagnostics.CodeAnalysis; |
| 2 | using System.Text.RegularExpressions; |
| 3 | |
| 4 | namespace CascadeIDE.Features.WebAiPortal.Application; |
| 5 | |
| 6 | /// <summary> |
| 7 | /// Извлечение тела JSON команды IDE из fenced-блока Markdown с языком <c>json-cascade</c> (ADR 0108). |
| 8 | /// Модель помещает туда объект <c>{ "command_id", "args" }</c> для последующего <c>invokeCSharpAction</c>. |
| 9 | /// </summary> |
| 10 | public static partial class WebAiPortalJsonCascadeFence |
| 11 | { |
| 12 | /// <summary>Имя языка в fenced-блоке (info string после открывающих ```).</summary> |
| 13 | public const string MarkdownFenceTag = "json-cascade"; |
| 14 | |
| 15 | [GeneratedRegex( |
| 16 | """```json-cascade[ \t]*\r?\n(.*?)```""", |
| 17 | RegexOptions.Singleline | RegexOptions.CultureInvariant, |
| 18 | matchTimeoutMilliseconds: 1000)] |
| 19 | private static partial Regex FenceRegex(); |
| 20 | |
| 21 | /// <summary>Первый блок <c>```json-cascade … ```</c> в тексте; внутреннее содержимое без обрамления fence.</summary> |
| 22 | public static bool TryExtractFirst(string? markdown, [NotNullWhen(true)] out string? jsonPayload) |
| 23 | { |
| 24 | jsonPayload = null; |
| 25 | if (string.IsNullOrEmpty(markdown)) |
| 26 | return false; |
| 27 | |
| 28 | var m = FenceRegex().Match(markdown); |
| 29 | if (!m.Success || m.Groups.Count < 2) |
| 30 | return false; |
| 31 | |
| 32 | var inner = m.Groups[1].Value.Trim(); |
| 33 | if (inner.Length == 0) |
| 34 | return false; |
| 35 | |
| 36 | jsonPayload = inner; |
| 37 | return true; |
| 38 | } |
| 39 | } |
| 40 | |
View only · write via MCP/CIDE