chore(scaffolding): Add rule scaffolding

Developers may now use  npm run lint to scaffold new rules.
This commit is contained in:
Dominik Ferber
2015-10-04 13:19:08 +02:00
parent 9dd3b34886
commit 63eba5883e
2 changed files with 215 additions and 0 deletions

View File

@@ -11,6 +11,7 @@
"lint": "eslint ./",
"prebuild": "npm run clean && mkdir dist",
"prepublish": "npm run build",
"rule": "babel scripts/new-rule.js | node",
"semantic-release": "semantic-release pre && npm publish && semantic-release post",
"test": "npm run lint && npm run build && npm run unit-test",
"unit-test": "istanbul cover --dir reports/coverage node_modules/mocha/bin/_mocha tests/**/*.js -- --reporter dot --compilers js:babel/register"
@@ -35,12 +36,14 @@
"devDependencies": {
"babel": "5.8.23",
"babel-eslint": "4.1.3",
"colors": "1.1.2",
"coveralls": "2.11.4",
"cz-conventional-changelog": "1.0.1",
"eslint": "1.6.0",
"ghooks": "0.3.2",
"istanbul": "0.3.21",
"mocha": "2.3.3",
"readline-sync": "1.2.21",
"rewire": "2.3.4",
"rimraf": "2.4.3",
"semantic-release": "4.3.5",

212
scripts/new-rule.js Normal file
View File

@@ -0,0 +1,212 @@
/* eslint-disable no-console */
var fs = require('fs')
var readlineSync = require('readline-sync')
var colors = require('colors/safe')
console.log('Scaffolding new rule. Please give the following details.')
var authorName = readlineSync.question(colors.green('What is your name? '))
var ruleId = readlineSync.question(colors.green('What is the rule ID? '))
var desc = readlineSync.question(colors.green('Type a short description of this rule: '))
var failingExample = readlineSync.question(colors.green('Type a short example of the code that will fail: '))
var escapedFailingExample = failingExample.replace(`'`, `\\'`)
var doc = `# ${desc} (${ruleId})
Please describe the origin of the rule here.
## Rule Details
This rule aims to...
The following patterns are considered warnings:
\`\`\`js
// fill me in
\`\`\`
The following patterns are not warnings:
\`\`\`js
// fill me in
\`\`\`
### Options
If there are any options, describe them here. Otherwise, delete this section.
## When Not To Use It
Give a short description of when it would be appropriate to turn off this rule.
## Further Reading
If there are other links that describe the issue this rule addresses, please include them here in a bulleted list.
`
var rule = `/**
* @fileoverview ${desc}
* @author ${authorName}
* @copyright 2015 ${authorName}. All rights reserved.
* See LICENSE file in root directory for full license.
*/
// -----------------------------------------------------------------------------
// Rule Definition
// -----------------------------------------------------------------------------
module.exports = (/* getMeta */) => (/* context */) => {
// variables should be defined here
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
// any helper functions should go here or else delete this section
// ---------------------------------------------------------------------------
// Public
// ---------------------------------------------------------------------------
return {
// give me methods
}
}
module.exports.schema = [
// fill in your schema
]
`
var test = `/**
* @fileoverview ${desc}
* @author ${authorName}
* @copyright 2015 ${authorName}. All rights reserved.
* See LICENSE file in root directory for full license.
*/
// -----------------------------------------------------------------------------
// Requirements
// -----------------------------------------------------------------------------
import { CLIENT, SERVER } from '../../../dist/util/environment.js'
var rule = require('../../../dist/rules/${ruleId}')
var RuleTester = require('eslint').RuleTester
// -----------------------------------------------------------------------------
// Environments
// -----------------------------------------------------------------------------
const serverEnv = {
path: 'server/${ruleId}.js',
env: CLIENT
isCompatibilityFile: false,
isInMeteorProject: true,
isPackageConfig: false,
isMobileConfig: false
}
const clientEnv = {
path: 'server/${ruleId}.js',
env: CLIENT
isCompatibilityFile: false,
isInMeteorProject: true,
isPackageConfig: false,
isMobileConfig: false
}
// -----------------------------------------------------------------------------
// Tests
// -----------------------------------------------------------------------------
var ruleTester = new RuleTester()
ruleTester.run('${ruleId}', rule(() => serverEnv), {
valid: [
// fill me in
],
invalid: [
{
code: '${escapedFailingExample}',
errors: [
{message: 'Unexpected Session statement.', type: 'MemberExpression'}
]
}
]
})
ruleTester.run('${ruleId}', rule(() => clientEnv), {
valid: [
// fill me in
],
invalid: [
{
code: '${escapedFailingExample}',
errors: [
{message: 'Unexpected Session statement.', type: 'MemberExpression'}
]
}
]
})
`
var docFileName = `docs/rules/${ruleId}.md`
var ruleFileName = `lib/rules/${ruleId}.js`
var testFileName = `tests/lib/rules/${ruleId}.js`
var writeOptions = {
encoding: 'utf8',
flag: 'wx'
}
try {
fs.writeFileSync(ruleFileName, rule, writeOptions)
fs.writeFileSync(testFileName, test, writeOptions)
fs.writeFileSync(docFileName, doc, writeOptions)
console.log(colors.white('✓ ') + colors.green('create ' + ruleFileName))
console.log(colors.white('✓ ') + colors.green('create ' + testFileName))
console.log(colors.white('✓ ') + colors.green('create ' + docFileName))
} catch (e) {
if (e.code === 'EEXIST') {
console.log(colors.red(`Aborting because rule already exists (${e.path})`))
// clean up already created files
switch (e.path) {
case ruleFileName:
break
case testFileName:
fs.unlinkSync(ruleFileName)
break
case docFileName:
fs.unlinkSync(ruleFileName)
fs.unlinkSync(testFileName)
break
default:
break
}
} else {
console.log(e)
}
}