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..706b7e170c 100644 --- a/lib/rules/sort-prop-types.js +++ b/lib/rules/sort-prop-types.js @@ -8,13 +8,13 @@ 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'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ - + const messages = { requiredPropsFirst: 'Required prop types must be listed before all other prop types', callbackPropsLast: 'Callback prop types must be listed after all other prop types', @@ -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..58d7342a93 100644 --- a/lib/util/propTypesSort.js +++ b/lib/util/propTypesSort.js @@ -116,9 +116,35 @@ 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. */ +let 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 = []; + let newStart = 0; + let newEnd = 0; + try { + commentBefore = sourceCode.getCommentsBefore(node); + commentAfter = sourceCode.getCommentsAfter(node); + } catch (e) { /**/ }; + if (commentAfter.length === 0 || commentBefore.length === 0) { + newStart = node.range[0] + newEnd = node.range[1] + } + const firstCommentBefore = commentBefore[0]; + if (commentBefore.length >= 1) { + newStart = firstCommentBefore.range[0] + } + const lastCommentAfter = commentAfter[commentAfter.length - 1]; + if (commentAfter.length >= 1) { + newEnd = lastCommentAfter.range[1] + } + commentnodeMap.set(node, { start: newStart, end: newEnd, hasComment: true }); + }; const nodeGroups = allNodes.reduce((acc, curr) => { if (curr.type === 'ExperimentalSpreadProperty' || curr.type === 'SpreadElement') { acc.push([]); @@ -135,7 +161,8 @@ function fixPropTypesSort(fixer, context, declarations, ignoreCase, requiredFirs source = nodes.reduceRight((acc, attr, index) => { const sortedAttr = sortedAttributes[index]; - let sortedAttrText = context.getSourceCode().getText(sortedAttr); + let 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 +173,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 +181,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..c246260db6 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,268 @@ 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', + }, + ], + } : [], + semver.satisfies(eslintPkg.version, '> 3') ? { + code: ` + var First = createReactClass({ + propTypes: { + /* z */ + /* z */ + z: PropTypes.string /* z */, + /* a */ + a: PropTypes.any /* a */ + /* a */ + /* a */, + b: PropTypes.any + }, + render: function() { + return ; + } + }); + `, + output: ` + var First = createReactClass({ + propTypes: { + /* a */ + a: PropTypes.any /* a */ + /* a */ + /* a */, + b: PropTypes.any, + /* z */ + /* z */ + z: PropTypes.string /* z */ + }, + render: function() { + return ; + } + }); + `, + errors: [ + { + messageId: 'propsNotSorted', + line: 8, + column: 13, + type: 'Property', + }, + { + messageId: 'propsNotSorted', + line: 11, + column: 13, + type: 'Property', + }, + ], + } : [], + )), });