@sugarcube-org/cli 0.0.0-alpha.2 → 0.0.0-alpha.4

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.
Files changed (2) hide show
  1. package/dist/index.mjs +11 -11
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- var je=Object.defineProperty;var p=(e,n)=>je(e,"name",{value:n,configurable:!0});import{Command as O}from"commander";import{validationPipeline as Ce,generationPipeline as Fe}from"@sugarcube-org/core";import{z as l}from"zod";import g from"picocolors";import h from"path";import X,{readFile as le,writeFile as A,mkdir as P}from"fs/promises";import{existsSync as D}from"fs";import{text as M,isCancel as b,select as W,multiselect as ee,confirm as z,log as k,spinner as te,intro as B,note as V,cancel as ne,outro as L}from"@clack/prompts";import Ee from"node-fetch";import ue from"fast-glob";import{execa as Ie}from"execa";import{detect as De}from"@antfu/ni";import se from"node:fs/promises";const oe=l.enum(["react","astro","nunjucks"]),pe=l.object({path:l.string(),type:l.string()}),Ne=pe.extend({framework:oe}),Pe=l.object({name:l.string(),type:l.string(),description:l.string().optional(),frameworks:l.array(l.string()).optional(),files:l.array(l.union([Ne,pe])),tokens:l.record(l.object({type:l.string(),mapping:l.string()})).optional(),dependencies:l.record(oe,l.array(l.string())).optional(),registryDependencies:l.record(oe,l.array(l.string())).optional(),tokenDependencies:l.array(l.string()).optional()}),Te=l.array(Pe),Re=l.object({content:l.string()}),re=l.object({tokens:l.union([l.object({source:l.array(l.string()),type:l.enum(["starter-kit","custom"]),themes:l.record(l.array(l.string())).optional()}),l.record(l.string(),l.object({source:l.array(l.string()),type:l.enum(["starter-kit","custom"]),themes:l.record(l.array(l.string())).optional()}))]),options:l.object({fluid:l.object({min:l.number(),max:l.number()}).optional(),prefix:l.string().optional(),color:l.enum(["hex","rgb","rgba","hsl","hsla","oklch","p3"]).optional()}).optional(),output:l.object({directories:l.object({tokens:l.string(),components:l.string().optional(),css:l.string()}),css:l.object({separate:l.boolean(),manageIndex:l.boolean().optional(),format:l.enum(["css","scss","less"]).optional()})})}),v={error:g.red,warn:g.yellow,info:g.cyan,success:g.green,bold:g.bold,path:g.cyan},S={error(...e){console.log(v.error(e.join(" ")))},warn(...e){console.log(v.warn(e.join(" ")))},info(...e){console.log(v.info(e.join(" ")))},success(...e){console.log(v.success(e.join(" ")))},log(...e){console.log(e.join(" "))},break(){console.log("")}};class d extends Error{static{p(this,"CLIError")}constructor(n,t){super(n),this.name="CLIError",this.cause=t}}async function G(e,n={type:"files",paths:e}){const{trees:t,resolved:o,errors:s}=await Ce(e,{loader:n});if(s.load.length>0)throw new d(`Failed to load token files:
2
+ var je=Object.defineProperty;var p=(e,n)=>je(e,"name",{value:n,configurable:!0});import{Command as O}from"commander";import{validationPipeline as Ce,generationPipeline as Fe}from"@sugarcube-org/core";import{z as l}from"zod";import g from"picocolors";import h from"path";import X,{readFile as le,writeFile as M,mkdir as P}from"fs/promises";import{existsSync as D}from"fs";import{text as A,isCancel as b,select as U,multiselect as ee,confirm as z,log as k,spinner as te,intro as B,note as V,cancel as ne,outro as L}from"@clack/prompts";import Ee from"node-fetch";import ue from"fast-glob";import{execa as Ie}from"execa";import{detect as De}from"@antfu/ni";import se from"node:fs/promises";const oe=l.enum(["react","astro","nunjucks"]),pe=l.object({path:l.string(),type:l.string()}),Ne=pe.extend({framework:oe}),Pe=l.object({name:l.string(),type:l.string(),description:l.string().optional(),frameworks:l.array(l.string()).optional(),files:l.array(l.union([Ne,pe])),tokens:l.record(l.object({type:l.string(),mapping:l.string()})).optional(),dependencies:l.record(oe,l.array(l.string())).optional(),registryDependencies:l.record(oe,l.array(l.string())).optional(),tokenDependencies:l.array(l.string()).optional()}),Te=l.array(Pe),Re=l.object({content:l.string()}),re=l.object({tokens:l.union([l.object({source:l.array(l.string()),type:l.enum(["starter-kit","custom"]),themes:l.record(l.array(l.string())).optional()}),l.record(l.string(),l.object({source:l.array(l.string()),type:l.enum(["starter-kit","custom"]),themes:l.record(l.array(l.string())).optional()}))]),options:l.object({fluid:l.object({min:l.number(),max:l.number()}).optional(),prefix:l.string().optional(),color:l.enum(["hex","rgb","rgba","hsl","hsla","oklch","p3"]).optional()}).optional(),output:l.object({directories:l.object({tokens:l.string(),components:l.string().optional(),css:l.string()}),css:l.object({separate:l.boolean(),manageIndex:l.boolean().optional(),format:l.enum(["css","scss","less"]).optional()})})}),v={error:g.red,warn:g.yellow,info:g.cyan,success:g.green,bold:g.bold,path:g.cyan},S={error(...e){console.log(v.error(e.join(" ")))},warn(...e){console.log(v.warn(e.join(" ")))},info(...e){console.log(v.info(e.join(" ")))},success(...e){console.log(v.success(e.join(" ")))},log(...e){console.log(e.join(" "))},break(){console.log("")}};class d extends Error{static{p(this,"CLIError")}constructor(n,t){super(n),this.name="CLIError",this.cause=t}}async function G(e,n={type:"files",paths:e}){const{trees:t,resolved:o,errors:s}=await Ce(e,{loader:n});if(s.load.length>0)throw new d(`Failed to load token files:
3
3
  ${s.load.map(i=>`${i.file}: ${i.message}`).join(`
4
- `)}`);if(s.validation.length>0||s.flatten.length>0||s.resolution.length>0){S.break();const i=[...s.flatten,...s.validation,...s.resolution],c=new Map;throw i.forEach(a=>{if(a.source?.sourcePath){const r=c.get(a.source.sourcePath)||[];r.push(a.message),c.set(a.source.sourcePath,r)}}),c.forEach((a,r)=>{S.error(`Error(s) in ${v.path(r)}:`),a.forEach(u=>{S.error(` - ${u}`)}),S.break()}),new d(`Token validation failed. See ${v.info("https://docs.sugarcube.sh/w3c-token-format")} for help`)}return{trees:t,resolved:o}}p(G,"validateTokens");async function fe(e="./src/styles"){const n=await M({message:"Save CSS to",placeholder:e,validate:p(t=>{if(t.trim().replace(/['"]/g,"").length===0)return"Output directory cannot be empty"},"validate")});return b(n)&&process.exit(0),n}p(fe,"promptCSSOutputDirectory");async function Oe(e="./src/design-tokens"){const n=await M({message:"Save tokens to",placeholder:e,validate:p(t=>{if(!t.trim())return"Please provide a path"},"validate")});return b(n)&&process.exit(0),n}p(Oe,"promptTokensDirectory");async function Ae(){const e=await W({message:"Which kit?",options:[{label:"Responsive",value:"starter-fluid",hint:"Tokens with fluid typography and spacing (recommended)"},{label:"Static",value:"starter-static",hint:"Tokens with fixed typography and spacing"}]});return b(e)&&process.exit(0),e}p(Ae,"promptStarterKit");async function me(e="./src/components"){const n=await M({message:"Save components to",placeholder:e,validate:p(t=>{if(t.trim().replace(/['"]/g,"").length===0)return"Output directory cannot be empty"},"validate")});return b(n)&&process.exit(0),n}p(me,"promptComponentDirectory");async function de(e=!0){const n=[{label:"React",value:"react",hint:".tsx"},{label:"Astro",value:"astro",hint:".astro"},{label:"Nunjucks",value:"nunjucks",hint:".njk"}];e&&n.push({label:"Skip",value:"skip",hint:"continue without components"});const t=await W({message:"Build with",options:n});return b(t)&&process.exit(0),t}p(de,"promptComponentFramework");async function ge(e,n){const t=e.filter(s=>s.type==="component"&&s.frameworks?.includes(n)),o=await ee({message:"Select components to add",options:t.map(s=>({label:s.name,value:s.name,hint:s.description})),required:!0});return b(o)&&process.exit(0),o}p(ge,"promptComponentSelectionFiltered");async function Me(){const n=await W({message:"Set up tokens with",options:[{label:"Starter kit",value:"starter"},{label:"Own tokens",value:"existing"}]});return b(n)&&process.exit(0),n}p(Me,"promptTokenSetup");function Le(e,n,t,o){return e.output=e.output||{},e.output.directories={tokens:h.relative(process.cwd(),t),css:h.relative(process.cwd(),h.resolve(process.cwd(),n))},e.tokens||(e.tokens={type:"starter-kit",source:[]}),e}p(Le,"updateConfigWithTokenDirs");async function K(e,n=!1){const t=await z({message:e,initialValue:n});return(!t||b(t))&&process.exit(0),!0}p(K,"confirmOverwrite");async function Ue(){const e=await z({message:"Install CUBE CSS?",active:"Yes",inactive:"No",initialValue:!0});return b(e)&&process.exit(0),e}p(Ue,"promptInstallCube");async function We(){const e=await M({message:"Path to tokens?",placeholder:"./src/design-tokens",validate:p(n=>{if(n.trim().replace(/['"]/g,"").length===0)return"Path cannot be empty"},"validate")});return b(e)&&process.exit(0),e}p(We,"promptExistingTokensPath");async function ze(){const e=await z({message:"Generate separate CSS file for each token file?"});return b(e)&&process.exit(0),e}p(ze,"promptSeparateCSSFiles");async function Be(){const e=await W({message:"How would you like to organize your tokens?",options:[{value:"simple",label:"Simple (all tokens in one place)"},{value:"collections",label:"Collections (group related tokens together)"}]});return b(e)&&process.exit(0),e}p(Be,"promptCollectionOrganization");async function he(e,n=!1){if(e.length===0)return null;const t=await ee({message:`Select files for your ${n?"first":"next"} collection (including any theme files)`,options:e.map(o=>({label:o,value:o}))});return b(t)&&process.exit(0),t.length===0?null:t}p(he,"promptFilesForCollection");async function ie(e){const n=e.map(o=>h.dirname(o).split(h.sep)).reduce((o,s)=>o?o.filter((i,c)=>i===s[c]):s).pop(),t=await M({message:"Name this collection:",placeholder:n||"collection"});return b(t)&&process.exit(0),t}p(ie,"promptCollectionName");async function Ge(e){if(e.length<=1)return null;const n=await z({message:"Are any of these theme files?",initialValue:!1});if(b(n)&&process.exit(0),!n)return null;const t=[];let o=[...e];for(;o.length>0;){const s=await ee({message:t.length===0?"Select files for first theme:":"Select files for another theme (or Enter to finish):",options:o.map(c=>({label:c,value:c}))});if(b(s)&&process.exit(0),s.length===0)break;const i=await M({message:"Name this theme:",placeholder:"light"});if(b(i)&&process.exit(0),t.push({name:i,files:s}),o=o.filter(c=>!s.includes(c)),o.length>0){const c=await z({message:"Create another theme?",initialValue:!0});if(b(c)&&process.exit(0),!c)break}}return t.length>0?t:null}p(Ge,"promptIdentifyThemeFiles");async function we(e,n,t){const{output:o}=await Fe(e,n,t),s=o.map(i=>i.name).filter(i=>D(i));if(s.length>0){const i=s.map(c=>` - ${c}`).join(`
4
+ `)}`);if(s.validation.length>0||s.flatten.length>0||s.resolution.length>0){S.break();const i=[...s.flatten,...s.validation,...s.resolution],c=new Map;throw i.forEach(a=>{if(a.source?.sourcePath){const r=c.get(a.source.sourcePath)||[];r.push(a.message),c.set(a.source.sourcePath,r)}}),c.forEach((a,r)=>{S.error(`Error(s) in ${v.path(r)}:`),a.forEach(u=>{S.error(` - ${u}`)}),S.break()}),new d(`Token validation failed. See ${v.info("https://docs.sugarcube.sh/w3c-token-format")} for help`)}return{trees:t,resolved:o}}p(G,"validateTokens");async function fe(e="./src/styles"){const n=await A({message:"Save CSS to",placeholder:e,validate:p(t=>{if(t.trim().replace(/['"]/g,"").length===0)return"Output directory cannot be empty"},"validate")});return b(n)&&process.exit(0),n}p(fe,"promptCSSOutputDirectory");async function Oe(e="./src/design-tokens"){const n=await A({message:"Save tokens to",placeholder:e,validate:p(t=>{if(!t.trim())return"Please provide a path"},"validate")});return b(n)&&process.exit(0),n}p(Oe,"promptTokensDirectory");async function Me(){const e=await U({message:"Which kit?",options:[{label:"Responsive",value:"starter-fluid",hint:"Tokens with fluid typography and spacing (recommended)"},{label:"Static",value:"starter-static",hint:"Tokens with fixed typography and spacing"}]});return b(e)&&process.exit(0),e}p(Me,"promptStarterKit");async function me(e="./src/components"){const n=await A({message:"Save components to",placeholder:e,validate:p(t=>{if(t.trim().replace(/['"]/g,"").length===0)return"Output directory cannot be empty"},"validate")});return b(n)&&process.exit(0),n}p(me,"promptComponentDirectory");async function de(e=!0){const n=[{label:"React",value:"react",hint:".tsx"},{label:"Astro",value:"astro",hint:".astro"},{label:"Nunjucks",value:"nunjucks",hint:".njk"}];e&&n.push({label:"Skip",value:"skip",hint:"continue without components"});const t=await U({message:"Build with",options:n});return b(t)&&process.exit(0),t}p(de,"promptComponentFramework");async function ge(e,n){const t=e.filter(s=>s.type==="component"&&s.frameworks?.includes(n)),o=await ee({message:"Select components to add",options:t.map(s=>({label:s.name,value:s.name,hint:s.description})),required:!0});return b(o)&&process.exit(0),o}p(ge,"promptComponentSelectionFiltered");async function Ae(){const n=await U({message:"Set up tokens with",options:[{label:"Starter kit",value:"starter"},{label:"Own tokens",value:"existing"}]});return b(n)&&process.exit(0),n}p(Ae,"promptTokenSetup");function Le(e,n,t,o){return e.output=e.output||{},e.output.directories={tokens:h.relative(process.cwd(),t),css:h.relative(process.cwd(),h.resolve(process.cwd(),n))},e.tokens||(e.tokens={type:"starter-kit",source:[]}),e}p(Le,"updateConfigWithTokenDirs");async function K(e,n=!1){const t=await z({message:e,initialValue:n});return(!t||b(t))&&process.exit(0),!0}p(K,"confirmOverwrite");async function We(){const e=await z({message:"Install CUBE CSS?",active:"Yes",inactive:"No",initialValue:!0});return b(e)&&process.exit(0),e}p(We,"promptInstallCube");async function Ue(){const e=await A({message:"Path to tokens?",placeholder:"./src/design-tokens",validate:p(n=>{if(n.trim().replace(/['"]/g,"").length===0)return"Path cannot be empty"},"validate")});return b(e)&&process.exit(0),e}p(Ue,"promptExistingTokensPath");async function ze(){const e=await z({message:"Generate separate CSS file for each token file?"});return b(e)&&process.exit(0),e}p(ze,"promptSeparateCSSFiles");async function Be(){const e=await U({message:"How would you like to organize your tokens?",options:[{value:"simple",label:"Simple (all tokens in one place)"},{value:"collections",label:"Collections (group related tokens together)"}]});return b(e)&&process.exit(0),e}p(Be,"promptCollectionOrganization");async function he(e,n=!1){if(e.length===0)return null;const t=await ee({message:`Select files for your ${n?"first":"next"} collection (including any theme files)`,options:e.map(o=>({label:o,value:o}))});return b(t)&&process.exit(0),t.length===0?null:t}p(he,"promptFilesForCollection");async function ie(e){const n=e.map(o=>h.dirname(o).split(h.sep)).reduce((o,s)=>o?o.filter((i,c)=>i===s[c]):s).pop(),t=await A({message:"Name this collection:",placeholder:n||"collection"});return b(t)&&process.exit(0),t}p(ie,"promptCollectionName");async function Ge(e){if(e.length<=1)return null;const n=await z({message:"Are any of these theme files?",initialValue:!1});if(b(n)&&process.exit(0),!n)return null;const t=[];let o=[...e];for(;o.length>0;){const s=await ee({message:t.length===0?"Select files for first theme:":"Select files for another theme (or Enter to finish):",options:o.map(c=>({label:c,value:c}))});if(b(s)&&process.exit(0),s.length===0)break;const i=await A({message:"Name this theme:",placeholder:"light"});if(b(i)&&process.exit(0),t.push({name:i,files:s}),o=o.filter(c=>!s.includes(c)),o.length>0){const c=await z({message:"Create another theme?",initialValue:!0});if(b(c)&&process.exit(0),!c)break}}return t.length>0?t:null}p(Ge,"promptIdentifyThemeFiles");async function we(e,n,t){const{output:o}=await Fe(e,n,t),s=o.map(i=>i.name).filter(i=>D(i));if(s.length>0){const i=s.map(c=>` - ${c}`).join(`
5
5
  `);k.warn(g.yellow(`The following files will be regenerated:
6
6
  ${g.dim(i)}`)),await K("Continue?",!0)}for(const i of o)try{await X.mkdir(h.dirname(i.name),{recursive:!0}),await X.writeFile(i.name,i.content,"utf-8")}catch(c){const a=c instanceof Error?`: ${c.message}`:"";throw new d(`Failed to write CSS file ${i.name}${a}`)}return o}p(we,"generateAndWriteCSSVars");function Y(e){const t=[...e.config?[e.config]:[],...e.tokens||[],...e.generated].map(s=>h.relative(process.cwd(),s)),o=te();o.start(`Generating ${t.length} files:`),o.stop(`Generated ${t.length} files:`),t.forEach(s=>{S.log(` - ${s}`)}),S.break()}p(Y,"showSummary");const ye=process.env.REGISTRY_URL??"https://registry.sugarcube.sh/registry";async function ke(e){try{const n=await Ee(e);if(!n.ok){if(n.status===401)throw new d(`Registry access denied: Authentication required
7
7
  URL: ${v.info(e)}`);if(n.status===403)throw new d(`Registry access denied: Invalid or missing token
@@ -9,11 +9,11 @@ URL: ${v.info(e)}`);if(n.status===404)throw new d(`Registry resource not found
9
9
  URL: ${v.info(e)}`);const t=await n.json().catch(()=>null),o=t&&typeof t=="object"&&"error"in t?t.error:n.statusText;throw new d(`Registry request failed: ${o}
10
10
  URL: ${v.info(e)}`)}return n.json()}catch(n){throw n instanceof d?n:new d(`Failed to connect to registry
11
11
  URL: ${v.info(e)}
12
- Check your internet connection`)}}p(ke,"fetchRegistry");async function U(){const e=`${ye}/index.json`,n=await ke(e);try{return Te.parse(n)}catch{throw new d(`Invalid registry data received
13
- URL: ${v.info(e)}`)}}p(U,"getRegistryIndex");async function Z({type:e,name:n,framework:t}){const o=await U(),s=o.find(a=>a.type===e&&a.name===n);if(!s){const a=o.filter(r=>r.type===e).map(r=>r.name);throw new d(`${e} '${v.info(n)}' not found in registry
12
+ Check your internet connection`)}}p(ke,"fetchRegistry");async function W(){const e=`${ye}/index.json`,n=await ke(e);try{return Te.parse(n)}catch{throw new d(`Invalid registry data received
13
+ URL: ${v.info(e)}`)}}p(W,"getRegistryIndex");async function Z({type:e,name:n,framework:t}){const o=await W(),s=o.find(a=>a.type===e&&a.name===n);if(!s){const a=o.filter(r=>r.type===e).map(r=>r.name);throw new d(`${e} '${v.info(n)}' not found in registry
14
14
  Available ${e}s: ${a.join(", ")}`)}let i=s.files;e==="component"&&t&&(i=s.files.filter(a=>"framework"in a&&a.framework===t));const c=await Promise.all(i.map(async a=>{const r=`${ye}/${a.path}.json`,u=await ke(r);try{const f=Re.parse(u);return{path:a.path,type:a.type,framework:"framework"in a?a.framework:void 0,content:f.content}}catch{throw new d(`Invalid file content received
15
15
  File: ${v.info(a.path)}`)}}));return{item:s,files:c.filter(Boolean)}}p(Z,"getRegistryFiles");async function _e(e,n,t){const o=[],s=new Set;async function i(c){if(s.has(c))return;s.add(c);const a=e.find(u=>u.name===c);if(!a){const u=e.filter(f=>f.type==="component").map(f=>f.name).join(", ");throw new d(`Component '${c}' not found in registry
16
- Available components: ${u}`)}const r=a.registryDependencies?.[t]||[];for(const u of r)await i(u);o.push(a)}p(i,"resolveComponent");for(const c of n)await i(c);return o}p(_e,"resolveTree");const Je=p(async(e,n,t)=>{const o=await Z({type:"tokens",name:e});if(!o.files[0])throw new d(`Starter kit '${e}' does not contain any token files`);const s=h.resolve(process.cwd(),t),i=`${e}.json`,c=h.join(s,i),a={tokens:{source:[h.relative(process.cwd(),c)],type:"starter-kit"},options:e==="starter-fluid"?{fluid:{min:320,max:1200}}:void 0,output:{directories:{tokens:h.relative(process.cwd(),s),css:n},css:{separate:!1,manageIndex:!0}}};try{const r=re.parse(a),{trees:u,resolved:f}=await G(r,{type:"memory",data:{[c]:{collection:"default",content:o.files[0].content}}});return{config:r,tokens:[],trees:u,resolved:f,tokenContent:o.files[0].content,tokenPath:c,tokensDir:s}}catch(r){throw r instanceof l.ZodError?new d(`Invalid starter kit configuration: ${r.message}`):r}},"initializeFromStarterKit"),qe=p(async e=>{const n=await We(),t=await ue("**/*.json",{cwd:n,absolute:!0});if(t.length===0)throw new d(`No JSON files found in ${n}`);const o=[];for(const m of t)try{const w=await le(m,"utf-8");JSON.parse(w),o.push(m)}catch{k.warn(g.yellow(`Skipping invalid JSON file: ${m}`));continue}if(o.length===0)throw new d(`No valid JSON files found in ${n}
16
+ Available components: ${u}`)}const r=a.registryDependencies?.[t]||[];for(const u of r)await i(u);o.push(a)}p(i,"resolveComponent");for(const c of n)await i(c);return o}p(_e,"resolveTree");const Je=p(async(e,n,t)=>{const o=await Z({type:"tokens",name:e});if(!o.files[0])throw new d(`Starter kit '${e}' does not contain any token files`);const s=h.resolve(process.cwd(),t),i=`${e}.json`,c=h.join(s,i),a={tokens:{source:[h.relative(process.cwd(),c)],type:"starter-kit"},options:e==="starter-fluid"?{fluid:{min:320,max:1200}}:void 0,output:{directories:{tokens:h.relative(process.cwd(),s),css:n},css:{separate:!1,manageIndex:!0}}};try{const r=re.parse(a),{trees:u,resolved:f}=await G(r,{type:"memory",data:{[c]:{collection:"default",content:o.files[0].content}}});return{config:r,tokens:[],trees:u,resolved:f,tokenContent:o.files[0].content,tokenPath:c,tokensDir:s}}catch(r){throw r instanceof l.ZodError?new d(`Invalid starter kit configuration: ${r.message}`):r}},"initializeFromStarterKit"),qe=p(async e=>{const n=await Ue(),t=await ue("**/*.json",{cwd:n,absolute:!0});if(t.length===0)throw new d(`No JSON files found in ${n}`);const o=[];for(const m of t)try{const w=await le(m,"utf-8");JSON.parse(w),o.push(m)}catch{k.warn(g.yellow(`Skipping invalid JSON file: ${m}`));continue}if(o.length===0)throw new d(`No valid JSON files found in ${n}
17
17
  Ensure files contain valid JSON`);const s=o.map(m=>h.relative(process.cwd(),m)),i=h.resolve(process.cwd(),n),c=await fe();let a=await Be();const r=new Map;s.forEach(m=>{const w=h.basename(m),y=r.get(w)||[];r.set(w,[...y,m])});const u=Array.from(r.entries()).filter(([m,w])=>w.length>1).map(([m,w])=>({name:m,files:w}));if(a==="simple"&&u.length>0){const m=u.map(({name:w,files:y})=>{const $=y.map(x=>` - ${x}`).join(`
18
18
  `);return`
19
19
  ${w} appears in:
@@ -24,7 +24,7 @@ ${m}`)),k.message(g.cyan("Switching to collections to help organize these files.
24
24
  ${I} appears in:
25
25
  ${g.dim(xe)}`}).join(`
26
26
  `);k.warn(g.yellow(`Found duplicate filenames in collection "${j}":
27
- ${F}`)),k.message(g.cyan("Please either split these files into different collections or mark some as theme files."));const E=await he(y,$);if(!E){k.message(g.cyan("No files selected, skipping collection creation..."));break}x=E;const T=await ie(x);if(!T){k.message(g.cyan("No collection name provided, skipping collection creation..."));break}j=T;continue}R=!0,w.add(j)}catch(C){if(C instanceof d){k.error(`${C.message}`),k.message(g.cyan("Let's try again..."));continue}throw C}if(!R){k.message(g.cyan("Skipping collection creation..."));break}y=y.filter(C=>!x.includes(C)),y.length>0&&k.message(g.cyan(`Remaining files to organize: ${y.length}`)),$=!1}y.length>0?k.warn(g.yellow(`Warning: ${y.length} files were not assigned to any collection`)):k.message(g.cyan("Token organization complete")),e.tokens=m}const f=s.length>1?await ze():!1;e.output={directories:{tokens:h.relative(process.cwd(),i),css:c},css:{separate:f,manageIndex:!0}},e.options={fluid:{min:320,max:1200}};try{if(typeof e.tokens=="object"&&!Array.isArray(e.tokens)){const $=e.tokens,x=new Set;for(const[j,R]of Object.entries($)){if(x.has(j))throw new d(`Configuration Error: Duplicate collection name "${j}". Collection names must be unique.`);if(x.add(j),R.themes){const C=new Set;for(const N of Object.keys(R.themes)){if(C.has(N))throw new d(`Configuration Error: Duplicate theme name "${N}" in collection "${j}". Theme names must be unique within a collection.`);C.add(N)}}}}const m=re.parse(e),{trees:w,resolved:y}=await G(m);return{config:m,tokens:s,trees:w,resolved:y,tokenPath:n,tokensDir:i,tokenContent:void 0}}catch(m){throw m instanceof l.ZodError?new d(`Invalid configuration: ${m.message}`):m}},"initializeFromExistingTokens");async function Ve(){if(D("sugarcube.config.json")){const e=await W({message:"A sugarcube.config.json already exists in this project",options:[{label:"Overwrite existing config (start from scratch)",value:"overwrite"},{label:"Cancel initialization",value:"cancel"}]});return b(e)&&process.exit(0),{shouldProceed:e==="overwrite"}}return{shouldProceed:!0}}p(Ve,"preflightInit");async function _(){let e;try{e=await X.readFile("sugarcube.config.json","utf-8")}catch{throw new d("Cannot read config file - check file permissions")}let n;try{n=JSON.parse(e)}catch{throw new d("Invalid JSON in config file - check for syntax errors")}const t=re.safeParse(n);if(!t.success){const o=t.error.errors.map(s=>{const i=s.path.join(".");return i?`${i}: ${s.message}`:s.message}).join(`
27
+ ${F}`)),k.message(g.cyan("Please either split these files into different collections or mark some as theme files."));const E=await he(y,$);if(!E){k.message(g.cyan("No files selected, skipping collection creation..."));break}x=E;const T=await ie(x);if(!T){k.message(g.cyan("No collection name provided, skipping collection creation..."));break}j=T;continue}R=!0,w.add(j)}catch(C){if(C instanceof d){k.error(`${C.message}`),k.message(g.cyan("Let's try again..."));continue}throw C}if(!R){k.message(g.cyan("Skipping collection creation..."));break}y=y.filter(C=>!x.includes(C)),y.length>0&&k.message(g.cyan(`Remaining files to organize: ${y.length}`)),$=!1}y.length>0?k.warn(g.yellow(`Warning: ${y.length} files were not assigned to any collection`)):k.message(g.cyan("Token organization complete")),e.tokens=m}const f=s.length>1?await ze():!1;e.output={directories:{tokens:h.relative(process.cwd(),i),css:c},css:{separate:f,manageIndex:!0}},e.options={fluid:{min:320,max:1200}};try{if(typeof e.tokens=="object"&&!Array.isArray(e.tokens)){const $=e.tokens,x=new Set;for(const[j,R]of Object.entries($)){if(x.has(j))throw new d(`Configuration Error: Duplicate collection name "${j}". Collection names must be unique.`);if(x.add(j),R.themes){const C=new Set;for(const N of Object.keys(R.themes)){if(C.has(N))throw new d(`Configuration Error: Duplicate theme name "${N}" in collection "${j}". Theme names must be unique within a collection.`);C.add(N)}}}}const m=re.parse(e),{trees:w,resolved:y}=await G(m);return{config:m,tokens:s,trees:w,resolved:y,tokenPath:n,tokensDir:i,tokenContent:void 0}}catch(m){throw m instanceof l.ZodError?new d(`Invalid configuration: ${m.message}`):m}},"initializeFromExistingTokens");async function Ve(){if(D("sugarcube.config.json")){const e=await U({message:"A sugarcube.config.json already exists in this project",options:[{label:"Overwrite existing config (start from scratch)",value:"overwrite"},{label:"Cancel initialization",value:"cancel"}]});return b(e)&&process.exit(0),{shouldProceed:e==="overwrite"}}return{shouldProceed:!0}}p(Ve,"preflightInit");async function _(){let e;try{e=await X.readFile("sugarcube.config.json","utf-8")}catch{throw new d("Cannot read config file - check file permissions")}let n;try{n=JSON.parse(e)}catch{throw new d("Invalid JSON in config file - check for syntax errors")}const t=re.safeParse(n);if(!t.success){const o=t.error.errors.map(s=>{const i=s.path.join(".");return i?`${i}: ${s.message}`:s.message}).join(`
28
28
  `);throw new d(`Invalid configuration:
29
29
  ${o}
30
30
  See ${v.info("https://docs.sugarcube.sh/configuration")} for help.`)}if(typeof t.data.tokens=="object")for(const[o,s]of Object.entries(t.data.tokens)){if(!s.source?.length)continue;const i=new Map;s.source.forEach(a=>{const r=h.basename(a),u=i.get(r)||[];i.set(r,[...u,a])});const c=Array.from(i.entries()).filter(([a,r])=>r.length>1).map(([a,r])=>({name:a,files:r}));if(c.length>0){const a=c.map(({name:r,files:u})=>{const f=u.map(m=>` - ${m}`).join(`
@@ -38,13 +38,13 @@ To fix this:
38
38
  1. Use unique filenames for source files
39
39
  2. Or move some files to a different collection
40
40
  3. Or mark some files as theme files
41
- See ${v.info("https://docs.sugarcube.sh")} to learn more.`)}}return t.data}p(_,"validateAndLoadConfig");async function ae(e){const n={$schema:"https://sugarcube.style/schema.json",...e};try{const t=JSON.stringify(n,null,2);await A("sugarcube.config.json",t)}catch(t){const o=t instanceof Error?`: ${t.message}`:"";throw new d(`Failed to write config file${o}`)}}p(ae,"writeConfig");function Ke(e){const n=e.split("/"),t=n.findIndex(s=>s==="variables");if(t===-1||t===n.length-1)return"default";const o=n[t+1];return!o||o.endsWith(".css")?"default":o}p(Ke,"getCollectionFromPath");function be(e,n){if(e.includes("/variables/")){const t=Ke(e),o=n.variables.get(t)??[];o.push(e),n.variables.set(t,o)}else e.startsWith("global/")?n.global.push(e):e.startsWith("compositions/")?n.compositions.push(e):e.startsWith("utilities/")&&n.utilities.push(e)}p(be,"groupFile");async function Ye(e,n,t="merge"){const o={variables:new Map,global:[],compositions:[],utilities:[]},s=h.join(n,"index.css");t==="merge"&&D(s)&&(await le(s,"utf-8")).split(`
42
- `).filter(f=>f.trim().startsWith("@import")).map(f=>f.match(/'([^']+)'/)?.[1]).filter(f=>f!==void 0).forEach(f=>be(f,o)),e.filter(r=>r.endsWith(".css")).forEach(r=>{const u=h.relative(n,r).replace(/\\/g,"/");be(u,o)});const i=["reset.css","fonts.css","global-styles.css"];o.global.sort((r,u)=>{const f=i.findIndex(w=>r.endsWith(w)),m=i.findIndex(w=>u.endsWith(w));return f-m});const c=Array.from(o.variables.entries()).sort(([r,u],[f,m])=>r==="default"?-1:f==="default"?1:r.localeCompare(f)).flatMap(([r,u])=>u.sort((f,m)=>f.endsWith("tokens.variables.css")?-1:m.endsWith("tokens.variables.css")?1:f.localeCompare(m))),a=[...new Set([...c,...o.global,...o.compositions.sort(),...o.utilities.sort()])].map(r=>`@import '${r}';`);return await A(s,a.join(`
43
- `)),s}p(Ye,"generateIndexFile");const Ze=p(()=>{B(g.inverse(" Welcome to sugarcube. The toolkit for seriously sweet front ends "))},"welcome");async function He(e,{withFallback:n=!1}={}){const t=await De({programmatic:!0,cwd:e});if(t==="yarn@berry")return"yarn";if(t==="pnpm@6")return"pnpm";if(t==="bun")return"bun";if(!n)return t??"npm";const o=process.env.npm_config_user_agent||"";return o.startsWith("yarn")?"yarn":o.startsWith("pnpm")?"pnpm":o.startsWith("bun")?"bun":"npm"}p(He,"getPackageManager");async function Qe(e,n){const t=await He(n,{withFallback:!0}),o=t==="npm"?["install",...e]:["add",...e];await Ie(t,o,{cwd:n})}p(Qe,"installDependencies");async function ve({registryIndex:e,selectedComponents:n,componentType:t,componentsOutputDirectory:o,cssOutputDirectory:s}){const i=[],c=new Set;await P(o,{recursive:!0});const a=h.join(s,"global","variables");await P(h.join(s,"global"),{recursive:!0}),await P(a,{recursive:!0});const r=await _e(e,n,t);for(const u of r){const f=await Z({type:"component",name:u.name,framework:t});for(const w of f.files)if(w)try{if(w.path.endsWith(".variables.css")){const y=h.join(a,`${u.name}.variables.css`);await A(y,w.content),i.push(y)}else{const y=h.join(o,u.name);await P(y,{recursive:!0});const $=h.join(y,h.basename(w.path));await A($,w.content),i.push($)}}catch(y){const $=y instanceof Error?`: ${y.message}`:"";throw new d(`Failed to write component file for "${u.name}"${$}`)}(u.dependencies?.[t]||[]).forEach(w=>c.add(w))}if(c.size>0)try{await Qe(Array.from(c),process.cwd())}catch(u){const f=u instanceof Error?`: ${u.message}`:"";throw new d(`Failed to install component dependencies${f}`)}return{createdFiles:i,npmDependencies:c}}p(ve,"installComponents");async function Xe(e){const n=[],t=h.resolve(process.cwd(),e);await P(t,{recursive:!0});const s=(await U()).filter(i=>i.type==="cube").map(i=>i.name);for(const i of s){const c=await Z({type:"cube",name:i});for(const a of c.files){if(!a)continue;const r=a.path.replace(/^styles\//,""),u=h.join(t,r),f=h.dirname(u);try{await P(f,{recursive:!0}),await A(u,a.content),n.push(u)}catch(m){const w=m instanceof Error?`: ${m.message}`:"";throw new d(`Failed to write CUBE module "${i}"${w}`)}}}return n}p(Xe,"installCUBE");function et(e){switch(e){case"react":return"tsx";case"astro":return"astro";case"nunjucks":return"njk";default:return"tsx"}}p(et,"getExtension");function Se({components:e,componentType:n,componentsOutputDirectory:t}){return e.filter(o=>{const s=h.join(t,o,`${o}.${et(n)}`);return D(s)})}p(Se,"checkComponentExists");async function H({mode:e,cssOutputDirectory:n,files:t,config:o}){if(!o.output.css.manageIndex)return;const s=t.filter(a=>a.endsWith(".css"));if(s.length===0)return;const i=h.join(n,"index.css"),c=D(i);if(!(e==="create"&&c&&(k.warn(g.yellow(`The following file will be overwritten:
41
+ See ${v.info("https://docs.sugarcube.sh")} to learn more.`)}}return t.data}p(_,"validateAndLoadConfig");async function ae(e){const n={$schema:"https://sugarcube.style/schema.json",...e};try{const t=JSON.stringify(n,null,2);await M("sugarcube.config.json",t)}catch(t){const o=t instanceof Error?`: ${t.message}`:"";throw new d(`Failed to write config file${o}`)}}p(ae,"writeConfig");function Ke(e){const n=e.split("/"),t=n.findIndex(s=>s==="variables");if(t===-1||t===n.length-1)return"default";const o=n[t+1];return!o||o.endsWith(".css")?"default":o}p(Ke,"getCollectionFromPath");function be(e,n){if(e.includes("/variables/")){const t=Ke(e),o=n.variables.get(t)??[];o.push(e),n.variables.set(t,o)}else e.startsWith("global/")?n.global.push(e):e.startsWith("compositions/")?n.compositions.push(e):e.startsWith("utilities/")&&n.utilities.push(e)}p(be,"groupFile");async function Ye(e,n,t="merge"){const o={variables:new Map,global:[],compositions:[],utilities:[]},s=h.join(n,"index.css");t==="merge"&&D(s)&&(await le(s,"utf-8")).split(`
42
+ `).filter(f=>f.trim().startsWith("@import")).map(f=>f.match(/'([^']+)'/)?.[1]).filter(f=>f!==void 0).forEach(f=>be(f,o)),e.filter(r=>r.endsWith(".css")).forEach(r=>{const u=h.relative(n,r).replace(/\\/g,"/");be(u,o)});const i=["reset.css","fonts.css","global-styles.css"];o.global.sort((r,u)=>{const f=i.findIndex(w=>r.endsWith(w)),m=i.findIndex(w=>u.endsWith(w));return f-m});const c=Array.from(o.variables.entries()).sort(([r,u],[f,m])=>r==="default"?-1:f==="default"?1:r.localeCompare(f)).flatMap(([r,u])=>u.sort((f,m)=>f.endsWith("tokens.variables.css")?-1:m.endsWith("tokens.variables.css")?1:f.localeCompare(m))),a=[...new Set([...c,...o.global,...o.compositions.sort(),...o.utilities.sort()])].map(r=>`@import '${r}';`);return await M(s,a.join(`
43
+ `)),s}p(Ye,"generateIndexFile");const Ze=p(()=>{B(g.inverse(" Welcome to sugarcube. The toolkit for seriously sweet front ends "))},"welcome");async function He(e,{withFallback:n=!1}={}){const t=await De({programmatic:!0,cwd:e});if(console.log("packageManager:",t),t?.startsWith("yarn@"))return"yarn";if(t?.startsWith("pnpm@"))return"pnpm";if(t==="bun")return"bun";if(!n)return t?.split("@")[0]??"npm";const o=process.env.npm_config_user_agent||"";return o.startsWith("yarn")?"yarn":o.startsWith("pnpm")?"pnpm":o.startsWith("bun")?"bun":"npm"}p(He,"getPackageManager");async function Qe(e,n){const t=await He(n,{withFallback:!0});await Ie(t,[t==="npm"?"install":"add",...e],{cwd:n})}p(Qe,"installDependencies");async function ve({registryIndex:e,selectedComponents:n,componentType:t,componentsOutputDirectory:o,cssOutputDirectory:s}){const i=[],c=new Set;await P(o,{recursive:!0});const a=h.join(s,"global","variables");await P(h.join(s,"global"),{recursive:!0}),await P(a,{recursive:!0});const r=await _e(e,n,t);for(const u of r){const f=await Z({type:"component",name:u.name,framework:t});for(const w of f.files)if(w)try{if(w.path.endsWith(".variables.css")){const y=h.join(a,`${u.name}.variables.css`);await M(y,w.content),i.push(y)}else{const y=h.join(o,u.name);await P(y,{recursive:!0});const $=h.join(y,h.basename(w.path));await M($,w.content),i.push($)}}catch(y){const $=y instanceof Error?`: ${y.message}`:"";throw new d(`Failed to write component file for "${u.name}"${$}`)}(u.dependencies?.[t]||[]).forEach(w=>c.add(w))}if(c.size>0)try{await Qe(Array.from(c),process.cwd())}catch(u){const f=u instanceof Error?`: ${u.message}`:"";throw new d(`Failed to install component dependencies${f}`)}return{createdFiles:i,npmDependencies:c}}p(ve,"installComponents");async function Xe(e){const n=[],t=h.resolve(process.cwd(),e);await P(t,{recursive:!0});const s=(await W()).filter(i=>i.type==="cube").map(i=>i.name);for(const i of s){const c=await Z({type:"cube",name:i});for(const a of c.files){if(!a)continue;const r=a.path.replace(/^styles\//,""),u=h.join(t,r),f=h.dirname(u);try{await P(f,{recursive:!0}),await M(u,a.content),n.push(u)}catch(m){const w=m instanceof Error?`: ${m.message}`:"";throw new d(`Failed to write CUBE module "${i}"${w}`)}}}return n}p(Xe,"installCUBE");function et(e){switch(e){case"react":return"tsx";case"astro":return"astro";case"nunjucks":return"njk";default:return"tsx"}}p(et,"getExtension");function Se({components:e,componentType:n,componentsOutputDirectory:t}){return e.filter(o=>{const s=h.join(t,o,`${o}.${et(n)}`);return D(s)})}p(Se,"checkComponentExists");async function H({mode:e,cssOutputDirectory:n,files:t,config:o}){if(!o.output.css.manageIndex)return;const s=t.filter(a=>a.endsWith(".css"));if(s.length===0)return;const i=h.join(n,"index.css"),c=D(i);if(!(e==="create"&&c&&(k.warn(g.yellow(`The following file will be overwritten:
44
44
  ${g.dim(" - index.css")}`)),!await K("Continue?",!1))))try{return await Ye(s,n,e)}catch(a){const r=a instanceof Error?`: ${a.message}`:"";throw new d(`Failed to ${e} CSS index file${r}`)}}p(H,"manageCSSIndex");function J(e){if(S.break(),e instanceof d){const n=e.message.split(`
45
45
  `);n.length>1?(S.error(n[0]),S.break(),n.slice(1).forEach(t=>{S.error(` ${t.trim()}`)})):S.error(e.message),process.env.DEBUG&&e.cause&&S.info(`
46
46
  Caused by:`,e.cause)}else S.error(`An unexpected error occurred: ${e instanceof Error?e.message:String(e)}
47
47
  If this issue persists, please report it: ${g.cyanBright("https://github.com/sugarcube-org/sugarcube/issues")}`),process.env.DEBUG&&S.info(`
48
- Error details:`,e);S.break(),process.exit(0)}p(J,"handleError");const tt=new O().name("init").description("Initialize a new project").action(async()=>{try{Ze(),(await Ve()).shouldProceed||process.exit(0),V("Step 1. Set up tokens");const n=await Me();let t;switch(n){case"starter":const r=await Ae(),u=await fe(),f=await Oe();try{t=await Je(r,u,f),t.config=Le(t.config||{},u,f,r)}catch(m){ne(`Failed to initialize starter kit: ${m instanceof Error?m.message:"Unknown error"}`),process.exit(1)}break;case"existing":t=await qe({});break}V("Step 2. Add style system");const o=await Ue();V("Step 3. Add components");const s=await de();let i=[];if(s!=="skip"){const r=await U();r||(ne("Failed to fetch component list"),process.exit(1));const u=await ge(r,s),f=await me(),m=await Se({components:u,componentType:s,componentsOutputDirectory:f});if(m.length>0){const w=m.join(", ");await K(`The following components already exist and will be overwritten: ${w}. Continue?`,!1)}if(u.length>0){const w=te();w.start("Installing components...");try{const{createdFiles:y,npmDependencies:$}=await ve({registryIndex:r,selectedComponents:u,componentType:s,componentsOutputDirectory:f,cssOutputDirectory:t.config.output.directories.css});i=y,w.stop("Components installed successfully")}catch(y){throw w.stop("Installation failed"),y}}}V("Step 4. Generating files");try{if(await se.mkdir(t.tokensDir,{recursive:!0}),await se.mkdir(t.config.output.directories.css,{recursive:!0}),n==="starter"){if(!t.tokenContent)throw new d("Failed to generate token content for starter kit");await se.writeFile(t.tokenPath,t.tokenContent)}}catch(r){const u=r instanceof Error?`: ${r.message}`:"";throw new d(`Failed to create project files${u}`)}let c=[];c=await we(t.trees,t.resolved,t.config);let a=[];o&&(a=await Xe(t.config.output.directories.css)),await H({mode:"create",cssOutputDirectory:t.config.output.directories.css,files:[...c.map(r=>r.name),...i.filter(r=>r.endsWith(".css")),...a],config:t.config}),await ae(t.config),Y({config:"sugarcube.config.json",tokens:n==="starter"?t.tokens:[],generated:[...c.map(r=>r.name),...a,...i,...t.config.output.css.manageIndex?["index.css"]:[]]}),L(g.greenBright("Success! Project initialized \u2728"))}catch(e){J(e)}}),nt=new O().name("generate").description("Generate CSS from your design tokens").option("--force","Skip confirmation when deleting stale files").action(async e=>{try{if(B(g.inverse(" Generate CSS variables from your design tokens ")),!D("sugarcube.config.json"))throw new d("This command requires a sugarcube project. Run 'npx make-sugarcube init' first.");const n=await _(),{trees:t,resolved:o}=await G(n),s=await we(t,o,n);n.output.css.manageIndex&&await H({mode:"merge",cssOutputDirectory:n.output.directories.css,files:s.map(i=>i.name),config:n}),Y({generated:[...s.map(i=>i.name),...n.output.css.manageIndex?["index.css"]:[]]}),L(g.greenBright("Success! CSS variables generated successfully. \u2728"))}catch(n){J(n)}}),st=new O().name("validate").description("Validate design token files").argument("[paths...]","Token files or directories to validate (e.g., tokens.json or ./tokens)").action(async e=>{try{if(B(g.inverse(" Validate design tokens ")),D("sugarcube.config.json")&&!e.length){const s=await _();await G(s),L(g.greenBright("All tokens are valid \u2728"));return}if(!e.length)throw new d("No paths specified. Please provide files/directories to validate, or run this in a Sugarcube project directory.");const n=e.map(s=>h.normalize(s));for(const s of n)if(!D(s))throw new d(`Path not found: ${s}
48
+ Error details:`,e);S.break(),process.exit(0)}p(J,"handleError");const tt=new O().name("init").description("Initialize a new project").action(async()=>{try{Ze(),(await Ve()).shouldProceed||process.exit(0),V("Step 1. Set up tokens");const n=await Ae();let t;switch(n){case"starter":const r=await Me(),u=await fe(),f=await Oe();try{t=await Je(r,u,f),t.config=Le(t.config||{},u,f,r)}catch(m){ne(`Failed to initialize starter kit: ${m instanceof Error?m.message:"Unknown error"}`),process.exit(1)}break;case"existing":t=await qe({});break}V("Step 2. Add style system");const o=await We();V("Step 3. Add components");const s=await de();let i=[];if(s!=="skip"){const r=await W();r||(ne("Failed to fetch component list"),process.exit(1));const u=await ge(r,s),f=await me(),m=await Se({components:u,componentType:s,componentsOutputDirectory:f});if(m.length>0){const w=m.join(", ");await K(`The following components already exist and will be overwritten: ${w}. Continue?`,!1)}if(u.length>0){const w=te();w.start("Installing components...");try{const{createdFiles:y,npmDependencies:$}=await ve({registryIndex:r,selectedComponents:u,componentType:s,componentsOutputDirectory:f,cssOutputDirectory:t.config.output.directories.css});i=y,w.stop("Components installed successfully")}catch(y){throw w.stop("Installation failed"),y}}}V("Step 4. Generating files");try{if(await se.mkdir(t.tokensDir,{recursive:!0}),await se.mkdir(t.config.output.directories.css,{recursive:!0}),n==="starter"){if(!t.tokenContent)throw new d("Failed to generate token content for starter kit");await se.writeFile(t.tokenPath,t.tokenContent)}}catch(r){const u=r instanceof Error?`: ${r.message}`:"";throw new d(`Failed to create project files${u}`)}let c=[];c=await we(t.trees,t.resolved,t.config);let a=[];o&&(a=await Xe(t.config.output.directories.css)),await H({mode:"create",cssOutputDirectory:t.config.output.directories.css,files:[...c.map(r=>r.name),...i.filter(r=>r.endsWith(".css")),...a],config:t.config}),await ae(t.config),Y({config:"sugarcube.config.json",tokens:n==="starter"?t.tokens:[],generated:[...c.map(r=>r.name),...a,...i,...t.config.output.css.manageIndex?["index.css"]:[]]}),L(g.greenBright("Success! Project initialized \u2728"))}catch(e){J(e)}}),nt=new O().name("generate").description("Generate CSS from your design tokens").option("--force","Skip confirmation when deleting stale files").action(async e=>{try{if(B(g.inverse(" Generate CSS variables from your design tokens ")),!D("sugarcube.config.json"))throw new d("This command requires a sugarcube project. Run 'npx make-sugarcube init' first.");const n=await _(),{trees:t,resolved:o}=await G(n),s=await we(t,o,n);n.output.css.manageIndex&&await H({mode:"merge",cssOutputDirectory:n.output.directories.css,files:s.map(i=>i.name),config:n}),Y({generated:[...s.map(i=>i.name),...n.output.css.manageIndex?["index.css"]:[]]}),L(g.greenBright("Success! CSS variables generated successfully. \u2728"))}catch(n){J(n)}}),st=new O().name("validate").description("Validate design token files").argument("[paths...]","Token files or directories to validate (e.g., tokens.json or ./tokens)").action(async e=>{try{if(B(g.inverse(" Validate design tokens ")),D("sugarcube.config.json")&&!e.length){const s=await _();await G(s),L(g.greenBright("All tokens are valid \u2728"));return}if(!e.length)throw new d("No paths specified. Please provide files/directories to validate, or run this in a Sugarcube project directory.");const n=e.map(s=>h.normalize(s));for(const s of n)if(!D(s))throw new d(`Path not found: ${s}
49
49
  Please check that the specified files or directories exist`);const t=await ue(n.map(s=>s.endsWith(".json")?s:h.join(s,"**/*.json")));if(t.length===0)throw new d(`No JSON files found in the specified paths
50
- Please ensure the paths contain .json files`);const o=D("sugarcube.config.json")?await _():{output:{directories:{tokens:".",css:"."},css:{separate:!1}}};await G({...o,tokens:{type:"custom",source:t.map(s=>h.relative(process.cwd(),s))}}),L(g.greenBright("All tokens are valid \u2728"))}catch(n){J(n)}}),ot=new O().name("components").description("Add components to your project").argument("[components...]","Components to add (e.g., button card)").option("-f, --framework <type>","Framework to use (react, astro, nunjucks)").option("-s, --silent","Suppress logs and prompts").action(async(e,n)=>{try{if(n.silent||B(g.inverse(" Add components ")),!D("sugarcube.config.json"))throw new d("This command requires a sugarcube project. Run 'npx make-sugarcube init' first.");let t=await _(),o,s=[],i;if(e.length>0){if(!n.framework)throw new d("Framework must be specified in non-interactive mode (--framework)");const r=["react","astro","nunjucks"];if(!r.includes(n.framework))throw new d(`Invalid framework. Must be one of: ${r.join(", ")}`);if(i=n.framework,s=e,!t.output.directories.components)throw new d("Components directory must be configured in non-interactive mode. Please run without arguments first.");o=h.resolve(process.cwd(),t.output.directories.components)}else{i=await de(!1);const r=await U();if(r||(ne("Failed to fetch component list"),process.exit(1)),s=await ge(r,i),t.output.directories.components)o=h.resolve(process.cwd(),t.output.directories.components);else{const u=await me();o=h.resolve(process.cwd(),u),t.output.directories.components=h.relative(process.cwd(),o),await ae(t)}}const c=await Se({components:s,componentType:i,componentsOutputDirectory:o});if(c.length>0&&!n.silent){const r=c.join(", ");await K(`The following components already exist and will be overwritten: ${r}. Continue?`,!1)}let a;n.silent||(a=te(),a.start("Installing components..."));try{const r=await U(),{createdFiles:u,npmDependencies:f}=await ve({registryIndex:r,selectedComponents:s,componentType:i,componentsOutputDirectory:o,cssOutputDirectory:t.output.directories.css});await H({mode:"merge",cssOutputDirectory:t.output.directories.css,files:u,config:t}),n.silent||(a?.stop("Components installed successfully"),Y({generated:u}),L(g.greenBright("Success! Components installed \u2728")))}catch(r){throw n.silent||a?.stop("Installation failed"),r}}catch(t){J(t)}}),rt=new O().name("cube").description("Add CUBE CSS to your project").option("-s, --silent","Suppress logs and prompts").action(async e=>{const n=[];try{if(!D("sugarcube.config.json"))throw new d("This command requires a sugarcube project. Run 'npx make-sugarcube init' first.");e.silent||B(g.inverse(" Add CUBE CSS "));const t=await _(),o=h.resolve(process.cwd(),t.output.directories.css);try{await P(o,{recursive:!0})}catch(c){const a=c instanceof Error?`: ${c.message}`:"";throw new d(`Failed to create output directory${a}`)}const i=(await U()).filter(c=>c.type==="cube").map(c=>c.name);for(const c of i){const a=await Z({type:"cube",name:c});for(const r of a.files){if(!r)continue;const u=r.path.replace(/^styles\//,""),f=h.join(o,u),m=h.dirname(f);try{await P(m,{recursive:!0}),await A(f,r.content),n.push(f)}catch(w){const y=w instanceof Error?`: ${w.message}`:"";throw new d(`Failed to write CUBE CSS file ${f}${y}`)}}}await H({mode:"merge",cssOutputDirectory:o,files:n,config:t}),await ae(t),!e.silent&&n.length>0&&(Y({generated:n}),L(g.greenBright("Success! CUBE CSS added successfully. \u2728")))}catch(t){J(t)}});var it="@sugarcube-org/cli",at="0.0.0-alpha.2",ct={access:"restricted"},lt="A CLI for scaffolding sugarcube applications",ut="UNLICENSED",pt="Mark Tomlinson",ft={type:"git",url:"https://github.com/sugarcube-org/sugarcube"},mt={url:"https://github.com/sugarcube-org/sugarcube/issues"},dt=["cli","design-system","components","CUBE CSS","react","sugarcube"],gt=["dist","README.md","LICENSE.md"],ht="module",wt={sugarcube:"./dist/index.mjs"},yt={build:"pkgroll --minify",dev:"cross-env REGISTRY_URL=http://localhost:8787/registry tsx src/index.ts",test:"vitest","type-check":"tsc --noEmit",start:"cross-env REGISTRY_URL=https://sugarcube-registry.mark-tomlinson3.workers.dev/registry tsx src/index.ts",prepublishOnly:"pnpm up @sugarcube-org/core --filter @sugarcube-org/cli && pnpm build"},kt={"@antfu/ni":"^23.3.0","@clack/prompts":"^0.9.1","@sugarcube-org/core":"workspace:*",commander:"^12.1.0","cross-env":"^7.0.3",execa:"^9.5.2","fast-glob":"^3.3.2","fs-extra":"^11.2.0","lucide-react":"^0.468.0","node-fetch":"^3.3.0",picocolors:"^1.1.1",prompts:"^2.4.2",zod:"^3.23.8"},bt={"@types/fs-extra":"^11.0.4","@types/prompts":"^2.4.9",pkgroll:"^2.5.1",tsx:"^4.19.2"},vt={name:it,version:at,publishConfig:ct,description:lt,license:ut,author:pt,repository:ft,bugs:mt,keywords:dt,files:gt,type:ht,bin:wt,scripts:yt,dependencies:kt,devDependencies:bt};process.on("SIGINT",()=>process.exit(0)),process.on("SIGTERM",()=>process.exit(0));async function St(){const e=new O().name("sugarcube").description("CLI for scaffolding sugarcube applications").version(vt.version,"-v, --version","display the version number");e.addCommand(tt).addCommand(nt).addCommand(st).addCommand(ot).addCommand(rt),e.parse()}p(St,"main"),St();
50
+ Please ensure the paths contain .json files`);const o=D("sugarcube.config.json")?await _():{output:{directories:{tokens:".",css:"."},css:{separate:!1}}};await G({...o,tokens:{type:"custom",source:t.map(s=>h.relative(process.cwd(),s))}}),L(g.greenBright("All tokens are valid \u2728"))}catch(n){J(n)}}),ot=new O().name("components").description("Add components to your project").argument("[components...]","Components to add (e.g., button card)").option("-f, --framework <type>","Framework to use (react, astro, nunjucks)").option("-s, --silent","Suppress logs and prompts").action(async(e,n)=>{try{if(n.silent||B(g.inverse(" Add components ")),!D("sugarcube.config.json"))throw new d("This command requires a sugarcube project. Run 'npx make-sugarcube init' first.");let t=await _(),o,s=[],i;if(e.length>0){if(!n.framework)throw new d("Framework must be specified in non-interactive mode (--framework)");const r=["react","astro","nunjucks"];if(!r.includes(n.framework))throw new d(`Invalid framework. Must be one of: ${r.join(", ")}`);if(i=n.framework,s=e,!t.output.directories.components)throw new d("Components directory must be configured in non-interactive mode. Please run without arguments first.");o=h.resolve(process.cwd(),t.output.directories.components)}else{i=await de(!1);const r=await W();if(r||(ne("Failed to fetch component list"),process.exit(1)),s=await ge(r,i),t.output.directories.components)o=h.resolve(process.cwd(),t.output.directories.components);else{const u=await me();o=h.resolve(process.cwd(),u),t.output.directories.components=h.relative(process.cwd(),o),await ae(t)}}const c=await Se({components:s,componentType:i,componentsOutputDirectory:o});if(c.length>0&&!n.silent){const r=c.join(", ");await K(`The following components already exist and will be overwritten: ${r}. Continue?`,!1)}let a;n.silent||(a=te(),a.start("Installing components..."));try{const r=await W(),{createdFiles:u,npmDependencies:f}=await ve({registryIndex:r,selectedComponents:s,componentType:i,componentsOutputDirectory:o,cssOutputDirectory:t.output.directories.css});await H({mode:"merge",cssOutputDirectory:t.output.directories.css,files:u,config:t}),n.silent||(a?.stop("Components installed successfully"),Y({generated:u}),L(g.greenBright("Success! Components installed \u2728")))}catch(r){throw n.silent||a?.stop("Installation failed"),r}}catch(t){J(t)}}),rt=new O().name("cube").description("Add CUBE CSS to your project").option("-s, --silent","Suppress logs and prompts").action(async e=>{const n=[];try{if(!D("sugarcube.config.json"))throw new d("This command requires a sugarcube project. Run 'npx make-sugarcube init' first.");e.silent||B(g.inverse(" Add CUBE CSS "));const t=await _(),o=h.resolve(process.cwd(),t.output.directories.css);try{await P(o,{recursive:!0})}catch(c){const a=c instanceof Error?`: ${c.message}`:"";throw new d(`Failed to create output directory${a}`)}const i=(await W()).filter(c=>c.type==="cube").map(c=>c.name);for(const c of i){const a=await Z({type:"cube",name:c});for(const r of a.files){if(!r)continue;const u=r.path.replace(/^styles\//,""),f=h.join(o,u),m=h.dirname(f);try{await P(m,{recursive:!0}),await M(f,r.content),n.push(f)}catch(w){const y=w instanceof Error?`: ${w.message}`:"";throw new d(`Failed to write CUBE CSS file ${f}${y}`)}}}await H({mode:"merge",cssOutputDirectory:o,files:n,config:t}),await ae(t),!e.silent&&n.length>0&&(Y({generated:n}),L(g.greenBright("Success! CUBE CSS added successfully. \u2728")))}catch(t){J(t)}});var it="@sugarcube-org/cli",at="0.0.0-alpha.4",ct={access:"restricted"},lt="A CLI for scaffolding sugarcube applications",ut="UNLICENSED",pt="Mark Tomlinson",ft={type:"git",url:"https://github.com/sugarcube-org/sugarcube"},mt={url:"https://github.com/sugarcube-org/sugarcube/issues"},dt=["cli","design-system","components","CUBE CSS","react","sugarcube"],gt=["dist","README.md","LICENSE.md"],ht="module",wt={sugarcube:"./dist/index.mjs"},yt={build:"pkgroll --minify",dev:"cross-env REGISTRY_URL=http://localhost:8787/registry tsx src/index.ts",test:"vitest","type-check":"tsc --noEmit",start:"cross-env REGISTRY_URL=https://sugarcube-registry.mark-tomlinson3.workers.dev/registry tsx src/index.ts",prepublishOnly:"pnpm up @sugarcube-org/core --filter @sugarcube-org/cli && pnpm build"},kt={"@antfu/ni":"^23.3.0","@clack/prompts":"^0.9.1","@sugarcube-org/core":"workspace:*",commander:"^12.1.0","cross-env":"^7.0.3",execa:"^9.5.2","fast-glob":"^3.3.2","fs-extra":"^11.2.0","lucide-react":"^0.468.0","node-fetch":"^3.3.0",picocolors:"^1.1.1",prompts:"^2.4.2",zod:"^3.23.8"},bt={"@types/fs-extra":"^11.0.4","@types/prompts":"^2.4.9",pkgroll:"^2.5.1",tsx:"^4.19.2"},vt={name:it,version:at,publishConfig:ct,description:lt,license:ut,author:pt,repository:ft,bugs:mt,keywords:dt,files:gt,type:ht,bin:wt,scripts:yt,dependencies:kt,devDependencies:bt};process.on("SIGINT",()=>process.exit(0)),process.on("SIGTERM",()=>process.exit(0));async function St(){const e=new O().name("sugarcube").description("CLI for scaffolding sugarcube applications").version(vt.version,"-v, --version","display the version number");e.addCommand(tt).addCommand(nt).addCommand(st).addCommand(ot).addCommand(rt),e.parse()}p(St,"main"),St();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sugarcube-org/cli",
3
- "version": "0.0.0-alpha.2",
3
+ "version": "0.0.0-alpha.4",
4
4
  "publishConfig": {
5
5
  "access": "restricted"
6
6
  },