From 237e612fc3ccc105584a602f3d72127dff9a7492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sun, 30 Jul 2017 03:16:43 +0800 Subject: [PATCH 1/5] Update: add autofixing to test-case-property-ordering. (fixes #31) --- lib/rules/test-case-property-ordering.js | 26 ++++++-- .../lib/rules/test-case-property-ordering.js | 65 ++++++++++++++++--- 2 files changed, 75 insertions(+), 16 deletions(-) diff --git a/lib/rules/test-case-property-ordering.js b/lib/rules/test-case-property-ordering.js index 91547352..6bc8a71b 100644 --- a/lib/rules/test-case-property-ordering.js +++ b/lib/rules/test-case-property-ordering.js @@ -18,7 +18,7 @@ module.exports = { category: 'Tests', recommended: false, }, - fixable: null, // or "code" or "whitespace" + fixable: 'code', schema: [{ type: 'array', elements: { type: 'string' }, @@ -31,29 +31,43 @@ module.exports = { // ---------------------------------------------------------------------- const message = 'The properties of a test case should be placed in a consistent order: [{{order}}].'; const order = context.options[0] || ['code', 'output', 'options', 'parserOptions', 'errors']; + const sourceCode = context.getSourceCode(); return { Program (ast) { utils.getTestInfo(context, ast).forEach(testRun => { [testRun.valid, testRun.invalid].forEach(tests => { (tests || []).forEach(test => { - const keys = (test.properties || []).map(utils.getKeyName); + const properties = test.properties || []; + const keyNames = properties.map(utils.getKeyName); - for (let i = 0, lastChecked; i < keys.length; i++) { - const current = order.indexOf(keys[i]); + for (let i = 0, lastChecked; i < keyNames.length; i++) { + const current = order.indexOf(keyNames[i]); // current < lastChecked to catch unordered; // and lastChecked === -1 to catch extra properties before. if (current > -1 && (current < lastChecked || lastChecked === -1)) { - let orderMsg = order.filter(item => keys.indexOf(item) > -1); + let orderMsg = order.filter(item => keyNames.indexOf(item) > -1); orderMsg = orderMsg.concat( - lastChecked === -1 ? keys.filter(item => order.indexOf(item) === -1) : [] + lastChecked === -1 ? keyNames.filter(item => order.indexOf(item) === -1) : [] ); context.report({ node: test.properties[i], message, data: { order: orderMsg.join(', ') }, + fix (fixer) { + // reorder the properties and put in result array. + const result = []; + for (let j = 0; j < keyNames.length; j++) { + const insertedIndex = orderMsg.indexOf(keyNames[j]); + result[insertedIndex] = sourceCode.getText(properties[j]); + } + return fixer.replaceTextRange( + [test.properties[0].range[0], test.properties[test.properties.length - 1].range[1]], + result.join(',\n') + ); + }, }); } lastChecked = current; diff --git a/tests/lib/rules/test-case-property-ordering.js b/tests/lib/rules/test-case-property-ordering.js index 4b414a51..3749be31 100644 --- a/tests/lib/rules/test-case-property-ordering.js +++ b/tests/lib/rules/test-case-property-ordering.js @@ -71,20 +71,38 @@ ruleTester.run('test-case-property-ordering', rule, { ] }); `, + output: ` + new RuleTester().run('foo', bar, { + valid: [ + { + code: "foo",\noutput: "bar",\noptions: ["baz"], + }, + ] + }); + `, errors: [{ message: 'The properties of a test case should be placed in a consistent order: [code, output, options].' }], }, { code: ` - new RuleTester().run('foo', bar, { - valid: [ - { - env: { es6: true }, - code: "foo", - output: "bar", - options: ["baz"], - }, - ] - }); + new RuleTester().run('foo', bar, { + valid: [ + { + env: { es6: true }, + code: "foo", + output: "bar", + options: ["baz"], + }, + ] + }); + `, + output: ` + new RuleTester().run('foo', bar, { + valid: [ + { + code: "foo",\noutput: "bar",\noptions: ["baz"],\nenv: { es6: true }, + }, + ] + }); `, errors: [{ message: 'The properties of a test case should be placed in a consistent order: [code, output, options, env].' }], }, @@ -101,6 +119,15 @@ ruleTester.run('test-case-property-ordering', rule, { ] }); `, + output: ` + new RuleTester().run('foo', bar, { + valid: [ + { + code: "foo",\noutput: "bar",\noptions: ["baz"],\nenv: { es6: true }, + }, + ] + }); + `, errors: [{ message: 'The properties of a test case should be placed in a consistent order: [code, output, options, env].' }], }, { @@ -115,6 +142,15 @@ ruleTester.run('test-case-property-ordering', rule, { ] }); `, + output: ` + new RuleTester().run('foo', bar, { + valid: [ + { + code: "foo",\noptions: ["baz"],\noutput: "bar", + }, + ] + }); + `, options: [['code', 'errors', 'options', 'output', 'parserOptions']], errors: [{ message: 'The properties of a test case should be placed in a consistent order: [code, options, output].' }], }, @@ -132,6 +168,15 @@ ruleTester.run('test-case-property-ordering', rule, { ] }); `, + output: ` + new RuleTester().run('foo', bar, { + valid: [ + { + code: "foo",\nerrors: ["foo"],\noutput: "",\noptions: ["baz"],\nparserOptions: "", + }, + ] + }); + `, options: [['code', 'errors', 'output']], errors: [{ message: 'The properties of a test case should be placed in a consistent order: [code, errors, output, options, parserOptions].' }], }, From 5ee1c389c3f099afd711e1b2948b97dd42f0ee5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sun, 30 Jul 2017 19:21:30 +0100 Subject: [PATCH 2/5] Fix: handle whitespaces. --- lib/rules/test-case-property-ordering.js | 28 ++++++- .../lib/rules/test-case-property-ordering.js | 73 ++++--------------- 2 files changed, 37 insertions(+), 64 deletions(-) diff --git a/lib/rules/test-case-property-ordering.js b/lib/rules/test-case-property-ordering.js index 6bc8a71b..491f2637 100644 --- a/lib/rules/test-case-property-ordering.js +++ b/lib/rules/test-case-property-ordering.js @@ -53,19 +53,39 @@ module.exports = { ); context.report({ - node: test.properties[i], + node: properties[i], message, data: { order: orderMsg.join(', ') }, fix (fixer) { // reorder the properties and put in result array. + const last = properties[properties.length - 1]; const result = []; for (let j = 0; j < keyNames.length; j++) { const insertedIndex = orderMsg.indexOf(keyNames[j]); - result[insertedIndex] = sourceCode.getText(properties[j]); + const propertyCode = sourceCode.getText(properties[j]); + const propertyStart = properties[j].range[1]; + + // last property didn't include trailing comma. + const propertyEnd = j === properties.length - 1 ? + sourceCode.getTokenAfter(last, token => token.value === '}' && token.type === 'Punctuator').range[0] : + properties[j + 1].range[0]; + let trailing = sourceCode.getText().slice(propertyStart, propertyEnd); + + // for last property, should check & add trailling commas. + if (j === properties.length - 1 && sourceCode.getTokenAfter(last).value !== ',') { + trailing = ', ' + trailing; + } + result[insertedIndex] = propertyCode + trailing; } + + const start = properties[0].range[0]; + const end = sourceCode.getTokenAfter(last).value === ',' ? + sourceCode.getTokenAfter(last, token => token.value === '}' && token.type === 'Punctuator').range[0] : + last.range[1]; + return fixer.replaceTextRange( - [test.properties[0].range[0], test.properties[test.properties.length - 1].range[1]], - result.join(',\n') + [start, end], + result.join('') ); }, }); diff --git a/tests/lib/rules/test-case-property-ordering.js b/tests/lib/rules/test-case-property-ordering.js index 3749be31..ceae2873 100644 --- a/tests/lib/rules/test-case-property-ordering.js +++ b/tests/lib/rules/test-case-property-ordering.js @@ -22,23 +22,14 @@ ruleTester.run('test-case-property-ordering', rule, { ` new RuleTester().run('foo', bar, { valid: [ - { - code: "foo", - output: "bar", - options: ["baz"], - }, + { code: "foo", output: "bar", options: ["baz"], }, ] }); `, ` new RuleTester().run('foo', bar, { valid: [ - { - code: "foo", - output: "bar", - options: ["baz"], - env: { es6: true }, - }, + { code: "foo",output: "bar",options: ["baz"],env: { es6: true }, }, ] }); `, @@ -46,11 +37,7 @@ ruleTester.run('test-case-property-ordering', rule, { code: ` new RuleTester().run('foo', bar, { valid: [ - { - code: "foo", - options: ["baz"], - output: "bar", - }, + { code: "foo", options: ["baz"], output: "bar", }, ] }); `, @@ -63,20 +50,14 @@ ruleTester.run('test-case-property-ordering', rule, { code: ` new RuleTester().run('foo', bar, { valid: [ - { - code: "foo", - options: ["baz"], - output: "bar", - }, + { code: "foo", options: ["baz"], output: "bar", }, ] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ - { - code: "foo",\noutput: "bar",\noptions: ["baz"], - }, + { code: "foo", output: "bar", options: ["baz"], }, ] }); `, @@ -86,21 +67,14 @@ ruleTester.run('test-case-property-ordering', rule, { code: ` new RuleTester().run('foo', bar, { valid: [ - { - env: { es6: true }, - code: "foo", - output: "bar", - options: ["baz"], - }, + { env: { es6: true }, code: "foo", output: "bar", options: ["baz"], }, ] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ - { - code: "foo",\noutput: "bar",\noptions: ["baz"],\nenv: { es6: true }, - }, + { code: "foo", output: "bar", options: ["baz"], env: { es6: true }, }, ] }); `, @@ -110,21 +84,14 @@ ruleTester.run('test-case-property-ordering', rule, { code: ` new RuleTester().run('foo', bar, { valid: [ - { - code: "foo", - env: { es6: true }, - output: "bar", - options: ["baz"], - }, + { code: "foo", env: { es6: true }, output: "bar", options: ["baz"], }, ] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ - { - code: "foo",\noutput: "bar",\noptions: ["baz"],\nenv: { es6: true }, - }, + { code: "foo", output: "bar", options: ["baz"], env: { es6: true }, }, ] }); `, @@ -134,20 +101,14 @@ ruleTester.run('test-case-property-ordering', rule, { code: ` new RuleTester().run('foo', bar, { valid: [ - { - code: "foo", - output: "bar", - options: ["baz"], - }, + { code: "foo", output: "bar", options: ["baz"], }, ] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ - { - code: "foo",\noptions: ["baz"],\noutput: "bar", - }, + { code: "foo", options: ["baz"], output: "bar", }, ] }); `, @@ -158,22 +119,14 @@ ruleTester.run('test-case-property-ordering', rule, { code: ` new RuleTester().run('foo', bar, { valid: [ - { - options: ["baz"], - parserOptions: "", - code: "foo", - errors: ["foo"], - output: "", - }, + { options: ["baz"], parserOptions: "", code: "foo", errors: ["foo"], output: "", }, ] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ - { - code: "foo",\nerrors: ["foo"],\noutput: "",\noptions: ["baz"],\nparserOptions: "", - }, + { code: "foo", errors: ["foo"], output: "", options: ["baz"], parserOptions: "", }, ] }); `, From 542d268408a59145bd2ec2e37ec9b7018583a704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Mon, 31 Jul 2017 05:05:09 +0800 Subject: [PATCH 3/5] update. --- lib/rules/test-case-property-ordering.js | 18 +++++++----------- tests/lib/rules/test-case-property-ordering.js | 7 +++---- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/lib/rules/test-case-property-ordering.js b/lib/rules/test-case-property-ordering.js index 491f2637..5130153f 100644 --- a/lib/rules/test-case-property-ordering.js +++ b/lib/rules/test-case-property-ordering.js @@ -57,19 +57,18 @@ module.exports = { message, data: { order: orderMsg.join(', ') }, fix (fixer) { - // reorder the properties and put in result array. + const source = sourceCode.getText(); const last = properties[properties.length - 1]; + // end loc to replace(including whitespaces). + const finalEnd = sourceCode.getTokenAfter(last, token => token.value === '}' && token.type === 'Punctuator').range[0]; + // reorder the properties and put in result array. const result = []; for (let j = 0; j < keyNames.length; j++) { const insertedIndex = orderMsg.indexOf(keyNames[j]); const propertyCode = sourceCode.getText(properties[j]); const propertyStart = properties[j].range[1]; - - // last property didn't include trailing comma. - const propertyEnd = j === properties.length - 1 ? - sourceCode.getTokenAfter(last, token => token.value === '}' && token.type === 'Punctuator').range[0] : - properties[j + 1].range[0]; - let trailing = sourceCode.getText().slice(propertyStart, propertyEnd); + const propertyEnd = j < properties.length - 1 ? properties[j + 1].range[0] : finalEnd; + let trailing = source.slice(propertyStart, propertyEnd); // for last property, should check & add trailling commas. if (j === properties.length - 1 && sourceCode.getTokenAfter(last).value !== ',') { @@ -79,12 +78,9 @@ module.exports = { } const start = properties[0].range[0]; - const end = sourceCode.getTokenAfter(last).value === ',' ? - sourceCode.getTokenAfter(last, token => token.value === '}' && token.type === 'Punctuator').range[0] : - last.range[1]; return fixer.replaceTextRange( - [start, end], + [start, finalEnd], result.join('') ); }, diff --git a/tests/lib/rules/test-case-property-ordering.js b/tests/lib/rules/test-case-property-ordering.js index ceae2873..3efa1a7b 100644 --- a/tests/lib/rules/test-case-property-ordering.js +++ b/tests/lib/rules/test-case-property-ordering.js @@ -119,19 +119,18 @@ ruleTester.run('test-case-property-ordering', rule, { code: ` new RuleTester().run('foo', bar, { valid: [ - { options: ["baz"], parserOptions: "", code: "foo", errors: ["foo"], output: "", }, + {\ncode: "foo",\noutput: "",\nerrors: ["baz"],\nparserOptions: "",\n}, ] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ - { code: "foo", errors: ["foo"], output: "", options: ["baz"], parserOptions: "", }, + {\ncode: "foo",\noutput: "",\nparserOptions: "",\nerrors: ["baz"],\n}, ] }); `, - options: [['code', 'errors', 'output']], - errors: [{ message: 'The properties of a test case should be placed in a consistent order: [code, errors, output, options, parserOptions].' }], + errors: [{ message: 'The properties of a test case should be placed in a consistent order: [code, output, parserOptions, errors].' }], }, ], }); From 8cdb6d5962f798c1c4b85bba1daa1dcd2b6606f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Mon, 31 Jul 2017 00:07:15 +0100 Subject: [PATCH 4/5] Docs: test-case-properties-ordering autofix. --- README.md | 2 +- docs/rules/test-case-property-ordering.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bff41615..20a1a083 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ Name | ✔️ | 🛠 | Description [prefer-placeholders](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/prefer-placeholders.md) | | | Disallows template literals as report messages [report-message-format](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/report-message-format.md) | | | Enforces a consistent format for report messages [require-meta-fixable](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-fixable.md) | ✔️ | | Requires a `meta.fixable` property for fixable rules -[test-case-property-ordering](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/test-case-property-ordering.md) | | | Requires the properties of a test case to be placed in a consistent order. +[test-case-property-ordering](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/test-case-property-ordering.md) | | 🛠 | Requires the properties of a test case to be placed in a consistent order. [test-case-shorthand-strings](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/test-case-shorthand-strings.md) | | 🛠 | Enforces consistent usage of shorthand strings for test cases with no options ## Supported Presets diff --git a/docs/rules/test-case-property-ordering.md b/docs/rules/test-case-property-ordering.md index 9b012e05..7172b6bb 100644 --- a/docs/rules/test-case-property-ordering.md +++ b/docs/rules/test-case-property-ordering.md @@ -1,5 +1,7 @@ # enforce ordering of keys in test cases (test-case-property-ordering) +(fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#fix) automatically fixes problems reported by this rule. + This rule enforces that the properties of RuleTester test cases are arranged in a consistent order. ## Rule Details From 850e5c85593f6273b0313fb4b57897da1e6d669d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Mon, 31 Jul 2017 00:54:51 +0100 Subject: [PATCH 5/5] Update: applying multiple autofixes simultaneously. --- lib/rules/test-case-property-ordering.js | 30 ++++-------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/lib/rules/test-case-property-ordering.js b/lib/rules/test-case-property-ordering.js index 5130153f..ce2092de 100644 --- a/lib/rules/test-case-property-ordering.js +++ b/lib/rules/test-case-property-ordering.js @@ -57,32 +57,10 @@ module.exports = { message, data: { order: orderMsg.join(', ') }, fix (fixer) { - const source = sourceCode.getText(); - const last = properties[properties.length - 1]; - // end loc to replace(including whitespaces). - const finalEnd = sourceCode.getTokenAfter(last, token => token.value === '}' && token.type === 'Punctuator').range[0]; - // reorder the properties and put in result array. - const result = []; - for (let j = 0; j < keyNames.length; j++) { - const insertedIndex = orderMsg.indexOf(keyNames[j]); - const propertyCode = sourceCode.getText(properties[j]); - const propertyStart = properties[j].range[1]; - const propertyEnd = j < properties.length - 1 ? properties[j + 1].range[0] : finalEnd; - let trailing = source.slice(propertyStart, propertyEnd); - - // for last property, should check & add trailling commas. - if (j === properties.length - 1 && sourceCode.getTokenAfter(last).value !== ',') { - trailing = ', ' + trailing; - } - result[insertedIndex] = propertyCode + trailing; - } - - const start = properties[0].range[0]; - - return fixer.replaceTextRange( - [start, finalEnd], - result.join('') - ); + return orderMsg.map((key, index) => { + const propertyToInsert = test.properties[keyNames.indexOf(key)]; + return fixer.replaceText(test.properties[index], sourceCode.getText(propertyToInsert)); + }); }, }); }