forked from palantir/tslint
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Core object-literal-key-quotes rule (palantir#1364)
* Core quote-props rule * Tweaks for code review * rename
- Loading branch information
Showing
8 changed files
with
153 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import * as Lint from "../lint"; | ||
import * as ts from "typescript"; | ||
|
||
export class Rule extends Lint.Rules.AbstractRule { | ||
/* tslint:disable:object-literal-sort-keys */ | ||
public static metadata: Lint.IRuleMetadata = { | ||
ruleName: "object-literal-key-quotes", | ||
description: "Enforces consistent object literal property quote style.", | ||
descriptionDetails: Lint.Utils.dedent` | ||
Object literal property names can be defined in two ways: using literals or using strings. | ||
For example, these two objects are equivalent: | ||
var object1 = { | ||
property: true | ||
}; | ||
var object2 = { | ||
"property": true | ||
}; | ||
In many cases, it doesn’t matter if you choose to use an identifier instead of a string | ||
or vice-versa. Even so, you might decide to enforce a consistent style in your code. | ||
This rules lets you enforce consistent quoting of property names. Either they should always | ||
be quoted (default behavior) or quoted only as needed ("as-needed").`, | ||
optionsDescription: Lint.Utils.dedent` | ||
Possible settings are: | ||
* \`"always"\`: Property names should always be quoted. (This is the default.) | ||
* \`"as-needed"\`: Only property names which require quotes may be quoted (e.g. those with spaces in them). | ||
For ES6, computed property names (\`{[name]: value}\`) and methods (\`{foo() {}}\`) never need | ||
to be quoted.`, | ||
options: { | ||
type: "string", | ||
enum: ["always", "as-needed"], | ||
// TODO: eslint also supports "consistent", "consistent-as-needed" modes. | ||
// TODO: eslint supports "keywords", "unnecessary" and "numbers" options. | ||
}, | ||
optionExamples: ["[true, \"as-needed\"]", "[true, \"always\"]"], | ||
type: "style", | ||
}; | ||
/* tslint:enable:object-literal-sort-keys */ | ||
|
||
public static UNNEEDED_QUOTES = (name: string) => `Unnecessarily quoted property '${name}' found.`; | ||
public static UNQUOTED_PROPERTY = (name: string) => `Unquoted property '${name}' found.`; | ||
|
||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { | ||
const objectLiteralKeyQuotesWalker = new ObjectLiteralKeyQuotesWalker(sourceFile, this.getOptions()); | ||
return this.applyWithWalker(objectLiteralKeyQuotesWalker); | ||
} | ||
} | ||
|
||
// This is simplistic. See https://mothereff.in/js-properties for the gorey details. | ||
const IDENTIFIER_NAME_REGEX = /^(?:[\$A-Z_a-z])*$/; | ||
|
||
const NUMBER_REGEX = /^[0-9]+$/; | ||
|
||
type QuotesMode = "always" | "as-needed"; | ||
|
||
class ObjectLiteralKeyQuotesWalker extends Lint.RuleWalker { | ||
private mode: QuotesMode; | ||
|
||
constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) { | ||
super(sourceFile, options); | ||
|
||
this.mode = this.getOptions()[0] || "always"; | ||
} | ||
|
||
public visitPropertyAssignment(node: ts.PropertyAssignment) { | ||
const name = node.name; | ||
if (this.mode === "always") { | ||
if (name.kind !== ts.SyntaxKind.StringLiteral && | ||
name.kind !== ts.SyntaxKind.ComputedPropertyName) { | ||
this.addFailure(this.createFailure(name.getStart(), name.getWidth(), | ||
Rule.UNQUOTED_PROPERTY(name.getText()))); | ||
} | ||
} else if (this.mode === "as-needed") { | ||
if (name.kind === ts.SyntaxKind.StringLiteral) { | ||
// Check if the quoting is necessary. | ||
const stringNode = name as ts.StringLiteral; | ||
const property = stringNode.text; | ||
|
||
const isIdentifier = IDENTIFIER_NAME_REGEX.test(property); | ||
const isNumber = NUMBER_REGEX.test(property); | ||
if (isIdentifier || (isNumber && Number(property).toString() === property)) { | ||
this.addFailure(this.createFailure(stringNode.getStart(), stringNode.getWidth(), | ||
Rule.UNNEEDED_QUOTES(property))); | ||
} | ||
} | ||
} | ||
|
||
super.visitPropertyAssignment(node); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
const o = { | ||
'hello': 123, | ||
goodbye: 234, // failure | ||
~~~~~~~ [Unquoted property 'goodbye' found.] | ||
"quote": 345, | ||
"needs quote": 789, | ||
"hyphens-need-quotes": null, | ||
[computed]: 456, | ||
123: "hello", // failure | ||
~~~ [Unquoted property '123' found.] | ||
1e4: "something", // failure | ||
~~~ [Unquoted property '1e4' found.] | ||
.123: "float", // failure | ||
~~~~ [Unquoted property '.123' found.] | ||
'123': 'numbers do not need quotes', | ||
'010': 'but this one does.', | ||
'.123': 'as does this one', | ||
fn() { return }, | ||
true: 0, // failure | ||
~~~~ [Unquoted property 'true' found.] | ||
"0x0": 0, | ||
"true": 0, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"rules": { | ||
"object-literal-key-quotes": [true, "always"] | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
test/rules/object-literal-key-quotes/as-needed/test.ts.lint
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
const o = { | ||
'hello': 123, // failure | ||
~~~~~~~ [Unnecessarily quoted property 'hello' found.] | ||
goodbye: 234, | ||
"quote": 345, // failure | ||
~~~~~~~ [Unnecessarily quoted property 'quote' found.] | ||
"needs quote": 789, | ||
"hyphens-need-quotes": null, | ||
[computed]: 456, | ||
123: "hello", | ||
1e4: "something", | ||
.123: "float", | ||
'123': 'numbers do not need quotes', // failure | ||
~~~~~ [Unnecessarily quoted property '123' found.] | ||
'010': 'but this one does.', | ||
'.123': 'as does this one', | ||
fn() { return }, | ||
true: 0, | ||
"0x0": 0, | ||
"true": 0, // failure | ||
~~~~~~ [Unnecessarily quoted property 'true' found.] | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"rules": { | ||
"object-literal-key-quotes": [true, "as-needed"] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters