saneprint 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ All notable changes to saneprint will be documented here.
4
+
5
+ ---
6
+
7
+ ## [1.0.0] - 2026-03-02
8
+
9
+ ### Added
10
+
11
+ - Initial release of the `saneprint` CLI
12
+ - Feature-based architecture support (`src/features/...`)
13
+ - `theme.json` ingestion with automatic "remification" of units
14
+ - Production-grade Next.js boilerplate with TanStack Query and Redux Toolkit
15
+ - Brand identity with custom terminal styling
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 saneprint contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,257 @@
1
+ # saneprint
2
+
3
+ [![npm version](https://img.shields.io/npm/v/saneprint)](https://www.npmjs.com/package/saneprint)
4
+ [![npm downloads](https://img.shields.io/npm/dm/saneprint)](https://www.npmjs.com/package/saneprint)
5
+ [![license](https://img.shields.io/npm/l/saneprint)](./LICENSE)
6
+ [![node](https://img.shields.io/node/v/saneprint)](https://nodejs.org)
7
+
8
+ **saneprint** is a scaffolding tool that eliminates the constant AI back-and-forth. Start with a production-grade foundation that AI actually understands—ship features faster with zero refactoring tax.
9
+
10
+ ---
11
+
12
+ ## The Problem with "Vibe Coding"
13
+
14
+ You've probably been there: You ask your AI assistant (Cursor, Claude, Copilot) to "build a signup form" or "create a dashboard layout." The AI generates code that _looks_ right: nice indentation, modern syntax, the works.
15
+
16
+ But then reality hits:
17
+
18
+ - **Inconsistent Units**: One component uses `px`, another uses `rem`, another hardcodes pixel values
19
+ - **No Design System**: Colors are hardcoded HEX values (`#3b82f6`) scattered everywhere
20
+ - **Architectural Chaos**: AI invents new folder structures for every feature because there's no clear pattern to follow
21
+ - **Component Bloat**: 800-line "God Components" that mix logic, UI, and side effects
22
+ - **Copy-Paste Hell**: The same button styled 5 different ways across your app
23
+
24
+ This is **"Vibe Coding"**: code that feels correct but accumulates **massive technical debt from Day 1**.
25
+
26
+ Without a solid foundation, you're constantly fighting AI's tendency to hallucinate new patterns instead of following existing ones.
27
+
28
+ ---
29
+
30
+ ## Why saneprint Works
31
+
32
+ **You stop explaining. AI starts shipping.**
33
+
34
+ With a solid foundation in place:
35
+
36
+ - ✅ **Reduced Cognitive Load**: No more "where does this go?" or "how do we handle auth?"
37
+ - ✅ **Faster Velocity**: AI references existing patterns instead of inventing new ones—features ship in hours, not days
38
+ - ✅ **Less Back-and-Forth**: Point to your auth flow once. AI replicates it perfectly for every new feature.
39
+ - ✅ **Quality by Default**: Design system enforcement means zero inconsistencies sneak into production
40
+ - ✅ **Lower Maintenance**: When everything follows the same pattern, scaling to 50+ routes is painless
41
+
42
+ ---
43
+
44
+ ## What You Get Out of the Box
45
+
46
+ ### 1. Design System Pipeline (JSON → Code)
47
+
48
+ Without a design system, it's easy to fall into the trap: copy-paste Tailwind classes, use `bg-blue-500` here and `bg-blue-600` there, hope it all looks consistent in the end.
49
+
50
+ saneprint **forces** a design system:
51
+
52
+ ```bash
53
+ npx saneprint
54
+ # Choose: Custom Design System
55
+ # Define your colors, spacing, typography
56
+ ```
57
+
58
+ The CLI automatically:
59
+
60
+ - ✅ Converts all `px` values to `rem` (responsive by default)
61
+ - ✅ Generates CSS custom properties mapped to Tailwind
62
+ - ✅ Creates semantic color roles (`--color-brand`, `--color-accent`)
63
+ - ✅ Injects theme into your entire UI system
64
+
65
+ **Impact**: No more "fix all the inconsistent buttons" tickets. No designer QA cycles wasted on color mismatches. Your AI assistant becomes a productivity multiplier, not a cleanup job generator.
66
+
67
+ ### 2. Feature-Based Architecture
68
+
69
+ No more "components folder soup." Every feature is self-contained:
70
+
71
+ ```
72
+ src/features/
73
+ ├── core/ # Reusable UI (buttons, inputs, modals)
74
+ ├── auth/ # Complete auth flow (login, signup, OTP)
75
+ └── protected/ # Domain features (dashboard, users, etc.)
76
+ ```
77
+
78
+ Each feature has its own:
79
+
80
+ - `components/` - Feature-specific UI
81
+ - `hooks/` - Business logic extraction
82
+ - `pages/` - Page-level compositions
83
+ - `schemas/` - Zod validation schemas
84
+ - `index.ts` - Public API exports
85
+
86
+ **Impact**: Zero "where should this file go?" questions. You and your AI work 3x faster because the next step is always obvious.
87
+
88
+ ### 3. Production-Ready Auth Flow
89
+
90
+ Real apps need more than a basic login form. saneprint includes:
91
+
92
+ - ✅ Multi-step signup with OTP verification
93
+ - ✅ Forgot password flow with secure reset
94
+ - ✅ Cookie-based auth (HttpOnly, Secure, SameSite)
95
+ - ✅ Redux persistence for session state
96
+ - ✅ Protected route middleware
97
+ - ✅ Complete form validations with Zod
98
+
99
+ **Impact**: New features inherit production-grade patterns automatically. No "let's add error handling later" tech debt. Ship confidently from commit one.
100
+
101
+ ### 4. Living Styleguide
102
+
103
+ Every project includes a `/styleguide` route that showcases:
104
+
105
+ - Color system with semantic roles
106
+ - Typography hierarchy
107
+ - All form components (Input, Select, OTP, MultiSelect)
108
+ - Interactive elements (Buttons, Modals, Tooltips)
109
+ - Data visualization (Tables with virtualization)
110
+ - Best practices guide
111
+
112
+ **Impact**: Stop recreating the same component 5 different ways. Your styleguide is a single source of truth that prevents drift before it starts.
113
+
114
+ ### 5. Single Responsibility by Design
115
+
116
+ Components naturally stay focused and maintainable because the structure enforces separation of concerns:
117
+
118
+ - **Logic separated from UI**: Complex state management lives in custom hooks
119
+ - **Primitives vs Compositions**: Base components (`Button`, `Input`) live in `core/components`, feature-specific compositions stay in their domains
120
+ - **No mixed responsibilities**: Each component does one thing well
121
+ - **Design tokens, not inline styles**: All styling driven by the theme system
122
+
123
+ **Impact**: Onboard new developers in hours, not weeks. Every file is scannable. Debugging takes minutes because responsibilities are crystal clear.
124
+
125
+ ---
126
+
127
+ ## Real-World Workflow
128
+
129
+ ```bash
130
+ npx saneprint
131
+ cd my-project
132
+ pnpm install
133
+ pnpm dev
134
+ ```
135
+
136
+ When you prompt your AI:
137
+
138
+ > "Create a user management feature in `src/features/users`. Include a `UserListPage` that fetches data with TanStack Query, a `UserCard` component, and Zod schemas for validation. Follow the same structure as the auth feature."
139
+
140
+ AI has a clear reference to follow - it sees how auth is organized and replicates that pattern for users.
141
+
142
+ ---
143
+
144
+ ## What You Save
145
+
146
+ **Time:**
147
+
148
+ - No "which folder?" decisions (20+ mins per feature)
149
+ - No "let's standardize our buttons" refactors (5-10 hours)
150
+ - No "why is this color different?" design QA cycles (2-3 hours per sprint)
151
+ - No onboarding maze for new developers (2-3 days → 4 hours)
152
+
153
+ **Frustration:**
154
+
155
+ - Zero "AI reinvented the auth flow" rewrites
156
+ - Zero "I can't find where login logic lives" treasure hunts
157
+ - Zero "our codebase looks like 5 different people built it" embarrassment
158
+
159
+ **Money:**
160
+
161
+ - Lower maintenance costs (fewer bug tickets from inconsistent patterns)
162
+ - Faster feature delivery (ship 2-3x more with the same team)
163
+ - Better retention (developers actually enjoy working in the codebase)
164
+
165
+ ---
166
+
167
+ ## Quickstart
168
+
169
+ ```bash
170
+ npx saneprint
171
+ ```
172
+
173
+ Follow the prompts to choose:
174
+
175
+ - Project type (Next.js)
176
+ - Design system (default or custom)
177
+ - Project name
178
+
179
+ **Then:**
180
+
181
+ ```bash
182
+ cd your-project-name
183
+ pnpm install
184
+ pnpm dev
185
+ ```
186
+
187
+ Visit `http://localhost:3000/styleguide` to see your design system in action.
188
+
189
+ ---
190
+
191
+ ## The Stack
192
+
193
+ **Opinionated and Modern:**
194
+
195
+ - **Framework**: Next.js 14+ (App Router, Server Components)
196
+ - **Styling**: Tailwind CSS v4 (driven by design tokens)
197
+ - **Validation**: Zod (type-safe runtime validation)
198
+ - **Forms**: React Hook Form (performance-optimized)
199
+ - **State**: Redux Toolkit + TanStack Query (persistent + server state)
200
+ - **Icons**: Phosphor Icons (one library, consistent style)
201
+ - **Color System**: OKLCH (perceptually uniform colors)
202
+
203
+ ---
204
+
205
+ ## What Makes This "Production-Grade"?
206
+
207
+ ❌ **NOT** a tutorial project
208
+ ❌ **NOT** a minimal starter
209
+ ✅ **IS** a foundation you'd actually use in production
210
+
211
+ - HttpOnly cookie authentication (not localStorage JWT)
212
+ - Middleware-based route protection (Edge-optimized)
213
+ - Comprehensive error boundaries
214
+ - SEO metadata helpers
215
+ - Accessibility standards (ARIA labels, keyboard navigation)
216
+ - Performance optimizations (virtualized tables, debounced search)
217
+ - Type-safe API layer with environment guards
218
+
219
+ ---
220
+
221
+ ## Philosophy
222
+
223
+ **Stop fighting your tools. Start shipping.**
224
+
225
+ - **Less Explaining, More Building** - AI learns from your code, not from document after document of rules you'll never keep updated.
226
+
227
+ - **Velocity That Scales** - Your first feature takes 2 hours. Your 50th feature? Still 2 hours. Structure prevents slowdown.
228
+
229
+ - **Design Systems Without the Overhead** - You get token-based styling and a living styleguide automatically. No design-dev translation layer needed.
230
+
231
+ - **Quality That Compounds** - Every feature you ship makes the next one easier. Patterns reinforce themselves instead of diverging.
232
+
233
+ ---
234
+
235
+ ## Who This Is For
236
+
237
+ - **Solo Devs** shipping fast with AI assistance
238
+ - **Freelancers** delivering maintainable codebases to clients
239
+ - **Product Engineers** focused on features, not infrastructure
240
+ - **Designers who code** wanting a solid foundation that respects design systems and enforces their tokens from day one
241
+ - **Tech Leads** standardizing team output
242
+ - **Founders** who need quality code without a senior engineer (yet)
243
+
244
+ ---
245
+
246
+ ## Author
247
+
248
+ Built by **Karishma Garg**, Product Engineer
249
+
250
+ - GitHub: [@karishma-dev](https://github.com/karishma-dev)
251
+ - Portfolio: [karishma.dev](https://karishma.dev)
252
+
253
+ ---
254
+
255
+ ## License
256
+
257
+ MIT. See [LICENSE](./LICENSE) for details.
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import{Command as he}from"commander";import*as c from"@clack/prompts";import p from"chalk";import pe from"path";import*as i from"@clack/prompts";import f from"chalk";import b from"fs-extra";import re from"path";var u={version:"1.0.0",colors:{primary:{50:"oklch(0.985 0.015 180)",100:"oklch(0.97 0.04 180)",200:"oklch(0.94 0.07 180)",300:"oklch(0.89 0.1 180)",400:"oklch(0.79 0.13 180)",500:"oklch(0.7 0.14 180)",600:"oklch(0.59 0.13 185)",700:"oklch(0.5 0.11 190)",800:"oklch(0.41 0.09 190)",900:"oklch(0.35 0.07 195)"},secondary:{50:"oklch(0.98 0.01 200)",100:"oklch(0.95 0.02 200)",200:"oklch(0.88 0.04 200)",300:"oklch(0.8 0.06 200)",400:"oklch(0.7 0.08 200)",500:"oklch(0.6 0.09 200)",600:"oklch(0.5 0.08 200)",700:"oklch(0.4 0.07 200)",800:"oklch(0.3 0.06 200)",900:"oklch(0.2 0.05 200)"},tertiary:{50:"oklch(0.97 0.02 310)",100:"oklch(0.93 0.04 310)",200:"oklch(0.87 0.08 310)",300:"oklch(0.79 0.13 310)",400:"oklch(0.7 0.18 310)",500:"oklch(0.62 0.22 310)",600:"oklch(0.54 0.2 310)",700:"oklch(0.46 0.17 310)",800:"oklch(0.38 0.14 310)",900:"oklch(0.3 0.1 310)"},neutral:{0:"#ffffff",50:"oklch(0.99 0 0)",100:"oklch(0.97 0 0)",200:"oklch(0.92 0 0)",300:"oklch(0.86 0 0)",400:"oklch(0.68 0 0)",500:"oklch(0.52 0 0)",600:"oklch(0.38 0 0)",700:"oklch(0.3 0 0)",800:"oklch(0.19 0 0)",900:"oklch(0.13 0 0)",1e3:"#000000"},danger:{500:"oklch(0.628 0.218 29)",600:"oklch(0.55 0.2 29)"},success:{500:"oklch(0.698 0.176 142)",600:"oklch(0.6 0.16 142)"},warning:{500:"oklch(0.705 0.15 65)",600:"oklch(0.62 0.14 65)"},info:{500:"oklch(0.596 0.182 255)",600:"oklch(0.52 0.17 255)"}},typography:{fontFamily:{sans:"var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif",mono:"var(--font-geist-mono), ui-monospace, monospace"},styles:{heading1:{size:"48px",weight:"700",lineHeight:"1.1",letterSpacing:"-0.02em"},heading2:{size:"36px",weight:"700",lineHeight:"1.2",letterSpacing:"-0.01em"},heading3:{size:"30px",weight:"700",lineHeight:"1.25",letterSpacing:"-0.01em"},heading4:{size:"24px",weight:"600",lineHeight:"1.3",letterSpacing:"-0.005em"},heading5:{size:"20px",weight:"600",lineHeight:"1.35",letterSpacing:"0"},heading6:{size:"18px",weight:"600",lineHeight:"1.4",letterSpacing:"0"},body:{size:"16px",weight:"400",lineHeight:"1.5",letterSpacing:"0"},bodySm:{size:"14px",weight:"400",lineHeight:"1.5",letterSpacing:"0"},label:{size:"14px",weight:"600",lineHeight:"1.4",letterSpacing:"0.01em"},labelSm:{size:"12px",weight:"600",lineHeight:"1.35",letterSpacing:"0.01em"},caption:{size:"12px",weight:"400",lineHeight:"1.4",letterSpacing:"0"}}},themes:{light:{background:"{colors.neutral.50}",surface:"{colors.neutral.0}",text:"{colors.neutral.900}",textMuted:"{colors.neutral.600}",border:"{colors.neutral.200}",primary:"{colors.primary.500}",primaryHover:"{colors.primary.600}",secondary:"{colors.secondary.500}",secondaryHover:"{colors.secondary.600}",tertiary:"{colors.tertiary.500}",tertiaryHover:"{colors.tertiary.600}",danger:"{colors.danger.500}",dangerHover:"{colors.danger.600}",onPrimary:"{colors.neutral.0}",onSecondary:"{colors.neutral.0}",onTertiary:"{colors.neutral.0}",onDanger:"{colors.neutral.0}",inputBackground:"{colors.neutral.0}",inputBorder:"{colors.neutral.300}",inputFocusRing:"{colors.primary.500}"}}};var C="/* theme start */",S="/* theme end */",M={background:"background",surface:"surface",text:"foreground",textMuted:"muted",border:"border",primary:"brand",primaryHover:"brand-hover",secondary:"accent",secondaryHover:"accent-hover",tertiary:"tertiary",tertiaryHover:"tertiary-hover",danger:"danger",dangerHover:"danger-hover",onPrimary:"on-brand",onSecondary:"on-accent",onTertiary:"on-tertiary",onDanger:"on-danger",inputBackground:"input",inputBorder:"input-border",inputFocusRing:"focus-ring"},z=[{name:"primary",baseColor:"var(--color-brand)",hoverColor:"var(--color-brand-hover)",foregroundColor:"var(--color-on-brand)"},{name:"secondary",baseColor:"var(--color-accent)",hoverColor:"var(--color-accent-hover)",foregroundColor:"var(--color-on-accent)"},{name:"tertiary",baseColor:"var(--color-tertiary)",hoverColor:"var(--color-tertiary-hover)",foregroundColor:"var(--color-on-tertiary)"},{name:"danger",baseColor:"var(--color-danger)",hoverColor:"var(--color-danger-hover)",foregroundColor:"var(--color-on-danger)"}],V={heading1:"heading-1",heading2:"heading-2",heading3:"heading-3",heading4:"heading-4",heading5:"heading-5",heading6:"heading-6",body:"body",bodySm:"body-sm",label:"label",labelSm:"label-sm",caption:"caption"};function E(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function B(e){return JSON.parse(JSON.stringify(e))}function J(e){return Number.parseFloat(e.toFixed(4)).toString()}function U(e){return e.replace(/(-?\d*\.?\d+)px\b/g,(r,o)=>{let t=Number.parseFloat(o)/16;return`${J(t)}rem`})}function X(e){return U(e)}function d(e,r,o){if(r===null||typeof r!="object"||Array.isArray(r)){if(typeof e!=typeof r)throw new Error(`Invalid value at ${o}. Expected ${typeof r}.`);return}if(e===null||typeof e!="object"||Array.isArray(e))throw new Error(`Invalid value at ${o}. Expected an object.`);let t=r,n=e,s=Object.keys(t).sort(),x=Object.keys(n).sort();if(s.length!==x.length||s.some((g,v)=>g!==x[v]))throw new Error(`Theme schema mismatch at ${o}. Edit values only; do not add or remove keys.`);for(let g of s){let v=o==="theme"?`theme.${g}`:`${o}.${g}`;d(n[g],t[g],v)}}function $(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function Y(e){if(!$(e))throw new Error("Invalid value at theme.colors. Expected an object.");d(e,u.colors,"theme.colors")}function h(e,r){return` ${e}: ${r};`}function a(e,r){return[` ${e}`,...r.map(o=>` ${o}`)," }"]}function G(e,r){let o=e.split("."),t=r;for(let n of o){if(t===null||typeof t!="object"||!(n in t))throw new Error(`Could not resolve token reference {${e}}.`);t=t[n]}if(typeof t!="string")throw new Error(`Token reference {${e}} did not resolve to a string value.`);return t}function j(e,r){return e.replace(/\{([^}]+)\}/g,(o,t)=>j(G(t,r),r))}function m(e,r){return X(j(e,r))}function K(e,r){for(let[o,t]of Object.entries(r.colors))for(let[n,s]of Object.entries(t))e.push(h(`--color-${o}-${n}`,m(s,r)))}function W(e,r,o){for(let[t,n]of Object.entries(M))e.push(h(`--color-${n}`,m(r[t],o)))}function q(e,r){e.push(h("--font-sans",m(r.typography.fontFamily.sans,r))),e.push(h("--font-mono",m(r.typography.fontFamily.mono,r)));for(let[o,t]of Object.entries(r.typography.styles)){let n=t;e.push(h(`--text-${o}`,m(n.size,r))),e.push(h(`--text-${o}--line-height`,m(n.lineHeight,r))),e.push(h(`--tracking-${o}`,m(n.letterSpacing,r))),e.push(h(`--font-weight-${o}`,m(n.weight,r)))}}function Q(e){let r=["@theme inline {"];return K(r,e),W(r,e.themes.light,e),q(r,e),r.push("}"),r}function Z(e){let r=[];for(let o of Object.keys(e.typography.styles)){let t=V[o];r.push(`@utility ${t} {`,` font-size: var(--text-${o});`,` font-weight: var(--font-weight-${o});`,` line-height: var(--text-${o}--line-height);`,` letter-spacing: var(--tracking-${o});`,"}")}return r}function ee(){let e=["@layer components {"];e.push(...a(".btn {",["display: inline-flex;","align-items: center;","justify-content: center;","gap: 0.5rem;","border-radius: 0.75rem;","border: 1px solid transparent;","font-size: var(--text-label);","font-weight: var(--font-weight-label);","line-height: var(--text-label--line-height);","letter-spacing: var(--tracking-label);","transition-property: background-color, border-color, color, box-shadow, opacity;","transition-duration: 150ms;","transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);","cursor: pointer;"])),e.push(...a(".btn:focus-visible {",["outline: none;","box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-focus-ring) 35%, transparent);"])),e.push(...a(".btn:disabled {",["cursor: not-allowed;","opacity: 0.55;"]));for(let r of z)e.push(...a(`.btn-${r.name}-filled {`,[`background-color: ${r.baseColor};`,`border-color: ${r.baseColor};`,`color: ${r.foregroundColor};`])),e.push(...a(`.btn-${r.name}-filled:hover {`,[`background-color: ${r.hoverColor};`,`border-color: ${r.hoverColor};`])),e.push(...a(`.btn-${r.name}-outlined {`,["background-color: transparent;",`border-color: ${r.baseColor};`,`color: ${r.baseColor};`])),e.push(...a(`.btn-${r.name}-outlined:hover {`,[`background-color: color-mix(in srgb, ${r.baseColor} 10%, transparent);`,`border-color: ${r.hoverColor};`,`color: ${r.hoverColor};`])),e.push(...a(`.btn-${r.name}-ghost {`,["background-color: transparent;","border-color: transparent;",`color: ${r.baseColor};`])),e.push(...a(`.btn-${r.name}-ghost:hover {`,[`background-color: color-mix(in srgb, ${r.baseColor} 12%, transparent);`,`color: ${r.hoverColor};`]));return e.push(...a(".input {",["width: 100%;","border-radius: 0.75rem;","border: 1px solid var(--color-input-border);","background-color: var(--color-input);","font-size: var(--text-body);","font-weight: var(--font-weight-body);","line-height: var(--text-body--line-height);","letter-spacing: var(--tracking-body);","color: var(--color-foreground);","transition-property: border-color, box-shadow, background-color;","transition-duration: 150ms;","transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);","outline: none;"])),e.push(...a(".input::placeholder {",["color: var(--color-muted);"])),e.push(...a(".input:focus-visible {",["border-color: var(--color-focus-ring);","box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-focus-ring) 25%, transparent);"])),e.push("}"),e}function y(){return B(u)}function k(e){if(!$(e))throw new Error("Invalid value at theme. Expected an object.");let r=e.version,o=e.colors,t=e.typography,n=e.themes;if(typeof r!="string")throw new Error("Invalid value at theme.version. Expected a string.");return Y(o),d(t,u.typography,"theme.typography"),d(n,u.themes,"theme.themes"),{version:r,colors:o,typography:t,themes:{light:n.light}}}function O(e){return[C,...Q(e),"",...Z(e),"",...ee(),S].join(`
3
+ `)}function P(e,r){let o=new RegExp(`${E(C)}[\\s\\S]*?${E(S)}`,"m");if(!o.test(e))throw new Error("Could not find theme block in globals.css.");return e.replace(o,r.trim())}async function R(e){return e.path&&e.type&&e.name&&e.designSystem?{path:e.path,type:e.type,websiteName:e.name,designSystem:e.designSystem}:{...await i.group({path:()=>i.text({message:"Where should we create your project?",placeholder:"./my-app",initialValue:e.path}),websiteName:()=>i.text({message:"What is your website name?",placeholder:"Studio",initialValue:e.name}),designSystem:()=>i.select({message:"Choose your Design System",initialValue:e.designSystem,options:[{value:"default",label:"saneprint Default",hint:"Ready-to-go premium tokens"},{value:"custom",label:"Custom (Enterprise Level 2)",hint:"Generate canonical theme.json"}]})},{onCancel:()=>{i.cancel("Operation cancelled."),process.exit(0)}}),type:"next"}}async function N(e){let r=re.resolve(process.cwd(),"theme.json"),o=y();if(b.existsSync(r))try{return k(await b.readJSON(r))}catch{}for(e.primary&&(o.colors.primary[500]=e.primary,o.colors.primary[600]=e.primary,o.themes.light.primary=e.primary,o.themes.light.primaryHover=e.primary),e.secondary&&(o.colors.secondary[500]=e.secondary,o.colors.secondary[600]=e.secondary,o.themes.light.secondary=e.secondary,o.themes.light.secondaryHover=e.secondary),await b.writeJSON(r,o,{spaces:2}),i.note(`I've created a canonical ${f.hex("#106D7C")("theme.json")} in your current directory.
4
+
5
+ Edit values only. Do not add, delete, or rename keys.
6
+ The default schema now includes ${f.hex("#106D7C")("tertiary")} color tokens and semantic roles out of the box.
7
+ This schema drives the generated Tailwind tokens, color roles, and button/input variants.`,f.hex("#106D7C")("Custom Theme"));;){await i.confirm({message:"Done filling theme.json? Click continue to proceed."})!==!0&&(i.cancel("Operation cancelled."),process.exit(0));try{return k(await b.readJSON(r))}catch(n){i.log.error(f.red(`Error: ${n.message||"Invalid JSON"}`))}}}import l from"fs-extra";import T from"path";async function H(e,r){let o=T.join(e,"package.json");if(!l.existsSync(o))return;let t=await l.readJSON(o);t.name=r.toLowerCase().replace(/\s+/g,"-"),await l.writeJSON(o,t,{spaces:2})}async function L(e,r){let o=T.join(e,"src/app/layout.tsx");if(!l.existsSync(o))return;let n=(await l.readFile(o,"utf-8")).replace(/const siteName = ".*";/,`const siteName = "${r}";`);await l.writeFile(o,n)}async function _(e,r){let o=T.join(e,"src/app/globals.css");if(!l.existsSync(o))return;let t=await l.readFile(o,"utf-8"),n=P(t,O(r));await l.writeFile(o,n)}import D from"fs-extra";import w from"path";import{fileURLToPath as oe}from"url";import{downloadTemplate as te}from"giget";var ne=oe(import.meta.url),ie=w.dirname(ne),ae={next:"next-template",mobile:"mobile-template"},se={next:"github:BuildSanely/saneprint-templates/next-template",mobile:"github:BuildSanely/saneprint-templates/mobile-template"};function ce(e){return w.resolve(ie,"../../../templates",ae[e])}function le(e){let r=e==="next"?"PIX_TEMPLATE_SOURCE_NEXT":"PIX_TEMPLATE_SOURCE_MOBILE";return process.env[r]?.trim()||se[e]}async function I(e,r){if(process.env.PIX_DEV==="true"){let t=ce(e);if(!D.existsSync(t))throw new Error(`Template not found at ${t}`);await D.copy(t,r,{filter:n=>{let s=w.basename(n);return!["node_modules",".next","dist",".turbo"].includes(s)}});return}let o=le(e);await te(o,{dir:r,force:!0})}async function A(e){console.log(`
8
+ ${p.bold(p.hex("#106D7C")("sane")+p.hex("#8D0D46")("print"))}`),console.log(p.hex("#F1F1F1").dim("Opinionated scaffolding for Next.js")),console.log(p.hex("#F1F1F1").dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(),c.intro(`${p.bgHex("#8D0D46").white(" saneprint ")} Modern Project Scaffolder`);let r=await R(e),o=y();r.designSystem==="custom"&&(o=await N(e));let t=c.spinner();t.start(`Setting up your ${r.type} project...`);let n=pe.resolve(process.cwd(),r.path);try{await I(r.type,n),await H(n,r.websiteName),await L(n,r.websiteName),await _(n,o),t.stop("Scaffolding complete!"),c.note(`Next steps:
9
+ cd ${r.path}
10
+ pnpm install
11
+ pnpm dev`,p.hex("#106D7C")("Success!")),c.outro(p.hex("#8D0D46")("Happy coding!"))}catch(s){t.stop("Scaffolding failed."),c.log.error(p.red(s.message||String(s))),process.exit(1)}}var F=new he;F.name("saneprint").description("Opinionated scaffolding for Next.js").version("1.0.0").option("-p, --path <path>","Path to create the project").option("-t, --type <type>","Project type (next, mobile)").option("-n, --name <name>","Website name").option("-ds, --design-system <system>","Design system (default, custom)").option("-pr, --primary <color>","Primary color").option("-sc, --secondary <color>","Secondary color").action(e=>{A(e)});F.parse();
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/prompts/init.ts","../src/constants/default-theme.ts","../src/utils/theme.ts","../src/utils/injection.ts","../src/utils/template-source.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport { initCommand } from \"./commands/init.js\";\nimport { CLIOptions } from \"./types/index.js\";\n\nconst program = new Command();\n\nprogram\n\t.name(\"saneprint\")\n\t.description(\"Opinionated scaffolding for Next.js\")\n\t.version(\"1.0.0\")\n\t.option(\"-p, --path <path>\", \"Path to create the project\")\n\t.option(\"-t, --type <type>\", \"Project type (next, mobile)\")\n\t.option(\"-n, --name <name>\", \"Website name\")\n\t.option(\"-ds, --design-system <system>\", \"Design system (default, custom)\")\n\t.option(\"-pr, --primary <color>\", \"Primary color\")\n\t.option(\"-sc, --secondary <color>\", \"Secondary color\")\n\t.action((options: CLIOptions) => {\n\t\tinitCommand(options);\n\t});\n\nprogram.parse();\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport path from \"path\";\nimport { CLIOptions, EnterpriseTheme } from \"../types/index.js\";\nimport { promptProjectConfig, promptEnterpriseTheme } from \"../prompts/init.js\";\nimport {\n\tinjectPackageMetadata,\n\tinjectLayoutMetadata,\n\tinjectEnterpriseTheme,\n} from \"../utils/injection.js\";\nimport { scaffoldProjectTemplate } from \"../utils/template-source.js\";\nimport { getDefaultTheme } from \"../utils/theme.js\";\n\nexport async function initCommand(options: CLIOptions) {\n\tconsole.log(\n\t\t`\\n${chalk.bold(chalk.hex(\"#106D7C\")(\"sane\") + chalk.hex(\"#8D0D46\")(\"print\"))}`,\n\t);\n\tconsole.log(chalk.hex(\"#F1F1F1\").dim(\"Opinionated scaffolding for Next.js\"));\n\tconsole.log(\n\t\tchalk\n\t\t\t.hex(\"#F1F1F1\")\n\t\t\t.dim(\"──────────────────────────────────────────────────\"),\n\t);\n\tconsole.log();\n\n\tp.intro(\n\t\t`${chalk.bgHex(\"#8D0D46\").white(\" saneprint \")} Modern Project Scaffolder`,\n\t);\n\tconst project = await promptProjectConfig(options);\n\n\t// 2. Handle Enterprise Level 2 Design System\n\tlet enterpriseTheme: EnterpriseTheme = getDefaultTheme();\n\tif (project.designSystem === \"custom\") {\n\t\tenterpriseTheme = await promptEnterpriseTheme(options);\n\t}\n\n\t// 3. Scaffolding\n\tconst s = p.spinner();\n\ts.start(`Setting up your ${project.type} project...`);\n\n\tconst targetPath = path.resolve(process.cwd(), project.path);\n\n\ttry {\n\t\tawait scaffoldProjectTemplate(project.type, targetPath);\n\n\t\t// 4. Injection\n\t\tawait injectPackageMetadata(targetPath, project.websiteName);\n\t\tawait injectLayoutMetadata(targetPath, project.websiteName);\n\n\t\tawait injectEnterpriseTheme(targetPath, enterpriseTheme);\n\n\t\ts.stop(\"Scaffolding complete!\");\n\n\t\tp.note(\n\t\t\t`Next steps:\\n cd ${project.path}\\n pnpm install\\n pnpm dev`,\n\t\t\tchalk.hex(\"#106D7C\")(\"Success!\"),\n\t\t);\n\t\tp.outro(chalk.hex(\"#8D0D46\")(\"Happy coding!\"));\n\t} catch (err: any) {\n\t\ts.stop(\"Scaffolding failed.\");\n\t\tp.log.error(chalk.red(err.message || String(err)));\n\t\tprocess.exit(1);\n\t}\n}\n","import * as p from \"@clack/prompts\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport path from \"path\";\nimport { ProjectConfig, EnterpriseTheme, CLIOptions } from \"../types/index.js\";\nimport { getDefaultTheme, validateTheme } from \"../utils/theme.js\";\n\n/**\n * Main project configuration prompts\n */\nexport async function promptProjectConfig(\n\toptions: CLIOptions,\n): Promise<ProjectConfig> {\n\tif (options.path && options.type && options.name && options.designSystem) {\n\t\treturn {\n\t\t\tpath: options.path,\n\t\t\ttype: options.type as any,\n\t\t\twebsiteName: options.name,\n\t\t\tdesignSystem: options.designSystem as any,\n\t\t};\n\t}\n\n\tconst group = (await p.group<Omit<ProjectConfig, \"type\">>(\n\t\t{\n\t\t\tpath: () =>\n\t\t\t\tp.text({\n\t\t\t\t\tmessage: \"Where should we create your project?\",\n\t\t\t\t\tplaceholder: \"./my-app\",\n\t\t\t\t\tinitialValue: options.path,\n\t\t\t\t}) as any,\n\t\t\twebsiteName: () =>\n\t\t\t\tp.text({\n\t\t\t\t\tmessage: \"What is your website name?\",\n\t\t\t\t\tplaceholder: \"Studio\",\n\t\t\t\t\tinitialValue: options.name,\n\t\t\t\t}) as any,\n\t\t\t/*\n\t\t\ttype: () =>\n\t\t\t\tp.select({\n\t\t\t\t\tmessage: \"What are you building today?\",\n\t\t\t\t\tinitialValue: options.type,\n\t\t\t\t\toptions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvalue: \"next\",\n\t\t\t\t\t\t\tlabel: \"Next.js (Web)\",\n\t\t\t\t\t\t\thint: \"Production-grade App Router\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvalue: \"mobile\",\n\t\t\t\t\t\t\tlabel: \"React Native (Mobile)\",\n\t\t\t\t\t\t\thint: \"Expo Managed Workflow\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t}) as any,\n\t\t\t*/\n\t\t\tdesignSystem: () =>\n\t\t\t\tp.select({\n\t\t\t\t\tmessage: \"Choose your Design System\",\n\t\t\t\t\tinitialValue: options.designSystem,\n\t\t\t\t\toptions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvalue: \"default\",\n\t\t\t\t\t\t\tlabel: \"saneprint Default\",\n\t\t\t\t\t\t\thint: \"Ready-to-go premium tokens\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvalue: \"custom\",\n\t\t\t\t\t\t\tlabel: \"Custom (Enterprise Level 2)\",\n\t\t\t\t\t\t\thint: \"Generate canonical theme.json\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t}) as any,\n\t\t},\n\t\t{\n\t\t\tonCancel: () => {\n\t\t\t\tp.cancel(\"Operation cancelled.\");\n\t\t\t\tprocess.exit(0);\n\t\t\t},\n\t\t},\n\t)) as any;\n\n\treturn { ...group, type: \"next\" };\n}\n\n/**\n * Creates the canonical theme.json and waits for the user to edit it.\n */\nexport async function promptEnterpriseTheme(\n\toptions: CLIOptions,\n): Promise<EnterpriseTheme> {\n\tconst themePath = path.resolve(process.cwd(), \"theme.json\");\n\tconst defaultTheme = getDefaultTheme();\n\n\tif (fs.existsSync(themePath)) {\n\t\ttry {\n\t\t\treturn validateTheme(await fs.readJSON(themePath));\n\t\t} catch {\n\t\t\t// Fall through to overwrite with the canonical schema.\n\t\t}\n\t}\n\n\tif (options.primary) {\n\t\tdefaultTheme.colors.primary[\"500\"] = options.primary;\n\t\tdefaultTheme.colors.primary[\"600\"] = options.primary;\n\t\tdefaultTheme.themes.light.primary = options.primary;\n\t\tdefaultTheme.themes.light.primaryHover = options.primary;\n\t}\n\n\tif (options.secondary) {\n\t\tdefaultTheme.colors.secondary[\"500\"] = options.secondary;\n\t\tdefaultTheme.colors.secondary[\"600\"] = options.secondary;\n\t\tdefaultTheme.themes.light.secondary = options.secondary;\n\t\tdefaultTheme.themes.light.secondaryHover = options.secondary;\n\t}\n\n\tawait fs.writeJSON(themePath, defaultTheme, { spaces: 2 });\n\n\tp.note(\n\t\t`I've created a canonical ${chalk.hex(\"#106D7C\")(\"theme.json\")} in your current directory.\\n\\n` +\n\t\t\t`Edit values only. Do not add, delete, or rename keys.\\n` +\n\t\t\t`The default schema now includes ${chalk.hex(\"#106D7C\")(\"tertiary\")} color tokens and semantic roles out of the box.\\n` +\n\t\t\t`This schema drives the generated Tailwind tokens, color roles, and button/input variants.`,\n\t\tchalk.hex(\"#106D7C\")(\"Custom Theme\"),\n\t);\n\n\twhile (true) {\n\t\tconst ready = await p.confirm({\n\t\t\tmessage: \"Done filling theme.json? Click continue to proceed.\",\n\t\t});\n\t\tif (ready !== true) {\n\t\t\tp.cancel(\"Operation cancelled.\");\n\t\t\tprocess.exit(0);\n\t\t}\n\n\t\ttry {\n\t\t\treturn validateTheme(await fs.readJSON(themePath));\n\t\t} catch (err: any) {\n\t\t\tp.log.error(chalk.red(`Error: ${err.message || \"Invalid JSON\"}`));\n\t\t}\n\t}\n}\n","import { EnterpriseTheme } from \"../types/index.js\";\n\nexport const DEFAULT_THEME: EnterpriseTheme = {\n\tversion: \"1.0.0\",\n\tcolors: {\n\t\tprimary: {\n\t\t\t\"50\": \"oklch(0.985 0.015 180)\", // #f0fdfa\n\t\t\t\"100\": \"oklch(0.97 0.04 180)\", // #ccfbf1\n\t\t\t\"200\": \"oklch(0.94 0.07 180)\", // #99f6e4\n\t\t\t\"300\": \"oklch(0.89 0.1 180)\", // #5eead4\n\t\t\t\"400\": \"oklch(0.79 0.13 180)\", // #2dd4bf\n\t\t\t\"500\": \"oklch(0.7 0.14 180)\", // #14b8a6 - Teal primary\n\t\t\t\"600\": \"oklch(0.59 0.13 185)\", // #0d9488\n\t\t\t\"700\": \"oklch(0.5 0.11 190)\", // #0f766e\n\t\t\t\"800\": \"oklch(0.41 0.09 190)\", // #115e59\n\t\t\t\"900\": \"oklch(0.35 0.07 195)\", // #134e4a\n\t\t},\n\t\tsecondary: {\n\t\t\t\"50\": \"oklch(0.98 0.01 200)\",\n\t\t\t\"100\": \"oklch(0.95 0.02 200)\",\n\t\t\t\"200\": \"oklch(0.88 0.04 200)\",\n\t\t\t\"300\": \"oklch(0.8 0.06 200)\",\n\t\t\t\"400\": \"oklch(0.7 0.08 200)\",\n\t\t\t\"500\": \"oklch(0.6 0.09 200)\",\n\t\t\t\"600\": \"oklch(0.5 0.08 200)\",\n\t\t\t\"700\": \"oklch(0.4 0.07 200)\",\n\t\t\t\"800\": \"oklch(0.3 0.06 200)\",\n\t\t\t\"900\": \"oklch(0.2 0.05 200)\",\n\t\t},\n\t\ttertiary: {\n\t\t\t\"50\": \"oklch(0.97 0.02 310)\",\n\t\t\t\"100\": \"oklch(0.93 0.04 310)\",\n\t\t\t\"200\": \"oklch(0.87 0.08 310)\",\n\t\t\t\"300\": \"oklch(0.79 0.13 310)\",\n\t\t\t\"400\": \"oklch(0.7 0.18 310)\",\n\t\t\t\"500\": \"oklch(0.62 0.22 310)\",\n\t\t\t\"600\": \"oklch(0.54 0.2 310)\",\n\t\t\t\"700\": \"oklch(0.46 0.17 310)\",\n\t\t\t\"800\": \"oklch(0.38 0.14 310)\",\n\t\t\t\"900\": \"oklch(0.3 0.1 310)\",\n\t\t},\n\t\tneutral: {\n\t\t\t\"0\": \"#ffffff\",\n\t\t\t\"50\": \"oklch(0.99 0 0)\", // #fafafa\n\t\t\t\"100\": \"oklch(0.97 0 0)\", // #f5f5f5\n\t\t\t\"200\": \"oklch(0.92 0 0)\", // #e5e5e5\n\t\t\t\"300\": \"oklch(0.86 0 0)\", // #d4d4d4\n\t\t\t\"400\": \"oklch(0.68 0 0)\", // #a3a3a3\n\t\t\t\"500\": \"oklch(0.52 0 0)\", // #737373\n\t\t\t\"600\": \"oklch(0.38 0 0)\", // #525252\n\t\t\t\"700\": \"oklch(0.3 0 0)\", // #404040\n\t\t\t\"800\": \"oklch(0.19 0 0)\", // #262626\n\t\t\t\"900\": \"oklch(0.13 0 0)\", // #171717\n\t\t\t\"1000\": \"#000000\",\n\t\t},\n\t\tdanger: {\n\t\t\t\"500\": \"oklch(0.628 0.218 29)\", // #ef4444\n\t\t\t\"600\": \"oklch(0.55 0.2 29)\",\n\t\t},\n\t\tsuccess: {\n\t\t\t\"500\": \"oklch(0.698 0.176 142)\", // #22c55e\n\t\t\t\"600\": \"oklch(0.6 0.16 142)\",\n\t\t},\n\t\twarning: {\n\t\t\t\"500\": \"oklch(0.705 0.15 65)\", // #f59e0b\n\t\t\t\"600\": \"oklch(0.62 0.14 65)\",\n\t\t},\n\t\tinfo: {\n\t\t\t\"500\": \"oklch(0.596 0.182 255)\", // #3b82f6\n\t\t\t\"600\": \"oklch(0.52 0.17 255)\",\n\t\t},\n\t},\n\ttypography: {\n\t\tfontFamily: {\n\t\t\tsans: \"var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif\",\n\t\t\tmono: \"var(--font-geist-mono), ui-monospace, monospace\",\n\t\t},\n\t\tstyles: {\n\t\t\theading1: {\n\t\t\t\tsize: \"48px\",\n\t\t\t\tweight: \"700\",\n\t\t\t\tlineHeight: \"1.1\",\n\t\t\t\tletterSpacing: \"-0.02em\",\n\t\t\t},\n\t\t\theading2: {\n\t\t\t\tsize: \"36px\",\n\t\t\t\tweight: \"700\",\n\t\t\t\tlineHeight: \"1.2\",\n\t\t\t\tletterSpacing: \"-0.01em\",\n\t\t\t},\n\t\t\theading3: {\n\t\t\t\tsize: \"30px\",\n\t\t\t\tweight: \"700\",\n\t\t\t\tlineHeight: \"1.25\",\n\t\t\t\tletterSpacing: \"-0.01em\",\n\t\t\t},\n\t\t\theading4: {\n\t\t\t\tsize: \"24px\",\n\t\t\t\tweight: \"600\",\n\t\t\t\tlineHeight: \"1.3\",\n\t\t\t\tletterSpacing: \"-0.005em\",\n\t\t\t},\n\t\t\theading5: {\n\t\t\t\tsize: \"20px\",\n\t\t\t\tweight: \"600\",\n\t\t\t\tlineHeight: \"1.35\",\n\t\t\t\tletterSpacing: \"0\",\n\t\t\t},\n\t\t\theading6: {\n\t\t\t\tsize: \"18px\",\n\t\t\t\tweight: \"600\",\n\t\t\t\tlineHeight: \"1.4\",\n\t\t\t\tletterSpacing: \"0\",\n\t\t\t},\n\t\t\tbody: {\n\t\t\t\tsize: \"16px\",\n\t\t\t\tweight: \"400\",\n\t\t\t\tlineHeight: \"1.5\",\n\t\t\t\tletterSpacing: \"0\",\n\t\t\t},\n\t\t\tbodySm: {\n\t\t\t\tsize: \"14px\",\n\t\t\t\tweight: \"400\",\n\t\t\t\tlineHeight: \"1.5\",\n\t\t\t\tletterSpacing: \"0\",\n\t\t\t},\n\t\t\tlabel: {\n\t\t\t\tsize: \"14px\",\n\t\t\t\tweight: \"600\",\n\t\t\t\tlineHeight: \"1.4\",\n\t\t\t\tletterSpacing: \"0.01em\",\n\t\t\t},\n\t\t\tlabelSm: {\n\t\t\t\tsize: \"12px\",\n\t\t\t\tweight: \"600\",\n\t\t\t\tlineHeight: \"1.35\",\n\t\t\t\tletterSpacing: \"0.01em\",\n\t\t\t},\n\t\t\tcaption: {\n\t\t\t\tsize: \"12px\",\n\t\t\t\tweight: \"400\",\n\t\t\t\tlineHeight: \"1.4\",\n\t\t\t\tletterSpacing: \"0\",\n\t\t\t},\n\t\t},\n\t},\n\tthemes: {\n\t\tlight: {\n\t\t\tbackground: \"{colors.neutral.50}\",\n\t\t\tsurface: \"{colors.neutral.0}\",\n\t\t\ttext: \"{colors.neutral.900}\",\n\t\t\ttextMuted: \"{colors.neutral.600}\",\n\t\t\tborder: \"{colors.neutral.200}\",\n\t\t\tprimary: \"{colors.primary.500}\",\n\t\t\tprimaryHover: \"{colors.primary.600}\",\n\t\t\tsecondary: \"{colors.secondary.500}\",\n\t\t\tsecondaryHover: \"{colors.secondary.600}\",\n\t\t\ttertiary: \"{colors.tertiary.500}\",\n\t\t\ttertiaryHover: \"{colors.tertiary.600}\",\n\t\t\tdanger: \"{colors.danger.500}\",\n\t\t\tdangerHover: \"{colors.danger.600}\",\n\t\t\tonPrimary: \"{colors.neutral.0}\",\n\t\t\tonSecondary: \"{colors.neutral.0}\",\n\t\t\tonTertiary: \"{colors.neutral.0}\",\n\t\t\tonDanger: \"{colors.neutral.0}\",\n\t\t\tinputBackground: \"{colors.neutral.0}\",\n\t\t\tinputBorder: \"{colors.neutral.300}\",\n\t\t\tinputFocusRing: \"{colors.primary.500}\",\n\t\t},\n\t},\n};\n","import { DEFAULT_THEME } from \"../constants/default-theme.js\";\nimport {\n\tEnterpriseTheme,\n\tThemeRoles,\n\tTypographyStyle,\n} from \"../types/index.js\";\n\nconst THEME_START = \"/* theme start */\";\nconst THEME_END = \"/* theme end */\";\n\nconst THEME_ROLE_VARIABLES = {\n\tbackground: \"background\",\n\tsurface: \"surface\",\n\ttext: \"foreground\",\n\ttextMuted: \"muted\",\n\tborder: \"border\",\n\tprimary: \"brand\",\n\tprimaryHover: \"brand-hover\",\n\tsecondary: \"accent\",\n\tsecondaryHover: \"accent-hover\",\n\ttertiary: \"tertiary\",\n\ttertiaryHover: \"tertiary-hover\",\n\tdanger: \"danger\",\n\tdangerHover: \"danger-hover\",\n\tonPrimary: \"on-brand\",\n\tonSecondary: \"on-accent\",\n\tonTertiary: \"on-tertiary\",\n\tonDanger: \"on-danger\",\n\tinputBackground: \"input\",\n\tinputBorder: \"input-border\",\n\tinputFocusRing: \"focus-ring\",\n} satisfies Record<keyof ThemeRoles, string>;\n\nconst BUTTON_INTENTS = [\n\t{\n\t\tname: \"primary\",\n\t\tbaseColor: \"var(--color-brand)\",\n\t\thoverColor: \"var(--color-brand-hover)\",\n\t\tforegroundColor: \"var(--color-on-brand)\",\n\t},\n\t{\n\t\tname: \"secondary\",\n\t\tbaseColor: \"var(--color-accent)\",\n\t\thoverColor: \"var(--color-accent-hover)\",\n\t\tforegroundColor: \"var(--color-on-accent)\",\n\t},\n\t{\n\t\tname: \"tertiary\",\n\t\tbaseColor: \"var(--color-tertiary)\",\n\t\thoverColor: \"var(--color-tertiary-hover)\",\n\t\tforegroundColor: \"var(--color-on-tertiary)\",\n\t},\n\t{\n\t\tname: \"danger\",\n\t\tbaseColor: \"var(--color-danger)\",\n\t\thoverColor: \"var(--color-danger-hover)\",\n\t\tforegroundColor: \"var(--color-on-danger)\",\n\t},\n] as const;\n\nconst TYPOGRAPHY_CLASS_NAMES = {\n\theading1: \"heading-1\",\n\theading2: \"heading-2\",\n\theading3: \"heading-3\",\n\theading4: \"heading-4\",\n\theading5: \"heading-5\",\n\theading6: \"heading-6\",\n\tbody: \"body\",\n\tbodySm: \"body-sm\",\n\tlabel: \"label\",\n\tlabelSm: \"label-sm\",\n\tcaption: \"caption\",\n} as const;\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction cloneValue<T>(value: T): T {\n\treturn JSON.parse(JSON.stringify(value)) as T;\n}\n\nfunction formatNumber(value: number): string {\n\treturn Number.parseFloat(value.toFixed(4)).toString();\n}\n\nfunction pxToRem(value: string): string {\n\treturn value.replace(/(-?\\d*\\.?\\d+)px\\b/g, (_, rawNumber) => {\n\t\tconst remValue = Number.parseFloat(rawNumber) / 16;\n\t\treturn `${formatNumber(remValue)}rem`;\n\t});\n}\n\nfunction normalizeValue(value: string): string {\n\treturn pxToRem(value);\n}\n\nfunction assertObjectShape(\n\tvalue: unknown,\n\tschema: unknown,\n\tcurrentPath: string,\n): void {\n\tif (schema === null || typeof schema !== \"object\" || Array.isArray(schema)) {\n\t\tif (typeof value !== typeof schema) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid value at ${currentPath}. Expected ${typeof schema}.`,\n\t\t\t);\n\t\t}\n\t\treturn;\n\t}\n\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(`Invalid value at ${currentPath}. Expected an object.`);\n\t}\n\n\tconst schemaObject = schema as Record<string, unknown>;\n\tconst valueObject = value as Record<string, unknown>;\n\tconst schemaKeys = Object.keys(schemaObject).sort();\n\tconst valueKeys = Object.keys(valueObject).sort();\n\n\tif (\n\t\tschemaKeys.length !== valueKeys.length ||\n\t\tschemaKeys.some((key, index) => key !== valueKeys[index])\n\t) {\n\t\tthrow new Error(\n\t\t\t`Theme schema mismatch at ${currentPath}. Edit values only; do not add or remove keys.`,\n\t\t);\n\t}\n\n\tfor (const key of schemaKeys) {\n\t\tconst nextPath =\n\t\t\tcurrentPath === \"theme\" ? `theme.${key}` : `${currentPath}.${key}`;\n\t\tassertObjectShape(valueObject[key], schemaObject[key], nextPath);\n\t}\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction assertStringRecord(value: unknown, currentPath: string): void {\n\tif (!isRecord(value)) {\n\t\tthrow new Error(`Invalid value at ${currentPath}. Expected an object.`);\n\t}\n\n\tfor (const [key, entry] of Object.entries(value)) {\n\t\tif (typeof entry !== \"string\") {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid value at ${currentPath}.${key}. Expected a string.`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction assertThemeColorScales(colors: unknown): void {\n\tif (!isRecord(colors)) {\n\t\tthrow new Error(\"Invalid value at theme.colors. Expected an object.\");\n\t}\n\tassertObjectShape(colors, DEFAULT_THEME.colors, \"theme.colors\");\n}\n\nfunction themeLine(name: string, value: string): string {\n\treturn ` ${name}: ${value};`;\n}\n\nfunction cssRuleLines(selector: string, declarations: string[]): string[] {\n\treturn [\n\t\tselector,\n\t\t...declarations.map((declaration) => ` ${declaration}`),\n\t\t\"}\",\n\t];\n}\n\nfunction componentRuleLines(\n\tselector: string,\n\tdeclarations: string[],\n): string[] {\n\treturn [\n\t\t` ${selector}`,\n\t\t...declarations.map((declaration) => ` ${declaration}`),\n\t\t\" }\",\n\t];\n}\n\nfunction resolvePath(pathString: string, theme: EnterpriseTheme): string {\n\tconst keys = pathString.split(\".\");\n\tlet current: unknown = theme;\n\n\tfor (const key of keys) {\n\t\tif (\n\t\t\tcurrent === null ||\n\t\t\ttypeof current !== \"object\" ||\n\t\t\t!(key in (current as Record<string, unknown>))\n\t\t) {\n\t\t\tthrow new Error(`Could not resolve token reference {${pathString}}.`);\n\t\t}\n\n\t\tcurrent = (current as Record<string, unknown>)[key];\n\t}\n\n\tif (typeof current !== \"string\") {\n\t\tthrow new Error(\n\t\t\t`Token reference {${pathString}} did not resolve to a string value.`,\n\t\t);\n\t}\n\n\treturn current;\n}\n\nexport function resolveToken(value: string, theme: EnterpriseTheme): string {\n\treturn value.replace(/\\{([^}]+)\\}/g, (_, pathString) => {\n\t\treturn resolveToken(resolvePath(pathString, theme), theme);\n\t});\n}\n\nfunction resolveAndNormalize(value: string, theme: EnterpriseTheme): string {\n\treturn normalizeValue(resolveToken(value, theme));\n}\n\nfunction getRoleCssVariable(pathString: string): string | null {\n\tconst parts = pathString.split(\".\");\n\tif (parts[0] !== \"themes\" || parts.length !== 3) {\n\t\treturn null;\n\t}\n\n\tconst roleName = parts[2] as keyof ThemeRoles;\n\tconst cssName = THEME_ROLE_VARIABLES[roleName];\n\treturn cssName ? `var(--color-${cssName})` : null;\n}\n\nfunction getPaletteCssVariable(pathString: string): string | null {\n\tconst parts = pathString.split(\".\");\n\tif (parts[0] !== \"colors\" || parts.length !== 3) {\n\t\treturn null;\n\t}\n\n\treturn `var(--color-${parts[1]}-${parts[2]})`;\n}\n\nfunction resolveCssValue(value: string, theme: EnterpriseTheme): string {\n\treturn normalizeValue(\n\t\tvalue.replace(/\\{([^}]+)\\}/g, (_, pathString) => {\n\t\t\treturn (\n\t\t\t\tgetRoleCssVariable(pathString) ??\n\t\t\t\tgetPaletteCssVariable(pathString) ??\n\t\t\t\tresolveToken(`{${pathString}}`, theme)\n\t\t\t);\n\t\t}),\n\t);\n}\n\nfunction pushPaletteVariables(lines: string[], theme: EnterpriseTheme): void {\n\tfor (const [familyName, scale] of Object.entries(theme.colors)) {\n\t\tfor (const [tokenName, tokenValue] of Object.entries(\n\t\t\tscale as Record<string, string>,\n\t\t)) {\n\t\t\tlines.push(\n\t\t\t\tthemeLine(\n\t\t\t\t\t`--color-${familyName}-${tokenName}`,\n\t\t\t\t\tresolveAndNormalize(tokenValue, theme),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction pushRoleVariables(\n\tlines: string[],\n\troles: ThemeRoles,\n\ttheme: EnterpriseTheme,\n): void {\n\tfor (const [roleName, cssName] of Object.entries(THEME_ROLE_VARIABLES)) {\n\t\tlines.push(\n\t\t\tthemeLine(\n\t\t\t\t`--color-${cssName}`,\n\t\t\t\tresolveAndNormalize(roles[roleName as keyof ThemeRoles], theme),\n\t\t\t),\n\t\t);\n\t}\n}\n\nfunction pushTypographyVariables(\n\tlines: string[],\n\ttheme: EnterpriseTheme,\n): void {\n\tlines.push(\n\t\tthemeLine(\n\t\t\t\"--font-sans\",\n\t\t\tresolveAndNormalize(theme.typography.fontFamily.sans, theme),\n\t\t),\n\t);\n\tlines.push(\n\t\tthemeLine(\n\t\t\t\"--font-mono\",\n\t\t\tresolveAndNormalize(theme.typography.fontFamily.mono, theme),\n\t\t),\n\t);\n\n\tfor (const [tokenName, style] of Object.entries(theme.typography.styles)) {\n\t\tconst typedStyle = style as TypographyStyle;\n\t\tlines.push(\n\t\t\tthemeLine(\n\t\t\t\t`--text-${tokenName}`,\n\t\t\t\tresolveAndNormalize(typedStyle.size, theme),\n\t\t\t),\n\t\t);\n\t\tlines.push(\n\t\t\tthemeLine(\n\t\t\t\t`--text-${tokenName}--line-height`,\n\t\t\t\tresolveAndNormalize(typedStyle.lineHeight, theme),\n\t\t\t),\n\t\t);\n\t\tlines.push(\n\t\t\tthemeLine(\n\t\t\t\t`--tracking-${tokenName}`,\n\t\t\t\tresolveAndNormalize(typedStyle.letterSpacing, theme),\n\t\t\t),\n\t\t);\n\t\tlines.push(\n\t\t\tthemeLine(\n\t\t\t\t`--font-weight-${tokenName}`,\n\t\t\t\tresolveAndNormalize(typedStyle.weight, theme),\n\t\t\t),\n\t\t);\n\t}\n}\n\nfunction buildThemeInlineLines(theme: EnterpriseTheme): string[] {\n\tconst lines = [\"@theme inline {\"];\n\tpushPaletteVariables(lines, theme);\n\tpushRoleVariables(lines, theme.themes.light, theme);\n\tpushTypographyVariables(lines, theme);\n\tlines.push(\"}\");\n\treturn lines;\n}\n\nfunction buildTypographyUtilities(theme: EnterpriseTheme): string[] {\n\tconst lines: string[] = [];\n\n\tfor (const tokenName of Object.keys(theme.typography.styles) as Array<\n\t\tkeyof typeof TYPOGRAPHY_CLASS_NAMES\n\t>) {\n\t\tconst className = TYPOGRAPHY_CLASS_NAMES[tokenName];\n\t\tlines.push(\n\t\t\t`@utility ${className} {`,\n\t\t\t` font-size: var(--text-${tokenName});`,\n\t\t\t` font-weight: var(--font-weight-${tokenName});`,\n\t\t\t` line-height: var(--text-${tokenName}--line-height);`,\n\t\t\t` letter-spacing: var(--tracking-${tokenName});`,\n\t\t\t\"}\",\n\t\t);\n\t}\n\n\treturn lines;\n}\n\nfunction buildButtonVariantLines(): string[] {\n\tconst lines: string[] = [\"@layer components {\"];\n\n\tlines.push(\n\t\t...componentRuleLines(\".btn {\", [\n\t\t\t\"display: inline-flex;\",\n\t\t\t\"align-items: center;\",\n\t\t\t\"justify-content: center;\",\n\t\t\t\"gap: 0.5rem;\",\n\t\t\t\"border-radius: 0.75rem;\",\n\t\t\t\"border: 1px solid transparent;\",\n\t\t\t\"font-size: var(--text-label);\",\n\t\t\t\"font-weight: var(--font-weight-label);\",\n\t\t\t\"line-height: var(--text-label--line-height);\",\n\t\t\t\"letter-spacing: var(--tracking-label);\",\n\t\t\t\"transition-property: background-color, border-color, color, box-shadow, opacity;\",\n\t\t\t\"transition-duration: 150ms;\",\n\t\t\t\"transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\",\n\t\t\t\"cursor: pointer;\",\n\t\t]),\n\t);\n\tlines.push(\n\t\t...componentRuleLines(\".btn:focus-visible {\", [\n\t\t\t\"outline: none;\",\n\t\t\t\"box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-focus-ring) 35%, transparent);\",\n\t\t]),\n\t);\n\tlines.push(\n\t\t...componentRuleLines(\".btn:disabled {\", [\n\t\t\t\"cursor: not-allowed;\",\n\t\t\t\"opacity: 0.55;\",\n\t\t]),\n\t);\n\n\tfor (const intent of BUTTON_INTENTS) {\n\t\tlines.push(\n\t\t\t...componentRuleLines(`.btn-${intent.name}-filled {`, [\n\t\t\t\t`background-color: ${intent.baseColor};`,\n\t\t\t\t`border-color: ${intent.baseColor};`,\n\t\t\t\t`color: ${intent.foregroundColor};`,\n\t\t\t]),\n\t\t);\n\t\tlines.push(\n\t\t\t...componentRuleLines(`.btn-${intent.name}-filled:hover {`, [\n\t\t\t\t`background-color: ${intent.hoverColor};`,\n\t\t\t\t`border-color: ${intent.hoverColor};`,\n\t\t\t]),\n\t\t);\n\t\tlines.push(\n\t\t\t...componentRuleLines(`.btn-${intent.name}-outlined {`, [\n\t\t\t\t\"background-color: transparent;\",\n\t\t\t\t`border-color: ${intent.baseColor};`,\n\t\t\t\t`color: ${intent.baseColor};`,\n\t\t\t]),\n\t\t);\n\t\tlines.push(\n\t\t\t...componentRuleLines(`.btn-${intent.name}-outlined:hover {`, [\n\t\t\t\t`background-color: color-mix(in srgb, ${intent.baseColor} 10%, transparent);`,\n\t\t\t\t`border-color: ${intent.hoverColor};`,\n\t\t\t\t`color: ${intent.hoverColor};`,\n\t\t\t]),\n\t\t);\n\t\tlines.push(\n\t\t\t...componentRuleLines(`.btn-${intent.name}-ghost {`, [\n\t\t\t\t\"background-color: transparent;\",\n\t\t\t\t\"border-color: transparent;\",\n\t\t\t\t`color: ${intent.baseColor};`,\n\t\t\t]),\n\t\t);\n\t\tlines.push(\n\t\t\t...componentRuleLines(`.btn-${intent.name}-ghost:hover {`, [\n\t\t\t\t`background-color: color-mix(in srgb, ${intent.baseColor} 12%, transparent);`,\n\t\t\t\t`color: ${intent.hoverColor};`,\n\t\t\t]),\n\t\t);\n\t}\n\n\tlines.push(\n\t\t...componentRuleLines(\".input {\", [\n\t\t\t\"width: 100%;\",\n\t\t\t\"border-radius: 0.75rem;\",\n\t\t\t\"border: 1px solid var(--color-input-border);\",\n\t\t\t\"background-color: var(--color-input);\",\n\t\t\t\"font-size: var(--text-body);\",\n\t\t\t\"font-weight: var(--font-weight-body);\",\n\t\t\t\"line-height: var(--text-body--line-height);\",\n\t\t\t\"letter-spacing: var(--tracking-body);\",\n\t\t\t\"color: var(--color-foreground);\",\n\t\t\t\"transition-property: border-color, box-shadow, background-color;\",\n\t\t\t\"transition-duration: 150ms;\",\n\t\t\t\"transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\",\n\t\t\t\"outline: none;\",\n\t\t]),\n\t);\n\tlines.push(\n\t\t...componentRuleLines(\".input::placeholder {\", [\n\t\t\t\"color: var(--color-muted);\",\n\t\t]),\n\t);\n\tlines.push(\n\t\t...componentRuleLines(\".input:focus-visible {\", [\n\t\t\t\"border-color: var(--color-focus-ring);\",\n\t\t\t\"box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-focus-ring) 25%, transparent);\",\n\t\t]),\n\t);\n\n\tlines.push(\"}\");\n\treturn lines;\n}\n\nexport function getDefaultTheme(): EnterpriseTheme {\n\treturn cloneValue(DEFAULT_THEME);\n}\n\nexport function validateTheme(theme: unknown): EnterpriseTheme {\n\tif (!isRecord(theme)) {\n\t\tthrow new Error(\"Invalid value at theme. Expected an object.\");\n\t}\n\n\tconst version = theme.version;\n\tconst colors = theme.colors;\n\tconst typography = theme.typography;\n\tconst themes = theme.themes;\n\n\tif (typeof version !== \"string\") {\n\t\tthrow new Error(\"Invalid value at theme.version. Expected a string.\");\n\t}\n\n\tassertThemeColorScales(colors);\n\tassertObjectShape(\n\t\ttypography,\n\t\tDEFAULT_THEME.typography,\n\t\t\"theme.typography\",\n\t);\n\tassertObjectShape(themes, DEFAULT_THEME.themes, \"theme.themes\");\n\n\treturn {\n\t\tversion,\n\t\tcolors: colors as EnterpriseTheme[\"colors\"],\n\t\ttypography: typography as EnterpriseTheme[\"typography\"],\n\t\tthemes: {\n\t\t\tlight: (themes as EnterpriseTheme[\"themes\"]).light,\n\t\t},\n\t};\n}\n\nexport function generateThemeCss(theme: EnterpriseTheme): string {\n\treturn [\n\t\tTHEME_START,\n\t\t...buildThemeInlineLines(theme),\n\t\t\"\",\n\t\t...buildTypographyUtilities(theme),\n\t\t\"\",\n\t\t...buildButtonVariantLines(),\n\t\tTHEME_END,\n\t].join(\"\\n\");\n}\n\nexport function replaceThemeBlock(content: string, themeCss: string): string {\n\tconst pattern = new RegExp(\n\t\t`${escapeRegExp(THEME_START)}[\\\\s\\\\S]*?${escapeRegExp(THEME_END)}`,\n\t\t\"m\",\n\t);\n\n\tif (!pattern.test(content)) {\n\t\tthrow new Error(\"Could not find theme block in globals.css.\");\n\t}\n\n\treturn content.replace(pattern, themeCss.trim());\n}\n","import fs from \"fs-extra\";\nimport path from \"path\";\nimport { EnterpriseTheme } from \"../types/index.js\";\nimport { generateThemeCss, replaceThemeBlock } from \"./theme.js\";\n\nexport async function injectPackageMetadata(\n\ttargetPath: string,\n\twebsiteName: string,\n) {\n\tconst packagePath = path.join(targetPath, \"package.json\");\n\tif (!fs.existsSync(packagePath)) {\n\t\treturn;\n\t}\n\n\tconst packageJson = await fs.readJSON(packagePath);\n\tpackageJson.name = websiteName.toLowerCase().replace(/\\s+/g, \"-\");\n\tawait fs.writeJSON(packagePath, packageJson, { spaces: 2 });\n}\n\nexport async function injectLayoutMetadata(\n\ttargetPath: string,\n\twebsiteName: string,\n) {\n\tconst layoutPath = path.join(targetPath, \"src/app/layout.tsx\");\n\tif (!fs.existsSync(layoutPath)) {\n\t\treturn;\n\t}\n\n\tconst currentContent = await fs.readFile(layoutPath, \"utf-8\");\n\tconst nextContent = currentContent.replace(\n\t\t/const siteName = \".*\";/,\n\t\t`const siteName = \"${websiteName}\";`,\n\t);\n\tawait fs.writeFile(layoutPath, nextContent);\n}\n\nexport async function injectEnterpriseTheme(\n\ttargetPath: string,\n\ttheme: EnterpriseTheme,\n) {\n\tconst cssPath = path.join(targetPath, \"src/app/globals.css\");\n\tif (!fs.existsSync(cssPath)) {\n\t\treturn;\n\t}\n\n\tconst currentContent = await fs.readFile(cssPath, \"utf-8\");\n\tconst nextContent = replaceThemeBlock(currentContent, generateThemeCss(theme));\n\tawait fs.writeFile(cssPath, nextContent);\n}\n","import fs from \"fs-extra\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { downloadTemplate } from \"giget\";\nimport { ProjectType } from \"../types/index.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nconst TEMPLATE_DIRECTORIES: Record<ProjectType, string> = {\n\tnext: \"next-template\",\n\tmobile: \"mobile-template\",\n};\n\nconst DEFAULT_REMOTE_TEMPLATE_SOURCES: Record<ProjectType, string> = {\n\tnext: \"github:BuildSanely/saneprint-templates/next-template\",\n\tmobile: \"github:BuildSanely/saneprint-templates/mobile-template\",\n};\n\nfunction getLocalTemplatePath(projectType: ProjectType) {\n\treturn path.resolve(\n\t\t__dirname,\n\t\t\"../../../templates\",\n\t\tTEMPLATE_DIRECTORIES[projectType],\n\t);\n}\n\nfunction getRemoteTemplateSource(projectType: ProjectType) {\n\tconst envKey =\n\t\tprojectType === \"next\"\n\t\t\t? \"PIX_TEMPLATE_SOURCE_NEXT\"\n\t\t\t: \"PIX_TEMPLATE_SOURCE_MOBILE\";\n\n\treturn (\n\t\tprocess.env[envKey]?.trim() || DEFAULT_REMOTE_TEMPLATE_SOURCES[projectType]\n\t);\n}\n\nexport async function scaffoldProjectTemplate(\n\tprojectType: ProjectType,\n\ttargetPath: string,\n) {\n\tif (process.env.PIX_DEV === \"true\") {\n\t\tconst sourcePath = getLocalTemplatePath(projectType);\n\n\t\tif (!fs.existsSync(sourcePath)) {\n\t\t\tthrow new Error(`Template not found at ${sourcePath}`);\n\t\t}\n\n\t\tawait fs.copy(sourcePath, targetPath, {\n\t\t\tfilter: (src) => {\n\t\t\t\tconst basename = path.basename(src);\n\t\t\t\treturn ![\"node_modules\", \".next\", \"dist\", \".turbo\"].includes(basename);\n\t\t\t},\n\t\t});\n\t\treturn;\n\t}\n\n\tconst source = getRemoteTemplateSource(projectType);\n\tawait downloadTemplate(source, { dir: targetPath, force: true });\n}\n"],"mappings":"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","names":["Command","p","chalk","path","p","chalk","fs","path","DEFAULT_THEME","THEME_START","THEME_END","THEME_ROLE_VARIABLES","BUTTON_INTENTS","TYPOGRAPHY_CLASS_NAMES","escapeRegExp","value","cloneValue","formatNumber","pxToRem","_","rawNumber","remValue","normalizeValue","assertObjectShape","schema","currentPath","schemaObject","valueObject","schemaKeys","valueKeys","key","index","nextPath","isRecord","assertThemeColorScales","colors","isRecord","assertObjectShape","DEFAULT_THEME","themeLine","name","value","componentRuleLines","selector","declarations","declaration","resolvePath","pathString","theme","keys","current","key","resolveToken","value","_","resolveAndNormalize","normalizeValue","pushPaletteVariables","lines","theme","familyName","scale","tokenName","tokenValue","themeLine","resolveAndNormalize","pushRoleVariables","roles","roleName","cssName","THEME_ROLE_VARIABLES","pushTypographyVariables","style","typedStyle","buildThemeInlineLines","buildTypographyUtilities","className","TYPOGRAPHY_CLASS_NAMES","buildButtonVariantLines","componentRuleLines","intent","BUTTON_INTENTS","getDefaultTheme","cloneValue","DEFAULT_THEME","validateTheme","isRecord","version","colors","typography","themes","assertThemeColorScales","assertObjectShape","generateThemeCss","THEME_START","THEME_END","replaceThemeBlock","content","themeCss","pattern","escapeRegExp","promptProjectConfig","options","promptEnterpriseTheme","themePath","path","defaultTheme","getDefaultTheme","fs","validateTheme","chalk","err","fs","path","injectPackageMetadata","targetPath","websiteName","packagePath","path","fs","packageJson","injectLayoutMetadata","layoutPath","nextContent","injectEnterpriseTheme","theme","cssPath","currentContent","replaceThemeBlock","generateThemeCss","fs","path","fileURLToPath","downloadTemplate","__filename","__dirname","TEMPLATE_DIRECTORIES","DEFAULT_REMOTE_TEMPLATE_SOURCES","getLocalTemplatePath","projectType","getRemoteTemplateSource","envKey","scaffoldProjectTemplate","targetPath","sourcePath","src","basename","source","initCommand","options","chalk","project","promptProjectConfig","enterpriseTheme","getDefaultTheme","promptEnterpriseTheme","s","targetPath","path","scaffoldProjectTemplate","injectPackageMetadata","injectLayoutMetadata","injectEnterpriseTheme","err","program","Command","options","initCommand"]}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "saneprint",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "The official saneprint CLI",
6
+ "author": "Karishma Garg",
7
+ "license": "MIT",
8
+ "keywords": [
9
+ "nextjs",
10
+ "react",
11
+ "scaffolding",
12
+ "cli",
13
+ "architecture",
14
+ "ai-governance"
15
+ ],
16
+ "main": "dist/index.js",
17
+ "files": [
18
+ "dist",
19
+ "README.md",
20
+ "LICENSE",
21
+ "CHANGELOG.md"
22
+ ],
23
+ "bin": {
24
+ "saneprint": "dist/index.js"
25
+ },
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "scripts": {
30
+ "build": "tsup",
31
+ "dev": "tsup --watch",
32
+ "start": "node dist/index.js",
33
+ "lint": "eslint src/**/*.ts"
34
+ },
35
+ "dependencies": {
36
+ "commander": "^12.0.0",
37
+ "@clack/prompts": "^0.7.0",
38
+ "fs-extra": "^11.0.0",
39
+ "chalk": "^5.0.0",
40
+ "giget": "^1.2.0"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^20.0.0",
44
+ "@types/fs-extra": "^11.0.0",
45
+ "typescript": "^5.0.0",
46
+ "tsup": "^8.0.0"
47
+ }
48
+ }