From 75c65e094fc74b0fa4ee6937730d756ab1d6a926 Mon Sep 17 00:00:00 2001 From: tarasovsn Date: Thu, 15 Dec 2022 05:54:20 +0300 Subject: [PATCH] Fixed some errors in generator-types (#6095) Co-authored-by: starasov --- antd-tools/generator-types/index.js | 31 +++---- antd-tools/generator-types/src/formatter.ts | 18 +++- antd-tools/generator-types/src/index.ts | 91 +++++++++++++++------ antd-tools/generator-types/src/parser.ts | 8 +- antd-tools/generator-types/src/type.ts | 7 +- antd-tools/generator-types/src/utils.ts | 4 +- 6 files changed, 103 insertions(+), 56 deletions(-) diff --git a/antd-tools/generator-types/index.js b/antd-tools/generator-types/index.js index 650a7b8ee..8a456e0a1 100644 --- a/antd-tools/generator-types/index.js +++ b/antd-tools/generator-types/index.js @@ -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); -} diff --git a/antd-tools/generator-types/src/formatter.ts b/antd-tools/generator-types/src/formatter.ts index 5a17d0082..722077ecf 100644 --- a/antd-tools/generator-types/src/formatter.ts +++ b/antd-tools/generator-types/src/formatter.ts @@ -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: [], @@ -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: [], @@ -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( diff --git a/antd-tools/generator-types/src/index.ts b/antd-tools/generator-types/src/index.ts index 3536a8808..c500b38e1 100644 --- a/antd-tools/generator-types/src/index.ts +++ b/antd-tools/generator-types/src/index.ts @@ -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> { + 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 = new Map(); + data.flatMap(item => item).forEach(mergedTag => mergeTag(tags, mergedTag)); + return tags; } -export async function parseAndWrite(options: Options) { +function readTypings(options: Options): Map { + const tags: Map = 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, 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[]): VueTag[] { + if (mergedTagsArr.length === 1) return [...mergedTagsArr[0].values()]; + const tags: Map = 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 { if (!options.outputDir) { throw new Error('outputDir can not be empty.'); } - - 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); - }); - + 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 }; diff --git a/antd-tools/generator-types/src/parser.ts b/antd-tools/generator-types/src/parser.ts index 964b09516..5a20559e5 100644 --- a/antd-tools/generator-types/src/parser.ts +++ b/antd-tools/generator-types/src/parser.ts @@ -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(); @@ -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); @@ -108,6 +103,5 @@ export function mdParser(input: string): Articals { } } - // artical[0].content = title return artical; } diff --git a/antd-tools/generator-types/src/type.ts b/antd-tools/generator-types/src/type.ts index 503c9cf56..faf2ed939 100644 --- a/antd-tools/generator-types/src/type.ts +++ b/antd-tools/generator-types/src/type.ts @@ -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; }; @@ -56,6 +56,7 @@ export type VeturResult = { export type Options = { name: string; path: PathLike; + typingsPath: PathLike; test: RegExp; version: string; outputDir?: string; diff --git a/antd-tools/generator-types/src/utils.ts b/antd-tools/generator-types/src/utils.ts index 4b0aa3f80..50ef2ab34 100644 --- a/antd-tools/generator-types/src/utils.ts +++ b/antd-tools/generator-types/src/utils.ts @@ -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