Skip to content

Commit 805a24f

Browse files
committed
chore: introduce plugin via common repository
1 parent bef7a03 commit 805a24f

5 files changed

Lines changed: 23 additions & 225 deletions

File tree

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
"lintfix": "eslint '{src,example}/**/*.{js,ts}' --fix",
2727
"lint": "eslint '{src,example}/**/*.{js,ts}'",
2828
"format": "prettier {src,example,script}/**/*.{js,ts,wxss,less,wxml,html,json,md,wxs} --write",
29-
"site": "cd site && vite build",
30-
"site:dev": "cd site && vite",
31-
"site:intranet": "cd site && vite build --mode intranet",
29+
"site": "cd site && vite build --configLoader runner",
30+
"site:dev": "cd site && vite --configLoader runner",
31+
"site:intranet": "cd site && vite build --mode intranet --configLoader runner",
3232
"site:prerender": "node script/prerender.mjs",
3333
"cover": "jest --coverage",
3434
"test": "jest && jest -c jest.e2e.config.js",
@@ -110,12 +110,12 @@
110110
"stylelint": "^13.13.1",
111111
"tdesign-icons-view": "^0.3.6",
112112
"tdesign-publish-cli": "^0.0.12",
113-
"tdesign-site-components": "0.17.0-alpha.1",
113+
"tdesign-site-components": "^0.16.0",
114114
"tdesign-theme-generator": "^1.1.0",
115115
"tinycolor2": "^1.4.2",
116116
"tslib": "^2.8.1",
117117
"typescript": "~4.7.2",
118-
"vite": "^2.7.6",
118+
"vite": "^6.2.0",
119119
"vite-plugin-tdoc": "^2.0.1",
120120
"vue": "^3.2.4",
121121
"vue-router": "^4.0.11"
Lines changed: 10 additions & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -1,239 +1,32 @@
1-
/* eslint-disable */
2-
import { promises, readdirSync, statSync } from 'fs';
3-
import path from 'path';
4-
import type { ViteDevServer } from 'vite';
5-
import { CHILD_TO_PARENT_MAP } from './components';
6-
import type { ComponentLog, ComponentLogMap, LogItem, Logs, LogType, VersionLog } from './types';
1+
import { promises } from 'fs';
2+
import path, { dirname } from 'path';
3+
import { fileURLToPath } from 'url';
74

8-
const outputPath = path.resolve(__dirname, '../../../changelog.json');
9-
const changelogPath = path.resolve(__dirname, '../../../CHANGELOG.md');
10-
const componentsDir = path.resolve(__dirname, '../../../src');
5+
import type { ViteDevServer } from 'vite';
6+
import generateChangelogJson from '../../../src/_common/docs/plugins/changelog-to-json';
117

12-
const EXCLUDED_DIR = ['_common', 'common'];
13-
const COMP_LIST = getComponentList();
8+
const __dirname = dirname(fileURLToPath(import.meta.url));
149

15-
export const LOG_TYPES = ['🚨 Breaking Changes', '🚀 Features', '🐞 Bug Fixes'] as const;
10+
const outputPath = path.resolve(__dirname, '../../dist/changelog.json');
11+
const changelogPath = path.resolve(__dirname, '../../../CHANGELOG.md');
1612

