@danmoisan/drm-copilot-mcp 1.0.26 → 1.0.27

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.
Files changed (38) hide show
  1. package/out/mcp-server.js +542 -41
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +109 -5
  4. package/resources/claude-customizations/.claude/hooks/enforce-mermaid-validation.ps1 +390 -0
  5. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +105 -2
  6. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConfig.psm1 +32 -52
  7. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +107 -99
  8. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusNormalization.psm1 +295 -0
  9. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusValidation.psm1 +9 -3
  10. package/resources/claude-customizations/.claude/lib/mermaid/MermaidGrammar.psm1 +491 -0
  11. package/resources/claude-customizations/.claude/lib/mermaid/MermaidLineScanner.psm1 +488 -0
  12. package/resources/claude-customizations/.claude/lib/mermaid/MermaidMarkdownFences.psm1 +298 -0
  13. package/resources/claude-customizations/.claude/lib/mermaid/MermaidValidation.psm1 +496 -0
  14. package/resources/claude-customizations/.claude/rules/mermaid.md +142 -0
  15. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +61 -1
  16. package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +116 -0
  17. package/resources/claude-customizations/.claude/settings.json +5 -0
  18. package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +15 -0
  19. package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
  20. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +6 -0
  21. package/resources/claude-customizations/.claude/skills/mermaid-diagram/SKILL.md +184 -0
  22. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/c4.md +50 -0
  23. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/class.md +63 -0
  24. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/er.md +56 -0
  25. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/flowchart.md +68 -0
  26. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/gantt.md +51 -0
  27. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/other-types.md +82 -0
  28. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/pie.md +32 -0
  29. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/sequence.md +63 -0
  30. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/state.md +49 -0
  31. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +8 -7
  32. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +24 -4
  33. package/resources/claude-customizations/config/blast-radius.json +8 -0
  34. package/resources/claude-customizations/pack-manifests/core.json +19 -1
  35. package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
  36. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  37. package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
  38. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +16 -1
