Fixed some errors in generator-types (#6095)

Co-authored-by: starasov <starasov@sportmaster.ru>
pull/6152/merge
tarasovsn 2022-12-15 05:54:20 +03:00 committed by GitHub
parent 8a0c8a8fb1
commit 75c65e094f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 103 additions and 56 deletions

View File

@ -3,18 +3,21 @@ const pkg = require('../../package.json');
const { parseAndWrite } = require('./lib/index.js'); const { parseAndWrite } = require('./lib/index.js');
const rootPath = path.resolve(__dirname, '../../'); const rootPath = path.resolve(__dirname, '../../');
try { parseAndWrite({
parseAndWrite({ version: pkg.version,
version: pkg.version, name: 'ant-design-vue',
name: 'ant-design-vue', path: path.resolve(rootPath, './components'),
path: path.resolve(rootPath, './components'), typingsPath: path.resolve(rootPath, './typings/global.d.ts'),
// default match lang // default match lang
test: /en-US\.md/, test: /en-US\.md/,
outputDir: path.resolve(rootPath, './vetur'), outputDir: path.resolve(rootPath, './vetur'),
tagPrefix: 'a-', 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);
}

View File

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

View File

@ -1,52 +1,91 @@
import glob from 'fast-glob'; import glob from 'fast-glob';
import { join, dirname } from 'path'; import { dirname, join } from 'path';
import { mdParser } from './parser'; import { mdParser } from './parser';
import { formatter } from './formatter'; import { formatter } from './formatter';
import { genWebTypes } from './web-types'; import { genWebTypes } from './web-types';
import { readFileSync, outputFileSync } from 'fs-extra'; import { outputFileSync, readFileSync } from 'fs-extra';
import type { Options, VueTag } from './type'; import type { Options, VueTag } from './type';
import { normalizePath, getComponentName } from './utils'; import { getComponentName, normalizePath, toKebabCase } from './utils';
import { genVeturTags, genVeturAttributes } from './vetur'; import { genVeturAttributes, genVeturTags } from './vetur';
async function readMarkdown(options: Options) { async function readMarkdown(options: Options): Promise<Map<String, VueTag>> {
// const mds = await glob(normalizePath(`${options.path}/**/*.md`)) const mdPaths = await glob(normalizePath(`${options.path}/**/*.md`));
const mds = await glob(normalizePath(`${options.path}/**/*.md`)); const data = mdPaths
return mds
.filter(md => options.test.test(md)) .filter(md => options.test.test(md))
.map(path => { .map(path => {
const docPath = dirname(path); const docPath = dirname(path);
const componentName = docPath.substring(docPath.lastIndexOf('/') + 1); const kebabComponentName =
return { options.tagPrefix + docPath.substring(docPath.lastIndexOf('/') + 1) || '';
componentName: getComponentName(componentName || ''), const componentName = getComponentName(docPath.substring(docPath.lastIndexOf('/') + 1) || '');
md: readFileSync(path, 'utf-8'), 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) { 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);
}
}
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) { if (!options.outputDir) {
throw new Error('outputDir can not be empty.'); throw new Error('outputDir can not be empty.');
} }
const tagsFromMarkdown = await readMarkdown(options);
const docs = await readMarkdown(options); const tagsFromTypings = await readTypings(options);
const datas = docs const tags = mergeTags([tagsFromMarkdown, tagsFromTypings]);
.map(doc => formatter(mdParser(doc.md), doc.componentName, options.tagPrefix))
.filter(item => item) as VueTag[][];
const tags: VueTag[] = [];
datas.forEach(arr => {
tags.push(...arr);
});
const webTypes = genWebTypes(tags, options); const webTypes = genWebTypes(tags, options);
const veturTags = genVeturTags(tags); const veturTags = genVeturTags(tags);
const veturAttributes = genVeturAttributes(tags); const veturAttributes = genVeturAttributes(tags);
outputFileSync(join(options.outputDir, 'tags.json'), JSON.stringify(veturTags, null, 2)); outputFileSync(join(options.outputDir, 'tags.json'), JSON.stringify(veturTags, null, 2));
outputFileSync( outputFileSync(
join(options.outputDir, 'attributes.json'), join(options.outputDir, 'attributes.json'),
JSON.stringify(veturAttributes, null, 2), JSON.stringify(veturAttributes, null, 2),
); );
outputFileSync(join(options.outputDir, 'web-types.json'), JSON.stringify(webTypes, null, 2)); outputFileSync(join(options.outputDir, 'web-types.json'), JSON.stringify(webTypes, null, 2));
return tags.length;
} }
export default { parseAndWrite }; export default { parseAndWrite };

View File

@ -27,7 +27,7 @@ function readLine(input: string) {
function splitTableLine(line: string) { function splitTableLine(line: string) {
line = line.replace(/\\\|/g, 'JOIN'); 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 // remove pipe character on both sides
items.pop(); items.pop();
@ -77,11 +77,6 @@ export function mdParser(input: string): Articals {
const artical = []; const artical = [];
let start = 0; let start = 0;
const end = input.length; const end = input.length;
// artical.push({
// type: 'title',
// content: title,
// level: 0,
// });
while (start < end) { while (start < end) {
const target = input.substr(start); const target = input.substr(start);
@ -108,6 +103,5 @@ export function mdParser(input: string): Articals {
} }
} }
// artical[0].content = title
return artical; return artical;
} }

View File

@ -28,9 +28,9 @@ export type VueAttribute = {
export type VueTag = { export type VueTag = {
name: string; name: string;
slots?: VueSlot[]; slots: VueSlot[];
events?: VueEvent[]; events: VueEvent[];
attributes?: VueAttribute[]; attributes: VueAttribute[];
description?: string; description?: string;
}; };
@ -56,6 +56,7 @@ export type VeturResult = {
export type Options = { export type Options = {
name: string; name: string;
path: PathLike; path: PathLike;
typingsPath: PathLike;
test: RegExp; test: RegExp;
version: string; version: string;
outputDir?: string; outputDir?: string;

View File

@ -1,6 +1,6 @@
// myName -> my-name // myName -> my-name
export function toKebabCase(input: string): string { export function toKebabCase(camel: string): string {
return input.replace(/[A-Z]/g, (val, index) => (index === 0 ? '' : '-') + val.toLowerCase()); return camel.replace(/((?<=[a-z\d])[A-Z]|(?<=[A-Z\d])[A-Z](?=[a-z]))/g, '-$1').toLowerCase();
} }
// name `v2.0.0` -> name // name `v2.0.0` -> name