@domphy/doctor 0.17.0 → 0.18.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.
package/README.md CHANGED
@@ -42,7 +42,7 @@ console.log(format(issues))
42
42
 
43
43
  ```ts
44
44
  interface Diagnostic {
45
- rule: string // "inline-typography" | "void-content" | "missing-key" | "unknown-tag"
45
+ rule: string // one of the 12 rule ids below, e.g. "inline-typography"
46
46
  severity: "error" | "warning" | "info"
47
47
  path: string // "div > ul > li"
48
48
  message: string
@@ -52,12 +52,22 @@ interface Diagnostic {
52
52
 
53
53
  ## Rules
54
54
 
55
+ The doctor implements 12 rules:
56
+
55
57
  | Rule | Severity | Catches |
56
58
  | --- | --- | --- |
57
- | `inline-typography` | warning | `fontSize`/`lineHeight`/`fontWeight`/`letterSpacing` literals in `style` — use a typography patch |
58
- | `void-content` | error | a void tag (`input`, `img`, `br`, …) with non-null content |
59
59
  | `missing-key` | warning | a **dynamic** list (from a reactive function) of element children missing `_key` |
60
+ | `unstable-key` | warning | a dynamic list whose `_key`s are the array index (`0, 1, 2, …`) — unstable across reorders |
61
+ | `duplicate-key` | error | two sibling elements sharing the same `_key` value |
60
62
  | `unknown-tag` | warning | an element whose first key isn't a valid HTML/SVG tag (typo) |
63
+ | `void-content` | error | a void tag (`input`, `img`, `br`, …) with non-null content |
64
+ | `inline-typography` | warning | `fontSize`/`lineHeight`/`fontWeight`/`letterSpacing`/`fontFamily`/`textDecoration` literals in `style` — use a typography patch |
65
+ | `raw-theme-value` | info | a literal color (`#hex`, `rgb()`/`rgba()`) in a color `style` prop — use `themeColor()` (the hint includes an LCH-derived suggestion) |
66
+ | `raw-spacing-value` | info | a literal `rem`/`em`/`px` spacing value in a spacing `style` prop — use `themeSpacing()` |
67
+ | `unknown-tone` | warning | a `dataTone` that isn't valid tone grammar, or whose offset is out of the 18-step ramp (0–17) |
68
+ | `middle-surface-anchor` | warning | a `dataTone` of `shift-4`…`shift-13` (mid-ramp surface anchor) that may collapse child contrast |
69
+ | `unknown-density` | warning/error | a `dataDensity` that isn't valid grammar, or whose offset is out of the 5-step range (0–4) |
70
+ | `unknown-size` | warning/error | a `dataSize` that isn't valid grammar, or whose offset is out of the 8-step range (0–7) |
61
71
 
62
72
  By default the doctor **invokes reactive content functions** with a no-op listener to inspect their output (this is how `missing-key` is detected). Pass `{ runReactive: false }` if your reactive functions have side effects.
63
73
 
