Skip to content

Commit 75c65e0

Browse files
tarasovsnstarasov
and
starasov
authored
Fixed some errors in generator-types (#6095)
Co-authored-by: starasov <[email protected]>
1 parent 8a0c8a8 commit 75c65e0

File tree

6 files changed

+102
-55
lines changed

6 files changed

+102
-55
lines changed

antd-tools/generator-types/index.js

+17-14
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,21 @@ const pkg = require('../../package.json');
33
const { parseAndWrite } = require('./lib/index.js');
44
const rootPath = path.resolve(__dirname, '../../');
55

6-
try {
7-
parseAndWrite({
8-
version: pkg.version,
9-
name: 'ant-design-vue',
10-
path: path.resolve(rootPath, './components'),
11-
// default match lang
12-
test: /en-US\.md/,
13-
outputDir: path.resolve(rootPath, './vetur'),
14-
tagPrefix: 'a-',
6+
parseAndWrite({
7+
version: pkg.version,
8+
name: 'ant-design-vue',
9+
path: path.resolve(rootPath, './components'),
10+
typingsPath: path.resolve(rootPath, './typings/global.d.ts'),
11+
// default match lang
12+
test: /en-US\.md/,
13+
outputDir: path.resolve(rootPath, './vetur'),
14+
tagPrefix: 'a-',
15+
})
16+
.then(result => {
17+
// eslint-disable-next-line no-console
18+
console.log(`generator types success: ${result} tags generated`);
19+
})
20+
.catch(error => {
21+
console.error('generator types error', error);
22+
return Promise.reject(error);
1523
});
16-
// eslint-disable-next-line no-console
17-
console.log('generator types success');
18-
} catch (e) {
19-
console.error('generator types error', e);
20-
}

antd-tools/generator-types/src/formatter.ts

+14-4
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,19 @@ function parserProps(tag: VueTag, line: any) {
3434
});
3535
}
3636

37-
export function formatter(articals: Articals, componentName: string, tagPrefix = '') {
37+
export function formatter(
38+
articals: Articals,
39+
componentName: string,
40+
kebabComponentName: string,
41+
tagPrefix = '',
42+
) {
3843
if (!articals.length) {
3944
return;
4045
}
4146

4247
const tags: VueTag[] = [];
4348
const tag: VueTag = {
44-
name: getComponentName(componentName, tagPrefix),
49+
name: kebabComponentName,
4550
slots: [],
4651
events: [],
4752
attributes: [],
@@ -80,9 +85,13 @@ export function formatter(articals: Articals, componentName: string, tagPrefix =
8085
}
8186

8287
// 额外的子组件
83-
if (tableTitle.includes(componentName) && !tableTitle.includes('events')) {
88+
if (
89+
tableTitle.includes(componentName) &&
90+
!tableTitle.includes('events') &&
91+
!tableTitle.includes('()')
92+
) {
8493
const childTag: VueTag = {
85-
name: getComponentName(tableTitle.replace('.', ''), tagPrefix),
94+
name: getComponentName(tableTitle.replaceAll('.', '').replaceAll('/', ''), tagPrefix),
8695
slots: [],
8796
events: [],
8897
attributes: [],
@@ -93,6 +102,7 @@ export function formatter(articals: Articals, componentName: string, tagPrefix =
93102
tags.push(childTag);
94103
return;
95104
}
105+
96106
// 额外的子组件事件
97107
if (tableTitle.includes(componentName) && tableTitle.includes('events')) {
98108
const childTagName = getComponentName(
+64-25
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,91 @@
11
import glob from 'fast-glob';
2-
import { join, dirname } from 'path';
2+
import { dirname, join } from 'path';
33
import { mdParser } from './parser';
44
import { formatter } from './formatter';
55
import { genWebTypes } from './web-types';
6-
import { readFileSync, outputFileSync } from 'fs-extra';
6+
import { outputFileSync, readFileSync } from 'fs-extra';
77
import type { Options, VueTag } from './type';
8-
import { normalizePath, getComponentName } from './utils';
9-
import { genVeturTags, genVeturAttributes } from './vetur';
8+
import { getComponentName, normalizePath, toKebabCase } from './utils';
9+
import { genVeturAttributes, genVeturTags } from './vetur';
1010

11-
async function readMarkdown(options: Options) {
12-
// const mds = await glob(normalizePath(`${options.path}/**/*.md`))
13-
const mds = await glob(normalizePath(`${options.path}/**/*.md`));
14-
return mds
11+
async function readMarkdown(options: Options): Promise<Map<String, VueTag>> {
12+
const mdPaths = await glob(normalizePath(`${options.path}/**/*.md`));
13+
const data = mdPaths
1514
.filter(md => options.test.test(md))
1615
.map(path => {
1716
const docPath = dirname(path);
18-
const componentName = docPath.substring(docPath.lastIndexOf('/') + 1);
19-
return {
20-
componentName: getComponentName(componentName || ''),
21-
md: readFileSync(path, 'utf-8'),
22-
};
23-
});
17+
const kebabComponentName =
18+
options.tagPrefix + docPath.substring(docPath.lastIndexOf('/') + 1) || '';
19+
const componentName = getComponentName(docPath.substring(docPath.lastIndexOf('/') + 1) || '');
20+
const fileContent = readFileSync(path, 'utf-8');
21+
return formatter(mdParser(fileContent), componentName, kebabComponentName, options.tagPrefix);
22+
})
23+
.filter(item => item) as VueTag[][];
24+
const tags: Map<String, VueTag> = new Map();
25+
data.flatMap(item => item).forEach(mergedTag => mergeTag(tags, mergedTag));
26+
return tags;
2427
}
2528

26-
export async function parseAndWrite(options: Options) {
27-
if (!options.outputDir) {
28-
throw new Error('outputDir can not be empty.');
29+
function readTypings(options: Options): Map<String, VueTag> {
30+
const tags: Map<String, VueTag> = new Map();
31+
const fileContent = readFileSync(options.typingsPath, 'utf-8');
32+
fileContent
33+
.split('\n')
34+
.filter(line => line && line.includes('typeof'))
35+
.map(line => {
36+
const l = line.trim();
37+
return toKebabCase(l.substring(0, l.indexOf(':')));
38+
})
39+
.forEach(tagName =>
40+
tags.set(tagName, {
41+
name: tagName,
42+
slots: [],
43+
events: [],
44+
attributes: [],
45+
}),
46+
);
47+
return tags;
48+
}
49+
50+
function mergeTag(tags: Map<String, VueTag>, mergedTag: VueTag) {
51+
const tagName = mergedTag.name;
52+
const vueTag = tags.get(tagName);
53+
if (vueTag) {
54+
vueTag.slots = [...vueTag.slots, ...mergedTag.slots];
55+
vueTag.events = [...vueTag.events, ...mergedTag.events];
56+
vueTag.attributes = [...vueTag.attributes, ...mergedTag.attributes];
57+
} else {
58+
tags.set(tagName, mergedTag);
2959
}
60+
}
3061

31-
const docs = await readMarkdown(options);
32-
const datas = docs
33-
.map(doc => formatter(mdParser(doc.md), doc.componentName, options.tagPrefix))
34-
.filter(item => item) as VueTag[][];
35-
const tags: VueTag[] = [];
36-
datas.forEach(arr => {
37-
tags.push(...arr);
62+
function mergeTags(mergedTagsArr: Map<String, VueTag>[]): VueTag[] {
63+
if (mergedTagsArr.length === 1) return [...mergedTagsArr[0].values()];
64+
const tags: Map<String, VueTag> = new Map();
65+
if (mergedTagsArr.length === 0) return [];
66+
mergedTagsArr.forEach(mergedTags => {
67+
mergedTags.forEach(mergedTag => mergeTag(tags, mergedTag));
3868
});
69+
return [...tags.values()];
70+
}
3971

72+
export async function parseAndWrite(options: Options): Promise<Number> {
73+
if (!options.outputDir) {
74+
throw new Error('outputDir can not be empty.');
75+
}
76+
const tagsFromMarkdown = await readMarkdown(options);
77+
const tagsFromTypings = await readTypings(options);
78+
const tags = mergeTags([tagsFromMarkdown, tagsFromTypings]);
4079
const webTypes = genWebTypes(tags, options);
4180
const veturTags = genVeturTags(tags);
4281
const veturAttributes = genVeturAttributes(tags);
43-
4482
outputFileSync(join(options.outputDir, 'tags.json'), JSON.stringify(veturTags, null, 2));
4583
outputFileSync(
4684
join(options.outputDir, 'attributes.json'),
4785
JSON.stringify(veturAttributes, null, 2),
4886
);
4987
outputFileSync(join(options.outputDir, 'web-types.json'), JSON.stringify(webTypes, null, 2));
88+
return tags.length;
5089
}
5190

5291
export default { parseAndWrite };

antd-tools/generator-types/src/parser.ts

+1-7
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function readLine(input: string) {
2727
function splitTableLine(line: string) {
2828
line = line.replace(/\\\|/g, 'JOIN');
2929

30-
const items = line.split('|').map(item => item.trim().replace('JOIN', '|'));
30+
const items = line.split('|').map(item => item.trim().replaceAll('JOIN', '|'));
3131

3232
// remove pipe character on both sides
3333
items.pop();
@@ -77,11 +77,6 @@ export function mdParser(input: string): Articals {
7777
const artical = [];
7878
let start = 0;
7979
const end = input.length;
80-
// artical.push({
81-
// type: 'title',
82-
// content: title,
83-
// level: 0,
84-
// });
8580

8681
while (start < end) {
8782
const target = input.substr(start);
@@ -108,6 +103,5 @@ export function mdParser(input: string): Articals {
108103
}
109104
}
110105

111-
// artical[0].content = title
112106
return artical;
113107
}

antd-tools/generator-types/src/type.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ export type VueAttribute = {
2828

2929
export type VueTag = {
3030
name: string;
31-
slots?: VueSlot[];
32-
events?: VueEvent[];
33-
attributes?: VueAttribute[];
31+
slots: VueSlot[];
32+
events: VueEvent[];
33+
attributes: VueAttribute[];
3434
description?: string;
3535
};
3636

@@ -56,6 +56,7 @@ export type VeturResult = {
5656
export type Options = {
5757
name: string;
5858
path: PathLike;
59+
typingsPath: PathLike;
5960
test: RegExp;
6061
version: string;
6162
outputDir?: string;

antd-tools/generator-types/src/utils.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// myName -> my-name
2-
export function toKebabCase(input: string): string {
3-
return input.replace(/[A-Z]/g, (val, index) => (index === 0 ? '' : '-') + val.toLowerCase());
2+
export function toKebabCase(camel: string): string {
3+
return camel.replace(/((?<=[a-z\d])[A-Z]|(?<=[A-Z\d])[A-Z](?=[a-z]))/g, '-$1').toLowerCase();
44
}
55

66
// name `v2.0.0` -> name

0 commit comments

Comments
 (0)