cascivo 1.0.1 → 1.2.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/dist/args-CtmltI1S.mjs +2 -0
- package/dist/args-CtmltI1S.mjs.map +1 -0
- package/dist/audit-DqWSsQGC.mjs +11 -0
- package/dist/audit-DqWSsQGC.mjs.map +1 -0
- package/dist/{config-BtDgrvK3.mjs → config-DT-Cs7bC.mjs} +2 -2
- package/dist/{config-BtDgrvK3.mjs.map → config-DT-Cs7bC.mjs.map} +1 -1
- package/dist/email-CwQcZ-mB.mjs +4 -0
- package/dist/email-CwQcZ-mB.mjs.map +1 -0
- package/dist/generated/audit-contract.json +64 -11
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +80 -54
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -3
- package/dist/audit-DORMLLCY.mjs +0 -10
- package/dist/audit-DORMLLCY.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{a as e,
|
|
3
|
-
Styling: cascivo components read --cascivo-* tokens, which this project does not import yet.`),console.log(` ${
|
|
4
|
-
`));let e;try{e=await ke(t,n,i,{pm:
|
|
5
|
-
`)}`)}if(
|
|
6
|
-
`}function
|
|
7
|
-
`}function
|
|
2
|
+
import{a as e,l as t,n,o as r,r as i,s as a,t as o,u as s}from"./config-DT-Cs7bC.mjs";import{i as c,n as l,r as u,t as d}from"./fs-B7O-fNID.mjs";import{r as f,t as p}from"./http-Dx1cFJ5S.mjs";import{a as m,c as h,i as g,l as _,n as v,o as y,r as b,s as x,t as ee}from"./lock-BwLjTQmQ.mjs";import{n as S,r as C,t as te}from"./peer-versions-DIPdOfWj.mjs";import{n as w,r as T,t as E}from"./args-CtmltI1S.mjs";import{createRequire as D}from"node:module";import{argv as O,stdin as k,stdout as A}from"node:process";import{pathToFileURL as ne}from"node:url";import{existsSync as j,readFileSync as M,readdirSync as N,writeFileSync as P}from"node:fs";import{basename as re,dirname as ie,join as F,resolve as I}from"node:path";import{spawnSync as ae}from"node:child_process";import{readFile as oe}from"node:fs/promises";import{asTemplateMeta as se,buildRegistry as ce,isTemplateItem as L,parseItem as R,parseLegacyRegistry as le,validateIndex as ue,validateItem as de,validateTemplate as fe}from"@cascivo/registry";import{createInterface as z}from"node:readline/promises";function B(t,n=process.cwd(),i={}){if(t.length===0)return!0;let o=i.pm??e(n),[s,c]=r(o,t,{dev:i.dev??!1,...i.floors?{floors:i.floors}:{},...i.pin?{pin:i.pin}:{}});return console.log(`Installing ${t.join(`, `)} with ${s}…`),ae(s,c,{cwd:n,stdio:`inherit`,shell:process.platform===`win32`}).status===0?!0:(console.error(`Failed to install: ${t.join(`, `)}`),console.error(`Install them yourself with: ${a(o,t,{dev:i.dev??!1})}`),!1)}const pe=/^([^/]+)\/([^/]+)\/([^#]+)(?:#(.+))?$/;function V(e,t=process.env){return e.replace(/\$\{([^}]+)\}/g,(e,n)=>{let r=t[n];if(r===void 0)throw Error(`Environment variable ${n} is not set`);return r})}function H(e,t=process.env){if(e.startsWith(`http://`)||e.startsWith(`https://`)||e.startsWith(`./`)||e.startsWith(`/`))return{kind:`url`,name:e,raw:e};if(e.startsWith(`@`)){let t=e.indexOf(`/`,1);if(t===-1)throw Error(`Invalid namespace address: ${e} (expected @ns/name)`);return{kind:`namespace`,namespace:e.slice(0,t),name:e.slice(t+1),raw:e}}let n=e.includes(`#`)?e.slice(0,e.indexOf(`#`)):e,r=pe.exec(e);if(r&&!n.includes(`.`)&&n.split(`/`).length>=3){let[,t,n,i,a]=r;return{kind:`github`,name:`${t}/${n}/${i}`,ref:a??`main`,raw:e}}return{kind:`bare`,name:e,raw:e}}function U(e,t,n,r){let i=typeof n==`string`?n:n.url;if(!i.includes(`{name}`))throw Error(`Registry namespace "${e}" URL template must contain {name}: ${i}`);return V(i.replace(`{name}`,t),r)}async function W(e,t,n=process.env,r){switch(e.kind){case`url`:return{url:e.name};case`bare`:return{url:`${t.registry.replace(/\/registry\.json$/,``).replace(/\/r$/,``)}/r/${e.name}.json`};case`github`:{let t=e.name.split(`/`),n=t[0],r=t[1],i=t.slice(2).join(`/`);return{url:`https://raw.githubusercontent.com/${n}/${r}/${e.ref??`main`}/r/${i}.json`}}case`namespace`:{let i=e.namespace,a=e.name;if(t.registries?.[i]){let e=t.registries[i],r=U(i,a,e,n),o=typeof e==`string`?void 0:e.headers,s=typeof e==`string`?void 0:e.params,c=o?Object.fromEntries(Object.entries(o).map(([e,t])=>[e,V(t,n)])):void 0,l=s?Object.fromEntries(Object.entries(s).map(([e,t])=>[e,V(t,n)])):void 0,u={url:r};return c&&(u.headers=c),l&&(u.params=l),u}if(r){let e=await r(i);if(e)return{url:U(i,a,e,n)}}if(i===`@cascivo`||i===`@cascade`)return{url:`${o}/r/${a}.json`};throw Error(`Unknown namespace "${i}". Add it to registries in cascivo.config.ts or check the directory at cascivo.com`)}}}async function me(e,t,n=process.env,r){let i=new Set,a=[...e],o=[];for(;a.length>0;){let e=a.shift(),s=H(e,n),c=s.raw;if(i.has(c))continue;i.add(c);let{url:l,headers:u,params:d}=await W(s,t,n,r),f={};u&&(f.headers=u),d&&(f.params=d);let m=R(await p(l,f),l),h={spec:e,addr:s,itemUrl:l,item:m,registryBase:l.replace(/\/[^/]+\.json$/,``)};u&&(h.headers=u),d&&(h.params=d),o.push(h);for(let e of m.registryDependencies??[])a.push(e)}return{items:o}}const he=`${o}/r/registries.json`;function ge(e,t){if(typeof e!=`object`||!e)return null;let n=e.registries;if(!Array.isArray(n))return null;for(let e of n){if(typeof e!=`object`||!e)continue;let n=e;if(n.namespace!==t)continue;let r=n.registryUrl;return typeof r!=`string`||!/^https?:\/\//.test(r)?null:r}return null}async function _e(e,t){try{let n;if(t){let e=await t(he,{headers:{Accept:`application/json`}});if(!e.ok)throw Error(`HTTP ${e.status}`);n=await e.json()}else n=await p(he);return ge(n,e)}catch(e){let t=e instanceof Error?e.message:String(e);return console.warn(`Could not reach cascivo.com directory: ${t}`),null}}var ve=s({LAYOUT_ALIASES:()=>G,NAME_NOTES:()=>Ce,add:()=>Oe,isThirdParty:()=>Ee,resolveBareClosure:()=>we,resolveTemplateTarget:()=>Se});const ye=new Set([`react`,`react-dom`]);function be(e){try{let t=JSON.parse(M(F(e,`package.json`),`utf8`));return{...t.dependencies,...t.devDependencies}}catch{return{}}}function xe(e,t){let n=be(e);n[`@cascivo/themes`]!==void 0||n[`@cascivo/tokens`]!==void 0||(console.log(`
|
|
3
|
+
Styling: cascivo components read --cascivo-* tokens, which this project does not import yet.`),console.log(` ${a(t,[`@cascivo/themes`])}`),console.log(` import '@cascivo/themes/all' // once, in your entry file`),console.log(` <html data-theme="light"> // or any container`))}function Se(e,t){return d(e,I(e,t))}const G={box:`layout/flex`,hstack:`layout/flex`,vstack:`layout/flex`,gap:`spacer`},Ce={stack:`Note: cascivo's Stack overlaps children into a card-pile (z-axis), not a vertical spacing layout. For vertical spacing use Flex direction="vertical" (cascivo add flex; aliases: vstack, hstack).`};function we(e,t){let n=t.map(e=>({name:e,requested:!0})),r=new Set,i=[],a=[];for(;n.length>0;){let{name:t,requested:o}=n.shift(),s=h(e,G[t.toLowerCase()]??t);if(!s){a.push(t);continue}if(r.has(s.name))continue;r.add(s.name);let c=_(s,t);i.push({entry:s,requested:o,...c?{viaAlias:c}:{}});for(let e of s.registryDependencies??[])n.push({name:e,requested:!1})}return{resolved:i,missing:a}}const Te=/^https:\/\/(cascivo\.com|raw\.githubusercontent\.com\/cascivo\/cascivo)\//;function Ee(e){return!Te.test(e)}function De(e){return e.startsWith(`@`)||e.startsWith(`http://`)||e.startsWith(`https://`)||e.startsWith(`./`)||e.startsWith(`/`)||e.split(`/`).length>=3}async function Oe(t,n,r={}){if(t.length===0){console.error(`Usage: cascivo add <component...>`);return}let i=r.cwd??process.cwd(),o=r.pm??e(i),s=t.filter(De),l=t.filter(e=>!De(e)),d=null;if(l.length>0){d=await y(n.registry);let e=new Set(d.templates.map(e=>e.toLowerCase())),t=l.filter(t=>e.has(t.toLowerCase()));t.length>0&&(l=l.filter(t=>!e.has(t.toLowerCase())),s.push(...t.map(e=>`@cascivo/${e.toLowerCase()}`)))}let p=await v(i)??ee();if(s.length>0){let e=await me(s,n,process.env,_e);if(r.dryRun){console.log(`Dry run — would install:`);for(let t of e.items){let e=L(t.item)?` [template]`:``;console.log(` ${t.spec} (${t.item.name}@${t.item.version})${e} from ${t.itemUrl}`);for(let e of t.item.files){let n=L(t.item)&&e.target?` → ${e.target}`:``;console.log(` ${e.url}${n}`)}t.item.registryDependencies?.length&&console.log(` components: ${t.item.registryDependencies.join(`, `)}`)}return}for(let{item:t,itemUrl:a,registryBase:s}of e.items){Ee(a)&&console.log(`\nReview before use — files from non-directory registry: ${s}\n`+(t.files??[]).map(e=>` ${e.url}`).join(`
|
|
4
|
+
`));let e;try{e=await ke(t,n,i,{pm:o,...r.noInstall?{noInstall:!0}:{}})}catch(e){console.error(`Failed to install ${t.name}: ${e instanceof Error?e.message:e}`),process.exitCode=1;continue}p=g(p,t.name,{registry:s,version:t.version,installedAt:new Date().toISOString().slice(0,10),files:e})}if(await m(p,i),l.length===0){xe(i,o);return}}if(l.length===0)return;d??=await y(n.registry);let _=new Set,S=n.registry.replace(/\/registry\.json$/,``).replace(/\/r$/,``);for(let e of l){let t=Ce[e.toLowerCase()];t&&console.log(t);let n=G[e.toLowerCase()];if(!n)continue;let r=h(d,n);r&&console.log(`"${e}" is not a cascivo component — installing ${r.name} (its ${e} primitive).`)}let{resolved:C,missing:w}=we(d,l);for(let e of w)console.error(`Component "${e}" not found in registry. Run "cascivo list".`);for(let{entry:e,requested:t,viaAlias:n}of C)!t||!n||console.log(`\n"${n}" is cascivo's "${e.name}" — installing that.`);let T=new Set;for(let{entry:e,requested:t}of C)!t||!e.install||T.has(e.install)||(T.add(e.install),console.log(`\n"${e.name}" ships in the ${e.install} npm package — no source is copied into your project. Updates come from your package manager, not \`cascivo update\`.`));for(let{entry:e,requested:t}of C){if(!t||!e.deprecated)continue;let{replacement:n,since:r,note:i}=e.deprecated;console.warn(`\n⚠ "${e.name}" is deprecated since ${r}. Use "${n}" instead:\n cascivo add ${n}\n`+(i?` ${i}\n`:``)+` Adding "${e.name}" anyway — it still works.\n`)}let E={};for(let{entry:e}of C)for(let[t,n]of Object.entries(e.peerVersions??{}))E[t]=n;let D=new Set,O=[];for(let{entry:e,requested:t}of C){if(e.install){let t=e.install;D.add(t),console.log(`"${e.name}" is distributed as the npm package ${t} — a runtime dependency, not copied source (updates come via your package manager).`),O.push(` import { ${e.meta.name} } from '${t}'`),e.styles&&O.push(` import '${e.styles}' // once, in your entry file`);continue}let r=e.name.includes(`/`)?e.name.split(`/`).pop():e.name,a={},o;try{o=await Promise.all(e.files.map(async e=>({url:e,content:await f(e)})))}catch(t){console.error(`Failed to install ${e.name}: ${t instanceof Error?t.message:t}`),process.exitCode=1;continue}for(let{url:e,content:t}of o){let o=u(n.outputDir,r,x(e),i);await c(o,t),a[o]=b(t)}for(let t of e.dependencies)ye.has(t)||_.add(t);p=g(p,e.name,{registry:S,version:e.version,installedAt:new Date().toISOString().slice(0,10),files:a});let s=t?``:` (dependency)`;console.log(`Added ${e.name} to ${n.outputDir}/${r}/${s}`)}if(D.size>0){let e=be(i),t=[...D].filter(t=>e[t]===void 0);r.dryRun?console.log(`Dry run — would install npm package(s): ${[...D].join(`, `)}`):t.length>0&&(r.noInstall?console.log(`\nSkipped install (--no-install). Install with:\n ${a(o,t)}`):B(t,i,{pm:o})||(process.exitCode=1)),O.length>0&&console.log(`\nImport it:\n${O.join(`
|
|
5
|
+
`)}`)}if(_.size>0&&!r.dryRun&&(r.noInstall?console.log(`\nSkipped install (--no-install). Install with:\n ${a(o,[..._])}`):B([..._],i,{pm:o})),Object.keys(E).length>0){let e=await te(i,E);for(let t of e)console.error(`\nWarning: ${t.pkg} ${t.installed?`${t.installed} is`:`is not`} installed, but the copied component source needs ${t.pkg} ${t.required}. Run: ${a(o,[`${t.pkg}@latest`])}`),process.exitCode=1}await m(p,i),xe(i,o)}async function ke(t,n,r,i={}){let o={},s=new Set,l=L(t),d=t.name.includes(`/`)?t.name.split(`/`).pop():t.name,p=await Promise.all((t.files??[]).map(async e=>({file:e,content:await f(e.url)})));for(let{file:e,content:t}of p){let i=l&&e.target?Se(r,e.target):u(n.outputDir,d,x(e.url),r);await c(i,t),o[i]=b(t)}for(let e of t.dependencies??[])ye.has(e)||s.add(e);if(s.size>0&&(i.noInstall?console.log(`\nSkipped install (--no-install). Install with:\n ${a(i.pm??e(r),[...s])}`):B([...s],r,i.pm?{pm:i.pm}:{})),l){let e=t.files?.filter(e=>e.target).map(e=>e.target)??[];console.log(`Installed template ${t.name} (${e.length} files)`)}else console.log(`Added ${t.name} to ${n.outputDir}/${d}/`);return o}const K={"@cascivo/react":`1.2.0`,"@cascivo/themes":`1.0.0`,"@cascivo/charts":`1.2.0`,"@cascivo/icons":`1.1.0`,"@cascivo/eslint-config":`0.4.0`};function Ae(e){return e===`yarn`?`yarn`:`${e} install`}function je(e,t){return e===`npm`?`npm run ${t}`:`${e} ${t}`}function Me(e){return e.trim().toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``)||`section`}function Ne(e){let t=e.trim().split(/[^a-zA-Z0-9]+/).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(``)||`Section`;return/^[0-9]/.test(t)?`Section${t}`:t}function Pe(e){let t=e.trim().split(/[^a-zA-Z0-9]+/).filter(e=>e!==``&&!/^\d+$/.test(e)&&!/^v\d+$/i.test(e)),n=[];for(let e of t){if(n.length>=3||n.length>0&&n.join(` `).length+1+e.length>24)break;n.push(e.charAt(0).toUpperCase()+e.slice(1))}return n.join(` `)||`App`}function Fe(e){return e.trim().toLowerCase().replace(/[^a-z0-9._-]+/g,`-`).replace(/^-+|-+$/g,``)||`cascivo-app`}function Ie(e){let t=new Set,n=new Set,r=[];for(let i of e){let e=i.trim();if(!e)continue;let a=Me(e),o=Ne(e),s=2;for(;t.has(a)||n.has(o);)a=`${Me(e)}-${s}`,o=`${Ne(e)}${s}`,s++;t.add(a),n.add(o),r.push({key:a,label:e,component:o})}return r.length>0?r:[{key:`home`,label:`Home`,component:`Home`}]}function Le(e){let t={name:Fe(e.name),private:!0,version:`0.0.0`,type:`module`,scripts:{dev:`vite`,build:`tsc && vite build`,preview:`vite preview`,typecheck:`tsc --noEmit`,lint:`eslint .`,format:`prettier --write .`,"format:check":`prettier --check .`},dependencies:{"@cascivo/react":K[`@cascivo/react`],"@cascivo/themes":K[`@cascivo/themes`],"@preact/signals-react":`>=3.0.0`,react:`^19.0.0`,"react-dom":`^19.0.0`},devDependencies:{"@cascivo/eslint-config":K[`@cascivo/eslint-config`],"@eslint/js":`^9.0.0`,"@types/react":`^19.0.0`,"@types/react-dom":`^19.0.0`,"@vitejs/plugin-react":`^5.0.0`,eslint:`^9.0.0`,"eslint-plugin-react-hooks":`^7.0.0`,prettier:`^3.0.0`,typescript:`^5.7.0`,"typescript-eslint":`^8.0.0`,vite:`^7.0.0`}};return JSON.stringify(t,null,2)+`
|
|
6
|
+
`}function Re(){return JSON.stringify({compilerOptions:{target:`ES2022`,useDefineForClassFields:!0,lib:[`ES2022`,`DOM`,`DOM.Iterable`],module:`ESNext`,skipLibCheck:!0,moduleResolution:`bundler`,allowImportingTsExtensions:!0,resolveJsonModule:!0,isolatedModules:!0,moduleDetection:`force`,noEmit:!0,jsx:`react-jsx`,strict:!0,noUnusedLocals:!0,noUnusedParameters:!0,noFallthroughCasesInSwitch:!0},include:[`src`]},null,2)+`
|
|
7
|
+
`}function ze(){return`import react from '@vitejs/plugin-react'
|
|
8
8
|
import { defineConfig } from 'vite'
|
|
9
9
|
|
|
10
10
|
export default defineConfig({
|
|
11
11
|
plugins: [react()],
|
|
12
12
|
})
|
|
13
|
-
`}function
|
|
13
|
+
`}function Be(e){return`<!doctype html>
|
|
14
14
|
<html lang="en" data-theme="${e.theme}">
|
|
15
15
|
<head>
|
|
16
16
|
<meta charset="UTF-8" />
|
|
17
17
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
18
|
-
<title>${
|
|
18
|
+
<title>${Pe(e.name)}</title>
|
|
19
19
|
<style>
|
|
20
20
|
@layer vendor, cascivo.reset, cascivo.base, cascivo.tokens, cascivo.component,
|
|
21
21
|
cascivo.platform, cascivo.theme, cascivo.blocks, cascivo.example, cascivo.override;
|
|
@@ -49,7 +49,7 @@ export default defineConfig({
|
|
|
49
49
|
<script type="module" src="/src/main.tsx"><\/script>
|
|
50
50
|
</body>
|
|
51
51
|
</html>
|
|
52
|
-
`}function
|
|
52
|
+
`}function Ve(){return`import React from 'react'
|
|
53
53
|
import ReactDOM from 'react-dom/client'
|
|
54
54
|
import App from './App'
|
|
55
55
|
|
|
@@ -61,8 +61,8 @@ if (root) {
|
|
|
61
61
|
</React.StrictMode>,
|
|
62
62
|
)
|
|
63
63
|
}
|
|
64
|
-
`}function
|
|
65
|
-
`}function
|
|
64
|
+
`}function He(){return`/// <reference types="vite/client" />
|
|
65
|
+
`}function Ue(e){let t=e.map(e=>`import { ${e.component} } from './sections/${e.component}'`).join(`
|
|
66
66
|
`),n=e.map(e=>`'${e.key}'`).join(` | `),r=e.map(e=>` {
|
|
67
67
|
label: '${e.label.replace(/'/g,`\\'`)}',
|
|
68
68
|
active: section.value === '${e.key}',
|
|
@@ -94,7 +94,7 @@ ${i}
|
|
|
94
94
|
</Shell>
|
|
95
95
|
)
|
|
96
96
|
}
|
|
97
|
-
`}function
|
|
97
|
+
`}function We(e){return`'use client'
|
|
98
98
|
import { AppShell, ShellHeader, SideNav, type SideNavItem } from '@cascivo/react'
|
|
99
99
|
import type { ReactNode } from 'react'
|
|
100
100
|
|
|
@@ -125,14 +125,14 @@ export interface ShellProps {
|
|
|
125
125
|
export function Shell({ navItems, children }: ShellProps) {
|
|
126
126
|
return (
|
|
127
127
|
<AppShell
|
|
128
|
-
header={<ShellHeader brand={{ name: '${
|
|
128
|
+
header={<ShellHeader brand={{ name: '${Pe(e.name).replace(/'/g,`\\'`)}' }} />}
|
|
129
129
|
nav={<SideNav items={navItems} />}
|
|
130
130
|
>
|
|
131
131
|
{children}
|
|
132
132
|
</AppShell>
|
|
133
133
|
)
|
|
134
134
|
}
|
|
135
|
-
`}function
|
|
135
|
+
`}function Ge(e){return`import { Card, CardContent, CardHeader, CardTitle, Flex, Heading, Text } from '@cascivo/react'
|
|
136
136
|
|
|
137
137
|
export function ${e.component}() {
|
|
138
138
|
return (
|
|
@@ -158,7 +158,7 @@ export function ${e.component}() {
|
|
|
158
158
|
</Flex>
|
|
159
159
|
)
|
|
160
160
|
}
|
|
161
|
-
`}function
|
|
161
|
+
`}function Ke(){return`import js from '@eslint/js'
|
|
162
162
|
import tseslint from 'typescript-eslint'
|
|
163
163
|
import reactHooks from 'eslint-plugin-react-hooks'
|
|
164
164
|
import cascivo from '@cascivo/eslint-config'
|
|
@@ -180,17 +180,17 @@ export default [
|
|
|
180
180
|
// see https://cascivo.com/docs/using-with-strict-eslint.md
|
|
181
181
|
...cascivo,
|
|
182
182
|
]
|
|
183
|
-
`}function
|
|
184
|
-
`}function
|
|
183
|
+
`}function qe(){return JSON.stringify({semi:!1,singleQuote:!0,printWidth:100},null,2)+`
|
|
184
|
+
`}function Je(){return`dist
|
|
185
185
|
node_modules
|
|
186
186
|
# Vendored cascivo source is formatted upstream — reformatting it makes every
|
|
187
187
|
# \`cascivo add\` update a merge conflict.
|
|
188
188
|
src/components/ui/
|
|
189
|
-
`}function
|
|
189
|
+
`}function Ye(){return`node_modules
|
|
190
190
|
dist
|
|
191
191
|
*.local
|
|
192
192
|
.DS_Store
|
|
193
|
-
`}function
|
|
193
|
+
`}function Xe(e){let t=e.pm??`npm`;return`# ${e.name}
|
|
194
194
|
|
|
195
195
|
A [cascivo](https://cascivo.com) app — Vite + React + TypeScript, pre-wired with
|
|
196
196
|
the cascivo app shell, side navigation, and the \`${e.theme}\` theme.
|
|
@@ -198,8 +198,8 @@ the cascivo app shell, side navigation, and the \`${e.theme}\` theme.
|
|
|
198
198
|
## Develop
|
|
199
199
|
|
|
200
200
|
\`\`\`sh
|
|
201
|
-
${
|
|
202
|
-
${
|
|
201
|
+
${Ae(t)}
|
|
202
|
+
${je(t,`dev`)}
|
|
203
203
|
\`\`\`
|
|
204
204
|
|
|
205
205
|
## Structure
|
|
@@ -232,7 +232,7 @@ setLinkComponent(({ href, ...rest }: LinkComponentProps) => <Link to={href ?? '#
|
|
|
232
232
|
That one call makes \`SideNav\`, \`ShellHeader\` and \`Breadcrumb\` render real router links.
|
|
233
233
|
Links you write in page content use \`<Link asChild>\` instead — two kinds of link, two
|
|
234
234
|
mechanisms. Full recipe: https://cascivo.com/docs/using-with-a-router.md
|
|
235
|
-
`}function
|
|
235
|
+
`}function Ze(e){return`# Agent instructions — ${e.name}
|
|
236
236
|
|
|
237
237
|
This is a [cascivo](https://cascivo.com) app. When generating or editing CSS, follow
|
|
238
238
|
the **layer contract** — cascivo styles live in cascade layers, and layer order beats
|
|
@@ -299,13 +299,13 @@ The vocabulary types are on a subpath: \`import type { Tone } from '@cascivo/rea
|
|
|
299
299
|
add \`@cascivo/core\` to this app's dependencies — it is transitive here.
|
|
300
300
|
|
|
301
301
|
More: cascivo's machine-readable guide is at https://cascivo.com/llms.txt.
|
|
302
|
-
`}function
|
|
303
|
-
Next steps:`),console.log(` cd ${e}`),console.log(` ${
|
|
302
|
+
`}function Qe(e){let t=Ie(e.sections);return[{path:`package.json`,contents:Le(e)},{path:`tsconfig.json`,contents:Re()},{path:`vite.config.ts`,contents:ze()},{path:`index.html`,contents:Be(e)},{path:`eslint.config.js`,contents:Ke()},{path:`.prettierrc`,contents:qe()},{path:`.prettierignore`,contents:Je()},{path:`.gitignore`,contents:Ye()},{path:`README.md`,contents:Xe(e)},{path:`AGENTS.md`,contents:Ze(e)},{path:`src/main.tsx`,contents:Ve()},{path:`src/vite-env.d.ts`,contents:He()},{path:`src/App.tsx`,contents:Ue(t)},{path:`src/Shell.tsx`,contents:We(e)},...t.map(e=>({path:`src/sections/${e.component}.tsx`,contents:Ge(e)}))]}const $e=[`Dashboard`,`Reports`,`Settings`];async function et(t,n=process.cwd()){let r=t.includes(`--yes`)||t.includes(`-y`),a=w(t,[`pm`,`package-manager`,`theme`,`sections`,`template`])[0],o=E(t,`theme`),s=E(t,`sections`),l=T(t);if(`error`in l){console.error(l.error),process.exitCode=1;return}let u=e(n,{preferLockfileOverUserAgent:!0,...l.pm?{override:l.pm}:{}}),d=!r&&k.isTTY?z({input:k,output:A}):null;try{let e=a;!e&&d&&(e=(await d.question(`Project name? [my-cascivo-app]: `)).trim()),e||=`my-cascivo-app`;let r=(o??``).toLowerCase();!i.includes(r)&&d&&(r=(await d.question(`Theme? (${i.join(`/`)}) [light]: `)).trim().toLowerCase());let l=i.includes(r)?r:`light`,f=s;!f&&d&&(f=(await d.question(`Nav sections? (comma-separated) [${$e.join(`, `)}]: `)).trim());let p=(f??``).split(`,`).map(e=>e.trim()).filter(Boolean),m={name:e,theme:l,sections:p.length>0?p:$e,pm:u},h=F(n,e);if(j(h)&&N(h).length>0){console.error(`Target directory "${e}" already exists and is not empty.`),process.exitCode=1;return}let g=Qe(m);for(let e of g)await c(F(h,e.path),e.contents);console.log(`\nCreated ${e} with the ${l} theme (${g.length} files).`);let _=E(t,`template`);if(_){let{add:e}=await Promise.resolve().then(()=>ve),{loadConfig:t}=await import(`./config-DT-Cs7bC.mjs`).then(e=>e.i);console.log(`\nInstalling template "${_}"…`),await e([_],await t(),{cwd:h,pm:u})}console.log(`
|
|
303
|
+
Next steps:`),console.log(` cd ${e}`),console.log(` ${Ae(u)}`),console.log(` ${je(u,`dev`)}`),console.log(`
|
|
304
304
|
Good to know:`),console.log(` No cascivo.config.ts is written — this app uses the prebuilt @cascivo/react`),console.log(" packages and never copies source. `cascivo add <component>` writes the"),console.log(` config itself the first time you vendor a component.`),console.log(`
|
|
305
|
-
Adding a router? Keep src/Shell.tsx, delete src/App.tsx + src/sections/,`),console.log(` and register your Link once with setLinkComponent — see`),console.log(` https://cascivo.com/docs/using-with-a-router.md`)}finally{d?.close()}}var
|
|
306
|
-
`).some(e=>e.trim().replace(/\/+$/,``)===r))return`"${r}/" is not excluded from your formatter. Running it will rewrite code you own, and \`cascivo update\` will then report drift on files you never edited. Add "${r}/" to ${i}.`}return null}function
|
|
307
|
-
`;)n++;else if(i===`/`&&a===`*`){for(n+=2;n<r&&!(e[n]===`*`&&e[n+1]===`/`);)n++;n+=2}else if(i===`'`||i===`"`){for(n++;n<r&&e[n]!==i;)e[n]===`\\`&&n++,n++;n++,t+=i+i}else if(i==="`"){for(n++;n<r&&e[n]!=="`";)e[n]===`\\`&&n++,n++;n++,t+="``"}else t+=i,n++}return t}async function
|
|
308
|
-
`):``}function
|
|
305
|
+
Adding a router? Keep src/Shell.tsx, delete src/App.tsx + src/sections/,`),console.log(` and register your Link once with setLinkComponent — see`),console.log(` https://cascivo.com/docs/using-with-a-router.md`)}finally{d?.close()}}var tt=s({checkDuplicateCore:()=>ft,checkFormatterIgnore:()=>gt,checkProjectDependencies:()=>ut,checkSignalsCompat:()=>pt,checkSsrConfig:()=>_t,detectInstallPath:()=>st,runDoctor:()=>bt,stripCommentsAndStrings:()=>yt});const nt=[`@cascivo/core`,`@cascivo/tokens`,`@cascivo/themes`,`@preact/signals-react`],rt=[`@cascivo/react`,`@cascivo/themes`,`@preact/signals-react`],it={"@cascivo/core":`AI-RULES.md: never add @cascivo/core to a prebuilt-path app — it is transitive, and everything is re-exported from @cascivo/react`,"@cascivo/tokens":`GETTING-STARTED.md: @cascivo/tokens comes with @cascivo/themes as a direct dependency — never install it by hand`},at=[`@cascivo/i18n`,`@cascivo/charts`],ot=[`cascivo.config.ts`,`cascivo.config.js`,`cascivo.config.mjs`];function st(e){let t={},n=!0;try{let n=JSON.parse(M(F(e,`package.json`),`utf8`));t={...n.dependencies,...n.devDependencies}}catch{n=!1}if(!n)return`unknown`;let r=t[`@cascivo/react`]!==void 0,i=ct(e);return r&&i?`hybrid`:r?`prebuilt`:i?`copied`:`unknown`}function ct(e){for(let t of lt(e)){let n=F(e,t);if(j(n))try{if(N(n).some(e=>e.endsWith(`.tsx`)))return!0}catch{}}return!1}function lt(e){let t=new Set([`src/components/ui`]);for(let n of ot){let r=F(e,n);if(j(r))try{let e=/outputDir\s*:\s*['"]([^'"]+)['"]/.exec(M(r,`utf8`))?.[1];e!==void 0&&t.add(e)}catch{}}return[...t]}function ut(t){let n={};try{let e=JSON.parse(M(F(t,`package.json`),`utf8`));n={...e.dependencies,...e.devDependencies}}catch{return[]}let r=st(t);if(r===`unknown`)return[];let i=e(t),o=[],s=r===`prebuilt`?rt:nt;for(let e of s)n[e]===void 0&&o.push({package:e,required:!0,hint:`detected ${r} install path — ${a(i,[e])}`});if(r===`prebuilt`)for(let[e,t]of Object.entries(it))n[e]!==void 0&&o.push({package:e,required:!0,kind:`forbidden`,hint:t});for(let e of at)n[e]===void 0&&o.push({package:e,required:!1,hint:a(i,[e])});return o}const dt=[`@cascivo/react`,`@cascivo/charts`,`@cascivo/flow`,`@cascivo/editor`];async function ft(e){let t=await S(e,`@cascivo/core`),n=[];for(let r of dt){let i=F(e,`node_modules`,r);if(!j(i))continue;let a=await S(i,`@cascivo/core`);a!==null&&a!==t&&n.push(`${r} → ${a}`)}return n.length===0?null:{root:t,nested:n,hint:`Align the @cascivo/* versions (they are released together — see breaking-changes.json) and reinstall. Two copies of @cascivo/core means two signal registries: writes through one are invisible to components subscribed through the other, with no error.`}}async function pt(t){let[n,r]=await Promise.all([S(t,`@preact/signals-react`),S(t,`react`)]);if(n===null)return null;let i;try{i=C(n,`3.0.0`)<0}catch{return null}if(!i)return null;let o=a(e(t),[`@preact/signals-react@^3`]),s=null;if(r!==null){let e=/^(\d+)\./.exec(r.trim());s=e?Number(e[1]):null}return s!==null&&s>=19?{severity:`error`,detail:`@preact/signals-react ${n} cannot run on React ${r} — React 19 removed an internal signals 2.x imports, so it fails at module load. Upgrade to signals-react 3.x.`,hint:o}:{severity:`warning`,detail:`@preact/signals-react ${n} is below the required 3.x floor. It works on React 18 today but breaks the moment you move to React 19; upgrade now.`,hint:o}}const mt=[`@tanstack/react-start`,`vite-ssr`,`@remix-run/dev`],ht=[`vite.config.ts`,`vite.config.js`,`vite.config.mjs`,`vite.config.mts`];function gt(e,t){let n=[{configs:[`.prettierrc`,`.prettierrc.json`,`.prettierrc.js`,`prettier.config.js`],ignore:`.prettierignore`},{configs:[`.oxfmtrc`,`.oxfmtrc.json`],ignore:`.oxfmtignore`}],r=t.replace(/\/+$/,``);for(let{configs:t,ignore:i}of n){if(!t.some(t=>j(F(e,t))))continue;let n=``;try{n=M(F(e,i),`utf8`)}catch{}if(!n.split(`
|
|
306
|
+
`).some(e=>e.trim().replace(/\/+$/,``)===r))return`"${r}/" is not excluded from your formatter. Running it will rewrite code you own, and \`cascivo update\` will then report drift on files you never edited. Add "${r}/" to ${i}.`}return null}function _t(e){let t={};try{let n=JSON.parse(M(F(e,`package.json`),`utf8`));t={...n.dependencies,...n.devDependencies}}catch{return null}let n=mt.find(e=>t[e]!==void 0);if(n===void 0)return null;for(let t of ht){let n=F(e,t);if(!j(n))continue;let r=M(n,`utf8`);if(/noExternal/.test(r)&&/@cascivo/.test(r)||/cascivoSsr/.test(r))return null}return`${n} is a Vite SSR framework, but no vite config marks the cascivo packages ssr.noExternal — an unconfigured SSR build crashes with \`Unknown file extension ".css"\`. Add \`ssr: { noExternal: [/^@cascivo\\//] }\` (or the cascivoSsr() plugin from @cascivo/vite-plugin). Recipe: https://cascivo.com/docs/using-with-vite-ssr.md`}const vt=[`useState`,`useEffect`,`useLayoutEffect`,`useContext`,`useReducer`];function yt(e){let t=``,n=0,r=e.length;for(;n<r;){let i=e[n],a=e[n+1];if(i===`/`&&a===`/`)for(;n<r&&e[n]!==`
|
|
307
|
+
`;)n++;else if(i===`/`&&a===`*`){for(n+=2;n<r&&!(e[n]===`*`&&e[n+1]===`/`);)n++;n+=2}else if(i===`'`||i===`"`){for(n++;n<r&&e[n]!==i;)e[n]===`\\`&&n++,n++;n++,t+=i+i}else if(i==="`"){for(n++;n<r&&e[n]!=="`";)e[n]===`\\`&&n++,n++;n++,t+="``"}else t+=i,n++}return t}async function bt(e){let t=[],n=F(e,`packages`,`components`,`src`);if(!j(n))return{violations:[],passed:!0};let r=N(n,{withFileTypes:!0}).filter(e=>e.isDirectory()).map(e=>e.name),i=F(e,`packages`,`react`,`src`,`index.ts`),a=j(i)?M(i,`utf8`):``;for(let e of r){let r=F(n,e,`${e}.tsx`);if(!j(r))continue;let i=M(r,`utf8`),o=yt(i);for(let n of vt)RegExp(`\\b${n}\\b`).test(o)&&t.push({file:r,rule:`no-react-hooks`,detail:`Banned hook '${n}' in ${e}.tsx`});/aria-label="[A-Z]/.test(i)&&t.push({file:r,rule:`no-hardcoded-strings`,detail:`Hardcoded aria-label in ${e}.tsx — use t(builtin.*)`}),RegExp(`from.*components/src/${e}`).test(a)||t.push({file:r,rule:`missing-react-export`,detail:`${e} not exported from @cascivo/react`})}return{violations:t,passed:t.length===0}}function xt(e){return typeof e==`object`&&!!e&&`$t`in e}function St(e){return typeof e==`string`?`'${e.replace(/'/g,`\\'`)}'`:String(e)}function Ct(e){return typeof e==`string`?`"${e.replace(/"/g,`\\"`)}"`:typeof e==`number`||typeof e==`boolean`?`{${e}}`:e===null?`{null}`:xt(e)?`{"${e.$t}"} {/* i18n: ${e.$t} */}`:`{${JSON.stringify(e)}}`}function wt(e,t,n,r){return e===void 0?``:typeof e==`string`?e:xt(e)?`{/* i18n: ${e.$t} */}`:Array.isArray(e)?e.map(e=>Tt(e,t+` `,n,r)).join(`
|
|
308
|
+
`):``}function Tt(e,t,n,r){let i=e.component;r.add(i);let a=[];if(e.props)for(let[t,n]of Object.entries(e.props))a.push(`${t}=${Ct(n)}`);if(e.bind)for(let[t,n]of Object.entries(e.bind))n.startsWith(`$state.`)?a.push(`${t}={${n.slice(7)}.value}`):a.push(`${t}={data.${n.replace(/^\$data\./,``)}}`);if(e.events)for(let[t,n]of Object.entries(e.events))if(n.startsWith(`$state.set.`)){let e=n.slice(11);a.push(`${t}={(e) => (${e}.value = coerceValue(e))}`)}else if(n.startsWith(`$state.toggle.`)){let e=n.slice(14);a.push(`${t}={() => (${e}.value = !${e}.value)}`)}else a.push(`${t}={actions.${n.replace(/^\$actions\./,``)}}`);let o=a.length>0?` `+a.join(` `):``,s=e.children===void 0?void 0:wt(e.children,t,[],r);return s!==void 0&&s!==``?`${t}<${i}${o}>\n${t} ${s}\n${t}</${i}>`:`${t}<${i}${o} />`}function Et(e){let t=[],n=[];function r(e){if(e.bind)for(let n of Object.values(e.bind)){if(n.startsWith(`$state.`))continue;let e=n.replace(/^\$data\./,``);t.includes(e)||t.push(e)}if(e.events)for(let t of Object.values(e.events)){if(t.startsWith(`$state.`))continue;let e=t.replace(/^\$actions\./,``);n.includes(e)||n.push(e)}Array.isArray(e.children)&&e.children.forEach(r)}return e.forEach(r),{boundProps:t,actionProps:n}}function Dt(e){let t=e=>e.events&&Object.values(e.events).some(e=>e.startsWith(`$state.set.`))?!0:Array.isArray(e.children)?e.children.some(t):!1;return e.some(t)}function Ot(e,t,n){let r=new Set,i=Object.values(e.view.regions).flat(),{boundProps:a,actionProps:o}=Et(i),s=Object.entries(e.state??{}),c=s.length>0,l=Dt(i),u=Object.entries(e.view.regions).map(([e,t])=>` <div className="region-${e}">\n${t.map(e=>Tt(e,` `,[],r)).join(`
|
|
309
309
|
`)}\n </div>`).join(`
|
|
310
310
|
`),d=[...r].sort().map(e=>`import { ${e} } from '${n}/${e.toLowerCase()}/${e.toLowerCase()}'`).join(`
|
|
311
311
|
`),f=a.length>0,p=o.length>0,m=[f?`data: {\n${a.map(e=>` ${e.replace(/\./g,`_`)}: unknown // TODO: type your data`).join(`
|
|
@@ -320,7 +320,7 @@ function coerceValue(e: unknown) {
|
|
|
320
320
|
return e
|
|
321
321
|
}
|
|
322
322
|
`:``,v=c?` useSignals()
|
|
323
|
-
`+s.map(([e,t])=>` const ${e} = useSignal(${
|
|
323
|
+
`+s.map(([e,t])=>` const ${e} = useSignal(${St(t)})`).join(`
|
|
324
324
|
`)+`
|
|
325
325
|
`:``;return`import React from 'react'${g}
|
|
326
326
|
${d}
|
|
@@ -334,34 +334,34 @@ ${u}
|
|
|
334
334
|
</div>
|
|
335
335
|
)
|
|
336
336
|
}
|
|
337
|
-
`}async function
|
|
337
|
+
`}async function kt(e,t){let n=e.find((t,n)=>e[n-1]===`--out`),r=e.find(e=>!e.startsWith(`--`)),i=e.find((t,n)=>e[n-1]===`--components-dir`);if(!r){console.error(`Usage: cascivo generate <config.json> [--out output.tsx] [--components-dir ./src/components/ui]`),process.exitCode=1;return}let{readFileSync:a}=await import(`node:fs`),o=a(r,`utf-8`),s=Ot(JSON.parse(o),new Map,i??t.outputDir??`./src/components/ui`),c=n??F(ie(r),`${re(r,`.json`)}.tsx`);P(c,s,`utf-8`),console.log(`Generated ${c}`);try{let{spawnSync:e}=await import(`node:child_process`);e(`pnpm`,[`exec`,`vp`,`fmt`,c],{encoding:`utf8`,stdio:`inherit`}).status!==0&&e(`npx`,[`--yes`,`prettier`,`--write`,c],{encoding:`utf8`,stdio:`inherit`}).status!==0&&console.log(`(Note: formatter not found — output may need manual formatting)`)}catch{}}const q=[`@cascivo/core`,`@cascivo/tokens`,`@cascivo/themes`,`@preact/signals-react`],J=[`cascivo`];async function At(){let e=z({input:k,output:A});try{let t=(await e.question(`Theme? (${i.join(`/`)}) [light]: `)).trim().toLowerCase();return i.includes(t)?t:`light`}finally{e.close()}}function jt(e){return`import type { CascadeConfig } from 'cascivo'
|
|
338
338
|
|
|
339
339
|
const config: CascadeConfig = {
|
|
340
|
-
registry: '${
|
|
341
|
-
outputDir: '${
|
|
340
|
+
registry: '${n.registry}',
|
|
341
|
+
outputDir: '${n.outputDir}',
|
|
342
342
|
theme: '${e}',
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
export default config
|
|
346
|
-
`}const
|
|
347
|
-
ESLint: copied cascivo source may trip a strict host config on stylistic rules.`),console.log(` Scope them off your components dir — see docs/USING-WITH-STRICT-ESLINT.md`))}function
|
|
346
|
+
`}const Mt=[`eslint.config.js`,`eslint.config.mjs`,`eslint.config.cjs`,`eslint.config.ts`,`.eslintrc`,`.eslintrc.js`,`.eslintrc.cjs`,`.eslintrc.json`,`.eslintrc.yml`,`.eslintrc.yaml`];function Nt(e){Mt.some(t=>j(F(e,t)))&&(console.log(`
|
|
347
|
+
ESLint: copied cascivo source may trip a strict host config on stylistic rules.`),console.log(` Scope them off your components dir — see docs/USING-WITH-STRICT-ESLINT.md`))}function Pt(e,t,n){let r=F(e,`package.json`);if(!j(r))return[];let i;try{i=JSON.parse(M(r,`utf8`))}catch{return[]}let a=n.dev?`devDependencies`:`dependencies`,o=i[a]??={},s=[];for(let e of t)o[e]===void 0&&(o[e]=`latest`,s.push(e));return s.length===0?[]:(P(r,`${JSON.stringify(i,null,2)}\n`,`utf8`),s)}const Ft=[{config:[`.prettierrc`,`.prettierrc.json`,`.prettierrc.js`,`prettier.config.js`],ignore:`.prettierignore`},{config:[`.oxfmtrc`,`.oxfmtrc.json`],ignore:`.oxfmtignore`}];function It(e,t){let n=`${t.replace(/\/+$/,``)}/`;for(let{config:t,ignore:r}of Ft){if(!(t.some(t=>j(F(e,t)))||Lt(e,r)))continue;let i=F(e,r),a=j(i)?M(i,`utf8`):``;if(a.split(`
|
|
348
348
|
`).some(e=>e.trim()===n))continue;let o=`# cascivo: vendored component source — you own it, so do not reformat it
|
|
349
|
-
`;
|
|
349
|
+
`;P(i,a===``?o+n+`
|
|
350
350
|
`:`${a.replace(/\n*$/,`
|
|
351
|
-
`)}\n${o}${n}\n`,`utf8`),console.log(`\nAdded "${n}" to ${r} (so your formatter does not rewrite copied source).`)}}function
|
|
352
|
-
Dependencies`),console.log(` runtime: ${q.join(` `)}`),console.log(` dev: ${J.join(` `)} (types for cascivo.config.ts)`),console.log(" on demand: @cascivo/i18n, @cascivo/charts — added by `cascivo add` when a component or chart needs them")}async function
|
|
353
|
-
Skipped install (--no-install). Install the dependencies yourself:`),console.log(` ${
|
|
354
|
-
Install failed — cascivo.config.ts was written but the packages are not installed.`),
|
|
351
|
+
`)}\n${o}${n}\n`,`utf8`),console.log(`\nAdded "${n}" to ${r} (so your formatter does not rewrite copied source).`)}}function Lt(e,t){if(t!==`.prettierignore`)return!1;let n=F(e,`package.json`);if(!j(n))return!1;try{return`prettier`in JSON.parse(M(n,`utf8`))}catch{return!1}}function Rt(){console.log(`
|
|
352
|
+
Dependencies`),console.log(` runtime: ${q.join(` `)}`),console.log(` dev: ${J.join(` `)} (types for cascivo.config.ts)`),console.log(" on demand: @cascivo/i18n, @cascivo/charts — added by `cascivo add` when a component or chart needs them")}async function zt(t=[],r=process.cwd()){let o=t.includes(`--yes`)||t.includes(`-y`),s=t.includes(`--no-install`),l=E(t,`theme`)?.toLowerCase();if(l!==void 0&&!i.includes(l)){console.error(`Unknown theme "${l}". Available: ${i.join(`, `)}`),process.exitCode=1;return}let u=T(t);if(`error`in u){console.error(u.error),process.exitCode=1;return}let d=e(r,u.pm?{override:u.pm}:{}),f=l===void 0&&!o&&k.isTTY,p=l??(f?await At():`light`);if(await c(F(r,`cascivo.config.ts`),jt(p)),console.log(`\nCreated cascivo.config.ts (theme: ${p})`),s)console.log(`
|
|
353
|
+
Skipped install (--no-install). Install the dependencies yourself:`),console.log(` ${a(d,q)}`),console.log(` ${a(d,J,{dev:!0})}`);else{let e=B(q,r,{pm:d}),t=B(J,r,{pm:d,dev:!0});if(!e||!t){let n=[...e?[]:Pt(r,q,{dev:!1}),...t?[]:Pt(r,J,{dev:!0})];console.error(`
|
|
354
|
+
Install failed — cascivo.config.ts was written but the packages are not installed.`),n.length>0?(console.error(`Wrote ${n.length} dependency entries to package.json: ${n.join(`, `)}`),console.error(`Recover with:\n ${d} install`)):console.error(`Recover with:\n ${a(d,q)}\n ${a(d,J,{dev:!0})}`),process.exitCode=1}}console.log(`
|
|
355
355
|
Stylesheets — import these once, in this order, in your entry file:`),console.log(` import '@cascivo/tokens' // primitive tokens — every --cascivo-* value`),console.log(` import '@cascivo/themes/${p}.css'${` `.repeat(Math.max(1,16-p.length))}// the ${p} theme's semantic values`),console.log(" // …then your component CSS (`cascivo add` writes .module.css beside each component)"),console.log(`
|
|
356
356
|
Then set the theme on your root element:`),console.log(` <html data-theme="${p}">`),console.log(`
|
|
357
357
|
Switching themes at runtime? Use a bundle instead of the single theme:`),console.log(` import '@cascivo/themes/light-dark.css' // light + dark — the common case`),console.log(` import '@cascivo/themes/all.css' // all twelve themes`),console.log(` import { ThemeProvider } from '@cascivo/core'`),console.log(`
|
|
358
358
|
In YOUR components, when you read a signal during render:`),console.log(` import { useSignals } from '@cascivo/core'`),console.log(` function MyComponent() {`),console.log(` useSignals() // ← first statement, or the component never re-renders`),console.log(` return <span>{count.value}</span>`),console.log(` }`),console.log(`
|
|
359
|
-
Adding a chart later? Charts ship as an npm package with their own stylesheet:`),console.log(" import '@cascivo/charts/styles.css' // `cascivo add <chart>` reminds you"),
|
|
359
|
+
Adding a chart later? Charts ship as an npm package with their own stylesheet:`),console.log(" import '@cascivo/charts/styles.css' // `cascivo add <chart>` reminds you"),Rt(),It(r,n.outputDir),Nt(r),console.log(`
|
|
360
360
|
Packages version independently (changesets), so a low number means fewer`),console.log(`releases, not less finished. Pin exact versions, and before upgrading run:`),console.log(` cascivo doctor --drift # reads breaking-changes.json, reports API drift`),console.log(`
|
|
361
|
-
Add components with: cascivo add <name>`)}const
|
|
362
|
-
`)}function
|
|
361
|
+
Add components with: cascivo add <name>`)}const Bt={component:`Components`,layout:`Layouts (copy-paste)`,block:`Blocks (copy-paste)`,section:`Sections (copy-paste)`,chart:`Charts (npm: @cascivo/charts)`,flow:`Flow (npm: @cascivo/flow)`,editor:`Editor (npm: @cascivo/editor)`};function Vt(e){return e.deprecated?` ⚠ deprecated → ${e.deprecated.replacement}`:``}function Ht(e){let t=e.map(e=>[e.name,e.category,e.description+Vt(e)]),n=[`Name`,`Category`,`Description`],r=n.map((e,n)=>Math.max(e.length,...t.map(e=>(e[n]??``).length))),i=e=>e.map((e,t)=>e.padEnd(r[t]??e.length)).join(` `).trimEnd(),a=r.map(e=>`-`.repeat(e)).join(` `);return[i(n),a,...t.map(i)].join(`
|
|
362
|
+
`)}function Ut(e){if(e.length===0)return`No components found.`;if(!e.some(e=>e.type!==void 0))return Ht(e);let t=new Map;for(let n of e){let e=n.type??`component`;t.has(e)||t.set(e,[]),t.get(e).push(n)}let n=[];for(let[e,r]of t){let t=Bt[e]??e;n.push(`${t}\n${Ht(r)}`)}return n.join(`
|
|
363
363
|
|
|
364
|
-
`)}async function
|
|
364
|
+
`)}async function Wt(e,t={}){let n=(await y(e.registry)).components;t.installed&&(n=n.filter(t=>{let n=t.name.includes(`/`)?t.name.split(`/`).pop():t.name;return j(F(process.cwd(),e.outputDir,n))})),console.log(Ut(n)),console.log("\nTip: install any entry by its bare name — `cascivo add flex` resolves to `layout/flex`. Layout primitives (Flex, Grid, AutoGrid, Columns, Spacer, Center) replace inline-style layout; see docs/cookbooks/layout-and-spacing.md.")}function Gt(e){let t=[],n=[],r=new Set(e.items.map(e=>e.name));for(let i of e.items)if(L(i)){for(let e of fe(i))t.push(`template "${i.name}": ${e}`);for(let e of i.registryDependencies??[])!(e.includes(`/`)||e.startsWith(`@`)||e.startsWith(`http`))&&!r.has(e)&&n.push(`template "${i.name}": component "${e}" is not in this index — it must resolve from another registry at install time`)}return{errors:t,warnings:n}}async function Kt(e){let t=`cascade-registry.json`,n=`public/r`;for(let r=0;r<e.length;r++)e[r]===`--in`&&e[r+1]?(t=e[r+1],r++):e[r]===`--out`&&e[r+1]&&(n=e[r+1],r++);let r=I(t);if(!j(r)){console.error(`cascade registry build: file not found: ${r}`),process.exitCode=1;return}let i=JSON.parse(await oe(r,`utf8`));ie(r);let a=typeof i==`object`&&i&&i.schemaVersion===2?i:le(i),o=ue(a);if(o.warnings.length>0)for(let e of o.warnings)console.warn(`warn: ${e}`);if(!o.ok){for(let e of o.errors)console.error(`error: ${e}`);process.exitCode=1;return}let s=Gt(a);for(let e of s.warnings)console.warn(`warn: ${e}`);if(s.errors.length>0){for(let e of s.errors)console.error(`error: ${e}`);process.exitCode=1;return}let c=I(n);await ce(a,c),console.log(`cascade registry build: wrote static output to ${c}`)}function qt(e,t){let n=t.toLowerCase();return e.name.toLowerCase().includes(n)||e.description.toLowerCase().includes(n)||e.tags.some(e=>e.toLowerCase().includes(n))}async function Jt(e,t){let n=e.indexOf(`--registry`),r=n===-1?void 0:e[n+1],i=e.filter((t,n)=>t!==`--registry`&&e[n-1]!==`--registry`).join(` `).trim();if(!i){console.error(`Usage: cascivo search <query> [--registry @ns]`);return}let a=[];if(!r){let e=await y(t.registry);for(let t of e.components)qt(t,i)&&a.push({name:t.name,version:t.version,description:t.description})}let o=t.registries??{};for(let[e,t]of Object.entries(o))if(!(r&&e!==r))try{let n=await p((typeof t==`string`?t:t.url).replace(/{name}[^$]*$/,``).replace(/\/$/,``)+`/registry.json`),r=typeof n==`object`&&n&&Array.isArray(n.items)?n.items??[]:[];for(let t of r){if(!de(t).ok)continue;let n=t;qt(n,i)&&a.push({name:`${e}/${n.name}`,version:n.version,description:n.description,registry:e})}}catch{console.warn(` [warn] Could not search ${e} registry`)}if(a.length===0){console.log(`No results found.`);return}for(let e of a){let t=e.registry?` (${e.registry})`:``;console.log(`${e.name}@${e.version}${t} — ${e.description}`)}}const Y={baseMode:`light`,accentHue:250,accentChroma:.2,radiusBase:.375,fontFamily:`system`,presetId:`light`};function Yt(e){if(!e)return null;try{let t=e.replace(/-/g,`+`).replace(/_/g,`/`),n=atob(t),r=JSON.parse(n);return{baseMode:r.baseMode===`dark`?`dark`:`light`,accentHue:typeof r.accentHue==`number`?r.accentHue:Y.accentHue,accentChroma:typeof r.accentChroma==`number`?r.accentChroma:Y.accentChroma,radiusBase:typeof r.radiusBase==`number`?r.radiusBase:Y.radiusBase,fontFamily:r.fontFamily??Y.fontFamily,presetId:r.presetId??null}}catch{return null}}const X={geometric:`'Futura', 'Century Gothic', 'Trebuchet MS', ui-sans-serif, sans-serif`,humanist:`'Gill Sans', 'Trebuchet MS', 'Calibri', ui-sans-serif, sans-serif`,transitional:`'Optima', 'Candara', 'Palatino Linotype', ui-sans-serif, sans-serif`,mono:`ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace`};function Xt(e,t={}){let{previewMode:n=!1,themeName:r=`create-custom`}=t,i=e.baseMode===`light`,a=e.accentHue,o=e.accentChroma,s=(e,t=o)=>`oklch(${e} ${t.toFixed(3)} ${a})`,c=[`/* Add to your project CSS after importing the base theme: */`,`/* @import '@cascivo/themes/${e.baseMode}.css'; */`,`/* @import './theme.css'; */`,``,`@layer cascivo.theme {`,` [data-theme="${r}"] {`];return n&&(c.push(i?`
|
|
365
365
|
color-scheme: light;
|
|
366
366
|
--cascivo-color-background: oklch(1 0 0);
|
|
367
367
|
--cascivo-color-surface: oklch(0.985 0.002 264);
|
|
@@ -457,20 +457,20 @@ Add components with: cascivo add <name>`)}const Vt={component:`Components`,layou
|
|
|
457
457
|
--cascivo-ring-width: 2px;
|
|
458
458
|
--cascivo-ring-offset: 0px;
|
|
459
459
|
--cascivo-ring-color: color-mix(in oklch, var(--cascivo-color-accent) 65%, transparent);
|
|
460
|
-
--cascivo-focus-ring: 0 0 0 var(--cascivo-ring-width) var(--cascivo-ring-color);`),c.push(``)),c.push(` /* ── Accent ─────────────────────────────────── */`,` --cascivo-color-accent: ${s(i?.52:.65)};`,` --cascivo-color-accent-foreground: ${i?`oklch(1 0 0)`:`oklch(0.145 0.005 ${a})`};`,` --cascivo-color-accent-hover: ${s(i?.45:.707)};`,` --cascivo-color-accent-active: ${s(i?.373:.808,Math.min(o,.155))};`,` --cascivo-color-accent-subtle: ${s(i?.97:.623,.025)};`,` --cascivo-color-accent-muted: ${s(i?.932:.623,i?.055:o*.2)};`,``,` /* ── Radius ─────────────────────────────────── */`,` --cascivo-radius-base: ${e.radiusBase}rem;`,` --cascivo-radius-control: var(--cascivo-radius-base);`,` --cascivo-radius-surface: calc(var(--cascivo-radius-base) * 1.66);`,` --cascivo-radius-indicator: calc(var(--cascivo-radius-base) / 2);`,` --cascivo-radius-full: 9999px;`,` --cascivo-radius-component: var(--cascivo-radius-base);`,` --cascivo-radius-button: var(--cascivo-radius-base);`,` --cascivo-radius-input: var(--cascivo-radius-base);`,` --cascivo-radius-card: calc(var(--cascivo-radius-base) * 1.66);`,` --cascivo-radius-badge: var(--cascivo-radius-full);`,` --cascivo-radius-modal: calc(var(--cascivo-radius-base) * 2);`),e.fontFamily!==`system`&&(c.push(``),c.push(` /* ── Font ───────────────────────────────────── */`),c.push(` --cascivo-font-sans: ${
|
|
461
|
-
`)}const
|
|
462
|
-
Import the base theme and your overlay in your entry CSS:`),console.log(` @import '@cascivo/themes/${a.baseMode}.css';`),console.log(` @import './${n}.theme.css';`),console.log(`Then set it on a container:`),console.log(` <div data-theme="${n}">…</div>`)}async function
|
|
463
|
-
Import the theme in your root CSS or entry file:`),console.log(` import '@cascivo/themes/${n}.css'`),console.log(`Then set it on a container:`),console.log(` <div data-theme="${n}">…</div>`)}function
|
|
460
|
+
--cascivo-focus-ring: 0 0 0 var(--cascivo-ring-width) var(--cascivo-ring-color);`),c.push(``)),c.push(` /* ── Accent ─────────────────────────────────── */`,` --cascivo-color-accent: ${s(i?.52:.65)};`,` --cascivo-color-accent-foreground: ${i?`oklch(1 0 0)`:`oklch(0.145 0.005 ${a})`};`,` --cascivo-color-accent-hover: ${s(i?.45:.707)};`,` --cascivo-color-accent-active: ${s(i?.373:.808,Math.min(o,.155))};`,` --cascivo-color-accent-subtle: ${s(i?.97:.623,.025)};`,` --cascivo-color-accent-muted: ${s(i?.932:.623,i?.055:o*.2)};`,``,` /* ── Radius ─────────────────────────────────── */`,` --cascivo-radius-base: ${e.radiusBase}rem;`,` --cascivo-radius-control: var(--cascivo-radius-base);`,` --cascivo-radius-surface: calc(var(--cascivo-radius-base) * 1.66);`,` --cascivo-radius-indicator: calc(var(--cascivo-radius-base) / 2);`,` --cascivo-radius-full: 9999px;`,` --cascivo-radius-component: var(--cascivo-radius-base);`,` --cascivo-radius-button: var(--cascivo-radius-base);`,` --cascivo-radius-input: var(--cascivo-radius-base);`,` --cascivo-radius-card: calc(var(--cascivo-radius-base) * 1.66);`,` --cascivo-radius-badge: var(--cascivo-radius-full);`,` --cascivo-radius-modal: calc(var(--cascivo-radius-base) * 2);`),e.fontFamily!==`system`&&(c.push(``),c.push(` /* ── Font ───────────────────────────────────── */`),c.push(` --cascivo-font-sans: ${X[e.fontFamily]??X.humanist};`)),c.push(` }`),c.push(`}`),c.join(`
|
|
461
|
+
`)}const Zt=/^[a-z][a-z0-9-]*$/;function Qt(e,t){let n=e.find(e=>e.startsWith(`--${t}=`));if(n)return n.slice(t.length+3);let r=e.indexOf(`--${t}`),i=r===-1?void 0:e[r+1];return i&&!i.startsWith(`--`)?i:void 0}async function $t(e,t){let n=e.find(e=>!e.startsWith(`--`)),r=Qt(e,`from`),i=e.includes(`--dry-run`);if(!n||!r){console.error(`Usage: cascivo theme create <name> --from <hash> [--out <path>]`),console.error(`Get <hash> from the theme builder at https://cascivo.com/create (Copy CLI command).`);return}if(!Zt.test(n)){console.error(`Invalid theme name "${n}". Use lowercase letters, digits, and dashes.`);return}let a=Yt(r);if(!a){console.error(`Could not decode --from. Copy the command again from the theme builder.`);return}let o=Xt(a,{themeName:n});if(i){console.log(o);return}await c(I(t,Qt(e,`out`)??`${n}.theme.css`),o),console.log(`\n✓ Wrote ${n}.theme.css`),console.log(`
|
|
462
|
+
Import the base theme and your overlay in your entry CSS:`),console.log(` @import '@cascivo/themes/${a.baseMode}.css';`),console.log(` @import './${n}.theme.css';`),console.log(`Then set it on a container:`),console.log(` <div data-theme="${n}">…</div>`)}async function en(e){let[t,n]=e;if(t===`create`){await $t(e.slice(1),process.cwd());return}if(t!==`add`||!n){console.error(`Usage: cascivo theme add <${i.join(`|`)}>`),console.error(` cascivo theme create <name> --from <hash>`);return}if(!i.includes(n)){console.error(`Unknown theme "${n}". Available: ${i.join(`, `)}`);return}B([`@cascivo/themes`]),console.log(`
|
|
463
|
+
Import the theme in your root CSS or entry file:`),console.log(` import '@cascivo/themes/${n}.css'`),console.log(`Then set it on a container:`),console.log(` <div data-theme="${n}">…</div>`)}function tn(e,t){let n=e.split(`
|
|
464
464
|
`),r=t.split(`
|
|
465
|
-
`),i=n.length,a=r.length,o=Array.from({length:i+1},()=>Array.from({length:a+1},()=>0));for(let e=i-1;e>=0;e--)for(let t=a-1;t>=0;t--)o[e][t]=n[e]===r[t]?o[e+1][t+1]+1:Math.max(o[e+1][t],o[e][t+1]);let s=[],c=0,l=0;for(;c<i&&l<a;)n[c]===r[l]?(s.push(` ${n[c]}`),c++,l++):o[c+1][l]>=o[c][l+1]?(s.push(`- ${n[c]}`),c++):(s.push(`+ ${r[l]}`),l++);for(;c<i;)s.push(`- ${n[c++]}`);for(;l<a;)s.push(`+ ${r[l++]}`);return s}function
|
|
465
|
+
`),i=n.length,a=r.length,o=Array.from({length:i+1},()=>Array.from({length:a+1},()=>0));for(let e=i-1;e>=0;e--)for(let t=a-1;t>=0;t--)o[e][t]=n[e]===r[t]?o[e+1][t+1]+1:Math.max(o[e+1][t],o[e][t+1]);let s=[],c=0,l=0;for(;c<i&&l<a;)n[c]===r[l]?(s.push(` ${n[c]}`),c++,l++):o[c+1][l]>=o[c][l+1]?(s.push(`- ${n[c]}`),c++):(s.push(`+ ${r[l]}`),l++);for(;c<i;)s.push(`- ${n[c++]}`);for(;l<a;)s.push(`+ ${r[l++]}`);return s}function nn(e,t){return e!==t}function rn(e,t){let n=e.length,r=t.length,i=Array.from({length:n+1},()=>Array.from({length:r+1},()=>0));for(let a=1;a<=n;a++)for(let n=1;n<=r;n++)i[a][n]=e[a-1]===t[n-1]?i[a-1][n-1]+1:Math.max(i[a-1][n],i[a][n-1]);return i}function Z(e,t){let n=rn(e,t),r=[],i=e.length,a=t.length,o=[],s=[],c=[];function l(){o.length>0||s.length>0?(c.length>0&&(r.unshift({type:`common`,lines:[...c]}),c.length=0),r.unshift({type:o.length>0?`left`:`right`,lines:o.length>0?[...o]:[...s]}),o.length=0,s.length=0):c.length>0&&(r.unshift({type:`common`,lines:[...c]}),c.length=0)}for(;i>0||a>0;)i>0&&a>0&&e[i-1]===t[a-1]?((o.length>0||s.length>0)&&l(),c.unshift(e[i-1]),i--,a--):a>0&&(i===0||n[i][a-1]>=n[i-1][a])?(l(),s.unshift(t[a-1]),a--):(l(),o.unshift(e[i-1]),i--);return l(),r}function an(e,t,n){let r=e.split(`
|
|
466
466
|
`),i=t.split(`
|
|
467
467
|
`),a=n.split(`
|
|
468
468
|
`),o=Z(r,i),s=new Map,c=0;for(let e of o)e.type===`left`?s.set(`del:${c}`,e.lines):(e.type===`right`&&s.set(`ins:${c}`,e.lines),c+=e.lines.length);let l=[],u=0;if(r.length,i.length,a.length,t===e)return{text:n,conflicts:0};if(n===e)return{text:t,conflicts:0};let d=Z(r,i),f=Z(r,a),p=0,m=0,h=0,g=[],_=[];for(let e of d)e.type===`common`?(m+=e.lines.length,p+=e.lines.length):e.type===`right`?(g.push({baseStart:p,baseEnd:p,lines:e.lines}),m+=e.lines.length):(g.push({baseStart:p,baseEnd:p+e.lines.length,lines:[]}),p+=e.lines.length);p=0;for(let e of f)e.type===`common`?(h+=e.lines.length,p+=e.lines.length):e.type===`right`?(_.push({baseStart:p,baseEnd:p,lines:e.lines}),h+=e.lines.length):(_.push({baseStart:p,baseEnd:p+e.lines.length,lines:[]}),p+=e.lines.length);let v=new Map;for(let e of g)v.set(e.baseStart,{end:e.baseEnd,lines:e.lines});let y=new Map;for(let e of _)y.set(e.baseStart,{end:e.baseEnd,lines:e.lines});let b=0;for(;b<=r.length;){let e=v.get(b),t=y.get(b);if(e&&t){let n=Math.max(e.end,b),r=Math.max(t.end,b),i=e.lines,a=t.lines;JSON.stringify(i)===JSON.stringify(a)?l.push(...i):(l.push(`<<<<<<< local`),l.push(...i),l.push(`=======`),l.push(...a),l.push(`>>>>>>> upstream`),u++),b=Math.max(n,r,b+1)}else e?(l.push(...e.lines),b=Math.max(e.end,b+1)):t?(l.push(...t.lines),b=Math.max(t.end,b+1)):(b<r.length&&l.push(r[b]),b++)}return{text:l.join(`
|
|
469
|
-
`),conflicts:u}}async function
|
|
470
|
-
`)),i.push({path:a,content:r}))}if(i.length===0){console.log(`${e} is already up to date.`);return}if(r.yes||await
|
|
469
|
+
`),conflicts:u}}async function on(e){let t=z({input:k,output:A});try{let n=(await t.question(`${e} (y/N): `)).trim().toLowerCase();return n===`y`||n===`yes`}finally{t.close()}}async function sn(e,t,n={}){if(n.check)return un(t);if(!e){console.error(`Usage: cascivo update <component>`);return}let r=(await v())?.items[e],i=h(await y(t.registry),e);if(!i){console.error(`Component "${e}" not found in registry. Run "cascivo list".`);return}if(r){let a=r.version,o=`${r.registry}/r/${e}@${a}.json`,s=null;try{s=R(await p(o),o)}catch{console.warn(`Warning: could not fetch base version ${a} from ${o}. Falling back to two-way diff.`)}s?await cn(e,i,s,t,n):await ln(e,i,t,n)}else console.warn(`Warning: "${e}" has no lock entry. Falling back to two-way diff update (pre-v11 install).`),await ln(e,i,t,n)}async function cn(e,t,n,r,i){if(!t)return;let a=e.includes(`/`)?e.split(`/`).pop():e,o=[],s=[];for(let e of t.files){let t=x(e),i=n.files.find(e=>x(e.url)===t),c=u(r.outputDir,a,t),l=await f(e),d=j(c)?await oe(c,`utf8`):``,p=i?await f(i.url):``;if(p===``&&d===``){o.push({file:t,result:`clean`}),s.push({dest:c,content:l,conflicts:0});continue}let{text:m,conflicts:h}=an(p,d,l);if(h>0)o.push({file:t,result:`conflict`});else if(m===d){o.push({file:t,result:`unchanged`});continue}else o.push({file:t,result:`clean`});s.push({dest:c,content:m,conflicts:h})}if(s.length===0){console.log(`${e} is already up to date.`);return}for(let e of o){let t=e.result===`conflict`?`⚠`:e.result===`clean`?`✓`:`·`;console.log(` ${t} ${e.file} (${e.result})`)}let l=s.filter(e=>e.conflicts>0);if((i.yes?l.length===0:await on(`\nApply ${s.length} change(s) to ${e}?`))||i.yes){let n=await v(),r=n;for(let{dest:e,content:t,conflicts:n}of s){if(i.yes&&n>0){console.log(` skipped (conflicts): ${e}`);continue}await c(e,t)}if(n&&r){let i=l.length>0;r=g(r,e,{...n.items[e],version:t.version,...i?{conflicted:!0}:{}}),await m(r)}console.log(`Updated ${e}.`),l.length>0&&console.log(`${l.length} file(s) have conflict markers — resolve them manually.`)}else console.log(`Aborted. No files changed.`)}async function ln(e,t,n,r){if(!t)return;let i=[];for(let e of t.files){let r;try{r=await f(e)}catch(e){console.error(e instanceof Error?e.message:String(e));return}let a=u(n.outputDir,t.name,x(e)),o=await l(a);o===null?(console.log(`New file: ${a}`),i.push({path:a,content:r})):nn(o,r)&&(console.log(`\n--- ${a}`),console.log(tn(o,r).join(`
|
|
470
|
+
`)),i.push({path:a,content:r}))}if(i.length===0){console.log(`${e} is already up to date.`);return}if(r.yes||await on(`\nApply ${i.length} change(s) to ${e}?`)){for(let{path:e,content:t}of i)await c(e,t);console.log(`Updated ${e}.`)}else console.log(`Aborted. No files changed.`)}async function un(e){let t=await v();if(!t||Object.keys(t.items).length===0){console.log(`No installed components found in cascivo.lock.`);return}let n=await y(e.registry),r=0;for(let[e,i]of Object.entries(t.items)){let t=h(n,e);if(t)if(t.fileHashes&&Object.keys(t.fileHashes).length>0){let n=new Map(Object.entries(i.files).map(([e,t])=>[e.split(`/`).pop(),t])),a=Object.entries(t.fileHashes).filter(([e,t])=>n.get(e)!==t);a.length>0&&(console.log(`${e}: ${a.length} file(s) changed upstream (${i.version} → ${t.version})`),r++)}else t.version!==i.version&&(console.log(`${e}: ${i.version} → ${t.version}`),r++)}r>0?(console.log(`${r} component(s) outdated.`),process.exitCode=1):console.log(`All components up to date.`)}function dn(e){let t=[];if(t.push(`\n${e.name} v${e.version}`),t.push(`Type: ${e.type}${e.category?` / ${e.category}`:``}`),t.push(e.description),e.author&&t.push(`Author: ${e.author}`),e.license&&t.push(`License: ${e.license}`),e.homepage&&t.push(`Homepage: ${e.homepage}`),e.install?(t.push(`Distribution: npm package — pnpm add ${e.install}`),e.styles&&t.push(`Stylesheet: import '${e.styles}' (required)`)):L(e)||t.push(`Distribution: copy-paste — npx cascivo add ${e.name}`),L(e))try{let n=se(e.meta);if(t.push(`\nTemplate: ${n.intent}`),t.push(`Framework: ${n.framework}`),n.demoUrl&&t.push(`Demo: ${n.demoUrl}`),n.pages?.length){t.push(`Pages:`);for(let e of n.pages)t.push(` ${e.name} → ${e.target}`)}}catch{}if(e.changelog?.length){t.push(`
|
|
471
471
|
Changelog:`);for(let n of e.changelog.slice(0,5))t.push(` ${n.version}: ${n.note}`)}if(e.files?.length){t.push(`
|
|
472
|
-
Files:`);for(let n of e.files)t.push(` ${n.url}${n.target?` → ${n.target}`:``}`)}if(e.dependencies?.length&&t.push(`\nDependencies: ${e.dependencies.join(`, `)}`),e.registryDependencies?.length){let n=
|
|
473
|
-
`)}async function
|
|
472
|
+
Files:`);for(let n of e.files)t.push(` ${n.url}${n.target?` → ${n.target}`:``}`)}if(e.dependencies?.length&&t.push(`\nDependencies: ${e.dependencies.join(`, `)}`),e.registryDependencies?.length){let n=L(e)?`Components`:`Registry dependencies`;t.push(`${n}: ${e.registryDependencies.join(`, `)}`)}return t.join(`
|
|
473
|
+
`)}async function fn(e,t){let n=e[0];if(!n){console.error(`Usage: cascivo view <component-spec>`);return}let{url:r,headers:i,params:a}=await W(H(n),t),o={};i&&(o.headers=i),a&&(o.params=a);let s=R(await p(r,o),r);console.log(dn(s))}const Q=D(import.meta.url)(`../package.json`).version,pn=`cascivo ${Q} — the CSS-native, signal-driven, AI-first design system
|
|
474
474
|
|
|
475
475
|
Usage: cascivo <command> [options]
|
|
476
476
|
|
|
@@ -491,8 +491,34 @@ Commands:
|
|
|
491
491
|
registry build Build a static registry from a cascivo-registry.json file
|
|
492
492
|
template init <name> Scaffold a new template (source + manifest + registry entry)
|
|
493
493
|
tokens import <file> Import external design tokens as cascivo overrides
|
|
494
|
+
email lint <file...> Check rendered email HTML against the Can I email matrix
|
|
494
495
|
|
|
495
|
-
Run "cascivo <command> --help" for details.`,$=
|
|
496
|
+
Run "cascivo <command> --help" for details.`,$=i.join(` | `),mn={email:`Usage: cascivo email lint <file...> [options]
|
|
497
|
+
|
|
498
|
+
Check rendered email HTML against the Can I email support matrix — the same
|
|
499
|
+
conformance lint @cascivo/email exposes as \`lint()\`, with the setup done for you.
|
|
500
|
+
|
|
501
|
+
It lints rendered HTML, not templates: render in your own build and pass the
|
|
502
|
+
output, or pipe it in.
|
|
503
|
+
|
|
504
|
+
Arguments:
|
|
505
|
+
<file...> One or more rendered .html files, or \`-\` for stdin
|
|
506
|
+
|
|
507
|
+
Options:
|
|
508
|
+
--data <file> Use a local copy of the matrix instead of fetching
|
|
509
|
+
--refresh Re-fetch the matrix even if the cache is fresh
|
|
510
|
+
--no-allowlist Report findings CASCIVO_ALLOW waives, too
|
|
511
|
+
|
|
512
|
+
The matrix is fetched from https://www.caniemail.com/api/data.json and cached for
|
|
513
|
+
a day. It is not bundled with @cascivo/email because it is ~483 KB of test data.
|
|
514
|
+
|
|
515
|
+
Exits non-zero when a floor client genuinely cannot support something. A caveat is
|
|
516
|
+
partial support worth knowing about and never fails the command.
|
|
517
|
+
|
|
518
|
+
Examples:
|
|
519
|
+
cascivo email lint dist/emails/*.html
|
|
520
|
+
node render.js | cascivo email lint -
|
|
521
|
+
cascivo email lint dist/welcome.html --data caniemail.json`,create:`Usage: cascivo create [name] [options]
|
|
496
522
|
|
|
497
523
|
Scaffold a new ready-to-run app — Vite + React + TypeScript, pre-wired with the
|
|
498
524
|
cascivo app shell, side navigation, header, and a theme.
|
|
@@ -598,5 +624,5 @@ Options:
|
|
|
598
624
|
--repo <owner/repo> Repository the template will be hosted in`,tokens:`Usage: cascivo tokens import <file>
|
|
599
625
|
|
|
600
626
|
Import external design tokens (W3C design-tokens JSON) as cascivo token
|
|
601
|
-
overrides.`};async function
|
|
627
|
+
overrides.`};async function hn(e){let[n,...r]=e;if(n!==void 0&&(r.includes(`--help`)||r.includes(`-h`))){let e=mn[n];if(e!==void 0){console.log(e);return}}switch(n){case`create`:await et(r);break;case`init`:await zt(r);break;case`add`:{let e=T(r);if(`error`in e){console.error(e.error),process.exitCode=1;break}await Oe(w(r,[`pm`,`package-manager`]),await t(),{dryRun:r.includes(`--dry-run`),yes:r.includes(`--yes`),noInstall:r.includes(`--no-install`),...e.pm?{pm:e.pm}:{}});break}case`list`:await Wt(await t(),{installed:r.includes(`--installed`)});break;case`update`:await sn(r.filter(e=>!e.startsWith(`--`))[0],await t(),{check:r.includes(`--check`),yes:r.includes(`--yes`)});break;case`search`:await Jt(r,await t());break;case`view`:await fn(r,await t());break;case`theme`:await en(r);break;case`eject`:{let{eject:e}=await import(`./eject-B94ujtUo.mjs`),n=e=>{let t=r.find(t=>t.startsWith(`--${e}=`));if(t)return t.slice(e.length+3);let n=r.indexOf(`--${e}`),i=n===-1?void 0:r[n+1];return i&&!i.startsWith(`--`)?i:void 0},i=n(`tokens`);await e(r,await t(),{...i?{tokens:i.split(`,`).map(e=>e.trim()).filter(Boolean)}:{},...n(`scope`)?{scope:n(`scope`)}:{},...n(`out`)?{out:n(`out`)}:{},dryRun:r.includes(`--dry-run`)});break}case`generate`:await kt(r,await t());break;case`registry`:r[0]===`build`?await Kt(r.slice(1)):(console.error(`Unknown registry subcommand: ${r[0]}`),process.exitCode=1);break;case`template`:if(r[0]===`init`){let{templateInit:e}=await import(`./template-init-BFlRHOxK.mjs`);await e(r.slice(1))}else console.error(`Unknown template subcommand: ${r[0]}`),process.exitCode=1;break;case`doctor`:{let e=r.includes(`--ci`);if(r.includes(`--drift`)){let{runDoctorDrift:e}=await import(`./drift-BCtn9Ua_.mjs`);await e(await t())}else{let n=process.cwd(),r=await bt(n),{checkDuplicateCore:i,checkFormatterIgnore:a,checkProjectDependencies:o,checkSignalsCompat:s,checkSsrConfig:c,detectInstallPath:l}=await Promise.resolve().then(()=>tt),u=l(n)!==`unknown`,d=u?o(n):[],f=d.filter(e=>e.required),p=u?await s(n):null,m=p?.severity===`error`,h=u?c(n):null,g=u?await i(n):null,_=u?a(n,(await t()).outputDir):null,{runDoctorDrift:v}=await import(`./drift-BCtn9Ua_.mjs`),y=u?await v(await t(),n):{ran:!1,reason:`no cascivo install detected`,issues:0};if(r.passed&&d.length===0&&p===null&&h===null&&g===null&&_===null&&y.issues===0)console.log(y.ran?`No violations found.`:`No violations found (drift: not checked — ${y.reason}).`);else{for(let e of r.violations)console.error(`[${e.rule}] ${e.detail}\n ${e.file}`);for(let e of f)console.error(e.kind===`forbidden`?`[forbidden-dependency] ${e.package} must not be a direct dependency here. Remove it — ${e.hint}`:`[missing-dependency] ${e.package} is not in package.json. Install: ${e.hint}`);p&&(m?console.error:console.log)(`[${m?`signals-incompatible`:`signals-outdated`}] ${p.detail} Upgrade: ${p.hint}`),h&&console.log(`[ssr-config] ${h}`),_&&console.log(`[formatter-drift] ${_}`),g&&console.error(`[duplicate-core] More than one @cascivo/core is installed (root: ${g.root??`none`}; ${g.nested.join(`; `)}). `+g.hint);for(let e of d.filter(e=>!e.required))console.log(`[optional] ${e.package} is not installed; add it when a component or chart needs it: ${e.hint}`);e&&(r.violations.length>0||f.length>0||m||g!==null||y.issues>0)&&(process.exitCode=1)}}break}case`audit`:{let{audit:e}=await import(`./audit-DqWSsQGC.mjs`);await e(r,await t());break}case`email`:{let{email:e}=await import(`./email-CwQcZ-mB.mjs`);await e(r);break}case`tokens`:if(r[0]===`import`){let{tokensImport:e}=await import(`./tokens-VSJC9GgT.mjs`);await e(r.slice(1))}else console.error(`Unknown tokens subcommand: ${r[0]}`),process.exitCode=1;break;case void 0:case`--help`:case`-h`:case`help`:console.log(pn);break;case`--version`:case`-v`:console.log(Q);break;default:console.error(`Unknown command: ${n}\n`),console.log(pn),process.exitCode=1}}O[1]!==void 0&&import.meta.url===ne(O[1]).href&&hn(O.slice(2)).catch(e=>{console.error(e instanceof Error?e.message:String(e)),process.exitCode=1});export{Q as VERSION,hn as run};
|
|
602
628
|
//# sourceMappingURL=index.mjs.map
|