@sugarcube-org/cli 0.0.0-alpha.7 → 0.0.0-alpha.9

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