@nghitrum/dsforge 0.1.1

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/README.md ADDED
@@ -0,0 +1,226 @@
1
+ # dsforge
2
+
3
+ [![CI](https://github.com/nghitrum/dsforge/actions/workflows/ci.yml/badge.svg)](https://github.com/nghitrum/dsforge/actions/workflows/ci.yml)
4
+
5
+ Your design tokens live in Figma. Your components drift from the spec. Your docs are six sprints out of date. dsforge fixes all three with one config file.
6
+
7
+ ![dsforge showcase](docs/showcase.png)
8
+
9
+ ---
10
+
11
+ ## Before / After
12
+
13
+ **Before**
14
+
15
+ - Design tokens transcribed by hand into CSS variables across three repos
16
+ - Component variants documented in a Notion page that nobody updates
17
+ - AI coding tools guessing at constraints because there is no machine-readable spec
18
+
19
+ **After**
20
+
21
+ ```
22
+ design-system.config.json → dsforge generate
23
+ ```
24
+
25
+ ```
26
+ dist-ds/
27
+ ├── src/ 9 typed React components
28
+ ├── tokens/ CSS custom properties, JS map, Tailwind extension
29
+ ├── docs/ MDX documentation per component
30
+ ├── metadata/ AI-readable JSON contracts per component
31
+ └── showcase.html visual docs — open directly in the browser, no server
32
+ ```
33
+
34
+ One config. One command. Everything consistent, everything regeneratable.
35
+
36
+ ---
37
+
38
+ ## Quick start
39
+
40
+ ```bash
41
+ npx dsforge@latest init # scaffold config + rules
42
+ npx dsforge@latest generate # generate the full design system
43
+ npx dsforge@latest showcase # open the visual docs in your browser
44
+ ```
45
+
46
+ Output lands in `dist-ds/`. Regenerate it any time by running `generate` again.
47
+
48
+ ---
49
+
50
+ ## Config
51
+
52
+ `design-system.config.json` is the single source of truth. A minimal example:
53
+
54
+ ```json
55
+ {
56
+ "meta": { "name": "Acme DS", "version": "1.0.0" },
57
+ "tokens": {
58
+ "global": {
59
+ "brand-600": "#2563eb",
60
+ "neutral-900": "#0f172a",
61
+ "neutral-0": "#ffffff"
62
+ },
63
+ "semantic": {
64
+ "color-action": "{global.brand-600}",
65
+ "color-text-primary": "{global.neutral-900}",
66
+ "color-bg-default": "{global.neutral-0}"
67
+ }
68
+ },
69
+ "typography": {
70
+ "fontFamily": "Inter, system-ui, sans-serif",
71
+ "roles": {
72
+ "body": { "size": 16, "weight": 400, "lineHeight": 1.6 },
73
+ "heading": { "size": 24, "weight": 700, "lineHeight": 1.2 }
74
+ }
75
+ },
76
+ "themes": {
77
+ "light": {},
78
+ "dark": { "color-bg-default": "#0f172a", "color-text-primary": "#f1f5f9" }
79
+ }
80
+ }
81
+ ```
82
+
83
+ Tokens use a three-tier system: **global → semantic → component**. References use `{layer.key}` syntax and are resolved at generate time.
84
+
85
+ ---
86
+
87
+ ## What you get
88
+
89
+ ### 9 React components
90
+
91
+ Button · Input · Card · Badge · Checkbox · Radio · Select · Spinner · Toast
92
+
93
+ Each component is typed, themed with your actual tokens, and ships with a prop table, copyable TSX examples, WCAG accessibility notes, and an AI metadata contract.
94
+
95
+ ### CSS tokens
96
+
97
+ `base.css` — global and semantic CSS custom properties
98
+ `light.css` / `dark.css` — theme overrides
99
+ `tokens.js` — JS token map for runtime use
100
+ `tailwind.js` — Tailwind theme extension, ready to drop into `tailwind.config.js`
101
+
102
+ ### MDX docs
103
+
104
+ One `.mdx` file per component, generated from your config. Import them into any docs site.
105
+
106
+ ### AI metadata contracts
107
+
108
+ Each component emits `dist-ds/metadata/<component>.json`:
109
+
110
+ ```json
111
+ {
112
+ "component": "Button",
113
+ "role": "action-trigger",
114
+ "variants": ["primary", "secondary", "danger", "ghost"],
115
+ "destructiveVariants": ["danger"],
116
+ "accessibilityContract": {
117
+ "keyboard": true,
118
+ "focusRing": "required",
119
+ "ariaLabel": "required-for-icon-only"
120
+ },
121
+ "aiGuidance": [
122
+ "Use primary for the single most important action on a surface.",
123
+ "Never place two primary buttons side by side.",
124
+ "Use danger only for irreversible destructive actions."
125
+ ]
126
+ }
127
+ ```
128
+
129
+ AI coding assistants can read these before generating UI — no more inferring constraints from source code.
130
+
131
+ ### Visual showcase
132
+
133
+ `showcase.html` is a self-contained documentation site. No build step, no server — open it directly in the browser.
134
+
135
+ Includes live component previews with all variants and states, themed with your actual tokens. Theme switching (light/dark) is built in when both themes are defined in config.
136
+
137
+ ### npm-ready package
138
+
139
+ `dist-ds/` includes `package.json`, `tsconfig.json`, and a barrel `index.ts`. Run `npm publish` from `dist-ds/` to ship the design system as a package.
140
+
141
+ ---
142
+
143
+ ## Validation
144
+
145
+ `dsforge validate` runs nine health checks and produces a scored report:
146
+
147
+ | Check | Max score |
148
+ | --- | --- |
149
+ | Token architecture | 15 |
150
+ | Typography | 10 |
151
+ | Spacing | 10 |
152
+ | Radius | 5 |
153
+ | Elevation | 5 |
154
+ | Motion | 5 |
155
+ | Themes | 10 |
156
+ | Token resolution | 14 |
157
+ | Governance rules | 15 |
158
+
159
+ Scores below 70 are flagged as warnings. WCAG contrast is checked automatically for all color token pairs.
160
+
161
+ `design-system.rules.json` encodes your governance constraints:
162
+
163
+ ```json
164
+ {
165
+ "governance": {
166
+ "requireSemanticTokens": true,
167
+ "forbidHardcodedColors": true,
168
+ "requireAccessibilityProps": true
169
+ }
170
+ }
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Diff
176
+
177
+ `dsforge diff old.config.json new.config.json` classifies every change:
178
+
179
+ - **BREAKING** — tokens removed or renamed that are referenced by components
180
+ - **CHANGED** — existing values modified
181
+ - **ADDED** — new tokens or sections
182
+
183
+ Run this before deploying a config update to understand downstream impact.
184
+
185
+ ---
186
+
187
+ ## Commands
188
+
189
+ | Command | What it does |
190
+ | --- | --- |
191
+ | `dsforge init` | Scaffold `design-system.config.json` and `design-system.rules.json` |
192
+ | `dsforge generate` | Run the full pipeline — tokens, components, metadata, docs, showcase |
193
+ | `dsforge validate` | Run 9 health checks and score against governance rules |
194
+ | `dsforge diff` | Compare two configs — BREAKING / CHANGED / ADDED |
195
+ | `dsforge showcase` | Open `dist-ds/showcase.html` in your default browser |
196
+
197
+ Run `dsforge` with no arguments for an interactive menu.
198
+
199
+ ---
200
+
201
+ ## Coming next
202
+
203
+ - Additional components: Modal, Table, Tooltip, DatePicker
204
+ - **Pro**: AI-assisted token generation from brand guidelines or a Figma file
205
+ - Figma Variables API sync
206
+ - CI integration — fail builds on governance violations
207
+
208
+ ---
209
+
210
+ ## Development
211
+
212
+ ```bash
213
+ git clone https://github.com/your-org/dsforge
214
+ cd dsforge
215
+ npm install
216
+
217
+ npm run dev # run the CLI without a build step
218
+ npm run typecheck # type-check without emitting
219
+ npm test # run the test suite
220
+ ```
221
+
222
+ ---
223
+
224
+ ## License
225
+
226
+ MIT
@@ -0,0 +1,252 @@
1
+ // src/generators/package/emitter.ts
2
+ function generatePackageJson(config, componentNames) {
3
+ const scope = config.meta.npmScope ?? "@myorg";
4
+ const name = `${scope}/${config.meta.name}`;
5
+ const pkg = {
6
+ name,
7
+ version: config.meta.version,
8
+ description: config.meta.description ?? `${config.meta.name} design system`,
9
+ keywords: ["design-system", "tokens", "react", "typescript", "components"],
10
+ license: "MIT",
11
+ type: "module",
12
+ main: "./dist/index.js",
13
+ types: "./dist/index.d.ts",
14
+ exports: {
15
+ ".": {
16
+ import: "./dist/index.js",
17
+ types: "./dist/index.d.ts"
18
+ },
19
+ "./tokens/base.css": "./tokens/base.css",
20
+ ...Object.fromEntries(
21
+ Object.keys({}).concat(["light", "dark"]).map((t) => [`./tokens/${t}.css`, `./tokens/${t}.css`])
22
+ ),
23
+ "./tokens": "./tokens/tokens.js",
24
+ "./tailwind": "./tokens/tailwind.js",
25
+ "./metadata": "./metadata/index.json",
26
+ ...Object.fromEntries(
27
+ componentNames.map((c) => [`./metadata/${c}`, `./metadata/${c}.json`])
28
+ )
29
+ },
30
+ files: ["dist", "tokens", "metadata", "docs", "CHANGELOG.md"],
31
+ scripts: {
32
+ build: "tsc",
33
+ prepublishOnly: "npm run build"
34
+ },
35
+ devDependencies: {
36
+ "@types/react": "^18.0.0",
37
+ "@types/react-dom": "^18.0.0",
38
+ typescript: "^5.0.0"
39
+ },
40
+ peerDependencies: {
41
+ react: ">=17.0.0",
42
+ "react-dom": ">=17.0.0"
43
+ },
44
+ peerDependenciesMeta: {
45
+ react: { optional: false },
46
+ "react-dom": { optional: false }
47
+ },
48
+ engines: {
49
+ node: ">=18.0.0"
50
+ },
51
+ dsforge: {
52
+ generatedBy: "dsforge",
53
+ configVersion: config.meta.version,
54
+ preset: config.meta.preset ?? "comfortable",
55
+ components: componentNames,
56
+ themes: []
57
+ }
58
+ };
59
+ return JSON.stringify(pkg, null, 2);
60
+ }
61
+ function generateTsConfig() {
62
+ return JSON.stringify(
63
+ {
64
+ compilerOptions: {
65
+ target: "ES2020",
66
+ module: "NodeNext",
67
+ moduleResolution: "NodeNext",
68
+ lib: ["ES2020", "DOM"],
69
+ outDir: "./dist",
70
+ rootDir: "./src",
71
+ declaration: true,
72
+ declarationMap: true,
73
+ sourceMap: true,
74
+ strict: true,
75
+ esModuleInterop: true,
76
+ skipLibCheck: true,
77
+ jsx: "react-jsx"
78
+ },
79
+ include: ["src/**/*"],
80
+ exclude: ["node_modules", "dist"]
81
+ },
82
+ null,
83
+ 2
84
+ );
85
+ }
86
+ function generateReadme(config, componentNames) {
87
+ const scope = config.meta.npmScope ?? "@myorg";
88
+ const pkgName = `${scope}/${config.meta.name}`;
89
+ const themeNames = ["light", "dark"];
90
+ return `# ${config.meta.name}
91
+
92
+ > ${config.meta.description ?? "A design system generated by dsforge."}
93
+
94
+ [![npm version](https://badge.fury.io/js/${encodeURIComponent(pkgName)}.svg)](https://www.npmjs.com/package/${pkgName})
95
+
96
+ ---
97
+
98
+ ## Installation
99
+
100
+ \`\`\`bash
101
+ npm install ${pkgName}
102
+ \`\`\`
103
+
104
+ ## Quick start
105
+
106
+ \`\`\`tsx
107
+ // 1. Import base tokens (once, in your app root)
108
+ import "${pkgName}/tokens/base.css";
109
+ import "${pkgName}/tokens/light.css";
110
+
111
+ // 2. Wrap your app
112
+ import { ThemeProvider, Button } from "${pkgName}";
113
+
114
+ function App() {
115
+ return (
116
+ <ThemeProvider theme="light">
117
+ <Button variant="primary" aria-label="Get started">
118
+ Get started
119
+ </Button>
120
+ </ThemeProvider>
121
+ );
122
+ }
123
+ \`\`\`
124
+
125
+ ## Components
126
+
127
+ ${componentNames.map(
128
+ (c) => `- **${c.charAt(0).toUpperCase() + c.slice(1)}** \u2014 see \`metadata/${c}.json\` for contract`
129
+ ).join("\n")}
130
+
131
+ ## Themes
132
+
133
+ ${themeNames.map((t) => `- \`${t}\` \u2014 import \`${pkgName}/tokens/${t}.css\``).join("\n")}
134
+
135
+ ### Theme switching
136
+
137
+ \`\`\`tsx
138
+ import { useTheme } from "${pkgName}";
139
+
140
+ function ThemeToggle() {
141
+ const { theme, setTheme } = useTheme();
142
+ return (
143
+ <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
144
+ Toggle theme
145
+ </button>
146
+ );
147
+ }
148
+ \`\`\`
149
+
150
+ ## Using with Tailwind
151
+
152
+ \`\`\`js
153
+ // tailwind.config.js
154
+ const ds = require("${pkgName}/tailwind");
155
+ module.exports = {
156
+ theme: { extend: ds },
157
+ };
158
+ \`\`\`
159
+
160
+ ## Without React (CSS tokens only)
161
+
162
+ \`\`\`html
163
+ <link rel="stylesheet" href="node_modules/${pkgName}/tokens/base.css" />
164
+ <link rel="stylesheet" href="node_modules/${pkgName}/tokens/light.css" />
165
+
166
+ <button class="my-button">Click me</button>
167
+
168
+ <style>
169
+ .my-button {
170
+ background: var(--color-action);
171
+ color: var(--color-text-inverse);
172
+ border-radius: var(--radius-md);
173
+ padding: var(--component-padding-sm) var(--component-padding-md);
174
+ }
175
+ </style>
176
+ \`\`\`
177
+
178
+ ## Token customization
179
+
180
+ All design tokens are defined in \`design-system.config.json\`. After editing,
181
+ run \`dsforge generate\` to regenerate the package.
182
+
183
+ \`\`\`json
184
+ // design-system.config.json (excerpt)
185
+ {
186
+ "tokens": {
187
+ "global": {
188
+ "color-brand-500": "#2563eb"
189
+ },
190
+ "semantic": {
191
+ "color-action": "{global.color-brand-500}"
192
+ }
193
+ }
194
+ }
195
+ \`\`\`
196
+
197
+ Token references use \`{tier.name}\` syntax to alias values across tiers:
198
+ global \u2192 semantic \u2192 component. Changing a global value propagates through
199
+ every semantic and component token that references it.
200
+
201
+ ## AI tool integration
202
+
203
+ The \`metadata/\` directory contains machine-readable component contracts.
204
+ AI coding assistants (Copilot, Cursor, Claude Code) can read these to
205
+ generate UI that respects your governance rules automatically.
206
+
207
+ \`\`\`json
208
+ // ${pkgName}/metadata/button.json
209
+ {
210
+ "component": "Button",
211
+ "allowedVariants": ["primary", "secondary", "danger", "ghost"],
212
+ "requiredProps": ["aria-label"],
213
+ "accessibilityContract": { "keyboard": true, "focusRing": true }
214
+ }
215
+ \`\`\`
216
+
217
+ ---
218
+
219
+ Generated by [dsforge](https://github.com/nghitrum/dsforge) v${config.meta.version}.
220
+ `;
221
+ }
222
+ function generateChangelog(config) {
223
+ const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
224
+ return `# Changelog
225
+
226
+ All notable changes to \`${config.meta.name}\` are documented here.
227
+ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
228
+
229
+ ## [${config.meta.version}] \u2014 ${date}
230
+
231
+ ### Added
232
+
233
+ - Initial release generated by dsforge
234
+ - Components: see \`metadata/index.json\` for full list
235
+ - Token architecture: global \u2192 semantic \u2192 component (3-tier)
236
+ - Themes: light, dark
237
+ - CSS custom property output for all tokens
238
+ - Tailwind theme extension
239
+ - AI-consumable metadata per component
240
+
241
+ ---
242
+
243
+ _To add a new entry: run \`dsforge diff --from <prev-version>\` and paste the output here._
244
+ `;
245
+ }
246
+
247
+ export {
248
+ generatePackageJson,
249
+ generateTsConfig,
250
+ generateReadme,
251
+ generateChangelog
252
+ };