Skip to content
This repository was archived by the owner on Feb 21, 2022. It is now read-only.

Commit 6eb0608

Browse files
author
Manuel Lopez
committed
[docs] update CONTRIBUTING page to state that rules must have ter prefix
`new-rule` gulp task has been updated to make sure we add the ter prefix. The templates have also been updated and link to tslint has been added to point developers on how to design rule walkers.
1 parent fdf0230 commit 6eb0608

File tree

4 files changed

+45
-22
lines changed

4 files changed

+45
-22
lines changed

CONTRIBUTING.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ the issue easier and quicker.
1919
* tslint and typescript version.
2020

2121
$ tslint --version
22-
4.5.1
22+
5.2.0
2323
$ tsc --version
24-
Version 2.2.1
24+
Version 2.3.2
2525

2626
* `tslint.json` configuration.
2727
* typescript code being linted.
@@ -34,22 +34,25 @@ If you are not yet familiar with the way Github works (forking, pull requests, e
3434
check out this [article about forking](https://help.github.com/articles/fork-a-repo/). To get
3535
started on a new rule or fix/improve some existing rule you can follow the instructions below.
3636

37-
- Create a branch with the rule name, e.g. `no-if-usage`.
37+
- Pick the rule name you will be working on and add the `ter` prefix. For instance, if you will be
38+
working on the `no-tabs` rule, then the rule name will be `ter-no-tabs`. This is to avoid future
39+
name collision with native rules provided by `TSLint`.
40+
- Create a branch with the rule name, e.g. `ter-indent`.
3841
- If you haven't, run `npm install` to download the project dependencies.
3942
- Create your rule tests at `./src/test/rules` and your rule in `./src/rules` with the convention:
40-
- Name: rule-name (hyphenated, e.g: no-if-usage)
41-
- Rule File: ruleNameRule.ts (camelCased and with the `Rule` suffix, e.g: noIfUsageRule.ts)
42-
- Test File: ruleNameRuleTests.ts (camelCased and with the `RuleTests` suffix, e.g: noIfUsageRuleTests.ts)
43+
- Name: rule-name (hyphenated, e.g: `ter-no-if-usage`)
44+
- Rule File: ruleNameRule.ts (camelCased and with the `Rule` suffix, e.g: `terNoIfUsageRule.ts`)
45+
- Test File: ruleNameRuleTests.ts (camelCased and with the `RuleTests` suffix, e.g: `terNoIfUsageRuleTests.ts`)
4346

4447
This step can be done automatically by running
4548

4649
```
4750
gulp new-rule --rule rule-name
4851
```
4952

50-
This will generate a the rule template and test template in the appropiate directories.
53+
This will generate a the rule template and test template in the appropriate directories.
5154

52-
- Check if your rule is passing with `gulp test --single rule-name` (hyphenated, e.g no-inner-declarations)
55+
- Check if your rule is passing with `gulp test --single rule-name` (hyphenated, e.g ter-arrow-spacing)
5356
- During development you may have some linting errors that won't let you run the test. You can
5457
disable the linting process with the `--no-lint` flag: `gulp test --single rule-name --no-lint`.
5558
- If you are using the `RuleTester` utility as in the `ter-indent` rule tests you can specify a

gulpfile.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,15 @@ gulp.task('fetch', ['build'], function fetch(gulpCallBack) {
3838

3939
gulp.task('new-rule', ['build'], function newRule(done) {
4040
var newRule = require('./dist/tools/newRule');
41-
if (argv.rule) {
42-
newRule.writeNewRule(argv.rule);
43-
newRule.writeNewRuleTests(argv.rule);
44-
done();
45-
} else {
41+
const ruleName = argv.rule;
42+
if (!ruleName) {
4643
done('missing `--rule` option');
44+
} else if (!ruleName.startsWith('ter-')) {
45+
done('rule name is missing the `ter-` prefix');
46+
} else {
47+
newRule.writeNewRule(ruleName);
48+
newRule.writeNewRuleTests(ruleName);
49+
done();
4750
}
4851
});
4952

src/readme/rules.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3101,9 +3101,11 @@ const rules: IRule[] = [
31013101
}
31023102
];
31033103

3104-
function toCamelCase(str: string): string {
3104+
function toCamelCase(str: string, pascal: boolean = false): string {
31053105
const words = str.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1));
3106-
words[0] = words[0].toLowerCase();
3106+
if (!pascal) {
3107+
words[0] = words[0].toLowerCase();
3108+
}
31073109
return words.join('');
31083110
}
31093111

src/tools/newRule.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ import * as path from 'path';
44

55
export function writeNewRule(ruleKebabName: string): void {
66
const ruleCamelName = toCamelCase(ruleKebabName);
7+
const ruleOptionsName = `I${toCamelCase(ruleKebabName, true)}Options`;
78
const ruleTemplate = `import * as ts from 'typescript';
89
import * as Lint from 'tslint';
910
1011
const RULE_NAME = '${ruleKebabName}';
12+
interface ${ruleOptionsName} {
13+
// Add the options properties
14+
}
1115
1216
export class Rule extends Lint.Rules.AbstractRule {
1317
public static metadata: Lint.IRuleMetadata = {
@@ -41,14 +45,23 @@ export class Rule extends Lint.Rules.AbstractRule {
4145
type: '' // one of "functionality" | "maintainability" | "style" | "typescript"
4246
};
4347
48+
private formatOptions(ruleArguments: any[]): ${ruleOptionsName} {
49+
// handle the ruleArguments
50+
return {};
51+
}
52+
4453
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
45-
const walker = new RuleWalker(sourceFile, this.getOptions());
54+
// Convert the 'ruleArguments' into a useful format before passing it to the constructor of AbstractWalker.
55+
const opt = this.formatOptions(this.ruleArguments);
56+
const walker = new RuleWalker(sourceFile, this.ruleName, opt);
4657
return this.applyWithWalker(walker);
4758
}
4859
}
4960
50-
class RuleWalker extends Lint.RuleWalker {
51-
// ** RULE IMPLEMENTATION HERE **
61+
// NOTE: please remove this comment after reading: https://palantir.github.io/tslint/develop/custom-rules/walker-design.html
62+
class RuleWalker extends Lint.AbstractWalker<${ruleOptionsName}> {
63+
public walk(sourceFile: ts.SourceFile) {
64+
}
5265
}
5366
`;
5467
const projectDir = path.dirname(__dirname);
@@ -62,13 +75,15 @@ export function writeNewRuleTests(ruleKebabName: string): void {
6275
6376
const ruleTester = new RuleTester('${ruleKebabName}');
6477
65-
function expecting(errors: string[]]): Failure[] {
78+
// Change this function to better test the rule. In some cases the message never changes so we
79+
// can avoid passing it in. See other rule tests for examples.
80+
function expecting(errors: [string, number, number][]): Failure[] {
6681
return errors.map((err) => {
67-
let message = '';
82+
let message = err[0];
6883
return {
6984
failure: message,
70-
startPosition: new Position(err[0]),
71-
endPosition: new Position()
85+
startPosition: new Position(err[1]),
86+
endPosition: new Position(err[2])
7287
};
7388
});
7489
}

0 commit comments

Comments
 (0)