Enforce skill-declared slide grammar against parsed kinds.
(
slide_kinds: list[str],
grammar: DeckGrammar,
result: ValidationResult,
)
| 198 | |
| 199 | |
| 200 | def _apply_grammar_checks( |
| 201 | slide_kinds: list[str], |
| 202 | grammar: DeckGrammar, |
| 203 | result: ValidationResult, |
| 204 | ) -> None: |
| 205 | """Enforce skill-declared slide grammar against parsed kinds.""" |
| 206 | kind_attr = grammar.get("kind_attr", "data-type") |
| 207 | type_set = set(slide_kinds) |
| 208 | |
| 209 | for required in grammar.get("required", []): |
| 210 | if required not in type_set: |
| 211 | result.errors.append(f'missing required slide: {kind_attr}="{required}".') |
| 212 | |
| 213 | allowed = grammar.get("allowed") |
| 214 | if allowed: |
| 215 | allowed_set = set(allowed) |
| 216 | illegal = type_set - allowed_set - {""} |
| 217 | if illegal: |
| 218 | result.errors.append( |
| 219 | f"unknown {kind_attr} value(s): {sorted(illegal)!r}. Allowed: {sorted(allowed)!r}." |
| 220 | ) |
| 221 | |
| 222 | blank = sum(1 for t in slide_kinds if t == "") |
| 223 | if blank: |
| 224 | result.errors.append( |
| 225 | f"{blank} <section class='slide'> block(s) missing {kind_attr} attribute." |
| 226 | ) |
| 227 | |
| 228 | distinct = len(type_set - {""}) |
| 229 | min_distinct = grammar.get("min_distinct") |
| 230 | if min_distinct is not None and slide_kinds and distinct < min_distinct: |
| 231 | result.warnings.append( |
| 232 | f"only {distinct} distinct {kind_attr} value(s) used; " |
| 233 | f"recommend ≥ {min_distinct} for visual variety." |
| 234 | ) |
| 235 | |
| 236 | max_run = grammar.get("max_consecutive_same") |
| 237 | if max_run is not None: |
| 238 | run = 1 |
| 239 | for prev, cur in zip(slide_kinds, slide_kinds[1:]): |
| 240 | run = run + 1 if cur == prev and cur != "" else 1 |
| 241 | if run > max_run: |
| 242 | result.warnings.append( |
| 243 | f"{run} consecutive slides with {kind_attr}={cur!r}; " |
| 244 | f"break up runs of {max_run + 1}+ same type to avoid visual monotony." |
| 245 | ) |
| 246 | break |