@sugarcube-org/cli 0.0.0-alpha.15 → 0.0.0-alpha.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +9 -0
- package/README.md +48 -5
- package/dist/index.mjs +41 -49
- package/package.json +5 -4
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Proprietary Software
|
|
2
|
+
|
|
3
|
+
This software is proprietary and confidential. All rights reserved.
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2025 Mark Tomlinson
|
|
6
|
+
|
|
7
|
+
This software is provided "as is" without warranty of any kind, either express or implied.
|
|
8
|
+
|
|
9
|
+
Unauthorized copying, distribution, or use of this software is strictly prohibited.
|
package/README.md
CHANGED
|
@@ -1,9 +1,52 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @sugarcube-org/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
CLI for scaffolding sugarcube projects and managing design tokens.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## What it does
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- Initializes new sugarcube projects with design tokens and CSS architecture
|
|
8
|
+
- Generates CSS variables and utility classes from design tokens
|
|
9
|
+
- Validates design token files for W3C compliance
|
|
10
|
+
- Installs copy-to-use components for multiple frameworks
|
|
11
|
+
- Adds CUBE CSS architecture to projects
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g @sugarcube-org/cli
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Initialize a new project
|
|
23
|
+
make-sugarcube init
|
|
24
|
+
|
|
25
|
+
# Generate CSS from tokens
|
|
26
|
+
make-sugarcube generate
|
|
27
|
+
|
|
28
|
+
# Validate token files
|
|
29
|
+
make-sugarcube validate
|
|
30
|
+
|
|
31
|
+
# Add components
|
|
32
|
+
make-sugarcube components
|
|
33
|
+
|
|
34
|
+
# Add CUBE CSS
|
|
35
|
+
make-sugarcube cube
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Commands
|
|
39
|
+
|
|
40
|
+
- `init` - Set up a new sugarcube project
|
|
41
|
+
- `generate` - Generate CSS variables and utilities
|
|
42
|
+
- `validate` - Validate design token files
|
|
43
|
+
- `components` - Install copy-to-use components
|
|
44
|
+
- `cube` - Add CUBE CSS architecture
|
|
45
|
+
|
|
46
|
+
## Development
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pnpm install
|
|
50
|
+
pnpm build
|
|
51
|
+
pnpm dev
|
|
52
|
+
```
|
package/dist/index.mjs
CHANGED
|
@@ -1,58 +1,50 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
URL: ${
|
|
4
|
-
URL: ${
|
|
5
|
-
URL: ${
|
|
6
|
-
URL: ${
|
|
7
|
-
URL: ${
|
|
8
|
-
Check your internet connection`)}}
|
|
9
|
-
URL: ${
|
|
10
|
-
Available ${e}s: ${c.join(", ")}`)}let
|
|
11
|
-
File: ${
|
|
12
|
-
Available components: ${
|
|
2
|
+
var Te=Object.defineProperty;var a=(e,t)=>Te(e,"name",{value:t,configurable:!0});import{Command as j}from"commander";import{existsSync as k,readFileSync as re}from"node:fs";import{relative as E,join as h,basename as U,resolve as F,dirname as Ie,normalize as Fe}from"pathe";import{select as $e,isCancel as M,log as v,multiselect as Re,text as xe,confirm as Pe,spinner as K,intro as ie,cancel as je,outro as _}from"@clack/prompts";import{GLOBAL_DIR as _e,VARIABLES_FILE_SUFFIX as Ne,TOKENS_FILE_SUFFIX as ae,tokenProcessingPipeline as Ae,SUGARCUBE_CONFIG_FILE as b,loadConfig as L,DEFAULT_STYLES_PATH as V,DEFAULT_DESIGN_TOKENS_PATH as Oe,generateCSSVariables as H,writeCSSVariablesToDisk as q,generateIndex as B,generateCSSUtilityClasses as ce,writeCSSUtilitiesToDisk as le,SUGARCUBE_FILE as Ue,validateConfig as Le,DEFAULT_CONFIG as ue,normalizeConfig as Ge}from"@sugarcube-org/core";import w from"picocolors";import We from"node-fetch";import{z as d}from"zod";import J,{mkdir as $,writeFile as N}from"node:fs/promises";import{execa as Me}from"execa";import{detect as Be}from"@antfu/ni";import I,{resolve as Je}from"node:path";import Q from"fast-glob";var ze="0.0.0-alpha.16",Ke={version:ze};class m extends Error{static{a(this,"CLIError")}constructor(t,n){super(t),this.name="CLIError",this.cause=n}}class z extends m{static{a(this,"ValidationError")}constructor(t,n,o,s){super(t),this.field=n,this.value=o,this.suggestion=s,this.name="ValidationError"}}class X extends m{static{a(this,"FileOperationError")}constructor(t,n,o,s){super(t),this.filePath=n,this.operation=o,this.cause=s,this.name="FileOperationError"}}const Y=d.enum(["react","astro-native","astro-enhanced","web-components"]),pe=d.object({path:d.string(),type:d.string()}),Ve=pe.extend({framework:Y});d.object({themes:d.record(d.string(),d.array(d.string())).optional()}).strict();const He=d.object({name:d.string(),type:d.string(),description:d.string().optional(),frameworks:d.array(d.string()).optional(),files:d.array(d.union([Ve,pe])),tokens:d.record(d.object({type:d.string(),mapping:d.string()})).optional(),dependencies:d.record(Y,d.array(d.string())).optional(),registryDependencies:d.record(Y,d.array(d.string())).optional(),tokenDependencies:d.array(d.string()).optional()}),qe=d.array(He),Qe=d.object({content:d.string()}),C={error:w.red,warn:w.yellow,info:w.cyan,success:w.green,bold:w.bold,path:w.cyan},fe=process.env.REGISTRY_URL??"https://sugarcube.sh/r";async function me(e){try{const t=await We(e);if(!t.ok){if(t.status===401)throw new m(`Registry access denied: Authentication required
|
|
3
|
+
URL: ${C.info(e)}`);if(t.status===403)throw new m(`Registry access denied: Invalid or missing token
|
|
4
|
+
URL: ${C.info(e)}`);if(t.status===404)throw new m(`Registry resource not found
|
|
5
|
+
URL: ${C.info(e)}`);const n=await t.json().catch(()=>null),o=n&&typeof n=="object"&&"error"in n?n.error:t.statusText;throw new m(`Registry request failed: ${o}
|
|
6
|
+
URL: ${C.info(e)}`)}return t.json()}catch(t){throw t instanceof m?t:new m(`Failed to connect to registry
|
|
7
|
+
URL: ${C.info(e)}
|
|
8
|
+
Check your internet connection`)}}a(me,"fetchRegistry");async function A(){const e=`${fe}/index.json`,t=await me(e);try{return qe.parse(t)}catch{throw new m(`Invalid registry data received
|
|
9
|
+
URL: ${C.info(e)}`)}}a(A,"getRegistryIndex");async function Z({type:e,name:t,framework:n}){const o=await A(),s=o.find(c=>c.type===e&&c.name===t);if(!s){const c=o.filter(i=>i.type===e).map(i=>i.name);throw new m(`${e} '${C.info(t)}' not found in registry
|
|
10
|
+
Available ${e}s: ${c.join(", ")}`)}let r=s.files;e==="component"&&n&&(r=s.files.filter(c=>"framework"in c&&c.framework===n));const l=await Promise.all(r.map(async c=>{const i=`${fe}/${c.path}.json`,p=await me(i);try{const g=Qe.parse(p);return{path:c.path,type:c.type,framework:"framework"in c?c.framework:void 0,content:g.content}}catch{throw new m(`Invalid file content received
|
|
11
|
+
File: ${C.info(c.path)}`)}}));return{item:s,files:l}}a(Z,"getRegistryFiles");async function de(e,t,n){const o=[],s=new Set;async function r(l){if(s.has(l))return;s.add(l);const c=e.find(p=>p.name===l);if(!c){const p=e.filter(g=>g.type==="component").map(g=>g.name).join(", ");throw new m(`Component '${l}' not found in registry
|
|
12
|
+
Available components: ${p}`)}const i=c.registryDependencies?.[n]||[];for(const p of i)await r(p);o.push(c)}a(r,"resolveComponent");for(const l of t)await r(l);return o}a(de,"resolveTree");async function Xe({cssOutputDirectory:e,selectedComponents:t,componentType:n,componentsOutputDirectory:o,tokensOutputDirectory:s}){const r={variableCSS:[],utilityCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]},l=await A(),i=(await de(l,t,n)).map(f=>f.name),p=l.filter(f=>f.type==="component").filter(f=>i.includes(f.name)),g=p.flatMap(f=>f.files.filter(u=>(u.type==="tsx"||u.type==="astro"||u.type==="njk")&&"framework"in u&&u.framework===n).map(u=>E(process.cwd(),h(o,f.name,`${f.name}.${u.type}`))));r.componentFiles=g.filter(f=>k(h(process.cwd(),f)));const y=p.flatMap(f=>{const u=f.name;return[E(process.cwd(),h(o,f.name,`${u}.css`)),E(process.cwd(),h(e,_e,`${u}${Ne}`))]});r.componentCSS=y.filter(f=>k(h(process.cwd(),f)));const S=p.flatMap(f=>{const u=f.name;return[E(process.cwd(),h(s,`${u}${ae}`)),E(process.cwd(),h(s,"components",`${u}${ae}`))]});return r.componentCSS.push(...S.filter(f=>k(h(process.cwd(),f)))),r}a(Xe,"collectComponentOverwriteWarnings");async function ge({cubeDirectory:e}){const t={variableCSS:[],utilityCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]},n=await A();if(!n)throw new m("Failed to fetch registry index");const o=n.filter(s=>s.type==="cube").flatMap(s=>s.files).map(s=>{const r=s.path.replace(/^styles\//,"");return E(process.cwd(),h(e,r))});return t.cubeCSS=o.filter(s=>k(h(process.cwd(),s))),t}a(ge,"collectCubeOverwriteWarnings");const ee={PROJECT_REQUIRED:`This command requires you to initialize a sugarcube project. Run ${w.cyan("make-sugarcube init")} first.
|
|
13
13
|
|
|
14
|
-
For more information, visit: ${
|
|
15
|
-
${e.
|
|
16
|
-
`)}`),e.
|
|
17
|
-
${e.
|
|
18
|
-
`)}`),e.
|
|
19
|
-
${
|
|
20
|
-
`)}`)
|
|
21
|
-
${
|
|
22
|
-
`)}`)
|
|
14
|
+
For more information, visit: ${w.cyan("https://sugarcube.sh/docs/initialize")}`};function te(e){const t=[];if(e.variableCSS.length>0&&t.push(`CSS variables files:
|
|
15
|
+
${e.variableCSS.map(n=>` - ${n}`).join(`
|
|
16
|
+
`)}`),e.utilityCSS.length>0&&t.push(`CSS utility files:
|
|
17
|
+
${e.utilityCSS.map(n=>` - ${n}`).join(`
|
|
18
|
+
`)}`),e.cubeCSS.length>0&&t.push(`CUBE CSS files:
|
|
19
|
+
${e.cubeCSS.map(n=>` - ${n}`).join(`
|
|
20
|
+
`)}`),e.componentFiles.length>0||e.componentCSS.length>0){const n=[...e.componentFiles,...e.componentCSS];t.push(`Component files:
|
|
21
|
+
${n.map(o=>` - ${o}`).join(`
|
|
22
|
+
`)}`)}if(e.indexFiles.length>0&&t.push(`Index files:
|
|
23
|
+
${e.indexFiles.map(n=>` - ${n}`).join(`
|
|
24
|
+
`)}`),t.length!==0)return w.yellow(`WARNING: The following file(s) already exist and will be OVERWRITTEN:
|
|
23
25
|
|
|
24
|
-
${
|
|
26
|
+
${w.dim(t.join(`
|
|
25
27
|
|
|
26
|
-
`))}`)}
|
|
27
|
-
`);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
`))}`)}a(te,"formatOverwriteWarnings");function Ye(e){return typeof e.tokens=="object"&&!("source"in e.tokens)}a(Ye,"hasCollections$1");async function Ze(e){if(Ye(e)){const t=e.tokens;return"components"in t?!1:(t.components={source:["components/*.tokens.json"]},!0)}return!1}a(Ze,"handleComponentTokenIntegration");const D={error(...e){console.log(C.error(e.join(" ")))},warn(...e){console.log(C.warn(e.join(" ")))},info(...e){console.log(C.info(e.join(" ")))},success(...e){console.log(C.success(e.join(" ")))},log(...e){console.log(e.join(" "))},break(){console.log("")}};function et(...e){process.env.DEBUG==="true"&&process.stderr.write(`[sugarcube:debug] ${e.map(String).join(" ")}
|
|
29
|
+
`)}a(et,"debugLog");function G(e){if(D.break(),e instanceof m){const t=e.message.split(`
|
|
30
|
+
`);if(t.length>1){D.error(t[0]),D.break();for(const n of t.slice(1))D.error(` ${n.trim()}`)}else D.error(e.message);process.env.DEBUG&&e.cause&&D.info(`
|
|
31
|
+
Caused by:`,e.cause)}else D.error(`An unexpected error occurred: ${e instanceof Error?e.message:String(e)}
|
|
32
|
+
If this issue persists, please report it: ${w.cyanBright("https://github.com/sugarcube-org/sugarcube/issues")}`),process.env.DEBUG&&D.info(`
|
|
33
|
+
Error details:`,e);D.break(),process.exit(0)}a(G,"handleError");async function tt(e,{withFallback:t=!1}={}){const n=await Be({programmatic:!0,cwd:e});if(n?.startsWith("yarn@"))return"yarn";if(n?.startsWith("pnpm@"))return"pnpm";if(n==="bun")return"bun";if(!t)return n?.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"}a(tt,"getPackageManager");async function we(e,t){const n=await tt(t,{withFallback:!0}),o=n==="npm"?"install":"add";try{await Me(n,[o,...e],{cwd:t})}catch{const r=`Failed to install dependencies using ${n}.
|
|
31
34
|
|
|
32
35
|
This might be because you're using 'npx' with a pnpm project. Try:
|
|
33
|
-
pnpm dlx
|
|
36
|
+
pnpm dlx make-sugarcube components
|
|
34
37
|
|
|
35
38
|
Or use the appropriate package runner for your project:
|
|
36
|
-
npm: npx
|
|
37
|
-
pnpm: pnpm dlx
|
|
38
|
-
yarn: yarn dlx
|
|
39
|
-
bun: bunx
|
|
39
|
+
npm: npx make-sugarcube components
|
|
40
|
+
pnpm: pnpm dlx make-sugarcube components
|
|
41
|
+
yarn: yarn dlx make-sugarcube components
|
|
42
|
+
bun: bunx make-sugarcube components`;throw new Error(r)}}a(we,"installDependencies");function nt(e){const t=h(e,"blocks");return k(t)}a(nt,"hasBlocksDirectory");function st(e){return typeof e.tokens=="object"&&!("source"in e.tokens)}a(st,"hasCollections");async function ot(e,t,n){const{hasCollectionsMode:o,useBlocksDir:s,componentsOutputDirectory:r,cssOutputDirectory:l,tokensOutputDirectory:c}=n;if(e.path.endsWith(".tokens.json")){const g=o?h(c,"components",`${t.name}.tokens.json`):h(c,`${t.name}.tokens.json`);return await N(g,e.content),g}if(e.path.endsWith(".css")){if(s){const S=h(l,"blocks",`${t.name}.css`);return await N(S,e.content),S}const g=h(r,t.name);await $(g,{recursive:!0});const y=h(g,`${t.name}.css`);return await N(y,e.content),y}const i=h(r,t.name);await $(i,{recursive:!0});const p=h(i,U(e.path));return await N(p,e.content),p}a(ot,"writeComponentFile");async function rt({registryIndex:e,selectedComponents:t,componentType:n,componentsOutputDirectory:o,cssOutputDirectory:s,tokensOutputDirectory:r,config:l,overwrite:c}){const i=[],p=new Set,g=nt(s),y=st(l);if(await $(o,{recursive:!0}),await $(r,{recursive:!0}),y){const f=h(r,"components");await $(f,{recursive:!0})}const S=await de(e,t,n);for(const f of S){const u=await Z({type:"component",name:f.name,framework:n});for(const x of u.files)if(x)try{const P=await ot(x,f,{hasCollectionsMode:y,useBlocksDir:g,componentsOutputDirectory:o,cssOutputDirectory:s,tokensOutputDirectory:r});i.push(P)}catch(P){const be=P instanceof Error?`: ${P.message}`:"";throw new m(`Failed to write component file for "${f.name}"${be}`)}const W=f.dependencies?.[n]||[];for(const x of W)p.add(x)}if(p.size>0)try{await we(Array.from(p),process.cwd())}catch(f){const u=f instanceof Error?`: ${f.message}`:"";throw new m(`Failed to install component dependencies${u}`)}return{createdFiles:i,npmDependencies:p}}a(rt,"installComponents");async function it(e="src/ui/components"){const t=await xe({message:"Save components to",placeholder:e,validate:a(n=>{if(n.trim().replace(/['"]/g,"").length===0)return"Output directory cannot be empty"},"validate")});return M(t)&&process.exit(0),I.relative(process.cwd(),I.resolve(process.cwd(),t))}a(it,"promptComponentDirectory");async function he(e=!0){const t=[{label:"React",value:"react",hint:".tsx"},{label:"Astro (Native)",value:"astro-native",hint:"Minimal, standards-based .astro; uses native HTML features"},{label:"Astro (Enhanced)",value:"astro-enhanced",hint:"Advanced features, richer client-side logic - coming soon"},{label:"Web Components",value:"web-components",hint:"Native web components using TypeScript - coming soon"}];e&&t.push({label:"Skip",value:"skip",hint:"continue without components"});const n=await $e({message:"Build with",options:t});return M(n)&&process.exit(0),n==="astro-enhanced"||n==="web-components"?(v.info(w.blue("Sorry, this framework is coming soon! Please choose 'Astro (Native)' or 'React' for now.")),he(e)):n}a(he,"promptComponentFramework");async function at(e,t){const n=e.filter(s=>s.type==="component"&&s.frameworks?.includes(t)),o=await Re({message:"Select components to add",options:n.map(s=>({label:s.name,value:s.name,hint:s.description})),required:!0});return M(o)&&process.exit(0),o}a(at,"promptComponentSelectionFiltered");async function ne(e,t=!1){const n=await Pe({message:e,initialValue:t});return(!n||M(n))&&process.exit(0),!0}a(ne,"confirmOverwrite");function se(e){const t=e.generated,o=[...new Set(t)].map(r=>I.relative(process.cwd(),r)),s=K();s.start(`Writing ${o.length} files:`),s.stop(`Wrote ${o.length} files:`);for(const r of o)D.log(` - ${r}`);D.break()}a(se,"showSummary");async function O(e,t){const n=t?{type:"memory",data:t,config:e}:{type:"files",config:e},{trees:o,resolved:s,errors:r}=await Ae(n);if(r.load.length>0)throw new m(`Failed to load token files:
|
|
43
|
+
${r.load.map(l=>`${l.file}: ${l.message}`).join(`
|
|
44
|
+
`)}`);if(r.validation.length>0||r.flatten.length>0||r.resolution.length>0){D.break();const l=[...r.flatten,...r.validation,...r.resolution],c=new Map;for(const i of l)if(i.source?.sourcePath){const p=c.get(i.source.sourcePath)||[];p.push(i.message),c.set(i.source.sourcePath,p)}for(const[i,p]of c){D.error(`Error(s) in ${C.path(i)}:`);for(const g of p)D.error(` - ${g}`);D.break()}throw new m(`Token validation failed. See ${C.info("https://sugarcube.sh/docs/design-tokens")} for valid token formats`)}return{trees:o,resolved:s}}a(O,"processTokensForCLI");async function ye(e){const t={$schema:"https://sugarcube.sh/r/schema.json",...e};try{const n=JSON.stringify(t,null,2);await N(b,n)}catch(n){const o=n instanceof Error?`: ${n.message}`:"";throw new m(`Failed to write config file${o}`)}}a(ye,"writeConfig");async function ct(e,t,n,o,s,r,l){const c=await A(),{createdFiles:i}=await rt({registryIndex:c,selectedComponents:e,componentType:t,componentsOutputDirectory:n,cssOutputDirectory:o,tokensOutputDirectory:s,config:r,overwrite:l});return i}a(ct,"installComponentFiles");const lt=new j().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-native)").option("-s, --silent","Suppress logs and prompts").option("-o, --overwrite","Overwrite existing files").action(async(e,t)=>{try{if(t.silent||ie(w.inverse(" Add components ")),!k(b))throw new m(ee.PROJECT_REQUIRED);const{config:n}=await L();let o,s=[],r;if(e.length>0||t.framework){if(!t.framework)throw new m(`Framework is required when specifying components. Use --framework to specify a framework (react, astro-native) or run without arguments for interactive mode.
|
|
40
45
|
|
|
41
|
-
See ${
|
|
42
|
-
${
|
|
43
|
-
`)}
|
|
44
|
-
|
|
45
|
-
`);
|
|
46
|
-
${d} appears in:
|
|
47
|
-
${f.dim(F)}`}).join(`
|
|
48
|
-
`);b.warn(f.yellow(`Simple organization cannot have duplicate filenames:
|
|
49
|
-
${l}`)),b.message(f.cyan("Switching to collections to help organize these files...")),c="collections"}if(c==="simple"){const l={type:"custom",source:s},d=await nt(s);if(d&&d.length>0){const h=d.flatMap(F=>F.files);l.source=s.filter(F=>!h.includes(F)),l.themes=d.reduce((F,v)=>Object.assign(F,{[v.name]:v.files}),{})}e.tokens=l}else{const l={},d=new Set;let h=[...s],F=!0;for(;h.length>0;){let v=await $e(h,F);if(!v){b.message(f.cyan("No files selected, skipping collection creation..."));break}let T=await pe(v);if(!T){b.message(f.cyan("No collection name provided, skipping collection creation..."));break}let B=!1;for(;!B;)try{if(d.has(T)){b.warn(f.yellow(`Collection name "${T}" is already in use.`));const R=await pe(v);if(!R){b.message(f.cyan("No collection name provided, skipping collection creation..."));break}T=R;continue}const I={type:"custom",source:v};l[T]=I;const N=await tt(v);if(N&&N.length>0){const R=N.flatMap(D=>D.files),P=new Set;let M=!1;for(const D of N){if(P.has(D.name)){b.warn(f.yellow(`Theme name "${D.name}" is already used in this collection.`)),b.message(f.cyan("Starting theme selection over to avoid conflicts...")),M=!0;break}P.add(D.name)}if(M)continue;I.source=v.filter(D=>!R.includes(D)),I.themes=N.reduce((D,Y)=>Object.assign(D,{[Y.name]:Y.files}),{})}const J=new Map;for(const R of I.source){const P=i.basename(R),M=J.get(P)||[];J.set(P,[...M,R])}const ue=Array.from(J.entries()).filter(([R,P])=>P.length>1).map(([R,P])=>({name:R,files:P}));if(ue.length>0){const R=ue.map(({name:D,files:Y})=>{const Ee=Y.map(Ie=>` - ${Ie}`).join(`
|
|
50
|
-
`);return`
|
|
51
|
-
${D} appears in:
|
|
52
|
-
${f.dim(Ee)}`}).join(`
|
|
53
|
-
`);b.warn(f.yellow(`Found duplicate filenames in collection "${T}":
|
|
54
|
-
${R}`)),b.message(f.cyan("Please either split these files into different collections or mark some as theme files."));const P=await $e(h,F);if(!P){b.message(f.cyan("No files selected, skipping collection creation..."));break}v=P;const M=await pe(v);if(!M){b.message(f.cyan("No collection name provided, skipping collection creation..."));break}T=M;continue}B=!0,d.add(T)}catch(I){if(I instanceof g){b.error(`${I.message}`),b.message(f.cyan("Let's try again..."));continue}throw I}if(!B){b.message(f.cyan("Skipping collection creation..."));break}h=h.filter(I=>!v.includes(I)),h.length>0&&b.message(f.cyan(`Remaining files to organize: ${h.length}`)),F=!1}h.length>0?b.warn(f.yellow(`Warning: ${h.length} files were not assigned to any collection`)):b.message(f.cyan("Token organization complete")),e.tokens=l}if(e.output={directories:{tokens:i.relative(process.cwd(),a),css:r},css:{separate:!1,manageIndex:!0}},e.options={fluid:{min:320,max:1200}},typeof e.tokens=="object"&&!Array.isArray(e.tokens)){const l=e.tokens,d=new Set;for(const[h,F]of Object.entries(l)){if(d.has(h))throw new g(`Configuration Error: Duplicate collection name "${h}". Collection names must be unique.`);if(d.add(h),F.themes){const v=new Set;for(const T of Object.keys(F.themes)){if(v.has(T))throw new g(`Configuration Error: Duplicate theme name "${T}" in collection "${h}". Theme names must be unique within a collection.`);v.add(T)}}}}const S=await Promise.all(s.map(async l=>({path:i.resolve(process.cwd(),l),content:await de(i.resolve(process.cwd(),l),"utf-8")}))),w=me(e),{trees:k,resolved:x}=await G(w);return{config:w,tokens:s,trees:k,resolved:x,tokenPath:n,tokensDir:a,tokenFiles:S}},"initializeFromExistingTokens"),ct=p(async(e,n,t)=>{const o=await ee({type:"tokens",name:e});if(!o.files[0])throw new g(`Starter kit '${e}' does not contain any token files`);const s=i.resolve(process.cwd(),t),a=o.files.find(l=>i.basename(l.path)==="config.json");let r={};if(a)try{r=JSON.parse(a.content)}catch{console.warn(`Warning: Could not parse config.json for starter kit '${e}'`)}const c=o.files.filter(l=>i.basename(l.path)!=="config.json").map(l=>({path:i.join(s,i.basename(l.path)),content:l.content})),u=Object.fromEntries(c.map(l=>[i.basename(l.path),i.relative(process.cwd(),l.path)])),m={};if(r.themes)for(const[l,d]of Object.entries(r.themes))m[l]=d.map(h=>{const F=u[h];if(!F)throw new g(`Theme file '${h}' not found in starter kit '${e}'`);return F});const S={tokens:{source:c.map(l=>i.relative(process.cwd(),l.path)),type:"starter-kit",...Object.keys(m).length>0&&{themes:m}},options:{fluid:{min:320,max:1200}},output:{directories:{tokens:i.relative(process.cwd(),s),css:n},css:{separate:!1,manageIndex:!0}}},w=me(S),{trees:k,resolved:x}=await G(w,{type:"memory",data:Object.fromEntries(c.map(l=>[l.path,{collection:"default",content:l.content}]))});return{config:w,tokens:c.map(l=>i.relative(process.cwd(),l.path)),trees:k,resolved:x,tokenFiles:c,tokensDir:s}},"initializeFromStarterKit");async function lt(e){const n=[],t=i.resolve(process.cwd(),e);await A(t,{recursive:!0});const s=(await O()).filter(a=>a.type==="cube").map(a=>a.name);for(const a of s){const r=await ee({type:"cube",name:a});for(const c of r.files){if(!c)continue;const u=c.path.replace(/^styles\//,""),m=i.join(t,u),S=i.dirname(m);try{await A(S,{recursive:!0}),await q(m,c.content),n.push(m)}catch(w){const k=w instanceof Error?`: ${w.message}`:"";throw new g(`Failed to write CUBE module "${a}"${k}`)}}}return n}p(lt,"installCUBE");async function pt(){if(j("sugarcube.config.json")){const e=await H({message:f.yellow("WARNING: You are about to re-initialize an existing sugarcube project! This will overwrite your existing configuration file. "),options:[{label:"Overwrite existing file (start from scratch)",value:"overwrite"},{label:"Cancel initialization",value:"cancel"}]});return C(e)&&process.exit(0),{shouldProceed:e==="overwrite"}}return{shouldProceed:!0}}p(pt,"preflightInit");const ft=p(()=>{$.break(),V(" Welcome to sugarcube. The toolkit for seriously sweet front ends ")},"welcome"),ut=new z().name("init").description("Initialize a new sugarcube project").action(async()=>{try{ft(),(await pt()).shouldProceed||process.exit(0),ie("Step 1. Set up tokens");const n=await He();let t;switch(n){case"starter":{const d=await O();d||(Z("Failed to fetch starter kit list"),process.exit(1));const{name:h,tokenFilePaths:F}=await Ye(d),v=await Qe(),T=F.map(N=>({path:i.join(v,N)})),B=await rt({tokenFiles:T,tokensOutputDirectory:v});if(B.length>0){const N=B.map(J=>` - ${J}`).join(`
|
|
55
|
-
`);b.warn(f.yellow(`WARNING: The following token file(s) already exist in ${v} and will be OVERWRITTEN:
|
|
56
|
-
${f.dim(N)}`)),await Q("Continue?",!1)}const I=await xe();try{t=await ct(h,I,v)}catch(N){Z(`Failed to initialize starter kit: ${N instanceof Error?N.message:"Unknown error"}`),process.exit(1)}break}case"existing":t=await at({});break}ie("Step 2. Add style system");const o=await Xe();ie("Step 3. Add components");const s=await le();t.config.output.css.manageIndex=!1;let a,r,c;s!=="skip"&&(a=await Fe(),t.config.output.directories.components=i.relative(process.cwd(),a),c=await O(),c||(Z("Failed to fetch component list"),process.exit(1)),r=await je(c,s));const u=_e(await Se({config:t.config,cssOutputDirectory:t.config.output.directories.css}),r&&s!=="skip"&&a?await be({cssOutputDirectory:t.config.output.directories.css,selectedComponents:r,componentType:s,componentsOutputDirectory:a}):{designTokenCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]},o?await ve({cssOutputDirectory:t.config.output.directories.css}):{designTokenCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]}),m=te(u);m&&(b.warn(m),await Q("Continue?",!1));try{if(!t.tokensDir)throw new g("Tokens directory is not defined");if(await re.mkdir(t.tokensDir,{recursive:!0}),await re.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 d of t.tokenFiles)await re.writeFile(d.path,d.content)}}catch(d){const h=d instanceof Error?`: ${d.message}`:"";throw new g(`Failed to create project files${h}`)}let S=[];const{trees:w,resolved:k}=await G(t.config);S=await Te(w,k,t.config);let x=[];o&&(x=await lt(t.config.output.directories.css));let l=[];if(r&&s!=="skip"&&a){const d=oe();d.start("Installing components...");try{const h=await O();if(!h)throw new g("Failed to fetch component list");const{createdFiles:F,npmDependencies:v}=await Ce({registryIndex:h,selectedComponents:r,componentType:s,componentsOutputDirectory:a,cssOutputDirectory:t.config.output.directories.css});l=F,d.stop("Components installed successfully")}catch(h){throw d.stop("Installation failed"),h}}t.config.output.css.manageIndex&&await ne({cssOutputDirectory:t.config.output.directories.css,files:[...S.map(d=>d.path),...l.filter(d=>d.endsWith(".css")),...x]}),await fe(t.config),se({config:"sugarcube.config.json",tokens:n==="starter"?t.tokens:[],generated:[...S.map(d=>d.path),...x,...l,...t.config.output.css.manageIndex?["index.css"]:[]]}),L(f.greenBright("Success! Project initialized \u2728"))}catch(e){K(e)}}),mt=new z().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(V(f.inverse(" Validate design tokens ")),j("sugarcube.config.json")&&!e.length){const s=await _();await G(s),L(f.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=>i.normalize(s));for(const s of n)if(!j(s))throw new g(`Path not found: ${s}
|
|
57
|
-
Please check that the specified files or directories exist`);const t=await ge(n.map(s=>s.endsWith(".json")?s:i.join(s,"**/*.json")));if(t.length===0)throw new g(`No JSON files found in the specified paths
|
|
58
|
-
Please ensure the paths contain .json files`);const o=j("sugarcube.config.json")?await _():{output:{directories:{tokens:".",css:"."},css:{separate:!1}}};await G({...o,tokens:{type:"custom",source:t.map(s=>i.relative(process.cwd(),s))}}),L(f.greenBright("All tokens are valid \u2728"))}catch(n){K(n)}});process.on("SIGINT",()=>process.exit(0)),process.on("SIGTERM",()=>process.exit(0));async function dt(){const e=new z().name("sugarcube").description("CLI for scaffolding sugarcube projects").version(ze.version,"-v, --version","display the version number");e.addCommand(ut).addCommand(it).addCommand(mt).addCommand(st).addCommand(ot),e.parse()}p(dt,"main"),dt();
|
|
46
|
+
See ${w.cyan("https://docs.sugarcube.sh/cli/components")} for more information.`);if(!["react","astro-native"].includes(t.framework))throw new m("Invalid framework. Must be one of: react, astro-native.");if(r=t.framework,s=e,!n.output?.components)throw new m("Components directory must be configured in non-interactive mode. Please run the 'components' command without arguments first.");o=F(process.cwd(),n.output.components)}else{r=await he(!1);const y=await A();if(y||(je("Failed to fetch component list"),process.exit(1)),s=await at(y,r),n.output?.components)o=F(process.cwd(),n.output.components);else{const S=await it();o=F(process.cwd(),S),n.output.components=E(process.cwd(),o),await ye(n)}}const l=F(process.cwd(),n.output?.css||V),c=F(process.cwd(),n.output?.tokens||Oe),i=await Xe({cssOutputDirectory:l,selectedComponents:s,componentType:r,componentsOutputDirectory:o,tokensOutputDirectory:c}),p=te(i);p&&!t.force&&!t.silent&&(v.warn(p),await ne("Continue?",!1));const g=K();g.start("Installing components...");try{const y=await ct(s,r,o,l,c,n,t.overwrite||!1);g.stop("Components installed successfully"),await Ze(n);const{trees:S,resolved:f}=await O(n),{output:u}=await H(S,f,n);await q(u),await B(l,n),t.silent||(se({generated:y}),_(w.greenBright("Success! Components installed \u2728")))}catch(y){throw g.stop("Installation failed"),y}}catch(n){G(n)}});async function ke(e){const t=[],n=F(process.cwd(),e);await $(n,{recursive:!0});const s=(await A()).filter(r=>r.type==="cube").map(r=>r.name);for(const r of s){const l=await Z({type:"cube",name:r});for(const c of l.files){if(!c)continue;const i=c.path.replace(/^styles\//,""),p=h(n,i),g=Ie(p);try{await $(g,{recursive:!0}),await N(p,c.content),t.push(p)}catch(y){const S=y instanceof Error?`: ${y.message}`:"";throw new m(`Failed to write CUBE module "${r}"${S}`)}}}return t}a(ke,"installCUBE");const ut=new j().name("cube").description("Add CUBE CSS to your project").option("-s, --silent","Suppress logs and prompts").option("-f, --force","Skip overwrite confirmation").action(async e=>{try{if(!k(b))throw new m(ee.PROJECT_REQUIRED);const{config:t}=await L(),n=F(process.cwd(),t.output?.css||V);try{await $(n,{recursive:!0})}catch(l){const c=l instanceof Error?`: ${l.message}`:"";throw new m(`Failed to create output directory${c}`)}const o=await ge({cubeDirectory:n}),s=te(o);s&&!e.force&&!e.silent&&(v.warn(s),await ne("Continue?",!1));const r=await ke(n);await B(n,t),e.silent||(se({generated:r}),_(w.greenBright("Success! CUBE CSS added successfully. \u2728")))}catch(t){G(t)}});async function pt(e,t,n){const o=[],{output:s}=await H(e,t,n);await q(s),o.push(...s);const{output:r}=ce(t,n);await le(r),o.push(...r);const l=await B(n.output?.css||V,n);return o.push({path:l,css:Ue}),o}a(pt,"generateAllCSS");const ft=new j().name("generate").description("Generate CSS from your design tokens").option("--force","Skip overwrite confirmation").option("-s, --silent","Suppress logs and prompts").action(async e=>{try{if(!k(b))throw new m(ee.PROJECT_REQUIRED);const{config:t}=await L(),{trees:n,resolved:o}=await O(t),s=await pt(n,o,t);e.silent||(se({generated:s.map(r=>r.path)}),_(w.greenBright("Success! CSS generated successfully. \u2728")))}catch(t){G(t)}}),mt=["**/node_modules/**",".next","public","dist","build",".astro",".nuxt",".output",".svelte-kit"],R={"next-app":{tokensDir:"app/design-tokens",stylesDir:"app/styles",componentDir:"app/components"},"next-pages":{tokensDir:"src/design-tokens",stylesDir:"src/styles",componentDir:"src/components"},astro:{tokensDir:"src/design-tokens",stylesDir:"src/styles",componentDir:"src/components"},vite:{tokensDir:"src/design-tokens",stylesDir:"src/styles",componentDir:"src/components"},nuxt:{tokensDir:"assets/design-tokens",stylesDir:"assets/styles",componentDir:"components"},sveltekit:{tokensDir:"src/lib/design-tokens",stylesDir:"src/lib/styles",componentDir:"src/lib/components"},remix:{tokensDir:"app/design-tokens",stylesDir:"app/styles",componentDir:"app/components"},eleventy:{tokensDir:"src/_data/design-tokens",stylesDir:"src/styles",componentDir:"src/components"},none:{tokensDir:"src/design-tokens",stylesDir:"src/styles",componentDir:"src/components"}};function dt(e){try{const t=I.resolve(e,"package.json");if(!k(t))return null;const n=re(t,"utf-8");return JSON.parse(n)}catch{return null}}a(dt,"getPackageJson");function gt(e){const t=["design-tokens","tokens","src/design-tokens","src/tokens","app/design-tokens","assets/design-tokens","src/_data/design-tokens","src/lib/design-tokens"],n=["styles","css","src/styles","src/css","app/styles","assets/styles","assets/css","src/lib/styles"],o=["components","src/components","app/components","src/lib/components"],s={};for(const r of t)if(k(I.resolve(e,r))){s.existingTokensDir=r;break}for(const r of n)if(k(I.resolve(e,r))){s.existingStylesDir=r;break}for(const r of o)if(k(I.resolve(e,r))){s.existingComponentsDir=r;break}return s}a(gt,"findExistingPaths");async function wt(e){const[t,n,o]=await Promise.all([Q.glob("**/{next,vite,astro,nuxt,svelte,remix,eleventy}.config.*|.eleventy.js",{cwd:e,deep:3,ignore:mt}),k(I.resolve(e,"src")),dt(e)]),s=gt(e),r=k(I.resolve(e,`${n?"src/":""}app`)),l={framework:"none",isSrcDir:n,tokensDir:"src/design-tokens",stylesDir:"src/styles",componentDir:"src/components"};if(t.find(i=>i.startsWith("next.config."))?.length){const i=r?"next-app":"next-pages",p=R[i];return{...l,framework:i,tokensDir:s.existingTokensDir||p.tokensDir,stylesDir:s.existingStylesDir||p.stylesDir,componentDir:s.existingComponentsDir||p.componentDir}}if(t.find(i=>i.startsWith("astro.config."))?.length){const i=R.astro;return{...l,framework:"astro",tokensDir:s.existingTokensDir||i.tokensDir,stylesDir:s.existingStylesDir||i.stylesDir,componentDir:s.existingComponentsDir||i.componentDir}}if(t.find(i=>i.startsWith("nuxt.config."))?.length){const i=R.nuxt;return{...l,framework:"nuxt",tokensDir:s.existingTokensDir||i.tokensDir,stylesDir:s.existingStylesDir||i.stylesDir,componentDir:s.existingComponentsDir||i.componentDir}}if(t.find(i=>i.startsWith("svelte.config."))?.length){const i=R.sveltekit;return{...l,framework:"sveltekit",tokensDir:s.existingTokensDir||i.tokensDir,stylesDir:s.existingStylesDir||i.stylesDir,componentDir:s.existingComponentsDir||i.componentDir}}if(Object.keys(o?.dependencies??{}).find(i=>i.startsWith("@remix-run/"))){const i=R.remix;return{...l,framework:"remix",tokensDir:s.existingTokensDir||i.tokensDir,stylesDir:s.existingStylesDir||i.stylesDir,componentDir:s.existingComponentsDir||i.componentDir}}if(t.find(i=>i.startsWith("eleventy.config.")||i.startsWith(".eleventy."))?.length){const i=R.eleventy;return{...l,framework:"eleventy",tokensDir:s.existingTokensDir||i.tokensDir,stylesDir:s.existingStylesDir||i.stylesDir,componentDir:s.existingComponentsDir||i.componentDir}}if(t.find(i=>i.startsWith("vite.config."))?.length){const i=R.vite;return{...l,framework:"vite",tokensDir:s.existingTokensDir||i.tokensDir,stylesDir:s.existingStylesDir||i.stylesDir,componentDir:s.existingComponentsDir||i.componentDir}}const c=R.none;return{...l,framework:"none",tokensDir:s.existingTokensDir||(n?c.tokensDir:"design-tokens"),stylesDir:s.existingStylesDir||(n?c.stylesDir:"styles"),componentDir:s.existingComponentsDir||(n?c.componentDir:"components")}}a(wt,"getProjectInfo");function ht(e){return{"next-app":"Next.js (App Router)","next-pages":"Next.js (Pages Router)",astro:"Astro",vite:"Vite",nuxt:"Nuxt",sveltekit:"SvelteKit",remix:"Remix",eleventy:"11ty (Eleventy)",none:"No framework"}[e]}a(ht,"getFrameworkDisplayName");async function yt(){k(b)&&(v.error(`A ${w.cyan(b)} file already exists at ${w.cyan(process.cwd())}.
|
|
47
|
+
To start over, remove the ${w.cyan(b)} file and run ${w.cyan("init")} again.
|
|
48
|
+
`),process.exit(1))}a(yt,"preflightInit");function kt(e,t=process.cwd()){try{const n=Je(t,"package.json");if(!k(n))return!1;const o=re(n,"utf-8"),s=JSON.parse(o),r={...s.dependencies,...s.devDependencies,...s.peerDependencies};return e in r}catch{return!1}}a(kt,"isPackageInstalled");const Dt=a(async(e,t,n)=>{const o=await Z({type:"tokens",name:e});if(!o.files[0])throw new m(`Starter kit '${e}' does not contain any token files`);const s=F(process.cwd(),t),r=o.files.find(u=>U(u.path)==="config.json");let l={};if(r)try{l=JSON.parse(r.content)}catch(u){et(`Could not parse config.json for starter kit '${e}':`,u)}const c=o.files.filter(u=>U(u.path)!=="config.json").map(u=>({path:h(s,U(u.path)),content:u.content})),i=Object.fromEntries(c.map(u=>[U(u.path),E(process.cwd(),u.path)])),p={};if(l.themes)for(const[u,W]of Object.entries(l.themes))p[u]=W.map(x=>{const P=i[x];if(!P)throw new m(`Theme file '${x}' not found in starter kit '${e}'`);return P});const g={...n};Object.keys(p).length>0&&typeof g.tokens=="object"&&!Array.isArray(g.tokens)&&"source"in g.tokens&&(g.tokens.themes=p);const y=Le(g),{trees:S,resolved:f}=await O(y,Object.fromEntries(c.map(u=>[u.path,{collection:"default",content:u.content}])));return{config:y,trees:S,resolved:f,tokensDir:s,tokenFiles:c,createdTokenPaths:c.map(u=>E(process.cwd(),u.path))}},"initializeFromStarterKit"),St="https://sugarcube.sh/r/schema.json",oe="tailwind-fluid",De="**/*.json",Se="@sugarcube-org/vite",ve="@sugarcube-org/postcss",vt=["node_modules",".git",".next","dist","build"],Ct=/^[a-zA-Z][a-zA-Z0-9_-]*$/,Et=5,T={LAUNCH_INITIATED:"Launch sequence initiated.",PREFLIGHT_COMPLETE:"\u2714 Preflight checks",PROJECT_DETECTED:a(e=>`\u2714 Project detected (${e})`,"PROJECT_DETECTED"),TOKENS_INSTALLED:"\u2714 Design tokens installed",TOKENS_CONFIGURED:"\u2714 Design tokens configured",CUBE_INSTALLED:"\u2714 CUBE CSS installed",CSS_VARS_GENERATED:"\u2714 CSS variables generated",UTILITIES_GENERATED:"\u2714 Utility classes generated",DEPS_INSTALLED:"\u2714 Dependencies installed",CONFIG_WRITTEN:a(e=>`\u2714 Config file written (${e})`,"CONFIG_WRITTEN"),SUGARCUBE_ENTRY_CREATED:a(e=>`\u2714 Sugarcube entry point created (${e})`,"SUGARCUBE_ENTRY_CREATED"),SUCCESS:"Success! Project initialized \u2728",CONTINUING_WITHOUT_PLUGIN:"\u2714 Continuing without plugin..."};async function bt(e){if(e.setupResult=await Dt(e.starterKit??"",e.tokensDir,e.config),e.setupResult.tokenFiles)for(const t of e.setupResult.tokenFiles)try{await J.writeFile(t.path,t.content),e.createdFiles.push(t.path)}catch(n){throw new X("Failed to write token file",t.path,"writeFile",n instanceof Error?n:void 0)}}a(bt,"downloadAndWriteTokenFiles");async function Tt(e){await bt(e),v.success(T.TOKENS_INSTALLED)}a(Tt,"installFromStarterKit");async function It(e){try{await J.mkdir(e.tokensDir,{recursive:!0}),e.createdDirectories.push(e.tokensDir),await J.mkdir(e.stylesDir,{recursive:!0}),e.createdDirectories.push(e.stylesDir)}catch(t){throw new X("Failed to create directories",e.tokensDir,"mkdir",t instanceof Error?t:void 0)}}a(It,"createProjectDirectories");async function Ft(e,t,n,o,s){return{options:e,...t,config:n,minimalUserConfig:o,...s,createdFiles:[],createdDirectories:[],installedDependencies:[]}}a(Ft,"buildInitContext");function Ce(e,t){if(!e||e.trim()==="")throw new z(`${t} cannot be empty`,t,e,'Provide a valid directory path like "src/styles"');const n=Fe(e);if(n.includes("../")||n.startsWith("/"))throw new z(`${t} should be a relative path within your project`,t,e,`Use a relative path like "src/styles" instead of "${e}"`);const o=n.split("/")[0];if(o&&vt.includes(o))throw new z(`${t} cannot be in a reserved directory`,t,e,`Avoid using ${o}. Try "src/styles" or "assets/styles" instead`)}a(Ce,"validateDirectoryPath");function $t(e){if(e.tokensDir&&Ce(e.tokensDir,"tokens-dir"),e.stylesDir&&Ce(e.stylesDir,"styles-dir"),e.kit&&!Ct.test(e.kit))throw new z("Kit name contains invalid characters","kit",e.kit,'Use only letters, numbers, hyphens, and underscores. Try "tailwind-fluid" or "tailwind-static"')}a($t,"validateOptions");function Ee(e,t=0){if(typeof e!="object"||e===null||t>Et)return!1;for(const[n,o]of Object.entries(e))if(!n.startsWith("$")&&typeof o=="object"&&o!==null&&("$value"in o||Ee(o,t+1)))return!0;return!1}a(Ee,"hasAnyToken");async function Rt(e){try{const t=await Q(De,{cwd:e,absolute:!0});for(const n of t)try{const o=await J.readFile(n,"utf-8"),s=JSON.parse(o);if(Ee(s))return!0}catch{}return!1}catch{return!1}}a(Rt,"detectExistingTokens");function xt(e){return{source:[h(E(process.cwd(),e.actualTokensDir),De)]}}a(xt,"createSingleTokenCollection");async function Pt(e){return xt(e)}a(Pt,"buildTokensConfig");async function jt(e){const t=await Pt(e),n=E(process.cwd(),e.actualStylesDir),o=E(process.cwd(),e.actualTokensDir),s={$schema:St,tokens:t},r={};return n!==ue.output.css&&(r.css=n),o!==ue.output.tokens&&(r.tokens=o),Object.keys(r).length>0&&(s.output=r),s}a(jt,"generateMinimalConfig");function _t(e){return e==="next-app"||e==="next-pages"?ve:Se}a(_t,"selectPluginForFramework");async function Nt(e){await yt();const t=await wt(process.cwd());v.success(T.PREFLIGHT_COMPLETE),v.success(T.PROJECT_DETECTED(ht(t.framework)));const n=e.tokensDir||t.tokensDir,o=e.stylesDir||t.stylesDir,s=await Rt(n);return{projectInfo:t,tokensDir:n,stylesDir:o,hasExistingTokens:s}}a(Nt,"initializeProjectContext");function At(e,t,n){let o=null;n||(o=e.kit||oe);let s=null;e.plugin==="auto"||!e.plugin?s=_t(t.framework):e.plugin==="vite"?s=Se:e.plugin==="postcss"&&(s=ve);const r=e.cube!==!1;return{starterKit:o,pluginToInstall:s,installCube:r}}a(At,"determineInstallationTargets");async function Ot(e){if(!e.installCube)return;const t=await ge({cubeDirectory:e.stylesDir}),n=te(t);n&&(v.warn(n),await ne("Continue and overwrite existing files?",!1))}a(Ot,"checkConflicts");async function Ut(e){const{trees:t,resolved:n}=await O(e.config);e.setupResult={config:e.config,createdTokenPaths:[],trees:t,resolved:n,tokenFiles:[],tokensDir:e.tokensDir},v.success(T.TOKENS_CONFIGURED)}a(Ut,"processExistingTokens");async function Lt(e){!e.hasExistingTokens&&e.starterKit?await Tt(e):await Ut(e)}a(Lt,"setupDesignTokens");async function Gt(e){e.installCube&&(await ke(e.stylesDir),v.success(T.CUBE_INSTALLED))}a(Gt,"installCubeFiles");async function Wt(e){if(!e.setupResult)throw new m("Initialization incomplete. Please re-run the `init` command.");const{trees:t,resolved:n}=e.setupResult,{output:o}=await H(t,n,e.config);await q(o);const{output:s}=ce(n,e.config);await le(s),await B(e.stylesDir,e.config)}a(Wt,"writeStyles");async function Mt(e){if(!e.pluginToInstall)return;if(kt(e.pluginToInstall)){v.success(T.DEPS_INSTALLED);return}const t=K();t.start(`Installing ${e.pluginToInstall.split("/")[1]} plugin...`);try{await we([e.pluginToInstall],process.cwd()),e.installedDependencies.push(e.pluginToInstall),t.stop(T.DEPS_INSTALLED)}catch{t.stop(""),v.warn(w.yellow(`Failed to install ${e.pluginToInstall}. Install manually: npm install ${e.pluginToInstall}`)),v.info(T.CONTINUING_WITHOUT_PLUGIN)}}a(Mt,"installPlugins");async function Bt(e){try{await ye(e.minimalUserConfig),e.createdFiles.push(b),v.success(T.CONFIG_WRITTEN(b))}catch(t){throw new X("Failed to write configuration file",b,"writeFile",t instanceof Error?t:void 0)}_(w.greenBright(T.SUCCESS))}a(Bt,"finalize");const Jt=new j().name("init").description("Initialize a new sugarcube project").option("--kit <kit>",`Starter kit to use (default: ${oe})`,oe).option("--tokens-dir <dir>","Design tokens directory (e.g., 'src/design-tokens')").option("--styles-dir <dir>","Styles output directory (e.g., 'src/styles')").option("--plugin <type>","Plugin to install: vite, postcss, none, or auto (default: auto)","auto").option("--no-cube","Don't install CUBE CSS").action(async e=>{let t;try{$t(e);const n=await Nt(e),o=await jt({actualTokensDir:n.tokensDir,actualStylesDir:n.stylesDir}),r={...Ge(o),$schema:o.$schema},l=o,c=At(e,n.projectInfo,n.hasExistingTokens);t=await Ft(e,n,r,l,c),await Ot(t),await It(t),await Lt(t),await Gt(t),await Mt(t),await Wt(t),await Bt(t)}catch(n){G(n)}}),zt=new j().name("validate").description("Validate design token files").argument("[paths...]","Token files or directories to validate (e.g., src/design-tokens)").action(async e=>{try{if(ie(w.inverse(" Validate design tokens ")),k(b)&&!e.length){const{config:o}=await L();await O(o),_(w.greenBright("All tokens are valid \u2728"));return}if(!e.length)throw new m("No paths specified. Please provide files/directories to validate, or run this in a sugarcube project directory.");for(const o of e)if(!k(o))throw new m(`Path not found: ${o}
|
|
49
|
+
Please check that the specified files or directories exist`);const t=await Q(e.map(o=>o.endsWith(".json")?o:h(o,"**/*.json")));if(t.length===0)throw new m(`No JSON files found in the specified paths
|
|
50
|
+
Please ensure the paths contain .json files`);const n=k(b)?(await L()).config:{tokens:{source:[]},output:{tokens:".",css:".",separate:!1}};await O({...n,tokens:{source:t.map(o=>E(process.cwd(),o))}}),_(w.greenBright("All tokens are valid \u2728"))}catch(t){G(t)}});process.on("SIGINT",()=>process.exit(0)),process.on("SIGTERM",()=>process.exit(0));async function Kt(){const e=new j().name("sugarcube").description("CLI for scaffolding sugarcube projects"),t=process.argv[2];(!t||!["init","generate","validate","components","cube"].includes(t))&&e.version(Ke.version,"-v, --version","display the version number"),e.addCommand(Jt).addCommand(ft).addCommand(zt).addCommand(lt).addCommand(ut),e.parse()}a(Kt,"main"),Kt();
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sugarcube-org/cli",
|
|
3
|
-
"version": "0.0.0-alpha.
|
|
3
|
+
"version": "0.0.0-alpha.16",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
7
|
"description": "A CLI for scaffolding sugarcube applications",
|
|
8
|
-
"license": "
|
|
8
|
+
"license": "UNLICENSED",
|
|
9
9
|
"author": "Mark Tomlinson",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
@@ -43,9 +43,10 @@
|
|
|
43
43
|
"execa": "^9.5.2",
|
|
44
44
|
"fast-glob": "^3.3.2",
|
|
45
45
|
"node-fetch": "^3.3.0",
|
|
46
|
+
"pathe": "^2.0.3",
|
|
46
47
|
"picocolors": "^1.1.1",
|
|
47
48
|
"zod": "^3.24.2",
|
|
48
|
-
"@sugarcube-org/core": "0.0.1-alpha.
|
|
49
|
+
"@sugarcube-org/core": "0.0.1-alpha.6"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"pkgroll": "^2.5.1",
|
|
@@ -55,7 +56,7 @@
|
|
|
55
56
|
"node": ">=18.0.0"
|
|
56
57
|
},
|
|
57
58
|
"scripts": {
|
|
58
|
-
"build": "pkgroll --minify",
|
|
59
|
+
"build": "tsc --noEmit && pkgroll --minify",
|
|
59
60
|
"dev": "cross-env REGISTRY_URL=http://localhost:4321/r tsx src/index.ts",
|
|
60
61
|
"test": "vitest run",
|
|
61
62
|
"test:watch": "vitest",
|