diff --git a/CHANGELOG.md b/CHANGELOG.md index b57162789e..026fbbb9c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ### Fixed * configs: avoid legacy config system error ([#3461][] @ljharb) * [`jsx-no-target-blank`]: allow ternaries with literals ([#3464][] @akulsr0) +* [`sort-prop-types`]: restore autofixing ([#2574][] @ROSSROSALES) ### Changed * [Perf] component detection: improve performance by avoiding traversing parents unnecessarily ([#3459][] @golopot) @@ -21,6 +22,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange [#3464]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3464 [#3461]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3461 [#3459]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3459 +[#3452]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3452 [#3449]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3449 [#3424]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3429 [#2848]: https://github.com/jsx-eslint/eslint-plugin-react/pull/2848 diff --git a/docs/rules/sort-prop-types.md b/docs/rules/sort-prop-types.md index 0c0a5da0e1..a23d15c3fc 100644 --- a/docs/rules/sort-prop-types.md +++ b/docs/rules/sort-prop-types.md @@ -2,6 +2,8 @@ 💼 This rule is enabled in the following [configs](https://github.com/jsx-eslint/eslint-plugin-react#shareable-configurations): `all`. +🔧 This rule is automatically fixable using the `--fix` [flag](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) on the command line. + Some developers prefer to sort prop type declarations alphabetically to be able to find necessary declaration easier at the later time. Others feel that it adds complexity and becomes burden to maintain. ## Rule Details diff --git a/lib/rules/sort-prop-types.js b/lib/rules/sort-prop-types.js index 977f246432..d0428e0630 100644 --- a/lib/rules/sort-prop-types.js +++ b/lib/rules/sort-prop-types.js @@ -8,7 +8,7 @@ const variableUtil = require('../util/variable'); const propsUtil = require('../util/props'); const docsUrl = require('../util/docsUrl'); const propWrapperUtil = require('../util/propWrapper'); -// const propTypesSortUtil = require('../util/propTypesSort'); +const propTypesSortUtil = require('../util/propTypesSort'); const report = require('../util/report'); // ------------------------------------------------------------------------------ @@ -29,7 +29,7 @@ module.exports = { recommended: false, url: docsUrl('sort-prop-types'), }, - // fixable: 'code', + fixable: 'code', messages, @@ -106,17 +106,17 @@ module.exports = { return; } - // function fix(fixer) { - // return propTypesSortUtil.fixPropTypesSort( - // fixer, - // context, - // declarations, - // ignoreCase, - // requiredFirst, - // callbacksLast, - // sortShapeProp - // ); - // } + function fix(fixer) { + return propTypesSortUtil.fixPropTypesSort( + fixer, + context, + declarations, + ignoreCase, + requiredFirst, + callbacksLast, + sortShapeProp + ); + } const callbackPropsLastSeen = new WeakSet(); const requiredPropsFirstSeen = new WeakSet(); @@ -150,7 +150,7 @@ module.exports = { requiredPropsFirstSeen.add(curr); report(context, messages.requiredPropsFirst, 'requiredPropsFirst', { node: curr, - // fix + fix, }); } return curr; @@ -168,7 +168,7 @@ module.exports = { callbackPropsLastSeen.add(prev); report(context, messages.callbackPropsLast, 'callbackPropsLast', { node: prev, - // fix + fix, }); } return prev; @@ -180,7 +180,7 @@ module.exports = { propsNotSortedSeen.add(curr); report(context, messages.propsNotSorted, 'propsNotSorted', { node: curr, - // fix + fix, }); } return prev; diff --git a/lib/util/propTypesSort.js b/lib/util/propTypesSort.js index 6b6096f340..cbb5f97e3a 100644 --- a/lib/util/propTypesSort.js +++ b/lib/util/propTypesSort.js @@ -116,9 +116,39 @@ function sorter(a, b, context, ignoreCase, requiredFirst, callbacksLast) { * @param {Boolean=} sortShapeProp whether or not to sort propTypes defined in PropTypes.shape. * @returns {Object|*|{range, text}} the sort order of the two elements. */ +const commentnodeMap = new WeakMap(); // all nodes reference WeakMap for start and end range function fixPropTypesSort(fixer, context, declarations, ignoreCase, requiredFirst, callbacksLast, sortShapeProp) { function sortInSource(allNodes, source) { const originalSource = source; + const sourceCode = context.getSourceCode(); + for (let i = 0; i < allNodes.length; i++) { + const node = allNodes[i]; + let commentAfter = []; + let commentBefore = []; + try { + commentBefore = sourceCode.getCommentsBefore(node); + commentAfter = sourceCode.getCommentsAfter(node); + } catch (e) { /**/ } + if (commentAfter.length === 0 && commentBefore.length === 0) { + commentnodeMap.set(node, { start: node.range[0], end: node.range[1], hasComment: false }); + } else { + const firstCommentBefore = commentBefore[0]; + if (commentBefore.length === 1) { + commentnodeMap.set(node, { start: firstCommentBefore.range[0], end: node.range[1], hasComment: true }); + } + const firstCommentAfter = commentAfter[0]; + if (commentAfter.length === 1) { + commentnodeMap.set(node, { start: node.range[0], end: firstCommentAfter.range[1], hasComment: true }); + } + if (commentBefore.length === 1 && commentAfter.length === 1) { + commentnodeMap.set(node, { + start: firstCommentBefore.range[0], + end: firstCommentAfter.range[1], + hasComment: true, + }); + } + } + } const nodeGroups = allNodes.reduce((acc, curr) => { if (curr.type === 'ExperimentalSpreadProperty' || curr.type === 'SpreadElement') { acc.push([]); @@ -135,7 +165,11 @@ function fixPropTypesSort(fixer, context, declarations, ignoreCase, requiredFirs source = nodes.reduceRight((acc, attr, index) => { const sortedAttr = sortedAttributes[index]; - let sortedAttrText = context.getSourceCode().getText(sortedAttr); + const sourceCodeText = sourceCode.getText(); + let sortedAttrText = sourceCodeText.substring( + commentnodeMap.get(sortedAttr).start, + commentnodeMap.get(sortedAttr).end + ); if (sortShapeProp && isShapeProp(sortedAttr.value)) { const shape = getShapeProperties(sortedAttr.value); if (shape) { @@ -146,7 +180,7 @@ function fixPropTypesSort(fixer, context, declarations, ignoreCase, requiredFirs sortedAttrText = attrSource.slice(sortedAttr.range[0], sortedAttr.range[1]); } } - return `${acc.slice(0, attr.range[0])}${sortedAttrText}${acc.slice(attr.range[1])}`; + return `${acc.slice(0, commentnodeMap.get(attr).start)}${sortedAttrText}${acc.slice(commentnodeMap.get(attr).end)}`; }, source); }); return source; @@ -154,8 +188,8 @@ function fixPropTypesSort(fixer, context, declarations, ignoreCase, requiredFirs const source = sortInSource(declarations, context.getSourceCode().getText()); - const rangeStart = declarations[0].range[0]; - const rangeEnd = declarations[declarations.length - 1].range[1]; + const rangeStart = commentnodeMap.get(declarations[0]).start; + const rangeEnd = commentnodeMap.get(declarations[declarations.length - 1]).end; return fixer.replaceTextRange([rangeStart, rangeEnd], source.slice(rangeStart, rangeEnd)); } diff --git a/tests/lib/rules/sort-prop-types.js b/tests/lib/rules/sort-prop-types.js index d7fd02a5a6..88905aca20 100644 --- a/tests/lib/rules/sort-prop-types.js +++ b/tests/lib/rules/sort-prop-types.js @@ -10,6 +10,7 @@ const babelEslintVersion = require('babel-eslint/package.json').version; const semver = require('semver'); +const eslintPkg = require('eslint/package.json'); const RuleTester = require('eslint').RuleTester; const rule = require('../../../lib/rules/sort-prop-types'); @@ -468,8 +469,7 @@ ruleTester.run('sort-prop-types', rule, { options: [{ sortShapeProp: true }], } )), - - invalid: parsers.all([ + invalid: parsers.all([].concat( { code: ` var First = createReactClass({ @@ -482,17 +482,17 @@ ruleTester.run('sort-prop-types', rule, { } }); `, - // output: ` - // var First = createReactClass({ - // propTypes: { - // a: PropTypes.any, - // z: PropTypes.string - // }, - // render: function() { - // return
; - // } - // }); - // `, + output: ` + var First = createReactClass({ + propTypes: { + a: PropTypes.any, + z: PropTypes.string + }, + render: function() { + return ; + } + }); + `, errors: [ { messageId: 'propsNotSorted', @@ -502,7 +502,7 @@ ruleTester.run('sort-prop-types', rule, { }, ], }, - { + semver.satisfies(eslintPkg.version, '> 3') ? { code: ` var First = createReactClass({ propTypes: { @@ -516,20 +516,19 @@ ruleTester.run('sort-prop-types', rule, { } }); `, - // Disabled test for comments -- fails - // output: ` - // var First = createReactClass({ - // propTypes: { - // /* a */ - // a: PropTypes.any, - // /* z */ - // z: PropTypes.string - // }, - // render: function() { - // return ; - // } - // }); - // `, + output: ` + var First = createReactClass({ + propTypes: { + /* a */ + a: PropTypes.any, + /* z */ + z: PropTypes.string + }, + render: function() { + return ; + } + }); + `, errors: [ { messageId: 'propsNotSorted', @@ -538,7 +537,7 @@ ruleTester.run('sort-prop-types', rule, { type: 'Property', }, ], - }, + } : [], { code: ` var First = createReactClass({ @@ -551,17 +550,17 @@ ruleTester.run('sort-prop-types', rule, { } }); `, - // output: ` - // var First = createReactClass({ - // propTypes: { - // Z: PropTypes.any, - // z: PropTypes.any - // }, - // render: function() { - // return ; - // } - // }); - // `, + output: ` + var First = createReactClass({ + propTypes: { + Z: PropTypes.any, + z: PropTypes.any + }, + render: function() { + return ; + } + }); + `, errors: [ { messageId: 'propsNotSorted', @@ -583,17 +582,17 @@ ruleTester.run('sort-prop-types', rule, { } }); `, - // output: ` - // var First = createReactClass({ - // propTypes: { - // a: PropTypes.any, - // Z: PropTypes.any - // }, - // render: function() { - // return ; - // } - // }); - // `, + output: ` + var First = createReactClass({ + propTypes: { + a: PropTypes.any, + Z: PropTypes.any + }, + render: function() { + return ; + } + }); + `, options: [{ ignoreCase: true }], errors: [ { @@ -618,19 +617,19 @@ ruleTester.run('sort-prop-types', rule, { } }); `, - // output: ` - // var First = createReactClass({ - // propTypes: { - // A: PropTypes.any, - // Z: PropTypes.string, - // a: PropTypes.any, - // z: PropTypes.string - // }, - // render: function() { - // return ; - // } - // }); - // `, + output: ` + var First = createReactClass({ + propTypes: { + A: PropTypes.any, + Z: PropTypes.string, + a: PropTypes.any, + z: PropTypes.string + }, + render: function() { + return ; + } + }); + `, errors: 2, }, { @@ -654,26 +653,26 @@ ruleTester.run('sort-prop-types', rule, { } }); `, - // output: ` - // var First = createReactClass({ - // propTypes: { - // Zz: PropTypes.string, - // a: PropTypes.any - // }, - // render: function() { - // return ; - // } - // }); - // var Second = createReactClass({ - // propTypes: { - // ZZ: PropTypes.string, - // aAA: PropTypes.any - // }, - // render: function() { - // return ; - // } - // }); - // `, + output: ` + var First = createReactClass({ + propTypes: { + Zz: PropTypes.string, + a: PropTypes.any + }, + render: function() { + return ; + } + }); + var Second = createReactClass({ + propTypes: { + ZZ: PropTypes.string, + aAA: PropTypes.any + }, + render: function() { + return ; + } + }); + `, errors: 2, }, { @@ -697,26 +696,26 @@ ruleTester.run('sort-prop-types', rule, { ZZ: PropTypes.string }; `, - // output: ` - // class First extends React.Component { - // render() { - // return ; - // } - // } - // First.propTypes = { - // bb: PropTypes.string, - // yy: PropTypes.any - // }; - // class Second extends React.Component { - // render() { - // return ; - // } - // } - // Second.propTypes = { - // ZZ: PropTypes.string, - // aAA: PropTypes.any - // }; - // `, + output: ` + class First extends React.Component { + render() { + return ; + } + } + First.propTypes = { + bb: PropTypes.string, + yy: PropTypes.any + }; + class Second extends React.Component { + render() { + return ; + } + } + Second.propTypes = { + ZZ: PropTypes.string, + aAA: PropTypes.any + }; + `, errors: 2, }, { @@ -732,18 +731,18 @@ ruleTester.run('sort-prop-types', rule, { } } `, - // output: ` - // class Component extends React.Component { - // static propTypes = { - // a: PropTypes.any, - // y: PropTypes.any, - // z: PropTypes.any - // }; - // render() { - // return ; - // } - // } - // `, + output: ` + class Component extends React.Component { + static propTypes = { + a: PropTypes.any, + y: PropTypes.any, + z: PropTypes.any + }; + render() { + return ; + } + } + `, features: ['class fields'], errors: 2, }, @@ -760,18 +759,18 @@ ruleTester.run('sort-prop-types', rule, { } } `, - // output: ` - // class Component extends React.Component { - // static propTypes = forbidExtraProps({ - // a: PropTypes.any, - // y: PropTypes.any, - // z: PropTypes.any - // }); - // render() { - // return ; - // } - // } - // `, + output: ` + class Component extends React.Component { + static propTypes = forbidExtraProps({ + a: PropTypes.any, + y: PropTypes.any, + z: PropTypes.any + }); + render() { + return ; + } + } + `, features: ['class fields'], settings: { propWrapperFunctions: ['forbidExtraProps'], @@ -792,19 +791,19 @@ ruleTester.run('sort-prop-types', rule, { } }); `, - // output: ` - // var First = createReactClass({ - // propTypes: { - // a: PropTypes.any, - // z: PropTypes.string, - // onBar: PropTypes.func, - // onFoo: PropTypes.func - // }, - // render: function() { - // return ; - // } - // }); - // `, + output: ` + var First = createReactClass({ + propTypes: { + a: PropTypes.any, + z: PropTypes.string, + onBar: PropTypes.func, + onFoo: PropTypes.func + }, + render: function() { + return ; + } + }); + `, options: [{ callbacksLast: true }], errors: [ { @@ -829,19 +828,19 @@ ruleTester.run('sort-prop-types', rule, { } } `, - // output: ` - // class Component extends React.Component { - // static propTypes = { - // a: PropTypes.any, - // z: PropTypes.string, - // onBar: PropTypes.func, - // onFoo: PropTypes.func - // }; - // render() { - // return ; - // } - // } - // `, + output: ` + class Component extends React.Component { + static propTypes = { + a: PropTypes.any, + z: PropTypes.string, + onBar: PropTypes.func, + onFoo: PropTypes.func + }; + render() { + return ; + } + } + `, options: [{ callbacksLast: true }], features: ['class fields'], errors: [ @@ -867,19 +866,19 @@ ruleTester.run('sort-prop-types', rule, { onBar: PropTypes.func }; `, - // output: [ - // class First extends React.Component { - // render() { - // return ; - // } - // } - // First.propTypes = { - // a: PropTypes.any, - // z: PropTypes.string, - // onBar: PropTypes.func, - // onFoo: PropTypes.func - // }; - // `, + output: ` + class First extends React.Component { + render() { + return ; + } + } + First.propTypes = { + a: PropTypes.any, + z: PropTypes.string, + onBar: PropTypes.func, + onFoo: PropTypes.func + }; + `, options: [{ callbacksLast: true }], errors: [ { @@ -904,19 +903,19 @@ ruleTester.run('sort-prop-types', rule, { onBar: PropTypes.func }); `, - // output: ` - // class First extends React.Component { - // render() { - // return ; - // } - // } - // First.propTypes = forbidExtraProps({ - // a: PropTypes.any, - // z: PropTypes.string, - // onBar: PropTypes.func, - // onFoo: PropTypes.func - // }); - // `, + output: ` + class First extends React.Component { + render() { + return ; + } + } + First.propTypes = forbidExtraProps({ + a: PropTypes.any, + z: PropTypes.string, + onBar: PropTypes.func, + onFoo: PropTypes.func + }); + `, options: [{ callbacksLast: true }], settings: { propWrapperFunctions: ['forbidExtraProps'], @@ -939,15 +938,14 @@ ruleTester.run('sort-prop-types', rule, { }; First.propTypes = forbidExtraProps(propTypes); `, - - // output: ` - // const First = (props) => ; - // const propTypes = { - // a: PropTypes.any, - // z: PropTypes.string, - // }; - // First.propTypes = forbidExtraProps(propTypes) - // `, + output: ` + const First = (props) => ; + const propTypes = { + a: PropTypes.any, + z: PropTypes.string, + }; + First.propTypes = forbidExtraProps(propTypes); + `, settings: { propWrapperFunctions: ['forbidExtraProps'], }, @@ -969,15 +967,14 @@ ruleTester.run('sort-prop-types', rule, { }; First.propTypes = propTypes; `, - - // output: ` - // const First = (props) => ; - // const propTypes = { - // a: PropTypes.any, - // z: PropTypes.string, - // }; - // First.propTypes = propTypes; - // `, + output: ` + const First = (props) => ; + const propTypes = { + a: PropTypes.any, + z: PropTypes.string, + }; + First.propTypes = propTypes; + `, settings: { propWrapperFunctions: ['forbidExtraProps'], }, @@ -1004,19 +1001,19 @@ ruleTester.run('sort-prop-types', rule, { } }); `, - // output: ` - // var First = createReactClass({ - // propTypes: { - // a: PropTypes.any, - // z: PropTypes.string, - // onBar: PropTypes.func, - // onFoo: PropTypes.func - // }, - // render: function() { - // return ; - // } - // }); - // ` + output: ` + var First = createReactClass({ + propTypes: { + a: PropTypes.any, + z: PropTypes.string, + onBar: PropTypes.func, + onFoo: PropTypes.func + }, + render: function() { + return ; + } + }); + `, options: [{ callbacksLast: true }], errors: [ { @@ -1040,18 +1037,18 @@ ruleTester.run('sort-prop-types', rule, { } }); `, - // output: ` - // var First = createReactClass({ - // propTypes: { - // barRequired: PropTypes.string.isRequired, - // fooRequired: PropTypes.string.isRequired, - // a: PropTypes.any - // }, - // render: function() { - // return ; - // } - // }); - // `, + output: ` + var First = createReactClass({ + propTypes: { + barRequired: PropTypes.string.isRequired, + fooRequired: PropTypes.string.isRequired, + a: PropTypes.any + }, + render: function() { + return ; + } + }); + `, options: [{ requiredFirst: true }], errors: [ { @@ -1075,18 +1072,18 @@ ruleTester.run('sort-prop-types', rule, { } }); `, - // output: ` - // var First = createReactClass({ - // propTypes: { - // barRequired: PropTypes.string.isRequired, - // a: PropTypes.any, - // onFoo: PropTypes.func - // }, - // render: function() { - // return ; - // } - // }); - // ` + output: ` + var First = createReactClass({ + propTypes: { + barRequired: PropTypes.string.isRequired, + a: PropTypes.any, + onFoo: PropTypes.func + }, + render: function() { + return ; + } + }); + `, options: [{ requiredFirst: true }], errors: [ { @@ -1108,16 +1105,16 @@ ruleTester.run('sort-prop-types', rule, { } } `, - // output: ` - // export default class ClassWithSpreadInPropTypes extends BaseClass { - // static propTypes = { - // b: PropTypes.string, - // ...a.propTypes, - // c: PropTypes.string, - // d: PropTypes.string - // } - // } - // `, + output: ` + export default class ClassWithSpreadInPropTypes extends BaseClass { + static propTypes = { + b: PropTypes.string, + ...a.propTypes, + c: PropTypes.string, + d: PropTypes.string + } + } + `, features: ['class fields'], errors: [ { @@ -1141,18 +1138,18 @@ ruleTester.run('sort-prop-types', rule, { } } `, - // output: ` - // export default class ClassWithSpreadInPropTypes extends BaseClass { - // static propTypes = { - // b: PropTypes.string, - // ...a.propTypes, - // d: PropTypes.string, - // f: PropTypes.string, - // ...e.propTypes, - // c: PropTypes.string - // } - // } - // ` + output: ` + export default class ClassWithSpreadInPropTypes extends BaseClass { + static propTypes = { + b: PropTypes.string, + ...a.propTypes, + d: PropTypes.string, + f: PropTypes.string, + ...e.propTypes, + c: PropTypes.string + } + } + `, features: ['class fields'], errors: [ { @@ -1174,16 +1171,16 @@ ruleTester.run('sort-prop-types', rule, { }; TextFieldLabel.propTypes = propTypes; `, - // output: ` - // const propTypes = { - // a: PropTypes.string, - // b: PropTypes.string, - // }; - // const TextFieldLabel = (props) => { - // return ; - // }; - // TextFieldLabel.propTypes = propTypes; - // `, + output: ` + const propTypes = { + a: PropTypes.string, + b: PropTypes.string, + }; + const TextFieldLabel = (props) => { + return ; + }; + TextFieldLabel.propTypes = propTypes; + `, errors: [ { messageId: 'propsNotSorted', @@ -1210,22 +1207,22 @@ ruleTester.run('sort-prop-types', rule, { }), }; `, - // output: ` - // class Component extends React.Component { - // render() { - // return ; - // } - // } - // Component.propTypes = { - // x: PropTypes.any, - // y: PropTypes.any, - // z: PropTypes.shape({ - // a: PropTypes.any, - // b: PropTypes.bool, - // c: PropTypes.any, - // }), - // }; - // ` + output: ` + class Component extends React.Component { + render() { + return ; + } + } + Component.propTypes = { + x: PropTypes.any, + y: PropTypes.any, + z: PropTypes.shape({ + a: PropTypes.any, + b: PropTypes.bool, + c: PropTypes.any, + }), + }; + `, options: [{ sortShapeProp: true }], errors: [ { @@ -1255,23 +1252,23 @@ ruleTester.run('sort-prop-types', rule, { y: PropTypes.any, }; `, - // output: ` - // class Component extends React.Component { - // render() { - // return ; - // } - // } - // Component.propTypes = { - // x: PropTypes.any, - // y: PropTypes.any, - // z: PropTypes.shape(), - // }; - // `, - options: [{ sortShapeProp: true }], - errors: [ - { - messageId: 'propsNotSorted', - line: 10, + output: ` + class Component extends React.Component { + render() { + return ; + } + } + Component.propTypes = { + x: PropTypes.any, + y: PropTypes.any, + z: PropTypes.shape(), + }; + `, + options: [{ sortShapeProp: true }], + errors: [ + { + messageId: 'propsNotSorted', + line: 10, column: 11, type: 'Property', }, @@ -1290,18 +1287,18 @@ ruleTester.run('sort-prop-types', rule, { y: PropTypes.any, }; `, - // output: ` - // class Component extends React.Component { - // render() { - // return ; - // } - // } - // Component.propTypes = { - // x: PropTypes.any, - // y: PropTypes.any, - // z: PropTypes.shape(someType), - // }; - // `, + output: ` + class Component extends React.Component { + render() { + return ; + } + } + Component.propTypes = { + x: PropTypes.any, + y: PropTypes.any, + z: PropTypes.shape(someType), + }; + `, options: [{ sortShapeProp: true }], errors: [ { @@ -1330,23 +1327,23 @@ ruleTester.run('sort-prop-types', rule, { }), }; `, - // output: ` - // class Component extends React.Component { - // render() { - // return ; - // } - // } - // Component.propTypes = { - // a: PropTypes.shape({ - // C: PropTypes.string, - // a: PropTypes.any, - // b: PropTypes.bool, - // c: PropTypes.any, - // }), - // y: PropTypes.any, - // z: PropTypes.any, - // }; - // `, + output: ` + class Component extends React.Component { + render() { + return ; + } + } + Component.propTypes = { + a: PropTypes.shape({ + C: PropTypes.string, + a: PropTypes.any, + b: PropTypes.bool, + c: PropTypes.any, + }), + y: PropTypes.any, + z: PropTypes.any, + }; + `, options: [{ sortShapeProp: true }], errors: [ { @@ -1399,23 +1396,23 @@ ruleTester.run('sort-prop-types', rule, { }), }; `, - // output: ` - // class Component extends React.Component { - // render() { - // return ; - // } - // } - // Component.propTypes = { - // x: PropTypes.any, - // y: PropTypes.any, - // z: PropTypes.shape({ - // a: PropTypes.any, - // b: PropTypes.bool, - // c: PropTypes.any, - // C: PropTypes.string, - // }), - // }; - // `, + output: ` + class Component extends React.Component { + render() { + return ; + } + } + Component.propTypes = { + x: PropTypes.any, + y: PropTypes.any, + z: PropTypes.shape({ + a: PropTypes.any, + b: PropTypes.bool, + c: PropTypes.any, + C: PropTypes.string, + }), + }; + `, options: [ { sortShapeProp: true, @@ -1455,23 +1452,23 @@ ruleTester.run('sort-prop-types', rule, { }), }; `, - // output: ` - // class Component extends React.Component { - // render() { - // return ; - // } - // } - // Component.propTypes = { - // x: PropTypes.any, - // y: PropTypes.any, - // z: PropTypes.shape({ - // c: PropTypes.number.isRequired, - // a: PropTypes.string, - // b: PropTypes.any, - // d: PropTypes.bool, - // }), - // }; - // `, + output: ` + class Component extends React.Component { + render() { + return ; + } + } + Component.propTypes = { + x: PropTypes.any, + y: PropTypes.any, + z: PropTypes.shape({ + c: PropTypes.number.isRequired, + a: PropTypes.string, + b: PropTypes.any, + d: PropTypes.bool, + }), + }; + `, options: [ { sortShapeProp: true, @@ -1506,24 +1503,24 @@ ruleTester.run('sort-prop-types', rule, { }), }; `, - // output: ` - // class Component extends React.Component { - // render() { - // return ; - // } - // } - // Component.propTypes = { - // x: PropTypes.any, - // y: PropTypes.any, - // z: PropTypes.shape({ - // a: PropTypes.string, - // b: PropTypes.any, - // c: PropTypes.number.isRequired, - // d: PropTypes.bool, - // onFoo: PropTypes.func, - // }), - // }; - // `, + output: ` + class Component extends React.Component { + render() { + return ; + } + } + Component.propTypes = { + x: PropTypes.any, + y: PropTypes.any, + z: PropTypes.shape({ + a: PropTypes.string, + b: PropTypes.any, + c: PropTypes.number.isRequired, + d: PropTypes.bool, + onFoo: PropTypes.func, + }), + }; + `, options: [ { sortShapeProp: true, @@ -1565,25 +1562,25 @@ ruleTester.run('sort-prop-types', rule, { }), }; `, - // output: ` - // class Component extends React.Component { - // render() { - // return ; - // } - // } - // Component.propTypes = { - // x: PropTypes.any, - // y: PropTypes.any, - // z: PropTypes.shape({ - // a: PropTypes.string, - // b: PropTypes.any, - // c: PropTypes.number.isRequired, - // ...otherPropTypes, - // d: PropTypes.string, - // f: PropTypes.bool, - // }), - // }; - // `, + output: ` + class Component extends React.Component { + render() { + return ; + } + } + Component.propTypes = { + x: PropTypes.any, + y: PropTypes.any, + z: PropTypes.shape({ + a: PropTypes.string, + b: PropTypes.any, + c: PropTypes.number.isRequired, + ...otherPropTypes, + d: PropTypes.string, + f: PropTypes.bool, + }), + }; + `, options: [{ sortShapeProp: true }], errors: [ { @@ -1617,22 +1614,22 @@ ruleTester.run('sort-prop-types', rule, { } } `, - // output: ` - // class Component extends React.Component { - // static propTypes = { - // a: PropTypes.shape({ - // a: PropTypes.any, - // b: PropTypes.bool, - // c: PropTypes.any, - // }), - // y: PropTypes.any, - // z: PropTypes.any, - // }; - // render() { - // return ; - // } - // } - // `, + output: ` + class Component extends React.Component { + static propTypes = { + a: PropTypes.shape({ + a: PropTypes.any, + b: PropTypes.bool, + c: PropTypes.any, + }), + y: PropTypes.any, + z: PropTypes.any, + }; + render() { + return ; + } + } + `, options: [{ sortShapeProp: true }], features: ['class fields', 'no-ts-old'], // TODO: FIXME: remove no-ts-old and fix errors: [ @@ -1674,17 +1671,17 @@ ruleTester.run('sort-prop-types', rule, { } }); `, - // output: ` - // var First = createReactClass({ - // propTypes: { - // a: PropTypes.any, - // z: PropTypes.string - // }, - // render: function() { - // return ; - // } - // }); - // `, + output: ` + var First = createReactClass({ + propTypes: { + a: PropTypes.any, + z: PropTypes.string + }, + render: function() { + return ; + } + }); + `, options: [{ noSortAlphabetically: false }], errors: [ { @@ -1708,18 +1705,18 @@ ruleTester.run('sort-prop-types', rule, { } }); `, - // output: ` - // var First = createReactClass({ - // propTypes: { - // a: PropTypes.any, - // 'data-letter': PropTypes.string, - // e: PropTypes.any - // }, - // render: function() { - // return ; - // } - // }); - // `, + output: ` + var First = createReactClass({ + propTypes: { + a: PropTypes.any, + 'data-letter': PropTypes.string, + e: PropTypes.any + }, + render: function() { + return ; + } + }); + `, options: [{ noSortAlphabetically: false }], errors: [ { @@ -1742,17 +1739,17 @@ ruleTester.run('sort-prop-types', rule, { 0: PropTypes.any, }; `, - // output: ` - // class Component extends React.Component { - // render() { - // return ; - // } - // } - // Component.propTypes = { - // 0: PropTypes.any, - // 1: PropTypes.any, - // }; - // `, + output: ` + class Component extends React.Component { + render() { + return ; + } + } + Component.propTypes = { + 0: PropTypes.any, + 1: PropTypes.any, + }; + `, options: [{ ignoreCase: true }], errors: [ { @@ -1780,22 +1777,22 @@ ruleTester.run('sort-prop-types', rule, { } } `, - // output: ` - // const shape = { - // a: PropTypes.any, - // b: PropTypes.bool, - // c: PropTypes.any, - // }; - // class Component extends React.Component { - // static propTypes = { - // x: PropTypes.shape(shape), - // }; + output: ` + const shape = { + a: PropTypes.any, + b: PropTypes.bool, + c: PropTypes.any, + }; + class Component extends React.Component { + static propTypes = { + x: PropTypes.shape(shape), + }; - // render() { - // return ; - // } - // } - // `, + render() { + return ; + } + } + `, options: [{ sortShapeProp: true }], features: ['class fields', 'no-ts-old'], // TODO: FIXME: remove no-ts-old and fix errors: [ @@ -1829,21 +1826,21 @@ ruleTester.run('sort-prop-types', rule, { x: PropTypes.shape(shape) }; `, - // output: ` - // const shape = { - // a: PropTypes.any, - // b: PropTypes.bool, - // c: PropTypes.any, - // }; - // class Component extends React.Component { - // render() { - // return ; - // } - // } - // Component.propTypes = { - // x: PropTypes.shape(shape) - // }; - // `, + output: ` + const shape = { + a: PropTypes.any, + b: PropTypes.bool, + c: PropTypes.any, + }; + class Component extends React.Component { + render() { + return ; + } + } + Component.propTypes = { + x: PropTypes.shape(shape) + }; + `, options: [{ sortShapeProp: true }], errors: [ { @@ -1871,6 +1868,16 @@ ruleTester.run('sort-prop-types', rule, { } }); `, + output: ` + var Component = React.createClass({ + propTypes: { + a: React.PropTypes.string, + b: React.PropTypes.string, + c: React.PropTypes.string, + onChange: React.PropTypes.func, + } + }); + `, options: [{ callbacksLast: true }], errors: [ { @@ -1879,5 +1886,218 @@ ruleTester.run('sort-prop-types', rule, { }, ], }, - ]), + semver.satisfies(eslintPkg.version, '> 3') ? { + code: ` + var First = createReactClass({ + propTypes: { + z: PropTypes.string /* z */, + a: PropTypes.any /* a */, + b: PropTypes.any /* b */ + }, + render: function() { + return ; + } + }); + `, + output: ` + var First = createReactClass({ + propTypes: { + a: PropTypes.any /* a */, + b: PropTypes.any /* b */, + z: PropTypes.string /* z */ + }, + render: function() { + return ; + } + }); + `, + errors: [ + { + messageId: 'propsNotSorted', + line: 5, + column: 13, + type: 'Property', + }, + { + messageId: 'propsNotSorted', + line: 6, + column: 13, + type: 'Property', + }, + ], + } : [], + semver.satisfies(eslintPkg.version, '> 3') ? { + code: ` + var First = createReactClass({ + propTypes: { + /* z */ z: PropTypes.string, + /* a */ a: PropTypes.any, + /* b */ b: PropTypes.any + }, + render: function() { + return ; + } + }); + `, + output: ` + var First = createReactClass({ + propTypes: { + /* a */ a: PropTypes.any, + /* b */ b: PropTypes.any, + /* z */ z: PropTypes.string + }, + render: function() { + return ; + } + }); + `, + errors: [ + { + messageId: 'propsNotSorted', + line: 5, + column: 21, + type: 'Property', + }, + { + messageId: 'propsNotSorted', + line: 6, + column: 21, + type: 'Property', + }, + ], + } : [], + semver.satisfies(eslintPkg.version, '> 3') ? { + code: ` + var First = createReactClass({ + propTypes: { + /* z */ z: PropTypes.string /* z */, + /* a */ a: PropTypes.any /* a */, + /* b */ b: PropTypes.any /* b */ + }, + render: function() { + return ; + } + }); + `, + output: ` + var First = createReactClass({ + propTypes: { + /* a */ a: PropTypes.any /* a */, + /* b */ b: PropTypes.any /* b */, + /* z */ z: PropTypes.string /* z */ + }, + render: function() { + return ; + } + }); + `, + errors: [ + { + messageId: 'propsNotSorted', + line: 5, + column: 21, + type: 'Property', + }, + { + messageId: 'propsNotSorted', + line: 6, + column: 21, + type: 'Property', + }, + ], + } : [], + semver.satisfies(eslintPkg.version, '> 3') ? { + code: ` + var First = createReactClass({ + propTypes: { + /* z */ z: PropTypes.string, /* a */ a: PropTypes.any, /* b */ b: PropTypes.any + }, + render: function() { + return ; + } + }); + `, + output: ` + var First = createReactClass({ + propTypes: { + /* a */ a: PropTypes.any, /* b */ b: PropTypes.any, /* z */ z: PropTypes.string + }, + render: function() { + return ; + } + }); + `, + errors: [ + { + messageId: 'propsNotSorted', + line: 4, + column: 50, + type: 'Property', + }, + { + messageId: 'propsNotSorted', + line: 4, + column: 76, + type: 'Property', + }, + ], + } : [], + semver.satisfies(eslintPkg.version, '> 3') ? { + code: ` + class Component extends React.Component { + render() { + return ; + } + } + Component.propTypes = { + x: PropTypes.any, + y: PropTypes.any, + z: PropTypes.shape({ + a: PropTypes.string, + c: PropTypes.number.isRequired /* c */, + b: PropTypes.any, + ...otherPropTypes, + f: PropTypes.bool, + /* d */ + d: PropTypes.string, + }), + }; + `, + output: ` + class Component extends React.Component { + render() { + return ; + } + } + Component.propTypes = { + x: PropTypes.any, + y: PropTypes.any, + z: PropTypes.shape({ + a: PropTypes.string, + b: PropTypes.any, + c: PropTypes.number.isRequired /* c */, + ...otherPropTypes, + /* d */ + d: PropTypes.string, + f: PropTypes.bool, + }), + }; + `, + options: [{ sortShapeProp: true }], + errors: [ + { + messageId: 'propsNotSorted', + line: 13, + column: 13, + type: 'Property', + }, + { + messageId: 'propsNotSorted', + line: 17, + column: 13, + type: 'Property', + }, + ], + } : [] + )), });