aboutsummaryrefslogtreecommitdiffstats
path: root/packages/tslint-config
diff options
context:
space:
mode:
Diffstat (limited to 'packages/tslint-config')
-rw-r--r--packages/tslint-config/CHANGELOG.md4
-rw-r--r--packages/tslint-config/rules/underscorePrivatesRule.ts68
-rw-r--r--packages/tslint-config/tslint.json1
3 files changed, 73 insertions, 0 deletions
diff --git a/packages/tslint-config/CHANGELOG.md b/packages/tslint-config/CHANGELOG.md
index 45c9eaad8..5364ae0ee 100644
--- a/packages/tslint-config/CHANGELOG.md
+++ b/packages/tslint-config/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+v0.x.x - TBD
+------------------------
+ * Added custom 'underscore-privates' rule, requiring underscores to be prepended to private variable names
+
v0.3.0 - _December 20, 2017_
------------------------
* Added rules for unused imports, variables and Async suffixes (#265)
diff --git a/packages/tslint-config/rules/underscorePrivatesRule.ts b/packages/tslint-config/rules/underscorePrivatesRule.ts
new file mode 100644
index 000000000..d00f9696c
--- /dev/null
+++ b/packages/tslint-config/rules/underscorePrivatesRule.ts
@@ -0,0 +1,68 @@
+import * as Lint from 'tslint';
+import * as ts from 'typescript';
+
+const UNDERSCORE = '_'.charCodeAt(0);
+
+type RelevantClassMember =
+ | ts.MethodDeclaration
+ | ts.PropertyDeclaration
+ | ts.GetAccessorDeclaration
+ | ts.SetAccessorDeclaration;
+
+// Based on: https://github.com/DanielRosenwasser/underscore-privates-tslint-rule
+export class Rule extends Lint.Rules.AbstractRule {
+ public static FAILURE_STRING = 'private members name must be prefixed with an underscore';
+
+ public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
+ return this.applyWithFunction(sourceFile, walk);
+ }
+}
+
+function walk(ctx: Lint.WalkContext<void>): void {
+ traverse(ctx.sourceFile);
+
+ function traverse(node: ts.Node): void {
+ checkNodeForViolations(ctx, node);
+ return ts.forEachChild(node, traverse);
+ }
+}
+
+function checkNodeForViolations(ctx: Lint.WalkContext<void>, node: ts.Node): void {
+ if (!isRelevantClassMember(node)) {
+ return;
+ }
+
+ // The declaration might have a computed property name or a numeric name.
+ const name = node.name;
+ if (!nameIsIdentifier(name)) {
+ return;
+ }
+
+ if (!nameStartsWithUnderscore(name.text) && memberIsPrivate(node)) {
+ ctx.addFailureAtNode(name, Rule.FAILURE_STRING);
+ }
+}
+
+function isRelevantClassMember(node: ts.Node): node is RelevantClassMember {
+ switch (node.kind) {
+ case ts.SyntaxKind.MethodDeclaration:
+ case ts.SyntaxKind.PropertyDeclaration:
+ case ts.SyntaxKind.GetAccessor:
+ case ts.SyntaxKind.SetAccessor:
+ return true;
+ default:
+ return false;
+ }
+}
+
+function nameStartsWithUnderscore(text: string) {
+ return text.charCodeAt(0) === UNDERSCORE;
+}
+
+function memberIsPrivate(node: ts.Declaration) {
+ return Lint.hasModifier(node.modifiers, ts.SyntaxKind.PrivateKeyword);
+}
+
+function nameIsIdentifier(node: ts.Node): node is ts.Identifier {
+ return node.kind === ts.SyntaxKind.Identifier;
+}
diff --git a/packages/tslint-config/tslint.json b/packages/tslint-config/tslint.json
index acb6876c3..49e31b13d 100644
--- a/packages/tslint-config/tslint.json
+++ b/packages/tslint-config/tslint.json
@@ -81,6 +81,7 @@
],
"space-within-parens": false,
"type-literal-delimiter": true,
+ "underscore-privates": true,
"variable-name": [true,
"ban-keywords",
"allow-pascal-case"