@ant-design/tools
Version:
tools for ant design
166 lines (160 loc) • 5.61 kB
JavaScript
import { Command } from 'commander';
import { majo } from 'majo';
import fs from 'fs';
import path from 'path';
import chalk from 'chalk';
import unified from 'unified';
import parse from 'remark-parse';
import stringify from 'remark-stringify';
import yamlConfig from 'remark-yaml-config';
import frontmatter from 'remark-frontmatter';
// Minimal interface for AST node
// Define fileAPIs type
let fileAPIs = {};
const remarkWithYaml = unified().use(parse).use(stringify, {
listItemIndent: '1',
stringLength: () => 3
}).use(frontmatter).use(yamlConfig);
const stream = majo();
// Updated get with improved types
function get(obj, pathStr = '', defaultValue) {
return pathStr.split('.').reduce((acc, key) => {
if (acc && typeof acc === 'object' && key in acc) {
return acc[key];
}
return undefined;
}, obj) || defaultValue;
}
function getCellValue(node) {
let cloneNode = {
...node
};
// Traverse until a text node is found
while (cloneNode.type !== 'text' && cloneNode.children && cloneNode.children.length > 0) {
cloneNode = cloneNode.children[0];
}
return cloneNode.value || '';
}
function checkForCellDeletion(node) {
let cloneNode = {
...node
};
while (cloneNode.children && Array.isArray(cloneNode.children)) {
if (cloneNode.type === 'delete') {
return true;
}
cloneNode = cloneNode.children[0];
}
return cloneNode.type === 'delete';
}
// from small to large
const sizeBreakPoints = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
const whiteMethodList = ['afterChange', 'beforeChange'];
const groups = {
isDynamic: val => /^on[A-Z]/.test(val) || whiteMethodList.indexOf(val) > -1,
isSize: val => sizeBreakPoints.indexOf(val) > -1,
isDeprecated: checkForCellDeletion
};
function asciiSort(prev, next) {
if (prev > next) {
return 1;
}
if (prev < next) {
return -1;
}
return 0;
}
// follow the alphabet order
function alphabetSort(nodes) {
return nodes.sort((a, b) => asciiSort(getCellValue(a).toLowerCase(), getCellValue(b).toLowerCase()));
}
function sizeSort(nodes) {
return nodes.sort((a, b) => asciiSort(sizeBreakPoints.indexOf(getCellValue(a).toLowerCase()), sizeBreakPoints.indexOf(getCellValue(b).toLowerCase())));
}
function sort(ast, filename) {
const nameMatch = filename.match(/^components\/([^/]*)\//);
const componentName = nameMatch ? nameMatch[1] : 'unknown';
fileAPIs[componentName] = fileAPIs[componentName] || {
static: new Set(),
size: new Set(),
dynamic: new Set(),
deprecated: new Set()
};
ast.children.forEach(child => {
// Initialize arrays with Node type
const staticProps = [];
const dynamicProps = [];
const sizeProps = [];
const deprecatedProps = [];
if (child.type === 'table' && child.children) {
// Skip table header (thead)
child.children.slice(1).forEach(node => {
const value = getCellValue(node);
if (groups.isDeprecated(node)) {
deprecatedProps.push(node);
fileAPIs[componentName].deprecated.add(value);
} else if (groups.isDynamic(value)) {
dynamicProps.push(node);
fileAPIs[componentName].dynamic.add(value);
} else if (groups.isSize(value)) {
sizeProps.push(node);
fileAPIs[componentName].size.add(value);
} else {
staticProps.push(node);
fileAPIs[componentName].static.add(value);
}
});
child.children = [child.children[0], ...alphabetSort(staticProps), ...sizeSort(sizeProps), ...alphabetSort(dynamicProps), ...alphabetSort(deprecatedProps) // deprecated props should be the last
];
}
});
return ast;
}
function sortAPI(md, filename) {
const ast = remarkWithYaml.parse(md);
const sortedAst = sort(ast, filename);
return remarkWithYaml.stringify(sortedAst);
}
function sortMiddleware(ctx) {
Object.keys(ctx.files).forEach(filename => {
const content = ctx.fileContents(filename);
const sortedContent = sortAPI(content, filename);
if (get(ctx.meta, 'program.report', false)) {
console.log(chalk.cyan(`🔍 report ${filename}`));
} else {
ctx.writeContents(filename, sortedContent);
}
});
}
export default (() => {
fileAPIs = {};
const program = new Command();
program.version('0.1.0').option('-f, --file [file]', 'Specify which file to be transformed', 'components/**/index.+(zh-CN|en-US).md').option('-o, --output [output]', 'Specify component api output path', '~component-api.json').option('-r, --report', 'Only output the report, will not modify the file', false).parse(process.argv);
// inject context to the majo stream
function injectContext(ctx) {
if (typeof ctx.meta !== 'object') ctx.meta = {};
Object.assign(ctx.meta, {
program
});
}
/* eslint-disable no-console */
stream.source(program.file).use(injectContext).use(sortMiddleware).dest('.').then(() => {
if (program.output) {
const data = {};
Object.keys(fileAPIs).forEach(componentName => {
data[componentName] = {
static: [...fileAPIs[componentName].static],
size: [...fileAPIs[componentName].size],
dynamic: [...fileAPIs[componentName].dynamic],
deprecated: [...fileAPIs[componentName].deprecated]
};
});
const reportPath = path.resolve(program.output);
fs.writeFileSync(reportPath, JSON.stringify(data, null, 2), 'utf8');
console.log(chalk.cyan(`API list file: ${reportPath}`));
}
}).then(() => {
console.log(chalk.green(`sort ant-design api successfully!`));
});
/* eslint-enable no-console */
});