diff --git a/lib/rules/prop-name-casing.js b/lib/rules/prop-name-casing.js index f744aee5a..04c2a16eb 100644 --- a/lib/rules/prop-name-casing.js +++ b/lib/rules/prop-name-casing.js @@ -8,6 +8,20 @@ const utils = require('../utils') const casing = require('../utils/casing') const allowedCaseOptions = ['camelCase', 'snake_case'] +function canFixPropertyName (node, originalName) { + // Can not fix of computed property names & shorthand + if (node.computed || node.shorthand) { + return false + } + const key = node.key + // Can not fix of unknown types + if (key.type !== 'Literal' && key.type !== 'Identifier') { + return false + } + // Can fix of ASCII printable characters + return originalName.match(/[ -~]+/) +} + // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ @@ -46,7 +60,12 @@ function create (context) { data: { name: propName, caseType: caseType - } + }, + fix: canFixPropertyName(item, propName) ? fixer => { + return item.key.type === 'Literal' + ? fixer.replaceText(item.key, item.key.raw.replace(item.key.value, convertedName)) + : fixer.replaceText(item.key, convertedName) + } : undefined }) } } @@ -63,7 +82,7 @@ module.exports = { description: 'enforce specific casing for the Prop name in Vue components', category: undefined // 'strongly-recommended' }, - fixable: null, // or "code" or "whitespace" + fixable: 'code', // null or "code" or "whitespace" schema: [ { enum: allowedCaseOptions diff --git a/tests/lib/rules/prop-name-casing.js b/tests/lib/rules/prop-name-casing.js index 3df60c8ba..0c706635d 100644 --- a/tests/lib/rules/prop-name-casing.js +++ b/tests/lib/rules/prop-name-casing.js @@ -121,6 +121,13 @@ ruleTester.run('prop-name-casing', rule, { } } `, + output: ` + export default { + props: { + greetingText: String + } + } + `, parserOptions, errors: [{ message: 'Prop "greeting_text" is not in camelCase.', @@ -138,6 +145,13 @@ ruleTester.run('prop-name-casing', rule, { } `, options: ['camelCase'], + output: ` + export default { + props: { + greetingText: String + } + } + `, parserOptions, errors: [{ message: 'Prop "greeting_text" is not in camelCase.', @@ -155,6 +169,13 @@ ruleTester.run('prop-name-casing', rule, { } `, options: ['snake_case'], + output: ` + export default { + props: { + greeting_text: String + } + } + `, parserOptions, errors: [{ message: 'Prop "greetingText" is not in snake_case.', @@ -172,6 +193,13 @@ ruleTester.run('prop-name-casing', rule, { } `, options: ['camelCase'], + output: ` + export default { + props: { + 'greetingText': String + } + } + `, parserOptions, errors: [{ message: 'Prop "greeting-text" is not in camelCase.', @@ -189,12 +217,156 @@ ruleTester.run('prop-name-casing', rule, { } `, options: ['snake_case'], + output: ` + export default { + props: { + 'greeting_text': String + } + } + `, parserOptions, errors: [{ message: 'Prop "greeting-text" is not in snake_case.', type: 'Property', line: 4 }] + }, + { + filename: 'test.vue', + code: ` + export default { + props: { + 'greeting_text': String + } + } + `, + output: ` + export default { + props: { + 'greetingText': String + } + } + `, + parserOptions, + errors: [{ + message: 'Prop "greeting_text" is not in camelCase.', + type: 'Property', + line: 4 + }] + }, + { + // computed property name + filename: 'test.vue', + code: ` + export default { + props: { + ['greeting-text']: String + } + } + `, + output: null, + parserOptions, + errors: [{ + message: 'Prop "greeting-text" is not in camelCase.', + type: 'Property', + line: 4 + }] + }, + { + // shorthand + filename: 'test.vue', + code: ` + export default { + props: { + greeting_text + } + } + `, + output: null, + parserOptions, + errors: [{ + message: 'Prop "greeting_text" is not in camelCase.', + type: 'Property', + line: 4 + }] + }, + { + // valiable computed property name + filename: 'test.vue', + code: ` + export default { + props: { + [greeting_text]: String + } + } + `, + output: null, + parserOptions, + errors: [{ + // bug ? + message: 'Prop "greeting_text" is not in camelCase.', + type: 'Property', + line: 4 + }] + }, + { + // emoji + filename: 'test.vue', + code: ` + export default { + props: { + '\u{1F37B}': String + } + } + `, + output: null, + parserOptions, + errors: [{ + message: 'Prop "\u{1F37B}" is not in camelCase.', + type: 'Property', + line: 4 + }] + }, + { + // Japanese characters + filename: 'test.vue', + code: ` + export default { + props: { + '漢字': String + } + } + `, + output: null, + parserOptions, + errors: [{ + message: 'Prop "漢字" is not in camelCase.', + type: 'Property', + line: 4 + }] + }, + { + filename: 'test.vue', + code: ` + export default { + props: { + 'abc-123-def': String + } + } + `, + output: ` + export default { + props: { + 'abc123Def': String + } + } + `, + parserOptions, + errors: [{ + message: 'Prop "abc-123-def" is not in camelCase.', + type: 'Property', + line: 4 + }] } ] })