├── .gitignore ├── .prettierrc ├── .github └── workflows │ └── nodejs.yml ├── .eslintrc ├── tests ├── no-trim.js ├── no-grep.js ├── no-merge.js ├── no-proxy.js ├── no-is-function.js ├── no-param.js ├── no-in-array.js ├── no-is-array.js ├── no-when.js ├── no-extend.js ├── no-global-eval.js ├── no-parse-html.js ├── no-deferred.js ├── no-is.js ├── no-has.js ├── no-val.js ├── no-css.js ├── no-hide.js ├── no-load.js ├── no-show.js ├── no-size.js ├── no-html.js ├── no-text.js ├── no-bind.js ├── no-find.js ├── no-clone.js ├── no-prop.js ├── no-toggle.js ├── no-filter.js ├── no-animate.js ├── no-parent.js ├── no-closest.js ├── no-parents.js ├── no-trigger.js ├── no-submit.js ├── no-delegate.js ├── no-map.js ├── no-each.js ├── no-attr.js ├── no-data.js ├── no-ajax.js ├── no-ready.js ├── no-serialize.js ├── no-ajax-events.js ├── no-slide.js ├── no-fade.js ├── no-wrap.js ├── no-class.js └── no-sizzle.js ├── rules ├── no-grep.js ├── no-trim.js ├── no-when.js ├── no-merge.js ├── no-proxy.js ├── no-global-eval.js ├── no-in-array.js ├── no-is-array.js ├── no-is-function.js ├── no-param.js ├── no-parse-html.js ├── no-extend.js ├── no-has.js ├── no-is.js ├── no-val.js ├── no-hide.js ├── no-load.js ├── no-map.js ├── no-show.js ├── no-size.js ├── no-animate.js ├── no-clone.js ├── no-css.js ├── no-each.js ├── no-html.js ├── no-text.js ├── no-toggle.js ├── no-bind.js ├── no-closest.js ├── no-deferred.js ├── no-filter.js ├── no-find.js ├── no-parents.js ├── no-parent.js ├── no-prop.js ├── no-trigger.js ├── no-delegate.js ├── no-submit.js ├── no-attr.js ├── no-data.js ├── no-slide.js ├── no-fade.js ├── no-wrap.js ├── no-class.js ├── no-ajax.js ├── no-serialize.js ├── utils.js ├── no-ready.js ├── no-ajax-events.js └── no-sizzle.js ├── package.json ├── LICENSE ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": false, 3 | "semi": false, 4 | "singleQuote": true, 5 | "trailingComma": "none" 6 | } 7 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | on: [push] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | - name: Use Node.js 9 | uses: actions/setup-node@v1 10 | with: 11 | node-version: '14.x' 12 | - run: npm install 13 | - run: npm run build --if-present 14 | - run: npm test 15 | env: 16 | CI: true 17 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "env": { 4 | "node": true, 5 | "es6": true 6 | }, 7 | "plugins": ["prettier"], 8 | "rules": { 9 | "prettier/prettier": "error", 10 | "camelcase": "error", 11 | "eqeqeq": ["error", "smart"], 12 | "no-implicit-globals": "error", 13 | "no-unused-expressions": "error", 14 | "no-var": "error", 15 | "prefer-const": "error", 16 | "strict": "error" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/no-trim.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-trim') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer String#trim to $.trim' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-trim', rule, { 10 | valid: ['trim()', '"test".trim()', '"test".trim'], 11 | invalid: [ 12 | { 13 | code: '$.trim()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | } 16 | ] 17 | }) 18 | -------------------------------------------------------------------------------- /tests/no-grep.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-grep') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer Array#filter to $.grep' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-in-array', rule, { 10 | valid: ['grep()', '"test".grep()', '"test".grep'], 11 | invalid: [ 12 | { 13 | code: '$.grep()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | } 16 | ] 17 | }) 18 | -------------------------------------------------------------------------------- /tests/no-merge.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-merge') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer Array#concat to $.merge' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-merge', rule, { 10 | valid: ['merge()', '"test".merge()', '"test".merge'], 11 | invalid: [ 12 | { 13 | code: '$.merge()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | } 16 | ] 17 | }) 18 | -------------------------------------------------------------------------------- /tests/no-proxy.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-proxy') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer Function#bind to $.proxy' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-proxy', rule, { 10 | valid: ['proxy()', '"test".proxy()', '"test".proxy'], 11 | invalid: [ 12 | { 13 | code: '$.proxy()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | } 16 | ] 17 | }) 18 | -------------------------------------------------------------------------------- /tests/no-is-function.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-is-function') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer typeof to $.isFunction' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-function', rule, { 10 | valid: ['isFunction()', 'myClass.isFunction()'], 11 | invalid: [ 12 | { 13 | code: '$.isFunction()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | } 16 | ] 17 | }) 18 | -------------------------------------------------------------------------------- /tests/no-param.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-param') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer FormData or URLSearchParams to $.param' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-param', rule, { 10 | valid: ['param()', '"test".param()', '"test".param'], 11 | invalid: [ 12 | { 13 | code: '$.param()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | } 16 | ] 17 | }) 18 | -------------------------------------------------------------------------------- /tests/no-in-array.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-in-array') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer Array#indexOf to $.inArray' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-in-array', rule, { 10 | valid: ['inArray()', '"test".inArray()', '"test".inArray'], 11 | invalid: [ 12 | { 13 | code: '$.inArray()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | } 16 | ] 17 | }) 18 | -------------------------------------------------------------------------------- /tests/no-is-array.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-is-array') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer Array#isArray to $.isArray' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-in-array', rule, { 10 | valid: ['isArray()', '"test".isArray()', '"test".isArray'], 11 | invalid: [ 12 | { 13 | code: '$.isArray()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | } 16 | ] 17 | }) 18 | -------------------------------------------------------------------------------- /tests/no-when.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-when') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer Promise.all to $.when' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-when', rule, { 10 | valid: ['When()', 'new When()', '"test".when()', '"test".when', '$when()'], 11 | invalid: [ 12 | { 13 | code: '$.when(a,b)', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | } 16 | ] 17 | }) 18 | -------------------------------------------------------------------------------- /tests/no-extend.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-extend') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer Object#assign or the spread operator to $.extend' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-extend', rule, { 10 | valid: ['extend()', 'myMethod.extend()', 'myMethod.extend'], 11 | invalid: [ 12 | { 13 | code: '$.extend()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | } 16 | ] 17 | }) 18 | -------------------------------------------------------------------------------- /tests/no-global-eval.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-global-eval') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = '$.globalEval is not allowed' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-global-eval', rule, { 10 | valid: ['globalEval()', '"test".globalEval()', '"test".globalEval'], 11 | invalid: [ 12 | { 13 | code: '$.globalEval()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | } 16 | ] 17 | }) 18 | -------------------------------------------------------------------------------- /tests/no-parse-html.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-parse-html') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer createHTMLDocument to $.parseHTML' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-parse-html', rule, { 10 | valid: ['parseHTML()', '"test".parseHTML()', '"test".parseHTML'], 11 | invalid: [ 12 | { 13 | code: '$.parseHTML()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | } 16 | ] 17 | }) 18 | -------------------------------------------------------------------------------- /rules/no-grep.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | meta: { 5 | docs: {}, 6 | schema: [] 7 | }, 8 | 9 | create: function (context) { 10 | return { 11 | CallExpression: function (node) { 12 | if (node.callee.type !== 'MemberExpression') return 13 | if (node.callee.object.name !== '$') return 14 | if (node.callee.property.name !== 'grep') return 15 | 16 | context.report({ 17 | node: node, 18 | message: 'Prefer Array#filter to $.grep' 19 | }) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rules/no-trim.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | meta: { 5 | docs: {}, 6 | schema: [] 7 | }, 8 | 9 | create: function (context) { 10 | return { 11 | CallExpression: function (node) { 12 | if (node.callee.type !== 'MemberExpression') return 13 | if (node.callee.object.name !== '$') return 14 | if (node.callee.property.name !== 'trim') return 15 | 16 | context.report({ 17 | node: node, 18 | message: 'Prefer String#trim to $.trim' 19 | }) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rules/no-when.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | meta: { 5 | docs: {}, 6 | schema: [] 7 | }, 8 | 9 | create: function (context) { 10 | return { 11 | CallExpression: function (node) { 12 | if (node.callee.type !== 'MemberExpression') return 13 | if (node.callee.object.name !== '$') return 14 | if (node.callee.property.name !== 'when') return 15 | 16 | context.report({ 17 | node: node, 18 | message: 'Prefer Promise.all to $.when' 19 | }) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rules/no-merge.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | meta: { 5 | docs: {}, 6 | schema: [] 7 | }, 8 | 9 | create: function (context) { 10 | return { 11 | CallExpression: function (node) { 12 | if (node.callee.type !== 'MemberExpression') return 13 | if (node.callee.object.name !== '$') return 14 | if (node.callee.property.name !== 'merge') return 15 | 16 | context.report({ 17 | node: node, 18 | message: 'Prefer Array#concat to $.merge' 19 | }) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rules/no-proxy.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | meta: { 5 | docs: {}, 6 | schema: [] 7 | }, 8 | 9 | create: function (context) { 10 | return { 11 | CallExpression: function (node) { 12 | if (node.callee.type !== 'MemberExpression') return 13 | if (node.callee.object.name !== '$') return 14 | if (node.callee.property.name !== 'proxy') return 15 | 16 | context.report({ 17 | node: node, 18 | message: 'Prefer Function#bind to $.proxy' 19 | }) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rules/no-global-eval.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | meta: { 5 | docs: {}, 6 | schema: [] 7 | }, 8 | 9 | create: function (context) { 10 | return { 11 | CallExpression: function (node) { 12 | if (node.callee.type !== 'MemberExpression') return 13 | if (node.callee.object.name !== '$') return 14 | if (node.callee.property.name !== 'globalEval') return 15 | 16 | context.report({ 17 | node: node, 18 | message: '$.globalEval is not allowed' 19 | }) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rules/no-in-array.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | meta: { 5 | docs: {}, 6 | schema: [] 7 | }, 8 | 9 | create: function (context) { 10 | return { 11 | CallExpression: function (node) { 12 | if (node.callee.type !== 'MemberExpression') return 13 | if (node.callee.object.name !== '$') return 14 | if (node.callee.property.name !== 'inArray') return 15 | 16 | context.report({ 17 | node: node, 18 | message: 'Prefer Array#indexOf to $.inArray' 19 | }) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rules/no-is-array.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | meta: { 5 | docs: {}, 6 | schema: [] 7 | }, 8 | 9 | create: function (context) { 10 | return { 11 | CallExpression: function (node) { 12 | if (node.callee.type !== 'MemberExpression') return 13 | if (node.callee.object.name !== '$') return 14 | if (node.callee.property.name !== 'isArray') return 15 | 16 | context.report({ 17 | node: node, 18 | message: 'Prefer Array#isArray to $.isArray' 19 | }) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rules/no-is-function.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | meta: { 5 | docs: {}, 6 | schema: [] 7 | }, 8 | 9 | create: function (context) { 10 | return { 11 | CallExpression: function (node) { 12 | if (node.callee.type !== 'MemberExpression') return 13 | if (node.callee.object.name !== '$') return 14 | if (node.callee.property.name !== 'isFunction') return 15 | 16 | context.report({ 17 | node: node, 18 | message: 'Prefer typeof to $.isFunction' 19 | }) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rules/no-param.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | meta: { 5 | docs: {}, 6 | schema: [] 7 | }, 8 | 9 | create: function (context) { 10 | return { 11 | CallExpression: function (node) { 12 | if (node.callee.type !== 'MemberExpression') return 13 | if (node.callee.object.name !== '$') return 14 | if (node.callee.property.name !== 'param') return 15 | 16 | context.report({ 17 | node: node, 18 | message: 'Prefer FormData or URLSearchParams to $.param' 19 | }) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rules/no-parse-html.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | meta: { 5 | docs: {}, 6 | schema: [] 7 | }, 8 | 9 | create: function (context) { 10 | return { 11 | CallExpression: function (node) { 12 | if (node.callee.type !== 'MemberExpression') return 13 | if (node.callee.object.name !== '$') return 14 | if (node.callee.property.name !== 'parseHTML') return 15 | 16 | context.report({ 17 | node: node, 18 | message: 'Prefer createHTMLDocument to $.parseHTML' 19 | }) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rules/no-extend.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | meta: { 5 | docs: {}, 6 | schema: [] 7 | }, 8 | 9 | create: function (context) { 10 | return { 11 | CallExpression: function (node) { 12 | if (node.callee.type !== 'MemberExpression') return 13 | if (node.callee.object.name !== '$') return 14 | if (node.callee.property.name !== 'extend') return 15 | 16 | context.report({ 17 | node: node, 18 | message: 'Prefer Object#assign or the spread operator to $.extend' 19 | }) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rules/no-has.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'has') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: '$.has is not allowed' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-is.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'is') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer matches to $.is' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-val.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'val') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer value to $.val' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-hide.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'hide') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: '$.hide is not allowed' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-load.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'load') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer fetch to $.load' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-map.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'map') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer Array#map to $.map' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-show.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'show') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: '$.show is not allowed' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-size.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'size') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer length to $.size' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-animate.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'animate') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: '$.animate is not allowed' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-clone.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'clone') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer cloneNode to $.clone' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-css.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'css') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer getComputedStyle to $.css' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-each.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'each') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer Array#forEach to $.each' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-html.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'html') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer innerHTML to $.html' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-text.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'text') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer textContent to $.text' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-toggle.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'toggle') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: '$.toggle is not allowed' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-bind.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'bind') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer addEventListener to $.bind' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-closest.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'closest') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer closest to $.closest' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-deferred.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | meta: { 5 | docs: {}, 6 | schema: [] 7 | }, 8 | 9 | create: function (context) { 10 | function enforce(node) { 11 | if (node.callee.type !== 'MemberExpression') return 12 | if (node.callee.object.name !== '$') return 13 | if (node.callee.property.name !== 'Deferred') return 14 | 15 | context.report({ 16 | node: node, 17 | message: 'Prefer Promise to $.Deferred' 18 | }) 19 | } 20 | 21 | return { 22 | CallExpression: enforce, 23 | NewExpression: enforce 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-filter.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'filter') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer Array#filter to $.filter' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-find.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'find') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer querySelectorAll to $.find' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-parents.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'parents') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer closest to $.parents' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-parent.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'parent') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer parentElement to $.parent' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-prop.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'prop') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer direct property access to $.prop' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-trigger.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'trigger') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer dispatchEvent to $.trigger' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-delegate.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'delegate') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer addEventListener to $.delegate' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rules/no-submit.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'submit') return 16 | 17 | if (utils.isjQuery(node)) { 18 | context.report({ 19 | node: node, 20 | message: 'Prefer dispatchEvent + form.submit() to $.submit' 21 | }) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/no-deferred.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-deferred') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer Promise to $.Deferred' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-deferred', rule, { 10 | valid: [ 11 | 'Deferred()', 12 | 'new Deferred()', 13 | '"test".Deferred()', 14 | '"test".Deferred' 15 | ], 16 | invalid: [ 17 | { 18 | code: '$.Deferred()', 19 | errors: [{message: error, type: 'CallExpression'}] 20 | }, 21 | { 22 | code: 'new $.Deferred()', 23 | errors: [{message: error, type: 'NewExpression'}] 24 | } 25 | ] 26 | }) 27 | -------------------------------------------------------------------------------- /rules/no-attr.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (node.callee.property.name !== 'attr') return 16 | 17 | if (utils.isjQuery(node)) { 18 | const getOrSet = node.arguments.length === 2 ? 'set' : 'get' 19 | context.report({ 20 | node: node, 21 | message: `Prefer ${getOrSet}Attribute to $.attr` 22 | }) 23 | } 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /rules/no-data.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | return { 13 | CallExpression: function (node) { 14 | if (node.callee.type !== 'MemberExpression') return 15 | if (!utils.isjQuery(node)) return 16 | 17 | const name = node.callee.property.name 18 | switch (name) { 19 | case 'data': 20 | case 'removeData': 21 | context.report({ 22 | node: node, 23 | message: 'Prefer WeakMap to $.' + name 24 | }) 25 | } 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-plugin-jquery", 3 | "version": "1.5.1", 4 | "description": "Disallow jQuery functions with native equivalents.", 5 | "repository": "dgraham/eslint-plugin-jquery", 6 | "license": "MIT", 7 | "keywords": [ 8 | "eslint", 9 | "eslintplugin", 10 | "eslint-plugin" 11 | ], 12 | "author": "David Graham", 13 | "main": "index.js", 14 | "scripts": { 15 | "pretest": "eslint .", 16 | "test": "mocha --reporter dot tests/" 17 | }, 18 | "peerDependencies": { 19 | "eslint": ">=5.4.0" 20 | }, 21 | "devDependencies": { 22 | "eslint": "^7.4.0", 23 | "eslint-plugin-prettier": "^3.1.4", 24 | "mocha": "^8.0.1", 25 | "prettier": "^2.0.5" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /rules/no-slide.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | const forbidden = ['slideDown', 'slideToggle', 'slideUp'] 13 | 14 | return { 15 | CallExpression: function (node) { 16 | if (node.callee.type !== 'MemberExpression') return 17 | if (forbidden.indexOf(node.callee.property.name) === -1) return 18 | 19 | if (utils.isjQuery(node)) { 20 | context.report({ 21 | node: node, 22 | message: '$.' + node.callee.property.name + ' is not allowed' 23 | }) 24 | } 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rules/no-fade.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | const forbidden = ['fadeIn', 'fadeOut', 'fadeTo', 'fadeToggle'] 13 | 14 | return { 15 | CallExpression: function (node) { 16 | if (node.callee.type !== 'MemberExpression') return 17 | if (forbidden.indexOf(node.callee.property.name) === -1) return 18 | 19 | if (utils.isjQuery(node)) { 20 | context.report({ 21 | node: node, 22 | message: '$.' + node.callee.property.name + ' is not allowed' 23 | }) 24 | } 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rules/no-wrap.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | const forbidden = ['wrap', 'wrapAll', 'wrapInner', 'unwrap'] 13 | 14 | return { 15 | CallExpression: function (node) { 16 | if (node.callee.type !== 'MemberExpression') return 17 | if (forbidden.indexOf(node.callee.property.name) === -1) return 18 | 19 | if (utils.isjQuery(node)) { 20 | context.report({ 21 | node: node, 22 | message: '$.' + node.callee.property.name + ' is not allowed' 23 | }) 24 | } 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rules/no-class.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | const forbidden = ['addClass', 'hasClass', 'removeClass', 'toggleClass'] 13 | 14 | return { 15 | CallExpression: function (node) { 16 | if (node.callee.type !== 'MemberExpression') return 17 | if (forbidden.indexOf(node.callee.property.name) === -1) return 18 | 19 | if (utils.isjQuery(node)) { 20 | context.report({ 21 | node: node, 22 | message: 'Prefer classList to $.' + node.callee.property.name 23 | }) 24 | } 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rules/no-ajax.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | meta: { 5 | docs: {}, 6 | schema: [] 7 | }, 8 | 9 | create: function (context) { 10 | return { 11 | CallExpression: function (node) { 12 | if (node.callee.type !== 'MemberExpression') return 13 | if (node.callee.object.name !== '$') return 14 | 15 | const name = node.callee.property.name 16 | switch (name) { 17 | case 'ajax': 18 | case 'get': 19 | case 'getJSON': 20 | case 'getScript': 21 | case 'post': 22 | context.report({ 23 | node: node, 24 | message: 'Prefer fetch to $.' + name 25 | }) 26 | } 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rules/no-serialize.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | const forbidden = ['serialize', 'serializeArray'] 13 | 14 | return { 15 | CallExpression: function (node) { 16 | if (node.callee.type !== 'MemberExpression') return 17 | if (forbidden.indexOf(node.callee.property.name) === -1) return 18 | 19 | if (utils.isjQuery(node)) { 20 | context.report({ 21 | node: node, 22 | message: 23 | 'Prefer FormData or URLSearchParams to $.' + 24 | node.callee.property.name 25 | }) 26 | } 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/no-is.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-is') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer matches to $.is' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-is', rule, { 10 | valid: ['is()', '[].is()', 'div.is()', 'div.is'], 11 | invalid: [ 12 | { 13 | code: '$("div").is()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.is()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().is()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").is())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-has.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-has') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = '$.has is not allowed' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-has', rule, { 10 | valid: ['has()', '[].has()', 'div.has()', 'div.has'], 11 | invalid: [ 12 | { 13 | code: '$("div").has()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.has()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().has()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").has())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-val.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-val') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer value to $.val' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-val', rule, { 10 | valid: ['val()', '[].val()', 'div.val()', 'div.val'], 11 | invalid: [ 12 | { 13 | code: '$("div").val()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.val()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().val()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").val())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-css.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-css') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer getComputedStyle to $.css' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-css', rule, { 10 | valid: ['css()', '[].css()', 'div.css()', 'div.css'], 11 | invalid: [ 12 | { 13 | code: '$("div").css()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.css()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().css()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").css())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-hide.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-hide') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = '$.hide is not allowed' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-hide', rule, { 10 | valid: ['hide()', '[].hide()', 'div.hide()', 'div.hide'], 11 | invalid: [ 12 | { 13 | code: '$("div").hide()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.hide()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().hide()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").hide())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-load.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-load') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer fetch to $.load' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-load', rule, { 10 | valid: ['load()', '[].load()', 'div.load()', 'div.load'], 11 | invalid: [ 12 | { 13 | code: '$("div").load()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.load()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().load()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").load())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-show.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-show') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = '$.show is not allowed' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-show', rule, { 10 | valid: ['show()', '[].show()', 'div.show()', 'div.show'], 11 | invalid: [ 12 | { 13 | code: '$("div").show()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.show()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().show()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").show())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-size.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-size') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer length to $.size' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-size', rule, { 10 | valid: ['size()', '[].size()', 'div.size()', 'div.size'], 11 | invalid: [ 12 | { 13 | code: '$("div").size()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.size()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().size()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").size())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-html.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-html') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer innerHTML to $.html' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-html', rule, { 10 | valid: ['html()', '[].html()', 'div.html()', 'div.html'], 11 | invalid: [ 12 | { 13 | code: '$("div").html()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.html()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().html()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").html())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-text.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-text') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer textContent to $.text' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-text', rule, { 10 | valid: ['text()', '[].text()', 'div.text()', 'div.text'], 11 | invalid: [ 12 | { 13 | code: '$("div").text()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.text()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().text()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").text())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-bind.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-bind') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer addEventListener to $.bind' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-bind', rule, { 10 | valid: ['bind()', '[].bind()', 'div.bind()', 'div.bind'], 11 | invalid: [ 12 | { 13 | code: '$("div").bind()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.bind()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().bind()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").bind())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-find.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-find') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer querySelectorAll to $.find' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-find', rule, { 10 | valid: ['find()', '[].find()', 'div.find()', 'div.find'], 11 | invalid: [ 12 | { 13 | code: '$("div").find()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.find()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().find()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").find())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-clone.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-clone') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer cloneNode to $.clone' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-clone', rule, { 10 | valid: ['clone()', '[].clone()', 'div.clone()', 'div.clone'], 11 | invalid: [ 12 | { 13 | code: '$("div").clone()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.clone()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().clone()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").clone())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-prop.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-prop') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer direct property access to $.prop' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-prop', rule, { 10 | valid: ['prop()', '[].prop()', 'div.prop()', 'div.prop'], 11 | invalid: [ 12 | { 13 | code: '$("div").prop()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.prop()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().prop()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").prop())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-toggle.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-toggle') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = '$.toggle is not allowed' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-toggle', rule, { 10 | valid: ['toggle()', '[].toggle()', 'div.toggle()', 'div.toggle'], 11 | invalid: [ 12 | { 13 | code: '$("div").toggle()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.toggle()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().toggle()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").toggle())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-filter.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-filter') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer Array#filter to $.filter' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-filter', rule, { 10 | valid: ['filter()', '[].filter()', 'div.filter()', 'div.filter'], 11 | invalid: [ 12 | { 13 | code: '$("div").filter()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.filter()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().filter()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").filter())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-animate.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-animate') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = '$.animate is not allowed' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-animate', rule, { 10 | valid: ['animate()', '[].animate()', 'div.animate()', 'div.animate'], 11 | invalid: [ 12 | { 13 | code: '$("div").animate()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.animate()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().animate()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").animate())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-parent.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-parent') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer parentElement to $.parent' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-parent', rule, { 10 | valid: ['parent()', '[].parent()', 'div.parent()', 'div.parent'], 11 | invalid: [ 12 | { 13 | code: '$("div").parent()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.parent()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().parent()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").parent())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-closest.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-closest') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer closest to $.closest' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-closest', rule, { 10 | valid: ['closest()', '[].closest()', 'div.closest()', 'div.closest'], 11 | invalid: [ 12 | { 13 | code: '$("div").closest()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.closest()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().closest()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").closest())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-parents.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-parents') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer closest to $.parents' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-parents', rule, { 10 | valid: ['parents()', '[].parents()', 'div.parents()', 'div.parents'], 11 | invalid: [ 12 | { 13 | code: '$("div").parents()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.parents()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().parents()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").parents())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-trigger.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-trigger') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer dispatchEvent to $.trigger' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-trigger', rule, { 10 | valid: ['trigger()', '[].trigger()', 'div.trigger()', 'div.trigger'], 11 | invalid: [ 12 | { 13 | code: '$("div").trigger()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.trigger()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().trigger()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").trigger())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-submit.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-submit') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer dispatchEvent + form.submit() to $.submit' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-submit', rule, { 10 | valid: ['submit()', '[].submit()', 'form.submit()', 'form.submit'], 11 | invalid: [ 12 | { 13 | code: '$("form").submit()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$form.submit()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("form").first().submit()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("form").append($("input").submit())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-delegate.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-delegate') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer addEventListener to $.delegate' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-delegate', rule, { 10 | valid: ['delegate()', '[].delegate()', 'div.delegate()', 'div.delegate'], 11 | invalid: [ 12 | { 13 | code: '$("div").delegate()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$div.delegate()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$("div").first().delegate()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").append($("input").delegate())', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | } 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /tests/no-map.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-map') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer Array#map to $.map' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-map', rule, { 10 | valid: ['map()', '[].map()', 'div.map()', 'div.map'], 11 | invalid: [ 12 | { 13 | code: '$.map()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$("div").map()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$div.map()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").first().map()', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | }, 28 | { 29 | code: '$("div").append($("input").map())', 30 | errors: [{message: error, type: 'CallExpression'}] 31 | } 32 | ] 33 | }) 34 | -------------------------------------------------------------------------------- /tests/no-each.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-each') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer Array#forEach to $.each' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-each', rule, { 10 | valid: ['each()', '[].each()', 'div.each()', 'div.each'], 11 | invalid: [ 12 | { 13 | code: '$.each()', 14 | errors: [{message: error, type: 'CallExpression'}] 15 | }, 16 | { 17 | code: '$("div").each()', 18 | errors: [{message: error, type: 'CallExpression'}] 19 | }, 20 | { 21 | code: '$div.each()', 22 | errors: [{message: error, type: 'CallExpression'}] 23 | }, 24 | { 25 | code: '$("div").first().each()', 26 | errors: [{message: error, type: 'CallExpression'}] 27 | }, 28 | { 29 | code: '$("div").append($("input").each())', 30 | errors: [{message: error, type: 'CallExpression'}] 31 | } 32 | ] 33 | }) 34 | -------------------------------------------------------------------------------- /rules/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | function traverse(node) { 4 | while (node) { 5 | switch (node.type) { 6 | case 'CallExpression': 7 | node = node.callee 8 | break 9 | case 'MemberExpression': 10 | node = node.object 11 | break 12 | case 'Identifier': 13 | return node 14 | default: 15 | return null 16 | } 17 | } 18 | } 19 | 20 | // Traverses from a node up to its root parent to determine if it 21 | // originated from a jQuery `$()` function. 22 | // 23 | // node - The CallExpression node to start the traversal. 24 | // 25 | // Examples 26 | // 27 | // // $('div').find('p').first() 28 | // isjQuery(firstNode) // => true 29 | // 30 | // Returns true if the function call node is attached to a jQuery element set. 31 | function isjQuery(node) { 32 | const id = traverse(node) 33 | return id && id.name.startsWith('$') 34 | } 35 | 36 | module.exports = { 37 | traverse: traverse, 38 | isjQuery: isjQuery 39 | } 40 | -------------------------------------------------------------------------------- /rules/no-ready.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | // $(function(){}) 6 | function isDirect(node) { 7 | return ( 8 | node.callee.type === 'Identifier' && 9 | node.callee.name === '$' && 10 | node.arguments[0] && 11 | (node.arguments[0].type === 'FunctionExpression' || 12 | node.arguments[0].type === 'ArrowFunctionExpression') 13 | ) 14 | } 15 | 16 | // $(document).ready() 17 | function isChained(node) { 18 | return ( 19 | node.callee.type === 'MemberExpression' && 20 | node.callee.property.name === 'ready' && 21 | utils.isjQuery(node) 22 | ) 23 | } 24 | 25 | module.exports = { 26 | meta: { 27 | docs: {}, 28 | schema: [] 29 | }, 30 | 31 | create: function (context) { 32 | return { 33 | CallExpression: function (node) { 34 | if (isDirect(node) || isChained(node)) { 35 | context.report({ 36 | node: node, 37 | message: '$.ready is not allowed' 38 | }) 39 | } 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2019 David Graham 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /rules/no-ajax-events.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | const methodName = 'on' 6 | const disallowedEvents = { 7 | ajaxStart: true, 8 | ajaxSend: true, 9 | ajaxSuccess: true, 10 | ajaxError: true, 11 | ajaxComplete: true, 12 | ajaxStop: true 13 | } 14 | 15 | const MemberExpression = 'MemberExpression' 16 | const Literal = 'Literal' 17 | 18 | module.exports = { 19 | meta: { 20 | docs: {}, 21 | schema: [] 22 | }, 23 | 24 | create: function (context) { 25 | return { 26 | CallExpression: function (node) { 27 | if ( 28 | node.callee.type === MemberExpression && 29 | node.callee.property.name === methodName && 30 | node.arguments.length >= 1 31 | ) { 32 | const arg = node.arguments[0] 33 | if ( 34 | arg.type === Literal && 35 | arg.value in disallowedEvents && 36 | utils.isjQuery(node) 37 | ) { 38 | context.report({ 39 | node: node, 40 | message: `Prefer remoteForm to ${arg.value}` 41 | }) 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/no-attr.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-attr') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const getError = 'Prefer getAttribute to $.attr' 7 | const setError = 'Prefer setAttribute to $.attr' 8 | 9 | const ruleTester = new RuleTester() 10 | ruleTester.run('no-attr', rule, { 11 | valid: ['attr()', '[].attr()', 'div.attr()', 'div.attr'], 12 | invalid: [ 13 | { 14 | code: '$("div").attr()', 15 | errors: [{message: getError, type: 'CallExpression'}] 16 | }, 17 | { 18 | code: '$div.attr()', 19 | errors: [{message: getError, type: 'CallExpression'}] 20 | }, 21 | { 22 | code: '$("div").first().attr()', 23 | errors: [{message: getError, type: 'CallExpression'}] 24 | }, 25 | { 26 | code: '$("div").append($("input").attr())', 27 | errors: [{message: getError, type: 'CallExpression'}] 28 | }, 29 | { 30 | code: '$("div").attr("name")', 31 | errors: [{message: getError, type: 'CallExpression'}] 32 | }, 33 | { 34 | code: '$("div").attr("name", "random")', 35 | errors: [{message: setError, type: 'CallExpression'}] 36 | } 37 | ] 38 | }) 39 | -------------------------------------------------------------------------------- /tests/no-data.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-data') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Prefer WeakMap to $.data' 7 | const removeError = 'Prefer WeakMap to $.removeData' 8 | 9 | const ruleTester = new RuleTester() 10 | ruleTester.run('no-data', rule, { 11 | valid: [ 12 | 'data()', 13 | '[].data()', 14 | 'div.data()', 15 | 'div.data', 16 | 17 | 'removeData()', 18 | '[].removeData()', 19 | 'div.removeData()', 20 | 'div.removeData' 21 | ], 22 | invalid: [ 23 | { 24 | code: '$("div").data()', 25 | errors: [{message: error, type: 'CallExpression'}] 26 | }, 27 | { 28 | code: '$div.data()', 29 | errors: [{message: error, type: 'CallExpression'}] 30 | }, 31 | { 32 | code: '$("div").first().data()', 33 | errors: [{message: error, type: 'CallExpression'}] 34 | }, 35 | { 36 | code: '$("div").append($("input").data())', 37 | errors: [{message: error, type: 'CallExpression'}] 38 | }, 39 | { 40 | code: '$("div").removeData()', 41 | errors: [{message: removeError, type: 'CallExpression'}] 42 | }, 43 | { 44 | code: '$div.removeData()', 45 | errors: [{message: removeError, type: 'CallExpression'}] 46 | } 47 | ] 48 | }) 49 | -------------------------------------------------------------------------------- /rules/no-sizzle.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const utils = require('./utils.js') 4 | 5 | module.exports = { 6 | meta: { 7 | docs: {}, 8 | schema: [] 9 | }, 10 | 11 | create: function (context) { 12 | const forbidden = /:animated|:button|:checkbox|:eq|:even|:file|:first([^-]|$)|:gt|:has|:header|:hidden|:image|:input|:last([^-]|$)|:lt|:odd|:parent|:password|:radio|:reset|:selected|:submit|:text|:visible/ 13 | const traversals = [ 14 | 'children', 15 | 'closest', 16 | 'filter', 17 | 'find', 18 | 'has', 19 | 'is', 20 | 'next', 21 | 'nextAll', 22 | 'nextUntil', 23 | 'not', 24 | 'parent', 25 | 'parents', 26 | 'parentsUntil', 27 | 'prev', 28 | 'prevAll', 29 | 'prevUntil', 30 | 'siblings' 31 | ] 32 | 33 | return { 34 | CallExpression: function (node) { 35 | if (!node.arguments[0]) return 36 | if (!utils.isjQuery(node)) return 37 | if ( 38 | node.callee.type === 'MemberExpression' && 39 | traversals.indexOf(node.callee.property.name) === -1 40 | ) 41 | return 42 | 43 | if (forbidden.test(node.arguments[0].value)) { 44 | context.report({ 45 | node: node, 46 | message: 'Selector extensions are not allowed' 47 | }) 48 | } 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/no-ajax.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-ajax') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const ajaxError = 'Prefer fetch to $.ajax' 7 | const getError = 'Prefer fetch to $.get' 8 | const jsonError = 'Prefer fetch to $.getJSON' 9 | const scriptError = 'Prefer fetch to $.getScript' 10 | const postError = 'Prefer fetch to $.post' 11 | 12 | const ruleTester = new RuleTester() 13 | ruleTester.run('no-ajax', rule, { 14 | valid: [ 15 | 'ajax()', 16 | 'div.ajax()', 17 | 'div.ajax', 18 | 19 | 'get()', 20 | 'div.get()', 21 | 'div.get', 22 | 23 | 'getJSON()', 24 | 'div.getJSON()', 25 | 'div.getJSON', 26 | 27 | 'getScript()', 28 | 'div.getScript()', 29 | 'div.getScript', 30 | 31 | 'post()', 32 | 'div.post()', 33 | 'div.post' 34 | ], 35 | invalid: [ 36 | { 37 | code: '$.ajax()', 38 | errors: [{message: ajaxError, type: 'CallExpression'}] 39 | }, 40 | { 41 | code: '$.get()', 42 | errors: [{message: getError, type: 'CallExpression'}] 43 | }, 44 | { 45 | code: '$.getJSON()', 46 | errors: [{message: jsonError, type: 'CallExpression'}] 47 | }, 48 | { 49 | code: '$.getScript()', 50 | errors: [{message: scriptError, type: 'CallExpression'}] 51 | }, 52 | { 53 | code: '$.post()', 54 | errors: [{message: postError, type: 'CallExpression'}] 55 | } 56 | ] 57 | }) 58 | -------------------------------------------------------------------------------- /tests/no-ready.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-ready') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = '$.ready is not allowed' 7 | 8 | const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 6}}) 9 | ruleTester.run('no-ready', rule, { 10 | valid: [ 11 | 'ready(function() { })', 12 | 'ready(() => { })', 13 | 'ready()', 14 | '[].ready()', 15 | 'div.ready()', 16 | 'div.ready', 17 | '$("div")', 18 | '$(document)', 19 | '$()' 20 | ], 21 | invalid: [ 22 | { 23 | code: '$(function() { })', 24 | errors: [{message: error, type: 'CallExpression'}] 25 | }, 26 | { 27 | code: '$(() => { })', 28 | errors: [{message: error, type: 'CallExpression'}] 29 | }, 30 | { 31 | code: '$(function init() { })', 32 | errors: [{message: error, type: 'CallExpression'}] 33 | }, 34 | { 35 | code: '$(document).ready(function() { })', 36 | errors: [{message: error, type: 'CallExpression'}] 37 | }, 38 | { 39 | code: '$(document).ready(() => { })', 40 | errors: [{message: error, type: 'CallExpression'}] 41 | }, 42 | { 43 | code: '$().ready(function() { })', 44 | errors: [{message: error, type: 'CallExpression'}] 45 | }, 46 | { 47 | code: '$("img").ready(function() { })', 48 | errors: [{message: error, type: 'CallExpression'}] 49 | }, 50 | { 51 | code: '$div.ready(function() { })', 52 | errors: [{message: error, type: 'CallExpression'}] 53 | }, 54 | { 55 | code: '$("img").first().ready(function() { })', 56 | errors: [{message: error, type: 'CallExpression'}] 57 | } 58 | ] 59 | }) 60 | -------------------------------------------------------------------------------- /tests/no-serialize.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-serialize') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const serializeError = 'Prefer FormData or URLSearchParams to $.serialize' 7 | const arrayError = 'Prefer FormData or URLSearchParams to $.serializeArray' 8 | 9 | const ruleTester = new RuleTester() 10 | ruleTester.run('no-serialize', rule, { 11 | valid: [ 12 | 'serialize()', 13 | '[].serialize()', 14 | 'div.serialize()', 15 | 'div.serialize', 16 | 17 | 'serializeArray()', 18 | '[].serializeArray()', 19 | 'div.serializeArray()', 20 | 'div.serializeArray' 21 | ], 22 | invalid: [ 23 | { 24 | code: '$("div").serialize()', 25 | errors: [{message: serializeError, type: 'CallExpression'}] 26 | }, 27 | { 28 | code: '$div.serialize()', 29 | errors: [{message: serializeError, type: 'CallExpression'}] 30 | }, 31 | { 32 | code: '$("div").first().serialize()', 33 | errors: [{message: serializeError, type: 'CallExpression'}] 34 | }, 35 | { 36 | code: '$("div").append($("input").serialize())', 37 | errors: [{message: serializeError, type: 'CallExpression'}] 38 | }, 39 | { 40 | code: '$("div").serializeArray()', 41 | errors: [{message: arrayError, type: 'CallExpression'}] 42 | }, 43 | { 44 | code: '$div.serializeArray()', 45 | errors: [{message: arrayError, type: 'CallExpression'}] 46 | }, 47 | { 48 | code: '$("div").first().serializeArray()', 49 | errors: [{message: arrayError, type: 'CallExpression'}] 50 | }, 51 | { 52 | code: '$("div").append($("input").serializeArray())', 53 | errors: [{message: arrayError, type: 'CallExpression'}] 54 | } 55 | ] 56 | }) 57 | -------------------------------------------------------------------------------- /tests/no-ajax-events.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-ajax-events') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const ruleTester = new RuleTester() 7 | ruleTester.run('no-ajax-events', rule, { 8 | valid: [ 9 | '$(document).on("click", function(e){ })', 10 | '$form.on("submit", function(e){ })', 11 | '$form.on()', 12 | 'on("ajaxSuccess", ".js-select-menu", function(e){ })', 13 | 'form.on("ajaxSend")' 14 | ], 15 | invalid: [ 16 | { 17 | code: '$(document).on("ajaxSend", function(e){ })', 18 | errors: [ 19 | { 20 | message: 'Prefer remoteForm to ajaxSend', 21 | type: 'CallExpression' 22 | } 23 | ] 24 | }, 25 | { 26 | code: '$(document).on("ajaxSuccess", function(e){ })', 27 | errors: [ 28 | { 29 | message: 'Prefer remoteForm to ajaxSuccess', 30 | type: 'CallExpression' 31 | } 32 | ] 33 | }, 34 | { 35 | code: '$form.on("ajaxError", function(e){ })', 36 | errors: [ 37 | { 38 | message: 'Prefer remoteForm to ajaxError', 39 | type: 'CallExpression' 40 | } 41 | ] 42 | }, 43 | { 44 | code: '$form.on("ajaxComplete", function(e){ })', 45 | errors: [ 46 | { 47 | message: 'Prefer remoteForm to ajaxComplete', 48 | type: 'CallExpression' 49 | } 50 | ] 51 | }, 52 | { 53 | code: '$form.on("ajaxStart", function(e){ })', 54 | errors: [ 55 | { 56 | message: 'Prefer remoteForm to ajaxStart', 57 | type: 'CallExpression' 58 | } 59 | ] 60 | }, 61 | { 62 | code: '$form.on("ajaxStop", function(e){ })', 63 | errors: [ 64 | { 65 | message: 'Prefer remoteForm to ajaxStop', 66 | type: 'CallExpression' 67 | } 68 | ] 69 | } 70 | ] 71 | }) 72 | -------------------------------------------------------------------------------- /tests/no-slide.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-slide') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const downError = '$.slideDown is not allowed' 7 | const toggleError = '$.slideToggle is not allowed' 8 | const upError = '$.slideUp is not allowed' 9 | 10 | const ruleTester = new RuleTester() 11 | ruleTester.run('no-slide', rule, { 12 | valid: [ 13 | 'slideDown()', 14 | '[].slideDown()', 15 | 'div.slideDown()', 16 | 'div.slideDown', 17 | 18 | 'slideToggle()', 19 | '[].slideToggle()', 20 | 'div.slideToggle()', 21 | 'div.slideToggle', 22 | 23 | 'slideUp()', 24 | '[].slideUp()', 25 | 'div.slideUp()', 26 | 'div.slideUp' 27 | ], 28 | invalid: [ 29 | { 30 | code: '$("div").slideDown()', 31 | errors: [{message: downError, type: 'CallExpression'}] 32 | }, 33 | { 34 | code: '$div.slideDown()', 35 | errors: [{message: downError, type: 'CallExpression'}] 36 | }, 37 | { 38 | code: '$("div").first().slideDown()', 39 | errors: [{message: downError, type: 'CallExpression'}] 40 | }, 41 | { 42 | code: '$("div").append($("input").slideDown())', 43 | errors: [{message: downError, type: 'CallExpression'}] 44 | }, 45 | 46 | { 47 | code: '$("div").slideToggle()', 48 | errors: [{message: toggleError, type: 'CallExpression'}] 49 | }, 50 | { 51 | code: '$div.slideToggle()', 52 | errors: [{message: toggleError, type: 'CallExpression'}] 53 | }, 54 | { 55 | code: '$("div").first().slideToggle()', 56 | errors: [{message: toggleError, type: 'CallExpression'}] 57 | }, 58 | { 59 | code: '$("div").append($("input").slideToggle())', 60 | errors: [{message: toggleError, type: 'CallExpression'}] 61 | }, 62 | 63 | { 64 | code: '$("div").slideUp()', 65 | errors: [{message: upError, type: 'CallExpression'}] 66 | }, 67 | { 68 | code: '$div.slideUp()', 69 | errors: [{message: upError, type: 'CallExpression'}] 70 | }, 71 | { 72 | code: '$("div").first().slideUp()', 73 | errors: [{message: upError, type: 'CallExpression'}] 74 | }, 75 | { 76 | code: '$("div").append($("input").slideUp())', 77 | errors: [{message: upError, type: 'CallExpression'}] 78 | } 79 | ] 80 | }) 81 | -------------------------------------------------------------------------------- /tests/no-fade.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-fade') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const inError = '$.fadeIn is not allowed' 7 | const outError = '$.fadeOut is not allowed' 8 | const toError = '$.fadeTo is not allowed' 9 | const toggleError = '$.fadeToggle is not allowed' 10 | 11 | const ruleTester = new RuleTester() 12 | ruleTester.run('no-fade', rule, { 13 | valid: [ 14 | 'fadeIn()', 15 | '[].fadeIn()', 16 | 'div.fadeIn()', 17 | 'div.fadeIn', 18 | 19 | 'fadeOut()', 20 | '[].fadeOut()', 21 | 'div.fadeOut()', 22 | 'div.fadeOut', 23 | 24 | 'fadeTo()', 25 | '[].fadeTo()', 26 | 'div.fadeTo()', 27 | 'div.fadeTo', 28 | 29 | 'fadeToggle()', 30 | '[].fadeToggle()', 31 | 'div.fadeToggle()', 32 | 'div.fadeToggle' 33 | ], 34 | invalid: [ 35 | { 36 | code: '$("div").fadeIn()', 37 | errors: [{message: inError, type: 'CallExpression'}] 38 | }, 39 | { 40 | code: '$div.fadeIn()', 41 | errors: [{message: inError, type: 'CallExpression'}] 42 | }, 43 | { 44 | code: '$("div").first().fadeIn()', 45 | errors: [{message: inError, type: 'CallExpression'}] 46 | }, 47 | { 48 | code: '$("div").append($("input").fadeIn())', 49 | errors: [{message: inError, type: 'CallExpression'}] 50 | }, 51 | 52 | { 53 | code: '$("div").fadeOut()', 54 | errors: [{message: outError, type: 'CallExpression'}] 55 | }, 56 | { 57 | code: '$div.fadeOut()', 58 | errors: [{message: outError, type: 'CallExpression'}] 59 | }, 60 | { 61 | code: '$("div").first().fadeOut()', 62 | errors: [{message: outError, type: 'CallExpression'}] 63 | }, 64 | { 65 | code: '$("div").append($("input").fadeOut())', 66 | errors: [{message: outError, type: 'CallExpression'}] 67 | }, 68 | 69 | { 70 | code: '$("div").fadeTo()', 71 | errors: [{message: toError, type: 'CallExpression'}] 72 | }, 73 | { 74 | code: '$div.fadeTo()', 75 | errors: [{message: toError, type: 'CallExpression'}] 76 | }, 77 | { 78 | code: '$("div").first().fadeTo()', 79 | errors: [{message: toError, type: 'CallExpression'}] 80 | }, 81 | { 82 | code: '$("div").append($("input").fadeTo())', 83 | errors: [{message: toError, type: 'CallExpression'}] 84 | }, 85 | 86 | { 87 | code: '$("div").fadeToggle()', 88 | errors: [{message: toggleError, type: 'CallExpression'}] 89 | }, 90 | { 91 | code: '$div.fadeToggle()', 92 | errors: [{message: toggleError, type: 'CallExpression'}] 93 | }, 94 | { 95 | code: '$("div").first().fadeToggle()', 96 | errors: [{message: toggleError, type: 'CallExpression'}] 97 | }, 98 | { 99 | code: '$("div").append($("input").fadeToggle())', 100 | errors: [{message: toggleError, type: 'CallExpression'}] 101 | } 102 | ] 103 | }) 104 | -------------------------------------------------------------------------------- /tests/no-wrap.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-wrap') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const wrapError = '$.wrap is not allowed' 7 | const wrapAllError = '$.wrapAll is not allowed' 8 | const wrapInnerError = '$.wrapInner is not allowed' 9 | const unwrapError = '$.unwrap is not allowed' 10 | 11 | const ruleTester = new RuleTester() 12 | ruleTester.run('no-wrap', rule, { 13 | valid: [ 14 | 'wrap()', 15 | '[].wrap()', 16 | 'div.wrap()', 17 | 'div.wrap', 18 | 19 | 'wrapAll()', 20 | '[].wrapAll()', 21 | 'div.wrapAll()', 22 | 'div.wrapAll', 23 | 24 | 'wrapInner()', 25 | '[].wrapInner()', 26 | 'div.wrapInner()', 27 | 'div.wrapInner', 28 | 29 | 'unwrap()', 30 | '[].unwrap()', 31 | 'div.unwrap()', 32 | 'div.unwrap' 33 | ], 34 | invalid: [ 35 | { 36 | code: '$("div").wrap()', 37 | errors: [{message: wrapError, type: 'CallExpression'}] 38 | }, 39 | { 40 | code: '$div.wrap()', 41 | errors: [{message: wrapError, type: 'CallExpression'}] 42 | }, 43 | { 44 | code: '$("div").first().wrap()', 45 | errors: [{message: wrapError, type: 'CallExpression'}] 46 | }, 47 | { 48 | code: '$("div").append($("input").wrap())', 49 | errors: [{message: wrapError, type: 'CallExpression'}] 50 | }, 51 | { 52 | code: '$("div").wrapAll()', 53 | errors: [{message: wrapAllError, type: 'CallExpression'}] 54 | }, 55 | { 56 | code: '$div.wrapAll()', 57 | errors: [{message: wrapAllError, type: 'CallExpression'}] 58 | }, 59 | { 60 | code: '$("div").first().wrapAll()', 61 | errors: [{message: wrapAllError, type: 'CallExpression'}] 62 | }, 63 | { 64 | code: '$("div").append($("input").wrapAll())', 65 | errors: [{message: wrapAllError, type: 'CallExpression'}] 66 | }, 67 | { 68 | code: '$("div").wrapInner()', 69 | errors: [{message: wrapInnerError, type: 'CallExpression'}] 70 | }, 71 | { 72 | code: '$div.wrapInner()', 73 | errors: [{message: wrapInnerError, type: 'CallExpression'}] 74 | }, 75 | { 76 | code: '$("div").first().wrapInner()', 77 | errors: [{message: wrapInnerError, type: 'CallExpression'}] 78 | }, 79 | { 80 | code: '$("div").append($("input").wrapInner())', 81 | errors: [{message: wrapInnerError, type: 'CallExpression'}] 82 | }, 83 | { 84 | code: '$("div").unwrap()', 85 | errors: [{message: unwrapError, type: 'CallExpression'}] 86 | }, 87 | { 88 | code: '$div.unwrap()', 89 | errors: [{message: unwrapError, type: 'CallExpression'}] 90 | }, 91 | { 92 | code: '$("div").first().unwrap()', 93 | errors: [{message: unwrapError, type: 'CallExpression'}] 94 | }, 95 | { 96 | code: '$("div").append($("input").unwrap())', 97 | errors: [{message: unwrapError, type: 'CallExpression'}] 98 | } 99 | ] 100 | }) 101 | -------------------------------------------------------------------------------- /tests/no-class.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-class') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const addError = 'Prefer classList to $.addClass' 7 | const hasError = 'Prefer classList to $.hasClass' 8 | const removeError = 'Prefer classList to $.removeClass' 9 | const toggleError = 'Prefer classList to $.toggleClass' 10 | 11 | const ruleTester = new RuleTester() 12 | ruleTester.run('no-class', rule, { 13 | valid: [ 14 | 'addClass()', 15 | '[].addClass()', 16 | 'div.addClass()', 17 | 'div.addClass', 18 | 19 | 'hasClass()', 20 | '[].hasClass()', 21 | 'div.hasClass()', 22 | 'div.hasClass', 23 | 24 | 'removeClass()', 25 | '[].removeClass()', 26 | 'div.removeClass()', 27 | 'div.removeClass', 28 | 29 | 'toggleClass()', 30 | '[].toggleClass()', 31 | 'div.toggleClass()', 32 | 'div.toggleClass' 33 | ], 34 | invalid: [ 35 | { 36 | code: '$("div").addClass()', 37 | errors: [{message: addError, type: 'CallExpression'}] 38 | }, 39 | { 40 | code: '$div.addClass()', 41 | errors: [{message: addError, type: 'CallExpression'}] 42 | }, 43 | { 44 | code: '$("div").first().addClass()', 45 | errors: [{message: addError, type: 'CallExpression'}] 46 | }, 47 | { 48 | code: '$("div").append($("input").addClass())', 49 | errors: [{message: addError, type: 'CallExpression'}] 50 | }, 51 | { 52 | code: '$("div").hasClass()', 53 | errors: [{message: hasError, type: 'CallExpression'}] 54 | }, 55 | { 56 | code: '$div.hasClass()', 57 | errors: [{message: hasError, type: 'CallExpression'}] 58 | }, 59 | { 60 | code: '$("div").first().hasClass()', 61 | errors: [{message: hasError, type: 'CallExpression'}] 62 | }, 63 | { 64 | code: '$("div").append($("input").hasClass())', 65 | errors: [{message: hasError, type: 'CallExpression'}] 66 | }, 67 | { 68 | code: '$("div").removeClass()', 69 | errors: [{message: removeError, type: 'CallExpression'}] 70 | }, 71 | { 72 | code: '$div.removeClass()', 73 | errors: [{message: removeError, type: 'CallExpression'}] 74 | }, 75 | { 76 | code: '$("div").first().removeClass()', 77 | errors: [{message: removeError, type: 'CallExpression'}] 78 | }, 79 | { 80 | code: '$("div").append($("input").removeClass())', 81 | errors: [{message: removeError, type: 'CallExpression'}] 82 | }, 83 | { 84 | code: '$("div").toggleClass()', 85 | errors: [{message: toggleError, type: 'CallExpression'}] 86 | }, 87 | { 88 | code: '$div.toggleClass()', 89 | errors: [{message: toggleError, type: 'CallExpression'}] 90 | }, 91 | { 92 | code: '$("div").first().toggleClass()', 93 | errors: [{message: toggleError, type: 'CallExpression'}] 94 | }, 95 | { 96 | code: '$("div").append($("input").toggleClass())', 97 | errors: [{message: toggleError, type: 'CallExpression'}] 98 | } 99 | ] 100 | }) 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eslint-plugin-jquery 2 | 3 | Disallow jQuery functions with native equivalents. 4 | 5 | ## Installation 6 | 7 | You'll first need to install [ESLint](http://eslint.org): 8 | 9 | ``` 10 | $ npm install eslint --save-dev 11 | ``` 12 | 13 | Next, install `eslint-plugin-jquery`: 14 | 15 | ``` 16 | $ npm install eslint-plugin-jquery --save-dev 17 | ``` 18 | 19 | **Note:** If you installed ESLint globally (using the `-g` flag) then you must also install `eslint-plugin-jquery` globally. 20 | 21 | ## Usage 22 | 23 | Add `jquery` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix. 24 | 25 | You can either enable individual rules as follows: 26 | ```json 27 | { 28 | "plugins": [ 29 | "jquery" 30 | ], 31 | "rules": { 32 | "jquery/no-ajax": 2, 33 | "jquery/no-ajax-events": 2, 34 | "jquery/no-animate": 2, 35 | "jquery/no-attr": 2, 36 | "jquery/no-bind": 2, 37 | "jquery/no-class": 2, 38 | "jquery/no-clone": 2, 39 | "jquery/no-closest": 2, 40 | "jquery/no-css": 2, 41 | "jquery/no-data": 2, 42 | "jquery/no-deferred": 2, 43 | "jquery/no-delegate": 2, 44 | "jquery/no-each": 2, 45 | "jquery/no-extend": 2, 46 | "jquery/no-fade": 2, 47 | "jquery/no-filter": 2, 48 | "jquery/no-find": 2, 49 | "jquery/no-global-eval": 2, 50 | "jquery/no-grep": 2, 51 | "jquery/no-has": 2, 52 | "jquery/no-hide": 2, 53 | "jquery/no-html": 2, 54 | "jquery/no-in-array": 2, 55 | "jquery/no-is-array": 2, 56 | "jquery/no-is-function": 2, 57 | "jquery/no-is": 2, 58 | "jquery/no-load": 2, 59 | "jquery/no-map": 2, 60 | "jquery/no-merge": 2, 61 | "jquery/no-param": 2, 62 | "jquery/no-parent": 2, 63 | "jquery/no-parents": 2, 64 | "jquery/no-parse-html": 2, 65 | "jquery/no-prop": 2, 66 | "jquery/no-proxy": 2, 67 | "jquery/no-ready": 2, 68 | "jquery/no-serialize": 2, 69 | "jquery/no-show": 2, 70 | "jquery/no-size": 2, 71 | "jquery/no-sizzle": 2, 72 | "jquery/no-slide": 2, 73 | "jquery/no-submit": 2, 74 | "jquery/no-text": 2, 75 | "jquery/no-toggle": 2, 76 | "jquery/no-trigger": 2, 77 | "jquery/no-trim": 2, 78 | "jquery/no-val": 2, 79 | "jquery/no-when": 2, 80 | "jquery/no-wrap": 2 81 | } 82 | } 83 | ``` 84 | 85 | Or you can use the full set of rules: 86 | ```json 87 | { 88 | "plugins": [ 89 | "jquery" 90 | ], 91 | "extends": [ 92 | "plugin:jquery/deprecated" 93 | ] 94 | } 95 | ``` 96 | 97 | Or a subset: 98 | ```json 99 | { 100 | "plugins": [ 101 | "jquery" 102 | ], 103 | "extends": [ 104 | "plugin:jquery/slim" 105 | ] 106 | } 107 | ``` 108 | The `slim` set uses the following rules: `jquery/no-ajax`, `jquery/no-animate`, `jquery/no-fade`, `jquery/no-hide`, `jquery/no-load`, `jquery/no-param`, `jquery/no-serialize`, `jquery/no-show`, `jquery/no-slide`, `jquery/no-toggle`. 109 | 110 | 111 | ## Development 112 | 113 | ``` 114 | npm install 115 | npm test 116 | ``` 117 | 118 | ## License 119 | 120 | Distributed under the MIT license. See LICENSE for details. 121 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | rules: { 5 | 'no-ajax': require('./rules/no-ajax'), 6 | 'no-ajax-events': require('./rules/no-ajax-events'), 7 | 'no-animate': require('./rules/no-animate'), 8 | 'no-attr': require('./rules/no-attr'), 9 | 'no-bind': require('./rules/no-bind'), 10 | 'no-class': require('./rules/no-class'), 11 | 'no-clone': require('./rules/no-clone'), 12 | 'no-closest': require('./rules/no-closest'), 13 | 'no-css': require('./rules/no-css'), 14 | 'no-data': require('./rules/no-data'), 15 | 'no-deferred': require('./rules/no-deferred'), 16 | 'no-delegate': require('./rules/no-delegate'), 17 | 'no-each': require('./rules/no-each'), 18 | 'no-extend': require('./rules/no-extend'), 19 | 'no-fade': require('./rules/no-fade'), 20 | 'no-filter': require('./rules/no-filter'), 21 | 'no-find': require('./rules/no-find'), 22 | 'no-global-eval': require('./rules/no-global-eval'), 23 | 'no-grep': require('./rules/no-grep'), 24 | 'no-has': require('./rules/no-has'), 25 | 'no-hide': require('./rules/no-hide'), 26 | 'no-html': require('./rules/no-html'), 27 | 'no-in-array': require('./rules/no-in-array'), 28 | 'no-is-array': require('./rules/no-is-array'), 29 | 'no-is-function': require('./rules/no-is-function'), 30 | 'no-is': require('./rules/no-is'), 31 | 'no-load': require('./rules/no-load'), 32 | 'no-map': require('./rules/no-map'), 33 | 'no-merge': require('./rules/no-merge'), 34 | 'no-param': require('./rules/no-param'), 35 | 'no-parent': require('./rules/no-parent'), 36 | 'no-parents': require('./rules/no-parents'), 37 | 'no-parse-html': require('./rules/no-parse-html'), 38 | 'no-prop': require('./rules/no-prop'), 39 | 'no-proxy': require('./rules/no-proxy'), 40 | 'no-ready': require('./rules/no-ready'), 41 | 'no-serialize': require('./rules/no-serialize'), 42 | 'no-show': require('./rules/no-show'), 43 | 'no-size': require('./rules/no-size'), 44 | 'no-sizzle': require('./rules/no-sizzle'), 45 | 'no-slide': require('./rules/no-slide'), 46 | 'no-submit': require('./rules/no-submit'), 47 | 'no-text': require('./rules/no-text'), 48 | 'no-toggle': require('./rules/no-toggle'), 49 | 'no-trigger': require('./rules/no-trigger'), 50 | 'no-trim': require('./rules/no-trim'), 51 | 'no-val': require('./rules/no-val'), 52 | 'no-when': require('./rules/no-when'), 53 | 'no-wrap': require('./rules/no-wrap') 54 | }, 55 | configs: { 56 | deprecated: { 57 | rules: { 58 | 'jquery/no-ajax': 2, 59 | 'jquery/no-ajax-events': 2, 60 | 'jquery/no-animate': 2, 61 | 'jquery/no-attr': 2, 62 | 'jquery/no-bind': 2, 63 | 'jquery/no-class': 2, 64 | 'jquery/no-clone': 2, 65 | 'jquery/no-closest': 2, 66 | 'jquery/no-css': 2, 67 | 'jquery/no-data': 2, 68 | 'jquery/no-deferred': 2, 69 | 'jquery/no-delegate': 2, 70 | 'jquery/no-each': 2, 71 | 'jquery/no-extend': 2, 72 | 'jquery/no-fade': 2, 73 | 'jquery/no-filter': 2, 74 | 'jquery/no-find': 2, 75 | 'jquery/no-global-eval': 2, 76 | 'jquery/no-grep': 2, 77 | 'jquery/no-has': 2, 78 | 'jquery/no-hide': 2, 79 | 'jquery/no-html': 2, 80 | 'jquery/no-in-array': 2, 81 | 'jquery/no-is-array': 2, 82 | 'jquery/no-is-function': 2, 83 | 'jquery/no-is': 2, 84 | 'jquery/no-load': 2, 85 | 'jquery/no-map': 2, 86 | 'jquery/no-merge': 2, 87 | 'jquery/no-param': 2, 88 | 'jquery/no-parent': 2, 89 | 'jquery/no-parents': 2, 90 | 'jquery/no-parse-html': 2, 91 | 'jquery/no-prop': 2, 92 | 'jquery/no-proxy': 2, 93 | 'jquery/no-ready': 2, 94 | 'jquery/no-serialize': 2, 95 | 'jquery/no-show': 2, 96 | 'jquery/no-size': 2, 97 | 'jquery/no-sizzle': 2, 98 | 'jquery/no-slide': 2, 99 | 'jquery/no-submit': 2, 100 | 'jquery/no-text': 2, 101 | 'jquery/no-toggle': 2, 102 | 'jquery/no-trigger': 2, 103 | 'jquery/no-trim': 2, 104 | 'jquery/no-val': 2, 105 | 'jquery/no-when': 2, 106 | 'jquery/no-wrap': 2 107 | } 108 | }, 109 | slim: { 110 | rules: { 111 | 'jquery/no-ajax': 2, 112 | 'jquery/no-animate': 2, 113 | 'jquery/no-fade': 2, 114 | 'jquery/no-hide': 2, 115 | 'jquery/no-load': 2, 116 | 'jquery/no-param': 2, 117 | 'jquery/no-serialize': 2, 118 | 'jquery/no-show': 2, 119 | 'jquery/no-slide': 2, 120 | 'jquery/no-toggle': 2 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /tests/no-sizzle.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rule = require('../rules/no-sizzle') 4 | const RuleTester = require('eslint').RuleTester 5 | 6 | const error = 'Selector extensions are not allowed' 7 | 8 | const ruleTester = new RuleTester() 9 | ruleTester.run('no-sizzle', rule, { 10 | valid: [ 11 | 'find(":input")', 12 | 'div.find(":input")', 13 | '$(this).on("custom:input")', 14 | '$(this).on("custom:selected")', 15 | '$(this).find(".selected")', 16 | '$(this).find(":checked")', 17 | '$(this).find("input")', 18 | '$(this).find(":first-child")', 19 | '$(this).find(":first-child div")', 20 | '$(this).find(":last-child")', 21 | '$(this).find(":last-child div")', 22 | '$(this).find($())', 23 | '$(this).find(function() {})', 24 | '$(this).find()', 25 | '$(function() {})' 26 | ], 27 | invalid: [ 28 | { 29 | code: '$(":animated")', 30 | errors: [{message: error, type: 'CallExpression'}] 31 | }, 32 | { 33 | code: '$(":button")', 34 | errors: [{message: error, type: 'CallExpression'}] 35 | }, 36 | { 37 | code: '$(":checkbox")', 38 | errors: [{message: error, type: 'CallExpression'}] 39 | }, 40 | { 41 | code: '$(":eq")', 42 | errors: [{message: error, type: 'CallExpression'}] 43 | }, 44 | { 45 | code: '$(":even")', 46 | errors: [{message: error, type: 'CallExpression'}] 47 | }, 48 | { 49 | code: '$(":file")', 50 | errors: [{message: error, type: 'CallExpression'}] 51 | }, 52 | { 53 | code: '$(":first")', 54 | errors: [{message: error, type: 'CallExpression'}] 55 | }, 56 | { 57 | code: '$(":gt")', 58 | errors: [{message: error, type: 'CallExpression'}] 59 | }, 60 | { 61 | code: '$(":has")', 62 | errors: [{message: error, type: 'CallExpression'}] 63 | }, 64 | { 65 | code: '$(":header")', 66 | errors: [{message: error, type: 'CallExpression'}] 67 | }, 68 | { 69 | code: '$(":hidden")', 70 | errors: [{message: error, type: 'CallExpression'}] 71 | }, 72 | { 73 | code: '$(":image")', 74 | errors: [{message: error, type: 'CallExpression'}] 75 | }, 76 | { 77 | code: '$(":input")', 78 | errors: [{message: error, type: 'CallExpression'}] 79 | }, 80 | { 81 | code: '$(":last")', 82 | errors: [{message: error, type: 'CallExpression'}] 83 | }, 84 | { 85 | code: '$(":lt")', 86 | errors: [{message: error, type: 'CallExpression'}] 87 | }, 88 | { 89 | code: '$(":odd")', 90 | errors: [{message: error, type: 'CallExpression'}] 91 | }, 92 | { 93 | code: '$(":parent")', 94 | errors: [{message: error, type: 'CallExpression'}] 95 | }, 96 | { 97 | code: '$(":password")', 98 | errors: [{message: error, type: 'CallExpression'}] 99 | }, 100 | { 101 | code: '$(":radio")', 102 | errors: [{message: error, type: 'CallExpression'}] 103 | }, 104 | { 105 | code: '$(":reset")', 106 | errors: [{message: error, type: 'CallExpression'}] 107 | }, 108 | { 109 | code: '$(":selected")', 110 | errors: [{message: error, type: 'CallExpression'}] 111 | }, 112 | { 113 | code: '$(":submit")', 114 | errors: [{message: error, type: 'CallExpression'}] 115 | }, 116 | { 117 | code: '$(":text")', 118 | errors: [{message: error, type: 'CallExpression'}] 119 | }, 120 | { 121 | code: '$(":visible")', 122 | errors: [{message: error, type: 'CallExpression'}] 123 | }, 124 | { 125 | code: '$("div").children(":first")', 126 | errors: [{message: error, type: 'CallExpression'}] 127 | }, 128 | { 129 | code: '$("div").closest(":first")', 130 | errors: [{message: error, type: 'CallExpression'}] 131 | }, 132 | { 133 | code: '$("div").filter(":first")', 134 | errors: [{message: error, type: 'CallExpression'}] 135 | }, 136 | { 137 | code: '$("div").find(":first")', 138 | errors: [{message: error, type: 'CallExpression'}] 139 | }, 140 | { 141 | code: '$("div").has(":first")', 142 | errors: [{message: error, type: 'CallExpression'}] 143 | }, 144 | { 145 | code: '$("div").is(":first")', 146 | errors: [{message: error, type: 'CallExpression'}] 147 | }, 148 | { 149 | code: '$("div").next(":first")', 150 | errors: [{message: error, type: 'CallExpression'}] 151 | }, 152 | { 153 | code: '$("div").nextAll(":first")', 154 | errors: [{message: error, type: 'CallExpression'}] 155 | }, 156 | { 157 | code: '$("div").nextUntil(":first")', 158 | errors: [{message: error, type: 'CallExpression'}] 159 | }, 160 | { 161 | code: '$("div").not(":first")', 162 | errors: [{message: error, type: 'CallExpression'}] 163 | }, 164 | { 165 | code: '$("div").parent(":first")', 166 | errors: [{message: error, type: 'CallExpression'}] 167 | }, 168 | { 169 | code: '$("div").parents(":first")', 170 | errors: [{message: error, type: 'CallExpression'}] 171 | }, 172 | { 173 | code: '$("div").parentsUntil(":first")', 174 | errors: [{message: error, type: 'CallExpression'}] 175 | }, 176 | { 177 | code: '$("div").prev(":first")', 178 | errors: [{message: error, type: 'CallExpression'}] 179 | }, 180 | { 181 | code: '$("div").prevAll(":first")', 182 | errors: [{message: error, type: 'CallExpression'}] 183 | }, 184 | { 185 | code: '$("div").prevUntil(":first")', 186 | errors: [{message: error, type: 'CallExpression'}] 187 | }, 188 | { 189 | code: '$("div").siblings(":first")', 190 | errors: [{message: error, type: 'CallExpression'}] 191 | }, 192 | { 193 | code: '$("div:first")', 194 | errors: [{message: error, type: 'CallExpression'}] 195 | }, 196 | { 197 | code: '$("div:first").find("p")', 198 | errors: [{message: error, type: 'CallExpression'}] 199 | }, 200 | { 201 | code: '$("div").find("p:first").addClass("test").find("p")', 202 | errors: [{message: error, type: 'CallExpression'}] 203 | }, 204 | { 205 | code: '$("div").find(":first")', 206 | errors: [{message: error, type: 'CallExpression'}] 207 | }, 208 | { 209 | code: '$("div").find("div:animated")', 210 | errors: [{message: error, type: 'CallExpression'}] 211 | }, 212 | { 213 | code: '$div.find("form input:checkbox")', 214 | errors: [{message: error, type: 'CallExpression'}] 215 | } 216 | ] 217 | }) 218 | --------------------------------------------------------------------------------