design-md-generator 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/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # Design MD Generator
2
+
3
+ 从任意网站或本地源码生成 `DESIGN.md` 文件。使用 Puppeteer 访问在线网站,或通过静态分析本地源码,提取设计令牌(颜色、排版、组件、布局、阴影、响应式断点),输出遵循 [Google Stitch DESIGN.md 格式](https://stitch.withgoogle.com/docs/design-md/overview/) 的结构化 Markdown 文档。
4
+
5
+ ## 快速开始
6
+
7
+ ```bash
8
+ # 安装依赖
9
+ npm install
10
+
11
+ # 模式一:从在线网站生成 DESIGN.md
12
+ node src/cli.js url https://stripe.com
13
+
14
+ # 模式二:从本地源码生成 DESIGN.md
15
+ node src/cli.js local ./my-project
16
+
17
+ # 带选项
18
+ node src/cli.js url https://stripe.com -o ./output/stripe-DESIGN.md -n "Stripe" --screenshot --json
19
+ node src/cli.js local ./my-project -o ./output/project-DESIGN.md -p "src/pages/home" "src/components" --json
20
+ ```
21
+
22
+ ## 两种提取模式
23
+
24
+ ### 模式一:在线网站提取(URL 模式)
25
+
26
+ 通过 Puppeteer 启动无头浏览器访问目标网站,从实时 DOM 和计算样式中提取设计令牌。
27
+
28
+ ```
29
+ Usage: design-md url [options] <url>
30
+
31
+ 参数:
32
+ url 要提取设计令牌的网站 URL
33
+
34
+ 选项:
35
+ -o, --output <path> 输出文件路径(默认:"./DESIGN.md")
36
+ -n, --name <name> 网站名称(不指定则自动检测)
37
+ -t, --timeout <ms> 导航超时时间,毫秒(默认:"30000")
38
+ -s, --screenshot 保存首页截图
39
+ --json 同时输出原始令牌的 JSON 文件
40
+ -w, --wait <selector> 提取前等待指定的 CSS 选择器
41
+ ```
42
+
43
+ **使用示例:**
44
+
45
+ ```bash
46
+ # 基本用法(url 是默认子命令)
47
+ design-md url https://stripe.com
48
+
49
+ # 完整选项
50
+ design-md url https://linear.app -o ./output/linear-DESIGN.md -n "Linear" --json --screenshot
51
+
52
+ # SPA 应用需要额外等待
53
+ design-md url https://app.example.com -w ".main-content" -t 60000
54
+ ```
55
+
56
+ ### 模式二:本地源码提取(Local 模式)
57
+
58
+ 通过静态分析本地前端源码文件(CSS/SCSS/Less/HTML/JSX/TSX/Vue/Svelte),提取设计令牌。无需浏览器,适用于:
59
+
60
+ - 本地开发中的项目
61
+ - 需要认证才能访问的页面
62
+ - 需要针对特定页面/组件生成设计文档
63
+ - CI/CD 流水线中自动生成设计文档
64
+
65
+ ```
66
+ Usage: design-md local [options] <dir>
67
+
68
+ 参数:
69
+ dir 要分析的源码目录
70
+
71
+ 选项:
72
+ -o, --output <path> 输出文件路径(默认:"./DESIGN.md")
73
+ -n, --name <name> 项目名称(不指定则从 package.json 自动检测)
74
+ -p, --pages <patterns...> 聚焦分析的页面/目录模式(如 "src/pages/home" "components/Header")
75
+ -i, --include <patterns...> 仅包含匹配这些模式的文件
76
+ -e, --exclude <patterns...> 排除匹配这些模式的文件
77
+ --json 同时输出原始令牌的 JSON 文件
78
+ ```
79
+
80
+ **使用示例:**
81
+
82
+ ```bash
83
+ # 分析整个项目
84
+ design-md local ./my-react-app
85
+
86
+ # 聚焦特定页面
87
+ design-md local ./my-project -p "src/pages/dashboard" "src/components/shared"
88
+
89
+ # 排除测试文件
90
+ design-md local ./my-project -e "__tests__" "*.test" "*.spec"
91
+
92
+ # 仅分析特定目录下的样式
93
+ design-md local ./my-project -i "src/styles" "src/theme"
94
+ ```
95
+
96
+ **支持的文件类型:**
97
+
98
+ | 类别 | 扩展名 |
99
+ |------|--------|
100
+ | 样式文件 | `.css`, `.scss`, `.sass`, `.less`, `.styl`, `.stylus` |
101
+ | 模板文件 | `.html`, `.htm`, `.jsx`, `.tsx`, `.vue`, `.svelte` |
102
+ | 配置文件 | `tailwind.config.*`, `theme.*`, `tokens.*`, `design-tokens.*` |
103
+
104
+ **自动忽略的目录:** `node_modules`, `.git`, `.next`, `.nuxt`, `dist`, `build`, `out`, `.cache`, `coverage`, `vendor`
105
+
106
+ ## 提取内容
107
+
108
+ | 类别 | URL 模式提取内容 | Local 模式提取内容 |
109
+ |------|-----------------|-------------------|
110
+ | **CSS 变量** | 从可访问的样式表中提取所有 `--custom-property` | 从所有样式文件中提取 |
111
+ | **颜色** | 从 500+ DOM 元素采样背景色、文字色、边框色 | 从源码中提取 hex/rgb/hsl 颜色值 |
112
+ | **语义颜色** | 从关键元素(body、nav、标题、链接、按钮)提取 | 从 CSS 变量命名推断语义角色 |
113
+ | **排版** | 字体族、完整层级表(字号、字重、行高、字间距) | 从 font-family/font-size 等声明提取 |
114
+ | **组件** | 按钮、卡片、徽章、输入框、导航栏的完整属性 | 从选择器模式匹配提取组件样式块 |
115
+ | **布局** | 间距比例尺、max-width、Grid/Flex 使用情况 | 从 padding/margin/gap 声明提取 |
116
+ | **阴影** | 所有不同的 box-shadow 值及使用频率 | 从 box-shadow 声明提取 |
117
+ | **断点** | 从可访问的样式表中提取媒体查询断点 | 从 @media 规则提取 |
118
+ | **元信息** | 页面标题、描述、主题色、深色/浅色模式检测 | 从 package.json 读取项目信息 |
119
+ | **Tailwind** | — | 自动检测并解析 tailwind.config.* 配置 |
120
+
121
+ ## 输出格式(9 大章节)
122
+
123
+ 生成的 `DESIGN.md` 遵循标准的 9 章节格式:
124
+
125
+ 1. **视觉主题与氛围** — 风格基调、设计哲学、关键特征
126
+ 2. **色彩体系与角色** — 语义化颜色及十六进制值、功能角色
127
+ 3. **排版规则** — 字体族、完整层级表
128
+ 4. **组件样式** — 按钮、卡片、输入框、导航栏及其状态
129
+ 5. **布局原则** — 间距比例尺、Grid、留白哲学
130
+ 6. **层深与阴影** — 阴影系统、表面层次结构
131
+ 7. **设计规范与禁忌** — 设计护栏和反模式
132
+ 8. **响应式行为** — 断点、触控目标尺寸、折叠策略
133
+ 9. **AI 代理提示指南** — 快速颜色参考、即用型组件提示
134
+
135
+ ## 编程接口
136
+
137
+ ```javascript
138
+ const { generateDesignMdFromUrl, generateDesignMdFromLocal } = require('design-md-generator');
139
+
140
+ // 模式一:从 URL 提取
141
+ const result1 = await generateDesignMdFromUrl('https://stripe.com', {
142
+ outputPath: './DESIGN.md',
143
+ siteName: 'Stripe',
144
+ timeout: 30000,
145
+ screenshot: true,
146
+ outputJson: true,
147
+ });
148
+
149
+ // 模式二:从本地源码提取
150
+ const result2 = await generateDesignMdFromLocal('./my-project', {
151
+ outputPath: './DESIGN.md',
152
+ siteName: 'My Project',
153
+ pages: ['src/pages/home', 'src/components'],
154
+ exclude: ['__tests__'],
155
+ outputJson: true,
156
+ });
157
+
158
+ // 两种模式返回相同结构
159
+ console.log(result1.markdown); // DESIGN.md 内容
160
+ console.log(result1.tokens); // 原始设计令牌
161
+ console.log(result1.colorCount); // 颜色数量
162
+ console.log(result1.fontCount); // 字体族数量
163
+ console.log(result1.componentCount); // 组件样式数量
164
+ ```
165
+
166
+ ## 已知限制
167
+
168
+ ### URL 模式
169
+
170
+ - **跨域样式表**:外部 CDN 的 CSS 可能无法提取 CSS 变量
171
+ - **JavaScript 渲染内容**:工具等待 `networkidle2`,但重度 SPA 站点可能需要 `--wait` 选项
172
+ - **Hover/Focus 状态**:仅捕获默认状态(不模拟交互)
173
+ - **深色模式**:提取默认主题;需使用浏览器偏好设置测试深色模式
174
+ - **私有/认证页面**:仅支持公开页面
175
+
176
+ ### Local 模式
177
+
178
+ - **CSS-in-JS**:不支持 styled-components、emotion 等运行时 CSS 方案的完整解析
179
+ - **动态样式**:无法捕获通过 JavaScript 动态生成的样式
180
+ - **计算值**:无法获取浏览器计算后的实际值(如 `calc()` 表达式)
181
+ - **Tailwind 工具类**:仅从配置文件提取,不解析模板中的工具类使用
182
+ - **主题切换**:仅分析源码中的静态声明
183
+
184
+ ## 许可证
185
+
186
+ MIT
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "design-md-generator",
3
+ "version": "1.0.0",
4
+ "description": "Generate DESIGN.md files from any website using Puppeteer to extract design tokens",
5
+ "main": "src/index.js",
6
+ "bin": {
7
+ "design-md-generator": "./src/cli.js"
8
+ },
9
+ "files": [
10
+ "src/**/*.js",
11
+ "README.md"
12
+ ],
13
+ "engines": {
14
+ "node": ">=18.0.0"
15
+ },
16
+ "scripts": {
17
+ "generate": "node src/cli.js",
18
+ "test": "echo \"Error: no test specified\" && exit 1",
19
+ "postinstall": "echo '✅ design-md-generator installed! Run: design-md-generator <url> to generate a DESIGN.md'"
20
+ },
21
+ "keywords": [
22
+ "design-system",
23
+ "design-md",
24
+ "design-tokens",
25
+ "puppeteer",
26
+ "css-extraction",
27
+ "style-guide",
28
+ "web-scraping"
29
+ ],
30
+ "license": "MIT",
31
+ "dependencies": {
32
+ "puppeteer": "^24.0.0",
33
+ "commander": "^13.0.0"
34
+ }
35
+ }
package/src/cli.js ADDED
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * CLI entry point for design-md-generator
5
+ * Usage:
6
+ * design-md-generator <url> [options] — Extract from live website via Puppeteer
7
+ * design-md-generator local <dir> [options] — Extract from local source code
8
+ */
9
+
10
+ const { program } = require('commander');
11
+ const path = require('path');
12
+ const { generateDesignMdFromUrl, generateDesignMdFromLocal } = require('./index');
13
+
14
+ // ============================================================
15
+ // Default command: extract from URL via Puppeteer
16
+ // ============================================================
17
+ program
18
+ .name('design-md-generator')
19
+ .description('Generate DESIGN.md from any website or local source code')
20
+ .version('1.0.0');
21
+
22
+ program
23
+ .command('url', { isDefault: true })
24
+ .description('Generate DESIGN.md from a live website URL using Puppeteer')
25
+ .argument('<url>', 'Website URL to extract design tokens from')
26
+ .option('-o, --output <path>', 'Output file path', './DESIGN.md')
27
+ .option('-n, --name <name>', 'Site name (auto-detected if not provided)')
28
+ .option('-t, --timeout <ms>', 'Navigation timeout in milliseconds', '30000')
29
+ .option('-s, --screenshot', 'Save a screenshot of the homepage')
30
+ .option('--json', 'Also output raw tokens as JSON')
31
+ .option('-w, --wait <selector>', 'Wait for a specific CSS selector before extracting')
32
+ .action(async (url, options) => {
33
+ try {
34
+ // Normalize URL
35
+ if (!url.startsWith('http://') && !url.startsWith('https://')) {
36
+ url = 'https://' + url;
37
+ }
38
+
39
+ console.log(`\n🎨 Design MD Generator (URL mode)\n`);
40
+ console.log(` URL: ${url}`);
41
+ console.log(` Output: ${options.output}`);
42
+ console.log('');
43
+
44
+ const result = await generateDesignMdFromUrl(url, {
45
+ outputPath: path.resolve(options.output),
46
+ siteName: options.name,
47
+ timeout: parseInt(options.timeout),
48
+ screenshot: options.screenshot,
49
+ outputJson: options.json,
50
+ waitForSelector: options.wait,
51
+ });
52
+
53
+ console.log(`\n✨ Done! DESIGN.md generated successfully.`);
54
+ console.log(` 📄 ${result.outputPath}`);
55
+ if (result.jsonPath) {
56
+ console.log(` 📊 ${result.jsonPath}`);
57
+ }
58
+ if (result.screenshotPath) {
59
+ console.log(` 📸 ${result.screenshotPath}`);
60
+ }
61
+ console.log(` 🎨 ${result.colorCount} colors extracted`);
62
+ console.log(` 🔤 ${result.fontCount} font families detected`);
63
+ console.log(` 📐 ${result.componentCount} component styles captured`);
64
+ console.log('');
65
+ } catch (error) {
66
+ console.error(`\n❌ Error: ${error.message}\n`);
67
+ if (error.message.includes('net::ERR')) {
68
+ console.error(' Could not reach the website. Check the URL and your network connection.');
69
+ }
70
+ if (error.message.includes('timeout')) {
71
+ console.error(' The page took too long to load. Try increasing --timeout.');
72
+ }
73
+ process.exit(1);
74
+ }
75
+ });
76
+
77
+ // ============================================================
78
+ // Local command: extract from local source code
79
+ // ============================================================
80
+ program
81
+ .command('local')
82
+ .description('Generate DESIGN.md from local source code by static analysis')
83
+ .argument('<dir>', 'Directory containing source code to analyze')
84
+ .option('-o, --output <path>', 'Output file path', './DESIGN.md')
85
+ .option('-n, --name <name>', 'Project name (auto-detected from package.json if not provided)')
86
+ .option('-p, --pages <patterns...>', 'Page/directory patterns to focus on (e.g. "src/pages/home" "components/Header")')
87
+ .option('-i, --include <patterns...>', 'Include only files matching these patterns')
88
+ .option('-e, --exclude <patterns...>', 'Exclude files matching these patterns')
89
+ .option('--json', 'Also output raw tokens as JSON')
90
+ .action(async (dir, options) => {
91
+ try {
92
+ console.log(`\n🎨 Design MD Generator (Local mode)\n`);
93
+ console.log(` Directory: ${path.resolve(dir)}`);
94
+ console.log(` Output: ${options.output}`);
95
+ if (options.pages) {
96
+ console.log(` Pages: ${options.pages.join(', ')}`);
97
+ }
98
+ console.log('');
99
+
100
+ const result = await generateDesignMdFromLocal(dir, {
101
+ outputPath: path.resolve(options.output),
102
+ siteName: options.name,
103
+ pages: options.pages || [],
104
+ include: options.include || [],
105
+ exclude: options.exclude || [],
106
+ outputJson: options.json,
107
+ });
108
+
109
+ console.log(`\n✨ Done! DESIGN.md generated successfully.`);
110
+ console.log(` 📄 ${result.outputPath}`);
111
+ if (result.jsonPath) {
112
+ console.log(` 📊 ${result.jsonPath}`);
113
+ }
114
+ console.log(` 🎨 ${result.colorCount} colors extracted`);
115
+ console.log(` 🔤 ${result.fontCount} font families detected`);
116
+ console.log(` 📐 ${result.componentCount} component styles captured`);
117
+ console.log('');
118
+ } catch (error) {
119
+ console.error(`\n❌ Error: ${error.message}\n`);
120
+ if (error.message.includes('not found')) {
121
+ console.error(' Directory not found. Check the path and try again.');
122
+ }
123
+ process.exit(1);
124
+ }
125
+ });
126
+
127
+ program.parse();