From a065198bef359fe9f62c66565fb710ddeed7190a Mon Sep 17 00:00:00 2001 From: reduckted Date: Fri, 28 Dec 2018 13:28:17 +1000 Subject: [PATCH] 586 walk in new rule template (#702) * Used a walk function instead of extending RuleWalker in the new rule template. * Used EJS for the new rule template. * Added a prompt asking whether the new rule has options. * Replaced EJS templates with Underscore templates. --- build-tasks/create-rule.js | 32 +++++++---------- build-tasks/templates/rule.template | 48 ++++++++++++++++++++++++++ build-tasks/templates/rule.template.js | 39 --------------------- 3 files changed, 60 insertions(+), 59 deletions(-) create mode 100644 build-tasks/templates/rule.template delete mode 100644 build-tasks/templates/rule.template.js diff --git a/build-tasks/create-rule.js b/build-tasks/create-rule.js index e7c2b33ee..830d6bc41 100644 --- a/build-tasks/create-rule.js +++ b/build-tasks/create-rule.js @@ -1,6 +1,8 @@ +const { execSync } = require('child_process'); +const { template } = require('underscore'); const fs = require('fs'); const inquirer = require('inquirer'); -const { execSync } = require('child_process'); +const path = require('path'); const { writeFile } = require('./common/files'); const questions = [ @@ -27,6 +29,12 @@ const questions = [ return 'Please enter a description for the rule.'; } }, + { + name: 'hasOptions', + message: 'Has options:', + type: 'confirm', + default: false + }, { name: 'typescriptOnly', message: 'TypeScript only:', @@ -92,21 +100,9 @@ inquirer.prompt(questions).then(answers => { function createImplementationFile(answers) { const ruleFile = camelCase(answers.name) + 'Rule'; const sourceFileName = 'src/' + ruleFile + '.ts'; - const walkerName = pascalCase(ruleFile) + 'Walker'; - - const ruleTemplate = require('./templates/rule.template'); - const ruleSource = ruleTemplate({ - ruleName: answers.name, - walkerName, - type: answers.type, - description: answers.description, - typescriptOnly: answers.typescriptOnly, - issueClass: answers.issueClass, - issueType: answers.issueType, - severity: answers.severity, - level: answers.level, - group: answers.group - }); + + const ruleTemplate = fs.readFileSync(path.resolve(__dirname, 'templates/rule.template'), 'utf8'); + const ruleSource = template(ruleTemplate)(answers); writeFile(sourceFileName, ruleSource); @@ -147,10 +143,6 @@ function camelCase(input) { return input.toLowerCase().replace(/-(.)/g, (match, group1) => group1.toUpperCase()); } -function pascalCase(input) { - return input.charAt(0).toUpperCase() + input.substr(1); -} - function tryOpenFiles(files) { // Check if we're running in the VS Code terminal. If we // are, then we can try to open the new files in VS Code. diff --git a/build-tasks/templates/rule.template b/build-tasks/templates/rule.template new file mode 100644 index 000000000..30339710c --- /dev/null +++ b/build-tasks/templates/rule.template @@ -0,0 +1,48 @@ +import * as ts from 'typescript'; +import * as Lint from 'tslint'; + +import { ExtendedMetadata } from './utils/ExtendedMetadata'; +import { AstUtils } from './utils/AstUtils'; +import { Utils } from './utils/Utils'; + +const FAILURE_STRING: string = 'Some error message: '; // TODO: Define an error message +<% if (hasOptions) { %> +interface Options { + // TODO: Add option properties. +} +<% } %> +export class Rule extends Lint.Rules.AbstractRule { + public static metadata: ExtendedMetadata = { + ruleName: '<%= name %>', + type: '<%= type %>', + description: '<%= description %>',<% if (hasOptions) { %> + options: { + // TODO: Fill in the options. + }, + optionsDescription: '', // TODO: Fill in the options description. + optionExamples: [], // TODO: Add option examples. + <% } else { %> + options: null, // tslint:disable-line:no-null-keyword + optionsDescription: '', + <% } %>typescriptOnly: <%= typescriptOnly %>, + issueClass: '<%= issueClass %>', + issueType: '<%= issueType %>', + severity: '<%= severity %>', + level: '<%= level %>', + group: '<%= group %>', + commonWeaknessEnumeration: '...' // if possible, please map your rule to a CWE (see cwe_descriptions.json and https://cwe.mitre.org) + }; + + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + return this.applyWithFunction(sourceFile, walk<% if (hasOptions) { %>, this.getOptions()<% } %>); + } +} + +function walk(ctx: Lint.WalkContext<<% if (hasOptions) { %>Options<% } else { %>void<% } %>>) { + function cb(node: ts.Node): void { + // TODO: Implement the rule here. + return ts.forEachChild(node, cb); + } + + return ts.forEachChild(ctx.sourceFile, cb); +} diff --git a/build-tasks/templates/rule.template.js b/build-tasks/templates/rule.template.js deleted file mode 100644 index d2e5f22e5..000000000 --- a/build-tasks/templates/rule.template.js +++ /dev/null @@ -1,39 +0,0 @@ -module.exports = ({ ruleName, walkerName, type, description, typescriptOnly, issueClass, issueType, severity, level, group }) => - `import * as ts from 'typescript'; -import * as Lint from 'tslint'; - -import { ExtendedMetadata } from './utils/ExtendedMetadata'; -import { AstUtils } from './utils/AstUtils'; -import { Utils } from './utils/Utils'; - -const FAILURE_STRING: string = 'Some error message: '; // TODO: Define an error message - -export class Rule extends Lint.Rules.AbstractRule { - public static metadata: ExtendedMetadata = { - ruleName: '${ruleName}', - type: '${type}', - description: '${description}', - // TODO: Fill in the options and options description, or leave them as they are if there are no options. - options: null, // tslint:disable-line:no-null-keyword - optionsDescription: '', - optionExamples: [], // TODO: Remove this property if the rule has no options - typescriptOnly: ${typescriptOnly}, - issueClass: '${issueClass}', - issueType: '${issueType}', - severity: '${severity}', - level: '${level}', - group: '${group}', - commonWeaknessEnumeration: '...' // if possible, please map your rule to a CWE (see cwe_descriptions.json and https://cwe.mitre.org) - }; - - public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - return this.applyWithWalker(new ${walkerName}(sourceFile, this.getOptions())); - } -} - -class ${walkerName} extends Lint.RuleWalker { - protected visitNode(node: ts.Node): void { - super.visitNode(node); - } -} -`;