├── .github └── workflows │ └── validate.yml ├── .gitignore ├── .npmignore ├── .npmrc ├── LICENSE ├── README.md ├── eslintrc.json ├── index.js ├── package.json └── test ├── basic.js └── validate-config.js /.github/workflows/validate.yml: -------------------------------------------------------------------------------- 1 | name: validate 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | main: 13 | strategy: 14 | matrix: 15 | eslint: [8.0.0, 8] 16 | node: [12.22.0, 12, 14.17.0, 14, 16.0.0, 16] 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: 🛑 Cancel Previous Runs 20 | uses: styfle/cancel-workflow-action@0.9.1 21 | 22 | - name: ⬇️ Checkout repo 23 | uses: actions/checkout@v2 24 | 25 | - name: ⎔ Setup node 26 | uses: actions/setup-node@v2 27 | with: 28 | node-version: ${{ matrix.node }} 29 | 30 | - name: 📥 Download deps 31 | uses: bahmutov/npm-install@v1 32 | with: 33 | useLockFile: false 34 | 35 | - name: Install ESLint v${{ matrix.eslint }} 36 | run: npm install --no-save --force eslint@${{ matrix.eslint }} 37 | 38 | - name: ▶️ Run tests 39 | run: npm test 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .github/ 2 | test/ 3 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Feross Aboukhadijeh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eslint-config-standard-jsx [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][downloads-url] [![javascript style guide][standard-image]][standard-url] 2 | 3 | [travis-image]: https://img.shields.io/travis/standard/eslint-config-standard-jsx/master.svg 4 | [travis-url]: https://travis-ci.org/standard/eslint-config-standard-jsx 5 | [npm-image]: https://img.shields.io/npm/v/eslint-config-standard-jsx.svg 6 | [npm-url]: https://npmjs.org/package/eslint-config-standard-jsx 7 | [downloads-image]: https://img.shields.io/npm/dm/eslint-config-standard-jsx.svg 8 | [downloads-url]: https://npmjs.org/package/eslint-config-standard-jsx 9 | [standard-image]: https://img.shields.io/badge/code_style-standard-brightgreen.svg 10 | [standard-url]: https://standardjs.com 11 | 12 | #### An ESLint [Shareable Config](http://eslint.org/docs/developer-guide/shareable-configs) for JSX support in [JavaScript Standard Style](http://standardjs.com) 13 | 14 | [![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](http://standardjs.com) 15 | 16 | ## Install 17 | 18 | This module is for advanced users. You probably want to use [`standard`](http://standardjs.com) instead :) 19 | 20 | ```bash 21 | npm install eslint-config-standard-jsx 22 | ``` 23 | 24 | ## Usage 25 | 26 | Shareable configs are designed to work with the `extends` feature of `.eslintrc` files. 27 | You can learn more about 28 | [Shareable Configs](http://eslint.org/docs/developer-guide/shareable-configs) on the 29 | official ESLint website. 30 | 31 | This Shareable Config adds extra JSX style rules to the baseline JavaScript Standard Style 32 | rules provided in 33 | [`eslint-config-standard`](https://www.npmjs.com/package/eslint-config-standard). 34 | It doesn't assume that you're using React, so other virtual DOM libraries like 35 | `virtual-dom` and `deku` are supported. 36 | 37 | Even though this config is JSX only (no React), it makes use of 38 | [`eslint-plugin-react`](https://npmjs.com/package/eslint-plugin-react) for its generic 39 | JSX rules. 40 | 41 | (If you want React-specific rules too, consider using 42 | [`eslint-config-standard-react`](https://www.npmjs.com/package/eslint-config-standard-react) 43 | instead.) 44 | 45 | Here's how to install everything you need: 46 | 47 | ```bash 48 | npm install --save-dev eslint-config-standard eslint-config-standard-jsx eslint-plugin-promise eslint-plugin-import eslint-plugin-node eslint-plugin-react 49 | ``` 50 | 51 | Then, add this to your .eslintrc file: 52 | 53 | ``` 54 | { 55 | "extends": ["standard", "standard-jsx"] 56 | } 57 | ``` 58 | 59 | *Note: We omitted the `eslint-config-` prefix since it is automatically assumed by ESLint.* 60 | 61 | You can override settings from the shareable config by adding them directly into your 62 | `.eslintrc` file. 63 | 64 | ### Looking for something easier than this? 65 | 66 | The easiest way to use JavaScript Standard Style to check your code is to use the 67 | [`standard`](http://standardjs.com) package. This comes with a global 68 | Node command line program (`standard`) that you can run or add to your `npm test` script 69 | to quickly check your style. 70 | 71 | ## Badge 72 | 73 | Use this in one of your projects? Include one of these badges in your readme to 74 | let people know that your code is using the standard style. 75 | 76 | [![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](http://standardjs.com) 77 | 78 | ```markdown 79 | [![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](http://standardjs.com) 80 | ``` 81 | 82 | [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com) 83 | 84 | ```markdown 85 | [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com) 86 | ``` 87 | 88 | ## Learn more 89 | 90 | For the full listing of rules, editor plugins, FAQs, and more, visit the main 91 | [JavaScript Standard Style repo](http://standardjs.com). 92 | 93 | ## License 94 | 95 | MIT. Copyright (c) [Feross Aboukhadijeh](http://feross.org). 96 | -------------------------------------------------------------------------------- /eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 2022, 4 | "ecmaFeatures": { 5 | "jsx": true 6 | }, 7 | "sourceType": "module" 8 | }, 9 | 10 | "plugins": [ 11 | "react" 12 | ], 13 | 14 | "settings": { 15 | "react": { 16 | "version": "17" 17 | }, 18 | "linkComponents": [ 19 | "Link" 20 | ] 21 | }, 22 | 23 | "rules": { 24 | "jsx-quotes": ["error", "prefer-single"], 25 | "react/jsx-boolean-value": "error", 26 | "react/jsx-closing-bracket-location": ["error", "tag-aligned"], 27 | "react/jsx-closing-tag-location": "error", 28 | "react/jsx-curly-brace-presence": ["error", { 29 | "props": "never", 30 | "children": "never" 31 | }], 32 | "react/jsx-curly-newline": ["error", { 33 | "multiline": "consistent", 34 | "singleline": "consistent" 35 | }], 36 | "react/jsx-curly-spacing": ["error", { 37 | "attributes": { "when": "never", "allowMultiline": true }, 38 | "children": { "when": "never", "allowMultiline": true } 39 | }], 40 | "react/jsx-equals-spacing": ["error", "never"], 41 | "react/jsx-first-prop-new-line": ["error", "multiline-multiprop"], 42 | "react/jsx-fragments": ["error", "syntax"], 43 | "react/jsx-handler-names": "error", 44 | "react/jsx-indent": ["error", 2, { 45 | "checkAttributes": false, 46 | "indentLogicalExpressions": true 47 | }], 48 | "react/jsx-indent-props": ["error", 2], 49 | "react/jsx-key": ["error", { 50 | "checkFragmentShorthand": true 51 | }], 52 | "react/jsx-no-comment-textnodes": "error", 53 | "react/jsx-no-duplicate-props": "error", 54 | "react/jsx-no-target-blank": ["error", { "enforceDynamicLinks": "always" }], 55 | "react/jsx-no-undef": ["error", { "allowGlobals": true }], 56 | "react/jsx-pascal-case": ["error", { "allowAllCaps": false }], 57 | "react/jsx-props-no-multi-spaces": "error", 58 | "react/jsx-tag-spacing": ["error", { 59 | "closingSlash": "never", 60 | "beforeSelfClosing": "always", 61 | "afterOpening": "never", 62 | "beforeClosing": "never" 63 | }], 64 | "react/jsx-uses-react": "error", 65 | "react/jsx-uses-vars": "error", 66 | "react/jsx-wrap-multilines": ["error", { 67 | "declaration": "parens-new-line", 68 | "assignment": "parens-new-line", 69 | "return": "parens-new-line", 70 | "arrow": "ignore", 71 | "condition": "ignore", 72 | "logical": "ignore", 73 | "prop": "ignore" 74 | }], 75 | "react/no-children-prop": "error", 76 | "react/no-danger-with-children": "error", 77 | "react/no-deprecated": "error", 78 | "react/no-direct-mutation-state": "error", 79 | "react/no-find-dom-node": "error", 80 | "react/no-is-mounted": "error", 81 | "react/no-string-refs": ["error", { 82 | "noTemplateLiterals": true 83 | }], 84 | "react/no-unescaped-entities": ["error", { 85 | "forbid": [">", "}"] 86 | }], 87 | "react/no-render-return-value": "error", 88 | "react/require-render-return": "error", 89 | "react/self-closing-comp": "error" 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! eslint-config-standard-jsx. MIT License. Feross Aboukhadijeh */ 2 | module.exports = require('./eslintrc.json') 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-config-standard-jsx", 3 | "description": "JavaScript Standard Style JSX support - ESLint Shareable Config", 4 | "version": "11.0.0", 5 | "author": { 6 | "name": "Feross Aboukhadijeh", 7 | "email": "feross@feross.org", 8 | "url": "https://feross.org" 9 | }, 10 | "bugs": { 11 | "url": "https://github.com/standard/eslint-config-standard-jsx/issues" 12 | }, 13 | "devDependencies": { 14 | "@types/eslint": "^8.4.1", 15 | "@types/tape": "^4.13.2", 16 | "eslint": "^8.8.0", 17 | "eslint-plugin-react": "^7.28.0", 18 | "tape": "^5.5.0" 19 | }, 20 | "homepage": "https://github.com/standard/eslint-config-standard-jsx", 21 | "keywords": [ 22 | "JavaScript Standard Style", 23 | "check", 24 | "checker", 25 | "code", 26 | "code checker", 27 | "code linter", 28 | "code standards", 29 | "code style", 30 | "enforce", 31 | "eslint", 32 | "eslintconfig", 33 | "hint", 34 | "jscs", 35 | "jshint", 36 | "jsx", 37 | "lint", 38 | "policy", 39 | "quality", 40 | "simple", 41 | "standard", 42 | "standard style", 43 | "style", 44 | "style checker", 45 | "style linter", 46 | "verify" 47 | ], 48 | "license": "MIT", 49 | "main": "index.js", 50 | "peerDependencies": { 51 | "eslint": "^8.8.0", 52 | "eslint-plugin-react": "^7.28.0" 53 | }, 54 | "repository": { 55 | "type": "git", 56 | "url": "git://github.com/standard/eslint-config-standard-jsx.git" 57 | }, 58 | "scripts": { 59 | "test": "tape test/*.js" 60 | }, 61 | "funding": [ 62 | { 63 | "type": "github", 64 | "url": "https://github.com/sponsors/feross" 65 | }, 66 | { 67 | "type": "patreon", 68 | "url": "https://www.patreon.com/feross" 69 | }, 70 | { 71 | "type": "consulting", 72 | "url": "https://feross.org/support" 73 | } 74 | ] 75 | } 76 | -------------------------------------------------------------------------------- /test/basic.js: -------------------------------------------------------------------------------- 1 | const config = require('../') 2 | const test = require('tape') 3 | 4 | test('test basic properties of config', function (t) { 5 | t.ok(isObject(config.parserOptions)) 6 | t.ok(isObject(config.rules)) 7 | t.ok(Array.isArray(config.plugins)) 8 | t.end() 9 | }) 10 | 11 | function isObject (obj) { 12 | return typeof obj === 'object' && obj !== null 13 | } 14 | -------------------------------------------------------------------------------- /test/validate-config.js: -------------------------------------------------------------------------------- 1 | const { ESLint } = require('eslint') 2 | const test = require('tape') 3 | 4 | test('load config in eslint to validate all rule syntax is correct', async t => { 5 | const cli = new ESLint({ 6 | useEslintrc: false, 7 | overrideConfigFile: 'eslintrc.json' 8 | }) 9 | 10 | const code = 'var foo = 1\nvar bar = function () {}\nbar(foo)\n' 11 | 12 | const result = await cli.lintText(code) 13 | 14 | t.equal(result.length, 1, 'Should return a single result item') 15 | t.equal(result[0].errorCount, 0, 'The result item should show no errors') 16 | t.end() 17 | }) 18 | 19 | test('space before an opening tag\'s closing bracket should not be allowed', async t => { 20 | const cli = new ESLint({ 21 | useEslintrc: false, 22 | overrideConfigFile: 'eslintrc.json' 23 | }) 24 | 25 | const shouldPass = { 26 | selfClosing: '
', 27 | withChildren: ` 28 |
29 | test 30 |
31 | `, 32 | withChildrenWithPropsMultiLine: ` 33 |
37 | test 38 |
39 | ` 40 | } 41 | 42 | const shouldFail = { 43 | selfClosing: '
', 44 | openingTag: ` 45 |
46 | test 47 |
48 | `, 49 | closingTag: ` 50 |
51 | test 52 |
53 | ` 54 | } 55 | 56 | const testPlansCount = Object.keys(shouldPass).length + Object.keys(shouldFail).length 57 | 58 | t.plan(testPlansCount * 2) 59 | 60 | for (const testCase in shouldPass) { 61 | const result = await cli.lintText(shouldPass[testCase]) 62 | t.equal(result.length, 1, 'Should return a single result item') 63 | t.equal(result[0].errorCount, 0, 'The result item should show no errors') 64 | } 65 | 66 | for (const testCase in shouldFail) { 67 | const result = await cli.lintText(shouldFail[testCase]) 68 | t.equal(result.length, 1, 'Should return a single result item') 69 | t.true(result[0].errorCount > 0, 'The result item should have errors') 70 | } 71 | }) 72 | --------------------------------------------------------------------------------