Skip to content

Commit

Permalink
Added jsdoc formatting rule
Browse files Browse the repository at this point in the history
  • Loading branch information
gscshoyru committed Dec 9, 2013
1 parent d2ec389 commit da464f6
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Supported Rules
* `forin` enforces a `for ... in` statement to be filtered with an `if` statement.*
* `indent` enforces consistent indentation levels (currently disabled).
* `interface-name` enforces the rule that interface names must begin with a capital 'I'
* `jsdoc-format` enforces basic format rules for jsdoc comments -- spaces after the *'s and alignment -- all comments that start with /** will be checked
* `label-position` enforces labels only on sensible statements.
* `label-undefined` checks that labels are defined before usage.
* `max-line-length` sets the maximum length of a line.
Expand Down
87 changes: 87 additions & 0 deletions src/rules/jsdocFormatRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright 2013 Palantir Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/// <reference path='../../lib/tslint.d.ts' />

export class Rule extends Lint.Rules.AbstractRule {
static FAILURE_STRING = "this jsdoc is not formatted correctly";

public apply(syntaxTree: TypeScript.SyntaxTree): Lint.RuleFailure[] {
return this.applyWithWalker(new JsdocWalker(syntaxTree, this.getOptions()));
}
}

class JsdocWalker extends Lint.RuleWalker {
public visitToken(token: TypeScript.ISyntaxToken): void {
this.findFailuresForTrivia(token.leadingTrivia().toArray(), this.position());
this.findFailuresForTrivia(token.trailingTrivia().toArray(), this.position() + token.leadingTriviaWidth() + token.width());

super.visitToken(token);
}

private findFailuresForTrivia(triviaList: TypeScript.ISyntaxTrivia[], startingPosition: number) {
var currentPosition = startingPosition;
var lastTriviaItem: TypeScript.ISyntaxTrivia = null;
triviaList.forEach((triviaItem) => {
if (triviaItem.kind() === TypeScript.SyntaxKind.MultiLineCommentTrivia) {
var commentText = triviaItem.fullText();
var lines = commentText.split("\n");

var firstLine = lines[0];
// regex is: start of string, followed by any amount of whitespace, followed by /**
var isJsdocMatch = firstLine.match(/^\s*\/\*\*/);
if (isJsdocMatch != null) {
var lastTriviaItemLines = lastTriviaItem.fullText().split("\n");
var lastTriviaItemLineLength = lastTriviaItemLines[lastTriviaItemLines.length - 1].length;
var indexToMatch = firstLine.indexOf("**") + lastTriviaItemLineLength;
// all lines but the first and last
var otherLines = lines.splice(1, lines.length - 2);
otherLines.forEach((line) => {
// regex is: start of string, followed by any amount of whitespace, followed by *,
// followed by either a space or the end of the string
var asteriskMatch = line.match(/^\s*\*( |$)/);
if (asteriskMatch == null) {
this.addFailureAt(currentPosition, triviaItem.fullWidth());
}
var asteriskIndex = line.indexOf("*");
if (asteriskIndex !== indexToMatch) {
this.addFailureAt(currentPosition, triviaItem.fullWidth());
}
});
var lastLine = lines[lines.length - 1];
// regex is: start of string, followed by any amount of whitespace, followed by */,
// followed by the end of the string
var endBlockCommentMatch = lastLine.match(/^\s*\*\/$/);
if (endBlockCommentMatch == null) {
this.addFailureAt(currentPosition, triviaItem.fullWidth());
}
var lastAsteriskIndex = lastLine.indexOf("*");
if (lastAsteriskIndex !== indexToMatch) {
this.addFailureAt(currentPosition, triviaItem.fullWidth());
}
}

}
currentPosition += triviaItem.fullWidth();
lastTriviaItem = triviaItem;
});
}

private addFailureAt(currentPosition: number, width: number) {
var failure = this.createFailure(currentPosition, width, Rule.FAILURE_STRING);
this.addFailure(failure);
}
}
42 changes: 42 additions & 0 deletions test/files/rules/jsdoc.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
class Clazz { //this is not a block comment
/* block comment
*Not a jsdoc and not subject to the rules lalala
* oh look I'm over here and you can't do anything about me
*and now I'm here, wheeee
I've even got characters where I shouldn't. How fun! *
You can't stop me! */
public funcxion() {
/**
* This is jsdoc
* and it is correct
* so should be no errors here
*
* not on the above line either
*/
}

/**
* this is also jsdoc
*and it has a problem on this line
*/

/**
* this jsoc is fine
* up until the last line when it isn't
*/

/**
* this jsdoc has characters where it really should
not */

/**
* same thing with this
one *
*/

/**
* what else can go wrong?
* oh right this
*/

}
40 changes: 40 additions & 0 deletions test/rules/jsdocFormatRuleTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2013 Palantir Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/// <reference path='../references.ts' />

describe("<jsdoc-format>", () => {
var JsdocFormatRule = Lint.Test.getRule("jsdoc-format");

it("ensures jsdoc comments have properly lined up asterisks and start with spaces", () => {
var fileName = "rules/jsdoc.test.ts";
var createFailure = Lint.Test.createFailuresOnFile(fileName, JsdocFormatRule.FAILURE_STRING);
var expectedFailure1 = createFailure([18, 5], [21, 8]);
var expectedFailure2 = createFailure([23, 5], [26, 6]);
var expectedFailure3 = createFailure([28, 5], [30, 8]);
var expectedFailure4 = createFailure([32, 5], [35, 8]);
var expectedFailure5 = createFailure([37, 5], [40, 8]);

var actualFailures = Lint.Test.applyRuleOnFile(fileName, JsdocFormatRule);

Lint.Test.assertContainsFailure(actualFailures, expectedFailure1);
Lint.Test.assertContainsFailure(actualFailures, expectedFailure2);
Lint.Test.assertContainsFailure(actualFailures, expectedFailure3);
Lint.Test.assertContainsFailure(actualFailures, expectedFailure4);
Lint.Test.assertContainsFailure(actualFailures, expectedFailure5);
assert.lengthOf(actualFailures, 5);
});
});

0 comments on commit da464f6

Please sign in to comment.