@@ -0,0 +1,491 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Mermaid grammar reference data for the dependency-free structural validator.
4
+
5
+ .DESCRIPTION
6
+ Data-only module holding the diagram-type keyword allowlist, the per-type
7
+ arrow/edge token sets, the deep-checked type set, and the statement-keyword
8
+ exemption list used by MermaidLineScanner.psm1 and MermaidValidation.psm1.
9
+ Every export is a pure accessor: no filesystem, subprocess, network, or
10
+ wall-clock access, and no input is mutated.
11
+
12
+ Pinned documentation version: Mermaid 11.17.0.
13
+ Source: https://mermaid.js.org/intro/syntax-reference.html
14
+ (per-type pages under https://mermaid.js.org/syntax/ ; fetched 2026-08-19).
15
+
16
+ Staleness is auditable from this header. Mermaid adds diagram types several
17
+ times per year, so the allowlist is a snapshot, not a closed set: an
18
+ out-of-date allowlist costs a drift warning, never a false rejection. The one
19
+ exception is a near miss, documented at Resolve-MermaidMisspelledKeyword.
20
+
21
+ `Verified = $true` means the keyword form was read from the pinned
22
+ documentation. `Verified = $false` means the type appears in the 11.x
23
+ documentation sidebar but its exact first-line keyword form was not verified,
24
+ so it resolves with a drift warning and its body is not judged.
25
+
26
+ Only the five deep-checked types (flowchart, sequence, class, state, ER) carry
27
+ structural judgement; every other type is keyword-checked only, the fail-open
28
+ policy for free-text and plugin-backed grammars. Brackets are structural only
29
+ where they delimit node shapes or attribute blocks: a gantt task named
30
+ `Deploy (phase 1` must never be blocked as unbalanced.
31
+ #>
32
+
33
+ Set-StrictMode -Version Latest
34
+
35
+ $script:MermaidGrammarVersion = '11.17.0'
36
+ $script:MermaidGrammarSourceUrl = 'https://mermaid.js.org/intro/syntax-reference.html'
37
+
38
+ # Statement-keyword lines carry URLs, CSS declarations, and free text. They are
39
+ # exempt from BOTH the arrow rules and the bracket-balance rules; only the
40
+ # quote-termination rule may still apply. Narrowing or extending this list changes
41
+ # false-positive behavior, so it is held in one place.
42
+ $script:MermaidStatementKeyword = @(
43
+ 'click', 'style', 'classDef', 'linkStyle', 'class', 'accTitle', 'accDescr', 'title'
44
+ )
45
+
46
+ # Block and declaration keywords that are never edge statements. They are exempt
47
+ # from the arrow rules only (their bracket characters still participate in the
48
+ # balance count, which is what keeps ER and state composite blocks correct).
49
+ # A longer list here can only make the validator more permissive, never stricter.
50
+ $script:MermaidNonEdgeKeyword = @(
51
+ 'subgraph', 'end', 'direction', 'state', 'note', 'Note', 'participant',
52
+ 'actor', 'loop', 'alt', 'else', 'opt', 'par', 'and', 'critical', 'break',
53
+ 'rect', 'activate', 'deactivate', 'autonumber', 'box', 'create', 'destroy',
54
+ 'namespace', 'cssClass', 'callback', 'link', 'links', 'properties',
55
+ 'details', 'section', 'requirement', 'element'
56
+ )
57
+
58
+ # Types whose statement lines put free-text labels after the first colon. Arrow
59
+ # and quote checks apply to the pre-colon segment only for these types.
60
+ $script:MermaidPostColonLabelType = @('sequence', 'class', 'state', 'er')
61
+
62
+ <#
63
+ Arrow patterns are anchored regexes matched against a single candidate arrow
64
+ token produced by Get-MermaidArrowCandidate. They are deliberately more
65
+ permissive than the documented token list so that length variants (`---->`,
66
+ `====>`, `-...->`) and the tilde runs used by class-diagram generics never
67
+ produce a finding. The five deep entries below carry the full shape; the
68
+ keyword-accept entries are expanded from a compact map because they share one
69
+ fixed shape: keyword-checked only, brackets never structural, no arrow grammar.
70
+ #>
71
+ $script:MermaidDiagramType = [ordered]@{
72
+ flowchart = [ordered]@{
73
+ Keywords = @('flowchart', 'graph', 'flowchart-elk'); Verified = $true; Deep = $true; BracketStructural = $true
74
+ ArrowTokens = @('-->', '---', '-.->', '-.-', '==>', '===', '~~~', '--o', '--x', 'o--o', 'x--x', '<-->')
75
+ ArrowPattern = '^(?:~+|[<ox]?-{2,}[>ox]?|<?={2,}>?|-\.+-?>?|\.+-?>?)$'
76
+ }
77
+ sequence = [ordered]@{
78
+ Keywords = @('sequenceDiagram'); Verified = $true; Deep = $true; BracketStructural = $false
79
+ ArrowTokens = @('->', '-->', '->>', '-->>', '<<->>', '<<-->>', '-x', '--x', '-)', '--)')
80
+ ArrowPattern = '^(?:~+|(?:<<)?-{1,2}(?:>{1,2}|x|\)|\\|/)?)$'
81
+ }
82
+ class = [ordered]@{
83
+ Keywords = @('classDiagram', 'classDiagram-v2'); Verified = $true; Deep = $true; BracketStructural = $true
84
+ ArrowTokens = @('<|--', '--|>', '*--', '--*', 'o--', '--o', '-->', '<--', '--', '..>', '<..', '..|>', '<|..', '..')
85
+ ArrowPattern = '^(?:~+|(?:<\|?|\*|o)?(?:-{2,}|\.{2,})(?:\|>|>|\*|o)?)$'
86
+ }
87
+ state = [ordered]@{
88
+ Keywords = @('stateDiagram-v2', 'stateDiagram'); Verified = $true; Deep = $true; BracketStructural = $true
89
+ ArrowTokens = @('-->')
90
+ ArrowPattern = '^(?:~+|-{2,}>)$'
91
+ }
92
+ er = [ordered]@{
93
+ Keywords = @('erDiagram'); Verified = $true; Deep = $true; BracketStructural = $true
94
+ ArrowTokens = @('|o--o|', '||--||', '}o--o{', '}|--|{', '|o..o|', '}|..|{')
95
+ ArrowPattern = '^(?:~+|(?:\|o|\|\||\}o|\}\|)(?:-{2}|\.{2})(?:o\||\|\||o\{|\|\{))$'
96
+ }
97
+ }
98
+
99
+ # Keyword-accept types, verified against the pinned documentation. The map value is
100
+ # the documented first-line keyword form or forms. `packet` is the 11.17 keyword;
101
+ # `packet-beta` was the earlier form, retained as an alias so neither spelling
102
+ # costs a false rejection. The three types whose documentation lists edge tokens
103
+ # carry them for reference only (see the reference-token block after the expansion
104
+ # loop); no arrow judgement is ever performed on a non-deep type.
105
+ $script:MermaidVerifiedKeywordOnlyType = [ordered]@{
106
+ journey = @('journey')
107
+ gantt = @('gantt')
108
+ pie = @('pie')
109
+ quadrant = @('quadrantChart')
110
+ requirement = @('requirementDiagram')
111
+ gitgraph = @('gitGraph')
112
+ mindmap = @('mindmap')
113
+ timeline = @('timeline')
114
+ zenuml = @('zenuml')
115
+ sankey = @('sankey-beta')
116
+ xychart = @('xychart-beta')
117
+ block = @('block-beta')
118
+ packet = @('packet', 'packet-beta')
119
+ kanban = @('kanban')
120
+ architecture = @('architecture-beta')
121
+ radar = @('radar-beta')
122
+ treemap = @('treemap-beta')
123
+ c4 = @('C4Context', 'C4Container', 'C4Component', 'C4Dynamic', 'C4Deployment')
124
+ info = @('info')
125
+ }
126
+
127
+ # 11.x documentation-sidebar additions. The diagram types are documented but their
128
+ # exact first-line keyword forms were not individually verified, so they are
129
+ # keyword-accept only and always carry a drift warning.
130
+ $script:MermaidUnverifiedKeywordOnlyType = [ordered]@{
131
+ swimlanes = @('swimlanes')
132
+ eventmodeling = @('eventmodeling')
133
+ venn = @('venn')
134
+ ishikawa = @('ishikawa')
135
+ wardley = @('wardley')
136
+ cynefin = @('cynefin')
137
+ treeview = @('treeView')
138
+ railroad = @('railroad', 'railroad-beta')
139
+ }
140
+
141
+ foreach ($tier in @(
142
+ @{ Map = $script:MermaidVerifiedKeywordOnlyType; Verified = $true },
143
+ @{ Map = $script:MermaidUnverifiedKeywordOnlyType; Verified = $false })) {
144
+ foreach ($name in $tier.Map.Keys) {
145
+ $script:MermaidDiagramType[$name] = [ordered]@{
146
+ Keywords = @($tier.Map[$name]); Verified = $tier.Verified; Deep = $false; BracketStructural = $false
147
+ ArrowTokens = @()
148
+ ArrowPattern = $null
149
+ }
150
+ }
151
+ }
152
+
153
+ # Documented edge tokens for the keyword-accept types whose pages list them. These
154
+ # are reference data only: ArrowPattern stays $null, so no arrow is ever judged.
155
+ $script:MermaidDiagramType['requirement'].ArrowTokens = @('->', '<-')
156
+ $script:MermaidDiagramType['block'].ArrowTokens = @('-->', '--')
157
+ $script:MermaidDiagramType['architecture'].ArrowTokens = @('--', '-->')
158
+
159
+ function Get-MermaidGrammarVersion {
160
+ <#
161
+ .SYNOPSIS
162
+ Returns the pinned Mermaid documentation version this table snapshots.
163
+ #>
164
+ [CmdletBinding()]
165
+ [OutputType([string])]
166
+ param()
167
+ return $script:MermaidGrammarVersion
168
+ }
169
+
170
+ function Get-MermaidGrammarSourceUrl {
171
+ <#
172
+ .SYNOPSIS
173
+ Returns the documentation URL the pinned grammar table was read from.
174
+ #>
175
+ [CmdletBinding()]
176
+ [OutputType([string])]
177
+ param()
178
+ return $script:MermaidGrammarSourceUrl
179
+ }
180
+
181
+ function Get-MermaidDiagramTypeName {
182
+ <#
183
+ .SYNOPSIS
184
+ Returns the canonical diagram-type names in table order.
185
+ #>
186
+ [CmdletBinding()]
187
+ [OutputType([string[]])]
188
+ param()
189
+ return [string[]]@($script:MermaidDiagramType.Keys)
190
+ }
191
+
192
+ function Get-MermaidDiagramTypeEntry {
193
+ <#
194
+ .SYNOPSIS
195
+ Returns the grammar entry for a canonical diagram-type name, or $null.
196
+ #>
197
+ [CmdletBinding()]
198
+ [OutputType([System.Collections.Specialized.OrderedDictionary])]
199
+ param([Parameter(Mandatory)][AllowEmptyString()][string] $DiagramType)
200
+
201
+ if (-not $script:MermaidDiagramType.Contains($DiagramType)) { return $null }
202
+
203
+ return $script:MermaidDiagramType[$DiagramType]
204
+ }
205
+
206
+ function Get-MermaidDeepCheckedType {
207
+ <#
208
+ .SYNOPSIS
209
+ Returns the diagram types that receive structural judgement beyond the
210
+ first-line keyword check.
211
+ #>
212
+ [CmdletBinding()]
213
+ [OutputType([string[]])]
214
+ param()
215
+
216
+ $names = [System.Collections.Generic.List[string]]::new()
217
+ foreach ($name in $script:MermaidDiagramType.Keys) {
218
+ if ($script:MermaidDiagramType[$name].Deep) {
219
+ $names.Add($name)
220
+ }
221
+ }
222
+
223
+ return [string[]]@($names.ToArray())
224
+ }
225
+
226
+ function Test-MermaidDeepCheckedType {
227
+ <#
228
+ .SYNOPSIS
229
+ Returns $true when the supplied canonical diagram type is deep-checked.
230
+ #>
231
+ [CmdletBinding()]
232
+ [OutputType([bool])]
233
+ param([Parameter(Mandatory)][AllowEmptyString()][string] $DiagramType)
234
+
235
+ $entry = Get-MermaidDiagramTypeEntry -DiagramType $DiagramType
236
+ if ($null -eq $entry) { return $false }
237
+
238
+ return [bool]$entry.Deep
239
+ }
240
+
241
+ function Test-MermaidBracketStructuralType {
242
+ <#
243
+ .SYNOPSIS
244
+ Returns $true when brackets are structural for the supplied diagram type.
245
+ #>
246
+ [CmdletBinding()]
247
+ [OutputType([bool])]
248
+ param([Parameter(Mandatory)][AllowEmptyString()][string] $DiagramType)
249
+
250
+ $entry = Get-MermaidDiagramTypeEntry -DiagramType $DiagramType
251
+ if ($null -eq $entry) { return $false }
252
+
253
+ return [bool]$entry.BracketStructural
254
+ }
255
+
256
+ function Test-MermaidPostColonLabelType {
257
+ <#
258
+ .SYNOPSIS
259
+ Returns $true when the diagram type puts free text after the first colon.
260
+ #>
261
+ [CmdletBinding()]
262
+ [OutputType([bool])]
263
+ param([Parameter(Mandatory)][AllowEmptyString()][string] $DiagramType)
264
+
265
+ return $script:MermaidPostColonLabelType -contains $DiagramType
266
+ }
267
+
268
+ function Get-MermaidArrowToken {
269
+ <#
270
+ .SYNOPSIS
271
+ Returns the documented arrow/edge token set for a diagram type.
272
+ .DESCRIPTION
273
+ The documentation reference set. Validation uses Get-MermaidArrowPattern,
274
+ which additionally admits the documented length variants.
275
+ #>
276
+ [CmdletBinding()]
277
+ [OutputType([string[]])]
278
+ param([Parameter(Mandatory)][AllowEmptyString()][string] $DiagramType)
279
+
280
+ $entry = Get-MermaidDiagramTypeEntry -DiagramType $DiagramType
281
+ if ($null -eq $entry) { return [string[]]@() }
282
+
283
+ return [string[]]@($entry.ArrowTokens)
284
+ }
285
+
286
+ function Get-MermaidArrowPattern {
287
+ <#
288
+ .SYNOPSIS
289
+ Returns the anchored regex accepting a valid arrow token for a type.
290
+ .DESCRIPTION
291
+ Returns $null when the type carries no arrow grammar, which the caller must
292
+ treat as "do not judge arrows" rather than "reject all arrows".
293
+ #>
294
+ [CmdletBinding()]
295
+ [OutputType([string])]
296
+ param([Parameter(Mandatory)][AllowEmptyString()][string] $DiagramType)
297
+
298
+ $entry = Get-MermaidDiagramTypeEntry -DiagramType $DiagramType
299
+ if ($null -eq $entry) { return $null }
300
+
301
+ return $entry.ArrowPattern
302
+ }
303
+
304
+ function Get-MermaidStatementKeyword {
305
+ <#
306
+ .SYNOPSIS
307
+ Returns the statement keywords exempt from arrow and bracket rules.
308
+ #>
309
+ [CmdletBinding()]
310
+ [OutputType([string[]])]
311
+ param()
312
+ return [string[]]@($script:MermaidStatementKeyword)
313
+ }
314
+
315
+ function Test-MermaidStatementKeyword {
316
+ <#
317
+ .SYNOPSIS
318
+ Returns $true when a first token is an exempt statement keyword.
319
+ #>
320
+ [CmdletBinding()]
321
+ [OutputType([bool])]
322
+ param([AllowEmptyString()][string] $Token)
323
+
324
+ if ([string]::IsNullOrEmpty($Token)) { return $false }
325
+
326
+ return $script:MermaidStatementKeyword -contains $Token
327
+ }
328
+
329
+ function Test-MermaidNonEdgeKeyword {
330
+ <#
331
+ .SYNOPSIS
332
+ Returns $true when a first token opens a block or declaration.
333
+ #>
334
+ [CmdletBinding()]
335
+ [OutputType([bool])]
336
+ param([AllowEmptyString()][string] $Token)
337
+
338
+ if ([string]::IsNullOrEmpty($Token)) { return $false }
339
+
340
+ return $script:MermaidNonEdgeKeyword -contains $Token
341
+ }
342
+
343
+ function Test-MermaidPlausibleKeyword {
344
+ <#
345
+ .SYNOPSIS
346
+ Returns $true when a token is shaped like a Mermaid diagram keyword.
347
+ .DESCRIPTION
348
+ The shape rule is the version-drift safety valve: a token of letters,
349
+ digits, and hyphens beginning with a letter is treated as a plausible
350
+ keyword newer than the pinned allowlist. Only a missing or clearly
351
+ non-keyword first line is rejected outright.
352
+ #>
353
+ [CmdletBinding()]
354
+ [OutputType([bool])]
355
+ param([AllowEmptyString()][string] $Token)
356
+
357
+ if ([string]::IsNullOrEmpty($Token)) { return $false }
358
+
359
+ return [bool]($Token -cmatch '^[A-Za-z][A-Za-z0-9-]*$')
360
+ }
361
+
362
+ function Test-MermaidSingleEditDistance {
363
+ <#
364
+ .SYNOPSIS
365
+ Returns $true when two tokens differ by exactly one character edit.
366
+ .DESCRIPTION
367
+ One edit means one substitution (equal lengths, exactly one differing
368
+ position) or one insertion or deletion (lengths differing by one, where
369
+ removing one character from the longer yields the shorter). Comparison is
370
+ ordinal and case-sensitive, matching Mermaid keyword resolution.
371
+ #>
372
+ [CmdletBinding()]
373
+ [OutputType([bool])]
374
+ param(
375
+ [Parameter(Mandatory)][AllowEmptyString()][string] $First,
376
+ [Parameter(Mandatory)][AllowEmptyString()][string] $Second
377
+ )
378
+
379
+ if ([Math]::Abs($First.Length - $Second.Length) -gt 1) { return $false }
380
+
381
+ if ($First.Length -eq $Second.Length) {
382
+ $mismatch = 0
383
+ for ($index = 0; $index -lt $First.Length; $index++) {
384
+ if ($First[$index] -cne $Second[$index]) {
385
+ $mismatch++
386
+ }
387
+ if ($mismatch -gt 1) { return $false }
388
+ }
389
+ return ($mismatch -eq 1)
390
+ }
391
+
392
+ $longer = if ($First.Length -gt $Second.Length) { $First } else { $Second }
393
+ $shorter = if ($First.Length -gt $Second.Length) { $Second } else { $First }
394
+ for ($index = 0; $index -lt $longer.Length; $index++) {
395
+ if ([string]::Equals($longer.Remove($index, 1), $shorter, [System.StringComparison]::Ordinal)) { return $true }
396
+ }
397
+
398
+ return $false
399
+ }
400
+
401
+ function Resolve-MermaidMisspelledKeyword {
402
+ <#
403
+ .SYNOPSIS
404
+ Returns the known keyword a token appears to misspell, or $null.
405
+ .DESCRIPTION
406
+ Only tokens of five or more characters are considered, and only a
407
+ single-edit difference counts. The narrow radius is deliberate: a wider one
408
+ would begin catching genuinely new diagram types and convert the
409
+ version-drift warn-and-allow valve into a false rejection. A typo, by
410
+ contrast, is a defect the gate is required to name (`flowchar` for
411
+ `flowchart`).
412
+ #>
413
+ [CmdletBinding()]
414
+ [OutputType([string])]
415
+ param([AllowEmptyString()][string] $Token)
416
+
417
+ if ([string]::IsNullOrEmpty($Token) -or $Token.Length -lt 5) { return $null }
418
+
419
+ foreach ($name in $script:MermaidDiagramType.Keys) {
420
+ foreach ($keyword in $script:MermaidDiagramType[$name].Keywords) {
421
+ if ($keyword.Length -lt 5) {
422
+ continue
423
+ }
424
+ if (Test-MermaidSingleEditDistance -First $Token -Second $keyword) { return $keyword }
425
+ }
426
+ }
427
+
428
+ return $null
429
+ }
430
+
431
+ function Resolve-MermaidDiagramType {
432
+ <#
433
+ .SYNOPSIS
434
+ Resolves the declared diagram type from a candidate first line.
435
+ .DESCRIPTION
436
+ Takes the first whitespace-delimited token of the trimmed line, strips a
437
+ trailing colon or semicolon (the `gitGraph LR:` and `graph TD;` forms), and
438
+ looks it up with ordinal, case-sensitive comparison because Mermaid
439
+ keywords are case-sensitive (`C4Context`, `stateDiagram-v2`).
440
+
441
+ Returns Token (the normalized first token), Type (canonical name or $null),
442
+ IsKnown, IsVerified, IsPlausibleKeyword, and MisspelledOf (the keyword an
443
+ unresolved token appears to misspell, or $null).
444
+ #>
445
+ [CmdletBinding()]
446
+ [OutputType([System.Collections.Specialized.OrderedDictionary])]
447
+ param([AllowEmptyString()][string] $FirstLine)
448
+
449
+ $token = ''
450
+ if (-not [string]::IsNullOrWhiteSpace($FirstLine)) {
451
+ $token = (($FirstLine.Trim() -split '\s+', 2)[0]) -replace '[:;]+$', ''
452
+ }
453
+
454
+ $result = [ordered]@{
455
+ Token = $token
456
+ Type = $null
457
+ IsKnown = $false
458
+ IsVerified = $false
459
+ IsPlausibleKeyword = (Test-MermaidPlausibleKeyword -Token $token)
460
+ MisspelledOf = $null
461
+ }
462
+
463
+ if ([string]::IsNullOrEmpty($token)) { return $result }
464
+
465
+ foreach ($name in $script:MermaidDiagramType.Keys) {
466
+ $entry = $script:MermaidDiagramType[$name]
467
+ foreach ($keyword in $entry.Keywords) {
468
+ if ([string]::Equals($keyword, $token, [System.StringComparison]::Ordinal)) {
469
+ $result.Type = $name
470
+ $result.IsKnown = $true
471
+ $result.IsVerified = [bool]$entry.Verified
472
+ return $result
473
+ }
474
+ }
475
+ }
476
+
477
+ if ($result.IsPlausibleKeyword) {
478
+ $result.MisspelledOf = Resolve-MermaidMisspelledKeyword -Token $token
479
+ }
480
+
481
+ return $result
482
+ }
483
+
484
+ Export-ModuleMember -Function @(
485
+ 'Get-MermaidGrammarVersion', 'Get-MermaidGrammarSourceUrl', 'Get-MermaidDiagramTypeName',
486
+ 'Get-MermaidDiagramTypeEntry', 'Get-MermaidDeepCheckedType', 'Test-MermaidDeepCheckedType',
487
+ 'Test-MermaidBracketStructuralType', 'Test-MermaidPostColonLabelType', 'Get-MermaidArrowToken',
488
+ 'Get-MermaidArrowPattern', 'Get-MermaidStatementKeyword', 'Test-MermaidStatementKeyword',
489
+ 'Test-MermaidNonEdgeKeyword', 'Test-MermaidPlausibleKeyword', 'Test-MermaidSingleEditDistance',
490
+ 'Resolve-MermaidMisspelledKeyword', 'Resolve-MermaidDiagramType'
491
+ )