1713
export default function changelog2Json() {
1814
return {
1915
name: 'changelog-to-json',
2016
configureServer(server: ViteDevServer) {
2117
// 开发模式时拦截请求
2218
server.middlewares.use('/changelog.json', async (_, res) => {
23-
const json = await generateChangelogJson();
19+
const json = await generateChangelogJson(changelogPath, 'mobile');
2420
res.setHeader('Content-Type', 'application/json');
2521
res.end(JSON.stringify(json));
2622
});
2723
},
2824
async closeBundle() {
2925
// 生产构建时写入物理文件
3026
if (process.env.NODE_ENV === 'production') {
31-
const json = await generateChangelogJson();
27+
const json = await generateChangelogJson(changelogPath, 'mobile');
3228
await promises.writeFile(outputPath, JSON.stringify(json));
3329
}
3430
},
3531
};
3632
}
37-
38-
async function generateChangelogJson() {
39-
try {
40-
const logMd = await promises.readFile(changelogPath, 'utf-8');
41-
const detailedLogs = parseMd2Json(logMd);
42-
const compMap = formatJson2CompMap(detailedLogs);
43-
console.log('\x1b[32m%s\x1b[0m', '✅ Sync CHANGELOG.md to changelog.json');
44-
return compMap;
45-
} catch (error) {
46-
console.error('\x1b[31m%s\x1b[0m', '❌ Fail to generate changelog.json', '\x1b[33m', error);
47-
return {};
48-
}
49-
}
50-
51-
/**
52-
* 将整份 Markdown 先根据版本号拆分
53-
*/
54-
function parseMd2Json(logMd: string) {
55-
const headerRegex = /^\s*##\s*🌈\s*(\d+\.\d+\.\d+)\s+`(\d{4}-\d{2}-\d{2})`\s*$/gm;
56-
const matches = Array.from(logMd.matchAll(headerRegex));
57-
58-
const logs = matches.map((match, i) => {
59-
const version = match[1];
60-
const date = match[2];
61-
62-
const start = match.index + match[0].length;
63-
const end = i < matches.length - 1 ? matches[i + 1].index : logMd.length;
64-
const log = logMd.slice(start, end).trim();
65-
66-
return {
67-
version,
68-
date,
69-
log: parseLogByType(log),
70-
};
71-
});
72-
73-
return logs;
74-
}
75-
76-
/**
77-
* 进一步根据指定的变更类型拆分
78-
*/
79-
function parseLogByType(logBlock: string) {
80-
const logs: Logs = {};
81-
82-
LOG_TYPES.forEach((type) => {
83-
const typeRegex = new RegExp(`### ${type}\\r?\\n([\\s\\S]+?)(?=### |$)`, 'g');
84-
const matches = Array.from(logBlock.matchAll(typeRegex));
85-
86-
if (matches.length > 0) {
87-
const logBlock = matches.map((match) => match[1]).join('\n');
88-
const entries = extractLogEntries(logBlock);
89-
logs[type] = groupLogByComponent(entries);
90-
}
91-
});
92-
93-
return logs;
94-
}
95-
96-
/**
97-
* 获取每种变更类型里面的每一段日志
98-
* - case 1: 单独一行 -> 作为一条
99-
* - case 2: 存在父子列表 -> 使用换行符,合并为一条
100-
*/
101-
function extractLogEntries(logBlock: string) {
102-
const lines = logBlock.split('\n').filter((line) => line.trim() !== '');
103-
const logs: string[] = [];
104-
105-
let currEntry = '';
106-
for (let i = 0; i < lines.length; i++) {
107-
const line = lines[i].trim();
108-
109-
// 跳过空行
110-
if (!line) continue;
111-
112-
// 是否为子项(短横线前面有空格)
113-
const isChildEntry = /^\s+-/.test(lines[i]);
114-
115-
// 是否为父项(直接以短横线开头)
116-
const isParentEntry = line.startsWith('-') && !isChildEntry;
117-
118-
if (isParentEntry) {
119-
// 如果是父项,保存之前的日志
120-
if (currEntry) {
121-
logs.push(currEntry.trim());
122-
}
123-
// 开始新项,去掉开头的 -
124-
currEntry = line.substring(1).trim();
125-
} else if (isChildEntry) {
126-
// 如果是子项,添加到当前项中
127-
const childContent = line.replace(/^\s*-\s*/, '').trim();
128-
currEntry += `\n${childContent}`;
129-
}
130-
}
131-
132-
// 处理最后一项
133-
logs.push(currEntry.trim());
134-
return logs;
135-
}
136-
137-
/**
138-
* 根据每一条日志提及的组件名,将其归类
139-
*/
140-
function groupLogByComponent(entries: string[]) {
141-
const logs: LogItem[] = [];
142-
143-
const compRegex = /`([^`]+)`/g;
144-
entries.forEach((entry) => {
145-
// 使用 Set 去重
146-
const components = [
147-
...new Set(
148-
Array.from(entry.matchAll(compRegex))
149-
// 所有反引号包裹的字符
150-
.map((match) => match[1])
151-
// 过滤无效组件名
152-
.filter((name) => COMP_LIST.includes(name))
153-
// 将子组件转换为父组件名
154-
.map((name) => CHILD_TO_PARENT_MAP[name] || name),
155-
),
156-
];
157-
158-
// 如果一条日志提到了多个组件,则每个组件都插入一条对应的日志
159-
components.forEach((component) => {
160-
logs.push({
161-
component,
162-
description: entry,
163-
});
164-
});
165-
});
166-
167-
return logs;
168-
}
169-
170-
/**
171-
* 将解析后的日志 JSON 转换为以组件名作为 key 的映射格式
172-
*/
173-
function formatJson2CompMap(logJson: VersionLog[]) {
174-
const compMap: ComponentLogMap = {};
175-
176-
logJson.forEach((entry) => {
177-
const { version, date, log } = entry;
178-
179-
(Object.keys(log) as LogType[]).forEach((type) => {
180-
log[type]?.forEach((item: LogItem) => {
181-
const { component, description } = item;
182-
183-
if (!compMap[component]) {
184-
compMap[component] = [];
185-
}
186-
187-
// 查找当前组件的版本记录
188-
let versionEntry = compMap[component].find((v) => v.version === version);
189-
190-
if (!versionEntry) {
191-
versionEntry = {
192-
version,
193-
date,
194-
} as ComponentLog;
195-
compMap[component].push(versionEntry);
196-
}
197-
198-
if (!versionEntry[type]) {
199-
versionEntry[type] = [];
200-
}
201-
versionEntry[type]?.push(description);
202-
});
203-
});
204-
});
205-
206-
// 按组件名字母顺序排序
207-
const sortedCompMap = Object.keys(compMap)
208-
.sort((a, b) => a.localeCompare(b))
209-
.reduce((acc, key) => ({ ...acc, [key]: compMap[key] }), {});
210-
211-
return sortedCompMap as ComponentLogMap;
212-
}
213-
214-
/**
215-
* 使组件名符合帕斯卡命名规范
216-
*/
217-
function convert2PascalCase(str: string) {
218-
return str
219-
.split(/[-_]/)
220-
.map((word: string) => word.charAt(0).toUpperCase() + word.slice(1))
221-
.join('');
222-
}
223-
224-
/**
225-
* 生成可用的组件名列表
226-
*/
227-
function getComponentList() {
228-
const compList: string[] = [];
229-
const files = readdirSync(componentsDir);
230-
files.forEach((file) => {
231-
const filePath = path.join(componentsDir, file);
232-
const stat = statSync(filePath);
233-
if (stat.isDirectory() && !EXCLUDED_DIR.includes(file)) {
234-
const componentName = convert2PascalCase(file);
235-
compList.push(componentName);
236-
}
237-
});
238-
return compList;
239-
}

site/plugins/plugin-tdoc/md-to-vue.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import fs from 'fs';
22
import path from 'path';
3+
import { fileURLToPath } from 'url';
34
import matter from 'gray-matter';
45

6+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
57
const componentPath = path.join(__dirname, './component.vue').replaceAll('\\', '/');
68

79
const DEFAULT_TABS = [

site/vite.config.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
import * as path from 'path';
1+
import path from 'path';
2+
import { fileURLToPath } from 'url';
3+
import { defineConfig } from 'vite';
24

35
import rollupResolve from '@rollup/plugin-node-resolve';
46
import vue from '@vitejs/plugin-vue';
57
import vueJsx from '@vitejs/plugin-vue-jsx';
6-
import { defineConfig } from 'vite';
78

89
import changelog2Json from './plugins/changelog-to-json';
910
import createTDesignPlugin from './plugins/plugin-tdoc';
1011

12+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
13+
1114
const publicPathMap: Record<string, string> = {
1215
preview: '/',
1316
intranet: '/miniprogram/',

src/_common

Submodule _common updated 187 files

0 commit comments

Comments
 (0)