Skip to content
This repository was archived by the owner on Mar 23, 2024. It is now read-only.

Commit a195c2e

Browse files
fxmaxvlmarkelog
authored andcommitted
New rule: requireSpaceBeforeDestructuredValue
Require space after colon in object destructuring Valid: const { String: EmberString } = Ember; Invalid: const { String:EmberString } = Ember; Fixes #2074 Closes gh-2142
1 parent 378c7df commit a195c2e

File tree

4 files changed

+222
-1
lines changed

4 files changed

+222
-1
lines changed

grouping.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@
162162
"requireObjectDestructuring",
163163
"requireEnhancedObjectLiterals",
164164
"requireArrayDestructuring",
165-
"disallowVar"
165+
"disallowVar",
166+
"requireSpaceBeforeDestructuredValues"
166167
],
167168
"Everything else": [
168169
"requireParenthesesAroundIIFE",

lib/config/configuration.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,7 @@ Configuration.prototype.registerDefaultRules = function() {
958958
this.registerRule(require('../rules/require-array-destructuring'));
959959
this.registerRule(require('../rules/disallow-var'));
960960
this.registerRule(require('../rules/require-imports-alphabetized'));
961+
this.registerRule(require('../rules/require-space-before-destructured-values'));
961962
/* ES6 only (end) */
962963

963964
this.registerRule(require('../rules/require-curly-braces'));
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/**
2+
* Require space after colon in object destructuring.
3+
*
4+
* Type: `Boolean`
5+
*
6+
* Value: `true`
7+
*
8+
* Version: `ES6`
9+
*
10+
* #### Example
11+
*
12+
* ```js
13+
* "requireSpaceBeforeDestructuredValues": true
14+
* ```
15+
*
16+
* ##### Valid
17+
* ```js
18+
* const { foo: objectsFoo } = SomeObject;
19+
* ```
20+
* ##### Invalid
21+
* ```js
22+
* const { foo:objectsFoo } = SomeObject;
23+
* ```
24+
*
25+
* ##### Valid
26+
* ```js
27+
* const { [ { foo: objectsFoo } ] } = SomeObject;
28+
* ```
29+
* ##### Invalid
30+
* ```js
31+
* const { [ { foo:objectsFoo } ] } = SomeObject;
32+
* ```
33+
*/
34+
35+
var assert = require('assert');
36+
37+
module.exports = function() {};
38+
39+
module.exports.prototype = {
40+
41+
configure: function(options) {
42+
assert(
43+
options === true,
44+
this.getOptionName() + ' option requires a true value or should be removed'
45+
);
46+
},
47+
48+
getOptionName: function() {
49+
return 'requireSpaceBeforeDestructuredValues';
50+
},
51+
52+
check: function(file, errors) {
53+
var checkSpaceMissing = function (propKey) {
54+
var keyToken = file.getFirstNodeToken(propKey);
55+
var colon = file.findNextToken(keyToken, 'Punctuator', ':');
56+
57+
errors.assert.whitespaceBetween({
58+
token: colon,
59+
nextToken: file.getNextToken(colon),
60+
message: 'Missing space after key colon'
61+
});
62+
};
63+
64+
var letsCheckThisOne = function(item) {
65+
66+
if (!item) {
67+
return;
68+
}
69+
70+
if (item.type === 'ObjectPattern') {
71+
item.properties.forEach(function(property) {
72+
73+
if (property.shorthand || property.method || property.kind !== 'init') {
74+
return;
75+
}
76+
77+
checkSpaceMissing(property.key);
78+
79+
//Strategy for nested structures
80+
var propValue = property.value;
81+
82+
if (!propValue) {
83+
return;
84+
}
85+
86+
letsCheckThisOne(propValue);
87+
});
88+
}
89+
90+
if (item.type === 'ArrayPattern') {
91+
item.elements.forEach(letsCheckThisOne);
92+
}
93+
};
94+
95+
file.iterateNodesByType(['VariableDeclaration', 'AssignmentExpression'], function(node) {
96+
97+
if (node.type === 'VariableDeclaration') {
98+
node.declarations.forEach(function(declaration) {
99+
letsCheckThisOne(declaration.id || {});
100+
});
101+
}
102+
103+
if (node.type === 'AssignmentExpression') {
104+
var left = node.left;
105+
106+
if (left) {
107+
letsCheckThisOne(left);
108+
}
109+
}
110+
});
111+
}
112+
};
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
var Checker = require('../../../lib/checker');
2+
var expect = require('chai').expect;
3+
4+
describe('rules/require-space-before-destructured-values', function() {
5+
var checker;
6+
var rules = { requireSpaceBeforeDestructuredValues: true };
7+
8+
beforeEach(function() {
9+
checker = new Checker();
10+
checker.registerDefaultRules();
11+
checker.configure(rules);
12+
});
13+
14+
it('should report with no space after keys colons in plain objects', function() {
15+
expect(checker.checkString('var { foo:objFoo, bar: objBar } = SomeThing;'))
16+
.to.have.one.validation.error.from('requireSpaceBeforeDestructuredValues');
17+
18+
expect(checker.checkString('var { foo:objFoo, bar:objBar } = SomeThing;'))
19+
.to.have.error.count.eq(2);
20+
});
21+
22+
it('should report with no space after keys colons in nested arrays', function() {
23+
expect(checker.checkString('var { a:[{b: objB}] } = obj;'))
24+
.to.have.one.validation.error.from('requireSpaceBeforeDestructuredValues');
25+
26+
expect(checker.checkString('var { a: [{b:objB}] } = obj;'))
27+
.to.have.one.validation.error.from('requireSpaceBeforeDestructuredValues');
28+
29+
expect(checker.checkString('var { a: [ {b: objB}, {c: [ {d:objD}] } ] } = obj;'))
30+
.to.have.one.validation.error.from('requireSpaceBeforeDestructuredValues');
31+
});
32+
33+
it('should report with no space after keys colons in nested objects', function() {
34+
expect(checker.checkString('var { a: {b:objB} } = obj;'))
35+
.to.have.one.validation.error.from('requireSpaceBeforeDestructuredValues');
36+
37+
expect(checker.checkString('var { a: {b: objB, c: {d:objD} } } = obj;'))
38+
.to.have.one.validation.error.from('requireSpaceBeforeDestructuredValues');
39+
40+
expect(checker.checkString('var { a:{b: objB, c:{d:objD} } } = obj;'))
41+
.to.have.error.count.eq(3);
42+
});
43+
44+
it('should report with no space after keys colons in nested objects and arrays', function() {
45+
expect(checker.checkString('var { a: {b:objB}, c: [ {d:objD} ] } = obj;'))
46+
.to.have.error.count.eq(2);
47+
48+
expect(checker.checkString('var { a: { b: [ { c: { d: [ {e:objE} ] } } ] } } = obj;'))
49+
.to.have.one.validation.error.from('requireSpaceBeforeDestructuredValues');
50+
});
51+
52+
it('should report mixed shorthand and normal object destructured values', function() {
53+
expect(checker.checkString('var { a, b:objB } = obj;'))
54+
.to.have.one.validation.error.from('requireSpaceBeforeDestructuredValues');
55+
});
56+
57+
it('should not report with end of line after keys colons', function() {
58+
expect(checker.checkString(
59+
'var {\n' +
60+
' a:\n' +
61+
' objA\n' +
62+
'} = obj;'
63+
)).to.have.no.errors();
64+
});
65+
66+
it(
67+
'should report in assignment expressions',
68+
function() {
69+
expect(checker.checkString(
70+
'({a:asdf, b: asdf2} = {a:1, b:2});'
71+
)).to.have.error.count.eq(1);
72+
73+
expect(checker.checkString(
74+
'fn({a:asdf, b:asdf2} = obj);'
75+
)).to.have.error.count.eq(2);
76+
77+
expect(checker.checkString(
78+
'({a:a1, b:b1} = {a:a2, b:b2} = {a:1, b:1});'
79+
)).to.have.error.count.eq(4);
80+
81+
expect(checker.checkString(
82+
'([{a:asdf, b:asdf2}] = [{a:1, b:1}]);'
83+
)).to.have.error.count.eq(2);
84+
85+
expect(checker.checkString(
86+
'([{a:a1, b:b1}, {c:{d:[{e:e1}]}}] = obj);'
87+
)).to.have.error.count.eq(5);
88+
}
89+
);
90+
91+
it(
92+
'should report in multiline assignment expressions',
93+
function() {
94+
expect(checker.checkString(
95+
'({\n' +
96+
'a:asdf, b:asdf2\n' +
97+
'} = {a:1, b:2});'
98+
)).to.have.error.count.eq(2);
99+
}
100+
);
101+
102+
it('should not report with Identifiers', function() {
103+
expect(checker.checkString(
104+
'(a = {a:asdf, b:asdf2});'
105+
)).to.have.no.errors();
106+
});
107+
});

0 commit comments

Comments
 (0)