@@ -1,5 +1,5 @@
1
- "use strict";var Domphy=(()=>{var x=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var F=Object.prototype.hasOwnProperty;var C=(e,s)=>{for(var t in s)x(e,t,{get:s[t],enumerable:!0})},z=(e,s,t,n)=>{if(s&&typeof s=="object"||typeof s=="function")for(let r of U(s))!F.call(e,r)&&r!==t&&x(e,r,{get:()=>s[r],enumerable:!(n=P(s,r))||n.enumerable});return e};var H=e=>z(x({},"__esModule",{value:!0}),e);var at={};C(at,{doctor:()=>S});var S={};C(S,{diagnose:()=>$,fix:()=>B,format:()=>D,validate:()=>M});var b=["a","abbr","address","article","aside","audio","b","base","blockquote","br","button","canvas","caption","cite","code","col","colgroup","data","datalist","dd","del","details","dfn","dialog","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","i","iframe","img","input","ins","kbd","label","legend","li","main","map","mark","meta","meter","nav","noscript","object","ol","optgroup","option","output","p","param","picture","pre","progress","q","rp","rt","ruby","s","samp","section","select","slot","small","source","span","strong","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","title","tr","track","u","ul","var","video","wbr","bdi","bdo","math","menu","search","area","embed","hr","animate","animateMotion","animateTransform","circle","clipPath","cursor","defs","desc","ellipse","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence","filter","foreignObject","g","image","line","linearGradient","marker","mask","metadata","mpath","path","pattern","polygon","polyline","prefetch","radialGradient","rect","set","solidColor","stop","svg","switch","symbol","tbreak","text","textPath","tspan","use","view"];var w=["svg","circle","path","rect","ellipse","line","polyline","polygon","g","defs","use","symbol","linearGradient","radialGradient","stop","clipPath","mask","filter","text","tspan","textPath","image","pattern","marker","animate","animateTransform","animateMotion","feGaussianBlur","feComposite","feColorMatrix","feMerge","feMergeNode","feOffset","feFlood","feBlend","foreignObject"],v=["area","base","br","col","embed","hr","img","input","link","meta","source","track","wbr"];var q=["onAbort","onAuxClick","onBeforeMatch","onBeforeToggle","onBlur","onCancel","onCanPlay","onCanPlayThrough","onChange","onClick","onClose","onContextLost","onContextMenu","onContextRestored","onCopy","onCueChange","onCut","onDblClick","onDrag","onDragEnd","onDragEnter","onDragLeave","onDragOver","onDragStart","onDrop","onDurationChange","onEmptied","onEnded","onError","onFocus","onFormData","onInput","onInvalid","onKeyDown","onKeyPress","onKeyUp","onLoad","onLoadedData","onLoadedMetadata","onLoadStart","onMouseDown","onMouseEnter","onMouseLeave","onMouseMove","onMouseOut","onMouseOver","onMouseUp","onPaste","onPause","onPlay","onPlaying","onProgress","onRateChange","onReset","onResize","onScroll","onScrollEnd","onSecurityPolicyViolation","onSeeked","onSeeking","onSelect","onSlotChange","onStalled","onSubmit","onSuspend","onTimeUpdate","onToggle","onVolumeChange","onWaiting","onWheel","onTouchStart","onTouchMove","onTouchEnd","onTouchCancel","onPointerDown","onPointerMove","onPointerUp","onPointerCancel","onPointerEnter","onPointerLeave","onPointerOver","onPointerOut","onGotPointerCapture","onLostPointerCapture","onCompositionStart","onCompositionUpdate","onCompositionEnd","onTransitionEnd","onTransitionStart","onAnimationStart","onAnimationEnd","onAnimationIteration","onFullscreenChange","onFullscreenError","onFocusIn","onFocusOut"],ht=q.reduce((e,s)=>{let t=s.slice(2).toLowerCase();return e[t]=s,e},{});var ut=typeof process!="undefined"&&process.env!=null&&process.env.NODE_ENV!=="production";var W=e=>{let s=t=>t>.04045?Math.pow((t+.055)/1.055,2.4):t/12.92;return e.map(s)};var L=e=>{let s=parseInt(e.slice(1,3),16)/255,t=parseInt(e.slice(3,5),16)/255,n=parseInt(e.slice(5,7),16)/255;return W([s,t,n])};var N=e=>{let[s,t,n]=e,r=.4124564*s+.3575761*t+.1804375*n,i=.2126729*s+.7151522*t+.072175*n,u=.0193339*s+.119192*t+.9503041*n,l=.95047,d=1,m=1.08883,f=a=>a>.008856?Math.cbrt(a):7.787*a+16/116,p=f(r/l),g=f(i/d),o=f(u/m);return[116*g-16,500*(p-g),200*(g-o)]};var O=e=>{let[s,t,n]=e,r=Math.sqrt(t*t+n*n);if(r<1e-4)return[s,0,0];let i=(Math.atan2(n,t)*180/Math.PI+360)%360;return i>=359.9999&&(i=0),[s,r,i]};var j=e=>{let s=e.match(/\d+(\.\d+)?/g);if(!s||s.length<3)throw new Error("Invalid CSS rgb()");let t=n=>{let r=n/255;return r<=.04045?r/12.92:Math.pow((r+.055)/1.055,2.4)};return[t(Number(s[0])),t(Number(s[1])),t(Number(s[2]))]};var V=new Set([...b,...w]),G=new Set(v),K=new Set(["$","style","_key","_portal","_context","_metadata"]),Y=new Set(["fontSize","lineHeight","fontWeight","letterSpacing","fontFamily","textDecoration"]),Z=new Set(["color","backgroundColor","background","borderColor","border","outlineColor","outline","fill","stroke"]),J=/#[0-9a-fA-F]{3,8}\b|\b(?:rgba?|hsla?)\s*\(/,X=new Set(["margin","marginTop","marginRight","marginBottom","marginLeft","marginInline","marginBlock","marginInlineStart","marginInlineEnd","marginBlockStart","marginBlockEnd","padding","paddingTop","paddingRight","paddingBottom","paddingLeft","paddingInline","paddingBlock","paddingInlineStart","paddingInlineEnd","paddingBlockStart","paddingBlockEnd","gap","rowGap","columnGap"]),Q=/^(\d+(?:\.\d+)?)(rem|em|px)$/;function _(e){let s=e.match(/^(increase|decrease|shift)-(\d+)$/);return s?{family:s[1],n:parseInt(s[2],10)}:null}function tt(e){if(e==="inherit"||e==="base"||/^-?\d+$/.test(e))return!0;let s=_(e);return s?s.n<=17:!1}function et(e){try{let s=e.trim(),t;if(s.startsWith("#")){let i=s;if(i.length===9&&(i=i.slice(0,7)),i.length===5&&(i=i.slice(0,4)),i.length===4&&(i=`#${i[1]}${i[1]}${i[2]}${i[2]}${i[3]}${i[3]}`),i.length!==7)return null;t=L(i)}else if(/^rgba?\s*\(/.test(s))t=j(s);else return null;let n=N(t),r=O(n);return[r[0],r[1],r[2]]}catch(s){return null}}function st(e){let[s,t,n]=e,r=Math.round((s-50)/10),i=Math.max(-9,Math.min(9,r)),u;Math.abs(i)<=1?u='"base"':i<0?u=`"decrease-${Math.abs(i)}"`:u=`"increase-${i}"`;let l;return t<12?l="neutral":n<30||n>=330?l="error":n<75?l="warning":n<165?l="success":(n<265,l="primary"),`(l) => themeColor(l, ${u}, "${l}") [perceptual LCH L=${Math.round(s)} C=${Math.round(t)} h=${Math.round(n)}\xB0]`}function nt(e,s){let t=Q.exec(s);if(!t)return null;let n=parseFloat(t[1]),r=t[2],i;return r==="rem"||r==="em"?i=Math.round(n*4):i=Math.round(n/4),i<=0?null:`${e}: themeSpacing(${i}) \u2014 themeSpacing(n)=n/4em, so ${i}/4=${i/4}em \u2248 ${s} at default density`}function E(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function A(e){for(let s in e)if(V.has(s))return s}function $(e,s={}){let t=[];return k(e,"",t,!1,s.runReactive!==!1),t}function k(e,s,t,n,r){var g;if(typeof e=="function"){if(!r)return;let o;try{o=e(()=>{})}catch(a){return}k(o,s,t,!0,r);return}if(Array.isArray(e)){let o=e.filter(h=>E(h)&&A(h));n&&(o.length>1&&o.some(h=>h._key===void 0)&&t.push({rule:"missing-key",severity:"warning",path:s||"(list)",message:"Dynamic list child without `_key` \u2014 reordered/keyed lists need a stable `_key` for correct reconcile.",hint:"Add `_key: <stable id>` to each item produced by the reactive function."}),o.length>1&&o.every((h,c)=>h._key===c)&&t.push({rule:"unstable-key",severity:"warning",path:s||"(list)",message:"Dynamic list `_key` values are the array index (0, 1, 2, \u2026) \u2014 index keys are unstable across reorders/inserts.",hint:"Key by a stable identity from the data (e.g. `_key: item.id`), not the loop index."}));let a=new Map;for(let h of o){let c=h._key;if(c==null)continue;let y=`${typeof c}:${String(c)}`;a.set(y,((g=a.get(y))!=null?g:0)+1)}for(let[h,c]of a)if(c>1){let y=h.slice(h.indexOf(":")+1);t.push({rule:"duplicate-key",severity:"error",path:s||"(list)",message:`Duplicate \`_key\` "${y}" among ${c} siblings \u2014 keys must be unique within a list.`,hint:"Give each sibling a distinct stable `_key` (e.g. a record id, not a constant)."})}e.forEach((h,c)=>{k(h,`${s}[${c}]`,t,!1,r)});return}if(!E(e))return;let i=e,u=A(i),l=u?s?`${s} > ${u}`:u:s||"(root)";if(!u){let o=Object.keys(i).filter(a=>!K.has(a)&&!a.startsWith("_on")&&!a.startsWith("on")&&!a.startsWith("data")&&!a.startsWith("aria"));o.length===1&&t.push({rule:"unknown-tag",severity:"warning",path:l,message:`"${o[0]}" is not a known HTML/SVG tag \u2014 likely a typo.`,hint:"An element's first key must be a valid tag (div, button, span, \u2026)."});return}let d=i[u];if(G.has(u)&&d!==null&&d!==void 0&&t.push({rule:"void-content",severity:"error",path:l,message:`Void tag "${u}" must have null content (got ${Array.isArray(d)?"array":typeof d}).`,hint:`Write { ${u}: null, \u2026 } and put attributes as sibling keys.`}),E(i.style)){let o=i.style;for(let a in o){let h=o[a];if(Y.has(a)&&typeof h!="function"&&t.push({rule:"inline-typography",severity:"warning",path:l,message:`Inline \`${a}\` \u2014 avoid inline typography styles.`,hint:"Use a typography patch (paragraph()/heading()/small()/strong()/\u2026) via $ so the theme owns the type scale."}),Z.has(a)&&typeof h=="string"&&J.test(h)){let c=et(h),y=c?st(c):"(l) => themeColor(l, tone, colorName)";t.push({rule:"raw-theme-value",severity:"info",path:l,message:`Inline \`${a}\` uses a literal color (${h}).`,hint:`Prefer a theme token \u2014 ${y} \u2014 so theming and dark mode apply.`})}if(X.has(a)&&typeof h=="string"){let c=nt(a,h);c&&t.push({rule:"raw-spacing-value",severity:"info",path:l,message:`Inline \`${a}: "${h}"\` uses a literal spacing value.`,hint:`Prefer themeSpacing() for theme density: ${c}`})}}}let m=i.dataTone;if(typeof m=="string")if(!tt(m))t.push({rule:"unknown-tone",severity:"warning",path:l,message:`\`dataTone\` "${m}" is not a valid tone.`,hint:'Use "inherit", "base", a number, or "shift-N"/"increase-N"/"decrease-N" with N \u2264 17 (the ramp has 18 steps). Words like "surface"/"text" are not tones.'});else{let o=_(m);(o==null?void 0:o.family)==="shift"&&o.n>=4&&o.n<=13&&t.push({rule:"middle-surface-anchor",severity:"warning",path:l,message:`\`dataTone: "${m}"\` uses a mid-ramp surface anchor (steps 4\u201313). Child tones derived from this surface may clamp and collapse contrast.`,hint:"Prefer edge anchors: shift-0\u20133 for light surfaces, shift-14\u201317 for dark. Mid anchors are only correct for intentionally inverted/highlighted regions."})}let f=i.dataDensity;if(typeof f=="string"&&f!=="inherit"){let o=_(f);!o||o.family==="shift"?t.push({rule:"unknown-density",severity:"warning",path:l,message:`\`dataDensity\` "${f}" is not a valid density offset.`,hint:'Use "inherit", "increase-N", or "decrease-N" where N is 0\u20134. "shift-" is not valid for density.'}):o.n>4&&t.push({rule:"unknown-density",severity:"error",path:l,message:`\`dataDensity\` "${f}" N=${o.n} is out of range \u2014 the density scale has 5 steps (max offset: 4).`,hint:'Use "increase-N" or "decrease-N" where N \u2264 4. Density factors: [0.75, 1, 1.5, 2, 2.5].'})}let p=i.dataSize;if(typeof p=="string"&&p!=="inherit"){let o=_(p);!o||o.family==="shift"?t.push({rule:"unknown-size",severity:"warning",path:l,message:`\`dataSize\` "${p}" is not a valid size offset.`,hint:'Use "inherit", "increase-N", or "decrease-N" where N is 0\u20137. "shift-" is not valid for size.'}):o.n>7&&t.push({rule:"unknown-size",severity:"error",path:l,message:`\`dataSize\` "${p}" N=${o.n} is out of range \u2014 the size scale has 8 steps (max offset: 7).`,hint:'Use "increase-N" or "decrease-N" where N \u2264 7.'})}k(d,l,t,!1,r)}function M(e,s={}){let t=$(e,s),n={error:0,warning:0,info:0,total:t.length};for(let r of t)n[r.severity]+=1;return{ok:n.error===0,issues:t,summary:n}}function D(e){if(e.length===0)return"\u2713 No issues found.";let s=t=>t==="error"?"\u2717":t==="warning"?"\u26A0":"i";return e.map(t=>`${s(t.severity)} [${t.rule}] ${t.path}
1
+ "use strict";var Domphy=(()=>{var E=Object.defineProperty;var F=Object.getOwnPropertyDescriptor;var z=Object.getOwnPropertyNames;var H=Object.prototype.hasOwnProperty;var C=(s,e)=>{for(var t in e)E(s,t,{get:e[t],enumerable:!0})},q=(s,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of z(e))!H.call(s,o)&&o!==t&&E(s,o,{get:()=>e[o],enumerable:!(i=F(e,o))||i.enumerable});return s};var W=s=>q(E({},"__esModule",{value:!0}),s);var at={};C(at,{doctor:()=>S});var S={};C(S,{diagnose:()=>$,fix:()=>P,format:()=>I,validate:()=>x});var V=s=>{let e=t=>t>.04045?Math.pow((t+.055)/1.055,2.4):t/12.92;return s.map(e)};var L=s=>{let e=parseInt(s.slice(1,3),16)/255,t=parseInt(s.slice(3,5),16)/255,i=parseInt(s.slice(5,7),16)/255;return V([e,t,i])};var N=s=>{let[e,t,i]=s,o=.4124564*e+.3575761*t+.1804375*i,n=.2126729*e+.7151522*t+.072175*i,u=.0193339*e+.119192*t+.9503041*i,l=.95047,d=1,m=1.08883,f=r=>r>.008856?Math.cbrt(r):7.787*r+16/116,p=f(o/l),b=f(n/d),v=f(u/m);return[116*b-16,500*(p-b),200*(b-v)]};var O=s=>{let[e,t,i]=s,o=Math.sqrt(t*t+i*i);if(o<1e-4)return[e,0,0];let n=(Math.atan2(i,t)*180/Math.PI+360)%360;return n>=359.9999&&(n=0),[e,o,n]};var j=s=>{let e=s.match(/\d+(\.\d+)?/g);if(!e||e.length<3)throw new Error("Invalid CSS rgb()");let t=i=>{let o=i/255;return o<=.04045?o/12.92:Math.pow((o+.055)/1.055,2.4)};return[t(Number(e[0])),t(Number(e[1])),t(Number(e[2]))]};var D=["a","abbr","address","article","aside","audio","b","base","blockquote","br","button","canvas","caption","cite","code","col","colgroup","data","datalist","dd","del","details","dfn","dialog","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","i","iframe","img","input","ins","kbd","label","legend","li","main","map","mark","meta","meter","nav","noscript","object","ol","optgroup","option","output","p","param","picture","pre","progress","q","rp","rt","ruby","s","samp","section","select","slot","small","source","span","strong","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","title","tr","track","u","ul","var","video","wbr","bdi","bdo","math","menu","search","area","embed","hr","animate","animateMotion","animateTransform","circle","clipPath","cursor","defs","desc","ellipse","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence","filter","foreignObject","g","image","line","linearGradient","marker","mask","metadata","mpath","path","pattern","polygon","polyline","prefetch","radialGradient","rect","set","solidColor","stop","svg","switch","symbol","tbreak","text","textPath","tspan","use","view"];var A=["svg","circle","path","rect","ellipse","line","polyline","polygon","g","defs","use","symbol","linearGradient","radialGradient","stop","clipPath","mask","filter","text","tspan","textPath","image","pattern","marker","animate","animateTransform","animateMotion","feGaussianBlur","feComposite","feColorMatrix","feMerge","feMergeNode","feOffset","feFlood","feBlend","foreignObject"],B=["area","base","br","col","embed","hr","img","input","link","meta","source","track","wbr"];var G=["onAbort","onAuxClick","onBeforeMatch","onBeforeToggle","onBlur","onCancel","onCanPlay","onCanPlayThrough","onChange","onClick","onClose","onContextLost","onContextMenu","onContextRestored","onCopy","onCueChange","onCut","onDblClick","onDrag","onDragEnd","onDragEnter","onDragLeave","onDragOver","onDragStart","onDrop","onDurationChange","onEmptied","onEnded","onError","onFocus","onFormData","onInput","onInvalid","onKeyDown","onKeyPress","onKeyUp","onLoad","onLoadedData","onLoadedMetadata","onLoadStart","onMouseDown","onMouseEnter","onMouseLeave","onMouseMove","onMouseOut","onMouseOver","onMouseUp","onPaste","onPause","onPlay","onPlaying","onProgress","onRateChange","onReset","onResize","onScroll","onScrollEnd","onSecurityPolicyViolation","onSeeked","onSeeking","onSelect","onSlotChange","onStalled","onSubmit","onSuspend","onTimeUpdate","onToggle","onVolumeChange","onWaiting","onWheel","onTouchStart","onTouchMove","onTouchEnd","onTouchCancel","onPointerDown","onPointerMove","onPointerUp","onPointerCancel","onPointerEnter","onPointerLeave","onPointerOver","onPointerOut","onGotPointerCapture","onLostPointerCapture","onCompositionStart","onCompositionUpdate","onCompositionEnd","onTransitionEnd","onTransitionStart","onAnimationStart","onAnimationEnd","onAnimationIteration","onFullscreenChange","onFullscreenError","onFocusIn","onFocusOut"],ut=G.reduce((s,e)=>{let t=e.slice(2).toLowerCase();return s[t]=e,s},{});var ct=typeof process!="undefined"&&process.env!=null&&process.env.NODE_ENV!=="production";var K=new Set([...D,...A]),w=new Set(B);function y(s){return typeof s=="object"&&s!==null&&!Array.isArray(s)}function _(s){for(let e in s)if(K.has(e))return e}var Y=new Set(["$","style","_key","_portal","_context","_metadata"]),Z=new Set(["fontSize","lineHeight","fontWeight","letterSpacing","fontFamily","textDecoration"]),J=new Set(["color","backgroundColor","background","borderColor","border","outlineColor","outline","fill","stroke"]),X=/#[0-9a-fA-F]{3,8}\b|\b(?:rgba?|hsla?)\s*\(/,Q=new Set(["margin","marginTop","marginRight","marginBottom","marginLeft","marginInline","marginBlock","marginInlineStart","marginInlineEnd","marginBlockStart","marginBlockEnd","padding","paddingTop","paddingRight","paddingBottom","paddingLeft","paddingInline","paddingBlock","paddingInlineStart","paddingInlineEnd","paddingBlockStart","paddingBlockEnd","gap","rowGap","columnGap"]),tt=/^(\d+(?:\.\d+)?)(rem|em|px)$/;function k(s){let e=s.match(/^(increase|decrease|shift)-(\d+)$/);return e?{family:e[1],n:parseInt(e[2],10)}:null}function et(s){if(s==="inherit"||s==="base"||/^-?\d+$/.test(s))return!0;let e=k(s);return e?e.n<=17:!1}function st(s){try{let e=s.trim(),t;if(e.startsWith("#")){let n=e;if(n.length===9&&(n=n.slice(0,7)),n.length===5&&(n=n.slice(0,4)),n.length===4&&(n=`#${n[1]}${n[1]}${n[2]}${n[2]}${n[3]}${n[3]}`),n.length!==7)return null;t=L(n)}else if(/^rgba?\s*\(/.test(e))t=j(e);else return null;let i=N(t),o=O(i);return[o[0],o[1],o[2]]}catch(e){return null}}var it=/#[0-9a-fA-F]{3,8}\b|rgba?\s*\([^)]*\)/;function nt(s){let e=it.exec(s);return e?e[0]:null}function rt(s){let[e,t,i]=s,o=Math.round((e-50)/10),n=Math.max(-9,Math.min(9,o)),u;Math.abs(n)<=1?u='"base"':n<0?u=`"decrease-${Math.abs(n)}"`:u=`"increase-${n}"`;let l;return t<12?l="neutral":i<30||i>=330?l="error":i<75?l="warning":i<165?l="success":(i<265,l="primary"),`(l) => themeColor(l, ${u}, "${l}") [perceptual LCH L=${Math.round(e)} C=${Math.round(t)} h=${Math.round(i)}\xB0]`}function ot(s,e){let t=tt.exec(e);if(!t)return null;let i=parseFloat(t[1]),o=t[2],n;return o==="rem"||o==="em"?n=Math.round(i*4):n=Math.round(i/4),n<=0?null:`${s}: themeSpacing(${n}) \u2014 themeSpacing(n)=n/4em, so ${n}/4=${n/4}em \u2248 ${e} at default density`}function $(s,e={}){let t=[];return M(s,"",t,!1,e.runReactive!==!1),t}function M(s,e,t,i,o){var b,v;if(typeof s=="function"){if(!o)return;let r;try{r=s(()=>{})}catch(h){return}M(r,e,t,!0,o);return}if(Array.isArray(s)){let r=s.filter(a=>y(a)&&_(a));i&&(r.length>1&&r.some(a=>a._key===void 0)&&t.push({rule:"missing-key",severity:"warning",path:e||"(list)",message:"Dynamic list child without `_key` \u2014 reordered/keyed lists need a stable `_key` for correct reconcile.",hint:"Add `_key: <stable id>` to each item produced by the reactive function."}),r.length>1&&r.every((a,c)=>a._key===c)&&t.push({rule:"unstable-key",severity:"warning",path:e||"(list)",message:"Dynamic list `_key` values are the array index (0, 1, 2, \u2026) \u2014 index keys are unstable across reorders/inserts.",hint:"Key by a stable identity from the data (e.g. `_key: item.id`), not the loop index."}));let h=new Map;for(let a of r){let c=a._key;if(c==null)continue;let g=`${typeof c}:${String(c)}`;h.set(g,((b=h.get(g))!=null?b:0)+1)}for(let[a,c]of h)if(c>1){let g=a.slice(a.indexOf(":")+1);t.push({rule:"duplicate-key",severity:"error",path:e||"(list)",message:`Duplicate \`_key\` "${g}" among ${c} siblings \u2014 keys must be unique within a list.`,hint:"Give each sibling a distinct stable `_key` (e.g. a record id, not a constant)."})}s.forEach((a,c)=>{M(a,`${e}[${c}]`,t,!1,o)});return}if(!y(s))return;let n=s,u=_(n),l=u?e?`${e} > ${u}`:u:e||"(root)";if(!u){let r=Object.keys(n).filter(h=>!Y.has(h)&&!h.startsWith("_on")&&!h.startsWith("on")&&!h.startsWith("data")&&!h.startsWith("aria"));r.length===1&&t.push({rule:"unknown-tag",severity:"warning",path:l,message:`"${r[0]}" is not a known HTML/SVG tag \u2014 likely a typo.`,hint:"An element's first key must be a valid tag (div, button, span, \u2026)."});return}let d=n[u];if(w.has(u)&&d!==null&&d!==void 0&&t.push({rule:"void-content",severity:"error",path:l,message:`Void tag "${u}" must have null content (got ${Array.isArray(d)?"array":typeof d}).`,hint:`Write { ${u}: null, \u2026 } and put attributes as sibling keys.`}),y(n.style)){let r=n.style;for(let h in r){let a=r[h];if(Z.has(h)&&typeof a!="function"&&t.push({rule:"inline-typography",severity:"warning",path:l,message:`Inline \`${h}\` \u2014 avoid inline typography styles.`,hint:"Use a typography patch (paragraph()/heading()/small()/strong()/\u2026) via $ so the theme owns the type scale."}),J.has(h)&&typeof a=="string"&&X.test(a)){let c=(v=nt(a))!=null?v:a,g=st(c),U=g?rt(g):"(l) => themeColor(l, tone, colorName)";t.push({rule:"raw-theme-value",severity:"info",path:l,message:`Inline \`${h}\` uses a literal color (${a}).`,hint:`Prefer a theme token \u2014 ${U} \u2014 so theming and dark mode apply.`})}if(Q.has(h)&&typeof a=="string"){let c=ot(h,a);c&&t.push({rule:"raw-spacing-value",severity:"info",path:l,message:`Inline \`${h}: "${a}"\` uses a literal spacing value.`,hint:`Prefer themeSpacing() for theme density: ${c}`})}}}let m=n.dataTone;if(typeof m=="string")if(!et(m))t.push({rule:"unknown-tone",severity:"warning",path:l,message:`\`dataTone\` "${m}" is not a valid tone.`,hint:'Use "inherit", "base", a number, or "shift-N"/"increase-N"/"decrease-N" with N \u2264 17 (the ramp has 18 steps). Words like "surface"/"text" are not tones.'});else{let r=k(m);(r==null?void 0:r.family)==="shift"&&r.n>=4&&r.n<=13&&t.push({rule:"middle-surface-anchor",severity:"warning",path:l,message:`\`dataTone: "${m}"\` uses a mid-ramp surface anchor (steps 4\u201313). Child tones derived from this surface may clamp and collapse contrast.`,hint:"Prefer edge anchors: shift-0\u20133 for light surfaces, shift-14\u201317 for dark. Mid anchors are only correct for intentionally inverted/highlighted regions."})}let f=n.dataDensity;if(typeof f=="string"&&f!=="inherit"){let r=k(f);!r||r.family==="shift"?t.push({rule:"unknown-density",severity:"warning",path:l,message:`\`dataDensity\` "${f}" is not a valid density offset.`,hint:'Use "inherit", "increase-N", or "decrease-N" where N is 0\u20134. "shift-" is not valid for density.'}):r.n>4&&t.push({rule:"unknown-density",severity:"error",path:l,message:`\`dataDensity\` "${f}" N=${r.n} is out of range \u2014 the density scale has 5 steps (max offset: 4).`,hint:'Use "increase-N" or "decrease-N" where N \u2264 4. Density factors: [0.75, 1, 1.5, 2, 2.5].'})}let p=n.dataSize;if(typeof p=="string"&&p!=="inherit"){let r=k(p);!r||r.family==="shift"?t.push({rule:"unknown-size",severity:"warning",path:l,message:`\`dataSize\` "${p}" is not a valid size offset.`,hint:'Use "inherit", "increase-N", or "decrease-N" where N is 0\u20137. "shift-" is not valid for size.'}):r.n>7&&t.push({rule:"unknown-size",severity:"error",path:l,message:`\`dataSize\` "${p}" N=${r.n} is out of range \u2014 the size scale has 8 steps (max offset: 7).`,hint:'Use "increase-N" or "decrease-N" where N \u2264 7.'})}M(d,l,t,!1,o)}function x(s,e={}){let t=$(s,e),i={error:0,warning:0,info:0,total:t.length};for(let o of t)i[o.severity]+=1;return{ok:i.error===0,issues:t,summary:i}}function I(s){if(s.length===0)return"\u2713 No issues found.";let e=t=>t==="error"?"\u2717":t==="warning"?"\u26A0":"i";return s.map(t=>`${e(t.severity)} [${t.rule}] ${t.path}
2
2
  ${t.message}${t.hint?`
3
3
  \u2192 ${t.hint}`:""}`).join(`
4
- `)}var it=new Set([...b,...w]),rt=new Set(v);function I(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function ot(e){for(let s in e)if(it.has(s))return s}function R(e){if(Array.isArray(e))return e.map(R);if(I(e)){let s={};for(let t in e)s[t]=R(e[t]);return s}return e}function B(e,s={}){let t=R(e),n=[];return T(t,"",n),{tree:t,applied:n,report:M(t,s)}}function T(e,s,t){if(Array.isArray(e)){for(let[i,u]of e.entries())T(u,`${s}[${i}]`,t);return}if(!I(e))return;let n=ot(e);if(!n)return;let r=s?`${s} > ${n}`:n;rt.has(n)&&e[n]!==null&&e[n]!==void 0&&(e[n]=null,t.push({rule:"void-content",path:r,message:`Void tag <${n}> cannot have content \u2014 cleared to null.`})),T(e[n],r,t)}return H(at);})();
4
+ `)}function R(s){if(Array.isArray(s))return s.map(R);if(y(s)){let e={};for(let t in s)e[t]=R(s[t]);return e}return s}function P(s,e={}){let t=R(s),i=[];return T(t,"",i),{tree:t,applied:i,report:x(t,e)}}function T(s,e,t){if(Array.isArray(s)){for(let[n,u]of s.entries())T(u,`${e}[${n}]`,t);return}if(!y(s))return;let i=_(s);if(!i)return;let o=e?`${e} > ${i}`:i;w.has(i)&&s[i]!==null&&s[i]!==void 0&&(s[i]=null,t.push({rule:"void-content",path:o,message:`Void tag <${i}> cannot have content \u2014 cleared to null.`})),T(s[i],o,t)}return W(at);})();
5
5
  //# sourceMappingURL=doctor.global.js.map