@webority/canvas-kit 0.87.3 → 0.88.1

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
@@ -89,6 +89,3 @@ Any file changed after the build fails the check.
89
89
  The package builds into `dist` before publish: `pnpm run build`. Its tests run with `pnpm test`, which reads the
90
90
  source under `src`. The tests build throwaway product folders with a stub library, so they need only the
91
91
  package's own dependencies installed.
92
-
93
- The sample kit under `src/__fixtures__/sample-kit` resolves `@webority/ui-react` and `react` through this package's
94
- devDependencies, so it builds from the workspace after `pnpm install`.
@@ -1 +1 @@
1
- import{readText as e}from"./files.js";import{existsSync as t}from"node:fs";import{dirname as n,join as r,resolve as i}from"node:path";import a from"@babel/parser";var o=`function`,s=8,c=2,l=120,u=[`ForwardRefExoticComponent`,`FC`,`FunctionComponent`,`ComponentType`,`MemoExoticComponent`],d=[`Array`,`ReadonlyArray`,`Set`,`ReadonlySet`],f=/(^i|I)con$/,p=/(Href|href|Url|url)$/,m=new Map,h=new Set,g=new Set,_=[];function v(e,t){return e<t?-1:+(e>t)}function y(e){return[...new Set(e)].sort(v)}function b(e){return e.type===`Identifier`?e.name:e.type===`StringLiteral`?e.value:null}function x(e){let t=e.type===`TSImportType`?e.qualifier:e.typeName;return t?t.type===`TSQualifiedName`?t.right.name:t.name:null}function ee(e){switch(e.type){case`TSDeclareFunction`:case`FunctionDeclaration`:case`TSInterfaceDeclaration`:case`TSTypeAliasDeclaration`:return[[e.id.name,e]];case`VariableDeclaration`:return e.declarations.filter(e=>e.id.type===`Identifier`).map(e=>[e.id.name,e]);default:return[]}}function S(t){if(m.has(t))return m.get(t);let n=e(t),r=a.parse(n,{sourceType:`module`,plugins:[`typescript`]}),i={declarations:new Map,imports:new Map,exports:[],defaultDeclaration:null,source:n};for(let e of r.program.body)if(e.type===`ImportDeclaration`)for(let t of e.specifiers)t.type===`ImportSpecifier`&&i.imports.set(t.local.name,{source:e.source.value,imported:b(t.imported)});else if(e.type===`ExportAllDeclaration`)i.exports.push({star:!0,source:e.source.value});else if(e.type===`ExportDefaultDeclaration`)i.defaultDeclaration=e.declaration,i.exports.push({name:`default`,local:`default`});else if(e.type===`ExportNamedDeclaration`&&e.source)for(let t of e.specifiers)i.exports.push({name:t.exported.name,local:t.local.name,source:e.source.value});else{let t=e.type===`ExportNamedDeclaration`,n=t?e.declaration:e;for(let[e,r]of n?ee(n):[])i.declarations.set(e,r),t&&i.exports.push({name:e,local:e});if(t)for(let t of e.specifiers)i.exports.push({name:t.exported.name,local:t.local.name})}return m.set(t,i),i}function C(e,a){if(!a.startsWith(`.`))return null;let o=i(n(e),a).replace(/\.(jsx?|tsx?)$/,``);for(let e of[`${o}.d.ts`,r(o,`index.d.ts`)])if(t(e))return e;throw Error(`Cannot resolve ${a} from ${e}`)}function w(e,t=new Set){let n=new Map;if(t.has(e))return n;t.add(e);for(let r of S(e).exports){if(r.star){let i=C(e,r.source);for(let[e,r]of i?w(i,t):[])e!=="default"&&!n.has(e)&&n.set(e,r);continue}let i=r.source===void 0?e:C(e,r.source);i&&n.set(r.name,{file:i,local:r.local})}return n}function T(e,t=new Set){let n=`${e.file}#${e.local}`;if(t.has(n))return null;t.add(n);let r=S(e.file);if(r.declarations.has(e.local))return e;let i=r.exports.find(t=>t.name===e.local&&t.source!==void 0),a=i&&C(e.file,i.source);return a?T({file:a,local:i.local},t):null}function E(e){return e.local==="default"?e:T(e)}function te(e){let t=E(e);if(!t)return null;let{declarations:n,defaultDeclaration:r}=S(t.file),i=t.local==="default"?r?.type===`Identifier`?n.get(r.name):r:n.get(t.local);return i?.type===`TSDeclareFunction`||i?.type===`FunctionDeclaration`?i:null}function ne(e,t,n){let r=e.params[0];if(!r)return[];let i=(r.type===`AssignmentPattern`?r.left:r).typeAnnotation?.typeAnnotation;if(!i)return null;let a=F(i,t.file,new Map,0);if(a)return a;let o=x(i);if(i.type===`TSTypeReference`&&o?.endsWith(`Props`)&&S(t.file).declarations.has(o))throw Error(`${n}: ${o} is not an object type in ${t.file}`);return null}function D(e,t){let n=S(e),r=n.declarations.get(t);if(r)return{file:e,declared:r};let i=n.imports.get(t),a=i&&C(e,i.source);if(!a)return null;let o=T({file:a,local:i.imported});return o?{file:o.file,declared:S(o.file).declarations.get(o.local)}:null}function O(e,t,n,r,i){let a=new Map;return(e.typeParameters?.params??[]).forEach((e,o)=>{let s=t[o];s?a.set(e.name,{node:s,file:n,env:r}):e.default?a.set(e.name,{node:e.default,file:i,env:a}):a.set(e.name,{node:{type:`TSUnknownKeyword`},file:i,env:new Map})}),a}function k(e){if(!e?.expression)return null;let t=(e.typeParameters??e.typeArguments)?.params;return{type:`TSTypeReference`,typeName:e.expression,...t?{typeParameters:{params:t}}:{}}}function A(e,t,n){if(e.type===`TSImportType`){let t=e.argument?.value;return typeof t!=`string`||!t.startsWith(`.`)}let r=n?S(n).imports.get(t):null;return!!(r&&!r.source.startsWith(`.`))}function j(e,t,n){if(!e)return null;let r=e.type===`TSUnionType`?e.types:[e],i=[];for(let e of r){if(e.type===`TSNullKeyword`||e.type===`TSUndefinedKeyword`)continue;let r=U(e,t,n);if(r.length===0||r.includes(null))return null;i.push(...r)}return i.length>0?i:null}function M(e,t,n,r){let i=e.filter(e=>e.type!==`TSNullKeyword`&&e.type!==`TSUndefinedKeyword`);if(i.length===1)return F(i[0],t,n,r);let a=[];for(let e of i){let i=F(e,t,n,r);if(!i)return null;a.push(i)}let o=[],s=new Map;for(let e of a)for(let t of e){let e=s.get(t.name);e||(e={name:t.name,count:0,requiredEverywhere:!0,branches:[]},s.set(t.name,e),o.push(t.name)),e.count+=1,e.requiredEverywhere=e.requiredEverywhere&&!t.optional,e.branches.push(...t.branches)}return o.map(e=>{let t=s.get(e);return{name:e,optional:!(t.count===a.length&&t.requiredEverywhere),branches:t.branches}})}function N(e,t,n,r,i,a){let o=O(e,t,n,r,i),s=[],c=new Map;for(let t of e.extends??[]){let e=F(k(t),i,o,a+1);if(!e)return null;for(let t of e)c.has(t.name)||s.push(t.name),c.set(t.name,t)}let l=F({type:`TSTypeLiteral`,members:e.body.body},i,o,a);if(!l)return null;for(let e of l){let t=s.indexOf(e.name);t>=0&&s.splice(t,1),s.push(e.name),c.set(e.name,e)}return s.map(e=>c.get(e))}function P(e,t,n,r){let i=x(e),a=(e.typeParameters??e.typeArguments)?.params??[];if(i&&n.has(i)){let e=n.get(i);return F(e.node,e.file,e.env,r+1)}if(i===`RefAttributes`)return[];if([`Partial`,`Required`,`Readonly`].includes(i)&&a.length===1){let e=F(a[0],t,n,r);return e?i===`Partial`?e.map(e=>({...e,optional:!0})):i===`Required`?e.map(e=>({...e,optional:!1})):e:null}if((i===`Omit`||i===`Pick`)&&a.length===2){let e=F(a[0],t,n,r);if(!e)return null;let o=j(a[1],t,r);if(!o)return i===`Omit`?e:null;let s=new Set(o);return i===`Omit`?e.filter(e=>!s.has(e.name)):e.filter(e=>s.has(e.name))}if(A(e,i,t))return i&&g.add(i),[];let o=D(t,i);if(!o?.declared)return null;if(o.declared.type===`TSInterfaceDeclaration`)return N(o.declared,a,t,n,o.file,r);if(o.declared.type===`TSTypeAliasDeclaration`){let e=O(o.declared,a,t,n,o.file);return F(o.declared.typeAnnotation,o.file,e,r+1)}return null}function F(e,t,n,r){if(!e||r>=s)return null;switch(e.type){case`TSParenthesizedType`:return F(e.typeAnnotation,t,n,r);case`TSTypeLiteral`:return e.members.filter(e=>e.type===`TSPropertySignature`&&b(e.key)!==null).map(e=>({name:b(e.key),optional:e.optional===!0,branches:[{node:e.typeAnnotation?.typeAnnotation??{type:`TSAnyKeyword`},file:t,env:n}]}));case`TSIntersectionType`:{let i=[],a=new Map;for(let o of e.types){let e=F(o,t,n,r);if(!e)return null;for(let t of e)a.has(t.name)||i.push(t.name),a.set(t.name,t)}return i.map(e=>a.get(e))}case`TSUnionType`:return M(e.types,t,n,r);case`TSTypeReference`:case`TSImportType`:return P(e,t,n,r);default:return null}}function I(e,t,n){if(e===`ReactNode`||e===`ReactElement`)return{type:`node`};if(d.includes(e))return{type:`array`};if(e===`Record`)return{type:`object`};if(e===`Date`)return{type:`string`};if(e===`Function`)return o;if(e===`SlotIcon`)return{type:`node`};if(!t||n>=s)return null;let r=D(t,e);if(r?.declared?.type===`TSTypeAliasDeclaration`)return G(r.declared.typeAnnotation,r.file,n+1);if(r?.declared?.type===`TSInterfaceDeclaration`){let i=F({type:`TSTypeReference`,typeName:{type:`Identifier`,name:e}},t,_.at(-1)??new Map,n+1);return i?J(i,r.declared):null}return null}function L(e){return e.type===`TSBooleanKeyword`||e.type===`TSLiteralType`&&e.literal.type===`BooleanLiteral`}function R(e){return e.type===`TSLiteralType`&&e.literal.type===`StringLiteral`}function z(e){return e.type===`TSObjectKeyword`||e.type===`TSTypeLiteral`}function B(e){return e?.type===`TSQualifiedName`&&e.left.type===`Identifier`&&e.left.name===`JSX`&&e.right.name===`Element`}function V(e){return e.type===`TSTypeReference`&&[`File`,`Blob`].includes(x(e))}function H(e,t,n){let r=e.filter(e=>e.type!==`TSNullKeyword`&&e.type!==`TSUndefinedKeyword`&&!V(e)),i=e=>r.every(t=>t.type===`TSLiteralType`&&t.literal.type===e);if(r.length===0)return null;if(i(`StringLiteral`))return{type:`enum`,enum:y(r.map(e=>e.literal.value))};if(i(`BooleanLiteral`)||r.some(L)&&r.every(e=>L(e)||R(e)||z(e)))return{type:`boolean`};if(i(`NumericLiteral`))return{type:`number`};if(r.length===1&&r[0].type!==`TSLiteralType`)return G(r[0],t,n);let a=r.flatMap(e=>U(e,t,n));if(a.length>0&&!a.includes(null))return{type:`enum`,enum:y(a)};let s=new Set(r.map(e=>W(e,t,n)));return s.has(`node`)?{type:`node`}:s.size===2&&s.has(`string`)&&s.has(`number`)?{type:`stringOrNumber`}:s.size===1&&!s.has(null)?{type:[...s][0]}:r.every(e=>e.type!==`TSLiteralType`)&&r.map(e=>G(e,t,n)).every(e=>e&&e!==o&&[`object`,`array`].includes(e.type))?{type:`any`}:null}function U(e,t,n){if(e.type===`TSLiteralType`)return e.literal.type===`StringLiteral`?[e.literal.value]:[null];let r=G(e,t,n);return r?.type===`enum`?r.enum:[null]}function W(e,t,n){if(e.type===`TSLiteralType`){let t=e.literal.type;return t===`StringLiteral`?`string`:t===`NumericLiteral`?`number`:t===`BooleanLiteral`?`boolean`:null}let r=G(e,t,n);return r?.type===`enum`?`string`:r&&r!==o&&[`node`,`string`,`number`,`boolean`].includes(r.type)?r.type:null}function G(e,t,n=0){switch(e.type){case`TSParenthesizedType`:return G(e.typeAnnotation,t,n);case`TSAnyKeyword`:case`TSUnknownKeyword`:return{type:`any`,anyUnknown:!0};case`TSStringKeyword`:return{type:`string`};case`TSNumberKeyword`:return{type:`number`};case`TSBooleanKeyword`:return{type:`boolean`};case`TSArrayType`:return X(e.elementType,t,n);case`TSTypeLiteral`:return Y(e.members,t);case`TSFunctionType`:return o;case`TSLiteralType`:return H([e],t,n);case`TSUnionType`:return H(e.types,t,n);case`TSTypeReference`:{let r=x(e),i=_.at(-1);if(r&&i?.has(r)){let e=i.get(r);_.push(e.env);try{return G(e.node,e.file,n+1)}finally{_.pop()}}return B(e.typeName)?{type:`node`}:d.includes(r)&&e.typeParameters?.params.length===1?X(e.typeParameters.params[0],t,n):I(r,t,n)}case`TSImportType`:return B(e.qualifier)?{type:`node`}:I(x(e),null,n);default:return null}}function K(e,t){return p.test(e)&&(t===`string`||t===`any`)?`url`:t}function q(e,t=e){if(h.size>=c||h.has(t))return null;h.add(t);try{return Z(e)}finally{h.delete(t)}}function J(e,t=e){let n=q(e,t);return n?{type:`object`,fields:n.props,skippedFields:n.skippedProps,...n.hasHandler?{handler:!0}:{}}:{type:`object`}}function Y(e,t){let n=F({type:`TSTypeLiteral`,members:e},t,_.at(-1)??new Map,0);return n?J(n):{type:`object`}}function X(e,t,n){let r=G(e,t,n);return r?.fields?{type:`array`,itemFields:r.fields,skippedFields:r.skippedFields,...r.handler?{itemHandler:!0}:{}}:{type:`array`}}function re(e){_.push(e.env);try{return G(e.node,e.file)}finally{_.pop()}}function ie(e){let t=e.branches.map(e=>Q(e.node,e.file));return t.length===1?t[0]:t.join(` | `)}function Z(e){let t=[],n=[],r=!1,i=!1;for(let a of e){let e=a.name;if(e===`children`){r=!0;continue}let s=a.branches.map(e=>re(e));if(s.every(e=>e===o)){i=!0;continue}let c=a.branches[0],l;if(s.every(e=>e!==null&&JSON.stringify(e)===JSON.stringify(s[0])))l=s[0];else if(a.branches.every(e=>e.file===c.file&&e.env===c.env)){let e={type:`TSUnionType`,types:a.branches.map(e=>e.node)};_.push(c.env);try{l=G(e,c.file)}finally{_.pop()}}if(l===o){i=!0;continue}if(!l){n.push({name:e,type:ie(a)});continue}let{type:u,enum:d,anyUnknown:p,fields:m,itemFields:h,skippedFields:g=[]}=l;for(let t of g)n.push({...t,name:`${e}${u===`array`?`[]`:``}.${t.name}`});t.push({name:e,type:K(e,u===`node`&&f.test(e)?`icon`:u),...l.handler?{handler:!0}:{},...l.itemHandler?{itemHandler:!0}:{},...d?{enum:d}:{},...m?{fields:m}:{},...h?{itemFields:h}:{},required:!a.optional&&!p})}return t.sort((e,t)=>v(e.name,t.name)),{props:t,acceptsChildren:r,skippedProps:n,hasHandler:i}}function Q(e,t){if(e.start===void 0)return e.type===`TSUnionType`?e.types.map(e=>Q(e,t)).join(` | `):e.type;let n=t?S(t).source:null;if(!n)return e.type;let r=n.slice(e.start,e.end).replace(/\s+/g,` `);return r.length>l?`${r.slice(0,l)}...`:r}function $(e){let t=E(e);if(!t)return null;let{declarations:n,defaultDeclaration:r}=S(t.file),i=t.local==="default"?r?.type===`Identifier`&&n.get(r.name):n.get(t.local);return i?.type===`VariableDeclarator`?{node:i,declarations:n}:null}function ae(e){let t=$(e)?.node.id.typeAnnotation?.typeAnnotation;return[`TSTypeReference`,`TSImportType`].includes(t?.type)&&u.includes(x(t))}function oe(e){let t=$(e);if(!t)return null;let n=E(e)?.file,r=t.node.id.typeAnnotation?.typeAnnotation;for(;r;){if(![`TSTypeReference`,`TSImportType`].includes(r.type)||!u.includes(x(r)))return null;let e=(r.typeParameters??r.typeArguments)?.params??[];if(e.length===0)return[];if(r=e[0],![`TSTypeReference`,`TSImportType`].includes(r.type)||!u.includes(x(r)))return F(r,n,new Map,0)}return null}function se(e,{namedConsts:t=!1,kit:n=``}={}){m=new Map,h.clear(),g.clear(),_.length=0;let r=[],i=[];for(let[a,o]of w(e)){if(!/^[A-Z][A-Za-z0-9]*$/.test(a))continue;let s=te(o),c=E(o),l=s?ne(s,c,a):t?oe(o):null;if(!l){(s||t&&ae(o))&&i.push(`Component left out, its props could not be read: ${n} ${a}`);continue}let u=Z(l);if(u.skippedProps.length>0){let e=u.skippedProps.map(({name:e,type:t})=>`${e} (${t})`).join(`, `);i.push(`Skipped props, no manifest type: ${n} ${a}: ${e}`)}r.push({name:a,acceptsChildren:u.acceptsChildren,props:u.props,file:c?.file??e})}return r.sort((e,t)=>v(e.name,t.name)),g.size>0&&i.push(`Props inherited from outside the kit were not read: ${n} ${y(g).join(`, `)}`),{components:r,warnings:i}}export{se as collectComponents};
1
+ import{readText as e}from"./files.js";import{existsSync as t}from"node:fs";import{dirname as n,join as r,resolve as i}from"node:path";import a from"@babel/parser";var o=`function`,s=8,c=2,l=120,u=[`ForwardRefExoticComponent`,`FC`,`FunctionComponent`,`ComponentType`,`MemoExoticComponent`],d=[`ReactElement`,`ReactNode`,`ReactPortal`],f=[`Array`,`ReadonlyArray`,`Set`,`ReadonlySet`],ee=/(^i|I)con$/,p=/(Href|href|Url|url)$/,m=new Map,h=new Set,g=new Set,_=[];function v(e,t){return e<t?-1:+(e>t)}function y(e){return[...new Set(e)].sort(v)}function b(e){return e.type===`Identifier`?e.name:e.type===`StringLiteral`?e.value:null}function x(e){let t=e.type===`TSImportType`?e.qualifier:e.typeName;return t?t.type===`TSQualifiedName`?t.right.name:t.name:null}function S(e){switch(e.type){case`TSDeclareFunction`:case`FunctionDeclaration`:case`TSInterfaceDeclaration`:case`TSTypeAliasDeclaration`:return[[e.id.name,e]];case`ClassDeclaration`:return e.id?[[e.id.name,e]]:[];case`VariableDeclaration`:return e.declarations.filter(e=>e.id.type===`Identifier`).map(e=>[e.id.name,e]);default:return[]}}function C(t){if(m.has(t))return m.get(t);let n=e(t),r=a.parse(n,{sourceType:`module`,plugins:[`typescript`]}),i={declarations:new Map,imports:new Map,exports:[],defaultDeclaration:null,source:n};for(let e of r.program.body)if(e.type===`ImportDeclaration`)for(let t of e.specifiers)t.type===`ImportSpecifier`&&i.imports.set(t.local.name,{source:e.source.value,imported:b(t.imported)});else if(e.type===`ExportAllDeclaration`)i.exports.push({star:!0,source:e.source.value});else if(e.type===`ExportDefaultDeclaration`)i.defaultDeclaration=e.declaration,i.exports.push({name:`default`,local:`default`});else if(e.type===`ExportNamedDeclaration`&&e.source)for(let t of e.specifiers)i.exports.push({name:t.exported.name,local:t.local.name,source:e.source.value});else{let t=e.type===`ExportNamedDeclaration`,n=t?e.declaration:e;for(let[e,r]of n?S(n):[])i.declarations.set(e,r),t&&i.exports.push({name:e,local:e});if(t)for(let t of e.specifiers)i.exports.push({name:t.exported.name,local:t.local.name})}return m.set(t,i),i}function w(e,a){if(!a.startsWith(`.`))return null;let o=i(n(e),a).replace(/\.(jsx?|tsx?)$/,``);for(let e of[`${o}.d.ts`,r(o,`index.d.ts`)])if(t(e))return e;throw Error(`Cannot resolve ${a} from ${e}`)}function T(e,t=new Set){let n=new Map;if(t.has(e))return n;t.add(e);for(let r of C(e).exports){if(r.star){let i=w(e,r.source);for(let[e,r]of i?T(i,t):[])e!=="default"&&!n.has(e)&&n.set(e,r);continue}let i=r.source===void 0?e:w(e,r.source);i&&n.set(r.name,{file:i,local:r.local})}return n}function E(e,t=new Set){let n=`${e.file}#${e.local}`;if(t.has(n))return null;t.add(n);let r=C(e.file);if(r.declarations.has(e.local))return e;let i=r.exports.find(t=>t.name===e.local&&t.source!==void 0),a=i&&w(e.file,i.source);return a?E({file:a,local:i.local},t):null}function D(e){return e.local==="default"?e:E(e)}function O(e){let t=D(e);if(!t)return null;let{declarations:n,defaultDeclaration:r}=C(t.file),i=t.local==="default"?r?.type===`Identifier`?n.get(r.name):r:n.get(t.local);return i?.type===`TSDeclareFunction`||i?.type===`FunctionDeclaration`?i:null}function te(e,t,n){let r=e.params[0];if(!r)return[];let i=(r.type===`AssignmentPattern`?r.left:r).typeAnnotation?.typeAnnotation;if(!i)return null;let a=P(i,t.file,new Map,0);if(a)return a;let o=x(i);if(i.type===`TSTypeReference`&&o?.endsWith(`Props`)&&C(t.file).declarations.has(o))throw Error(`${n}: ${o} is not an object type in ${t.file}`);return null}function k(e,t){let n=C(e),r=n.declarations.get(t);if(r)return{file:e,declared:r};let i=n.imports.get(t),a=i&&w(e,i.source);if(!a)return null;let o=E({file:a,local:i.imported});return o?{file:o.file,declared:C(o.file).declarations.get(o.local)}:null}function A(e,t,n,r,i){let a=new Map;return(e.typeParameters?.params??[]).forEach((e,o)=>{let s=t[o];s?a.set(e.name,{node:s,file:n,env:r}):e.default?a.set(e.name,{node:e.default,file:i,env:a}):a.set(e.name,{node:{type:`TSUnknownKeyword`},file:i,env:new Map})}),a}function j(e){if(!e?.expression)return null;let t=(e.typeParameters??e.typeArguments)?.params;return{type:`TSTypeReference`,typeName:e.expression,...t?{typeParameters:{params:t}}:{}}}function M(e,t,n){if(e.type===`TSImportType`){let t=e.argument?.value;return typeof t!=`string`||!t.startsWith(`.`)}let r=n?C(n).imports.get(t):null;return!!(r&&!r.source.startsWith(`.`))}function ne(e,t,n){if(!e)return null;let r=e.type===`TSUnionType`?e.types:[e],i=[];for(let e of r){if(e.type===`TSNullKeyword`||e.type===`TSUndefinedKeyword`)continue;let r=z(e,t,n);if(r.length===0||r.includes(null))return null;i.push(...r)}return i.length>0?i:null}function re(e,t,n,r){let i=e.filter(e=>e.type!==`TSNullKeyword`&&e.type!==`TSUndefinedKeyword`);if(i.length===1)return P(i[0],t,n,r);let a=[];for(let e of i){let i=P(e,t,n,r);if(!i)return null;a.push(i)}let o=[],s=new Map;for(let e of a)for(let t of e){let e=s.get(t.name);e||(e={name:t.name,count:0,requiredEverywhere:!0,branches:[]},s.set(t.name,e),o.push(t.name)),e.count+=1,e.requiredEverywhere=e.requiredEverywhere&&!t.optional,e.branches.push(...t.branches)}return o.map(e=>{let t=s.get(e);return{name:e,optional:!(t.count===a.length&&t.requiredEverywhere),branches:t.branches}})}function ie(e,t,n,r,i,a){let o=A(e,t,n,r,i),s=[],c=new Map;for(let t of e.extends??[]){let e=P(j(t),i,o,a+1);if(!e)return null;for(let t of e)c.has(t.name)||s.push(t.name),c.set(t.name,t)}let l=P({type:`TSTypeLiteral`,members:e.body.body},i,o,a);if(!l)return null;for(let e of l){let t=s.indexOf(e.name);t>=0&&s.splice(t,1),s.push(e.name),c.set(e.name,e)}return s.map(e=>c.get(e))}function N(e,t,n,r){let i=x(e),a=(e.typeParameters??e.typeArguments)?.params??[];if(i&&n.has(i)){let e=n.get(i);return P(e.node,e.file,e.env,r+1)}if(i===`RefAttributes`)return[];if([`Partial`,`Required`,`Readonly`].includes(i)&&a.length===1){let e=P(a[0],t,n,r);return e?i===`Partial`?e.map(e=>({...e,optional:!0})):i===`Required`?e.map(e=>({...e,optional:!1})):e:null}if((i===`Omit`||i===`Pick`)&&a.length===2){let e=P(a[0],t,n,r);if(!e)return null;let o=ne(a[1],t,r);if(!o)return i===`Omit`?e:null;let s=new Set(o);return i===`Omit`?e.filter(e=>!s.has(e.name)):e.filter(e=>s.has(e.name))}if(M(e,i,t))return i&&g.add(i),[];let o=k(t,i);if(!o?.declared)return null;if(o.declared.type===`TSInterfaceDeclaration`)return ie(o.declared,a,t,n,o.file,r);if(o.declared.type===`TSTypeAliasDeclaration`){let e=A(o.declared,a,t,n,o.file);return P(o.declared.typeAnnotation,o.file,e,r+1)}return null}function P(e,t,n,r){if(!e||r>=s)return null;switch(e.type){case`TSParenthesizedType`:return P(e.typeAnnotation,t,n,r);case`TSTypeLiteral`:return e.members.filter(e=>e.type===`TSPropertySignature`&&b(e.key)!==null).map(e=>({name:b(e.key),optional:e.optional===!0,branches:[{node:e.typeAnnotation?.typeAnnotation??{type:`TSAnyKeyword`},file:t,env:n}]}));case`TSIntersectionType`:{let i=[],a=new Map;for(let o of e.types){let e=P(o,t,n,r);if(!e)return null;for(let t of e)a.has(t.name)||i.push(t.name),a.set(t.name,t)}return i.map(e=>a.get(e))}case`TSUnionType`:return re(e.types,t,n,r);case`TSTypeReference`:case`TSImportType`:return N(e,t,n,r);default:return null}}function F(e,t,n){if(e===`ReactNode`||e===`ReactElement`)return{type:`node`};if(f.includes(e))return{type:`array`};if(e===`Record`)return{type:`object`};if(e===`Date`)return{type:`string`};if(e===`Function`)return o;if(e===`SlotIcon`)return{type:`node`};if(!t||n>=s)return null;let r=k(t,e);if(r?.declared?.type===`TSTypeAliasDeclaration`)return V(r.declared.typeAnnotation,r.file,n+1);if(r?.declared?.type===`TSInterfaceDeclaration`){let i=P({type:`TSTypeReference`,typeName:{type:`Identifier`,name:e}},t,_.at(-1)??new Map,n+1);return i?W(i,r.declared):null}return null}function I(e){return e.type===`TSBooleanKeyword`||e.type===`TSLiteralType`&&e.literal.type===`BooleanLiteral`}function ae(e){return e.type===`TSLiteralType`&&e.literal.type===`StringLiteral`}function oe(e){return e.type===`TSObjectKeyword`||e.type===`TSTypeLiteral`}function L(e){return e?.type===`TSQualifiedName`&&e.left.type===`Identifier`&&e.left.name===`JSX`&&e.right.name===`Element`}function se(e){return e.type===`TSTypeReference`&&[`File`,`Blob`].includes(x(e))}function R(e,t,n){let r=e.filter(e=>e.type!==`TSNullKeyword`&&e.type!==`TSUndefinedKeyword`&&!se(e)),i=e=>r.every(t=>t.type===`TSLiteralType`&&t.literal.type===e);if(r.length===0)return null;if(i(`StringLiteral`))return{type:`enum`,enum:y(r.map(e=>e.literal.value))};if(i(`BooleanLiteral`)||r.some(I)&&r.every(e=>I(e)||ae(e)||oe(e)))return{type:`boolean`};if(i(`NumericLiteral`))return{type:`number`};if(r.length===1&&r[0].type!==`TSLiteralType`)return V(r[0],t,n);let a=r.flatMap(e=>z(e,t,n));if(a.length>0&&!a.includes(null))return{type:`enum`,enum:y(a)};let s=new Set(r.map(e=>B(e,t,n)));return s.has(`node`)?{type:`node`}:s.size===2&&s.has(`string`)&&s.has(`number`)?{type:`stringOrNumber`}:s.size===1&&!s.has(null)?{type:[...s][0]}:r.every(e=>e.type!==`TSLiteralType`)&&r.map(e=>V(e,t,n)).every(e=>e&&e!==o&&[`object`,`array`].includes(e.type))?{type:`any`}:null}function z(e,t,n){if(e.type===`TSLiteralType`)return e.literal.type===`StringLiteral`?[e.literal.value]:[null];let r=V(e,t,n);return r?.type===`enum`?r.enum:[null]}function B(e,t,n){if(e.type===`TSLiteralType`){let t=e.literal.type;return t===`StringLiteral`?`string`:t===`NumericLiteral`?`number`:t===`BooleanLiteral`?`boolean`:null}let r=V(e,t,n);return r?.type===`enum`?`string`:r&&r!==o&&[`node`,`string`,`number`,`boolean`].includes(r.type)?r.type:null}function V(e,t,n=0){switch(e.type){case`TSParenthesizedType`:return V(e.typeAnnotation,t,n);case`TSAnyKeyword`:case`TSUnknownKeyword`:return{type:`any`,anyUnknown:!0};case`TSStringKeyword`:return{type:`string`};case`TSNumberKeyword`:return{type:`number`};case`TSBooleanKeyword`:return{type:`boolean`};case`TSArrayType`:return K(e.elementType,t,n);case`TSTypeLiteral`:return G(e.members,t);case`TSFunctionType`:return o;case`TSLiteralType`:return R([e],t,n);case`TSUnionType`:return R(e.types,t,n);case`TSTypeReference`:{let r=x(e),i=_.at(-1);if(r&&i?.has(r)){let e=i.get(r);_.push(e.env);try{return V(e.node,e.file,n+1)}finally{_.pop()}}return L(e.typeName)?{type:`node`}:f.includes(r)&&e.typeParameters?.params.length===1?K(e.typeParameters.params[0],t,n):F(r,t,n)}case`TSImportType`:return L(e.qualifier)?{type:`node`}:F(x(e),null,n);default:return null}}function H(e,t){return p.test(e)&&(t===`string`||t===`any`)?`url`:t}function U(e,t=e){if(h.size>=c||h.has(t))return null;h.add(t);try{return q(e)}finally{h.delete(t)}}function W(e,t=e){let n=U(e,t);return n?{type:`object`,fields:n.props,skippedFields:n.skippedProps,...n.hasHandler?{handler:!0}:{}}:{type:`object`}}function G(e,t){let n=P({type:`TSTypeLiteral`,members:e},t,_.at(-1)??new Map,0);return n?W(n):{type:`object`}}function K(e,t,n){let r=V(e,t,n);return r?.fields?{type:`array`,itemFields:r.fields,skippedFields:r.skippedFields,...r.handler?{itemHandler:!0}:{}}:{type:`array`}}function ce(e){_.push(e.env);try{return V(e.node,e.file)}finally{_.pop()}}function le(e){let t=e.branches.map(e=>J(e.node,e.file));return t.length===1?t[0]:t.join(` | `)}function q(e){let t=[],n=[],r=!1,i=!1;for(let a of e){let e=a.name;if(e===`children`){r=!0;continue}let s=a.branches.map(e=>ce(e));if(s.every(e=>e===o)){i=!0;continue}let c=a.branches[0],l;if(s.every(e=>e!==null&&JSON.stringify(e)===JSON.stringify(s[0])))l=s[0];else if(a.branches.every(e=>e.file===c.file&&e.env===c.env)){let e={type:`TSUnionType`,types:a.branches.map(e=>e.node)};_.push(c.env);try{l=V(e,c.file)}finally{_.pop()}}if(l===o){i=!0;continue}if(!l){n.push({name:e,type:le(a)});continue}let{type:u,enum:d,anyUnknown:f,fields:p,itemFields:m,skippedFields:h=[]}=l;for(let t of h)n.push({...t,name:`${e}${u===`array`?`[]`:``}.${t.name}`});t.push({name:e,type:H(e,u===`node`&&ee.test(e)?`icon`:u),...l.handler?{handler:!0}:{},...l.itemHandler?{itemHandler:!0}:{},...d?{enum:d}:{},...p?{fields:p}:{},...m?{itemFields:m}:{},required:!a.optional&&!f})}return t.sort((e,t)=>v(e.name,t.name)),{props:t,acceptsChildren:r,skippedProps:n,hasHandler:i}}function J(e,t){if(e.start===void 0)return e.type===`TSUnionType`?e.types.map(e=>J(e,t)).join(` | `):e.type;let n=t?C(t).source:null;if(!n)return e.type;let r=n.slice(e.start,e.end).replace(/\s+/g,` `);return r.length>l?`${r.slice(0,l)}...`:r}function Y(e){let t=D(e);if(!t)return null;let{declarations:n,defaultDeclaration:r}=C(t.file),i=t.local==="default"?r?.type===`Identifier`&&n.get(r.name):n.get(t.local);return i?.type===`VariableDeclarator`?{node:i,declarations:n}:null}function X(e){return[`TSTypeReference`,`TSImportType`].includes(e?.type)&&u.includes(x(e))}function Z(e){if(!e)return!1;if(e.type===`TSParenthesizedType`)return Z(e.typeAnnotation);if(e.type===`TSUnionType`){let t=e.types.filter(e=>e.type!==`TSNullKeyword`&&e.type!==`TSUndefinedKeyword`);return t.length>0&&t.every(Z)}let t=e.type===`TSImportType`?e.qualifier:e.typeName;return[`TSTypeReference`,`TSImportType`].includes(e.type)&&(L(t)||d.includes(x(e)))}function Q(e){if(!e)return null;switch(e.type){case`TSParenthesizedType`:return Q(e.typeAnnotation);case`TSTypeReference`:case`TSImportType`:return X(e)?e:null;case`TSFunctionType`:return Z(e.typeAnnotation?.typeAnnotation)?e:null;case`TSTypeLiteral`:return e.members.find(e=>e.type===`TSCallSignatureDeclaration`&&Z(e.typeAnnotation?.typeAnnotation))??null;case`TSIntersectionType`:for(let t of e.types){let e=Q(t);if(e)return e}return null;default:return null}}function $(e){let t=D(e),n=t&&C(t.file).declarations.get(t.local);if(n?.type!==`ClassDeclaration`||!n.superClass)return null;let r=n.superClass.type===`MemberExpression`?n.superClass.property:n.superClass;return r?.type===`Identifier`&&[`Component`,`PureComponent`].includes(r.name)?{node:n,file:t.file}:null}function ue(e){let t=$(e);if(!t)return null;let n=(t.node.superTypeParameters??t.node.superTypeArguments)?.params?.[0];return n?P(n,t.file,new Map,0):[]}function de(e){return Q(Y(e)?.node.id.typeAnnotation?.typeAnnotation)!==null||$(e)!==null}function fe(e,t){let n=(e.parameters??e.params??[])[0];if(!n)return[];let r=(n.type===`AssignmentPattern`?n.left:n).typeAnnotation?.typeAnnotation;return r?P(r,t,A(e,[],t,new Map,t),0):null}function pe(e){let t=Y(e);if(!t)return null;let n=D(e)?.file,r=Q(t.node.id.typeAnnotation?.typeAnnotation);if(r&&!X(r))return fe(r,n);for(;r;){if(![`TSTypeReference`,`TSImportType`].includes(r.type)||!u.includes(x(r)))return null;let e=(r.typeParameters??r.typeArguments)?.params??[];if(e.length===0)return[];if(r=e[0],![`TSTypeReference`,`TSImportType`].includes(r.type)||!u.includes(x(r)))return P(r,n,new Map,0)}return null}function me(e,{namedConsts:t=!1,kit:n=``}={}){m=new Map,h.clear(),g.clear(),_.length=0;let r=[],i=[],a=[];for(let[o,s]of T(e)){if(!/^[A-Z][A-Za-z0-9]*$/.test(o))continue;let c=O(s),l=D(s),u=c?te(c,l,o):t?pe(s)??ue(s):null;if(!u){(c||t&&de(s))&&(i.push(`Component left out, its props could not be read: ${n} ${o}`),a.push(o));continue}let d=q(u);if(d.skippedProps.length>0){let e=d.skippedProps.map(({name:e,type:t})=>`${e} (${t})`).join(`, `);i.push(`Skipped props, no manifest type: ${n} ${o}: ${e}`)}r.push({name:o,acceptsChildren:d.acceptsChildren,props:d.props,file:l?.file??e})}return r.sort((e,t)=>v(e.name,t.name)),g.size>0&&i.push(`Props inherited from outside the kit were not read: ${n} ${y(g).join(`, `)}`),{components:r,warnings:i,unreadable:y(a)}}export{me as collectComponents};
@@ -0,0 +1,10 @@
1
+ import type { ComponentMeta, ComponentUsage } from "./meta.js";
2
+
3
+ export interface GuidanceFile {
4
+ format: "webority-guidance/1";
5
+ package: { name: string; version: string };
6
+ components: { name: string; usage: ComponentUsage }[];
7
+ }
8
+
9
+ export declare function guidanceOf(metas: { meta: ComponentMeta }[], pkg: { name: string; version: string }): GuidanceFile;
10
+ export declare function writeGuidance(options: { configFile: string; outFile: string }): Promise<GuidanceFile>;
@@ -0,0 +1 @@
1
+ function e(e,t){throw Error(`guidanceOf is not built yet.`)}async function t(e){throw Error(`writeGuidance is not built yet.`)}export{e as guidanceOf,t as writeGuidance};
@@ -0,0 +1,149 @@
1
+ import type { ComponentUsage } from "./meta.js";
2
+
3
+ // The manifest a kit release folder carries as manifest.json. build.js writes it for a product kit, and
4
+ // publish-fleet-kit.mjs writes it for a fleet kit. The release row holds the same JSON, and the CLI reads an offline copy.
5
+
6
+ // Which kit a document's root carries. A product kit is "Product"; the two fleet kits are the Webority kits.
7
+ export type CanvasKitKind = "WeborityWeb" | "WeborityPhone" | "Product";
8
+
9
+ export type CanvasKitPlatform = "Web" | "Phone";
10
+
11
+ // The type a prop takes in the manifest. A "url" is a string prop named like a link; an "icon" is a node slot that
12
+ // takes a library icon.
13
+ export type CanvasManifestPropType =
14
+ | "any"
15
+ | "array"
16
+ | "boolean"
17
+ | "enum"
18
+ | "enumOrNumber"
19
+ | "icon"
20
+ | "node"
21
+ | "number"
22
+ | "object"
23
+ | "string"
24
+ | "stringOrNumber"
25
+ | "url";
26
+
27
+ export interface CanvasManifestProp {
28
+ name: string;
29
+ type: CanvasManifestPropType;
30
+ // The values an enum prop takes: strings, numbers (a numeric literal union, sorted), or both. On an enumOrNumber
31
+ // prop, its named values; the prop also takes any number.
32
+ enum?: (string | number)[];
33
+ // The fields of an object prop.
34
+ fields?: CanvasManifestProp[];
35
+ // The fields of each item of an array prop. A list whose items carry href or to takes the action on the Web.
36
+ itemFields?: CanvasManifestProp[];
37
+ required: boolean;
38
+ description?: string;
39
+ // The value the component applies when the prop is left out, as JSON.
40
+ default?: unknown;
41
+ }
42
+
43
+ export interface CanvasManifestComponent {
44
+ // The component's name as a document places it.
45
+ name: string;
46
+ // The data-wui value the importer matches: the App* name on the component's outermost element. Null means the
47
+ // importer never places this component.
48
+ marker: string | null;
49
+ acceptsChildren: boolean;
50
+ props: CanvasManifestProp[];
51
+ itemsTakeAction: string[];
52
+ takesAction: string[];
53
+ // The package the component comes from. A product's own component names its source file.
54
+ source: string;
55
+ role?: "title" | "navigation";
56
+ // Present on every Web component; absent on Phone until its metas carry usage.
57
+ usage?: ComponentUsage;
58
+ }
59
+
60
+ // The token names of a kit's vocabulary, by group. The colour names carry their meanings from the theme.
61
+ export interface CanvasManifestTokens {
62
+ color: string[];
63
+ space: string[];
64
+ radius: string[];
65
+ shadow: string[];
66
+ font: string[];
67
+ text: string[];
68
+ colorMeanings?: Record<string, string>;
69
+ }
70
+
71
+ // Each token's value, so the importer can draw a kit's values into a file's theme. Null on a release built before
72
+ // this field existed; a token lift from such a release is refused until the release is rebuilt.
73
+ export interface CanvasManifestTokenValues {
74
+ color: Record<string, CanvasManifestColorValue>;
75
+ space: Record<string, number>;
76
+ radius: Record<string, number>;
77
+ shadow: Record<string, string>;
78
+ font: Record<string, CanvasManifestFontValue>;
79
+ text: Record<string, CanvasManifestTextValue>;
80
+ }
81
+
82
+ export interface CanvasManifestColorValue {
83
+ light: string;
84
+ dark: string;
85
+ }
86
+
87
+ export interface CanvasManifestFontValue {
88
+ family: string;
89
+ fallback: string;
90
+ }
91
+
92
+ export interface CanvasManifestTextValue {
93
+ size: number;
94
+ lineHeight?: number | null;
95
+ weight?: number | null;
96
+ }
97
+
98
+ export interface CanvasManifestStyleKey {
99
+ name: string;
100
+ type: string;
101
+ values: string[];
102
+ appliesTo: string;
103
+ phoneSupported: boolean;
104
+ description: string;
105
+ }
106
+
107
+ export interface CanvasManifest {
108
+ // The document kind the release serves: a fleet kit's kind, or "Product" for a product kit.
109
+ kind: CanvasKitKind;
110
+ library: {
111
+ name: string;
112
+ version: string;
113
+ };
114
+ rendererProtocolVersion: number;
115
+ platform: CanvasKitPlatform;
116
+ kitModuleVersion: number;
117
+ productKit: null;
118
+ components: CanvasManifestComponent[];
119
+ tokens: CanvasManifestTokens;
120
+ tokenValues: CanvasManifestTokenValues | null;
121
+ icons: string[];
122
+ // A product release no longer carries style keys; the embedded Webority manifests keep them as the renderer's table.
123
+ styleKeys?: CanvasManifestStyleKey[];
124
+ }
125
+
126
+ export interface CanvasReleaseFileStamp {
127
+ sha256: string;
128
+ bytes: number;
129
+ }
130
+
131
+ // release.json: stamps each content file with its SHA-256 and byte count. A file that no longer matches its stamp
132
+ // makes the release unreadable, because a published release never changes.
133
+ export interface CanvasReleaseStamp {
134
+ // The kit key, which is also the release folder's first level under Webority.Canvas.Kits.
135
+ name: string;
136
+ version: string;
137
+ platform: CanvasKitPlatform;
138
+ kitModuleVersion: number;
139
+ rendererProtocolVersion: number;
140
+ library: {
141
+ name: string;
142
+ version: string;
143
+ };
144
+ files: {
145
+ "manifest.json": CanvasReleaseFileStamp;
146
+ "kit.js": CanvasReleaseFileStamp;
147
+ "kit.css": CanvasReleaseFileStamp;
148
+ };
149
+ }
package/dist/manifest.js CHANGED
@@ -1 +1 @@
1
- import{findPackageDir as e,readJson as t,readText as n,toPosix as r}from"./files.js";import"./kitModule.js";import{collectComponents as i}from"./declarations.js";import{PHONE_EXCLUDED_COMPONENTS as a,applyPhoneActions as o,phoneChromeEntries as s,phoneIcons as c,phoneTokenValues as l,phoneTokens as u}from"./phone.js";import{colourMeanings as ee,webIcons as te,webTokenValues as ne,webTokens as d}from"./tokens.js";import{createRequire as f}from"node:module";import{existsSync as p,mkdtempSync as m,rmSync as h}from"node:fs";import{dirname as g,join as _,relative as v,resolve as y}from"node:path";import{execFileSync as b}from"node:child_process";import{tmpdir as x}from"node:os";import S from"@babel/parser";var C=/^[a-z][a-z0-9-]{1,39}$/,w=[`Web`,`Phone`],T=[`title`,`navigation`],E=_(g(f(import.meta.url).resolve(`typescript/package.json`)),`bin`,`tsc`),D=[`.jsx`,`.js`,`.tsx`,`.ts`,`.mjs`],re=/^App[A-Z]/,ie={Web:`WeborityWeb`,Phone:`WeborityPhone`};function O(n,r){let i=e(n,r);if(!i)throw Error(`${r} is not installed for ${n}. Run pnpm install there.`);let a=t(_(i,`package.json`)),o=(e,t)=>{if(typeof e==`string`)return t==="default"?e:void 0;if(!(!e||typeof e!=`object`))return typeof e[t]==`string`?e[t]:o(e.import,t)??o(e.default,t)},s=a.exports?.[`.`],c=a.types??o(s,`types`),l=o(s,`default`)??a.main;if(!c)throw Error(`${r} declares no types, and the manifest reads its declaration files.`);if(!l)throw Error(`${r} declares no entry file for its runtime.`);let u=o(a.exports?.[`./canvasKit`],`default`);return{dir:i,pkg:a,typesFile:_(i,c),entryFile:_(i,l),canvasKitFile:u?_(i,u):null}}function k(t){let n=e(t,`@webority/theme`);if(!n)throw Error(`@webority/theme is not installed for ${t}. Run pnpm install.`);return n}function A(e,n,r){let i=t(_(e,`package.json`)),a=i.dependencies?.[n]??i.devDependencies?.[n];if(/^\d+\.\d+\.\d+$/.test(a??``)&&a!==r)throw Error(`${n} is pinned to ${a} in package.json but ${r} is installed. Run pnpm install first.`)}function j(e,t){let n=m(_(x(),`canvas-kit-declarations-`));try{b(process.execPath,[E,`--allowJs`,`--declaration`,`--emitDeclarationOnly`,`--jsx`,`react-jsx`,`--module`,`esnext`,`--moduleResolution`,`bundler`,`--target`,`es2022`,`--skipLibCheck`,`--rootDir`,e,`--outDir`,n,t],{cwd:e,encoding:`utf8`,stdio:`pipe`})}catch(e){throw h(n,{recursive:!0,force:!0}),Error(`Could not read the declarations of ${t}: ${e.stdout||e.stderr||e.message}`)}return n}function M(e,t,n){let i=v(t,n).replace(/\.d\.ts$/,``);for(let t of D)if(p(_(e,`${i}${t}`)))return r(`${i}${t}`);throw Error(`No source file for the declarations in ${n}`)}function N(e,t,r){let i=/\.tsx?$/.test(t)?[`jsx`,`typescript`]:[`jsx`],a=S.parse(n(_(e,t)),{sourceType:`module`,plugins:i});for(let e of a.program.body){let t=e.type===`ExpressionStatement`?e.expression:null;if(t?.type===`AssignmentExpression`&&t.left.type===`MemberExpression`&&!t.left.computed&&t.left.object.type===`Identifier`&&t.left.object.name===r&&t.left.property.name===`displayName`&&t.right.type===`StringLiteral`)return t.right.value}return null}function P(e){return e.filter(e=>e.type===`array`&&(e.itemFields??[]).some(e=>[`href`,`to`].includes(e.name))).map(e=>e.name)}function F(e,t){return e.filter(e=>e[t]===!0).map(e=>e.name)}function I(e){return e.map(e=>Object.fromEntries(Object.entries(e).filter(([e])=>e!==`handler`&&e!==`itemHandler`).map(([e,t])=>[e,Array.isArray(t)&&(e===`fields`||e===`itemFields`)?I(t):t])))}function L(e,n){if(!n)return;let r=t(n);if(typeof r!=`object`||!r||Array.isArray(r))throw Error(`${n} must be an object from component name to role.`);for(let[t,i]of Object.entries(r)){let r=e.find(e=>e.name===t);if(!r)throw Error(`${n} names ${t}, which the kit does not have.`);if(!T.includes(i))throw Error(`${n}: ${t} has role ${JSON.stringify(i)}; a role is title or navigation.`);r.role=i}}function R(e){let n=t(e);if(!Array.isArray(n)||n.some(e=>typeof e?.name!=`string`))throw Error(`${e} must be the style key table: a list of style keys, each with a name.`);return n}function z(e){let n=t(e);if(n?.schema!==1)throw Error(`${e} has schema ${n?.schema}; this reader reads schema 1.`);if(!n.itemActions)throw Error(`${e} has no itemActions; the phone kit's action lists come from it.`);return{flags:n.styleKeys??{},itemActions:n.itemActions}}function B(e,t,n){let r=e.map(({name:e})=>e),i=r.filter(e=>typeof t[e]!=`boolean`),a=Object.keys(t).filter(e=>!r.includes(e));if(i.length>0||a.length>0)throw Error(`${n} must list exactly the style keys of the style key table, each true or false. Missing or not a boolean: ${i.join(`, `)||`none`}. Not in the table: ${a.join(`, `)||`none`}.`)}function V(e,t){return e.map(({name:e,type:n,values:r,appliesTo:i,description:a})=>({name:e,type:n,values:r,appliesTo:i,...t?{phoneSupported:t[e]}:{},description:a}))}function H({projectRoot:e,kit:r,platform:f,entry:p,libraryPackage:m,rolesFile:g,rendererProtocolVersion:b,phoneRendererSupportFile:x,styleKeysFile:S}){if(!C.test(r??``))throw Error(`kit ${JSON.stringify(r)} must be 2 to 40 characters: lowercase letters, digits and hyphens, starting with a letter.`);if(!w.includes(f))throw Error(`platform must be Web or Phone, not ${JSON.stringify(f)}.`);if(!Number.isInteger(b)||b<1)throw Error(`rendererProtocolVersion must be a positive integer, not ${JSON.stringify(b)}.`);if(f===`Phone`&&!x)throw Error(`A Phone kit needs phoneRendererSupportFile, the phone renderer's support file.`);let T=y(e),E=O(T,m);A(T,m,E.pkg.version);let D=x?z(x):null,H=f===`Phone`?D:null,U=S?R(S):null;U&&D&&B(U,D.flags,x);let W=i(E.typesFile,{namedConsts:!0,kit:m}),G=f===`Phone`?W.components.filter(({name:e})=>!a.has(e)):W.components,K=[];if(f===`Phone`){if(!E.canvasKitFile)throw Error(`${m} exports no ./canvasKit subpath; a Phone kit takes the device frame parts from it.`);K=s(E.canvasKitFile,m);let e=new Set(G.map(({name:e})=>e)),t=K.filter(({name:t})=>e.has(t)).map(({name:e})=>e);if(t.length>0)throw Error(`${m} exports ${t.join(`, `)} from both its main entry and ./canvasKit.`)}let q={components:[],warnings:[]},J=new Map;if(p!==void 0){let e=y(p);if(v(T,e).startsWith(`..`))throw Error(`The kit entry ${e} is outside the product folder ${T}.`);let t=j(T,e);try{q=i(_(t,v(T,e)).replace(/\.[^./\\]+$/,`.d.ts`),{kit:r}),J=new Map(q.components.map(e=>[e.name,M(T,t,e.file)]))}finally{h(t,{recursive:!0,force:!0})}}let ae=new Set([...G,...K].map(({name:e})=>e)),Y=q.components.filter(({name:e})=>ae.has(e)).map(({name:e})=>e);if(Y.length>0)throw Error(`The kit names ${Y.join(`, `)} as ${m} already has them; rename the product components.`);let X=[...G.map(e=>({...e,source:m,marker:re.test(e.name)?e.name:null})),...q.components.map(e=>{let t=J.get(e.name);return{...e,source:t,marker:N(T,t,e.name)}})].map(({name:e,marker:t,acceptsChildren:n,props:r,source:i})=>({name:e,marker:t,acceptsChildren:n,props:I(r),itemsTakeAction:f===`Web`?P(r):F(r,`itemHandler`),takesAction:f===`Web`?[]:F(r,`handler`),source:i})).concat(K).sort((e,t)=>e.name<t.name?-1:+(e.name>t.name));H&&o(X,H.itemActions),L(X,g);let Z,Q,$;if(f===`Web`){let e=k(T);Z=d(n(_(e,`scss`,`_tokens.scss`))),Z.colorMeanings=ee(Z.color,t(_(e,`token-meanings.json`))),Q=ne(_(e,`dist`,`published-theme.json`),Z),$=te(_(E.dir,`dist`))}else{let e=_(E.dir,`lib`,`module`,`theme`,`tokens.js`);Z=u(e),Q=l(e),$=c(_(E.dir,`lib`,`typescript`,`module`,`components`,`AppIcon`,`catalog.g.d.ts`))}return{manifest:{kind:p===void 0?ie[f]:`Product`,library:{name:E.pkg.name,version:E.pkg.version},rendererProtocolVersion:b,platform:f,kitModuleVersion:2,productKit:null,components:X,tokens:Z,tokenValues:Q,icons:$,...U?{styleKeys:V(U,H?H.flags:null)}:{}},warnings:[...W.warnings,...q.warnings],phoneChromeNames:K.map(({name:e})=>e)}}export{O as libraryFiles,H as readManifest,z as readPhoneSupport};
1
+ import{findPackageDir as e,readJson as t,readText as n,toPosix as r}from"./files.js";import"./kitModule.js";import{collectComponents as i}from"./declarations.js";import{PHONE_EXCLUDED_COMPONENTS as a,applyPhoneActions as o,phoneChromeEntries as s,phoneIcons as c,phoneTokenValues as l,phoneTokens as u}from"./phone.js";import{colourMeanings as d,webIcons as ee,webTokenValues as te,webTokens as ne}from"./tokens.js";import{createRequire as f}from"node:module";import{existsSync as p,mkdtempSync as m,rmSync as h}from"node:fs";import{dirname as g,join as _,relative as v,resolve as y}from"node:path";import{execFileSync as b}from"node:child_process";import{tmpdir as x}from"node:os";import S from"@babel/parser";var re=/^[a-z][a-z0-9-]{1,39}$/,C=[`Web`,`Phone`],w=[`title`,`navigation`],T=_(g(f(import.meta.url).resolve(`typescript/package.json`)),`bin`,`tsc`),E=[`.jsx`,`.js`,`.tsx`,`.ts`,`.mjs`],ie=/^App[A-Z]/,ae={Web:`WeborityWeb`,Phone:`WeborityPhone`};function D(n,r){let i=e(n,r);if(!i)throw Error(`${r} is not installed for ${n}. Run pnpm install there.`);let a=t(_(i,`package.json`)),o=(e,t)=>{if(typeof e==`string`)return t==="default"?e:void 0;if(!(!e||typeof e!=`object`))return typeof e[t]==`string`?e[t]:o(e.import,t)??o(e.default,t)},s=a.exports?.[`.`],c=a.types??o(s,`types`),l=o(s,`default`)??a.main;if(!c)throw Error(`${r} declares no types, and the manifest reads its declaration files.`);if(!l)throw Error(`${r} declares no entry file for its runtime.`);let u=o(a.exports?.[`./canvasKit`],`default`);return{dir:i,pkg:a,typesFile:_(i,c),entryFile:_(i,l),canvasKitFile:u?_(i,u):null}}function O(t){let n=e(t,`@webority/theme`);if(!n)throw Error(`@webority/theme is not installed for ${t}. Run pnpm install.`);return n}function k(e,n,r){let i=t(_(e,`package.json`)),a=i.dependencies?.[n]??i.devDependencies?.[n];if(/^\d+\.\d+\.\d+$/.test(a??``)&&a!==r)throw Error(`${n} is pinned to ${a} in package.json but ${r} is installed. Run pnpm install first.`)}function A(e,t){let n=m(_(x(),`canvas-kit-declarations-`));try{b(process.execPath,[T,`--allowJs`,`--declaration`,`--emitDeclarationOnly`,`--jsx`,`react-jsx`,`--module`,`esnext`,`--moduleResolution`,`bundler`,`--target`,`es2022`,`--skipLibCheck`,`--rootDir`,e,`--outDir`,n,t],{cwd:e,encoding:`utf8`,stdio:`pipe`})}catch(e){throw h(n,{recursive:!0,force:!0}),Error(`Could not read the declarations of ${t}: ${e.stdout||e.stderr||e.message}`)}return n}function j(e,t,n){let i=v(t,n).replace(/\.d\.ts$/,``);for(let t of E)if(p(_(e,`${i}${t}`)))return r(`${i}${t}`);throw Error(`No source file for the declarations in ${n}`)}function M(e,t,r){let i=/\.tsx?$/.test(t)?[`jsx`,`typescript`]:[`jsx`],a=S.parse(n(_(e,t)),{sourceType:`module`,plugins:i});for(let e of a.program.body){let t=e.type===`ExpressionStatement`?e.expression:null;if(t?.type===`AssignmentExpression`&&t.left.type===`MemberExpression`&&!t.left.computed&&t.left.object.type===`Identifier`&&t.left.object.name===r&&t.left.property.name===`displayName`&&t.right.type===`StringLiteral`)return t.right.value}return null}function N(e){return e.filter(e=>e.type===`array`&&(e.itemFields??[]).some(e=>[`href`,`to`].includes(e.name))).map(e=>e.name)}function P(e,t){return e.filter(e=>e[t]===!0).map(e=>e.name)}function F(e){return e.map(e=>Object.fromEntries(Object.entries(e).filter(([e])=>e!==`handler`&&e!==`itemHandler`).map(([e,t])=>[e,Array.isArray(t)&&(e===`fields`||e===`itemFields`)?F(t):t])))}function I(e,n){if(!n)return;let r=t(n);if(typeof r!=`object`||!r||Array.isArray(r))throw Error(`${n} must be an object from component name to role.`);for(let[t,i]of Object.entries(r)){let r=e.find(e=>e.name===t);if(!r)throw Error(`${n} names ${t}, which the kit does not have.`);if(!w.includes(i))throw Error(`${n}: ${t} has role ${JSON.stringify(i)}; a role is title or navigation.`);r.role=i}}function L(e){let n=t(e);if(!Array.isArray(n)||n.some(e=>typeof e?.name!=`string`))throw Error(`${e} must be the style key table: a list of style keys, each with a name.`);return n}function R(e){let n=t(e);if(n?.schema!==1)throw Error(`${e} has schema ${n?.schema}; this reader reads schema 1.`);if(!n.itemActions)throw Error(`${e} has no itemActions; the phone kit's action lists come from it.`);return{flags:n.styleKeys??{},itemActions:n.itemActions}}function z(e,t,n){let r=e.map(({name:e})=>e),i=r.filter(e=>typeof t[e]!=`boolean`),a=Object.keys(t).filter(e=>!r.includes(e));if(i.length>0||a.length>0)throw Error(`${n} must list exactly the style keys of the style key table, each true or false. Missing or not a boolean: ${i.join(`, `)||`none`}. Not in the table: ${a.join(`, `)||`none`}.`)}function B(e,t){return e.map(({name:e,type:n,values:r,appliesTo:i,description:a})=>({name:e,type:n,values:r,appliesTo:i,...t?{phoneSupported:t[e]}:{},description:a}))}function V({projectRoot:e,kit:r,platform:f,entry:p,libraryPackage:m,rolesFile:g,rendererProtocolVersion:b,phoneRendererSupportFile:x,styleKeysFile:S}){if(!re.test(r??``))throw Error(`kit ${JSON.stringify(r)} must be 2 to 40 characters: lowercase letters, digits and hyphens, starting with a letter.`);if(!C.includes(f))throw Error(`platform must be Web or Phone, not ${JSON.stringify(f)}.`);if(!Number.isInteger(b)||b<1)throw Error(`rendererProtocolVersion must be a positive integer, not ${JSON.stringify(b)}.`);if(f===`Phone`&&!x)throw Error(`A Phone kit needs phoneRendererSupportFile, the phone renderer's support file.`);let w=y(e),T=D(w,m);k(w,m,T.pkg.version);let E=x?R(x):null,V=f===`Phone`?E:null,H=S?L(S):null;H&&E&&z(H,E.flags,x);let U=i(T.typesFile,{namedConsts:!0,kit:m}),W=f===`Phone`?U.components.filter(({name:e})=>!a.has(e)):U.components,G=[];if(f===`Phone`){if(!T.canvasKitFile)throw Error(`${m} exports no ./canvasKit subpath; a Phone kit takes the device frame parts from it.`);G=s(T.canvasKitFile,m);let e=new Set(W.map(({name:e})=>e)),t=G.filter(({name:t})=>e.has(t)).map(({name:e})=>e);if(t.length>0)throw Error(`${m} exports ${t.join(`, `)} from both its main entry and ./canvasKit.`)}let K={components:[],warnings:[],unreadable:[]},q=new Map;if(p!==void 0){let e=y(p);if(v(w,e).startsWith(`..`))throw Error(`The kit entry ${e} is outside the product folder ${w}.`);let t=A(w,e);try{K=i(_(t,v(w,e)).replace(/\.[^./\\]+$/,`.d.ts`),{kit:r}),q=new Map(K.components.map(e=>[e.name,j(w,t,e.file)]))}finally{h(t,{recursive:!0,force:!0})}}let J=[...U.unreadable.filter(e=>f!==`Phone`||!a.has(e)).map(e=>`${m} ${e}`),...K.unreadable.map(e=>`${r} ${e}`)];if(J.length>0)throw Error(`The kit would leave out ${J.join(`, `)}: their props could not be read. Give each a props type the reader can follow, or list it as not drawn.`);let oe=new Set([...W,...G].map(({name:e})=>e)),Y=K.components.filter(({name:e})=>oe.has(e)).map(({name:e})=>e);if(Y.length>0)throw Error(`The kit names ${Y.join(`, `)} as ${m} already has them; rename the product components.`);let X=[...W.map(e=>({...e,source:m,marker:ie.test(e.name)?e.name:null})),...K.components.map(e=>{let t=q.get(e.name);return{...e,source:t,marker:M(w,t,e.name)}})].map(({name:e,marker:t,acceptsChildren:n,props:r,source:i})=>({name:e,marker:t,acceptsChildren:n,props:F(r),itemsTakeAction:f===`Web`?N(r):P(r,`itemHandler`),takesAction:f===`Web`?[]:P(r,`handler`),source:i})).concat(G).sort((e,t)=>e.name<t.name?-1:+(e.name>t.name));V&&o(X,V.itemActions),I(X,g);let Z,Q,$;if(f===`Web`){let e=O(w);Z=ne(n(_(e,`scss`,`_tokens.scss`))),Z.colorMeanings=d(Z.color,t(_(e,`token-meanings.json`))),Q=te(_(e,`dist`,`published-theme.json`),Z),$=ee(_(T.dir,`dist`))}else{let e=_(T.dir,`lib`,`module`,`theme`,`tokens.js`);Z=u(e),Q=l(e),$=c(_(T.dir,`lib`,`typescript`,`module`,`components`,`AppIcon`,`catalog.g.d.ts`))}return{manifest:{kind:p===void 0?ae[f]:`Product`,library:{name:T.pkg.name,version:T.pkg.version},rendererProtocolVersion:b,platform:f,kitModuleVersion:2,productKit:null,components:X,tokens:Z,tokenValues:Q,icons:$,...H?{styleKeys:B(H,V?V.flags:null)}:{}},warnings:[...U.warnings,...K.warnings],phoneChromeNames:G.map(({name:e})=>e)}}export{D as libraryFiles,V as readManifest,R as readPhoneSupport};
package/dist/meta.d.ts ADDED
@@ -0,0 +1,80 @@
1
+ /** A prop type, in the kit manifest wire names (CanvasManifestProp.Type). Event handlers are never described: DesignKeys leaves them out. */
2
+ export type MetaPropType =
3
+ | "string"
4
+ | "number"
5
+ | "stringOrNumber"
6
+ | "boolean"
7
+ | "enum"
8
+ | "enumOrNumber"
9
+ | "url"
10
+ | "icon"
11
+ | "node"
12
+ | "array"
13
+ | "object"
14
+ | "any";
15
+
16
+ export interface MetaProp {
17
+ type: MetaPropType;
18
+ /**
19
+ * The values of an enum, in the order the component lists them; a numeric literal union lists numbers.
20
+ * On an enumOrNumber, the named values only: the prop also takes any number. Only on these two types, and required there.
21
+ */
22
+ values?: readonly (string | number)[];
23
+ /** The value the component applies when the prop is left out, as JSON. Never on a required prop. */
24
+ default?: unknown;
25
+ required?: boolean;
26
+ description: string;
27
+ /** The fields of an object prop. Only on an object. */
28
+ fields?: Readonly<Record<string, MetaProp>>;
29
+ /** The fields of each item of a list whose items are objects. Only on an array. */
30
+ itemFields?: Readonly<Record<string, MetaProp>>;
31
+ }
32
+
33
+ /** A placed element: a component of the kit, or one of the HTML tags in HTML_TAGS. A node or icon prop value may be a MetaNode. */
34
+ export interface MetaNode {
35
+ component: string;
36
+ props?: Readonly<Record<string, unknown>>;
37
+ /** Text, or a list of placed elements and text items. */
38
+ children?: string | readonly (MetaNode | string)[];
39
+ }
40
+
41
+ export interface MetaExample {
42
+ /** The parity case id: the component name for its base example, "<name>.<case>" for the others. */
43
+ id: string;
44
+ title: string;
45
+ props: Readonly<Record<string, unknown>>;
46
+ children?: string | readonly (MetaNode | string)[];
47
+ /** An element the example is placed inside, for a component that only renders within a parent. */
48
+ wrap?: MetaNode;
49
+ }
50
+
51
+ /** One side of a do and dont pair; do[i] is shown beside dont[i]. Example props may be scalars, icons, nodes, or arrays and objects checked against the prop's itemFields or fields. */
52
+ export interface MetaPractice {
53
+ note: string;
54
+ example: readonly MetaNode[];
55
+ }
56
+
57
+ export interface ComponentUsage {
58
+ when: readonly string[];
59
+ whenNot: readonly { text: string; instead?: string }[];
60
+ do: readonly MetaPractice[];
61
+ dont: readonly MetaPractice[];
62
+ a11y: readonly string[];
63
+ }
64
+
65
+ export interface ComponentMeta {
66
+ /** The catalogue name, such as AppButton. */
67
+ name: string;
68
+ /** The data-wui value the component renders, or null when it renders none. */
69
+ marker: string | null;
70
+ platforms: readonly ("web" | "phone")[];
71
+ acceptsChildren: boolean;
72
+ props: Readonly<Record<string, MetaProp>>;
73
+ /** Design props deliberately not shown in the kit, such as a render prop no kit type fits. The type check accepts them unlisted. */
74
+ omit?: readonly string[];
75
+ examples: readonly MetaExample[];
76
+ usage: ComponentUsage;
77
+ }
78
+
79
+ /** Returns the meta unchanged; the const parameter keeps literal types for the type check. */
80
+ export declare function defineMeta<const M extends ComponentMeta>(meta: M): M;
package/dist/meta.js ADDED
@@ -0,0 +1 @@
1
+ function e(e){return e}export{e as defineMeta};
@@ -0,0 +1,104 @@
1
+ // Type rules that prove a meta equals its component's typed props. P is the props type (React ComponentProps of
2
+ // the component), N is React's ReactNode, both supplied by the generated check file so this file imports no react.
3
+ import type { ComponentMeta, MetaProp } from "./meta.js";
4
+
5
+ type IsAny<T> = 0 extends 1 & T ? true : false;
6
+ type Same<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;
7
+ type Handler = (...args: never[]) => unknown;
8
+ // React's ElementType and ComponentType both carry a class constructor member; a render prop never does.
9
+ type Constructor = abstract new (...args: never[]) => unknown;
10
+ type Defined<T> = Exclude<T, null | undefined>;
11
+ type Shape = Readonly<Record<string, MetaProp>>;
12
+
13
+ /** Every field a design sets at any depth: all but event handlers and component-typed fields. */
14
+ type FieldKeys<P> = {
15
+ [K in keyof P]-?: IsAny<P[K]> extends true
16
+ ? K
17
+ : [Defined<P[K]>] extends [Handler]
18
+ ? never
19
+ : [Extract<Defined<P[K]>, Constructor>] extends [never]
20
+ ? K
21
+ : never;
22
+ }[keyof P] &
23
+ string;
24
+
25
+ /** Every prop a design sets: the field keys, less React's children, ref and key (a nested data field may be named key). */
26
+ export type DesignKeys<P> = Exclude<FieldKeys<P>, "children" | "ref" | "key">;
27
+
28
+ type RequiredKeys<P> = { [K in keyof P]-?: Partial<Pick<P, K>> extends Pick<P, K> ? never : K }[keyof P];
29
+ type ItemOf<T> = Defined<T> extends readonly (infer I)[] ? I : Defined<T> extends ReadonlySet<infer I> ? I : never;
30
+
31
+ type ValueOk<T, M extends MetaProp, N> = M["type"] extends "any"
32
+ ? IsAny<T>
33
+ : IsAny<T> extends true
34
+ ? false
35
+ : M["type"] extends "enum"
36
+ ? Same<Defined<T>, NonNullable<M["values"]>[number]>
37
+ : M["type"] extends "enumOrNumber"
38
+ ? Same<Defined<T>, NonNullable<M["values"]>[number] | number>
39
+ : M["type"] extends "boolean"
40
+ ? Same<Defined<T>, boolean>
41
+ : M["type"] extends "number"
42
+ ? Same<Defined<T>, number>
43
+ : M["type"] extends "stringOrNumber"
44
+ ? // A Date prop is written as an ISO string in a meta, so string | number | Date is a stringOrNumber too.
45
+ Same<Defined<T>, string | number> extends true
46
+ ? true
47
+ : Same<Defined<T>, string | number | Date>
48
+ : M["type"] extends "string" | "url"
49
+ ? Same<Defined<T>, string>
50
+ : M["type"] extends "icon"
51
+ ? string extends Defined<T>
52
+ ? true
53
+ : false
54
+ : M["type"] extends "node"
55
+ ? Defined<N> extends Defined<T>
56
+ ? true
57
+ : false
58
+ : M["type"] extends "array"
59
+ ? [Defined<T>] extends [readonly unknown[] | ReadonlySet<unknown>]
60
+ ? true
61
+ : false
62
+ : M["type"] extends "object"
63
+ ? [Defined<T>] extends [readonly unknown[] | ReadonlySet<unknown> | Handler]
64
+ ? false
65
+ : [Defined<T>] extends [object]
66
+ ? true
67
+ : false
68
+ : false;
69
+
70
+ type RequiredOk<P, K extends keyof P, M extends MetaProp> = Same<
71
+ K extends RequiredKeys<P> ? true : false,
72
+ M["required"] extends true ? true : false
73
+ >;
74
+
75
+ type NestedOk<T, M extends MetaProp, N> = M["type"] extends "object"
76
+ ? M["fields"] extends Shape
77
+ ? ShapeOk<Defined<T>, M["fields"], N>
78
+ : true
79
+ : M["type"] extends "array"
80
+ ? M["itemFields"] extends Shape
81
+ ? ShapeOk<ItemOf<T>, M["itemFields"], N>
82
+ : true
83
+ : true;
84
+
85
+ type ShapeOk<T, F extends Shape, N> =
86
+ Same<FieldKeys<T>, keyof F & string> extends true ? ([PropsMismatch<T, F, N>] extends [never] ? true : false) : false;
87
+
88
+ /** The names of meta props whose type, required flag or nested fields differ from the component's. */
89
+ export type PropsMismatch<P, F extends Shape, N> = {
90
+ [K in keyof F & keyof P & string]: ValueOk<P[K], F[K], N> extends true
91
+ ? RequiredOk<P, K, F[K]> extends true
92
+ ? NestedOk<P[K], F[K], N> extends true
93
+ ? never
94
+ : K
95
+ : K
96
+ : K;
97
+ }[keyof F & keyof P & string];
98
+
99
+ /** Props the component takes that the meta neither lists nor omits. */
100
+ export type ExtraProps<P, M extends ComponentMeta> = Exclude<DesignKeys<P>, keyof M["props"] | NonNullable<M["omit"]>[number]>;
101
+ /** Props the meta lists that the component does not take. */
102
+ export type MissingProps<P, M extends ComponentMeta> = Exclude<keyof M["props"] & string, DesignKeys<P>>;
103
+ export type MismatchedProps<P, M extends ComponentMeta, N> = PropsMismatch<P, M["props"], N>;
104
+ export type ChildrenOk<P, M extends ComponentMeta> = Same<"children" extends keyof P ? true : false, M["acceptsChildren"]>;
@@ -0,0 +1 @@
1
+ function e(e){throw Error(`checkMetaTypes is not built yet.`)}export{e as checkMetaTypes};
package/dist/metas.js ADDED
@@ -0,0 +1 @@
1
+ var e=Object.freeze([`a`,`b`,`button`,`div`,`img`,`kbd`,`li`,`p`,`span`,`strong`,`table`,`tbody`,`td`,`th`,`thead`,`tr`,`ul`]);async function t(e){throw Error(`readMetas is not built yet.`)}function n(e){throw Error(`checkMetas is not built yet.`)}function r(e,t){throw Error(`manifestComponent is not built yet.`)}function i(e,t){throw Error(`componentModuleOf is not built yet.`)}export{e as HTML_TAGS,n as checkMetas,i as componentModuleOf,r as manifestComponent,t as readMetas};
package/dist/phone.js CHANGED
@@ -1 +1 @@
1
- import{readText as e}from"./files.js";import t from"@babel/parser";var n=new Set([`Form`,`NetworkStatusBanner`,`SkeletonClockProvider`,`SkeletonProvider`,`SkeletonSkip`,`ThemeProvider`,`ToastProvider`,`Box`,`Text`]),r=[`sans`],i=`System`;function a(n){return t.parse(e(n),{sourceType:`module`,plugins:[`typescript`]})}function o(e){return[...new Set(e)].sort((e,t)=>e<t?-1:+(e>t))}function s(e){return e.type===`Identifier`?e.name:e.type===`StringLiteral`?e.value:null}function c(e){let t=new Map;for(let n of e.program.body){let e=n.type===`ExportNamedDeclaration`?n.declaration:n;if(e?.type===`VariableDeclaration`)for(let n of e.declarations)n.id.type===`Identifier`&&t.set(n.id.name,n.init)}return t}function l(e,t,n){let r=t;for(let t=0;r?.type===`Identifier`;t+=1){if(t>10||!e.has(r.name))throw Error(`${r.name} in ${n} is not a constant the reader can follow.`);r=e.get(r.name)}return r}function u(e,t,n,r){let i=n.properties.find(e=>e.type===`ObjectProperty`&&s(e.key)===r);if(!i)throw Error(`${r} is missing from the theme in ${t}`);return l(e,i.value,t)}function d(e){return e.properties.filter(e=>e.type===`ObjectProperty`).map(e=>s(e.key))}function f(e,t,n,r=``){return n.properties.flatMap(n=>{if(n.type!==`ObjectProperty`)return[];let i=`${r}${s(n.key)}`,a=l(e,n.value,t);return a.type===`StringLiteral`?[i]:a.type===`ObjectExpression`?f(e,t,a,`${i}.`):[]})}function p(e){let t=c(a(e));if(!t.has(`lightTheme`))throw Error(`lightTheme is not declared in ${e}`);let n=l(t,t.get(`lightTheme`),e),i=u(t,e,n,`typography`);return{color:o(f(t,e,u(t,e,n,`colors`))),space:o(d(u(t,e,n,`spacing`))),radius:o(d(u(t,e,n,`radius`))),shadow:o(d(u(t,e,n,`shadows`))),font:r,text:o(d(u(t,e,i,`fontSize`)))}}function m(e,t,n){let r=l(e,t,n);if(r.type===`StringLiteral`||r.type===`NumericLiteral`)return r.value;if(r.type===`UnaryExpression`&&r.operator===`-`&&r.argument.type===`NumericLiteral`)return-r.argument.value;if(r.type===`ObjectExpression`)return Object.fromEntries(r.properties.map(t=>{if(t.type!==`ObjectProperty`)throw Error(`${n} spreads an object the reader cannot follow.`);return[s(t.key),m(e,t.value,n)]}));throw Error(`${n} has a ${r.type} the reader cannot read as a value.`)}function h(e,t,n){for(let r of[[`typography`,`fontFamily`,`sans`],[`fontFamily`,`sans`]])try{let i=g(e,t,n,r);if(typeof i==`string`&&i!==``)return i}catch{}return`System`}function g(e,t,n,r){let i=l(e,n,t);for(let n of r)i=u(e,t,i,n);return m(e,i,t)}function _(e,t,n){return Object.fromEntries(Object.entries(e).map(([e,r])=>{if(typeof r!=`number`)throw Error(`${t}.${e} in ${n} is not a number.`);return[e,r]}))}function v(e,t,n){if(Object.keys(e).length===0)return`none`;let{shadowColor:r,shadowOffset:i,shadowOpacity:a,shadowRadius:o}=e,s=/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(typeof r==`string`?r:``);if(!s||typeof i?.width!=`number`||typeof i?.height!=`number`||typeof a!=`number`||typeof o!=`number`)throw Error(`shadows.${t} in ${n} is not a shadow the reader can draw.`);let c=s[1].length===3?[...s[1]].map(e=>e+e).join(``):s[1],[l,u,d]=[0,2,4].map(e=>Number.parseInt(c.slice(e,e+2),16));return`${i.width}px ${i.height}px ${o}px rgba(${l}, ${u}, ${d}, ${a})`}function y(e){let t=c(a(e));for(let n of[`lightTheme`,`darkTheme`])if(!t.has(n))throw Error(`${n} is not declared in ${e}; the phone kit's token values need the light and dark themes.`);let n=t.get(`lightTheme`),r=t.get(`darkTheme`),o=u(t,e,l(t,n,e),`colors`),s=u(t,e,l(t,r,e),`colors`),d=h(t,e,n);return{color:Object.fromEntries(f(t,e,o).map(n=>{let r=n.split(`.`);return[n,{light:g(t,e,o,r),dark:g(t,e,s,r)}]})),space:_(g(t,e,n,[`spacing`]),`spacing`,e),radius:_(g(t,e,n,[`radius`]),`radius`,e),shadow:Object.fromEntries(Object.entries(g(t,e,n,[`shadows`])).map(([t,n])=>[t,v(n,t,e)])),font:{sans:{family:d,fallback:i}},text:Object.fromEntries(Object.entries(_(g(t,e,n,[`typography`,`fontSize`]),`fontSize`,e)).map(([e,t])=>[e,{size:t,lineHeight:null,weight:null}]))}}function b(e){let t=a(e).program.body.map(e=>e.type===`ExportNamedDeclaration`?e.declaration:e).find(e=>e?.type===`TSTypeAliasDeclaration`&&e.id.name===`IconName`);if(t?.typeAnnotation.type!==`TSUnionType`)throw Error(`IconName union not found in ${e}`);return o(t.typeAnnotation.types.map(t=>{if(t.type!==`TSLiteralType`||t.literal.type!==`StringLiteral`)throw Error(`IconName in ${e} has a member that is not a string literal`);return t.literal.value}))}function x(e,t,n){let r=l(e,t,n);switch(r.type){case`StringLiteral`:case`NumericLiteral`:case`BooleanLiteral`:return r.value;case`UnaryExpression`:if(r.operator===`!`&&r.argument.type===`NumericLiteral`)return!r.argument.value;break;case`ArrayExpression`:return r.elements.map(t=>x(e,t,n));case`ObjectExpression`:return Object.fromEntries(r.properties.map(t=>{if(t.type!==`ObjectProperty`||t.computed)throw Error(`phoneChromeEntries in ${n} has an object member the reader cannot follow.`);return[s(t.key),x(e,t.value,n)]}));case`MemberExpression`:if(!r.computed&&r.property.type===`Identifier`){let t=x(e,r.object,n);if(typeof t==`object`&&t&&r.property.name in t)return t[r.property.name]}break}throw Error(`phoneChromeEntries in ${n} has a ${r.type} the reader cannot read as data.`)}function S(e){return new Set(e.program.body.filter(e=>e.type===`ExportNamedDeclaration`&&e.declaration).flatMap(({declaration:e})=>e.type===`VariableDeclaration`?e.declarations.map(e=>e.id.name):[e.id?.name]))}function C(n,r){let i=t.parse(e(n),{sourceType:`module`,plugins:[`jsx`]}),a=c(i);if(!a.has(`phoneChromeEntries`))throw Error(`phoneChromeEntries is not declared in ${n}; the phone kit's frame parts come from it.`);let o=x(a,a.get(`phoneChromeEntries`),n),s=S(i);if(!Array.isArray(o)||o.length===0)throw Error(`phoneChromeEntries in ${n} must be a list of manifest entries.`);return o.map(e=>{let{name:t,marker:i,acceptsChildren:a,props:o,itemsTakeAction:c,takesAction:l,source:u}=e??{};if(typeof t!=`string`||typeof i!=`string`||typeof a!=`boolean`||!Array.isArray(o)||!Array.isArray(c)||!Array.isArray(l))throw Error(`phoneChromeEntries in ${n} has an entry that is not a manifest component: ${JSON.stringify(e)}`);if(u!==r)throw Error(`phoneChromeEntries in ${n}: ${t} names the source ${u}, not ${r}.`);if(!s.has(t))throw Error(`phoneChromeEntries in ${n} lists ${t}, which the module does not export.`);return{name:t,marker:i,acceptsChildren:a,props:o,itemsTakeAction:c,takesAction:l,source:u}})}function w(e,t){for(let[n,r]of[[`itemsTakeAction`,`array`],[`takesAction`,`object`]])for(let[i,a]of Object.entries(t[n]??{})){let t=e.find(({name:e})=>e===i);if(!t)throw Error(`phoneStyleSupport.json ${n} names ${i}, which the kit does not have.`);for(let e of a)if(t.props.find(({name:t})=>t===e)?.type!==r)throw Error(`phoneStyleSupport.json ${n} names ${i}.${e}, which is not a prop of type ${r} in the kit.`);t[n]=o([...new Set([...t[n],...a])])}}export{n as PHONE_EXCLUDED_COMPONENTS,w as applyPhoneActions,C as phoneChromeEntries,b as phoneIcons,y as phoneTokenValues,p as phoneTokens};
1
+ import{readText as e}from"./files.js";import t from"@babel/parser";var n=new Set([`ErrorBoundary`,`Form`,`HookFormField`,`NetworkStatusBanner`,`SkeletonClockProvider`,`SkeletonProvider`,`SkeletonSkip`,`ThemeProvider`,`ToastProvider`,`Box`,`Text`]),r=[`sans`],i=`System`;function a(n){return t.parse(e(n),{sourceType:`module`,plugins:[`typescript`]})}function o(e){return[...new Set(e)].sort((e,t)=>e<t?-1:+(e>t))}function s(e){return e.type===`Identifier`?e.name:e.type===`StringLiteral`?e.value:null}function c(e){let t=new Map;for(let n of e.program.body){let e=n.type===`ExportNamedDeclaration`?n.declaration:n;if(e?.type===`VariableDeclaration`)for(let n of e.declarations)n.id.type===`Identifier`&&t.set(n.id.name,n.init)}return t}function l(e,t,n){let r=t;for(let t=0;r?.type===`Identifier`;t+=1){if(t>10||!e.has(r.name))throw Error(`${r.name} in ${n} is not a constant the reader can follow.`);r=e.get(r.name)}return r}function u(e,t,n,r){let i=n.properties.find(e=>e.type===`ObjectProperty`&&s(e.key)===r);if(!i)throw Error(`${r} is missing from the theme in ${t}`);return l(e,i.value,t)}function d(e){return e.properties.filter(e=>e.type===`ObjectProperty`).map(e=>s(e.key))}function f(e,t,n,r=``){return n.properties.flatMap(n=>{if(n.type!==`ObjectProperty`)return[];let i=`${r}${s(n.key)}`,a=l(e,n.value,t);return a.type===`StringLiteral`?[i]:a.type===`ObjectExpression`?f(e,t,a,`${i}.`):[]})}function p(e){let t=c(a(e));if(!t.has(`lightTheme`))throw Error(`lightTheme is not declared in ${e}`);let n=l(t,t.get(`lightTheme`),e),i=u(t,e,n,`typography`);return{color:o(f(t,e,u(t,e,n,`colors`))),space:o(d(u(t,e,n,`spacing`))),radius:o(d(u(t,e,n,`radius`))),shadow:o(d(u(t,e,n,`shadows`))),font:r,text:o(d(u(t,e,i,`fontSize`)))}}function m(e,t,n){let r=l(e,t,n);if(r.type===`StringLiteral`||r.type===`NumericLiteral`)return r.value;if(r.type===`UnaryExpression`&&r.operator===`-`&&r.argument.type===`NumericLiteral`)return-r.argument.value;if(r.type===`ObjectExpression`)return Object.fromEntries(r.properties.map(t=>{if(t.type!==`ObjectProperty`)throw Error(`${n} spreads an object the reader cannot follow.`);return[s(t.key),m(e,t.value,n)]}));throw Error(`${n} has a ${r.type} the reader cannot read as a value.`)}function h(e,t,n){for(let r of[[`typography`,`fontFamily`,`sans`],[`fontFamily`,`sans`]])try{let i=g(e,t,n,r);if(typeof i==`string`&&i!==``)return i}catch{}return`System`}function g(e,t,n,r){let i=l(e,n,t);for(let n of r)i=u(e,t,i,n);return m(e,i,t)}function _(e,t,n){return Object.fromEntries(Object.entries(e).map(([e,r])=>{if(typeof r!=`number`)throw Error(`${t}.${e} in ${n} is not a number.`);return[e,r]}))}function v(e,t,n){if(Object.keys(e).length===0)return`none`;let{shadowColor:r,shadowOffset:i,shadowOpacity:a,shadowRadius:o}=e,s=/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(typeof r==`string`?r:``);if(!s||typeof i?.width!=`number`||typeof i?.height!=`number`||typeof a!=`number`||typeof o!=`number`)throw Error(`shadows.${t} in ${n} is not a shadow the reader can draw.`);let c=s[1].length===3?[...s[1]].map(e=>e+e).join(``):s[1],[l,u,d]=[0,2,4].map(e=>Number.parseInt(c.slice(e,e+2),16));return`${i.width}px ${i.height}px ${o}px rgba(${l}, ${u}, ${d}, ${a})`}function y(e){let t=c(a(e));for(let n of[`lightTheme`,`darkTheme`])if(!t.has(n))throw Error(`${n} is not declared in ${e}; the phone kit's token values need the light and dark themes.`);let n=t.get(`lightTheme`),r=t.get(`darkTheme`),o=u(t,e,l(t,n,e),`colors`),s=u(t,e,l(t,r,e),`colors`),d=h(t,e,n);return{color:Object.fromEntries(f(t,e,o).map(n=>{let r=n.split(`.`);return[n,{light:g(t,e,o,r),dark:g(t,e,s,r)}]})),space:_(g(t,e,n,[`spacing`]),`spacing`,e),radius:_(g(t,e,n,[`radius`]),`radius`,e),shadow:Object.fromEntries(Object.entries(g(t,e,n,[`shadows`])).map(([t,n])=>[t,v(n,t,e)])),font:{sans:{family:d,fallback:i}},text:Object.fromEntries(Object.entries(_(g(t,e,n,[`typography`,`fontSize`]),`fontSize`,e)).map(([e,t])=>[e,{size:t,lineHeight:null,weight:null}]))}}function b(e){let t=a(e).program.body.map(e=>e.type===`ExportNamedDeclaration`?e.declaration:e).find(e=>e?.type===`TSTypeAliasDeclaration`&&e.id.name===`IconName`);if(t?.typeAnnotation.type!==`TSUnionType`)throw Error(`IconName union not found in ${e}`);return o(t.typeAnnotation.types.map(t=>{if(t.type!==`TSLiteralType`||t.literal.type!==`StringLiteral`)throw Error(`IconName in ${e} has a member that is not a string literal`);return t.literal.value}))}function x(e,t,n){let r=l(e,t,n);switch(r.type){case`StringLiteral`:case`NumericLiteral`:case`BooleanLiteral`:return r.value;case`UnaryExpression`:if(r.operator===`!`&&r.argument.type===`NumericLiteral`)return!r.argument.value;break;case`ArrayExpression`:return r.elements.map(t=>x(e,t,n));case`ObjectExpression`:return Object.fromEntries(r.properties.map(t=>{if(t.type!==`ObjectProperty`||t.computed)throw Error(`phoneChromeEntries in ${n} has an object member the reader cannot follow.`);return[s(t.key),x(e,t.value,n)]}));case`MemberExpression`:if(!r.computed&&r.property.type===`Identifier`){let t=x(e,r.object,n);if(typeof t==`object`&&t&&r.property.name in t)return t[r.property.name]}break}throw Error(`phoneChromeEntries in ${n} has a ${r.type} the reader cannot read as data.`)}function S(e){return new Set(e.program.body.filter(e=>e.type===`ExportNamedDeclaration`&&e.declaration).flatMap(({declaration:e})=>e.type===`VariableDeclaration`?e.declarations.map(e=>e.id.name):[e.id?.name]))}function C(n,r){let i=t.parse(e(n),{sourceType:`module`,plugins:[`jsx`]}),a=c(i);if(!a.has(`phoneChromeEntries`))throw Error(`phoneChromeEntries is not declared in ${n}; the phone kit's frame parts come from it.`);let o=x(a,a.get(`phoneChromeEntries`),n),s=S(i);if(!Array.isArray(o)||o.length===0)throw Error(`phoneChromeEntries in ${n} must be a list of manifest entries.`);return o.map(e=>{let{name:t,marker:i,acceptsChildren:a,props:o,itemsTakeAction:c,takesAction:l,source:u}=e??{};if(typeof t!=`string`||typeof i!=`string`||typeof a!=`boolean`||!Array.isArray(o)||!Array.isArray(c)||!Array.isArray(l))throw Error(`phoneChromeEntries in ${n} has an entry that is not a manifest component: ${JSON.stringify(e)}`);if(u!==r)throw Error(`phoneChromeEntries in ${n}: ${t} names the source ${u}, not ${r}.`);if(!s.has(t))throw Error(`phoneChromeEntries in ${n} lists ${t}, which the module does not export.`);return{name:t,marker:i,acceptsChildren:a,props:o,itemsTakeAction:c,takesAction:l,source:u}})}function w(e,t){for(let[n,r]of[[`itemsTakeAction`,`array`],[`takesAction`,`object`]])for(let[i,a]of Object.entries(t[n]??{})){let t=e.find(({name:e})=>e===i);if(!t)throw Error(`phoneStyleSupport.json ${n} names ${i}, which the kit does not have.`);for(let e of a)if(t.props.find(({name:t})=>t===e)?.type!==r)throw Error(`phoneStyleSupport.json ${n} names ${i}.${e}, which is not a prop of type ${r} in the kit.`);t[n]=o([...new Set([...t[n],...a])])}}export{n as PHONE_EXCLUDED_COMPONENTS,w as applyPhoneActions,C as phoneChromeEntries,b as phoneIcons,y as phoneTokenValues,p as phoneTokens};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/canvas-kit",
3
- "version": "0.87.3",
3
+ "version": "0.88.1",
4
4
  "description": "Builds product kits for Webority Canvas: a kit bundle, its manifest, and the spec shape the renderers answer.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -11,7 +11,11 @@
11
11
  "exports": {
12
12
  ".": "./dist/index.js",
13
13
  "./kitModule": "./dist/kitModule.js",
14
- "./browser": "./dist/browser.js"
14
+ "./browser": "./dist/browser.js",
15
+ "./meta": {
16
+ "types": "./dist/meta.d.ts",
17
+ "default": "./dist/meta.js"
18
+ }
15
19
  },
16
20
  "bin": {
17
21
  "canvas-kit": "./dist/cli.js"
@@ -22,8 +26,7 @@
22
26
  "vite": "^8.0.12"
23
27
  },
24
28
  "devDependencies": {
25
- "react": "^19.2.6",
26
- "@webority/ui-react": "0.87.3"
29
+ "react": "^19.2.6"
27
30
  },
28
31
  "scripts": {
29
32
  "build": "vite build --config vite.cli.config.js",