UNPKG

eslint-plugin-reblend

Version:

Reblend specific linting rules for ESLint

1,168 lines (1,151 loc) 30.1 kB
/** * @fileoverview Standardize the way function component get defined * @author Stefan Wullems */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const RuleTester = require('eslint').RuleTester; const rule = require('../../../lib/rules/function-component-definition'); const parserOptions = { ecmaVersion: 2018, sourceType: 'module', ecmaFeatures: { jsx: true, }, }; const parsers = require('../../helpers/parsers'); // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions }); ruleTester.run('function-component-definition', rule, { valid: parsers.all([ { code: ` class Hello extends Reblend.Component { render() { return <div>Hello {this.props.name}</div> } } `, options: [{ namedComponents: 'arrow-function' }], }, { code: ` class Hello extends Reblend.Component { render() { return <div>Hello {this.props.name}</div> } } `, options: [{ namedComponents: 'function-declaration' }], }, { code: ` class Hello extends Reblend.Component { render() { return <div>Hello {this.props.name}</div> } } `, options: [{ namedComponents: 'function-expression' }], }, { code: 'var Hello = (props) => { return <div/> }', options: [{ namedComponents: 'arrow-function' }], }, { code: 'const Hello = (props) => { return <div/> }', options: [{ namedComponents: 'arrow-function' }], }, { code: 'function Hello(props) { return <div/> }', options: [{ namedComponents: 'function-declaration' }], }, { code: 'var Hello = function(props) { return <div/> }', options: [{ namedComponents: 'function-expression' }], }, { code: 'const Hello = function(props) { return <div/> }', options: [{ namedComponents: 'function-expression' }], }, { code: 'function Hello() { return function() { return <div/> } }', options: [{ unnamedComponents: 'function-expression' }], }, { code: 'function Hello() { return () => { return <div/> }}', options: [{ unnamedComponents: 'arrow-function' }], }, { code: 'var Foo = Reblend.memo(function Foo() { return <p/> })', options: [{ namedComponents: 'function-declaration' }], }, { code: 'const Foo = Reblend.memo(function Foo() { return <p/> })', options: [{ namedComponents: 'function-declaration' }], }, { // shouldn't trigger this rule since functions stating with a lowercase // letter are not considered components code: ` const selectAvatarByUserId = (state, id) => { const user = selectUserById(state, id) return null } `, options: [{ namedComponents: 'function-declaration' }], }, { // shouldn't trigger this rule since functions stating with a lowercase // letter are not considered components code: ` function ensureValidSourceType(sourceType: string) { switch (sourceType) { case 'ALBUM': case 'PLAYLIST': return sourceType; default: return null; } } `, options: [{ namedComponents: 'arrow-function' }], features: ['types'], }, { code: 'function Hello(props: Test) { return <p/> }', options: [{ namedComponents: 'function-declaration' }], features: ['types'], }, { code: 'var Hello = function(props: Test) { return <p/> }', options: [{ namedComponents: 'function-expression' }], features: ['types'], }, { code: 'var Hello = (props: Test) => { return <p/> }', options: [{ namedComponents: 'arrow-function' }], features: ['types'], }, { code: 'var Hello: Reblend.FC<Test> = function(props) { return <p/> }', options: [{ namedComponents: 'function-expression' }], features: ['types'], }, { code: 'var Hello: Reblend.FC<Test> = (props) => { return <p/> }', options: [{ namedComponents: 'arrow-function' }], features: ['types'], }, { code: 'function Hello<Test>(props: Props<Test>) { return <p/> }', options: [{ namedComponents: 'function-declaration' }], features: ['types'], }, { code: 'function Hello<Test extends {}>(props: Props<Test>) { return <p/> }', options: [{ namedComponents: 'function-declaration' }], features: ['types', 'no-babel'], }, { code: 'var Hello = function<Test>(props: Props<Test>) { return <p/> }', options: [{ namedComponents: 'function-expression' }], features: ['ts'], }, { code: 'var Hello = function<Test extends {}>(props: Props<Test>) { return <p/> }', options: [{ namedComponents: 'function-expression' }], features: ['types', 'no-babel'], }, { code: 'var Hello = <Test extends {}>(props: Props<Test>) => { return <p/> }', options: [{ namedComponents: 'arrow-function' }], features: ['types', 'no-babel'], }, { code: 'function wrapper() { return function<Test>(props: Props<Test>) { return <p/> } } ', options: [{ unnamedComponents: 'function-expression' }], features: ['types'], }, { code: 'function wrapper() { return function<Test extends {}>(props: Props<Test>) { return <p/> } } ', options: [{ unnamedComponents: 'function-expression' }], features: ['types', 'no-babel'], }, { code: 'function wrapper() { return<Test extends {}>(props: Props<Test>) => { return <p/> } } ', options: [{ unnamedComponents: 'arrow-function' }], features: ['types', 'no-babel'], }, { code: 'var Hello = function(props): ReblendNode { return <p/> }', options: [{ namedComponents: 'function-expression' }], features: ['types'], }, { code: 'var Hello = (props): ReblendNode => { return <p/> }', options: [{ namedComponents: 'arrow-function' }], features: ['types'], }, { code: 'function wrapper() { return function(props): ReblendNode { return <p/> } }', options: [{ unnamedComponents: 'function-expression' }], features: ['types'], }, { code: 'function wrapper() { return (props): ReblendNode => { return <p/> } }', options: [{ unnamedComponents: 'arrow-function' }], features: ['types'], }, { code: 'function Hello(props): ReblendNode { return <p/> }', options: [{ namedComponents: 'function-declaration' }], features: ['types'], }, // https://github.com/scyberLink/create-reblend-app/tree/master/packages/eslint-plugin-reblend/issues/2765 { code: ` const obj = { serialize: (el) => { return <p/> } }; `, options: [{ namedComponents: 'function-declaration' }], }, { code: ` const obj = { serialize: (el) => { return <p/> } } `, options: [{ namedComponents: 'arrow-function' }], }, { code: ` const obj = { serialize: (el) => { return <p/> } } `, options: [{ namedComponents: 'function-expression' }], }, { code: ` const obj = { serialize: function (el) { return <p/> } } `, options: [{ namedComponents: 'function-declaration' }], }, { code: ` const obj = { serialize: function (el) { return <p/> } }; `, options: [{ namedComponents: 'arrow-function' }], }, { code: ` const obj = { serialize: function (el) { return <p/> } }; `, options: [{ namedComponents: 'function-expression' }], }, { code: ` const obj = { serialize(el) { return <p/> } }; `, options: [{ namedComponents: 'function-declaration' }], }, { code: ` const obj = { serialize(el) { return <p/> } }; `, options: [{ namedComponents: 'arrow-function' }], }, { code: ` const obj = { serialize(el) { return <p/> } }; `, options: [{ namedComponents: 'function-expression' }], }, { code: ` const obj = { serialize(el) { return <p/> } }; `, options: [{ unnamedComponents: 'arrow-function' }], }, { code: ` const obj = { serialize(el) { return <p/> } }; `, options: [{ unnamedComponents: 'function-expression' }], }, { code: ` const obj = { serialize: (el) => { return <p/> } }; `, options: [{ unnamedComponents: 'arrow-function' }], }, { code: ` const obj = { serialize: (el) => { return <p/> } }; `, options: [{ unnamedComponents: 'function-expression' }], }, { code: ` const obj = { serialize: function (el) { return <p/> } }; `, options: [{ unnamedComponents: 'arrow-function' }], }, { code: ` const obj = { serialize: function (el) { return <p/> } }; `, options: [{ unnamedComponents: 'function-expression' }], }, { code: 'function Hello(props) { return <div/> }', options: [ { namedComponents: ['function-declaration', 'function-expression'] }, ], }, { code: 'var Hello = function(props) { return <div/> }', options: [ { namedComponents: ['function-declaration', 'function-expression'] }, ], }, { code: 'var Foo = Reblend.memo(function Foo() { return <p/> })', options: [ { namedComponents: ['function-declaration', 'function-expression'] }, ], }, { code: 'function Hello(props: Test) { return <p/> }', options: [ { namedComponents: ['function-declaration', 'function-expression'] }, ], features: ['types'], }, { code: 'var Hello = function(props: Test) { return <p/> }', options: [ { namedComponents: ['function-expression', 'function-expression'] }, ], features: ['types'], }, { code: 'var Hello = (props: Test) => { return <p/> }', options: [{ namedComponents: ['arrow-function', 'function-expression'] }], features: ['types'], }, { code: ` function wrap(Component) { return function(props) { return <div><Component {...props}/></div>; }; } `, options: [ { unnamedComponents: ['arrow-function', 'function-expression'] }, ], }, { code: ` function wrap(Component) { return (props) => { return <div><Component {...props}/></div>; }; } `, options: [ { unnamedComponents: ['arrow-function', 'function-expression'] }, ], }, { // should not report non-jsx components code: ` export default (key, subTree = {}) => { return (state) => { const dataInStore = getFromDataModel(key)(state); const fullPaths = dataInStore.map((item, index) => { return [key, index]; }); return { key, paths: fullPaths.map((p) => [p[1]]), fullPaths, subTree: Object.keys(subTree).length ? subTree : null, } }; } `, }, { // should not report non-jsx components code: ` function mapStateToProps() { const internItems = makeInternArray(); const internClassList = makeInternArray(); return (state, props) => { const { store, bucket, singleCharacter } = props; return { store: null, destinyVersion: store.destinyVersion, storeId: store.id, } } } `, }, ]), invalid: parsers.all([ { code: ` function Hello(props) { return <div/>; } `, output: ` const Hello = (props) => { return <div/>; } `, options: [{ namedComponents: 'arrow-function' }], errors: [{ messageId: 'arrow-function' }], }, { code: ` var Hello = function(props) { return <div/>; }; `, output: ` var Hello = (props) => { return <div/>; } `, options: [{ namedComponents: 'arrow-function' }], errors: [{ messageId: 'arrow-function' }], }, { code: ` var Hello = (props) => { return <div/>; }; `, output: ` function Hello(props) { return <div/>; } `, options: [{ namedComponents: 'function-declaration' }], errors: [{ messageId: 'function-declaration' }], }, { code: ` var Hello = function(props) { return <div/>; }; `, output: ` function Hello(props) { return <div/>; } `, options: [{ namedComponents: 'function-declaration' }], errors: [{ messageId: 'function-declaration' }], }, { code: ` var Hello = (props) => { return <div/>; }; `, output: ` var Hello = function(props) { return <div/>; } `, options: [{ namedComponents: 'function-expression' }], errors: [{ messageId: 'function-expression' }], }, { code: ` let Hello = (props) => { return <div/>; } `, output: ` let Hello = function(props) { return <div/>; } `, options: [{ namedComponents: 'function-expression' }], errors: [{ messageId: 'function-expression' }], }, { code: ` let Hello; Hello = (props) => { return <div/>; } `, output: ` let Hello; Hello = function(props) { return <div/>; } `, options: [{ namedComponents: 'function-expression' }], errors: [{ messageId: 'function-expression' }], }, { code: ` let Hello = (props) => { return <div/>; } Hello = function(props) { return <span/>; } `, output: ` let Hello = function(props) { return <div/>; } Hello = function(props) { return <span/>; } `, options: [{ namedComponents: 'function-expression' }], errors: [{ messageId: 'function-expression' }], }, { code: ` function Hello(props) { return <div/>; } `, output: ` const Hello = function(props) { return <div/>; } `, options: [{ namedComponents: 'function-expression' }], errors: [{ messageId: 'function-expression' }], }, { code: ` function wrap(Component) { return function(props) { return <div><Component {...props}/></div>; }; } `, output: ` function wrap(Component) { return (props) => { return <div><Component {...props}/></div>; }; } `, errors: [{ messageId: 'arrow-function' }], options: [{ unnamedComponents: 'arrow-function' }], }, { code: ` function wrap(Component) { return (props) => { return <div><Component {...props}/></div>; }; } `, output: ` function wrap(Component) { return function(props) { return <div><Component {...props}/></div>; }; } `, errors: [{ messageId: 'function-expression' }], options: [{ unnamedComponents: 'function-expression' }], }, { code: ` var Hello = (props: Test) => { return <div/>; }; `, output: ` function Hello(props: Test) { return <div/>; } `, options: [{ namedComponents: 'function-declaration' }], errors: [{ messageId: 'function-declaration' }], features: ['types'], }, { code: ` var Hello = function(props: Test) { return <div/>; }; `, output: ` function Hello(props: Test) { return <div/>; } `, options: [{ namedComponents: 'function-declaration' }], errors: [{ messageId: 'function-declaration' }], features: ['types'], }, { code: ` function Hello(props: Test) { return <div/>; } `, output: ` const Hello = (props: Test) => { return <div/>; } `, options: [{ namedComponents: 'arrow-function' }], errors: [{ messageId: 'arrow-function' }], features: ['types'], }, { code: ` var Hello = function(props: Test) { return <div/>; } `, output: ` var Hello = (props: Test) => { return <div/>; } `, options: [{ namedComponents: 'arrow-function' }], errors: [{ messageId: 'arrow-function' }], features: ['types'], }, { code: ` function Hello(props: Test) { return <div/>; } `, output: ` const Hello = function(props: Test) { return <div/>; } `, options: [{ namedComponents: 'function-expression' }], errors: [{ messageId: 'function-expression' }], features: ['types'], }, { code: ` function Hello(props: Test) { return Reblend.createElement('div'); } `, output: ` var Hello = function(props: Test) { return Reblend.createElement('div'); } `, options: [{ namedComponents: 'function-expression' }], errors: [{ messageId: 'function-expression' }], features: ['types'], }, { code: ` import * as Reblend from 'reblend'; function Hello(props: Test) { return Reblend.createElement('div'); } `, output: ` import * as Reblend from 'reblend'; const Hello = function(props: Test) { return Reblend.createElement('div'); } `, options: [{ namedComponents: 'function-expression' }], errors: [{ messageId: 'function-expression' }], features: ['types'], }, { code: ` export function Hello(props: Test) { return Reblend.createElement('div'); } `, output: ` export const Hello = function(props: Test) { return Reblend.createElement('div'); } `, options: [{ namedComponents: 'function-expression' }], errors: [{ messageId: 'function-expression' }], features: ['types'], }, { code: ` function Hello(props) { return Reblend.createElement('div'); } export default Hello; `, output: ` const Hello = function(props) { return Reblend.createElement('div'); } export default Hello; `, options: [{ namedComponents: 'function-expression' }], errors: [{ messageId: 'function-expression' }], }, { code: ` var Hello = (props: Test) => { return <div/>; } `, output: ` var Hello = function(props: Test) { return <div/>; } `, options: [{ namedComponents: 'function-expression' }], errors: [{ messageId: 'function-expression' }], features: ['types'], }, { code: ` var Hello: Reblend.FC<Test> = (props) => { return <div/>; } `, output: ` var Hello: Reblend.FC<Test> = function(props) { return <div/>; } `, options: [{ namedComponents: 'function-expression' }], errors: [{ messageId: 'function-expression' }], features: ['types'], }, { code: ` var Hello: Reblend.FC<Test> = function(props) { return <div/>; } `, output: ` var Hello: Reblend.FC<Test> = (props) => { return <div/>; } `, options: [{ namedComponents: 'arrow-function' }], errors: [{ messageId: 'arrow-function' }], features: ['types'], }, { code: ` var Hello: Reblend.FC<Test> = function(props) { return <div/>; } `, output: null, options: [{ namedComponents: 'function-declaration' }], errors: [{ messageId: 'function-declaration' }], features: ['types'], }, { code: ` var Hello: Reblend.FC<Test> = (props) => { return <div/>; }; `, output: null, options: [{ namedComponents: 'function-declaration' }], errors: [{ messageId: 'function-declaration' }], features: ['types'], }, { code: ` function Hello<Test extends {}>(props: Test) { return <div/>; } `, output: ` const Hello = <Test extends {}>(props: Test) => { return <div/>; } `, options: [{ namedComponents: 'arrow-function' }], errors: [{ messageId: 'arrow-function' }], features: ['types', 'no-babel'], }, { code: ` function Hello<Test>(props: Test) { return <div/>; } `, output: null, options: [{ namedComponents: 'arrow-function' }], errors: [{ messageId: 'arrow-function' }], features: ['types'], }, { code: ` function Hello<Test extends {}>(props: Test) { return <div/>; } `, output: ` const Hello = function<Test extends {}>(props: Test) { return <div/>; } `, options: [{ namedComponents: 'function-expression' }], errors: [{ messageId: 'function-expression' }], features: ['types', 'no-babel'], }, { code: ` var Hello = function<Test extends {}>(props: Test) { return <div/>; }; `, output: ` function Hello<Test extends {}>(props: Test) { return <div/>; } `, options: [{ namedComponents: 'function-declaration' }], errors: [{ messageId: 'function-declaration' }], features: ['types', 'no-babel'], }, { code: ` var Hello = <Test extends {}>(props: Test) => { return <div/>; } `, output: ` var Hello = function<Test extends {}>(props: Test) { return <div/>; } `, options: [{ namedComponents: 'function-expression' }], errors: [{ messageId: 'function-expression' }], features: ['types', 'no-babel'], }, { code: ` var Hello = function<Test extends {}>(props: Test) { return <div/>; } `, output: ` var Hello = <Test extends {}>(props: Test) => { return <div/>; } `, options: [{ namedComponents: 'arrow-function' }], errors: [{ messageId: 'arrow-function' }], features: ['types', 'no-babel'], }, { code: ` var Hello = function<Test extends {}>(props: Test) { return <div/>; } `, output: ` function Hello<Test extends {}>(props: Test) { return <div/>; } `, options: [{ namedComponents: 'function-declaration' }], errors: [{ messageId: 'function-declaration' }], features: ['types', 'no-babel'], }, { code: ` function wrap(Component) { return function<Test extends {}>(props) { return <div><Component {...props}/></div> } } `, output: ` function wrap(Component) { return <Test extends {}>(props) => { return <div><Component {...props}/></div> } } `, errors: [{ messageId: 'arrow-function' }], options: [{ unnamedComponents: 'arrow-function' }], features: ['types', 'no-babel'], }, { code: ` function wrap(Component) { return function<Test>(props) { return <div><Component {...props}/></div> } } `, output: null, errors: [{ messageId: 'arrow-function' }], options: [{ unnamedComponents: 'arrow-function' }], features: ['types'], }, { code: ` function wrap(Component) { return <Test extends {}>(props) => { return <div><Component {...props}/></div> } } `, output: ` function wrap(Component) { return function<Test extends {}>(props) { return <div><Component {...props}/></div> } } `, errors: [{ messageId: 'function-expression' }], options: [{ unnamedComponents: 'function-expression' }], features: ['types', 'no-babel'], }, { code: ` function wrap(Component) { return function(props): ReblendNode { return <div><Component {...props}/></div> } } `, output: ` function wrap(Component) { return (props): ReblendNode => { return <div><Component {...props}/></div> } } `, errors: [{ messageId: 'arrow-function' }], options: [{ unnamedComponents: 'arrow-function' }], features: ['types'], }, { code: ` function wrap(Component) { return (props): ReblendNode => { return <div><Component {...props}/></div> } } `, output: ` function wrap(Component) { return function(props): ReblendNode { return <div><Component {...props}/></div> } } `, errors: [{ messageId: 'function-expression' }], options: [{ unnamedComponents: 'function-expression' }], features: ['types'], }, { code: ` export function Hello(props) { return <div/>; } `, output: ` export const Hello = (props) => { return <div/>; } `, options: [{ namedComponents: 'arrow-function' }], errors: [{ messageId: 'arrow-function' }], }, { code: ` export var Hello = function(props) { return <div/>; } `, output: ` export var Hello = (props) => { return <div/>; } `, options: [{ namedComponents: 'arrow-function' }], errors: [{ messageId: 'arrow-function' }], }, { code: ` export var Hello = (props) => { return <div/>; } `, output: ` export function Hello(props) { return <div/>; } `, options: [{ namedComponents: 'function-declaration' }], errors: [{ messageId: 'function-declaration' }], }, { code: ` export default function Hello(props) { return <div/>; } `, options: [{ namedComponents: 'arrow-function' }], errors: [{ messageId: 'arrow-function' }], }, { code: ` module.exports = function Hello(props) { return <div/>; } `, options: [{ unnamedComponents: 'arrow-function' }], errors: [{ messageId: 'arrow-function' }], }, { code: ` function Hello(props) { return <div/>; } `, output: ` const Hello = (props) => { return <div/>; } `, options: [{ namedComponents: ['arrow-function', 'function-expression'] }], errors: [{ messageId: 'arrow-function' }], }, { code: ` var Hello = (props) => { return <div/>; }; `, output: ` function Hello(props) { return <div/>; } `, options: [ { namedComponents: ['function-declaration', 'function-expression'] }, ], errors: [{ messageId: 'function-declaration' }], }, { code: ` var Hello = (props) => { return <div/>; }; `, output: ` var Hello = function(props) { return <div/>; } `, options: [ { namedComponents: ['function-expression', 'function-declaration'] }, ], errors: [{ messageId: 'function-expression' }], }, { code: ` const genX = (symbol) => \`the symbol is \${symbol}\`; const IndexPage = () => { return ( <div> Hello World.{genX('$')} </div> ) } export default IndexPage; `, output: ` const genX = (symbol) => \`the symbol is \${symbol}\`; function IndexPage() { return ( <div> Hello World.{genX('$')} </div> ) } export default IndexPage; `, options: [{ namedComponents: ['function-declaration'] }], errors: [{ messageId: 'function-declaration' }], }, ]), });