@vant/markdown-vetur
Advanced tools
| import { Articals } from './parser'; | ||
| import { VueTag } from './type'; | ||
| export declare function formatter(articals: Articals, tagPrefix?: string): VueTag | undefined; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const utils_1 = require("./utils"); | ||
| function getComponentName(artical, tagPrefix) { | ||
| if (artical.content) { | ||
| return tagPrefix + utils_1.toKebabCase(artical.content.split(' ')[0]); | ||
| } | ||
| return ''; | ||
| } | ||
| function formatter(articals, tagPrefix = '') { | ||
| if (!articals.length) { | ||
| return; | ||
| } | ||
| const tag = { | ||
| name: getComponentName(articals[0], tagPrefix), | ||
| slots: [], | ||
| events: [], | ||
| attributes: [], | ||
| }; | ||
| const tables = articals.filter(artical => artical.type === 'table'); | ||
| tables.forEach(item => { | ||
| const { table } = item; | ||
| const prevIndex = articals.indexOf(item) - 1; | ||
| const prevArtical = articals[prevIndex]; | ||
| if (!prevArtical || !prevArtical.content || !table || !table.body) { | ||
| return; | ||
| } | ||
| const tableTitle = prevArtical.content; | ||
| if (tableTitle.includes('Props')) { | ||
| table.body.forEach(line => { | ||
| const [name, desc, type, defaultVal] = line; | ||
| tag.attributes.push({ | ||
| name: utils_1.removeVersion(name), | ||
| default: defaultVal, | ||
| description: desc, | ||
| value: { | ||
| type: utils_1.formatType(type), | ||
| kind: 'expression', | ||
| }, | ||
| }); | ||
| }); | ||
| return; | ||
| } | ||
| if (tableTitle.includes('Events')) { | ||
| table.body.forEach(line => { | ||
| const [name, desc] = line; | ||
| tag.events.push({ | ||
| name: utils_1.removeVersion(name), | ||
| description: desc, | ||
| }); | ||
| }); | ||
| return; | ||
| } | ||
| if (tableTitle.includes('Slots')) { | ||
| table.body.forEach(line => { | ||
| const [name, desc] = line; | ||
| tag.slots.push({ | ||
| name: utils_1.removeVersion(name), | ||
| description: desc, | ||
| }); | ||
| }); | ||
| } | ||
| }); | ||
| return tag; | ||
| } | ||
| exports.formatter = formatter; |
| import { Options } from './type'; | ||
| export declare function parseAndWrite(options: Options): Promise<void>; | ||
| declare const _default: { | ||
| parseAndWrite: typeof parseAndWrite; | ||
| }; | ||
| export default _default; |
| declare type TableContent = { | ||
| head: string[]; | ||
| body: string[][]; | ||
| }; | ||
| export declare type Artical = { | ||
| type: string; | ||
| content?: string; | ||
| table?: TableContent; | ||
| level?: number; | ||
| }; | ||
| export declare type Articals = Artical[]; | ||
| export declare function mdParser(input: string): Articals; | ||
| export {}; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| /* eslint-disable no-cond-assign */ | ||
| const TITLE_REG = /^(#+)\s+([^\n]*)/; | ||
| const TABLE_REG = /^\|.+\n\|\s*-+/; | ||
| const TD_REG = /\s*`[^`]+`\s*|([^|`]+)/g; | ||
| const TABLE_SPLIT_LINE_REG = /^\|\s*-/; | ||
| function readLine(input) { | ||
| const end = input.indexOf('\n'); | ||
| return input.substr(0, end !== -1 ? end : input.length); | ||
| } | ||
| function splitTableLine(line) { | ||
| line = line.replace('\\|', 'JOIN'); | ||
| const items = line.split('|').map(item => item.trim().replace('JOIN', '|')); | ||
| // remove pipe character on both sides | ||
| items.pop(); | ||
| items.shift(); | ||
| return items; | ||
| } | ||
| function tableParse(input) { | ||
| let start = 0; | ||
| let isHead = true; | ||
| const end = input.length; | ||
| const table = { | ||
| head: [], | ||
| body: [], | ||
| }; | ||
| while (start < end) { | ||
| const target = input.substr(start); | ||
| const line = readLine(target); | ||
| if (!/^\|/.test(target)) { | ||
| break; | ||
| } | ||
| if (TABLE_SPLIT_LINE_REG.test(target)) { | ||
| isHead = false; | ||
| } | ||
| else if (!isHead && line.includes('|')) { | ||
| const matched = line.trim().match(TD_REG); | ||
| if (matched) { | ||
| table.body.push(splitTableLine(line)); | ||
| } | ||
| } | ||
| start += line.length + 1; | ||
| } | ||
| return { | ||
| table, | ||
| usedLength: start, | ||
| }; | ||
| } | ||
| function mdParser(input) { | ||
| const artical = []; | ||
| let start = 0; | ||
| const end = input.length; | ||
| while (start < end) { | ||
| const target = input.substr(start); | ||
| let match; | ||
| if ((match = TITLE_REG.exec(target))) { | ||
| artical.push({ | ||
| type: 'title', | ||
| content: match[2], | ||
| level: match[1].length, | ||
| }); | ||
| start += match.index + match[0].length; | ||
| } | ||
| else if ((match = TABLE_REG.exec(target))) { | ||
| const { table, usedLength } = tableParse(target.substr(match.index)); | ||
| artical.push({ | ||
| type: 'table', | ||
| table, | ||
| }); | ||
| start += match.index + usedLength; | ||
| } | ||
| else { | ||
| start += readLine(target).length + 1; | ||
| } | ||
| } | ||
| return artical; | ||
| } | ||
| exports.mdParser = mdParser; |
| /// <reference types="node" /> | ||
| import { PathLike } from 'fs'; | ||
| export declare type VueSlot = { | ||
| name: string; | ||
| description: string; | ||
| }; | ||
| export declare type VueEventArgument = { | ||
| name: string; | ||
| type: string; | ||
| }; | ||
| export declare type VueEvent = { | ||
| name: string; | ||
| description?: string; | ||
| arguments?: VueEventArgument[]; | ||
| }; | ||
| export declare type VueAttribute = { | ||
| name: string; | ||
| default: string; | ||
| description: string; | ||
| value: { | ||
| kind: 'expression'; | ||
| type: string; | ||
| }; | ||
| }; | ||
| export declare type VueTag = { | ||
| name: string; | ||
| slots?: VueSlot[]; | ||
| events?: VueEvent[]; | ||
| attributes?: VueAttribute[]; | ||
| description?: string; | ||
| }; | ||
| export declare type VeturTag = { | ||
| description?: string; | ||
| attributes: string[]; | ||
| }; | ||
| export declare type VeturTags = Record<string, VeturTag>; | ||
| export declare type VeturAttribute = { | ||
| type: string; | ||
| description: string; | ||
| }; | ||
| export declare type VeturAttributes = Record<string, VeturAttribute>; | ||
| export declare type VeturResult = { | ||
| tags: VeturTags; | ||
| attributes: VeturAttributes; | ||
| }; | ||
| export declare type Options = { | ||
| name: string; | ||
| path: PathLike; | ||
| test: RegExp; | ||
| version: string; | ||
| outputDir?: string; | ||
| tagPrefix?: string; | ||
| }; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); |
| export declare function toKebabCase(input: string): string; | ||
| export declare function removeVersion(str: string): string; | ||
| export declare function formatType(type: string): string; | ||
| export declare function normalizePath(path: string): string; |
+21
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| // myName -> my-name | ||
| function toKebabCase(input) { | ||
| return input.replace(/[A-Z]/g, (val, index) => (index === 0 ? '' : '-') + val.toLowerCase()); | ||
| } | ||
| exports.toKebabCase = toKebabCase; | ||
| // name `v2.0.0` -> name | ||
| function removeVersion(str) { | ||
| return str.replace(/`(\w|\.)+`/g, '').trim(); | ||
| } | ||
| exports.removeVersion = removeVersion; | ||
| // *boolean* -> boolean | ||
| function formatType(type) { | ||
| return type.replace(/\*/g, ''); | ||
| } | ||
| exports.formatType = formatType; | ||
| function normalizePath(path) { | ||
| return path.replace(/\\/g, '/'); | ||
| } | ||
| exports.normalizePath = normalizePath; |
| import { VueTag } from './type'; | ||
| export declare function genVeturTags(tags: VueTag[]): Record<string, import("./type").VeturTag>; | ||
| export declare function genVeturAttributes(tags: VueTag[]): Record<string, import("./type").VeturAttribute>; |
+27
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| function genVeturTags(tags) { | ||
| const veturTags = {}; | ||
| tags.forEach(tag => { | ||
| veturTags[tag.name] = { | ||
| attributes: tag.attributes ? tag.attributes.map(item => item.name) : [], | ||
| }; | ||
| }); | ||
| return veturTags; | ||
| } | ||
| exports.genVeturTags = genVeturTags; | ||
| function genVeturAttributes(tags) { | ||
| const veturAttributes = {}; | ||
| tags.forEach(tag => { | ||
| if (tag.attributes) { | ||
| tag.attributes.forEach(attr => { | ||
| veturAttributes[`${tag.name}/${attr.name}`] = { | ||
| type: attr.value.type, | ||
| description: `${attr.description}, 默认值: ${attr.default}`, | ||
| }; | ||
| }); | ||
| } | ||
| }); | ||
| return veturAttributes; | ||
| } | ||
| exports.genVeturAttributes = genVeturAttributes; |
| import { VueTag, Options } from './type'; | ||
| export declare function genWebTypes(tags: VueTag[], options: Options): { | ||
| $schema: string; | ||
| framework: string; | ||
| name: string; | ||
| version: string; | ||
| contributions: { | ||
| html: { | ||
| tags: VueTag[]; | ||
| attributes: never[]; | ||
| 'types-syntax': string; | ||
| }; | ||
| }; | ||
| }; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| // create web-types.json to provide autocomplete in JetBrains IDEs | ||
| function genWebTypes(tags, options) { | ||
| return { | ||
| $schema: 'https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json', | ||
| framework: 'vue', | ||
| name: options.name, | ||
| version: options.version, | ||
| contributions: { | ||
| html: { | ||
| tags, | ||
| attributes: [], | ||
| 'types-syntax': 'typescript', | ||
| }, | ||
| }, | ||
| }; | ||
| } | ||
| exports.genWebTypes = genWebTypes; |
+28
-80
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const fast_glob_1 = __importDefault(require("fast-glob")); | ||
| const path_1 = require("path"); | ||
| const md_parser_1 = require("./md-parser"); | ||
| const codegen_1 = require("./codegen"); | ||
| const fs_1 = require("fs"); | ||
| function parseText(input) { | ||
| const ast = md_parser_1.mdParser(input); | ||
| return codegen_1.codegen(ast); | ||
| const parser_1 = require("./parser"); | ||
| const formatter_1 = require("./formatter"); | ||
| const web_types_1 = require("./web-types"); | ||
| const fs_extra_1 = require("fs-extra"); | ||
| const utils_1 = require("./utils"); | ||
| const vetur_1 = require("./vetur"); | ||
| async function readMarkdown(options) { | ||
| const mds = await fast_glob_1.default(utils_1.normalizePath(`${options.path}/**/*.md`)); | ||
| return mds | ||
| .filter(md => options.test.test(md)) | ||
| .map(path => fs_extra_1.readFileSync(path, 'utf-8')); | ||
| } | ||
| exports.parseText = parseText; | ||
| const defaultOptions = { | ||
| maxDeep: Infinity, | ||
| tagPrefix: '' | ||
| }; | ||
| function parse(options) { | ||
| options = { | ||
| ...defaultOptions, | ||
| ...options | ||
| }; | ||
| const result = { | ||
| tags: {}, | ||
| attributes: {} | ||
| }; | ||
| function putResult(componentName, component) { | ||
| componentName = options.tagPrefix + componentName; | ||
| const attributes = Object.keys(component.attributes); | ||
| const tag = { | ||
| description: component.description, | ||
| attributes | ||
| }; | ||
| result.tags[componentName] = tag; | ||
| attributes.forEach(key => { | ||
| result.attributes[`${componentName}/${key}`] = component.attributes[key]; | ||
| }); | ||
| } | ||
| function recursiveParse(options, deep) { | ||
| if (options.maxDeep && deep > options.maxDeep) { | ||
| return; | ||
| } | ||
| deep++; | ||
| const files = fs_1.readdirSync(options.path); | ||
| files.forEach(item => { | ||
| const currentPath = path_1.join(options.path.toString(), item); | ||
| const stats = fs_1.statSync(currentPath); | ||
| if (stats.isDirectory()) { | ||
| recursiveParse({ | ||
| ...options, | ||
| path: currentPath | ||
| }, deep); | ||
| } | ||
| else if (stats.isFile() && options.test.test(item)) { | ||
| const file = fs_1.readFileSync(currentPath); | ||
| const tags = parseText(file.toString()); | ||
| if (tags.default) { | ||
| // one tag | ||
| putResult(currentPath.split('/').slice(-2)[0], tags.default); | ||
| } | ||
| else { | ||
| Object.keys(tags).forEach(key => { | ||
| putResult(key, tags[key]); | ||
| }); | ||
| } | ||
| } | ||
| }); | ||
| } | ||
| recursiveParse(options, 0); | ||
| return result; | ||
| } | ||
| exports.parse = parse; | ||
| function parseAndWrite(options) { | ||
| const { tags, attributes } = parse(options); | ||
| async function parseAndWrite(options) { | ||
| if (!options.outputDir) { | ||
| return; | ||
| throw new Error('outputDir can not be empty.'); | ||
| } | ||
| const isExist = fs_1.existsSync(options.outputDir); | ||
| if (!isExist) { | ||
| fs_1.mkdirSync(options.outputDir); | ||
| } | ||
| fs_1.writeFileSync(path_1.join(options.outputDir, 'tags.json'), JSON.stringify(tags, null, 2)); | ||
| fs_1.writeFileSync(path_1.join(options.outputDir, 'attributes.json'), JSON.stringify(attributes, null, 2)); | ||
| const mds = await readMarkdown(options); | ||
| const datas = mds | ||
| .map(md => formatter_1.formatter(parser_1.mdParser(md), options.tagPrefix)) | ||
| .filter(item => !!item); | ||
| const webTypes = web_types_1.genWebTypes(datas, options); | ||
| const veturTags = vetur_1.genVeturTags(datas); | ||
| const veturAttributes = vetur_1.genVeturAttributes(datas); | ||
| fs_extra_1.outputFileSync(path_1.join(options.outputDir, 'tags.json'), JSON.stringify(veturTags, null, 2)); | ||
| fs_extra_1.outputFileSync(path_1.join(options.outputDir, 'attributes.json'), JSON.stringify(veturAttributes, null, 2)); | ||
| fs_extra_1.outputFileSync(path_1.join(options.outputDir, 'web-types.json'), JSON.stringify(webTypes, null, 2)); | ||
| } | ||
| exports.parseAndWrite = parseAndWrite; | ||
| exports.default = { | ||
| parse, | ||
| parseText, | ||
| parseAndWrite | ||
| }; | ||
| exports.default = { parseAndWrite }; |
+8
-1
| { | ||
| "name": "@vant/markdown-vetur", | ||
| "version": "1.1.0", | ||
| "version": "2.0.0-beta.0", | ||
| "description": "simple parse markdown to vue component description for vetur auto-completion", | ||
@@ -19,3 +19,10 @@ "main": "lib/index.js", | ||
| "release": "npm run build && npm publish" | ||
| }, | ||
| "dependencies": { | ||
| "fast-glob": "^3.2.2", | ||
| "fs-extra": "^9.0.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/fs-extra": "^8.1.0" | ||
| } | ||
| } |
+1
-1
| # Vant Markdown Vetur | ||
| 将 .md 文件转换成能描述 vue 组件的 .json 文件,供 vscode 插件 *vetur* 读取,从而可以在 vue 模版语法中拥有自动补全的功能。 | ||
| 将 .md 文件转换成能描述 vue 组件的 .json 文件,供 WebStorm 和 vscode 的 `vetur` 插件读取,从而可以在 vue 模版语法中拥有自动补全的功能。 | ||
@@ -5,0 +5,0 @@ ## Install |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const FLAG_REG = /(.*?)\s*(Props|Event)/i; | ||
| function camelCaseToKebabCase(input) { | ||
| return input.replace(/[A-Z]/g, (val, index) => (index === 0 ? '' : '-') + val.toLowerCase()); | ||
| } | ||
| function removeVersionTag(str) { | ||
| return str.replace(/`(\w|\.)+`/g, '').trim(); | ||
| } | ||
| function getDescription(td, isProp) { | ||
| const desc = td[1] ? td[1].replace('<br>', '') : ''; | ||
| const type = td[2] ? td[2].replace(/\*/g, '') : ''; | ||
| const defaultVal = td[3] ? td[3].replace(/`/g, '') : ''; | ||
| if (isProp) { | ||
| return `${desc}, 默认值: ${defaultVal}, 类型: ${type}`; | ||
| } | ||
| return desc; | ||
| } | ||
| function codegen(artical) { | ||
| const tags = {}; | ||
| let tagDescription = ''; | ||
| for (let i = 0, len = artical.length; i < len; i++) { | ||
| const item = artical[i]; | ||
| if (item.type === 'title' && item.level === 2) { | ||
| if (item.content) { | ||
| tagDescription = item.content; | ||
| } | ||
| } | ||
| else if (item.type === 'table') { | ||
| const before = artical[i - 1]; | ||
| if (!before || !before.content) { | ||
| continue; | ||
| } | ||
| const { table } = item; | ||
| const match = FLAG_REG.exec(before.content); | ||
| if (!match || !table) { | ||
| continue; | ||
| } | ||
| const key = camelCaseToKebabCase(match[1] || 'default'); | ||
| const tag = tags[key] || { | ||
| description: tagDescription, | ||
| attributes: {} | ||
| }; | ||
| tags[key] = tag; | ||
| const isProp = /Props/i.test(match[2]); | ||
| table.body.forEach(td => { | ||
| const name = removeVersionTag(td[0]); | ||
| const attr = { | ||
| description: getDescription(td, isProp), | ||
| type: isProp ? td[2].replace(/`/g, '').toLowerCase() : 'event' | ||
| }; | ||
| tag.attributes[name] = attr; | ||
| }); | ||
| } | ||
| } | ||
| return tags; | ||
| } | ||
| exports.codegen = codegen; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| /* eslint-disable no-cond-assign */ | ||
| const TITLE_REG = /^(#+)\s+([^\n]*)/; | ||
| const TABLE_REG = /^\|.+\n\|\s*-+/; | ||
| const TD_REG = /\s*`[^`]+`\s*|([^|`]+)/g; | ||
| const TABLE_SPLIT_LINE_REG = /^\|\s*-/; | ||
| function readLine(input) { | ||
| const end = input.indexOf('\n'); | ||
| return input.substr(0, end !== -1 ? end : input.length); | ||
| } | ||
| function splitTableLine(line) { | ||
| line = line.replace('\\|', 'JOIN'); | ||
| const items = line.split('|').map(item => item.trim().replace('JOIN', '|')); | ||
| // remove pipe character on both sides | ||
| items.pop(); | ||
| items.shift(); | ||
| return items; | ||
| } | ||
| function tableParse(input) { | ||
| let start = 0; | ||
| let isHead = true; | ||
| const end = input.length; | ||
| const table = { | ||
| head: [], | ||
| body: [] | ||
| }; | ||
| while (start < end) { | ||
| const target = input.substr(start); | ||
| const line = readLine(target); | ||
| if (!/^\|/.test(target)) { | ||
| break; | ||
| } | ||
| if (TABLE_SPLIT_LINE_REG.test(target)) { | ||
| isHead = false; | ||
| } | ||
| else if (!isHead && line.includes('|')) { | ||
| const matched = line.trim().match(TD_REG); | ||
| if (matched) { | ||
| table.body.push(splitTableLine(line)); | ||
| } | ||
| } | ||
| start += line.length + 1; | ||
| } | ||
| return { | ||
| table, | ||
| usedLength: start | ||
| }; | ||
| } | ||
| function mdParser(input) { | ||
| const artical = []; | ||
| let start = 0; | ||
| const end = input.length; | ||
| while (start < end) { | ||
| const target = input.substr(start); | ||
| let match; | ||
| if ((match = TITLE_REG.exec(target))) { | ||
| artical.push({ | ||
| type: 'title', | ||
| content: match[2], | ||
| level: match[1].length | ||
| }); | ||
| start += match.index + match[0].length; | ||
| } | ||
| else if ((match = TABLE_REG.exec(target))) { | ||
| const { table, usedLength } = tableParse(target.substr(match.index)); | ||
| artical.push({ | ||
| type: 'table', | ||
| table | ||
| }); | ||
| start += match.index + usedLength; | ||
| } | ||
| else { | ||
| start += readLine(target).length + 1; | ||
| } | ||
| } | ||
| return artical; | ||
| } | ||
| exports.mdParser = mdParser; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
12381
49.28%16
220%346
53.78%2
Infinity%1
Infinity%2
100%4
33.33%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added