From ae11da632b057fc6aa36d620b5ca40cb3a869c65 Mon Sep 17 00:00:00 2001 From: qingzhou Date: Tue, 20 Feb 2018 23:34:15 -0800 Subject: [PATCH] New: Auto-generate rule index Fix #391 --- helpers/rule-index-template.hbs | 14 +++++ helpers/update-content.js | 105 ++++++++++++++++++++++++++++---- 2 files changed, 106 insertions(+), 13 deletions(-) create mode 100644 helpers/rule-index-template.hbs diff --git a/helpers/rule-index-template.hbs b/helpers/rule-index-template.hbs new file mode 100644 index 000000000..f40414211 --- /dev/null +++ b/helpers/rule-index-template.hbs @@ -0,0 +1,14 @@ +# Rules categories + +{{#each categories}} +* [{{capitalize name}}](#{{name}}) +{{/each}} + +{{#each categories}} +## {{capitalize name}} + +{{#each rules}} +* [`{{name}}`]({{link}}) +{{/each}} + +{{/each}} diff --git a/helpers/update-content.js b/helpers/update-content.js index d47366535..1b8ff22e3 100644 --- a/helpers/update-content.js +++ b/helpers/update-content.js @@ -1,31 +1,110 @@ /* global config cp exec ls mv rm */ +const Handlebars = require('handlebars'); +const _ = require('lodash'); const shell = require('shelljs/global'); // eslint-disable-line no-unused-vars +const fs = require('fs'); const CLONE_URL = 'https://github.com/sonarwhal/sonarwhal.git'; // eslint-disable-line no-process-env -const SOURCE_DIR = 'src/content'; +const DEST_DIR = 'src/content'; +const DEST_RULES_DIR = `${DEST_DIR}/docs/user-guide/rules`; const TMP_DIR = require('./mktemp')(); +// const TMP_DIR = 'C:/Users/Quing/AppData/Local/Temp/VpB2e'; const PACKAGES_TMP_DIR = `${TMP_DIR}/packages`; +const categories = {}; + +/** + * Process catogories to be suitable for Handlebars templating. + * Before: { performance: ['rule-amp-validator'] } + * After: + * [{ + * name: 'performance', + * rules: [{ + * link: 'rule-amp-validator/', + * name: 'amp-validator' + * }] + * }] + */ +const processCategories = (cats) => { + const processedCategories = _.reduce(cats, (allCategories, includedRules, category) => { + const rules = _.map(includedRules, (rule) => { + const processedRule = { + link: `${rule}/`, + name: rule.replace(/^rule-/, '') + }; + + return processedRule; + }); + + const processedCategory = { + name: category, + rules + }; + + allCategories.push(processedCategory); + + return allCategories; + }, []); + + return { categories: processedCategories }; +}; + +/** Generate rule index markdown file. */ +const getRuleIndexContent = (cats) => { + Handlebars.registerHelper('capitalize', (str) => { + const filtered = str.replace(/[^a-zA-Z0-9]/g, ' '); + + return filtered.charAt(0).toUpperCase() + filtered.slice(1); + }); + + const templateContent = fs.readFileSync(`${__dirname}/rule-index-template.hbs`, 'utf8'); //eslint-disable-line no-sync + const template = Handlebars.compile(templateContent); + const ruleIndexContent = template(cats); + + return ruleIndexContent; +}; config.fatal = true; exec(`git clone ${CLONE_URL} "${TMP_DIR}"`); -rm('-rf', `${SOURCE_DIR}/docs/contributor-guide`); -rm('-rf', `${SOURCE_DIR}/docs/user-guide`); -rm('-rf', `${SOURCE_DIR}/about`); +rm('-rf', `${DEST_DIR}/docs/contributor-guide`); +rm('-rf', `${DEST_DIR}/docs/user-guide`); +rm('-rf', `${DEST_DIR}/about`); -cp('-R', `${PACKAGES_TMP_DIR}/sonarwhal/docs/contributor-guide`, `${SOURCE_DIR}/docs/contributor-guide`); -cp('-R', `${PACKAGES_TMP_DIR}/sonarwhal/docs/user-guide`, `${SOURCE_DIR}/docs/user-guide`); -cp('-R', `${PACKAGES_TMP_DIR}/sonarwhal/docs/about`, `${SOURCE_DIR}`); -cp(`${PACKAGES_TMP_DIR}/sonarwhal/CHANGELOG.md`, `${SOURCE_DIR}/about`); +cp('-R', `${PACKAGES_TMP_DIR}/sonarwhal/docs/contributor-guide`, `${DEST_DIR}/docs/contributor-guide`); +cp('-R', `${PACKAGES_TMP_DIR}/sonarwhal/docs/user-guide`, `${DEST_DIR}/docs/user-guide`); +cp('-R', `${PACKAGES_TMP_DIR}/sonarwhal/docs/about`, `${DEST_DIR}`); +cp(`${PACKAGES_TMP_DIR}/sonarwhal/CHANGELOG.md`, `${DEST_DIR}/about`); -const rules = ls('-R', `${PACKAGES_TMP_DIR}/rule-*/README.md`); +const ruleDocs = ls('-R', `${PACKAGES_TMP_DIR}/rule-*/README.md`); +const rules = ls('-R', `${PACKAGES_TMP_DIR}/rule-*/src/rule.ts`); +// Get rule documentations. +ruleDocs.forEach((ruleDocPath) => { + const ruleName = ruleDocPath.split('/').reverse()[1]; + const destRuleDocPath = `${DEST_RULES_DIR}/${ruleName}.md`; + + mv(ruleDocPath, destRuleDocPath); +}); + +// Get category information of rules. rules.forEach((rulePath) => { - const ruleName = rulePath.split('/').reverse()[1]; - const destRulePath = `${SOURCE_DIR}/docs/user-guide/rules/${ruleName}.md`; + const ruleContent = fs.readFileSync(rulePath, 'utf8'); // eslint-disable-line no-sync + const ruleName = rulePath.split('/').reverse()[2]; + const categoryRegex = /category:\s*Category\.([a-z]*)/; + const category = ruleContent.match(categoryRegex).pop(); - mv(rulePath, destRulePath); + if (categories[category]) { + categories[category].push(ruleName); + } else { + categories[category] = [ruleName]; + } }); -rm('-rf', TMP_DIR); +// Generate rule index markdown file. +const processedCategories = processCategories(categories); +const ruleIndexContent = getRuleIndexContent(processedCategories); + +fs.writeFileSync(`${DEST_RULES_DIR}/index.md`, ruleIndexContent); //eslint-disable-line no-sync + +// rm('-rf', TMP_DIR);