@webywz/breathing-github-profile 0.0.0-stage → 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 webywz
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 CHANGED
@@ -1,3 +1,281 @@
1
- # Temporary Holding Version
1
+ # breathing-github-profile
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **A living GitHub profile README — declarative config, marker-safe refresh, CLI + library.**
4
+ **会呼吸的 GitHub 主页 README:声明式配置、标记保护区刷新,CLI 与库双入口。**
5
+
6
+ [![npm](https://img.shields.io/npm/v/@webywz/breathing-github-profile.svg)](https://www.npmjs.com/package/@webywz/breathing-github-profile)
7
+ [![Test](https://github.com/webywz/breathing-github-profile/actions/workflows/test.yml/badge.svg)](https://github.com/webywz/breathing-github-profile/actions/workflows/test.yml)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
9
+
10
+ Package: `@webywz/breathing-github-profile` · CLI binary: `breathing-profile` · Node 18+
11
+
12
+ > Not on the npm registry yet. Install from GitHub until the first publish.
13
+ > 尚未发布到 npm,请先从 GitHub 安装。
14
+
15
+ ---
16
+
17
+ ## Features · 特性
18
+
19
+ | | EN | 中文 |
20
+ | --- | --- | --- |
21
+ | Config | YAML / JSON define intro, sections, and style | YAML / JSON 声明介绍、章节与样式 |
22
+ | Refresh | Updates only `<!--MARKER:START-->…<!--MARKER:END-->` | 只改标记区,手写文案保留 |
23
+ | Stats | Stars, forks, repos, followers; language mix; featured repos | 统计、语言分布、精选仓库 |
24
+ | Sections | `stats` · `languages` · `repos` · `custom` | 四种章节类型 |
25
+ | Automation | Daily GitHub Actions workflow | Actions 每日定时刷新 |
26
+ | API | CLI commands + TypeScript library exports | CLI + 库 |
27
+
28
+ Live example: [webywz/webywz](https://github.com/webywz/webywz).
29
+
30
+ ---
31
+
32
+ ## Install · 安装
33
+
34
+ ```bash
35
+ npm install github:webywz/breathing-github-profile
36
+ npx breathing-profile --help
37
+ ```
38
+
39
+ From source (develop / unpublished):
40
+
41
+ ```bash
42
+ git clone https://github.com/webywz/breathing-github-profile.git
43
+ cd breathing-github-profile
44
+ npm install
45
+ npm run build
46
+ ```
47
+
48
+ One-shot without a local clone:
49
+
50
+ ```bash
51
+ npx --yes --package github:webywz/breathing-github-profile -- breathing-profile generate -c config.yml -o README.md
52
+ ```
53
+
54
+ After the package is published:
55
+
56
+ ```bash
57
+ npm i -g @webywz/breathing-github-profile
58
+ npx @webywz/breathing-github-profile --help
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Quick start · 快速开始
64
+
65
+ ### 1. Config · 配置
66
+
67
+ Create `config.yml`:
68
+
69
+ ```yaml
70
+ username: your-github-username
71
+
72
+ intro:
73
+ zh: |
74
+ Full-stack developer · open source
75
+ Happy to connect.
76
+ en: |
77
+ Full-stack developer · open source
78
+ Let's connect.
79
+
80
+ featuredRepos:
81
+ - your-best-repo
82
+
83
+ sections:
84
+ - type: stats
85
+ marker: STATS
86
+ title: GitHub Stats · 统计
87
+
88
+ - type: languages
89
+ marker: LANGUAGES
90
+ title: Languages · 常用语言
91
+
92
+ - type: repos
93
+ marker: REPOS
94
+ title: Featured · 精选项目
95
+ ```
96
+
97
+ Full sample: [examples/webywz.yml](examples/webywz.yml).
98
+
99
+ ### 2. Generate · 生成
100
+
101
+ ```bash
102
+ npx breathing-profile generate -c config.yml -o README.md
103
+ npx breathing-profile refresh -c config.yml -r README.md
104
+ npx breathing-profile validate -c config.yml
105
+ ```
106
+
107
+ | Command | EN | 中文 |
108
+ | --- | --- | --- |
109
+ | `generate` | Write a full README from config + GitHub data | 按配置与 GitHub 数据生成完整 README |
110
+ | `refresh` | Rewrite marker sections only | 只刷新标记区 |
111
+ | `validate` | Check the config file | 校验配置 |
112
+
113
+ Optional: set `GITHUB_TOKEN` (or use `secrets.GITHUB_TOKEN` in Actions) for higher API rate limits.
114
+
115
+ ---
116
+
117
+ ## Configuration · 配置说明
118
+
119
+ ### Top-level · 顶层字段
120
+
121
+ | Field | Type | Required | Notes |
122
+ | --- | --- | --- | --- |
123
+ | `username` | string | yes | GitHub login |
124
+ | `intro.zh` / `intro.en` | string | one of zh/en | Bilingual intro blocks |
125
+ | `featuredRepos` | string[] | no | Pinned repo names |
126
+ | `sections` | Section[] | no | Ordered sections |
127
+ | `style` | StyleConfig | no | Theme / layout knobs |
128
+
129
+ ### Section types · 章节类型
130
+
131
+ **`stats`** — totals (stars, forks, public repos, followers, following).
132
+
133
+ ```yaml
134
+ - type: stats
135
+ marker: STATS
136
+ title: GitHub Stats · 统计
137
+ ```
138
+
139
+ **`languages`** — top languages by share.
140
+
141
+ ```yaml
142
+ - type: languages
143
+ marker: LANGUAGES
144
+ title: Languages · 常用语言
145
+ ```
146
+
147
+ **`repos`** — featured list, or highest-star repos when `featuredRepos` is empty.
148
+
149
+ ```yaml
150
+ - type: repos
151
+ marker: REPOS
152
+ title: Featured · 精选项目
153
+ ```
154
+
155
+ **`custom`** — raw Markdown inside a marker.
156
+
157
+ ```yaml
158
+ - type: custom
159
+ marker: TECH_STACK
160
+ title: Stack · 技术栈
161
+ content: |
162
+ TypeScript · NestJS · FastAPI · Vue
163
+ ```
164
+
165
+ Markers must match exactly:
166
+
167
+ ```markdown
168
+ <!--STATS:START-->
169
+ …
170
+ <!--STATS:END-->
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Automation · 自动刷新
176
+
177
+ In your profile repo (`USER/USER`):
178
+
179
+ 1. Add `config.yml`
180
+ 2. Add `.github/workflows/refresh-profile.yml`:
181
+
182
+ ```yaml
183
+ name: Refresh profile README
184
+
185
+ on:
186
+ schedule:
187
+ - cron: '0 0 * * *' # daily 00:00 UTC
188
+ workflow_dispatch:
189
+
190
+ permissions:
191
+ contents: write
192
+
193
+ jobs:
194
+ refresh:
195
+ runs-on: ubuntu-latest
196
+ steps:
197
+ - uses: actions/checkout@v4
198
+ - uses: actions/setup-node@v4
199
+ with:
200
+ node-version: '20'
201
+ - run: npm install github:webywz/breathing-github-profile
202
+ - name: Refresh README
203
+ env:
204
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
205
+ run: npx breathing-profile refresh
206
+ - name: Commit if changed
207
+ run: |
208
+ git config user.name "github-actions[bot]"
209
+ git config user.email "github-actions[bot]@users.noreply.github.com"
210
+ git add README.md data/profile.json
211
+ git diff --quiet || git commit -m "chore: refresh profile README"
212
+ git push
213
+ ```
214
+
215
+ Flow: cron → GitHub API → rewrite markers → commit only when content changed. Copy outside markers is never touched.
216
+
217
+ 流程:定时触发 → 拉 GitHub 数据 → 只改标记区 → 有变更才提交。标记外的手写内容不会被动。
218
+
219
+ ---
220
+
221
+ ## Library · 作为库使用
222
+
223
+ ```ts
224
+ import {
225
+ loadConfig,
226
+ GitHubClient,
227
+ ReadmeGenerator,
228
+ } from '@webywz/breathing-github-profile';
229
+
230
+ const config = loadConfig('config.yml');
231
+ const client = new GitHubClient(process.env.GITHUB_TOKEN);
232
+ const data = await client.getProfileData(config.username);
233
+ const readme = new ReadmeGenerator(config, data).generate();
234
+ ```
235
+
236
+ Also exported: `validateConfig`, `getDefaultConfig`, `updateReadmeMarkers`.
237
+
238
+ ---
239
+
240
+ ## Develop · 开发
241
+
242
+ ```bash
243
+ git clone https://github.com/webywz/breathing-github-profile.git
244
+ cd breathing-github-profile
245
+ npm install
246
+ npm run build
247
+ npm test
248
+ npm run lint
249
+
250
+ npm run generate -- -c examples/webywz.yml -o examples/README.md
251
+ npm run refresh -- -c examples/webywz.yml -r examples/README.md
252
+ ```
253
+
254
+ ```
255
+ src/
256
+ types.ts types
257
+ config.ts load / validate
258
+ github.ts GitHub client
259
+ generator.ts README generate + marker update
260
+ cli.ts CLI
261
+ index.ts library entry
262
+ examples/ sample configs
263
+ ```
264
+
265
+ ---
266
+
267
+ ## FAQ · 常见问题
268
+
269
+ **Rate limits?** Set `GITHUB_TOKEN`. Actions already injects `secrets.GITHUB_TOKEN`.
270
+
271
+ **Only update part of the README?** Use `refresh`, not `generate`.
272
+
273
+ **Markers not updating?** Names must match `marker` in config; use `<!--NAME:START-->` / `<!--NAME:END-->`.
274
+
275
+ ---
276
+
277
+ ## Links · 链接
278
+
279
+ - Demo profile: [webywz/webywz](https://github.com/webywz/webywz)
280
+ - Contributing: [CONTRIBUTING.md](CONTRIBUTING.md)
281
+ - License: [MIT](LICENSE) © webywz
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const ora_1 = __importDefault(require("ora"));
10
+ const fs_1 = require("fs");
11
+ const path_1 = require("path");
12
+ const config_1 = require("./config");
13
+ const github_1 = require("./github");
14
+ const generator_1 = require("./generator");
15
+ const program = new commander_1.Command();
16
+ program
17
+ .name('breathing-profile')
18
+ .description('可复用的活跃 GitHub profile README 生成器')
19
+ .version('1.0.0');
20
+ program
21
+ .command('generate')
22
+ .description('生成新的 README.md')
23
+ .option('-c, --config <path>', '配置文件路径', 'config.yml')
24
+ .option('-o, --output <path>', '输出文件路径', 'README.md')
25
+ .action(async (options) => {
26
+ const spinner = (0, ora_1.default)('正在生成 README...').start();
27
+ try {
28
+ if (!(0, fs_1.existsSync)(options.config)) {
29
+ throw new Error(`配置文件不存在: ${options.config}`);
30
+ }
31
+ const config = (0, config_1.loadConfig)(options.config);
32
+ const client = new github_1.GitHubClient();
33
+ spinner.text = `正在获取 ${config.username} 的 GitHub 数据...`;
34
+ const data = await client.getProfileData(config.username);
35
+ spinner.text = '正在生成 README 内容...';
36
+ const generator = new generator_1.ReadmeGenerator(config, data);
37
+ const readme = generator.generate();
38
+ (0, fs_1.writeFileSync)(options.output, readme, 'utf-8');
39
+ const dataDir = 'data';
40
+ if (!(0, fs_1.existsSync)(dataDir)) {
41
+ (0, fs_1.mkdirSync)(dataDir, { recursive: true });
42
+ }
43
+ (0, fs_1.writeFileSync)((0, path_1.join)(dataDir, 'profile.json'), JSON.stringify(data, null, 2), 'utf-8');
44
+ spinner.succeed(chalk_1.default.green(`✓ README 已生成: ${options.output}`));
45
+ console.log(chalk_1.default.gray(` 数据已保存到: ${(0, path_1.join)(dataDir, 'profile.json')}`));
46
+ }
47
+ catch (error) {
48
+ spinner.fail(chalk_1.default.red('生成失败'));
49
+ console.error(chalk_1.default.red(`错误: ${error.message}`));
50
+ process.exit(1);
51
+ }
52
+ });
53
+ program
54
+ .command('refresh')
55
+ .description('刷新现有 README 的标记部分')
56
+ .option('-c, --config <path>', '配置文件路径', 'config.yml')
57
+ .option('-r, --readme <path>', 'README 文件路径', 'README.md')
58
+ .action(async (options) => {
59
+ const spinner = (0, ora_1.default)('正在刷新 README...').start();
60
+ try {
61
+ if (!(0, fs_1.existsSync)(options.config)) {
62
+ throw new Error(`配置文件不存在: ${options.config}`);
63
+ }
64
+ if (!(0, fs_1.existsSync)(options.readme)) {
65
+ throw new Error(`README 文件不存在: ${options.readme}`);
66
+ }
67
+ const config = (0, config_1.loadConfig)(options.config);
68
+ const client = new github_1.GitHubClient();
69
+ spinner.text = `正在获取 ${config.username} 的 GitHub 数据...`;
70
+ const data = await client.getProfileData(config.username);
71
+ spinner.text = '正在更新 README 标记部分...';
72
+ const existingReadme = (0, fs_1.readFileSync)(options.readme, 'utf-8');
73
+ const markerSections = (config.sections || []).map(section => {
74
+ const marker = section.marker || section.type.toUpperCase();
75
+ let content = '';
76
+ const tempGenerator = new generator_1.ReadmeGenerator(config, data);
77
+ const fullReadme = tempGenerator.generate();
78
+ const startMarker = `<!--${marker}:START-->`;
79
+ const endMarker = `<!--${marker}:END-->`;
80
+ const regex = new RegExp(`${escapeRegex(startMarker)}([\\s\\S]*?)${escapeRegex(endMarker)}`);
81
+ const match = fullReadme.match(regex);
82
+ if (match) {
83
+ content = match[1].trim();
84
+ }
85
+ return { marker, content };
86
+ });
87
+ const updatedReadme = (0, generator_1.updateReadmeMarkers)(existingReadme, markerSections);
88
+ (0, fs_1.writeFileSync)(options.readme, updatedReadme, 'utf-8');
89
+ const dataDir = 'data';
90
+ if (!(0, fs_1.existsSync)(dataDir)) {
91
+ (0, fs_1.mkdirSync)(dataDir, { recursive: true });
92
+ }
93
+ (0, fs_1.writeFileSync)((0, path_1.join)(dataDir, 'profile.json'), JSON.stringify(data, null, 2), 'utf-8');
94
+ spinner.succeed(chalk_1.default.green(`✓ README 已刷新: ${options.readme}`));
95
+ console.log(chalk_1.default.gray(` 数据已保存到: ${(0, path_1.join)(dataDir, 'profile.json')}`));
96
+ }
97
+ catch (error) {
98
+ spinner.fail(chalk_1.default.red('刷新失败'));
99
+ console.error(chalk_1.default.red(`错误: ${error.message}`));
100
+ process.exit(1);
101
+ }
102
+ });
103
+ program
104
+ .command('validate')
105
+ .description('验证配置文件')
106
+ .option('-c, --config <path>', '配置文件路径', 'config.yml')
107
+ .action(async (options) => {
108
+ try {
109
+ if (!(0, fs_1.existsSync)(options.config)) {
110
+ throw new Error(`配置文件不存在: ${options.config}`);
111
+ }
112
+ const config = (0, config_1.loadConfig)(options.config);
113
+ console.log(chalk_1.default.green('✓ 配置文件有效'));
114
+ console.log(chalk_1.default.gray('\n配置内容:'));
115
+ console.log(JSON.stringify(config, null, 2));
116
+ }
117
+ catch (error) {
118
+ console.error(chalk_1.default.red(`✗ 配置文件无效: ${error.message}`));
119
+ process.exit(1);
120
+ }
121
+ });
122
+ function escapeRegex(str) {
123
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
124
+ }
125
+ program.parse();
126
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { ProfileConfig } from './types';
2
+ export declare function loadConfig(configPath: string): ProfileConfig;
3
+ export declare function validateConfig(config: ProfileConfig): void;
4
+ export declare function getDefaultConfig(): Partial<ProfileConfig>;
5
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,CAc5D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CA+B1D;AAED,wBAAgB,gBAAgB,IAAI,OAAO,CAAC,aAAa,CAAC,CAazD"}
package/dist/config.js ADDED
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadConfig = loadConfig;
4
+ exports.validateConfig = validateConfig;
5
+ exports.getDefaultConfig = getDefaultConfig;
6
+ const fs_1 = require("fs");
7
+ const yaml_1 = require("yaml");
8
+ function loadConfig(configPath) {
9
+ const content = (0, fs_1.readFileSync)(configPath, 'utf-8');
10
+ let config;
11
+ if (configPath.endsWith('.json')) {
12
+ config = JSON.parse(content);
13
+ }
14
+ else if (configPath.endsWith('.yml') || configPath.endsWith('.yaml')) {
15
+ config = (0, yaml_1.parse)(content);
16
+ }
17
+ else {
18
+ throw new Error('配置文件必须是 .json, .yml 或 .yaml 格式');
19
+ }
20
+ validateConfig(config);
21
+ return config;
22
+ }
23
+ function validateConfig(config) {
24
+ if (!config.username || typeof config.username !== 'string') {
25
+ throw new Error('配置中必须包含有效的 username 字段');
26
+ }
27
+ if (!config.intro || typeof config.intro !== 'object') {
28
+ throw new Error('配置中必须包含 intro 对象');
29
+ }
30
+ if (!config.intro.zh && !config.intro.en) {
31
+ throw new Error('intro 必须至少包含 zh 或 en 字段');
32
+ }
33
+ if (config.featuredRepos && !Array.isArray(config.featuredRepos)) {
34
+ throw new Error('featuredRepos 必须是数组');
35
+ }
36
+ if (config.sections && !Array.isArray(config.sections)) {
37
+ throw new Error('sections 必须是数组');
38
+ }
39
+ if (config.sections) {
40
+ for (const section of config.sections) {
41
+ if (!['stats', 'languages', 'repos', 'custom'].includes(section.type)) {
42
+ throw new Error(`不支持的 section 类型: ${section.type}`);
43
+ }
44
+ if (section.type === 'custom' && !section.content) {
45
+ throw new Error('custom 类型的 section 必须包含 content 字段');
46
+ }
47
+ }
48
+ }
49
+ }
50
+ function getDefaultConfig() {
51
+ return {
52
+ sections: [
53
+ { type: 'stats', marker: 'STATS' },
54
+ { type: 'languages', marker: 'LANGUAGES' },
55
+ { type: 'repos', marker: 'REPOS' }
56
+ ],
57
+ style: {
58
+ theme: 'auto',
59
+ icons: true,
60
+ badges: true
61
+ }
62
+ };
63
+ }
64
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;AAIA,gCAcC;AAED,wCA+BC;AAED,4CAaC;AAlED,2BAAkC;AAClC,+BAA0C;AAG1C,SAAgB,UAAU,CAAC,UAAkB;IAC3C,MAAM,OAAO,GAAG,IAAA,iBAAY,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAElD,IAAI,MAAqB,CAAC;IAC1B,IAAI,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACjC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;SAAM,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACvE,MAAM,GAAG,IAAA,YAAS,EAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,cAAc,CAAC,MAAM,CAAC,CAAC;IACvB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,cAAc,CAAC,MAAqB;IAClD,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,IAAI,MAAM,CAAC,aAAa,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACtC,IAAI,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtE,MAAM,IAAI,KAAK,CAAC,oBAAoB,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YACtD,CAAC;YACD,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;gBAClD,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAgB,gBAAgB;IAC9B,OAAO;QACL,QAAQ,EAAE;YACR,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;YAClC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE;YAC1C,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;SACnC;QACD,KAAK,EAAE;YACL,KAAK,EAAE,MAAM;YACb,KAAK,EAAE,IAAI;YACX,MAAM,EAAE,IAAI;SACb;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { ProfileConfig, ProfileData, MarkerSection } from './types';
2
+ export declare class ReadmeGenerator {
3
+ private config;
4
+ private data;
5
+ constructor(config: ProfileConfig, data: ProfileData);
6
+ generate(): string;
7
+ private generateHeader;
8
+ private generateIntro;
9
+ private generateSection;
10
+ private generateStats;
11
+ private generateLanguages;
12
+ private generateRepos;
13
+ private generateFooter;
14
+ }
15
+ export declare function updateReadmeMarkers(existingReadme: string, markerSections: MarkerSection[]): string;
16
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEpE,qBAAa,eAAe;IAExB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,IAAI;gBADJ,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,WAAW;IAG3B,QAAQ,IAAI,MAAM;IAiBlB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,eAAe;IA0BvB,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,iBAAiB;IAoBzB,OAAO,CAAC,aAAa;IA+BrB,OAAO,CAAC,cAAc;CAcvB;AAED,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,aAAa,EAAE,GAC9B,MAAM,CAsBR"}
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReadmeGenerator = void 0;
4
+ exports.updateReadmeMarkers = updateReadmeMarkers;
5
+ class ReadmeGenerator {
6
+ constructor(config, data) {
7
+ this.config = config;
8
+ this.data = data;
9
+ }
10
+ generate() {
11
+ const sections = [];
12
+ sections.push(this.generateHeader());
13
+ sections.push(this.generateIntro());
14
+ if (this.config.sections) {
15
+ for (const section of this.config.sections) {
16
+ sections.push(this.generateSection(section));
17
+ }
18
+ }
19
+ sections.push(this.generateFooter());
20
+ return sections.filter(s => s.trim()).join('\n\n');
21
+ }
22
+ generateHeader() {
23
+ const { user } = this.data;
24
+ return `# Hi there, I'm ${user.name || user.login} 👋
25
+
26
+ <div align="center">
27
+ <img src="${user.avatar_url}" width="150" height="150" alt="${user.login}" style="border-radius: 50%;" />
28
+ </div>`;
29
+ }
30
+ generateIntro() {
31
+ const { intro } = this.config;
32
+ const parts = [];
33
+ if (intro.zh) {
34
+ parts.push(`## 👨‍💻 关于我
35
+
36
+ ${intro.zh}`);
37
+ }
38
+ if (intro.en) {
39
+ parts.push(`## 👨‍💻 About Me
40
+
41
+ ${intro.en}`);
42
+ }
43
+ return parts.join('\n\n');
44
+ }
45
+ generateSection(section) {
46
+ const marker = section.marker || section.type.toUpperCase();
47
+ let content = '';
48
+ switch (section.type) {
49
+ case 'stats':
50
+ content = this.generateStats();
51
+ break;
52
+ case 'languages':
53
+ content = this.generateLanguages();
54
+ break;
55
+ case 'repos':
56
+ content = this.generateRepos();
57
+ break;
58
+ case 'custom':
59
+ content = section.content || '';
60
+ break;
61
+ }
62
+ if (!content)
63
+ return '';
64
+ return `<!--${marker}:START-->
65
+ ${section.title ? `## ${section.title}\n\n` : ''}${content}
66
+ <!--${marker}:END-->`;
67
+ }
68
+ generateStats() {
69
+ const { user, totalStars, totalForks } = this.data;
70
+ return `## 📊 GitHub 统计
71
+
72
+ <div align="center">
73
+
74
+ | 统计项 | 数值 |
75
+ |:---:|:---:|
76
+ | 🌟 总 Stars | ${totalStars} |
77
+ | 🍴 总 Forks | ${totalForks} |
78
+ | 📦 公开仓库 | ${user.public_repos} |
79
+ | 👥 关注者 | ${user.followers} |
80
+ | 💫 正在关注 | ${user.following} |
81
+
82
+ </div>`;
83
+ }
84
+ generateLanguages() {
85
+ const { languages } = this.data;
86
+ const sorted = Object.entries(languages)
87
+ .sort(([, a], [, b]) => b - a)
88
+ .slice(0, 8);
89
+ if (sorted.length === 0)
90
+ return '';
91
+ const rows = sorted.map(([lang, count]) => {
92
+ const percentage = ((count / Object.values(languages).reduce((a, b) => a + b, 0)) * 100).toFixed(1);
93
+ return `| ${lang} | ${count} | ${percentage}% |`;
94
+ }).join('\n');
95
+ return `## 💻 编程语言
96
+
97
+ | 语言 | 仓库数 | 占比 |
98
+ |:---|:---:|:---:|
99
+ ${rows}`;
100
+ }
101
+ generateRepos() {
102
+ const { repos } = this.data;
103
+ const featured = this.config.featuredRepos || [];
104
+ let displayRepos = repos;
105
+ if (featured.length > 0) {
106
+ displayRepos = repos.filter(r => featured.some(f => r.name === f || r.full_name === f));
107
+ }
108
+ else {
109
+ displayRepos = repos
110
+ .sort((a, b) => b.stargazers_count - a.stargazers_count)
111
+ .slice(0, 6);
112
+ }
113
+ if (displayRepos.length === 0)
114
+ return '';
115
+ const cards = displayRepos.map(repo => {
116
+ const lang = repo.language || 'N/A';
117
+ const desc = repo.description || '暂无描述';
118
+ return `### 📦 [${repo.name}](${repo.html_url})
119
+ ${desc}
120
+
121
+ ⭐ ${repo.stargazers_count} stars | 🍴 ${repo.forks_count} forks | 📝 ${lang}`;
122
+ }).join('\n\n');
123
+ return `## 🔥 精选项目
124
+
125
+ ${cards}`;
126
+ }
127
+ generateFooter() {
128
+ const { updatedAt } = this.data;
129
+ const date = new Date(updatedAt).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
130
+ return `---
131
+
132
+ <div align="center">
133
+
134
+ *此 README 由 [breathing-github-profile](https://github.com/webywz/breathing-github-profile) 自动生成*
135
+
136
+ *最后更新: ${date} (北京时间)*
137
+
138
+ </div>`;
139
+ }
140
+ }
141
+ exports.ReadmeGenerator = ReadmeGenerator;
142
+ function updateReadmeMarkers(existingReadme, markerSections) {
143
+ let updated = existingReadme;
144
+ for (const { marker, content } of markerSections) {
145
+ const startMarker = `<!--${marker}:START-->`;
146
+ const endMarker = `<!--${marker}:END-->`;
147
+ const regex = new RegExp(`${escapeRegex(startMarker)}[\\s\\S]*?${escapeRegex(endMarker)}`, 'g');
148
+ const replacement = `${startMarker}\n${content}\n${endMarker}`;
149
+ if (regex.test(updated)) {
150
+ updated = updated.replace(regex, replacement);
151
+ }
152
+ else {
153
+ updated += `\n\n${replacement}`;
154
+ }
155
+ }
156
+ return updated;
157
+ }
158
+ function escapeRegex(str) {
159
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
160
+ }
161
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { GitHubUser, GitHubRepo, ProfileData } from './types';
2
+ export declare class GitHubClient {
3
+ private token?;
4
+ private baseUrl;
5
+ constructor(token?: string);
6
+ private fetch;
7
+ getUser(username: string): Promise<GitHubUser>;
8
+ getRepos(username: string): Promise<GitHubRepo[]>;
9
+ getProfileData(username: string): Promise<ProfileData>;
10
+ }
11
+ //# sourceMappingURL=github.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE9D,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAC,CAAS;IACvB,OAAO,CAAC,OAAO,CAA4B;gBAE/B,KAAK,CAAC,EAAE,MAAM;YAIZ,KAAK;IAmBb,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAI9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAqBjD,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CA4B7D"}
package/dist/github.js ADDED
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GitHubClient = void 0;
4
+ class GitHubClient {
5
+ constructor(token) {
6
+ this.baseUrl = 'https://api.github.com';
7
+ this.token = token || process.env.GITHUB_TOKEN;
8
+ }
9
+ async fetch(endpoint) {
10
+ const headers = {
11
+ 'Accept': 'application/vnd.github.v3+json',
12
+ 'User-Agent': 'breathing-github-profile'
13
+ };
14
+ if (this.token) {
15
+ headers['Authorization'] = `token ${this.token}`;
16
+ }
17
+ const response = await fetch(`${this.baseUrl}${endpoint}`, { headers });
18
+ if (!response.ok) {
19
+ throw new Error(`GitHub API 错误: ${response.status} ${response.statusText}`);
20
+ }
21
+ return response.json();
22
+ }
23
+ async getUser(username) {
24
+ return this.fetch(`/users/${username}`);
25
+ }
26
+ async getRepos(username) {
27
+ const repos = [];
28
+ let page = 1;
29
+ const perPage = 100;
30
+ const maxPages = 10;
31
+ while (page <= maxPages) {
32
+ const batch = await this.fetch(`/users/${username}/repos?per_page=${perPage}&page=${page}&sort=updated`);
33
+ if (batch.length === 0)
34
+ break;
35
+ repos.push(...batch);
36
+ if (batch.length < perPage)
37
+ break;
38
+ page++;
39
+ }
40
+ return repos.filter(repo => !repo.fork);
41
+ }
42
+ async getProfileData(username) {
43
+ const [user, repos] = await Promise.all([
44
+ this.getUser(username),
45
+ this.getRepos(username)
46
+ ]);
47
+ const languages = {};
48
+ let totalStars = 0;
49
+ let totalForks = 0;
50
+ for (const repo of repos) {
51
+ totalStars += repo.stargazers_count;
52
+ totalForks += repo.forks_count;
53
+ if (repo.language) {
54
+ languages[repo.language] = (languages[repo.language] || 0) + 1;
55
+ }
56
+ }
57
+ return {
58
+ user,
59
+ repos,
60
+ languages,
61
+ totalStars,
62
+ totalForks,
63
+ updatedAt: new Date().toISOString()
64
+ };
65
+ }
66
+ }
67
+ exports.GitHubClient = GitHubClient;
68
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":";;;AAEA,MAAa,YAAY;IAIvB,YAAY,KAAc;QAFlB,YAAO,GAAG,wBAAwB,CAAC;QAGzC,IAAI,CAAC,KAAK,GAAG,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IACjD,CAAC;IAEO,KAAK,CAAC,KAAK,CAAI,QAAgB;QACrC,MAAM,OAAO,GAA2B;YACtC,QAAQ,EAAE,gCAAgC;YAC1C,YAAY,EAAE,0BAA0B;SACzC,CAAC;QAEF,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,eAAe,CAAC,GAAG,SAAS,IAAI,CAAC,KAAK,EAAE,CAAC;QACnD,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAExE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QAC9E,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,EAAgB,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,QAAgB;QAC5B,OAAO,IAAI,CAAC,KAAK,CAAa,UAAU,QAAQ,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,QAAgB;QAC7B,MAAM,KAAK,GAAiB,EAAE,CAAC;QAC/B,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,CAAC;QACpB,MAAM,QAAQ,GAAG,EAAE,CAAC;QAEpB,OAAO,IAAI,IAAI,QAAQ,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAC5B,UAAU,QAAQ,mBAAmB,OAAO,SAAS,IAAI,eAAe,CACzE,CAAC;YAEF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,MAAM;YAC9B,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;YAErB,IAAI,KAAK,CAAC,MAAM,GAAG,OAAO;gBAAE,MAAM;YAClC,IAAI,EAAE,CAAC;QACT,CAAC;QAED,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,QAAgB;QACnC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACtC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;YACtB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;SACxB,CAAC,CAAC;QAEH,MAAM,SAAS,GAA2B,EAAE,CAAC;QAC7C,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,UAAU,GAAG,CAAC,CAAC;QAEnB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,UAAU,IAAI,IAAI,CAAC,gBAAgB,CAAC;YACpC,UAAU,IAAI,IAAI,CAAC,WAAW,CAAC;YAE/B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YACjE,CAAC;QACH,CAAC;QAED,OAAO;YACL,IAAI;YACJ,KAAK;YACL,SAAS;YACT,UAAU;YACV,UAAU;YACV,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;IACJ,CAAC;CACF;AAhFD,oCAgFC"}
@@ -0,0 +1,5 @@
1
+ export { ProfileConfig, ProfileData, GitHubUser, GitHubRepo, Section, StyleConfig } from './types';
2
+ export { loadConfig, validateConfig, getDefaultConfig } from './config';
3
+ export { GitHubClient } from './github';
4
+ export { ReadmeGenerator, updateReadmeMarkers } from './generator';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACnG,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.updateReadmeMarkers = exports.ReadmeGenerator = exports.GitHubClient = exports.getDefaultConfig = exports.validateConfig = exports.loadConfig = void 0;
4
+ var config_1 = require("./config");
5
+ Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_1.loadConfig; } });
6
+ Object.defineProperty(exports, "validateConfig", { enumerable: true, get: function () { return config_1.validateConfig; } });
7
+ Object.defineProperty(exports, "getDefaultConfig", { enumerable: true, get: function () { return config_1.getDefaultConfig; } });
8
+ var github_1 = require("./github");
9
+ Object.defineProperty(exports, "GitHubClient", { enumerable: true, get: function () { return github_1.GitHubClient; } });
10
+ var generator_1 = require("./generator");
11
+ Object.defineProperty(exports, "ReadmeGenerator", { enumerable: true, get: function () { return generator_1.ReadmeGenerator; } });
12
+ Object.defineProperty(exports, "updateReadmeMarkers", { enumerable: true, get: function () { return generator_1.updateReadmeMarkers; } });
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,mCAAwE;AAA/D,oGAAA,UAAU,OAAA;AAAE,wGAAA,cAAc,OAAA;AAAE,0GAAA,gBAAgB,OAAA;AACrD,mCAAwC;AAA/B,sGAAA,YAAY,OAAA;AACrB,yCAAmE;AAA1D,4GAAA,eAAe,OAAA;AAAE,gHAAA,mBAAmB,OAAA"}
@@ -0,0 +1,68 @@
1
+ export interface ProfileConfig {
2
+ username: string;
3
+ intro: {
4
+ zh?: string;
5
+ en?: string;
6
+ };
7
+ featuredRepos?: string[];
8
+ sections?: Section[];
9
+ style?: StyleConfig;
10
+ }
11
+ export interface Section {
12
+ type: 'stats' | 'languages' | 'repos' | 'custom';
13
+ title?: string;
14
+ content?: string;
15
+ marker?: string;
16
+ }
17
+ export interface StyleConfig {
18
+ theme?: 'light' | 'dark' | 'auto';
19
+ icons?: boolean;
20
+ badges?: boolean;
21
+ }
22
+ export interface GitHubUser {
23
+ login: string;
24
+ name: string;
25
+ bio: string;
26
+ public_repos: number;
27
+ followers: number;
28
+ following: number;
29
+ created_at: string;
30
+ avatar_url: string;
31
+ html_url: string;
32
+ location?: string;
33
+ blog?: string;
34
+ twitter_username?: string;
35
+ company?: string;
36
+ }
37
+ export interface GitHubRepo {
38
+ name: string;
39
+ full_name: string;
40
+ description: string;
41
+ html_url: string;
42
+ homepage: string;
43
+ stargazers_count: number;
44
+ forks_count: number;
45
+ language: string;
46
+ topics: string[];
47
+ created_at: string;
48
+ updated_at: string;
49
+ pushed_at: string;
50
+ size: number;
51
+ watchers_count: number;
52
+ open_issues_count: number;
53
+ archived: boolean;
54
+ fork: boolean;
55
+ }
56
+ export interface ProfileData {
57
+ user: GitHubUser;
58
+ repos: GitHubRepo[];
59
+ languages: Record<string, number>;
60
+ totalStars: number;
61
+ totalForks: number;
62
+ updatedAt: string;
63
+ }
64
+ export interface MarkerSection {
65
+ marker: string;
66
+ content: string;
67
+ }
68
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE;QACL,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,EAAE,CAAC,EAAE,MAAM,CAAC;KACb,CAAC;IACF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,OAAO,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,CAAC;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IAClC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,115 @@
1
+ # 示例和演示
2
+
3
+ 本目录包含使用 breathing-github-profile 的示例配置。
4
+
5
+ ## 📄 webywz.yml
6
+
7
+ 完整的配置示例,展示所有可用功能:
8
+
9
+ - ✅ 中英文双语介绍
10
+ - ✅ 精选仓库列表
11
+ - ✅ 多种章节类型(统计、语言、项目)
12
+ - ✅ 自定义内容(技术栈徽章)
13
+ - ✅ 样式配置
14
+
15
+ ## 🚀 快速测试
16
+
17
+ ### 1. 验证配置
18
+
19
+ ```bash
20
+ npm run validate -- -c examples/webywz.yml
21
+ ```
22
+
23
+ 预期输出:
24
+ ```
25
+ ✓ 配置文件有效
26
+ ```
27
+
28
+ ### 2. 生成 README(演示模式)
29
+
30
+ ```bash
31
+ # 生成到临时文件
32
+ npm run generate -- -c examples/webywz.yml -o examples/test-output.md
33
+ ```
34
+
35
+ ### 3. 测试刷新功能
36
+
37
+ ```bash
38
+ # 首先生成一个 README
39
+ npm run generate -- -c examples/webywz.yml -o examples/demo.md
40
+
41
+ # 手动编辑 demo.md,在标记外添加自定义内容
42
+
43
+ # 刷新(只更新标记部分)
44
+ npm run refresh -- -c examples/webywz.yml -r examples/demo.md
45
+ ```
46
+
47
+ 你会发现自定义内容被保留,只有标记部分被更新!
48
+
49
+ ## 📝 创建你自己的配置
50
+
51
+ 1. 复制 `webywz.yml` 作为模板
52
+ 2. 修改 `username` 为你的 GitHub 用户名
53
+ 3. 更新 `intro` 中的介绍
54
+ 4. 根据需要调整 `sections`
55
+ 5. 运行 `npm run generate` 生成 README
56
+
57
+ ## 🔧 配置选项参考
58
+
59
+ ### 章节类型
60
+
61
+ #### stats
62
+ 显示 GitHub 统计信息
63
+
64
+ ```yaml
65
+ - type: stats
66
+ marker: STATS
67
+ title: 📊 我的统计
68
+ ```
69
+
70
+ #### languages
71
+ 显示编程语言分布
72
+
73
+ ```yaml
74
+ - type: languages
75
+ marker: LANGUAGES
76
+ title: 💻 技术栈
77
+ ```
78
+
79
+ #### repos
80
+ 显示精选项目
81
+
82
+ ```yaml
83
+ - type: repos
84
+ marker: REPOS
85
+ title: 🔥 热门项目
86
+ ```
87
+
88
+ #### custom
89
+ 自定义 Markdown 内容
90
+
91
+ ```yaml
92
+ - type: custom
93
+ marker: BADGES
94
+ title: 🎯 技能徽章
95
+ content: |
96
+ ![TypeScript](https://img.shields.io/badge/-TypeScript-blue)
97
+ ![React](https://img.shields.io/badge/-React-61DAFB)
98
+ ```
99
+
100
+ ## 💡 提示
101
+
102
+ 1. **标记名称**: 确保每个章节的 `marker` 唯一
103
+ 2. **GitHub Token**: 设置 `GITHUB_TOKEN` 环境变量以避免 API 速率限制
104
+ 3. **精选仓库**: 使用 `featuredRepos` 手动选择要展示的项目
105
+ 4. **自定义样式**: 在 `custom` 章节中使用 HTML 和 Markdown
106
+
107
+ ## 🌟 实际案例
108
+
109
+ 使用此工具的 Profile README:
110
+
111
+ - [webywz/webywz](https://github.com/webywz/webywz) - 配套的 profile 仓库
112
+
113
+ ---
114
+
115
+ 有问题?查看 [主文档](../README.md) 或提交 [issue](https://github.com/webywz/breathing-github-profile/issues)。
@@ -0,0 +1,21 @@
1
+ username: octocat
2
+
3
+ intro:
4
+ zh: |
5
+ 👋 你好!我是 Octocat
6
+
7
+ GitHub 的吉祥物,开源爱好者
8
+
9
+ en: |
10
+ 👋 Hi! I'm Octocat
11
+
12
+ GitHub's mascot and open source enthusiast
13
+
14
+ sections:
15
+ - type: stats
16
+ marker: STATS
17
+ title: 📊 统计数据
18
+
19
+ - type: languages
20
+ marker: LANGUAGES
21
+ title: 💻 编程语言
@@ -0,0 +1,66 @@
1
+ username: webywz
2
+
3
+ intro:
4
+ zh: |
5
+ 🚀 全栈开发者 | AI 爱好者 | 开源贡献者
6
+
7
+ 💡 专注于现代 Web 开发和人工智能技术
8
+ - 🔧 后端:Node.js (NestJS) / Python (FastAPI)
9
+ - 🎨 前端:React / Vue / TypeScript
10
+ - 🤖 AI:LangChain / Prompt Engineering
11
+ - 🛠 工具:GitHub Actions / Docker / Cloudflare
12
+
13
+ 📫 欢迎交流合作!
14
+
15
+ en: |
16
+ 🚀 Full-stack Developer | AI Enthusiast | Open Source Contributor
17
+
18
+ 💡 Focus on Modern Web Development and AI Technologies
19
+ - 🔧 Backend: Node.js (NestJS) / Python (FastAPI)
20
+ - 🎨 Frontend: React / Vue / TypeScript
21
+ - 🤖 AI: LangChain / Prompt Engineering
22
+ - 🛠 Tools: GitHub Actions / Docker / Cloudflare
23
+
24
+ 📫 Let's connect and collaborate!
25
+
26
+ featuredRepos:
27
+ - breathing-github-profile
28
+ - webywz
29
+
30
+ sections:
31
+ - type: stats
32
+ marker: STATS
33
+ title: 📊 GitHub 统计
34
+
35
+ - type: languages
36
+ marker: LANGUAGES
37
+ title: 💻 常用语言
38
+
39
+ - type: repos
40
+ marker: REPOS
41
+ title: 🔥 精选项目
42
+
43
+ - type: custom
44
+ marker: TECH_STACK
45
+ title: 🛠 技术栈
46
+ content: |
47
+ ### 后端开发
48
+ ![Node.js](https://img.shields.io/badge/-Node.js-339933?style=flat-square&logo=node.js&logoColor=white)
49
+ ![NestJS](https://img.shields.io/badge/-NestJS-E0234E?style=flat-square&logo=nestjs&logoColor=white)
50
+ ![Python](https://img.shields.io/badge/-Python-3776AB?style=flat-square&logo=python&logoColor=white)
51
+ ![FastAPI](https://img.shields.io/badge/-FastAPI-009688?style=flat-square&logo=fastapi&logoColor=white)
52
+
53
+ ### 前端开发
54
+ ![TypeScript](https://img.shields.io/badge/-TypeScript-3178C6?style=flat-square&logo=typescript&logoColor=white)
55
+ ![React](https://img.shields.io/badge/-React-61DAFB?style=flat-square&logo=react&logoColor=black)
56
+ ![Vue](https://img.shields.io/badge/-Vue-4FC08D?style=flat-square&logo=vue.js&logoColor=white)
57
+
58
+ ### AI & 工具
59
+ ![LangChain](https://img.shields.io/badge/-LangChain-1C3C3C?style=flat-square&logo=chainlink&logoColor=white)
60
+ ![Docker](https://img.shields.io/badge/-Docker-2496ED?style=flat-square&logo=docker&logoColor=white)
61
+ ![GitHub Actions](https://img.shields.io/badge/-GitHub_Actions-2088FF?style=flat-square&logo=github-actions&logoColor=white)
62
+
63
+ style:
64
+ theme: auto
65
+ icons: true
66
+ badges: true
package/package.json CHANGED
@@ -1,6 +1,66 @@
1
1
  {
2
2
  "name": "@webywz/breathing-github-profile",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0",
4
+ "description": "可复用的活跃 GitHub profile README 生成器,支持每日自动刷新",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "breathing-profile": "dist/cli.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc && node -e \"require('fs').chmodSync('dist/cli.js', 0o755)\"",
12
+ "dev": "tsc --watch",
13
+ "test": "jest",
14
+ "test:watch": "jest --watch",
15
+ "refresh": "tsx src/cli.ts refresh",
16
+ "generate": "tsx src/cli.ts generate",
17
+ "validate": "tsx src/cli.ts validate",
18
+ "lint": "eslint src --ext .ts",
19
+ "prepare": "npm run build",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "github",
24
+ "profile",
25
+ "readme",
26
+ "generator",
27
+ "automation"
28
+ ],
29
+ "author": "webywz",
30
+ "license": "MIT",
31
+ "files": [
32
+ "dist",
33
+ "examples"
34
+ ],
35
+ "dependencies": {
36
+ "yaml": "^2.3.4",
37
+ "commander": "^11.1.0",
38
+ "chalk": "^4.1.2",
39
+ "ora": "^5.4.1"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^20.10.5",
43
+ "@types/jest": "^29.5.11",
44
+ "@typescript-eslint/eslint-plugin": "^6.15.0",
45
+ "@typescript-eslint/parser": "^6.15.0",
46
+ "eslint": "^8.56.0",
47
+ "jest": "^29.7.0",
48
+ "ts-jest": "^29.1.1",
49
+ "typescript": "^5.3.3",
50
+ "tsx": "^4.7.0"
51
+ },
52
+ "engines": {
53
+ "node": ">=16.0.0"
54
+ },
55
+ "publishConfig": {
56
+ "access": "public"
57
+ },
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "git+https://github.com/webywz/breathing-github-profile.git"
61
+ },
62
+ "homepage": "https://github.com/webywz/breathing-github-profile#readme",
63
+ "bugs": {
64
+ "url": "https://github.com/webywz/breathing-github-profile/issues"
65
+ }
66
+ }