From 12bbdea4638bb1c542af9bc6a0192e6e9d5c54ee Mon Sep 17 00:00:00 2001 From: Armano Date: Thu, 10 Aug 2017 16:30:05 +0200 Subject: [PATCH 1/3] Fix exceptions in iterateFunctionExpression and iterateProperties: - Cannot read property 'type' of null --- lib/utils/index.js | 4 +++- tests/lib/rules/no-dupe-keys.js | 10 +++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/utils/index.js b/lib/utils/index.js index b2a5bacbf..9c7678c92 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -480,6 +480,8 @@ module.exports = { const nodes = node.properties.filter(p => p.type === 'Property' && groups.has(this.getStaticPropertyName(p.key))) for (const item of nodes) { const name = this.getStaticPropertyName(item.key) + if (!name) continue + if (item.value.type === 'ArrayExpression') { yield * this.iterateArrayExpression(item.value, name) } else if (item.value.type === 'ObjectExpression') { @@ -531,7 +533,7 @@ module.exports = { assert(node.type === 'FunctionExpression') if (node.body.type === 'BlockStatement') { for (const item of node.body.body) { - if (item.type === 'ReturnStatement' && item.argument.type === 'ObjectExpression') { + if (item.type === 'ReturnStatement' && item.argument && item.argument.type === 'ObjectExpression') { yield * this.iterateObjectExpression(item.argument, groupName) } } diff --git a/tests/lib/rules/no-dupe-keys.js b/tests/lib/rules/no-dupe-keys.js index fbb314c90..fb23ff8ab 100644 --- a/tests/lib/rules/no-dupe-keys.js +++ b/tests/lib/rules/no-dupe-keys.js @@ -32,6 +32,9 @@ ruleTester.run('no-dupe-keys', rule, { dat: null } }, + data () { + return + }, methods: { _foo () {}, test () { @@ -68,7 +71,12 @@ ruleTester.run('no-dupe-keys', rule, { ...foo(), test () { } - } + }, + data () { + return { + ...dat + } + }, } `, parserOptions: { ecmaVersion: 8, sourceType: 'module', ecmaFeatures: { experimentalObjectRestSpread: true }} From b397aeb09a868e6a86c47926fae56163f2c720c6 Mon Sep 17 00:00:00 2001 From: Armano Date: Fri, 11 Aug 2017 22:26:50 +0200 Subject: [PATCH 2/3] Improve support for spread operator --- lib/rules/order-in-components.js | 4 +++- lib/utils/index.js | 1 + tests/lib/rules/name-property-casing.js | 13 +++++++++++- .../rules/no-async-in-computed-properties.js | 1 + tests/lib/rules/no-reservered-keys.js | 8 ++++++- tests/lib/rules/no-shared-component-data.js | 18 ++++++++++++++++ .../no-side-effects-in-computed-properties.js | 1 + tests/lib/rules/order-in-components.js | 21 ++++++++++++------- tests/lib/rules/require-prop-types.js | 1 + tests/lib/rules/require-render-return.js | 1 + tests/lib/rules/require-valid-default-prop.js | 10 ++++++++- 11 files changed, 68 insertions(+), 11 deletions(-) diff --git a/lib/rules/order-in-components.js b/lib/rules/order-in-components.js index d35d6458a..e6a131f7c 100644 --- a/lib/rules/order-in-components.js +++ b/lib/rules/order-in-components.js @@ -53,7 +53,9 @@ function getOrderMap (order) { } function checkOrder (propertiesNodes, orderMap, context) { - const properties = propertiesNodes.map(property => property.key) + const properties = propertiesNodes + .filter(property => property.type === 'Property') + .map(property => property.key) properties.forEach((property, i) => { const propertiesAbove = properties.slice(0, i) diff --git a/lib/utils/index.js b/lib/utils/index.js index 9c7678c92..e40c0935e 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -323,6 +323,7 @@ module.exports = { getComputedProperties (componentObject) { const computedPropertiesNode = componentObject.properties .find(p => + p.type === 'Property' && p.key.type === 'Identifier' && p.key.name === 'computed' && p.value.type === 'ObjectExpression' diff --git a/tests/lib/rules/name-property-casing.js b/tests/lib/rules/name-property-casing.js index 88ede6d6d..3c09f23f0 100644 --- a/tests/lib/rules/name-property-casing.js +++ b/tests/lib/rules/name-property-casing.js @@ -17,7 +17,8 @@ const RuleTester = require('eslint').RuleTester const parserOptions = { ecmaVersion: 6, - sourceType: 'module' + sourceType: 'module', + ecmaFeatures: { experimentalObjectRestSpread: true } } const ruleTester = new RuleTester() @@ -33,6 +34,16 @@ ruleTester.run('name-property-casing', rule, { options: ['camelCase'], parserOptions }, + { + filename: 'test.vue', + code: ` + export default { + ...name + } + `, + options: ['camelCase'], + parserOptions + }, { filename: 'test.vue', code: ` diff --git a/tests/lib/rules/no-async-in-computed-properties.js b/tests/lib/rules/no-async-in-computed-properties.js index 34c57e75f..e7cd02694 100644 --- a/tests/lib/rules/no-async-in-computed-properties.js +++ b/tests/lib/rules/no-async-in-computed-properties.js @@ -36,6 +36,7 @@ ruleTester.run('no-async-in-computed-properties', rule, { filename: 'test.vue', code: ` export default { + ...foo, computed: { ...mapGetters({ test: 'getTest' diff --git a/tests/lib/rules/no-reservered-keys.js b/tests/lib/rules/no-reservered-keys.js index 378a840c2..46744a266 100644 --- a/tests/lib/rules/no-reservered-keys.js +++ b/tests/lib/rules/no-reservered-keys.js @@ -11,6 +11,12 @@ const rule = require('../../../lib/rules/no-reservered-keys') const RuleTester = require('eslint').RuleTester +const parserOptions = { + ecmaVersion: 7, + sourceType: 'module', + ecmaFeatures: { experimentalObjectRestSpread: true } +} + // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ @@ -39,7 +45,7 @@ ruleTester.run('no-reservered-keys', rule, { } } `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' } + parserOptions } ], diff --git a/tests/lib/rules/no-shared-component-data.js b/tests/lib/rules/no-shared-component-data.js index aad6b3049..2a54ad07f 100644 --- a/tests/lib/rules/no-shared-component-data.js +++ b/tests/lib/rules/no-shared-component-data.js @@ -32,6 +32,24 @@ ruleTester.run('no-shared-component-data', rule, { }) ` }, + { + filename: 'test.js', + code: ` + new Vue({ + ...data, + data () { + return { + foo: 'bar' + } + } + }) + `, + parserOptions: { + ecmaVersion: 7, + sourceType: 'module', + ecmaFeatures: { experimentalObjectRestSpread: true } + } + }, { filename: 'test.js', code: ` diff --git a/tests/lib/rules/no-side-effects-in-computed-properties.js b/tests/lib/rules/no-side-effects-in-computed-properties.js index c6f95f15d..a84e6fae8 100644 --- a/tests/lib/rules/no-side-effects-in-computed-properties.js +++ b/tests/lib/rules/no-side-effects-in-computed-properties.js @@ -26,6 +26,7 @@ ruleTester.run('no-side-effects-in-computed-properties', rule, { valid: [ { code: `Vue.component('test', { + ...foo, computed: { ...test0({}), test1() { diff --git a/tests/lib/rules/order-in-components.js b/tests/lib/rules/order-in-components.js index 4470e895a..4886e88bf 100644 --- a/tests/lib/rules/order-in-components.js +++ b/tests/lib/rules/order-in-components.js @@ -9,6 +9,12 @@ const RuleTester = require('eslint').RuleTester const ruleTester = new RuleTester() +const parserOptions = { + ecmaVersion: 6, + sourceType: 'module', + ecmaFeatures: { experimentalObjectRestSpread: true } +} + ruleTester.run('order-in-components', rule, { valid: [ @@ -20,6 +26,7 @@ ruleTester.run('order-in-components', rule, { props: { propA: Number, }, + ...a, data () { return { msg: 'Welcome to Your Vue.js App' @@ -27,21 +34,21 @@ ruleTester.run('order-in-components', rule, { }, } `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' } + parserOptions }, { filename: 'test.vue', code: ` export default {} `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' } + parserOptions }, { filename: 'test.vue', code: ` export default 'example-text' `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' } + parserOptions }, { filename: 'test.jsx', @@ -55,7 +62,7 @@ ruleTester.run('order-in-components', rule, { }, } `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' } + parserOptions }, { filename: 'test.js', @@ -136,7 +143,7 @@ ruleTester.run('order-in-components', rule, { }, } `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + parserOptions, errors: [{ message: 'The "props" property should be above the "data" property on line 4.', line: 9 @@ -268,7 +275,7 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + parserOptions, errors: [{ message: 'The "name" property should be above the "data" property on line 3.', line: 16 @@ -284,7 +291,7 @@ ruleTester.run('order-in-components', rule, { test: 'ok' }; `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + parserOptions, options: [{ order: ['data', 'test', 'name'] }], errors: [{ message: 'The "test" property should be above the "name" property on line 5.', diff --git a/tests/lib/rules/require-prop-types.js b/tests/lib/rules/require-prop-types.js index 835d2552e..f630354c7 100644 --- a/tests/lib/rules/require-prop-types.js +++ b/tests/lib/rules/require-prop-types.js @@ -24,6 +24,7 @@ ruleTester.run('require-prop-types', rule, { filename: 'test.vue', code: ` export default { + ...foo, props: { ...test(), foo: String diff --git a/tests/lib/rules/require-render-return.js b/tests/lib/rules/require-render-return.js index 5aebda6eb..c12910ff7 100644 --- a/tests/lib/rules/require-render-return.js +++ b/tests/lib/rules/require-render-return.js @@ -26,6 +26,7 @@ ruleTester.run('require-render-return', rule, { valid: [ { code: `Vue.component('test', { + ...foo, render() { return {} } diff --git a/tests/lib/rules/require-valid-default-prop.js b/tests/lib/rules/require-valid-default-prop.js index b95fa71ae..de01ed9e0 100644 --- a/tests/lib/rules/require-valid-default-prop.js +++ b/tests/lib/rules/require-valid-default-prop.js @@ -13,7 +13,8 @@ const RuleTester = require('eslint').RuleTester const parserOptions = { ecmaVersion: 6, - sourceType: 'module' + sourceType: 'module', + ecmaFeatures: { experimentalObjectRestSpread: true, jsx: true } } function errorMessage (type) { @@ -32,6 +33,13 @@ const ruleTester = new RuleTester() ruleTester.run('require-valid-default-prop', rule, { valid: [ + { + filename: 'test.vue', + code: `export default { + ...foo + }`, + parserOptions + }, { filename: 'test.vue', code: `export default { From f67ef4b9f4b86f68d7f264edb41521d92c9b7d30 Mon Sep 17 00:00:00 2001 From: Armano Date: Sat, 12 Aug 2017 22:51:56 +0200 Subject: [PATCH 3/3] Add more unit tests to match all possible cases --- tests/lib/rules/html-end-tags.js | 33 ++++++++++--------- tests/lib/rules/require-valid-default-prop.js | 10 +++++- tests/lib/rules/valid-v-for.js | 9 +++++ 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/tests/lib/rules/html-end-tags.js b/tests/lib/rules/html-end-tags.js index e470e62b3..b4d648d56 100644 --- a/tests/lib/rules/html-end-tags.js +++ b/tests/lib/rules/html-end-tags.js @@ -49,21 +49,24 @@ tester.run('html-end-tags', rule, { } ], invalid: [ - // { - // filename: "test.vue", - // code: "", - // errors: ["'
' should not have end tag."], - // }, - // { - // filename: "test.vue", - // code: "", - // errors: ["'' should not have end tag."], - // }, - // { - // filename: "test.vue", - // code: "", - // errors: ["'' should not have end tag."], - // }, + // { + // filename: 'test.vue', + // code: '', + // output: '', + // errors: ["'
' should not have end tag."] + // }, + // { + // filename: 'test.vue', + // code: '', + // output: '', + // errors: ["'' should not have end tag."] + // }, + // { + // filename: 'test.vue', + // code: '', + // output: '', + // errors: ["'' should not have end tag."] + // }, { filename: 'test.vue', code: '', diff --git a/tests/lib/rules/require-valid-default-prop.js b/tests/lib/rules/require-valid-default-prop.js index de01ed9e0..b8794fbfb 100644 --- a/tests/lib/rules/require-valid-default-prop.js +++ b/tests/lib/rules/require-valid-default-prop.js @@ -36,7 +36,8 @@ ruleTester.run('require-valid-default-prop', rule, { { filename: 'test.vue', code: `export default { - ...foo + ...foo, + props: { ...foo } }`, parserOptions }, @@ -73,8 +74,13 @@ ruleTester.run('require-valid-default-prop', rule, { foo: null, foo: Number, foo: [String, Number], + foo: { }, + foo: { type: String }, foo: { type: Number, default: VAR_BAR }, foo: { type: Number, default: 100 }, + foo: { type: Number, default: Number.MAX_VALUE }, + foo: { type: Number, default: Foo.BAR }, + foo: { type: {}, default: '' }, foo: { type: [String, Number], default: '' }, foo: { type: [String, Number], default: 0 }, foo: { type: String, default: '' }, @@ -88,6 +94,8 @@ ruleTester.run('require-valid-default-prop', rule, { foo: { type: Symbol, default () { } }, foo: { type: Array, default () { } }, foo: { type: Symbol, default: Symbol('a') }, + foo: { type: String, default: \`Foo\` }, + foo: { type: Foo, default: Foo('a') }, foo: { type: String, default: \`Foo\` } } })`, diff --git a/tests/lib/rules/valid-v-for.js b/tests/lib/rules/valid-v-for.js index 80da18187..e3da7c5ed 100644 --- a/tests/lib/rules/valid-v-for.js +++ b/tests/lib/rules/valid-v-for.js @@ -78,6 +78,10 @@ tester.run('valid-v-for', rule, { { filename: 'test.vue', code: '' + }, + { + filename: 'test.vue', + code: '' } ], invalid: [ @@ -170,6 +174,11 @@ tester.run('valid-v-for', rule, { filename: 'test.vue', code: '', errors: ["Custom elements in iteration require 'v-bind:key' directives."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-for' directives require that attribute value."] } ] })