Skip to content

fix(generator-types): Fixed some bugs (web-type.json) #6095

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions antd-tools/generator-types/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@ const pkg = require('../../package.json');
const { parseAndWrite } = require('./lib/index.js');
const rootPath = path.resolve(__dirname, '../../');

try {
parseAndWrite({
version: pkg.version,
name: 'ant-design-vue',
path: path.resolve(rootPath, './components'),
// default match lang
test: /en-US\.md/,
outputDir: path.resolve(rootPath, './vetur'),
tagPrefix: 'a-',
parseAndWrite({
version: pkg.version,
name: 'ant-design-vue',
path: path.resolve(rootPath, './components'),
typingsPath: path.resolve(rootPath, './typings/global.d.ts'),
// default match lang
test: /en-US\.md/,
outputDir: path.resolve(rootPath, './vetur'),
tagPrefix: 'a-',
})
.then(result => {
// eslint-disable-next-line no-console
console.log(`generator types success: ${result} tags generated`);
})
.catch(error => {
console.error('generator types error', error);
return Promise.reject(error);
});
// eslint-disable-next-line no-console
console.log('generator types success');
} catch (e) {
console.error('generator types error', e);
}
18 changes: 14 additions & 4 deletions antd-tools/generator-types/src/formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,19 @@ function parserProps(tag: VueTag, line: any) {
});
}

