| 1 | { |
| 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", |
| 3 | "$id": "ppt-master://schemas/spec-lock/v1", |
| 4 | "title": "PPT Master spec_lock.md", |
| 5 | "description": "Schema for the Markdown section-and-data-line model emitted by the spec-lock parser.", |
| 6 | "type": "object", |
| 7 | "required": [ |
| 8 | "canvas", |
| 9 | "communication", |
| 10 | "mode", |
| 11 | "visual_style", |
| 12 | "colors", |
| 13 | "typography", |
| 14 | "icons", |
| 15 | "page_rhythm", |
| 16 | "pptx_structure", |
| 17 | "forbidden" |
| 18 | ], |
| 19 | "properties": { |
| 20 | "canvas": {"type": "object"}, |
| 21 | "communication": {"type": "object"}, |
| 22 | "mode": {"type": "object"}, |
| 23 | "visual_style": {"type": "object"}, |
| 24 | "colors": { |
| 25 | "type": "object", |
| 26 | "properties": { |
| 27 | "image_rendering": {"type": "string"}, |
| 28 | "image_rendering_behavior": {"type": "string"}, |
| 29 | "image_rendering_references": {"type": "string"} |
| 30 | } |
| 31 | }, |
| 32 | "typography": { |
| 33 | "type": "object", |
| 34 | "properties": { |
| 35 | "font_family": {"type": "string", "minLength": 1}, |
| 36 | "title_family": {"type": "string", "minLength": 1}, |
| 37 | "body_family": {"type": "string", "minLength": 1}, |
| 38 | "subtitle_family": {"type": "string", "minLength": 1}, |
| 39 | "annotation_family": {"type": "string", "minLength": 1}, |
| 40 | "footer_family": {"type": "string", "minLength": 1}, |
| 41 | "footnote_family": {"type": "string", "minLength": 1}, |
| 42 | "data_family": {"type": "string", "minLength": 1}, |
| 43 | "emphasis_family": {"type": "string", "minLength": 1}, |
| 44 | "quote_family": {"type": "string", "minLength": 1}, |
| 45 | "code_family": {"type": "string", "minLength": 1}, |
| 46 | "body": {"type": "number"}, |
| 47 | "title": {"type": "number"} |
| 48 | } |
| 49 | }, |
| 50 | "icons": { |
| 51 | "type": "object", |
| 52 | "properties": { |
| 53 | "library": {"type": "string"}, |
| 54 | "inventory": {"type": "string"}, |
| 55 | "stroke_width": {"enum": [1.5, 2, 3]} |
| 56 | } |
| 57 | }, |
| 58 | "images": {"type": "object"}, |
| 59 | "page_rhythm": {"type": "object"}, |
| 60 | "pptx_structure": {"type": "object"}, |
| 61 | "pptx_masters": {"type": "object"}, |
| 62 | "pptx_layouts": {"type": "object"}, |
| 63 | "page_pptx_layouts": {"type": "object"}, |
| 64 | "page_layouts": {"type": "object"}, |
| 65 | "page_charts": {"type": "object"}, |
| 66 | "forbidden": {"type": "string"} |
| 67 | }, |
| 68 | "x-markdown": { |
| 69 | "version": 1, |
| 70 | "marker": "spec-lock/v1", |
| 71 | "parser": "heading-data-lines-v1", |
| 72 | "strict_lines": true, |
| 73 | "unresolved_patterns": ["(?i)\\[fill(?:[^\\]]*)\\]"], |
| 74 | "sections": [ |
| 75 | { |
| 76 | "id": "canvas", |
| 77 | "pattern": "^canvas$", |
| 78 | "required": true, |
| 79 | "required_fields": ["viewBox", "format"], |
| 80 | "allowed_fields": ["viewBox", "format"] |
| 81 | }, |
| 82 | { |
| 83 | "id": "communication", |
| 84 | "pattern": "^communication$", |
| 85 | "required": true, |
| 86 | "required_fields": [ |
| 87 | "audience", |
| 88 | "objective", |
| 89 | "core_message" |
| 90 | ], |
| 91 | "allow_empty_fields": [ |
| 92 | "audience", |
| 93 | "objective", |
| 94 | "core_message" |
| 95 | ], |
| 96 | "allowed_fields": [ |
| 97 | "primary_language", |
| 98 | "audience", |
| 99 | "objective", |
| 100 | "core_message", |
| 101 | "consumption_mode" |
| 102 | ], |
| 103 | "field_patterns": { |
| 104 | "primary_language": "^(?!und(?:-|$))(?:(?:zh(?:-[a-z]{3}){0,3}(?:-[A-Z][a-z]{3}(?:-(?:[A-Z]{2}|[0-9]{3}))?|-(?:[A-Z]{2}|[0-9]{3})))|(?:(?!zh(?:-|$))(?:[a-z]{2,3}(?:-[a-z]{3}){0,3}|[a-z]{4}|[a-z]{5,8})(?:-[A-Z][a-z]{3})?(?:-(?:[A-Z]{2}|[0-9]{3}))?))(?:-(?:[a-z0-9]{5,8}|[0-9][a-z0-9]{3}))*(?:-[0-9a-wy-z](?:-[a-z0-9]{2,8})+)*(?:-x(?:-[a-z0-9]{1,8})+)?$" |
| 105 | }, |
| 106 | "field_enums": { |
| 107 | "consumption_mode": ["text", "balanced", "presentation"] |
| 108 | } |
| 109 | }, |
| 110 | { |
| 111 | "id": "mode", |
| 112 | "pattern": "^mode$", |
| 113 | "required": true, |
| 114 | "required_fields": ["mode"], |
| 115 | "allowed_fields": ["mode", "mode_behavior", "mode_references"], |
| 116 | "field_patterns": { |
| 117 | "mode_references": "^[a-z0-9][a-z0-9-]*(?:\\s*,\\s*[a-z0-9][a-z0-9-]*)*$" |
| 118 | }, |
| 119 | "field_enums": { |
| 120 | "mode": ["pyramid", "narrative", "instructional", "showcase", "briefing", "custom"] |
| 121 | } |
| 122 | }, |
| 123 | { |
| 124 | "id": "visual_style", |
| 125 | "pattern": "^visual_style$", |
| 126 | "required": true, |
| 127 | "required_fields": ["visual_style"], |
| 128 | "allowed_fields": ["visual_style", "visual_style_behavior", "visual_style_references"], |
| 129 | "field_patterns": { |
| 130 | "visual_style_references": "^[a-z0-9][a-z0-9-]*(?:\\s*,\\s*[a-z0-9][a-z0-9-]*)*$" |
| 131 | } |
| 132 | }, |
| 133 | { |
| 134 | "id": "colors", |
| 135 | "pattern": "^colors$", |
| 136 | "required": true, |
| 137 | "min_entries": 1, |
| 138 | "field_patterns": { |
| 139 | "image_rendering_references": "^[a-z0-9][a-z0-9-]*(?:\\s*,\\s*[a-z0-9][a-z0-9-]*)*$" |
| 140 | } |
| 141 | }, |
| 142 | { |
| 143 | "id": "typography", |
| 144 | "pattern": "^typography$", |
| 145 | "required": true, |
| 146 | "required_fields": ["font_family", "body", "title"], |
| 147 | "entry_key_pattern": "^[a-z][a-z0-9_]*$", |
| 148 | "field_value_rules": [ |
| 149 | { |
| 150 | "key_pattern": "^(?:font_family|[a-z][a-z0-9_]*_family)$", |
| 151 | "value_pattern": "^\\S(?:.*\\S)?$", |
| 152 | "requirement": "be a non-empty font-family stack" |
| 153 | }, |
| 154 | { |
| 155 | "key_pattern": "^(?!font_family$)(?![a-z][a-z0-9_]*_family$)[a-z][a-z0-9_]*$", |
| 156 | "value_pattern": "^(?=.*[1-9])(?:[0-9]+(?:\\.[0-9]+)?|\\.[0-9]+)$", |
| 157 | "normalize": false, |
| 158 | "numeric": "positive_finite", |
| 159 | "requirement": "be a positive finite unitless px number" |
| 160 | } |
| 161 | ] |
| 162 | }, |
| 163 | { |
| 164 | "id": "icons", |
| 165 | "pattern": "^icons$", |
| 166 | "required": true, |
| 167 | "required_fields": ["library", "inventory"], |
| 168 | "allowed_fields": ["library", "inventory", "stroke_width"], |
| 169 | "field_enums": { |
| 170 | "stroke_width": ["1.5", "2", "3"] |
| 171 | } |
| 172 | }, |
| 173 | {"id": "images", "pattern": "^images$", "required": false}, |
| 174 | { |
| 175 | "id": "page_rhythm", |
| 176 | "pattern": "^page_rhythm$", |
| 177 | "required": true, |
| 178 | "min_entries": 1, |
| 179 | "entry_key_pattern": "^P[0-9]{2,}$", |
| 180 | "value_enum": ["anchor", "dense", "breathing"] |
| 181 | }, |
| 182 | { |
| 183 | "id": "pptx_structure", |
| 184 | "pattern": "^pptx_structure$", |
| 185 | "required": true, |
| 186 | "required_fields": ["mode"], |
| 187 | "allowed_fields": ["mode", "template_reuse_scope", "template_adherence"], |
| 188 | "field_enums": { |
| 189 | "mode": ["flat", "structured"], |
| 190 | "template_reuse_scope": ["style", "layout", "mirror"], |
| 191 | "template_adherence": ["adaptive", "strict"] |
| 192 | } |
| 193 | }, |
| 194 | { |
| 195 | "id": "pptx_masters", |
| 196 | "pattern": "^pptx_masters$", |
| 197 | "required": false, |
| 198 | "min_entries": 1, |
| 199 | "entry_key_pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$", |
| 200 | "value_pattern": "^\\S(?:.*\\S)?$" |
| 201 | }, |
| 202 | { |
| 203 | "id": "pptx_layouts", |
| 204 | "pattern": "^pptx_layouts$", |
| 205 | "required": false, |
| 206 | "min_entries": 1, |
| 207 | "entry_key_pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$", |
| 208 | "value_pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}\\s*\\|\\s*[^|]+\\s*\\|\\s*(?:template:[A-Za-z0-9._-]+|P[0-9]{2,})$" |
| 209 | }, |
| 210 | { |
| 211 | "id": "page_pptx_layouts", |
| 212 | "pattern": "^page_pptx_layouts$", |
| 213 | "required": false, |
| 214 | "min_entries": 1, |
| 215 | "entry_key_pattern": "^P[0-9]{2,}$", |
| 216 | "value_pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$" |
| 217 | }, |
| 218 | { |
| 219 | "id": "page_layouts", |
| 220 | "pattern": "^page_layouts$", |
| 221 | "required": false, |
| 222 | "min_entries": 1, |
| 223 | "entry_key_pattern": "^P[0-9]{2,}$", |
| 224 | "value_pattern": "^[A-Za-z0-9._-]+$" |
| 225 | }, |
| 226 | { |
| 227 | "id": "page_charts", |
| 228 | "pattern": "^page_charts$", |
| 229 | "required": false, |
| 230 | "min_entries": 1, |
| 231 | "entry_key_pattern": "^P[0-9]{2,}$", |
| 232 | "value_catalog": { |
| 233 | "path": "../charts/charts_index.json", |
| 234 | "pointer": ["charts"], |
| 235 | "asset_path_pattern": "../charts/{value}.svg" |
| 236 | } |
| 237 | }, |
| 238 | {"id": "forbidden", "pattern": "^forbidden$", "required": true, "min_body_chars": 1} |
| 239 | ], |
| 240 | "conditions": [ |
| 241 | { |
| 242 | "id": "custom-mode", |
| 243 | "when": {"section": "mode", "field": "mode", "equals": "custom"}, |
| 244 | "then": {"required_fields": [{"section": "mode", "fields": ["mode_behavior"]}]} |
| 245 | }, |
| 246 | { |
| 247 | "id": "custom-visual-style", |
| 248 | "when": {"section": "visual_style", "field": "visual_style", "equals": "custom"}, |
| 249 | "then": { |
| 250 | "required_fields": [{"section": "visual_style", "fields": ["visual_style_behavior"]}] |
| 251 | } |
| 252 | }, |
| 253 | { |
| 254 | "id": "custom-image-rendering", |
| 255 | "when": {"section": "colors", "field": "image_rendering", "equals": "custom"}, |
| 256 | "then": { |
| 257 | "required_fields": [{"section": "colors", "fields": ["image_rendering_behavior"]}] |
| 258 | } |
| 259 | }, |
| 260 | { |
| 261 | "id": "stroke-icon-weight", |
| 262 | "when": {"section": "icons", "field": "library", "equals": "tabler-outline"}, |
| 263 | "then": {"required_fields": [{"section": "icons", "fields": ["stroke_width"]}]} |
| 264 | }, |
| 265 | { |
| 266 | "id": "structured-pptx", |
| 267 | "when": {"section": "pptx_structure", "field": "mode", "equals": "structured"}, |
| 268 | "then": { |
| 269 | "required_sections": ["pptx_masters", "pptx_layouts", "page_pptx_layouts", "page_layouts"], |
| 270 | "required_fields": [ |
| 271 | {"section": "pptx_structure", "fields": ["template_reuse_scope", "template_adherence"]} |
| 272 | ], |
| 273 | "field_values": [ |
| 274 | { |
| 275 | "section": "pptx_structure", |
| 276 | "field": "template_reuse_scope", |
| 277 | "enum": ["layout", "mirror"] |
| 278 | } |
| 279 | ] |
| 280 | } |
| 281 | }, |
| 282 | { |
| 283 | "id": "style-is-flat", |
| 284 | "when": {"section": "pptx_structure", "field": "template_reuse_scope", "equals": "style"}, |
| 285 | "then": { |
| 286 | "field_values": [{"section": "pptx_structure", "field": "mode", "enum": ["flat"]}] |
| 287 | } |
| 288 | }, |
| 289 | { |
| 290 | "id": "layout-is-structured", |
| 291 | "when": {"section": "pptx_structure", "field": "template_reuse_scope", "equals": "layout"}, |
| 292 | "then": { |
| 293 | "field_values": [{"section": "pptx_structure", "field": "mode", "enum": ["structured"]}] |
| 294 | } |
| 295 | }, |
| 296 | { |
| 297 | "id": "mirror-is-strict", |
| 298 | "when": {"section": "pptx_structure", "field": "template_reuse_scope", "equals": "mirror"}, |
| 299 | "then": { |
| 300 | "required_fields": [ |
| 301 | {"section": "pptx_structure", "fields": ["template_adherence"]} |
| 302 | ], |
| 303 | "field_values": [ |
| 304 | {"section": "pptx_structure", "field": "mode", "enum": ["structured"]}, |
| 305 | {"section": "pptx_structure", "field": "template_adherence", "enum": ["strict"]} |
| 306 | ] |
| 307 | } |
| 308 | }, |
| 309 | { |
| 310 | "id": "flat-has-no-structured-mappings", |
| 311 | "when": {"section": "pptx_structure", "field": "mode", "equals": "flat"}, |
| 312 | "then": { |
| 313 | "forbidden_sections": [ |
| 314 | "pptx_masters", |
| 315 | "pptx_layouts", |
| 316 | "page_pptx_layouts", |
| 317 | "page_layouts" |
| 318 | ], |
| 319 | "field_values": [ |
| 320 | {"section": "pptx_structure", "field": "template_reuse_scope", "enum": ["style"]}, |
| 321 | {"section": "pptx_structure", "field": "template_adherence", "enum": []} |
| 322 | ] |
| 323 | } |
| 324 | } |
| 325 | ], |
| 326 | "references": [ |
| 327 | { |
| 328 | "id": "layout-master", |
| 329 | "from_section": "pptx_layouts", |
| 330 | "value_component": {"separator": "|", "index": 0}, |
| 331 | "target_section": "pptx_masters" |
| 332 | }, |
| 333 | { |
| 334 | "id": "page-pptx-layout", |
| 335 | "from_section": "page_pptx_layouts", |
| 336 | "target_section": "pptx_layouts" |
| 337 | }, |
| 338 | { |
| 339 | "id": "page-input-prototype", |
| 340 | "from_section": "page_layouts", |
| 341 | "asset_path_pattern": "templates/{value}.svg" |
| 342 | } |
| 343 | ] |
| 344 | } |
| 345 | } |
| 346 |