123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 |
- import * as fs from 'fs';
- import * as path from 'path';
- import * as prettier from 'prettier';
- import * as Prism from 'prismjs';
- // tslint:disable-next-line:no-import-side-effect
- import 'prismjs/components/prism-typescript';
- import { parseDescription } from '../site/utils';
- interface RuleJson {
- rules: {
- [propName: string]: boolean | any[];
- };
- meta: {
- category: keyof typeof Builder.RuleCategoryPriority;
- description: string;
- reason?: string;
- 'ts-only'?: boolean;
- 'has-fixer'?: boolean;
- 'requires-type-info'?: boolean;
- prettier?: boolean;
- };
- }
- class Builder {
- public static RuleCategoryPriority = {
- 'typescript-specific': 0,
- functionality: 1,
- maintainability: 2,
- style: 3
- };
- public static RuleCategoryDescription = {
- 'typescript-specific': {
- title: 'TypeScript 相关',
- description: '与 TypeScript 特性相关的规则。'
- },
- functionality: {
- title: '功能性检查',
- description: '找出可能的错误,以及可能会产生 bug 的编码习惯。'
- },
- maintainability: {
- title: '可维护性',
- description: '增强代码可维护性的规则。'
- },
- style: {
- title: '代码风格',
- description: '与代码风格相关的规则。'
- }
- };
- private static CommentMap = {
- 'ts-only': '仅支持 ts 文件',
- 'has-fixer': '支持自动修复',
- 'requires-type-info': '需要提供类型信息',
- prettier: '可交由 prettier 控制'
- };
- private ruleList: RuleJson[] = this.getRuleList();
- /**
- * 生成 index.js 文件
- */
- public buildIndex() {
- const tslintConfigList = this.ruleList.map((ruleJson) => {
- const ruleName = Object.keys(ruleJson.rules)[0];
- const comments = Object.keys(ruleJson.meta).map((key) => {
- let metaItemValue: string =
- Builder.CommentMap[key] || ruleJson.meta[key].toString();
- return `@${key} ${metaItemValue
- // 去掉 `
- .replace(/`/g, '')
- // 如果在 meta 种存在手动写的 \n,则会换行并且对其行首
- .split('\n')
- .map((line, index) => {
- if (index === 0) return line;
- return ' '.repeat(key.length + 2) + line;
- })
- .join('\n')}`;
- });
- if (!ruleJson.meta.category) console.log(ruleJson.rules);
- return `/**
- ${comments
- // 统一添加行首的 *
- .join('\n')
- .split('\n')
- .map((comment) => `* ${comment}`)
- .join('\n')}
- */
- "${ruleName}": ${JSON.stringify(ruleJson.rules[ruleName])}`;
- });
- const tslintConfig = `
- /**
- * AlloyTeam TSLint 规则
- *
- * 作者: xcatliu <xcatliu@gmail.com>
- * 仓库: https://github.com/AlloyTeam/tslint-config-alloy
- *
- * 基于 tslint@5.11.0
- * 此文件是由脚本 scripts/build.ts 自动生成
- *
- * @category 此规则属于哪种分类
- * @description 一句话描述此规则
- * @reason 为什么要开启(关闭)此规则
- * @ts-only 仅支持 ts 文件
- * @has-fixer 支持自动修复
- * @requires-type-info 需要提供类型信息(需要 --project 参数)
- * @prettier 可交由 prettier 控制
- */
- module.exports = {
- "rules": {
- ${tslintConfigList.join(',\n')}
- }
- };
- `;
- fs.writeFileSync(
- path.resolve(__dirname, '../index.js'),
- // 使用 prettier 格式化文件内容
- prettier.format(tslintConfig, {
- ...require('../prettier.config'),
- parser: 'babylon'
- }),
- 'utf-8'
- );
- }
- /**
- * 生成 site/tslint.json
- */
- public buildSiteTSLintRulesJson() {
- const tslintJson = {};
- this.ruleList.forEach((ruleJson) => {
- const ruleName = this.getRuleName(ruleJson);
- tslintJson[ruleName] = ruleJson.rules[ruleName];
- });
- fs.writeFileSync(
- path.resolve(__dirname, '../site/tslint-rules.json'),
- // 使用 prettier 格式化文件内容
- prettier.format(JSON.stringify(tslintJson), {
- ...require('../prettier.config'),
- parser: 'json'
- }),
- 'utf-8'
- );
- }
- /**
- * 生成 site/tslint-meta.json
- */
- public buildSiteTSLintMetaJson() {
- const tslintMetaJson = {};
- this.ruleList.forEach((ruleJson) => {
- const ruleName = this.getRuleName(ruleJson);
- tslintMetaJson[ruleName] = ruleJson.meta;
- });
- fs.writeFileSync(
- path.resolve(__dirname, '../site/tslint-meta.json'),
- // 使用 prettier 格式化文件内容
- prettier.format(JSON.stringify(tslintMetaJson), {
- ...require('../prettier.config'),
- parser: 'json'
- }),
- 'utf-8'
- );
- }
- /**
- * 生成 site/tslint-tests.json
- */
- public buildSiteTSLintTestsJson() {
- const tslintTestsJson = {};
- this.ruleList.forEach((ruleJson) => {
- const ruleName = this.getRuleName(ruleJson);
- const testGoodPath = path.resolve(__dirname, '../test/', ruleName, 'good.ts');
- const testBadPath = path.resolve(__dirname, '../test/', ruleName, 'bad.ts');
- if (fs.existsSync(testGoodPath)) {
- if (!tslintTestsJson[ruleName]) {
- tslintTestsJson[ruleName] = {};
- }
- tslintTestsJson[ruleName].good = Prism.highlight(
- fs.readFileSync(testGoodPath, 'utf-8'),
- Prism.languages.typescript
- );
- }
- if (fs.existsSync(testBadPath)) {
- if (!tslintTestsJson[ruleName]) {
- tslintTestsJson[ruleName] = {};
- }
- tslintTestsJson[ruleName].bad = Prism.highlight(
- fs.readFileSync(testBadPath, 'utf-8'),
- Prism.languages.typescript
- );
- }
- });
- fs.writeFileSync(
- path.resolve(__dirname, '../site/tslint-tests.json'),
- // 使用 prettier 格式化文件内容
- prettier.format(JSON.stringify(tslintTestsJson), {
- ...require('../prettier.config'),
- parser: 'json'
- }),
- 'utf-8'
- );
- }
- /**
- * 生成 README.md 文件
- */
- public buildREADME() {
- const typescriptSpecificTable = this.renderCategoryTable('typescript-specific');
- const functionalityTable = this.renderCategoryTable('functionality');
- const maintainabilityTable = this.renderCategoryTable('maintainability');
- const styleTable = this.renderCategoryTable('style');
- const ruleContent = `
- ### ${Builder.RuleCategoryDescription['typescript-specific'].title}
- ${Builder.RuleCategoryDescription['typescript-specific'].description}
- ${typescriptSpecificTable}
- ### ${Builder.RuleCategoryDescription.functionality.title}
- ${Builder.RuleCategoryDescription.functionality.description}
- ${functionalityTable}
- ### ${Builder.RuleCategoryDescription.maintainability.title}
- ${Builder.RuleCategoryDescription.maintainability.description}
- ${maintainabilityTable}
- ### ${Builder.RuleCategoryDescription.style.title}
- ${Builder.RuleCategoryDescription.style.description}
- ${styleTable}
- `;
- const READMETemplate = fs.readFileSync(path.resolve(__dirname, '../_README.md'), 'utf-8');
- const READMEContent = READMETemplate.replace('RULE_CONTENT', ruleContent);
- fs.writeFileSync(
- path.resolve(__dirname, '../README.md'),
- // 使用 prettier 格式化文件内容
- prettier.format(READMEContent, {
- ...require('../prettier.config'),
- parser: 'markdown'
- }),
- 'utf-8'
- );
- }
- /**
- * 生成某一个分类的列表
- */
- private renderCategoryTable(category: string) {
- const ruleListHTML = this.ruleList
- .filter((ruleJson) => ruleJson.meta.category === category)
- .map((ruleJson) => {
- const ruleName = Object.keys(ruleJson.rules)[0];
- return `
- <tr>
- <td>${this.renderCheckMark(ruleJson.rules[ruleName])}</td>
- <td><a href="https://palantir.github.io/tslint/rules/${ruleName}/">${ruleName}</a></td>
- <td>${parseDescription(ruleJson.meta.description)}</td>
- </tr>`;
- })
- .join('');
- const tableHTML = `
- <table>
- <thead>
- <tr>
- <th width="60">开关</th>
- <th>名称</th>
- <th>描述</th>
- </tr>
- </thead>
- <tbody>${ruleListHTML}
- </tbody>
- </table>
- `;
- return tableHTML;
- }
- /**
- * 获取规则列表,根据分类和字母排序
- */
- private getRuleList() {
- const ruleList = fs
- .readdirSync(path.resolve(__dirname, '../test'))
- .filter((filename) =>
- fs.lstatSync(path.resolve(__dirname, '../test', filename)).isDirectory()
- )
- .map((ruleName) => {
- const ruleJson: RuleJson = require(path.resolve(
- __dirname,
- '../test',
- ruleName,
- 'tslint.json'
- ));
- return ruleJson;
- })
- .sort((aRuleJson, bRuleJson) => {
- const aRuleCategory = aRuleJson.meta.category;
- const bRuleCategory = bRuleJson.meta.category;
- if (
- Builder.RuleCategoryPriority[aRuleCategory] >
- Builder.RuleCategoryPriority[bRuleCategory]
- ) {
- return 1;
- }
- if (
- Builder.RuleCategoryPriority[aRuleCategory] <
- Builder.RuleCategoryPriority[bRuleCategory]
- ) {
- return -1;
- }
- return this.getRuleName(aRuleJson) > this.getRuleName(bRuleJson) ? 1 : -1;
- });
- return ruleList;
- }
- /**
- * 根据具体的规则对象生成规则的名称
- * @param ruleJson 具体的规则对象
- */
- private getRuleName(ruleJson: RuleJson) {
- return Object.keys(ruleJson.rules)[0];
- }
- private renderCheckMark(isCheck) {
- // undefined or null or false
- if (!isCheck) {
- return '❌';
- }
- return '✅';
- }
- }
- const builder = new Builder();
- builder.buildIndex();
- builder.buildREADME();
- builder.buildSiteTSLintRulesJson();
- builder.buildSiteTSLintMetaJson();
- builder.buildSiteTSLintTestsJson();
|