export function formatter(articals: Articals, componentName: string, tagPrefix = '') {
export function formatter(
articals: Articals,
componentName: string,
kebabComponentName: string,
tagPrefix = '',
) {
if (!articals.length) {
return;
}

const tags: VueTag[] = [];
const tag: VueTag = {
name: getComponentName(componentName, tagPrefix),
name: kebabComponentName,
slots: [],
events: [],
attributes: [],
Expand Down Expand Up @@ -80,9 +85,13 @@ export function formatter(articals: Articals, componentName: string, tagPrefix =
}

// 额外的子组件
if (tableTitle.includes(componentName) && !tableTitle.includes('events')) {
if (
tableTitle.includes(componentName) &&
!tableTitle.includes('events') &&
!tableTitle.includes('()')
) {
const childTag: VueTag = {
name: getComponentName(tableTitle.replace('.', ''), tagPrefix),
name: getComponentName(tableTitle.replaceAll('.', '').replaceAll('/', ''), tagPrefix),
slots: [],
events: [],
attributes: [],
Expand All @@ -93,6 +102,7 @@ export function formatter(articals: Articals, componentName: string, tagPrefix =
tags.push(childTag);
return;
}

// 额外的子组件事件
if (tableTitle.includes(componentName) && tableTitle.includes('events')) {
const childTagName = getComponentName(
Expand Down
89 changes: 64 additions & 25 deletions antd-tools/generator-types/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,91 @@
import glob from 'fast-glob';
import { join, dirname } from 'path';
import { dirname, join } from 'path';
import { mdParser } from './parser';
import { formatter } from './formatter';
import { genWebTypes } from './web-types';
import { readFileSync, outputFileSync } from 'fs-extra';
import { outputFileSync, readFileSync } from 'fs-extra';
import type { Options, VueTag } from './type';
import { normalizePath, getComponentName } from './utils';
import { genVeturTags, genVeturAttributes } from './vetur';
import { getComponentName, normalizePath, toKebabCase } from './utils';
import { genVeturAttributes, genVeturTags } from './vetur';

async function readMarkdown(options: Options) {
// const mds = await glob(normalizePath(`${options.path}/**/*.md`))
const mds = await glob(normalizePath(`${options.path}/**/*.md`));
return mds
async function readMarkdown(options: Options): Promise<Map<String, VueTag>> {
const mdPaths = await glob(normalizePath(`${options.path}/**/*.md`));
const data = mdPaths
.filter(md => options.test.test(md))
.map(path => {
const docPath = dirname(path);
const componentName = docPath.substring(docPath.lastIndexOf('/') + 1);
return {
componentName: getComponentName(componentName || ''),
md: readFileSync(path, 'utf-8'),
};
});
const kebabComponentName =
options.tagPrefix + docPath.substring(docPath.lastIndexOf('/') + 1) || '';
const componentName = getComponentName(docPath.substring(docPath.lastIndexOf('/') + 1) || '');
const fileContent = readFileSync(path, 'utf-8');
return formatter(mdParser(fileContent), componentName, kebabComponentName, options.tagPrefix);
})
.filter(item => item) as VueTag[][];
const tags: Map<String, VueTag> = new Map();
data.flatMap(item => item).forEach(mergedTag => mergeTag(tags, mergedTag));
return tags;
}

export async function parseAndWrite(options: Options) {
if (!options.outputDir) {
throw new Error('outputDir can not be empty.');
function readTypings(options: Options): Map<String, VueTag> {
const tags: Map<String, VueTag> = new Map();
const fileContent = readFileSync(options.typingsPath, 'utf-8');
fileContent
.split('\n')
.filter(line => line && line.includes('typeof'))
.map(line => {
const l = line.trim();
return toKebabCase(l.substring(0, l.indexOf(':')));
})
.forEach(tagName =>
tags.set(tagName, {
name: tagName,
slots: [],
events: [],
attributes: [],
}),
);
return tags;
}

function mergeTag(tags: Map<String, VueTag>, mergedTag: VueTag) {
const tagName = mergedTag.name;
const vueTag = tags.get(tagName);
if (vueTag) {
vueTag.slots = [...vueTag.slots, ...mergedTag.slots];
vueTag.events = [...vueTag.events, ...mergedTag.events];
vueTag.attributes = [...vueTag.attributes, ...mergedTag.attributes];
} else {
tags.set(tagName, mergedTag);
}
}

const docs = await readMarkdown(options);
const datas = docs
.map(doc => formatter(mdParser(doc.md), doc.componentName, options.tagPrefix))
.filter(item => item) as VueTag[][];
const tags: VueTag[] = [];
datas.forEach(arr => {
tags.push(...arr);
function mergeTags(mergedTagsArr: Map<String, VueTag>[]): VueTag[] {
if (mergedTagsArr.length === 1) return [...mergedTagsArr[0].values()];
const tags: Map<String, VueTag> = new Map();
if (mergedTagsArr.length === 0) return [];
mergedTagsArr.forEach(mergedTags => {
mergedTags.forEach(mergedTag => mergeTag(tags, mergedTag));
});
return [...tags.values()];
}

export async function parseAndWrite(options: Options): Promise<Number> {
if (!options.outputDir) {
throw new Error('outputDir can not be empty.');
}
const tagsFromMarkdown = await readMarkdown(options);
const tagsFromTypings = await readTypings(options);
const tags = mergeTags([tagsFromMarkdown, tagsFromTypings]);
const webTypes = genWebTypes(tags, options);
const veturTags = genVeturTags(tags);
const veturAttributes = genVeturAttributes(tags);

outputFileSync(join(options.outputDir, 'tags.json'), JSON.stringify(veturTags, null, 2));
outputFileSync(
join(options.outputDir, 'attributes.json'),
JSON.stringify(veturAttributes, null, 2),
);
outputFileSync(join(options.outputDir, 'web-types.json'), JSON.stringify(webTypes, null, 2));
return tags.length;
}

export default { parseAndWrite };
8 changes: 1 addition & 7 deletions antd-tools/generator-types/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function readLine(input: string) {
function splitTableLine(line: string) {
line = line.replace(/\\\|/g, 'JOIN');

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

// remove pipe character on both sides
items.pop();
Expand Down Expand Up @@ -77,11 +77,6 @@ export function mdParser(input: string): Articals {
const artical = [];
let start = 0;
const end = input.length;
// artical.push({
// type: 'title',
// content: title,
// level: 0,
// });

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

// artical[0].content = title
return artical;
}
7 changes: 4 additions & 3 deletions antd-tools/generator-types/src/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ export type VueAttribute = {

export type VueTag = {
name: string;
slots?: VueSlot[];
events?: VueEvent[];
attributes?: VueAttribute[];
slots: VueSlot[];
events: VueEvent[];
attributes: VueAttribute[];
description?: string;
};

Expand All @@ -56,6 +56,7 @@ export type VeturResult = {
export type Options = {
name: string;
path: PathLike;
typingsPath: PathLike;
test: RegExp;
version: string;
outputDir?: string;
Expand Down
4 changes: 2 additions & 2 deletions antd-tools/generator-types/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// myName -> my-name
export function toKebabCase(input: string): string {
return input.replace(/[A-Z]/g, (val, index) => (index === 0 ? '' : '-') + val.toLowerCase());
export function toKebabCase(camel: string): string {
return camel.replace(/((?<=[a-z\d])[A-Z]|(?<=[A-Z\d])[A-Z](?=[a-z]))/g, '-$1').toLowerCase();
}

// name `v2.0.0` -> name
Expand Down