pax_global_header00006660000000000000000000000064136742533620014525gustar00rootroot0000000000000052 comment=97f23ad0141e84712bf24feb7aad332617792752 eslint-plugin-eslint-plugin-2.3.0/000077500000000000000000000000001367425336200171115ustar00rootroot00000000000000eslint-plugin-eslint-plugin-2.3.0/.eslintrc.yml000066400000000000000000000006731367425336200215430ustar00rootroot00000000000000plugins: - node - self extends: - not-an-aardvark/node - plugin:node/recommended - plugin:self/all root: true rules: comma-dangle: - error - arrays: always-multiline objects: always-multiline functions: never # disallow trailing commas in function(es2017) require-jsdoc: error self/meta-property-ordering: off self/require-meta-docs-url: off self/report-message-format: - error - '^[^a-z].*\.$' eslint-plugin-eslint-plugin-2.3.0/.gitignore000066400000000000000000000000641367425336200211010ustar00rootroot00000000000000node_modules/ npm-debug.log .vscode .idea yarn.lock eslint-plugin-eslint-plugin-2.3.0/.npmrc000066400000000000000000000000251367425336200202260ustar00rootroot00000000000000package-lock = false eslint-plugin-eslint-plugin-2.3.0/.travis.yml000066400000000000000000000001051367425336200212160ustar00rootroot00000000000000language: node_js node_js: - '6' - '8' - '9' - '10' - '11' eslint-plugin-eslint-plugin-2.3.0/CHANGELOG.md000066400000000000000000000560721367425336200207340ustar00rootroot00000000000000# Changelog ## v2.3.0 (2020-06-23) * New: Add rule `prefer-object-rule` ([#101](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/101)) ([7f625f4](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/7f625f425332fc8028cbba38b8d4b93f0849dd62)) ## v2.2.2 (2020-06-10) * Fix: handle spreads in rule meta objects ([#100](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/100)) ([45a09a6](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/45a09a67942c55230fcae893633c1911b089a514)) * Docs: Fix incorrect rule reference in meta-property-ordering ([#96](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/96)) ([68059b1](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/68059b1ed2cb2710a4d6c4aa1d05afad8de565f0)) * Upgrade: eslint and other deps ([#92](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/92)) ([93d082c](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/93d082cce48da79bf7305df70e4fd0061b482e88)) ## v2.2.1 (2020-01-17) * Fix: update `require-meta-schema` rule to allow object schemas (in addition to array schemas) ([#90](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/90)) ([e582cb6](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/e582cb61d0f51c15a8e5d9e38c82d1c73f2d6edd)) ## v2.2.0 (2020-01-08) * Update: Add new rule `require-meta-docs-description` ([#89](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/89)) ([b175b46](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/b175b46732033c99e26e5380d83ea94727c15218)) * New: add `always` option to `consistent-output` rule ([#88](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/88)) ([8c74f24](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/8c74f242431de0d809f7be2801d4d889340fe84e)) * New: add new rule `require-meta-schema` ([#87](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/87)) ([10b28f0](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/10b28f03d12a4770db3433b3b9cedface0d480d4)) * Fix: Check for meta type even when using a function reference ([#84](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/84)) ([38ad521](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/38ad521963b4e10d001ef91314a637c1028972cf)) * Chore: fix incorrect test cases. ([#82](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/82)) ([c86c224](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/c86c22453bc9cb9aad536985f4361c7c9d3de096)) ## v2.1.0 (2019-05-08) * New: meta-property-ordering (fixes [#62](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/62)) ([#80](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/80)) ([aebf1cf](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/aebf1cf2023e014aa8778fe457bfa5c8a4c876fc)) * Revert "Update: add plugins: ['eslint-plugin'] in configs" ([#76](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/76)) ([9bab974](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/9bab97423656bb40a4cd199034c5a167e89b822e)) * Update: add plugins: ['eslint-plugin'] in configs ([bb71efa](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/bb71efaec765691c1cb85bd6d8d6b46a5ae0c960)) ## v2.0.1 (2018-12-22) * Fix: allow to use generator function as fix in fixer-return ([#75](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/75)) ([7556633](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/7556633ce349ec78a90fe7986d6090726e84c048)) * Fix: require-meta-type crash when has no meta property ([#73](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/73)) ([bc9b1a0](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/bc9b1a01cc3fcc9d115615c7e107f08c6bb0538c)) ## v2.0.0 (2018-12-08) * New: require-meta-type (fixes [#67](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/67)) ([#68](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/68)) ([7f87941](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/7f8794159aae178fdd6f069ed9d4dee27367633a)) * Update: ensure report-message-format checks formatting in meta.messages ([#72](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/72)) ([1ffb48a](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/1ffb48aec79c278562729698bff93493ee5ac20e)) * Upgrade: dev dependcies to latest ([#69](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/69)) ([9dad54f](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/9dad54f6b3e148068f6322011f4c5c63bd4178c0)) * Breaking: require node >= 6 & eslint >= 5 (fixes [#70](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/70)) ([#71](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/71)) ([c1778af](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/c1778af090dc88f122101e3cf6ea653b5bc49778)) ## v1.4.1 (2018-10-24) * Fix: no-deprecated-report-api should consider spread operator(fixes [#64](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/64)) ([#65](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/65)) ([ec7a34c](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/ec7a34c562123b78494a256c3f233fc0ff759e50)) * Chore: fix linting errors ([#66](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/66)) ([a128650](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/a12865059fb625a8c2fc123d81d636d825d3d9d8)) ## v1.4.0 (2018-01-27) * New: require-meta-docs-url (fixes [#55](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/55)) ([#56](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/56)) ([114d2c7](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/114d2c7aa1539d2271069ab54863bd3825fb7ec0)) ## v1.3.0 (2018-01-08) * Update: add meta.docs.url to rules ([eb207d0](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/eb207d0ef650e9f91f7f7ca3be2ab8cbe762f0d3)) * Docs: fix some errors in rule example. ([#52](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/52)) ([bd97347](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/bd9734768d0da32806f9c2bae6f0327f7f8427b3)) * Docs: fix prefer-replace-text doc name. ([#51](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/51)) ([786fc92](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/786fc92aa9d02c3a5cb75a7ca8417b5b7017b8d5)) * New: rule prefer-replace-text ([#50](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/50)) ([f0d27d5](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/f0d27d50f0b2d89bd3c38f9ffa02a8b8210f083d)) * Docs: http => https. ([#49](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/49)) ([86d3ebf](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/86d3ebfe80f6021bfac826b49f7c975542a64b70)) * Chore: add vscode to gitignore. ([#48](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/48)) ([0f64dc1](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/0f64dc15368c3d558d4d304c95f3fadccff4c456)) * Build: autogenerate the table in README.md (fixes [#43](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/43)) ([#46](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/46)) ([efae7da](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/efae7daaeecc96545aac3714c043e4b564aa0edd)) * Update: add --fix to prefer-output-null. ([#44](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/44)) ([0fc99af](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/0fc99af38a5217b698a0cff6c391496ecf2720aa)) * Docs: add no-deprecated-context-methods fixable. ([#45](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/45)) ([cf563fb](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/cf563fb48d1376ebf9031daa80f6c520ce80b893)) * Docs: add missing fixable icon to `no-deprecated-context-methods` ([#42](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/42)) ([3597af5](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/3597af584d02a4805516ff766e8deb62456301f6)) ## v1.2.0 (2017-09-10) * New: no-deprecated-context-methods rule (fixes [#40](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/40)) ([#41](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/41)) ([8931504](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/8931504a891dd95ccc60d3e75e93826cc5f56091)) ## v1.1.0 (2017-09-08) * Chore: add release script ([#39](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/39)) ([3454d60](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/3454d604bb98a4f06ffd32c2a70e183426b20c39)) * Update: utils.getTestInfo filter elements equal to null (fixes [#37](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/37)). ([#38](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/38)) ([7b33446](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/7b33446cd90c9f928618b59f6da1b9e05a8ea34f)) ## v1.0.0 (2017-08-31) * Fix: some rules crashing if tests array has missing elements (fixes [#35](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/35)). ([#36](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/36)) ([e3a14e1](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/e3a14e11d86836b1ab63d19c689327fea8f8a4bc)) * Breaking: update ESLint peerDependency to >=4.1.0 ([#33](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/33)) ([7cabcdc](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/7cabcdcae32ae67fc3769804aad5e5d8882b3baa)) * Chore: use local variable. ([#34](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/34)) ([e04a4bc](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/e04a4bc15963efdff6309549e34c51cfa2c2ea74)) * Update: add autofixing to test-case-property-ordering. (fixes [#31](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/31)) ([#32](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/32)) ([23f9010](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/23f90106a5c8b3cf1a785989d6c9ec798da339a9)) ## v0.8.0 (2017-07-26) * Breaking: add no-unused-placeholders to recommended. ([#29](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/29)) ([882c36a](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/882c36a075be72b136e75eef14b13f09cf3fc27b)) * Docs: fix rulename in example. ([#28](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/28)) ([6a9fb15](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/6a9fb15a34efb72691a8aa79ba23efc5f3e1f255)) * New: rule no-unused-placeholders. ([#26](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/26)) ([a090610](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/a090610265260d681dcf55f45b16252d957ec262)) * Chore: use utils.getReportInfo ([#27](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/27)) ([c9b07ce](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/c9b07ce9c4637ec03280ece8fe9aef16a7528ac0)) * Breaking: add some rules to recommended config ([#25](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/25)) ([8ac484c](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/8ac484c68e7314d6977855c1901541f6a3f5dc20)) * Update: no-identical-tests despite of properties order. ([#21](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/21)) ([223da80](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/223da80bd918d02bc1038434c382e13303deb6fe)) * New: rule test-case-property-ordering ([#16](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/16)) ([6137274](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/6137274a28a5b3036bc41933d96222ab6ed1c6a0)) * Chore: upgrade deps. ([#24](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/24)) ([b30c176](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/b30c17630da23c885f4c49d25da1da0289610737)) * Fix: linting errors. ([#23](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/23)) ([8d8526f](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/8d8526fe02ea5704469fb07df53970bcfdfeaec2)) * Fix: prefer-output-null crashes, when a test case is not object. ([#22](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/22)) ([7c7c772](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/7c7c772f2cb1850eaf364d69a29e49f9c954479a)) * New: fixer-return ([#15](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/15)) ([93bd142](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/93bd142cbf6159561099ad5e3cdfd8f1f90503f5)) * New: rule prefer-output-null ([#20](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/20)) ([9f98ac4](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/9f98ac45c6bbeb5b1be894e646d43dabf86befae)) * Docs: rules to be alphabetical. ([#18](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/18)) ([4cec353](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/4cec353c272d6dd799ba3c30cd4f06b103b0c7e8)) * Chore: upgrade eslint-config-not-an-aardvark@2.1.0 ([e079baf](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/e079baf5e33a4045162969a7490cb1e869963bf0)) * Update: add --fix to no-identical-tests. ([#13](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/13)) ([ca607c4](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/ca607c43aba3101cf68ed79a2c58636cbc96cfb3)) * Chore: disable package-lock.json ([#14](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/14)) ([b41a2b8](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/b41a2b86ea4e405080089cd9def20c9a0a027e36)) * Upgrade: eslint-plugin-self@1.0.1 ([3fc9cc3](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/3fc9cc3d72aff315341f916f09b753bfa4aa5350)) ## v0.7.4 (2017-07-01) * New: no-identical-tests rule ([#11](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/11)) ([8c19ab5](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/8c19ab5eb8942e35f102ca300a83ac73f67ce26f)) ## v0.7.3 (2017-07-01) * Update: support ESLint v4 ([e361d63](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/e361d63753092178edbdde36dbdbf5cc96b7817c)) * Chore: add Node 8 to travis ([9ee1ad3](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/9ee1ad376fa0a6f211bbbea5880a3962103c708f)) * Chore: remove identical tests ([#12](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/12)) ([82c6892](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/82c6892d0a4f5eb3f8f508b04643447ac7ba03e9)) * Chore: use eslint-plugin-self (fixes [#10](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/10)) ([58a927a](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/58a927a9d7d7f699a2ae70619c7e102a8fcdc547)) * Upgrade: espree to 3.4.3 ([#9](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/9)) ([3dfc4c6](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/3dfc4c6ff8ff1141a7f6aea80f81f28fd0499a9d)) ## v0.7.2 (2017-05-09) * Docs: update readme to indicate test-case-shorthand-strings is fixable ([e480d08](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/e480d082087064b306a489d9b101d3398ff6af22)) * Update: add fixer for test-case-shorthand-strings ([9fcf4a6](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/9fcf4a6060804a30d215985c99944fb955ea8a95)) * Docs: add example to consistent-output with output: null ([e2e3de3](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/e2e3de320c7f3f051df56f65fe3bea4826a23a54)) ## v0.7.1 (2017-02-22) * Fix: incorrect category for consistent-output ([308b048](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/308b048140e65a2b3b39023df2ab9ea814e754b4)) ## v0.7.0 (2017-02-22) * New: consistent-output rule ([64ed898](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/64ed898ad504a507551f6ebcbcd88f1c34bea61a)) * Docs: add directive comment to no-useless-token-range docs ([667e36f](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/667e36f015efdd532678d008ea06bc1f9aacadf4)) ## v0.6.0 (2017-02-22) * Docs: add travis badge to README.md ([55388b2](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/55388b28acb926e517c7d1acb67ede66f0845316)) * Breaking: add no-useless-token-range to recommended config ([277d11c](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/277d11cb323130e0e3870894b145ff03a9f6bf10)) * New: no-useless-token-range rule ([4537737](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/45377379b76ba0ce869d1179eaf4afd5e1c5ee21)) ## v0.5.0 (2017-02-01) * New: prefer-placeholders rule ([de03394](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/de033940546a791a12b800adc46f9bc32b24fef2)) * Chore: unify logic for parsing context.report() arguments ([d14cd05](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/d14cd055adb282d7aacfcfcadee44b0bbb8b3d4a)) * New: add more presets ([2fa5e7f](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/2fa5e7fbc664d6eaff6ffcc2aa26b1436d0b442f)) ## v0.4.0 (2017-02-01) * Chore: remove errors from valid test case ([815bf07](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/815bf073f8086e98eb57b31f3a60c8dd07f4a13b)) * Chore: enable test-case-shorthand-strings on this codebase ([558f1db](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/558f1dbc0635809e410b24b2e8be45fe9aa9b8e4)) * Docs: Remove incorrect "recommended" marking for report-message-format ([48b7e34](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/48b7e347f8346bf66b8169ac0ec5d78e77d43cb1)) * New: test-case-shorthand-strings rule ([cbbc49f](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/cbbc49f52ab447df68f340282ef821a44800e280)) ## v0.3.0 (2017-01-27) * Breaking: add no-missing-placeholders to eslint-plugin:recommended ([833d094](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/833d094a2b4ee4a9460264979b5a7a61d7182595)) * New: no-missing-placeholders rule ([a995733](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/a995733b0f3a555d946f7e8818396d0983fa8cc8)) ## v0.2.1 (2016-12-14) * Fix: check the type of the first arg of the old context.report() API ([29dc51c](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/29dc51c81749dd66d6d6b1861f307d8bd6947b89)) * Docs: Add require-meta-fixable to the list of rules in the readme ([45dac85](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/45dac8544547980a751532877c012c53b5e9224b)) ## v0.2.0 (2016-12-14) * Chore: refactor utils.getRuleInfo ([5f8dbd8](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/5f8dbd8a9a6eb4084081aef6adb543463d83474b)) * Fix: report-message-format crash on reporting empty object ([f32ada6](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/f32ada66623eb54385afcbf4516931ad94de0336)) * Breaking: add require-meta-fixable to recommended config ([0a1e1fa](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/0a1e1fa0fb24fdb2099a689f2cf47fc5ba98d832)) * New: require-meta-fixable rule ([59bfdd6](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/59bfdd62929d1b611f226e6b321a76ea69017154)) * Chore: Prohibit small letters as the first character of report messages ([7a74a7b](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/7a74a7b46680a9cf58c4b96da40e1d1a6ae5bcba)) * Fix: incorrect no-deprecated-report-api autofix if > 5 arguments passed ([2bd6cba](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/2bd6cba9209ea46eddbc33063c005b2586b96bd4)) * Update: improve the error location for no-deprecated-report-api ([937bafa](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/937bafa7710adb8e11c6f581485b44d367097f5f)) * Fix: report-message-format crash when calling report() with no arguments ([292d141](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/292d141ef7ef949ac0e92deeb70b9d836b65935a)) * Update: improve the report location for report-message-format ([15f3192](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/15f31929f23e163924f1e217e064eeac23de5276)) * Chore: use string placeholders for the message in report-message-format ([b5a13f6](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/b5a13f6699ba652ca3d44d459cdfcda3f8800443)) * Chore: enable report-message-format for this plugin's rules ([ad60708](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/ad607080d02736aa9b9aa46969ddd99b2a474dc6)) * Build: ensure the .eslintrc.js file is linted when running tests ([7abbbf5](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/7abbbf5db745861751f4bc0ac2202bd1b84328f1)) * Build: Dogfood this plugin's rules on its own codebase ([e345dc5](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/e345dc5670b343ef8dd1800aa84c096633a6f879)) * Chore: refactor no-deprecated-report-api to use getContextIdentifiers ([1914f17](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/1914f17cb5170c632a15d5c7e9bdc9fb19fd109b)) * Chore: fix comment indentation in no-deprecated-report-api ([c64e3d8](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/c64e3d86af82592fcb3b95500463dc69f9dc90df)) * New: report-message-format rule ([ffab432](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/ffab432d1351a2a3f759efc2a922d28e3cabdf90)) * Chore: add npm-debug.log to .gitignore ([63415f8](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/63415f899adc2bbddf8c1b9e4c78a02a78a9eec9)) ## v0.1.0 (2016-12-13) * New: Add a 'recommended' config ([7b9ec01](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/7b9ec012286f4c16af27e79db7e449916c56c3c6)) * New: no-deprecated-report-api rule ([06a6e5a](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/06a6e5ae81328ba37e8360ca5ad7498939059031)) * New: initial commit ([8b0ae4f](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/commit/8b0ae4f30014e9526af02ecba518f5edfd38c2b9)) eslint-plugin-eslint-plugin-2.3.0/LICENSE.md000066400000000000000000000021221367425336200205120ustar00rootroot00000000000000The MIT License (MIT) ===================== Copyright © 2016 Teddy Katz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. eslint-plugin-eslint-plugin-2.3.0/README.md000066400000000000000000000146501367425336200203760ustar00rootroot00000000000000# eslint-plugin-eslint-plugin [![Build Status](https://travis-ci.org/not-an-aardvark/eslint-plugin-eslint-plugin.svg?branch=master)](https://travis-ci.org/not-an-aardvark/eslint-plugin-eslint-plugin) An ESLint plugin for linting ESLint plugins ## Installation You'll first need to install [ESLint](https://eslint.org): ``` $ npm i eslint --save-dev ``` Next, install `eslint-plugin-eslint-plugin`: ``` $ npm install eslint-plugin-eslint-plugin --save-dev ``` **Note:** If you installed ESLint globally (using the `-g` flag) then you must also install `eslint-plugin-eslint-plugin` globally. ## Usage Add `eslint-plugin` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix: ```json { "plugins": [ "eslint-plugin" ] } ``` Then configure the rules you want to use under the rules section. ```json { "rules": { "eslint-plugin/no-deprecated-report-api": "error" } } ``` ## Supported Rules ✔️ indicates that a rule is recommended for all users. 🛠 indicates that a rule is fixable. Name | ✔️ | 🛠 | Description ----- | ----- | ----- | ----- [consistent-output](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/consistent-output.md) | | | enforce consistent use of output assertions in rule tests [fixer-return](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/fixer-return.md) | ✔️ | | require fixer function to always return a value. [meta-property-ordering](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/meta-property-ordering.md) | | 🛠 | enforce the order of meta properties [no-deprecated-context-methods](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/no-deprecated-context-methods.md) | | 🛠 | disallow usage of deprecated methods on rule context objects [no-deprecated-report-api](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/no-deprecated-report-api.md) | ✔️ | 🛠 | disallow use of the deprecated context.report() API [no-identical-tests](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/no-identical-tests.md) | ✔️ | 🛠 | disallow identical tests [no-missing-placeholders](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/no-missing-placeholders.md) | ✔️ | | disallow missing placeholders in rule report messages [no-unused-placeholders](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/no-unused-placeholders.md) | ✔️ | | disallow unused placeholders in rule report messages [no-useless-token-range](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/no-useless-token-range.md) | ✔️ | 🛠 | disallow unnecessary calls to sourceCode.getFirstToken and sourceCode.getLastToken [prefer-object-rule](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/prefer-object-rule.md) | | 🛠 | disallow rule exports where the export is a function. [prefer-output-null](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/prefer-output-null.md) | | 🛠 | disallow invalid RuleTester test cases with the output the same as the code. [prefer-placeholders](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/prefer-placeholders.md) | | | disallow template literals as report messages [prefer-replace-text](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/prefer-replace-text.md) | | | require using replaceText instead of replaceTextRange. [report-message-format](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/report-message-format.md) | | | enforce a consistent format for rule report messages [require-meta-docs-description](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-docs-description.md) | | | require rules to implement a meta.docs.description property with the correct format [require-meta-docs-url](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-docs-url.md) | | 🛠 | require rules to implement a meta.docs.url property [require-meta-fixable](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-fixable.md) | ✔️ | | require rules to implement a meta.fixable property [require-meta-schema](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-schema.md) | | 🛠 | require rules to implement a meta.schema property [require-meta-type](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-type.md) | | | require rules to implement a meta.type property [test-case-property-ordering](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/test-case-property-ordering.md) | | 🛠 | require the properties of a test case to be placed in a consistent order [test-case-shorthand-strings](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/test-case-shorthand-strings.md) | | 🛠 | enforce consistent usage of shorthand strings for test cases with no options ## Supported Presets Presets are enabled by adding a line to the `extends` list in your config file. For example, to enable the `recommended` preset, use: ```json { "extends": [ "plugin:eslint-plugin/recommended" ] } ``` * `recommended` enables all recommended rules from this plugin. * `rules-recommended` enables all recommended rules that are aimed at linting ESLint rule files. * `tests-recommended` enables all recommended rules that are aimed at linting ESLint test files. * `all` enables all rules in this plugin. * `rules` enables all rules that are aimed at linting ESLint rule files. * `tests` enables all rules that are aimed at linting ESLint test files. The list of recommended rules will only change in a major release of this plugin. However, new non-recommended rules might be added in a minor release of this plugin. Therefore, the using the `all`, `rules`, and `tests` presets is **not recommended for production use**, because the addition of new rules in a minor release could break your build. eslint-plugin-eslint-plugin-2.3.0/build/000077500000000000000000000000001367425336200202105ustar00rootroot00000000000000eslint-plugin-eslint-plugin-2.3.0/build/generate-readme-table.js000066400000000000000000000030731367425336200246630ustar00rootroot00000000000000'use strict'; const fs = require('fs'); const path = require('path'); const rules = require('..').rules; const README_LOCATION = path.resolve(__dirname, '..', 'README.md'); const BEGIN_TABLE_MARKER = '\n'; const END_TABLE_MARKER = '\n'; const expectedTableLines = Object.keys(rules) .sort() .reduce((lines, ruleId) => { const rule = rules[ruleId]; lines.push([ `[${ruleId}](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/${ruleId}.md)`, rule.meta.docs.recommended ? '✔️' : '', rule.meta.fixable ? '🛠' : '', rule.meta.docs.description, ].join(' | ')); return lines; }, ['Name | ✔️ | 🛠 | Description', '----- | ----- | ----- | -----']) .join('\n'); const readmeContents = fs.readFileSync(README_LOCATION, 'utf8'); if (!readmeContents.includes(BEGIN_TABLE_MARKER)) { throw new Error(`Could not find '${BEGIN_TABLE_MARKER}' marker in README.md.`); } if (!readmeContents.includes(END_TABLE_MARKER)) { throw new Error(`Could not find '${END_TABLE_MARKER}' marker in README.md.`); } const linesStartIndex = readmeContents.indexOf(BEGIN_TABLE_MARKER) + BEGIN_TABLE_MARKER.length; const linesEndIndex = readmeContents.indexOf(END_TABLE_MARKER); const updatedReadmeContents = readmeContents.slice(0, linesStartIndex) + expectedTableLines + readmeContents.slice(linesEndIndex); if (module.parent) { module.exports = updatedReadmeContents; } else { fs.writeFileSync(README_LOCATION, updatedReadmeContents); } eslint-plugin-eslint-plugin-2.3.0/docs/000077500000000000000000000000001367425336200200415ustar00rootroot00000000000000eslint-plugin-eslint-plugin-2.3.0/docs/rules/000077500000000000000000000000001367425336200211735ustar00rootroot00000000000000eslint-plugin-eslint-plugin-2.3.0/docs/rules/consistent-output.md000066400000000000000000000032661367425336200252530ustar00rootroot00000000000000# Enforce consistent use of output assertions in rule tests (consistent-output) When writing tests for a fixable rule with `RuleTester`, you can assert the autofix output of your test cases. However, it can be easy to forget to assert the output of a particular test case. ## Rule Details This rule aims to ensure that if any invalid test cases have output assertions, then all test cases have output assertions. Examples of **incorrect** code for this rule: ```js /* eslint eslint-plugin/consistent-output: error */ new RuleTester().run('example-rule', rule, { valid: [], invalid: [ { code: 'foo', output: 'bar', errors: ['baz'] }, { code: 'bar', errors: ['baz'] } ] }); ``` Examples of **correct** code for this rule: ```js /* eslint eslint-plugin/consistent-output: error */ new RuleTester().run('example-rule', rule, { valid: [], invalid: [ { code: 'foo', output: 'bar', errors: ['baz'] }, { code: 'bar', output: 'qux', errors: ['baz'] }, { code: 'foo', output: null, errors: ['baz'] } ] }); ``` ## Options This rule takes an optional string enum option with one of the following values: * `"consistent"` - (default) if any invalid test cases have output assertions, then all invalid test cases must have output assertions * `"always"` - always require invalid test cases to have output assertions ## When Not To Use It If you're not writing fixable rules, or you want to write test cases without output assertions, do not enable this rule. ## Further Reading * [`RuleTester` documentation](http://eslint.org/docs/developer-guide/working-with-plugins#testing) eslint-plugin-eslint-plugin-2.3.0/docs/rules/fixer-return.md000066400000000000000000000016101367425336200241450ustar00rootroot00000000000000# Enforces always return from a fixer function (fixer-return) In a fixable rule, missing return from a fixer function will not apply fixes. ## Rule Details This rule enforces that fixer functions always return a value. Examples of **incorrect** code for this rule: ```js /* eslint eslint-plugin/fixer-return: error */ module.exports = { create: function(context) { context.report( { fix: function(fixer) { fixer.foo(); } }); } }; ``` Examples of **correct** code for this rule: ```js /* eslint eslint-plugin/fixer-return: error */ module.exports = { create: function(context) { context.report( { fix: function(fixer) { return fixer.foo(); } }); } }; ``` ## When Not To Use It If you don't want to enforce always return from a fixer function, do not enable this rule. eslint-plugin-eslint-plugin-2.3.0/docs/rules/meta-property-ordering.md000066400000000000000000000026371367425336200261440ustar00rootroot00000000000000# enforce ordering of meta properties in rule source (meta-property-ordering) (fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#fix) automatically fixes problems reported by this rule. This rule enforces that meta properties of a rule are placed in a consistent order. ## Rule Details ### Options This rule has an array option: * `['type', 'docs', 'fixable', 'schema', 'messages', 'deprecated', 'replacedBy']` (default): The order that the properties of `meta` should be placed in. Examples of **incorrect** code for this rule: ```js /* eslint eslint-plugin/meta-property-ordering: ["error", ["type", "docs", "fixable", "schema", "messages"] ] */ // invalid; wrong order. module.exports = { meta: { docs: "", type: "problem", fixable: "code", }, create() {}, } // invalid; extra properties must be placed afterwards. module.exports = { meta: { type: "problem", fooooooooo: "foo", docs: "", fixable: "code", }, create() {}, } ``` Examples of **correct** code for this rule: ```js /* eslint eslint-plugin/meta-property-ordering: ["error", ["type", "docs", "fixable", "schema", "messages"] ] */ // valid; module.exports = { meta: { type: "bar", docs: "foo", messages: ["zoo"], fooooooooo: "foo", }, create() {}, } ``` ## When Not To Use It If don't want to enforce ordering of meta properties, you can turn off this rule. eslint-plugin-eslint-plugin-2.3.0/docs/rules/no-deprecated-context-methods.md000066400000000000000000000033021367425336200273500ustar00rootroot00000000000000# Disallows usage of deprecated methods on rule context objects (no-deprecated-context-methods) (fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#fix) automatically fixes problems reported by this rule. This rule disallows the use of deprecated methods on rule `context` objects. The deprecated methods are: * `getSource` * `getSourceLines` * `getAllComments` * `getNodeByRangeIndex` * `getComments` * `getCommentsBefore` * `getCommentsAfter` * `getCommentsInside` * `getJSDocComment` * `getFirstToken` * `getFirstTokens` * `getLastToken` * `getLastTokens` * `getTokenAfter` * `getTokenBefore` * `getTokenByRangeStart` * `getTokens` * `getTokensAfter` * `getTokensBefore` * `getTokensBetween` Instead of using these methods, you should use the equivalent methods on [`SourceCode`](https://eslint.org/docs/developer-guide/working-with-rules#contextgetsourcecode), e.g. `context.getSourceCode().getText()` instead of `context.getSource()`. ## Rule Details Examples of **incorrect** code for this rule: ```js module.exports = { create(context) { return { Program(node) { const firstToken = context.getFirstToken(node); } } } } ``` Examples of **correct** code for this rule: ```js module.exports = { create(context) { const sourceCode = context.getSourceCode(); return { Program(node) { const firstToken = sourceCode.getFirstToken(node); } } } }; ``` ## When Not To Use It If you need to support very old versions of ESLint where `SourceCode` doesn't exist, you should not enable this rule. ## Further Reading * [`SourceCode` API](https://eslint.org/docs/developer-guide/working-with-rules#contextgetsourcecode) eslint-plugin-eslint-plugin-2.3.0/docs/rules/no-deprecated-report-api.md000066400000000000000000000026041367425336200263110ustar00rootroot00000000000000# disallow use of the deprecated context.report() API (no-deprecated-report-api) (fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#fix) automatically fixes problems reported by this rule. ESLint has two APIs that rules can use to report problems. The [deprecated API](http://eslint.org/docs/developer-guide/working-with-rules-deprecated) accepts multiple arguments: `context.report(node, [loc], message)`. The ["new API"](http://eslint.org/docs/developer-guide/working-with-rules#contextreport) accepts a single argument: an object containing information about the reported problem. It is recommended that all rules use the new API. ## Rule Details This rule aims to disallow use of the deprecated `context.report(node, [loc], message)` API. The following patterns are considered warnings: ```js module.exports = { create(context) { context.report(node, 'This node is bad.'); context.report(node, loc, 'This node is bad.'); } }; ``` The following patterns are not warnings: ```js module.exports = { create(context) { context.report({ node, message: 'This node is bad.' }); context.report({ node, loc, message: 'This node is bad.' }); } }; ``` ## Further Reading * [Deprecated rule API](http://eslint.org/docs/developer-guide/working-with-rules-deprecated) * [New rule API](http://eslint.org/docs/developer-guide/working-with-rules) eslint-plugin-eslint-plugin-2.3.0/docs/rules/no-identical-tests.md000066400000000000000000000016431367425336200252270ustar00rootroot00000000000000# Disallow identical tests (no-identical-tests) (fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#fix) automatically fixes problems reported by this rule. When a rule has a lot of tests, it's sometimes difficult to tell if any tests are duplicates. This rule would warn if any test cases have the same properties. ## Rule Details Examples of **incorrect** code for this rule: ```js /* eslint eslint-plugin/no-identical-tests: error */ new RuleTester().run('foo', bar, { valid: [ { code: 'foo' }, { code: 'foo' } ], invalid: [] }); ``` Examples of **correct** code for this rule: ```js /* eslint eslint-plugin/no-identical-tests: error */ new RuleTester().run('foo', bar, { valid: [ { code: 'foo' }, { code: 'bar' } ], invalid: [] }); ``` ## When Not To Use It If you want to allow identical tests, do not enable this rule. eslint-plugin-eslint-plugin-2.3.0/docs/rules/no-missing-placeholders.md000066400000000000000000000033601367425336200262450ustar00rootroot00000000000000# Disallow missing placeholders in rule report messages (no-missing-placeholders) Report messages in rules can have placeholders surrounded by curly brackets. ```js context.report({ node, message: '{{disallowedNode}} nodes are not allowed.', data: { disallowedNode: node.type } }); // Resulting message: e.g. 'IfStatement nodes are not allowed.' ``` However, if no `data` argument is provided, or no matching replacement key exists in the `data` argument, the raw curly brackets will end up in the report message. This is usually a mistake. ## Rule Details This rule aims to disallow missing placeholders in rule report messages. Examples of **incorrect** code for this rule: ```js /*eslint eslint-plugin/no-missing-placeholders: error*/ module.exports = { create(context) { context.report({ node, message: '{{something}} is wrong.' }); context.report({ node, message: '{{something}} is wrong.', data: { somethingElse: 'foo' } }); context.report(node, '{{something}} is wrong.', { somethingElse: 'foo' }); } }; ``` Examples of **correct** code for this rule: ```js /*eslint eslint-plugin/no-missing-placeholders: error*/ module.exports = { create(context) { context.report({ node, message: 'something is wrong.' }); context.report({ node, message: '{{something}} is wrong.', data: { something: 'foo' } }); context.report(node, '{{something}} is wrong.', { something: 'foo' }); } }; ``` ## When Not To Use It If you want to use rule messages that actually contain double-curly bracket text, you should turn off this rule. ## Further Reading * [context.report() API](http://eslint.org/docs/developer-guide/working-with-rules#contextreport) eslint-plugin-eslint-plugin-2.3.0/docs/rules/no-unused-placeholders.md000066400000000000000000000026311367425336200260770ustar00rootroot00000000000000# Disallow unused placeholders in rule report messages (no-unused-placeholders) This rule aims to disallow unused placeholders in rule report messages. ## Rule Details Reports when a context.report call contains a data property that does not have a corresponding placeholder in the report message. Examples of **incorrect** code for this rule: ```js /*eslint eslint-plugin/no-unused-placeholders: error*/ module.exports = { create(context) { context.report({ node, message: 'something is wrong.', data: { something: 'foo' } }); context.report(node, 'something is wrong.', { something: 'foo' }); } }; ``` Examples of **correct** code for this rule: ```js /*eslint eslint-plugin/no-unused-placeholders: error*/ module.exports = { create(context) { context.report({ node, message: 'something is wrong.' }); context.report({ node, message: '{{something}} is wrong.', data: { something: 'foo' } }); context.report(node, '{{something}} is wrong.', { something: 'foo' }); } }; ``` ## When Not To Use It If you want to allow unused placeholders, you should turn off this rule. ## Further Reading * [context.report() API](http://eslint.org/docs/developer-guide/working-with-rules#contextreport) * [no-missing-placeholders](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/no-missing-placeholders.md) eslint-plugin-eslint-plugin-2.3.0/docs/rules/no-useless-token-range.md000066400000000000000000000027631367425336200260320ustar00rootroot00000000000000# Disallow unnecessary calls to sourceCode.getFirstToken and sourceCode.getLastToken (no-useless-token-range) AST nodes always start and end with tokens. As a result, the start index of the first token in a node is the same as the start index of the node itself, and the end index of the last token in a node is the same as the end index of the node itself. Using code like `sourceCode.getFirstToken(node).range[0]` unnecessarily hurts the performance of your rule, and makes your code less readable. ## Rule Details This rule aims to avoid unnecessary calls to `sourceCode.getFirstToken` and `sourceCode.getLastToken`. Examples of **incorrect** code for this rule: ```js /* eslint eslint-plugin/no-useless-token-range: error */ module.exports = { create(context) { const sourceCode = context.getSourceCode(); const rangeStart = sourceCode.getFirstToken(node).range[0]; const rangeEnd = sourceCode.getLastToken(node).range[1]; } }; ``` Examples of **correct** code for this rule: ```js /* eslint eslint-plugin/no-useless-token-range: error */ module.exports = { create(context) { const sourceCode = context.getSourceCode(); const rangeStart = node.range[0]; const rangeEnd = node.range[1]; } }; ``` ## Known Limitations * To ensure that your `SourceCode` instances can be detected, your rule must assign `context.getSourceCode()` to a variable somewhere. ## Further Reading * [`SourceCode` API](https://eslint.org/docs/developer-guide/working-with-rules#contextgetsourcecode) eslint-plugin-eslint-plugin-2.3.0/docs/rules/prefer-object-rule.md000066400000000000000000000021461367425336200252140ustar00rootroot00000000000000# Disallow rule exports where the export is a function. (prefer-object-rule) (fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#fix) automatically fixes problems reported by this rule. ## Rule Details The rule reports an error if it encounters a rule that's defined using the old style of just a `create` function. Examples of **incorrect** code for this rule: ```js /* eslint eslint-plugin/prefer-object-rule: error */ module.exports = function (context) { return { Program() { context.report() } }; }; module.exports = function create(context) { return { Program() { context.report() } }; }; module.exports = (context) => { return { Program() { context.report() } }; }; ``` Examples of **correct** code for this rule: ```js /* eslint eslint-plugin/prefer-object-rule: error */ module.exports = { create(context) { return { Program() { context.report() } }; }, }; module.exports = { create(context) { return { Program() { context.report() } }; }, }; module.exports = { create: (context) => { return { Program() { context.report() } }; }, }; ``` eslint-plugin-eslint-plugin-2.3.0/docs/rules/prefer-output-null.md000066400000000000000000000015451367425336200253130ustar00rootroot00000000000000# Disallows invalid RuleTester test cases with the output the same as the code. (prefer-output-null) (fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#fix) automatically fixes problems reported by this rule. ## Rule Details The rule reports an error if it encounters a test case where the output is the same as the code. Examples of **incorrect** code for this rule: ```js /* eslint eslint-plugin/prefer-output-null: error */ new RuleTester().run('foo', bar, { valid: [], invalid: [ { code: 'foo', output: 'foo', errors: [{ message: 'bar' }] }, ] }); ``` Examples of **correct** code for this rule: ```js /* eslint eslint-plugin/prefer-output-null: error */ new RuleTester().run('foo', bar, { valid: [], invalid: [ { code: 'foo', output: null, errors: [{ message: 'bar' }] }, ] }); ``` eslint-plugin-eslint-plugin-2.3.0/docs/rules/prefer-placeholders.md000066400000000000000000000031311367425336200254410ustar00rootroot00000000000000# disallow template literals as report messages (prefer-placeholders) Report messages in rules can have placeholders surrounded by curly brackets. ```js context.report({ node, message: '{{disallowedNode}} nodes are not allowed.', data: { disallowedNode: node.type } }); ``` Using placeholders is often preferred over using dynamic report messages, for a few reasons: * They can help enforce a separation of the message and the data. * It will be easier to migrate when ESLint starts supporting placing lint messages in metadata (see [#6740](https://github.com/eslint/eslint/issues/6740)) ## Rule Details This rule aims to report string concatenation and template literals in report messages. Examples of **incorrect** code for this rule: ```js /* eslint eslint-plugin/prefer-placeholders: error */ module.exports = { create(context) { context.report({ node, message: `The node ${node.name} is not allowed to be used.` }); context.report({ node, message: 'The node ' + node.name + ' is not allowed to be used.' }); } }; ``` Examples of **correct** code for this rule: ```js /* eslint eslint-plugin/prefer-placeholders: error */ module.exports = { create(context) { context.report({ node, message: 'The node {{name}} is not allowed to be used.', data: { name: node.name } }); } }; ``` ## When Not To Use It If you need to use string concatenation in your report messages for some reason, don't turn on this rule. ## Further Reading * [context.report() API](http://eslint.org/docs/developer-guide/working-with-rules#contextreport) eslint-plugin-eslint-plugin-2.3.0/docs/rules/prefer-replace-text.md000066400000000000000000000022711367425336200253750ustar00rootroot00000000000000# prefer using replaceText instead of replaceTextRange. (prefer-replace-text) ## Rule Details The rule reports an error if `replaceTextRange`'s first argument is an array of identical array elements. It can be easily replaced by `replaceText` to improve readability. Examples of **incorrect** code for this rule: ```js /* eslint eslint-plugin/prefer-replace-text: error */ module.exports = { create(context) { context.report({ fix(fixer) {        // error, can be written: return fixer.replaceText([node, '']); return fixer.replaceTextRange([node.range[0], node.range[1]], ''); } }); } }; ``` Examples of **correct** code for this rule: ```js /* eslint eslint-plugin/prefer-replace-text: error */ module.exports = { create(context) { context.report({ fix(fixer) { return fixer.replaceText(node, ''); } }); } }; module.exports = { create(context) { context.report({ fix(fixer) { // start = ... // end = ... return fixer.replaceTextRange([start, end], ''); } }); } }; ``` ## Further Reading * [Applying Fixes](https://eslint.org/docs/developer-guide/working-with-rules#applying-fixes) eslint-plugin-eslint-plugin-2.3.0/docs/rules/report-message-format.md000066400000000000000000000033711367425336200257440ustar00rootroot00000000000000# enforce a consistent format for rule report messages (report-message-format) It is sometimes desirable to maintain consistent formatting for all report messages. For example, you might want to mandate that all report messages begin with a capital letter and end with a period. ## Rule Details This rule aims to enforce a consistent format for rule report messages. ### Options This rule has a string option. The string should be a regular expression that all report messages must match. For example, in order to mandate that all report messages begin with a capital letter and end with a period, you can use the following configuration: ```json { "rules": { "eslint-plugin/report-message-format": ["error", "^[A-Z].*\\.$"] }, "plugins": [ "eslint-plugin" ] } ``` Note that since this rule uses static analysis and does not actually run your code, it will attempt to match report messages *before* placeholders are inserted. The following patterns are considered warnings: ```js /* eslint eslint-plugin/report-message-format: ["error", "^[A-Z].*\\.$"] */ module.exports = { meta: {}, create(context) { context.report(node, 'this message does not match the regular expression.'); context.report(node, 'Neither does this one'); context.report(node, 'This will get reported, regardless of the value of the {{placeholder}}', { placeholder: foo }) } }; ``` The following patterns are not warnings: ```js module.exports = { meta: {}, create(context) { context.report(node, 'This message matches the regular expression.'); context.report(node, 'So does this one.'); } }; ``` ## When Not To Use It If you don't want to enforce consistent formatting for your report messages, you can turn off this rule. eslint-plugin-eslint-plugin-2.3.0/docs/rules/require-meta-docs-description.md000066400000000000000000000025101367425336200273620ustar00rootroot00000000000000# require rules to implement a meta.docs.description property (require-meta-docs-description) Defining a clear and consistent description for each rule helps developers understand what they're used for. In particular, each rule description should begin with an allowed prefix: * `enforce` * `require` * `disallow` ## Rule Details This rule requires ESLint rules to have a valid `meta.docs.description` property. Examples of **incorrect** code for this rule: ```js /* eslint eslint-plugin/require-meta-docs-description: error */ module.exports = { meta: {}, create: function(context) { /* ... */} }; module.exports = { meta: { description: 'this rule does ...' }, // missing allowed prefix create: function(context) { /* ... */} }; ``` Examples of **correct** code for this rule: ```js /* eslint eslint-plugin/require-meta-docs-description: error */ module.exports = { meta: { description: 'disallow unused variables' }, create: function(context) { /* ... */} }; ``` ## Options This rule takes an optional object containing: - `String` — `pattern` — A regular expression that the description must match. Use `'.+'` to allow anything. Defaults to `^(enforce|require|disallow)`. ## Further Reading * [working-with-rules#options-schemas](https://eslint.org/docs/developer-guide/working-with-rules#options-schemas) eslint-plugin-eslint-plugin-2.3.0/docs/rules/require-meta-docs-url.md000066400000000000000000000056461367425336200256560ustar00rootroot00000000000000# require rules to implement a meta.docs.url property (require-meta-docs-url) `meta.docs.url` property is the official location to store a URL to their documentation in the rule metadata. Some integration tools will show the URL to users to understand rules. ## Rule Details This rule aims to require ESLint rules to have a `meta.docs.url` property. This rule has an option. ```json { "eslint-plugin/require-meta-docs-url": ["error", { "pattern": "https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/{{name}}.md" }] } ``` - `pattern` (`string`) ... A pattern to enforce rule's document URL. It replaces `{{name}}` placeholder by each rule name. The rule name is the basename of each rule file. Default is undefined. If you set the `pattern` option, this rule adds `meta.docs.url` property automatically when you execute `eslint --fix` command. The following patterns are considered warnings: ```js /* eslint eslint-plugin/require-meta-docs-url: "error" */ module.exports = { meta: {}, create(context) { } }; ``` ```js /* eslint eslint-plugin/require-meta-docs-url: "error" */ module.exports = { meta: { docs: { url: undefined } }, create(context) { } }; ``` ```js /* eslint eslint-plugin/require-meta-docs-url: ["error", {"pattern": "path/to/{{name}}.md"}] */ module.exports = { meta: { docs: { url: "wrong URL" } }, create(context) { } }; ``` The following patterns are not warnings: ```js /* eslint eslint-plugin/require-meta-docs-url: "error" */ module.exports = { meta: { docs: { url: "a URL" } }, create(context) { } }; ``` ```js /* eslint eslint-plugin/require-meta-docs-url: ["error", {"pattern": "path/to/{{name}}.md"}] */ module.exports = { meta: { docs: { url: "path/to/rule-name.md" } }, create(context) { } }; ``` ## Version specific URL If you want to enforce version-specific URLs, it's feasible easily with `.eslintrc.js` and `npm version ` script. For example: **.eslintrc.js**: ```js "use strict" const version = require("./package.json").version module.exports = { plugins: ["eslint-plugin"], // ... leaving out ... rules: { "eslint-plugin/require-meta-docs-url": ["error", { pattern: `path/to/v${version}/docs/rules/{{name}}.md`, }], } } ``` **package.json**: ```json { "version": "1.0.0", "scripts": { "pretest": "eslint .", "test": "... leaving out ...", "preversion": "npm test", "version": "eslint . --fix && git add ." }, // ... leaving out ... } ``` Then `npm version ` command will update every rule to the new version's URL. > npm runs `preversion` script on the current version, runs `version` script on the new version, and commits and makes a tag. > > Further reading: https://docs.npmjs.com/cli/version ## When Not To Use It If you do not plan to provide rule's documentation in website, you can turn off this rule. eslint-plugin-eslint-plugin-2.3.0/docs/rules/require-meta-fixable.md000066400000000000000000000036221367425336200255300ustar00rootroot00000000000000# require rules to implement a meta.fixable property (require-meta-fixable) A fixable ESLint rule must have a valid `meta.fixable` property. A rule reports a problem with a `fix()` function but does not export a `meta.fixable` property is likely to cause an unexpected error. ## Rule Details This rule aims to require ESLint rules to have a `meta.fixable` property if necessary. The following patterns are considered warnings: ```js /* eslint eslint-plugin/require-meta-fixable: "error" */ module.exports = { meta: {}, create(context) { context.report({ node, message: 'foo', fix(fixer) { return fixer.remove(node); } }); } }; ``` ```js /* eslint eslint-plugin/require-meta-fixable: "error" */ module.exports = { meta: { fixable: 'not a valid meta.fixable value' }, create(context) { context.report({ node, message: 'foo', fix(fixer) { return fixer.remove(node); } }); } }; ``` ```js /* eslint eslint-plugin/require-meta-fixable: "error" */ module.exports = function create(context) { context.report({ node, message: 'foo', fix(fixer) { return fixer.remove(node); } }); }; ``` The following patterns are not warnings: ```js /* eslint eslint-plugin/require-meta-fixable: "error" */ module.exports = { meta: { fixable: 'code' }, create(context) { context.report({ node, message: 'foo', fix(fixer) { return fixer.remove(node); } }); } }; ``` ```js /* eslint eslint-plugin/require-meta-fixable: "error" */ module.exports = { meta: {}, create(context) { context.report({ node, message: 'foo' }); } }; ``` ## When Not To Use It If you do not plan to implement autofixable rules, you can turn off this rule. ## Further Reading * [ESLint's autofix API](http://eslint.org/docs/developer-guide/working-with-rules#applying-fixes) eslint-plugin-eslint-plugin-2.3.0/docs/rules/require-meta-schema.md000066400000000000000000000026641367425336200253630ustar00rootroot00000000000000# require rules to implement a meta.schema property (require-meta-schema) Defining a schema for each rule allows eslint to validate that configuration options are passed correctly. Even when there are no options for a rule, a schema should still be defined (as an empty array) so that eslint can validate that no data is passed to the rule. ## Rule Details This rule requires ESLint rules to have a valid `meta.schema` property. Examples of **incorrect** code for this rule: ```js /* eslint eslint-plugin/require-meta-schema: error */ module.exports = { meta: {}, create: function(context) { /* ... */} }; module.exports = { meta: { schema: null }, create: function(context) { /* ... */} }; ``` Examples of **correct** code for this rule: ```js /* eslint eslint-plugin/require-meta-type: error */ module.exports = { meta: { schema: [] }, // ensures no options are passed to the rule create: function(context) { /* ... */} }; module.exports = { meta: { schema: [ { type: 'object', properties: { exceptRange: { type: 'boolean' } }, additionalProperties: false } ] }, create: function(context) { /* ... */} }; ``` ## Further Reading * [working-with-rules#options-schemas](https://eslint.org/docs/developer-guide/working-with-rules#options-schemas) eslint-plugin-eslint-plugin-2.3.0/docs/rules/require-meta-type.md000066400000000000000000000024131367425336200250740ustar00rootroot00000000000000# require rules to implement a meta.type property (require-meta-type) ESLint v5.9.0 introduces a new `--fix-type` option for the command line interface. This option allows users to filter the type of fixes applied when using `--fix`. Fixes in custom rules will not be applied when using `--fix-type` unless they include a meta.type field. ## Rule Details This rule aims to require ESLint rules to have a valid `meta.type` property. Examples of **incorrect** code for this rule: ```js /* eslint eslint-plugin/require-meta-type: error */ module.exports = { meta: {}, create: function(context) { // ... } }; module.exports = { meta: {type: 'invalid'}, create: function(context) { // ... } }; ``` Examples of **correct** code for this rule: ```js /* eslint eslint-plugin/require-meta-type: error */ module.exports = { meta: {type: 'problem'}, create: function(context) { // ... } }; ``` ## Further Reading * [command-line-interface#--fix-type](https://eslint.org/docs/user-guide/command-line-interface#--fix-type) * [working-with-rules#rule-basics](https://eslint.org/docs/developer-guide/working-with-rules#rule-basics) * [ESLint v5.9.0 released](https://eslint.org/blog/2018/11/eslint-v5.9.0-released#the-fix-type-option) eslint-plugin-eslint-plugin-2.3.0/docs/rules/test-case-property-ordering.md000066400000000000000000000024201367425336200270740ustar00rootroot00000000000000# enforce ordering of keys in test cases (test-case-property-ordering) (fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#fix) automatically fixes problems reported by this rule. This rule enforces that the properties of RuleTester test cases are arranged in a consistent order. ## Rule Details ### Options This rule has an array option: * `["code", "output", "options", "parserOptions", "errors"]` (default): The properties of a test case should be placed in a consistent order. Examples of **incorrect** code for this rule: ```js /* eslint eslint-plugin/test-case-property-ordering: ["error", ["code", "output", "options", "parserOptions", "errors"] ] */ // invalid; wrong order { code: "foo", options: ["baz"], output: "bar", } // invalid; extra properties should need to be placed afterwards. { code: "foo", env: { es6: true }, output: "bar", options: ["baz"], } ``` Examples of **correct** code for this rule: ```js /* eslint eslint-plugin/test-case-property-ordering: ["error", ["code", "output", "options", "parserOptions", "errors"] ] */ // valid; { code: "foo", output: "bar", options: ["baz"], } ``` ## When Not To Use It If don't want to enforce ordering of keys in test cases, you can turn off this rule. eslint-plugin-eslint-plugin-2.3.0/docs/rules/test-case-shorthand-strings.md000066400000000000000000000131001367425336200270570ustar00rootroot00000000000000# Enforce consistent usage of shorthand strings for test cases with no options (test-case-shorthand-strings) When writing valid test cases for rules with `RuleTester`, one can optionally include a string as a test case instead of an object, if the the test case does not use any options. ```js ruleTester.run('example-rule', rule, { valid: [ // shorthand string 'validTestCase;', // longform object { code: 'anotherValidTestCase;' } ], invalid: [ // ... ] }); ``` Some developers prefer using this shorthand because it's more concise, but others prefer not to use the shorthand for consistency, so that all test cases are provided as objects. Regardless of your preference, it's generally better to be consistent throughout a project. ## Rule Details This rule aims to enforce or disallow the use of strings as test cases. ### Options This rule has a string option: * `as-needed` (default): Requires the use of shorthand strings wherever possible. * `never`: Disallows the use of shorthand strings. * `consistent`: Requires that either all valid test cases use shorthand strings, or that no valid test cases use them. * `consistent-as-needed`: Requires that all valid test cases use the longer object form if there are any valid test cases that require the object form. Otherwise, requires all valid test cases to use shorthand strings. #### `as-needed` Examples of **incorrect** code for this rule with the default `as-needed` option: ```js /* eslint eslint-plugin/test-case-shorthand-strings: "error" */ ruleTester.run('example-rule', rule, { valid: [ { code: 'validTestCase;' }, { code: 'anotherValidTestCase;' } ], invalid: [] }); ``` Examples of **correct** code for this rule with the default `as-needed` option: ```js /* eslint eslint-plugin/test-case-shorthand-strings: "error" */ ruleTester.run('example-rule', rule, { valid: [ 'validTestCase;', 'anotherValidTestCase;', { code: 'testCaseWithOption;', options: ["foo"] } ], invalid: [] }); ``` #### `never` Examples of **incorrect** code for this rule with the `never` option: ```js /* eslint eslint-plugin/test-case-shorthand-strings: ["error", "never"] */ ruleTester.run('example-rule', rule, { valid: [ 'validTestCase;', 'anotherValidTestCase;' ], invalid: [] }); ``` Examples of **correct** code for this rule with the `never` option: ```js /* eslint eslint-plugin/test-case-shorthand-strings: ["error", "never"] */ ruleTester.run('example-rule', rule, { valid: [ { code: 'validTestCase;' }, { code: 'anotherValidTestCase;' } ], invalid: [] }); ``` #### `consistent` Examples of **incorrect** code for this rule with the `consistent` option: ```js /* eslint eslint-plugin/test-case-shorthand-strings: ["error", "consistent"] */ ruleTester.run('example-rule', rule, { valid: [ 'validTestCase;', 'anotherValidTestCase;', { code: 'testCaseWithOption', options: ["foo"] } ], invalid: [] }); ``` Examples of **correct** code for this rule with the `consistent` option: ```js /* eslint eslint-plugin/test-case-shorthand-strings: ["error", "consistent"] */ ruleTester.run('example-rule', rule, { valid: [ { code: 'validTestCase;' }, { code: 'anotherValidTestCase' }, { code: 'testCaseWithOption', options: ["foo"] } ], invalid: [] }); ruleTester.run('example-rule', rule, { valid: [ 'validTestCase;', 'anotherValidTestCase' ], invalid: [] }); ruleTester.run('example-rule', rule, { valid: [ { code: 'validTestCase;' }, { code: 'anotherValidTestCase' } ], invalid: [] }); ``` #### `never` Examples of **incorrect** code for this rule with the `consistent-as-needed` option: ```js /* eslint eslint-plugin/test-case-shorthand-strings: ["error", "consistent-as-needed"] */ ruleTester.run('example-rule', rule, { valid: [ 'validTestCase;', { code: 'anotherValidTestCase' } ], invalid: [] }); ruleTester.run('example-rule', rule, { valid: [ 'validTestCase;', 'anotherValidTestCase;', { code: 'testCaseWithOption;', options: ['foo'] } ], invalid: [] }); ruleTester.run('example-rule', rule, { valid: [ { code: 'validTestCase;' }, { code: 'anotherValidTestCase;' } ], invalid: [] }); ``` Examples of **correct** code for this rule with the `consistent-as-needed` option: ```js /* eslint eslint-plugin/test-case-shorthand-strings: ["error", "consistent-as-needed"] */ ruleTester.run('example-rule', rule, { valid: [ 'validTestCase;', 'anotherValidTestCase;' ], invalid: [] }); ruleTester.run('example-rule', rule, { valid: [ { code: 'validTestCase;' }, { code: 'anotherValidTestCase;' }, { code: 'testCaseWithOption;', options: ['foo'] } ], invalid: [] }); ``` ## Known Limitations * Test cases which are neither object literals nor string literals are ignored by this rule. * In order to find your test cases, your test file needs to match the following common pattern: * `new RuleTester()` or `new (require('eslint')).RuleTester()` is called at the top level of the file * `ruleTester.run` is called at the top level with the same variable (or in the same expression) as the `new RuleTester` instantiation ## When Not To Use It If you don't care about consistent usage of shorthand strings, you should not turn on this rule. ## Further Reading * [`RuleTester` documentation](http://eslint.org/docs/developer-guide/working-with-plugins#testing) eslint-plugin-eslint-plugin-2.3.0/lib/000077500000000000000000000000001367425336200176575ustar00rootroot00000000000000eslint-plugin-eslint-plugin-2.3.0/lib/index.js000066400000000000000000000043161367425336200213300ustar00rootroot00000000000000/** * @fileoverview An ESLint plugin for linting ESLint plugins * @author Teddy Katz */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const fs = require('fs'); const path = require('path'); const packageMetadata = require('../package'); const PLUGIN_NAME = packageMetadata.name.replace(/^eslint-plugin-/, ''); const PLUGIN_VERSION = packageMetadata.version; const configFilters = { all: () => true, recommended: rule => rule.meta.docs.recommended, rules: rule => rule.meta.docs.category === 'Rules', tests: rule => rule.meta.docs.category === 'Tests', 'rules-recommended': rule => configFilters.recommended(rule) && configFilters.rules(rule), 'tests-recommended': rule => configFilters.recommended(rule) && configFilters.tests(rule), }; // ------------------------------------------------------------------------------ // Plugin Definition // ------------------------------------------------------------------------------ /** * Loads a given rule from the filesystem and generates its documentation URL * @param {string} ruleName The name of the rule * @returns {Rule} The ESLint rule to export */ function loadRule (ruleName) { const rule = require(path.join(__dirname, 'rules', ruleName)); rule.meta.docs.url = `https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/tree/v${PLUGIN_VERSION}/docs/rules/${ruleName}.md`; return rule; } // import all rules in lib/rules const allRules = fs .readdirSync(`${__dirname}/rules`) .filter(fileName => fileName.endsWith('.js') && /^[^._]/.test(fileName)) .map(fileName => fileName.replace(/\.js$/, '')) .reduce((rules, ruleName) => Object.assign(rules, { [ruleName]: loadRule(ruleName) }), {}); module.exports.rules = allRules; module.exports.configs = Object.keys(configFilters).reduce((configs, configName) => { return Object.assign(configs, { [configName]: { rules: Object.keys(allRules) .filter(ruleName => configFilters[configName](allRules[ruleName])) .reduce((rules, ruleName) => Object.assign(rules, { [`${PLUGIN_NAME}/${ruleName}`]: 'error' }), {}), }, }); }, {}); eslint-plugin-eslint-plugin-2.3.0/lib/rules/000077500000000000000000000000001367425336200210115ustar00rootroot00000000000000eslint-plugin-eslint-plugin-2.3.0/lib/rules/consistent-output.js000066400000000000000000000033201367425336200250740ustar00rootroot00000000000000/** * @fileoverview Enforce consistent use of output assertions in rule tests * @author Teddy Katz */ 'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'enforce consistent use of output assertions in rule tests', category: 'Tests', recommended: false, }, type: 'suggestion', fixable: null, // or "code" or "whitespace" schema: [ { type: 'string', enum: ['always', 'consistent'], }, ], }, create (context) { // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- const always = context.options[0] && context.options[0] === 'always'; return { Program (ast) { utils.getTestInfo(context, ast).forEach(testRun => { const readableCases = testRun.invalid.filter(testCase => testCase.type === 'ObjectExpression'); const casesWithoutOutput = readableCases .filter(testCase => testCase.properties.map(utils.getKeyName).indexOf('output') === -1); if ( (casesWithoutOutput.length < readableCases.length) || (always && casesWithoutOutput.length > 0) ) { casesWithoutOutput.forEach(testCase => { context.report({ node: testCase, message: 'This test case should have an output assertion.', }); }); } }); }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/fixer-return.js000066400000000000000000000063061367425336200240060ustar00rootroot00000000000000/** * @fileoverview Enforces always return from a fixer function * @author 薛定谔的猫 */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'require fixer function to always return a value.', category: 'Possible Errors', recommended: true, }, type: 'problem', fixable: null, schema: [], }, create (context) { const message = 'Expected fixer function to always return a value.'; let funcInfo = { upper: null, codePath: null, hasReturn: false, hasYield: false, shouldCheck: false, node: null, }; let contextIdentifiers; /** * Checks whether or not the last code path segment is reachable. * Then reports this function if the segment is reachable. * * If the last code path segment is reachable, there are paths which are not * returned or thrown. * * @param {ASTNode} node - A node to check. * @returns {void} */ function checkLastSegment (node) { if ( funcInfo.shouldCheck && funcInfo.codePath.currentSegments.some(segment => segment.reachable) && (!node.generator || !funcInfo.hasYield) ) { context.report({ node, loc: (node.id || node).loc.start, message, }); } } return { Program (node) { contextIdentifiers = utils.getContextIdentifiers(context, node); }, // Stacks this function's information. onCodePathStart (codePath, node) { const parent = node.parent; const shouldCheck = node.type === 'FunctionExpression' && parent.parent.type === 'ObjectExpression' && parent.parent.parent.type === 'CallExpression' && contextIdentifiers.has(parent.parent.parent.callee.object) && parent.parent.parent.callee.property.name === 'report' && utils.getReportInfo(parent.parent.parent.arguments).fix === node; funcInfo = { upper: funcInfo, codePath, hasYield: false, hasReturn: false, shouldCheck, node, }; }, // Pops this function's information. onCodePathEnd () { funcInfo = funcInfo.upper; }, // Yield in generators YieldExpression () { if (funcInfo.shouldCheck) { funcInfo.hasYield = true; } }, // Checks the return statement is valid. ReturnStatement (node) { if (funcInfo.shouldCheck) { funcInfo.hasReturn = true; if (!node.argument) { context.report({ node, message, }); } } }, // Reports a given function if the last path is reachable. 'FunctionExpression:exit': checkLastSegment, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/meta-property-ordering.js000066400000000000000000000045031367425336200257700ustar00rootroot00000000000000/** * @fileoverview Enforces the order of meta properties */ 'use strict'; const { getKeyName, getRuleInfo } = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'enforce the order of meta properties', category: 'Rules', recommended: false, }, type: 'suggestion', fixable: 'code', schema: [{ type: 'array', elements: { type: 'string' }, }], }, create (context) { const sourceCode = context.getSourceCode(); const info = getRuleInfo(sourceCode.ast); const message = 'The meta properties should be placed in a consistent order: [{{order}}].'; const order = context.options[0] || ['type', 'docs', 'fixable', 'schema', 'messages']; const orderMap = new Map(order.map((name, i) => [name, i])); return { Program () { if ( !info || !info.meta || info.meta.properties.length < 2 ) { return; } const props = info.meta.properties; let last; const violatingProps = props.filter(prop => { const curr = orderMap.has(getKeyName(prop)) ? orderMap.get(getKeyName(prop)) : Infinity; return last > (last = curr); }); if (violatingProps.length === 0) { return; } const knownProps = props .filter(prop => orderMap.has(getKeyName(prop))) .sort((a, b) => orderMap.get(getKeyName(a)) - orderMap.get(getKeyName(b))); const unknownProps = props.filter(prop => !orderMap.has(getKeyName(prop))); for (const violatingProp of violatingProps) { context.report({ node: violatingProp, message, data: { order: knownProps.map(getKeyName).join(', '), }, fix (fixer) { const expectedProps = [...knownProps, ...unknownProps]; return props.map((prop, k) => { return fixer.replaceText( prop, sourceCode.getText(expectedProps[k]) ); }); }, }); } }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/no-deprecated-context-methods.js000066400000000000000000000054031367425336200272060ustar00rootroot00000000000000/** * @fileoverview Disallows usage of deprecated methods on rule context objects * @author Teddy Katz */ 'use strict'; const utils = require('../utils'); const DEPRECATED_PASSTHROUGHS = { getSource: 'getText', getSourceLines: 'getLines', getAllComments: 'getAllComments', getNodeByRangeIndex: 'getNodeByRangeIndex', getComments: 'getComments', getCommentsBefore: 'getCommentsBefore', getCommentsAfter: 'getCommentsAfter', getCommentsInside: 'getCommentsInside', getJSDocComment: 'getJSDocComment', getFirstToken: 'getFirstToken', getFirstTokens: 'getFirstTokens', getLastToken: 'getLastToken', getLastTokens: 'getLastTokens', getTokenAfter: 'getTokenAfter', getTokenBefore: 'getTokenBefore', getTokenByRangeStart: 'getTokenByRangeStart', getTokens: 'getTokens', getTokensAfter: 'getTokensAfter', getTokensBefore: 'getTokensBefore', getTokensBetween: 'getTokensBetween', }; // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'disallow usage of deprecated methods on rule context objects', category: 'Rules', recommended: false, }, type: 'suggestion', fixable: 'code', schema: [], }, create (context) { const sourceCode = context.getSourceCode(); // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- return { 'Program:exit' () { Array.from(utils.getContextIdentifiers(context, sourceCode.ast)) .filter( contextId => contextId.parent.type === 'MemberExpression' && contextId === contextId.parent.object && contextId.parent.property.type === 'Identifier' && Object.prototype.hasOwnProperty.call(DEPRECATED_PASSTHROUGHS, contextId.parent.property.name) ).forEach( contextId => context.report({ node: contextId.parent, message: 'Use `{{contextName}}.getSourceCode().{{replacement}}` instead of `{{contextName}}.{{original}}`.', data: { contextName: contextId.name, original: contextId.parent.property.name, replacement: DEPRECATED_PASSTHROUGHS[contextId.parent.property.name], }, fix: fixer => [ fixer.insertTextAfter(contextId, '.getSourceCode()'), fixer.replaceText(contextId.parent.property, DEPRECATED_PASSTHROUGHS[contextId.parent.property.name]), ], }) ); }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/no-deprecated-report-api.js000066400000000000000000000041231367425336200261410ustar00rootroot00000000000000/** * @fileoverview disallow use of the deprecated context.report() API * @author Teddy Katz */ 'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'disallow use of the deprecated context.report() API', category: 'Rules', recommended: true, }, type: 'suggestion', fixable: 'code', // or "code" or "whitespace" schema: [], }, create (context) { const sourceCode = context.getSourceCode(); let contextIdentifiers; // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- return { Program (node) { contextIdentifiers = utils.getContextIdentifiers(context, node); }, CallExpression (node) { if ( node.callee.type === 'MemberExpression' && contextIdentifiers.has(node.callee.object) && node.callee.property.type === 'Identifier' && node.callee.property.name === 'report' && (node.arguments.length > 1 || (node.arguments.length === 1 && node.arguments[0].type === 'SpreadElement')) ) { context.report({ node: node.callee.property, message: 'Use the new-style context.report() API.', fix (fixer) { const openingParen = sourceCode.getTokenBefore(node.arguments[0]); const closingParen = sourceCode.getLastToken(node); const reportInfo = utils.getReportInfo(node.arguments); if (!reportInfo) { return null; } return fixer.replaceTextRange( [openingParen.range[1], closingParen.range[0]], `{${Object.keys(reportInfo).map(key => `${key}: ${sourceCode.getText(reportInfo[key])}`).join(', ')}}` ); }, }); } }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/no-identical-tests.js000066400000000000000000000055571367425336200250710ustar00rootroot00000000000000/** * @fileoverview disallow identical tests * @author 薛定谔的猫 */ 'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'disallow identical tests', category: 'Tests', recommended: true, }, type: 'problem', fixable: 'code', schema: [], }, create (context) { // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- const message = 'This test case is identical to another case.'; const sourceCode = context.getSourceCode(); // ---------------------------------------------------------------------- // Helpers // ---------------------------------------------------------------------- /** *compare two test cases despite of properties order. *@returns {boolean} if eq, return true, else return false. */ function eq (testA, testB) { if (testA.type !== testB.type) { return false; } if (testA.type !== 'ObjectExpression') { return sourceCode.getText(testA) === sourceCode.getText(testB); } const propertiesA = testA.properties || []; const propertiesB = testB.properties || []; // if properties length not eq; return false; if (propertiesA.length !== propertiesB.length) { return false; } const propertiesSetA = new Set(); propertiesA.forEach(item => { const code = sourceCode.getText(item); propertiesSetA.add(code); }); for (let i = 0; i < propertiesB.length; i++) { const code = sourceCode.getText(propertiesB[i]); if (!propertiesSetA.has(code)) { return false; } } return true; } return { Program (ast) { utils.getTestInfo(context, ast).forEach(testRun => { [testRun.valid, testRun.invalid].forEach(tests => { const cache = []; tests.forEach(test => { if (cache.some(item => eq(item, test))) { context.report({ node: test, message, fix (fixer) { const start = sourceCode.getTokenBefore(test); const end = sourceCode.getTokenAfter(test); return fixer.removeRange( // should remove test's trailing comma [start.range[1], end.value === ',' ? end.range[1] : test.range[1]]); }, }); } else { cache.push(test); } }); }); }); }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/no-missing-placeholders.js000066400000000000000000000045241367425336200261020ustar00rootroot00000000000000/** * @fileoverview Disallow missing placeholders in rule report messages * @author Teddy Katz */ 'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'disallow missing placeholders in rule report messages', category: 'Rules', recommended: true, }, type: 'problem', fixable: null, schema: [], }, create (context) { let contextIdentifiers; // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- return { Program (ast) { contextIdentifiers = utils.getContextIdentifiers(context, ast); }, CallExpression (node) { if ( node.callee.type === 'MemberExpression' && contextIdentifiers.has(node.callee.object) && node.callee.property.type === 'Identifier' && node.callee.property.name === 'report' ) { const reportInfo = utils.getReportInfo(node.arguments); if ( reportInfo && reportInfo.message && reportInfo.message.type === 'Literal' && typeof reportInfo.message.value === 'string' && (!reportInfo.data || reportInfo.data.type === 'ObjectExpression') ) { // Same regex as the one ESLint uses // https://github.com/eslint/eslint/blob/e5446449d93668ccbdb79d78cc69f165ce4fde07/lib/eslint.js#L990 const PLACEHOLDER_MATCHER = /\{\{\s*([^{}]+?)\s*\}\}/g; let match; while ((match = PLACEHOLDER_MATCHER.exec(reportInfo.message.value))) { // eslint-disable-line no-extra-parens const matchingProperty = reportInfo.data && reportInfo.data.properties.find(prop => utils.getKeyName(prop) === match[1]); if (!matchingProperty) { context.report({ node: reportInfo.message, message: 'The placeholder {{{{missingKey}}}} does not exist.', data: { missingKey: match[1] }, }); } } } } }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/no-unused-placeholders.js000066400000000000000000000046021367425336200257310ustar00rootroot00000000000000/** * @fileoverview Disallow unused placeholders in rule report messages * @author 薛定谔的猫 */ 'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'disallow unused placeholders in rule report messages', category: 'Rules', recommended: true, }, type: 'problem', fixable: null, schema: [], }, create (context) { let contextIdentifiers; // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- return { Program (ast) { contextIdentifiers = utils.getContextIdentifiers(context, ast); }, CallExpression (node) { if ( node.callee.type === 'MemberExpression' && contextIdentifiers.has(node.callee.object) && node.callee.property.type === 'Identifier' && node.callee.property.name === 'report' ) { const reportInfo = utils.getReportInfo(node.arguments); if ( reportInfo && reportInfo.message && reportInfo.message.type === 'Literal' && typeof reportInfo.message.value === 'string' && reportInfo.data && reportInfo.data.type === 'ObjectExpression' ) { const message = reportInfo.message.value; // https://github.com/eslint/eslint/blob/2874d75ed8decf363006db25aac2d5f8991bd969/lib/linter.js#L986 const PLACEHOLDER_MATCHER = /\{\{\s*([^{}]+?)\s*\}\}/g; const placeholdersInMessage = new Set(); message.replace(PLACEHOLDER_MATCHER, (fullMatch, term) => { placeholdersInMessage.add(term); }); reportInfo.data.properties.forEach(prop => { const key = utils.getKeyName(prop); if (!placeholdersInMessage.has(key)) { context.report({ node: reportInfo.message, message: 'The placeholder {{{{unusedKey}}}} is unused.', data: { unusedKey: key }, }); } }); } } }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/no-useless-token-range.js000066400000000000000000000136501367425336200256610ustar00rootroot00000000000000/** * @fileoverview Disallow unnecessary calls to sourceCode.getFirstToken and sourceCode.getLastToken * @author Teddy Katz */ 'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'disallow unnecessary calls to sourceCode.getFirstToken and sourceCode.getLastToken', category: 'Rules', recommended: true, }, type: 'suggestion', fixable: 'code', schema: [], }, create (context) { const sourceCode = context.getSourceCode(); // ---------------------------------------------------------------------- // Helpers // ---------------------------------------------------------------------- /** * Determines whether a second argument to getFirstToken or getLastToken changes the output of the function. * This occurs when the second argument exists and is not an object literal, or has keys other than `includeComments`. * @param {ASTNode} arg The second argument to `sourceCode.getFirstToken` or `sourceCode.getLastToken` * @returns {boolean} `true` if the argument affects the output of getFirstToken or getLastToken */ function affectsGetTokenOutput (arg) { if (!arg) { return false; } if (arg.type !== 'ObjectExpression') { return true; } return arg.properties.length >= 2 || ( arg.properties.length === 1 && ( utils.getKeyName(arg.properties[0]) !== 'includeComments' || arg.properties[0].value.type !== 'Literal' )); } /** * Determines whether a node is a MemberExpression that accesses the `range` property * @param {ASTNode} node The node * @returns {boolean} `true` if the node is a MemberExpression that accesses the `range` property */ function isRangeAccess (node) { return node.type === 'MemberExpression' && node.property.type === 'Identifier' && node.property.name === 'range'; } /** * Determines whether a MemberExpression accesses the `start` property (either `.range[0]` or `.start`). * Note that this will also work correctly if the `.range` MemberExpression is passed. * @param {ASTNode} memberExpression The MemberExpression node to check * @returns {boolean} `true` if this node accesses either `.range[0]` or `.start` */ function isStartAccess (memberExpression) { if (isRangeAccess(memberExpression) && memberExpression.parent.type === 'MemberExpression') { return isStartAccess(memberExpression.parent); } return ( (memberExpression.property.type === 'Identifier' && memberExpression.property.name === 'start') || ( memberExpression.computed && memberExpression.property.type === 'Literal' && memberExpression.property.value === 0 && isRangeAccess(memberExpression.object) ) ); } /** * Determines whether a MemberExpression accesses the `start` property (either `.range[1]` or `.end`). * Note that this will also work correctly if the `.range` MemberExpression is passed. * @param {ASTNode} memberExpression The MemberExpression node to check * @returns {boolean} `true` if this node accesses either `.range[1]` or `.end` */ function isEndAccess (memberExpression) { if (isRangeAccess(memberExpression) && memberExpression.parent.type === 'MemberExpression') { return isEndAccess(memberExpression.parent); } return ( (memberExpression.property.type === 'Identifier' && memberExpression.property.name === 'end') || ( memberExpression.computed && memberExpression.property.type === 'Literal' && memberExpression.property.value === 1 && isRangeAccess(memberExpression.object) ) ); } // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- return { 'Program:exit' (ast) { Array.from(utils.getSourceCodeIdentifiers(context, ast)) .filter(identifier => identifier.parent.type === 'MemberExpression' && identifier.parent.object === identifier && identifier.parent.property.type === 'Identifier' && identifier.parent.parent.type === 'CallExpression' && identifier.parent === identifier.parent.parent.callee && identifier.parent.parent.arguments.length <= 2 && !affectsGetTokenOutput(identifier.parent.parent.arguments[1]) && identifier.parent.parent.parent.type === 'MemberExpression' && identifier.parent.parent === identifier.parent.parent.parent.object && ( (isStartAccess(identifier.parent.parent.parent) && identifier.parent.property.name === 'getFirstToken') || (isEndAccess(identifier.parent.parent.parent) && identifier.parent.property.name === 'getLastToken')) ) .forEach(identifier => { const fullRangeAccess = isRangeAccess(identifier.parent.parent.parent) ? identifier.parent.parent.parent.parent : identifier.parent.parent.parent; const replacementText = sourceCode.text.slice(fullRangeAccess.range[0], identifier.parent.parent.range[0]) + sourceCode.getText(identifier.parent.parent.arguments[0]) + sourceCode.text.slice(identifier.parent.parent.range[1], fullRangeAccess.range[1]); context.report({ node: identifier.parent.parent, message: "Use '{{replacementText}}' instead.", data: { replacementText }, fix (fixer) { return fixer.replaceText(identifier.parent.parent, sourceCode.getText(identifier.parent.parent.arguments[0])); }, }); }); }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/prefer-object-rule.js000066400000000000000000000042731367425336200250510ustar00rootroot00000000000000/** * @author Brad Zacher */ 'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'disallow rule exports where the export is a function.', category: 'Rules', recommended: false, }, messages: { preferObject: 'Rules should be declared using the object style.', }, type: 'suggestion', fixable: 'code', schema: [], }, create (context) { // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- const sourceCode = context.getSourceCode(); const ruleInfo = utils.getRuleInfo(sourceCode.ast); return { Program () { if (!ruleInfo || ruleInfo.isNewStyle) { return; } context.report({ node: ruleInfo.create, messageId: 'preferObject', *fix (fixer) { // note - we intentionally don't worry about formatting here, as otherwise we have // to indent the function correctly if (ruleInfo.create.type === 'FunctionExpression') { const openParenToken = sourceCode.getFirstToken( ruleInfo.create, token => token.type === 'Punctuator' && token.value === '(' ); if (!openParenToken) { // this shouldn't happen, but guarding against crashes just in case return null; } yield fixer.replaceTextRange( [ruleInfo.create.range[0], openParenToken.range[0]], '{create' ); yield fixer.insertTextAfter(ruleInfo.create, '}'); } else if (ruleInfo.create.type === 'ArrowFunctionExpression') { yield fixer.insertTextBefore(ruleInfo.create, '{create: '); yield fixer.insertTextAfter(ruleInfo.create, '}'); } }, }); }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/prefer-output-null.js000066400000000000000000000040411367425336200251370ustar00rootroot00000000000000/** * @fileoverview disallows invalid RuleTester test cases with the output the same as the code. * @author 薛定谔的猫 */ 'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'disallow invalid RuleTester test cases with the output the same as the code.', category: 'Tests', recommended: false, }, type: 'suggestion', fixable: 'code', schema: [], }, create (context) { // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- const message = 'Use `output: null` to assert that a test case is not autofixed.'; const sourceCode = context.getSourceCode(); return { Program (ast) { utils.getTestInfo(context, ast).forEach(testRun => { testRun.invalid.forEach(test => { /** * Get a test case's giving keyname node. * @param {string} the keyname to find. * @returns {Node} found node; if not found, return null; */ function getTestInfo (key) { if (test.type === 'ObjectExpression') { const res = test.properties.filter(item => item.key.name === key); return res.length ? res[res.length - 1] : null; } return key === 'code' ? test : null; } const code = getTestInfo('code'); const output = getTestInfo('output'); if (output && sourceCode.getText(output.value) === sourceCode.getText(code.value)) { context.report({ node: output, message, fix: fixer => fixer.replaceText(output.value, 'null'), }); } }); }); }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/prefer-placeholders.js000066400000000000000000000033251367425336200253000ustar00rootroot00000000000000/** * @fileoverview disallow template literals as report messages * @author Teddy Katz */ 'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'disallow template literals as report messages', category: 'Rules', recommended: false, }, type: 'suggestion', fixable: null, schema: [], }, create (context) { let contextIdentifiers; // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- return { Program (node) { contextIdentifiers = utils.getContextIdentifiers(context, node); }, CallExpression (node) { if ( node.callee.type === 'MemberExpression' && contextIdentifiers.has(node.callee.object) && node.callee.property.type === 'Identifier' && node.callee.property.name === 'report' ) { const reportInfo = utils.getReportInfo(node.arguments); if ( reportInfo && reportInfo.message && ( (reportInfo.message.type === 'TemplateLiteral' && reportInfo.message.expressions.length) || (reportInfo.message.type === 'BinaryExpression' && reportInfo.message.operator === '+') ) ) { context.report({ node: reportInfo.message, message: 'Use report message placeholders instead of string concatenation.', }); } } }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/prefer-replace-text.js000066400000000000000000000047721367425336200252370ustar00rootroot00000000000000/** * @fileoverview prefer using replaceText instead of replaceTextRange. * @author 薛定谔的猫 */ 'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'require using replaceText instead of replaceTextRange.', category: 'Rules', recommended: false, }, type: 'suggestion', fixable: null, schema: [], }, create (context) { const sourceCode = context.getSourceCode(); const message = 'Use replaceText instead of replaceTextRange.'; let funcInfo = { upper: null, codePath: null, shouldCheck: false, node: null, }; let contextIdentifiers; return { Program (node) { contextIdentifiers = utils.getContextIdentifiers(context, node); }, // Stacks this function's information. onCodePathStart (codePath, node) { const parent = node.parent; const shouldCheck = (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') && parent.parent.type === 'ObjectExpression' && parent.parent.parent.type === 'CallExpression' && contextIdentifiers.has(parent.parent.parent.callee.object) && parent.parent.parent.callee.property.name === 'report' && utils.getReportInfo(parent.parent.parent.arguments).fix === node; funcInfo = { upper: funcInfo, codePath, shouldCheck, node, }; }, // Pops this function's information. onCodePathEnd () { funcInfo = funcInfo.upper; }, // Checks the replaceTextRange arguments. 'CallExpression[arguments.length=2]' (node) { if (funcInfo.shouldCheck && node.callee.type === 'MemberExpression' && node.callee.property.name === 'replaceTextRange') { const arg = node.arguments[0]; const isIdenticalNodeRange = arg.type === 'ArrayExpression' && arg.elements[0].type === 'MemberExpression' && arg.elements[1].type === 'MemberExpression' && sourceCode.getText(arg.elements[0].object) === sourceCode.getText(arg.elements[1].object); if (isIdenticalNodeRange) { context.report({ node, message, }); } } }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/report-message-format.js000066400000000000000000000053431367425336200255770ustar00rootroot00000000000000/** * @fileoverview enforce a consistent format for rule report messages * @author Teddy Katz */ 'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'enforce a consistent format for rule report messages', category: 'Rules', recommended: false, }, type: 'suggestion', fixable: null, schema: [ { type: 'string' }, ], }, create (context) { const pattern = new RegExp(context.options[0] || ''); let contextIdentifiers; /** * Report a message node if it doesn't match the given formatting * @param {ASTNode} message The message AST node * @returns {void} */ function processMessageNode (message) { if ( (message.type === 'Literal' && typeof message.value === 'string' && !pattern.test(message.value)) || (message.type === 'TemplateLiteral' && message.quasis.length === 1 && !pattern.test(message.quasis[0].value.cooked)) ) { context.report({ node: message, message: "Report message does not match the pattern '{{pattern}}'.", data: { pattern: context.options[0] || '' }, }); } } // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- return { Program (node) { contextIdentifiers = utils.getContextIdentifiers(context, node); const ruleInfo = utils.getRuleInfo(context.getSourceCode().ast); const messagesObject = ruleInfo && ruleInfo.meta && ruleInfo.meta.type === 'ObjectExpression' && ruleInfo.meta.properties.find(prop => prop.type === 'Property' && utils.getKeyName(prop) === 'messages'); if (!messagesObject || messagesObject.value.type !== 'ObjectExpression') { return; } messagesObject.value.properties .filter(prop => prop.type === 'Property') .map(prop => prop.value) .forEach(processMessageNode); }, CallExpression (node) { if ( node.callee.type === 'MemberExpression' && contextIdentifiers.has(node.callee.object) && node.callee.property.type === 'Identifier' && node.callee.property.name === 'report' ) { const reportInfo = utils.getReportInfo(node.arguments); const message = reportInfo && reportInfo.message; if (!message) { return; } processMessageNode(message); } }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/require-meta-docs-description.js000066400000000000000000000055011367425336200272170ustar00rootroot00000000000000'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ const DEFAULT_PATTERN = new RegExp('^(enforce|require|disallow)'); /** * Whether or not the node is a string literal * * @param {object} node * @returns {boolean} whether or not the node is a string literal */ function isStringLiteral (node) { return node.type === 'Literal' && typeof node.value === 'string'; } module.exports = { meta: { docs: { description: 'require rules to implement a meta.docs.description property with the correct format', category: 'Rules', recommended: false, // TODO: enable it in a major release. }, type: 'suggestion', fixable: null, schema: [ { type: 'object', properties: { pattern: { type: 'string', }, }, additionalProperties: false, }, ], messages: { missing: '`meta.docs.description` is required.', wrongType: '`meta.docs.description` must be a non-empty string.', extraWhitespace: '`meta.docs.description` must not have leading nor trailing whitespace.', }, }, create (context) { const sourceCode = context.getSourceCode(); const info = utils.getRuleInfo(sourceCode.ast, sourceCode.scopeManager); return { Program () { if (info === null || info.meta === null) { return; } const pattern = context.options[0] && context.options[0].pattern ? new RegExp(context.options[0].pattern) : DEFAULT_PATTERN; const metaNode = info.meta; const docsNode = metaNode && metaNode.properties && metaNode.properties.find(p => p.type === 'Property' && utils.getKeyName(p) === 'docs'); const descriptionNode = docsNode && docsNode.value.properties && docsNode.value.properties.find(p => p.type === 'Property' && utils.getKeyName(p) === 'description'); if (!descriptionNode) { context.report({ node: docsNode ? docsNode : metaNode, messageId: 'missing' }); } else if (!isStringLiteral(descriptionNode.value) || descriptionNode.value.value === '') { context.report({ node: descriptionNode.value, messageId: 'wrongType' }); } else if (descriptionNode.value.value !== descriptionNode.value.value.trim()) { context.report({ node: descriptionNode.value, messageId: 'extraWhitespace' }); } else if (!pattern.test(descriptionNode.value.value)) { context.report({ node: descriptionNode.value, message: '`meta.docs.description` must match the regexp {{pattern}}.', data: { pattern }, }); } }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/require-meta-docs-url.js000066400000000000000000000073571367425336200255110ustar00rootroot00000000000000/** * @author Toru Nagashima */ 'use strict'; // ----------------------------------------------------------------------------- // Requirements // ----------------------------------------------------------------------------- const path = require('path'); const util = require('../utils'); // ----------------------------------------------------------------------------- // Rule Definition // ----------------------------------------------------------------------------- module.exports = { meta: { docs: { description: 'require rules to implement a meta.docs.url property', category: 'Rules', recommended: false, }, type: 'suggestion', fixable: 'code', schema: [{ type: 'object', properties: { pattern: { type: 'string' }, }, additionalProperties: false, }], }, /** * Creates AST event handlers for require-meta-docs-url. * @param {RuleContext} context - The rule context. * @returns {Object} AST event handlers. */ create (context) { const options = context.options[0] || {}; const sourceCode = context.getSourceCode(); const filename = context.getFilename(); const ruleName = filename === '' ? undefined : path.basename(filename, '.js'); const expectedUrl = !options.pattern || !ruleName ? undefined : options.pattern.replace(/{{\s*name\s*}}/g, ruleName); /** * Check whether a given node is the expected URL. * @param {Node} node The node of property value to check. * @returns {boolean} `true` if the node is the expected URL. */ function isExpectedUrl (node) { return Boolean( node && node.type === 'Literal' && typeof node.value === 'string' && ( expectedUrl === undefined || node.value === expectedUrl ) ); } return { Program (node) { const info = util.getRuleInfo(node); if (info === null) { return; } const metaNode = info.meta; const docsPropNode = metaNode && metaNode.properties && metaNode.properties.find(p => p.type === 'Property' && util.getKeyName(p) === 'docs'); const urlPropNode = docsPropNode && docsPropNode.value.properties && docsPropNode.value.properties.find(p => p.type === 'Property' && util.getKeyName(p) === 'url'); if (isExpectedUrl(urlPropNode && urlPropNode.value)) { return; } context.report({ loc: (urlPropNode && urlPropNode.value.loc) || (docsPropNode && docsPropNode.value.loc) || (metaNode && metaNode.loc) || node.loc.start, message: !urlPropNode ? 'Rules should export a `meta.docs.url` property.' : !expectedUrl ? '`meta.docs.url` property must be a string.' : /* otherwise */ '`meta.docs.url` property must be `{{expectedUrl}}`.', data: { expectedUrl, }, fix (fixer) { if (expectedUrl) { const urlString = JSON.stringify(expectedUrl); if (urlPropNode) { return fixer.replaceText(urlPropNode.value, urlString); } if (docsPropNode && docsPropNode.value.type === 'ObjectExpression') { return util.insertProperty(fixer, docsPropNode.value, `url: ${urlString}`, sourceCode); } if (!docsPropNode && metaNode && metaNode.type === 'ObjectExpression') { return util.insertProperty(fixer, metaNode, `docs: {\nurl: ${urlString}\n}`, sourceCode); } } return null; }, }); }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/require-meta-fixable.js000066400000000000000000000055301367425336200253620ustar00rootroot00000000000000/** * @fileoverview require rules to implement a meta.fixable property * @author Teddy Katz */ 'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'require rules to implement a meta.fixable property', category: 'Rules', recommended: true, }, type: 'problem', schema: [], }, create (context) { const sourceCode = context.getSourceCode(); const ruleInfo = utils.getRuleInfo(sourceCode.ast); let contextIdentifiers; let usesFixFunctions; // ---------------------------------------------------------------------- // Helpers // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- return { Program (node) { contextIdentifiers = utils.getContextIdentifiers(context, node); }, CallExpression (node) { if ( node.callee.type === 'MemberExpression' && contextIdentifiers.has(node.callee.object) && node.callee.property.type === 'Identifier' && node.callee.property.name === 'report' && (node.arguments.length > 4 || ( node.arguments.length === 1 && node.arguments[0].type === 'ObjectExpression' && node.arguments[0].properties.some(prop => utils.getKeyName(prop) === 'fix') )) ) { usesFixFunctions = true; } }, 'Program:exit' () { const metaFixableProp = ruleInfo && ruleInfo.meta && ruleInfo.meta.type === 'ObjectExpression' && ruleInfo.meta.properties.find(prop => utils.getKeyName(prop) === 'fixable'); if (metaFixableProp) { const VALID_VALUES = new Set(['code', 'whitespace', null, undefined]); const valueIsValid = metaFixableProp.value.type === 'Literal' ? VALID_VALUES.has(metaFixableProp.value.value) : metaFixableProp.value.type === 'TemplateLiteral' && metaFixableProp.value.quasis.length === 1 ? VALID_VALUES.has(metaFixableProp.value.quasis[0].value.cooked) : metaFixableProp.value.type === 'Identifier' && metaFixableProp.value.name === 'undefined'; if (!valueIsValid) { context.report({ node: metaFixableProp, message: '`meta.fixable` must be either `code`, `whitespace` or `null`.' }); } } else if (usesFixFunctions) { context.report({ node: ruleInfo.create, message: 'Fixable rules must export a `meta.fixable` property.' }); } }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/require-meta-schema.js000066400000000000000000000034471367425336200252150ustar00rootroot00000000000000'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'require rules to implement a meta.schema property', category: 'Rules', recommended: false, // TODO: enable it in a major release. }, type: 'suggestion', fixable: 'code', schema: [ { type: 'object', properties: { exceptRange: { type: 'boolean', }, }, additionalProperties: false, }, ], messages: { missing: '`meta.schema` is required (use [] if rule has no schema).', wrongType: '`meta.schema` should be an array or object (use [] if rule has no schema).', }, }, create (context) { const sourceCode = context.getSourceCode(); const info = utils.getRuleInfo(sourceCode.ast, sourceCode.scopeManager); return { Program () { if (info === null || info.meta === null) { return; } const metaNode = info.meta; const schemaNode = metaNode && metaNode.properties && metaNode.properties.find(p => p.type === 'Property' && utils.getKeyName(p) === 'schema'); if (!schemaNode) { context.report({ node: metaNode, messageId: 'missing', fix (fixer) { return utils.insertProperty(fixer, metaNode, 'schema: []', sourceCode); }, }); } else if (!['ArrayExpression', 'ObjectExpression'].includes(schemaNode.value.type)) { context.report({ node: schemaNode.value, messageId: 'wrongType' }); } }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/require-meta-type.js000066400000000000000000000037521367425336200247350ustar00rootroot00000000000000/** * @fileoverview require rules to implement a meta.type property * @author 薛定谔的猫 */ 'use strict'; const utils = require('../utils'); const VALID_TYPES = new Set(['problem', 'suggestion', 'layout']); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'require rules to implement a meta.type property', category: 'Rules', recommended: false, // TODO: enable it in a major release. }, type: 'problem', fixable: null, schema: [], messages: { missing: '`meta.type` is required (must be either `problem`, `suggestion`, or `layout`).', unexpected: '`meta.type` must be either `problem`, `suggestion` or `layout`.', }, }, create (context) { const sourceCode = context.getSourceCode(); const info = utils.getRuleInfo(sourceCode.ast, sourceCode.scopeManager); // ---------------------------------------------------------------------- // Helpers // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- return { Program () { if (info === null || info.meta === null) { return; } const metaNode = info.meta; const typeNode = metaNode && metaNode.properties && metaNode.properties.find(p => p.type === 'Property' && utils.getKeyName(p) === 'type'); if (typeNode && typeNode.value.type === 'Literal' && !VALID_TYPES.has(typeNode.value.value)) { context.report({ node: metaNode, messageId: 'unexpected' }); } else if (!typeNode) { context.report({ node: metaNode, messageId: 'missing' }); } }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/test-case-property-ordering.js000066400000000000000000000052651367425336200267400ustar00rootroot00000000000000/** * @fileoverview Requires the properties of a test case to be placed in a consistent order. * @author 薛定谔的猫 */ 'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'require the properties of a test case to be placed in a consistent order', category: 'Tests', recommended: false, }, type: 'suggestion', fixable: 'code', schema: [{ type: 'array', elements: { type: 'string' }, }], }, create (context) { // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- const message = 'The properties of a test case should be placed in a consistent order: [{{order}}].'; const order = context.options[0] || ['code', 'output', 'options', 'parserOptions', 'errors']; const sourceCode = context.getSourceCode(); return { Program (ast) { utils.getTestInfo(context, ast).forEach(testRun => { [testRun.valid, testRun.invalid].forEach(tests => { tests.forEach(test => { const properties = (test && test.properties) || []; const keyNames = properties.map(utils.getKeyName); for (let i = 0, lastChecked; i < keyNames.length; i++) { const current = order.indexOf(keyNames[i]); // current < lastChecked to catch unordered; // and lastChecked === -1 to catch extra properties before. if (current > -1 && (current < lastChecked || lastChecked === -1)) { let orderMsg = order.filter(item => keyNames.indexOf(item) > -1); orderMsg = orderMsg.concat( lastChecked === -1 ? keyNames.filter(item => order.indexOf(item) === -1) : [] ); context.report({ node: properties[i], message, data: { order: orderMsg.join(', ') }, fix (fixer) { return orderMsg.map((key, index) => { const propertyToInsert = properties[keyNames.indexOf(key)]; return fixer.replaceText(properties[index], sourceCode.getText(propertyToInsert)); }); }, }); } lastChecked = current; } }); }); }); }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/rules/test-case-shorthand-strings.js000066400000000000000000000062771367425336200267320ustar00rootroot00000000000000/** * @fileoverview Enforce consistent usage of shorthand strings for test cases with no options * @author Teddy Katz */ 'use strict'; const utils = require('../utils'); // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: 'enforce consistent usage of shorthand strings for test cases with no options', category: 'Tests', recommended: false, }, type: 'suggestion', schema: [{ enum: ['as-needed', 'never', 'consistent', 'consistent-as-needed'] }], fixable: 'code', }, create (context) { const shorthandOption = context.options[0] || 'as-needed'; const sourceCode = context.getSourceCode(); // ---------------------------------------------------------------------- // Helpers // ---------------------------------------------------------------------- /** * Reports test cases as necessary * @param {object[]} cases A list of test case nodes * @returns {void} */ function reportTestCases (cases) { const caseInfoList = cases.map(testCase => { if (testCase.type === 'Literal' || testCase.type === 'TemplateLiteral') { return { node: testCase, shorthand: true, needsLongform: false }; } if (testCase.type === 'ObjectExpression') { return { node: testCase, shorthand: false, needsLongform: !(testCase.properties.length === 1 && utils.getKeyName(testCase.properties[0]) === 'code'), }; } return null; }).filter(Boolean); const isConsistent = new Set(caseInfoList.map(caseInfo => caseInfo.shorthand)).size <= 1; const hasCaseNeedingLongform = caseInfoList.some(caseInfo => caseInfo.needsLongform); caseInfoList.filter({ 'as-needed': caseInfo => !caseInfo.shorthand && !caseInfo.needsLongform, never: caseInfo => caseInfo.shorthand, consistent: isConsistent ? () => false : caseInfo => caseInfo.shorthand, 'consistent-as-needed': caseInfo => caseInfo.shorthand === hasCaseNeedingLongform, }[shorthandOption]).forEach(badCaseInfo => { context.report({ node: badCaseInfo.node, message: 'Use {{preferred}} for this test case instead of {{actual}}.', data: { preferred: badCaseInfo.shorthand ? 'an object' : 'a string', actual: badCaseInfo.shorthand ? 'a string' : 'an object', }, fix (fixer) { return fixer.replaceText( badCaseInfo.node, badCaseInfo.shorthand ? `{code: ${sourceCode.getText(badCaseInfo.node)}}` : sourceCode.getText(badCaseInfo.node.properties[0].value) ); }, }); }); } // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- return { Program (ast) { utils.getTestInfo(context, ast).map(testRun => testRun.valid).filter(Boolean).forEach(reportTestCases); }, }; }, }; eslint-plugin-eslint-plugin-2.3.0/lib/utils.js000066400000000000000000000322661367425336200213660ustar00rootroot00000000000000'use strict'; /** * Determines whether a node is a 'normal' (i.e. non-async, non-generator) function expression. * @param {ASTNode} node The node in question * @returns {boolean} `true` if the node is a normal function expression */ function isNormalFunctionExpression (node) { const functionTypes = [ 'FunctionExpression', 'ArrowFunctionExpression', 'FunctionDeclaration', ]; return functionTypes.includes(node.type) && !node.generator && !node.async; } /** * Determines whether a node is a reference to function expression. * @param {ASTNode} node The node in question * @param {ScopeManager} scopeManager The scope manager to use for resolving references * @returns {boolean} `true` if the node is a reference to a function expression */ function isNormalFunctionExpressionReference (node, scopeManager) { if (!node || !scopeManager) { return false; } if (node.type !== 'Identifier') { return false; } const scope = scopeManager.acquire(node) || scopeManager.globalScope; if (!scope) { return false; } const references = scope.references; const createReference = references.find(reference => { return reference.identifier === node; }); if (!createReference || !createReference.resolved) { return false; } const definitions = createReference.resolved.defs; if (!definitions || !definitions.length) { return false; } // Assumes it is immediately initialized to a function let definitionNode = definitions[0].node; // If we find something like `const create = () => {}` then send the // righthand side into the type check. if (definitionNode.type === 'VariableDeclarator') { definitionNode = definitionNode.init; } return isNormalFunctionExpression(definitionNode); } /** * Determines whether a node is constructing a RuleTester instance * @param {ASTNode} node The node in question * @returns {boolean} `true` if the node is probably constructing a RuleTester instance */ function isRuleTesterConstruction (node) { return node.type === 'NewExpression' && ( (node.callee.type === 'Identifier' && node.callee.name === 'RuleTester') || (node.callee.type === 'MemberExpression' && node.callee.property.type === 'Identifier' && node.callee.property.name === 'RuleTester') ); } module.exports = { /** * Performs static analysis on an AST to try to determine the final value of `module.exports`. * @param {ASTNode} ast The `Program` AST node * @returns {Object} An object with keys `meta`, `create`, and `isNewStyle`. `meta` and `create` correspond to the AST nodes for the final values of `module.exports.meta` and `module.exports.create`. `isNewStyle` will be `true` if `module.exports` is an object, and `false` if module.exports is just the `create` function. If no valid ESLint rule info can be extracted from the file, the return value will be `null`. */ getRuleInfo (ast, scopeManager) { const INTERESTING_KEYS = new Set(['create', 'meta']); let exportsVarOverridden = false; let exportsIsFunction = false; const exportNodes = ast.body .filter(statement => statement.type === 'ExpressionStatement') .map(statement => statement.expression) .filter(expression => expression.type === 'AssignmentExpression') .filter(expression => expression.left.type === 'MemberExpression') .reduce((currentExports, node) => { if ( node.left.object.type === 'Identifier' && node.left.object.name === 'module' && node.left.property.type === 'Identifier' && node.left.property.name === 'exports' ) { exportsVarOverridden = true; if (isNormalFunctionExpression(node.right)) { // Check `module.exports = function () {}` exportsIsFunction = true; return { create: node.right, meta: null }; } else if (node.right.type === 'ObjectExpression') { // Check `module.exports = { create: function () {}, meta: {} }` exportsIsFunction = false; return node.right.properties.reduce((parsedProps, prop) => { const keyValue = module.exports.getKeyName(prop); if (INTERESTING_KEYS.has(keyValue)) { parsedProps[keyValue] = prop.value; } return parsedProps; }, {}); } return {}; } else if ( !exportsIsFunction && node.left.object.type === 'MemberExpression' && node.left.object.object.type === 'Identifier' && node.left.object.object.name === 'module' && node.left.object.property.type === 'Identifier' && node.left.object.property.name === 'exports' && node.left.property.type === 'Identifier' && INTERESTING_KEYS.has(node.left.property.name) ) { // Check `module.exports.create = () => {}` currentExports[node.left.property.name] = node.right; } else if ( !exportsVarOverridden && node.left.object.type === 'Identifier' && node.left.object.name === 'exports' && node.left.property.type === 'Identifier' && INTERESTING_KEYS.has(node.left.property.name) ) { // Check `exports.create = () => {}` currentExports[node.left.property.name] = node.right; } return currentExports; }, {}); const createExists = Object.prototype.hasOwnProperty.call(exportNodes, 'create'); if (!createExists) { return null; } const createIsFunction = isNormalFunctionExpression(exportNodes.create); const createIsFunctionReference = isNormalFunctionExpressionReference(exportNodes.create, scopeManager); if (!createIsFunction && !createIsFunctionReference) { return null; } return Object.assign({ isNewStyle: !exportsIsFunction, meta: null }, exportNodes); }, /** * Gets all the identifiers referring to the `context` variable in a rule source file. Note that this function will * only work correctly after traversing the AST has started (e.g. in the first `Program` node). * @param {RuleContext} context The `context` variable for the source file itself * @param {ASTNode} ast The `Program` node for the file * @returns {Set} A Set of all `Identifier` nodes that are references to the `context` value for the file */ getContextIdentifiers (context, ast) { const ruleInfo = module.exports.getRuleInfo(ast); if (!ruleInfo || !ruleInfo.create.params.length || ruleInfo.create.params[0].type !== 'Identifier') { return new Set(); } return new Set( context.getDeclaredVariables(ruleInfo.create) .find(variable => variable.name === ruleInfo.create.params[0].name) .references .map(ref => ref.identifier) ); }, /** * Gets the key name of a Property, if it can be determined statically. * @param {ASTNode} node The `Property` node * @returns {string|null} The key name, or `null` if the name cannot be determined statically. */ getKeyName (property) { if (!property.key) { // likely a SpreadElement or another non-standard node return null; } if (!property.computed && property.key.type === 'Identifier') { return property.key.name; } if (property.key.type === 'Literal') { return '' + property.key.value; } if (property.key.type === 'TemplateLiteral' && property.key.quasis.length === 1) { return property.key.quasis[0].value.cooked; } return null; }, /** * Performs static analysis on an AST to try to find test cases * @param {RuleContext} context The `context` variable for the source file itself * @param {ASTNode} ast The `Program` node for the file. * @returns {object} An object with `valid` and `invalid` keys containing a list of AST nodes corresponding to tests */ getTestInfo (context, ast) { const runCalls = []; const variableIdentifiers = new Set(); ast.body.forEach(statement => { if (statement.type === 'VariableDeclaration') { statement.declarations.forEach(declarator => { if (declarator.init && isRuleTesterConstruction(declarator.init) && declarator.id.type === 'Identifier') { context.getDeclaredVariables(declarator).forEach(variable => { variable.references.filter(ref => ref.isRead()).forEach(ref => variableIdentifiers.add(ref.identifier)); }); } }); } if ( statement.type === 'ExpressionStatement' && statement.expression.type === 'CallExpression' && statement.expression.callee.type === 'MemberExpression' && ( isRuleTesterConstruction(statement.expression.callee.object) || variableIdentifiers.has(statement.expression.callee.object) ) && statement.expression.callee.property.type === 'Identifier' && statement.expression.callee.property.name === 'run' ) { runCalls.push(statement.expression); } }); return runCalls .filter(call => call.arguments.length >= 3 && call.arguments[2].type === 'ObjectExpression') .map(call => call.arguments[2]) .map(run => { const validProperty = run.properties.find(prop => module.exports.getKeyName(prop) === 'valid'); const invalidProperty = run.properties.find(prop => module.exports.getKeyName(prop) === 'invalid'); return { valid: validProperty && validProperty.value.type === 'ArrayExpression' ? validProperty.value.elements.filter(Boolean) : [], invalid: invalidProperty && invalidProperty.value.type === 'ArrayExpression' ? invalidProperty.value.elements.filter(Boolean) : [], }; }); }, /** * Gets information on a report, given the arguments passed to context.report(). * @param {ASTNode[]} reportArgs The arguments passed to context.report() */ getReportInfo (reportArgs) { // If there is exactly one argument, the API expects an object. // Otherwise, if the second argument is a string, the arguments are interpreted as // ['node', 'message', 'data', 'fix']. // Otherwise, the arguments are interpreted as ['node', 'loc', 'message', 'data', 'fix']. if (!reportArgs.length) { return null; } if (reportArgs.length === 1) { if (reportArgs[0].type === 'ObjectExpression') { return reportArgs[0].properties.reduce((reportInfo, property) => { const propName = module.exports.getKeyName(property); if (propName !== null) { return Object.assign(reportInfo, { [propName]: property.value }); } return reportInfo; }, {}); } return null; } let keys; if ( (reportArgs[1].type === 'Literal' && typeof reportArgs[1].value === 'string') || reportArgs[1].type === 'TemplateLiteral' ) { keys = ['node', 'message', 'data', 'fix']; } else if ( reportArgs[1].type === 'ObjectExpression' || reportArgs[1].type === 'ArrayExpression' || (reportArgs[1].type === 'Literal' && typeof reportArgs[1].value !== 'string') ) { keys = ['node', 'loc', 'message', 'data', 'fix']; } else { // Otherwise, we can't statically determine what argument means what, so no safe fix is possible. return null; } return keys .slice(0, reportArgs.length) .reduce((reportInfo, key, index) => Object.assign(reportInfo, { [key]: reportArgs[index] }), {}); }, /** * Gets a set of all `sourceCode` identifiers. * @param {RuleContext} context The context for the rule file * @param {ASTNode} ast The AST of the file. This must have `parent` properties. * @returns {Set} A set of all identifiers referring to the `SourceCode` object. */ getSourceCodeIdentifiers (context, ast) { return new Set(Array.from(module.exports.getContextIdentifiers(context, ast)) .filter(identifier => identifier.parent && identifier.parent.type === 'MemberExpression' && identifier === identifier.parent.object && identifier.parent.property.type === 'Identifier' && identifier.parent.property.name === 'getSourceCode' && identifier.parent.parent.type === 'CallExpression' && identifier.parent === identifier.parent.parent.callee && identifier.parent.parent.parent.type === 'VariableDeclarator' && identifier.parent.parent === identifier.parent.parent.parent.init && identifier.parent.parent.parent.id.type === 'Identifier' ) .map(identifier => context.getDeclaredVariables(identifier.parent.parent.parent)) .reduce((allVariables, variablesForIdentifier) => allVariables.concat(variablesForIdentifier), []) .map(variable => variable.references) .reduce((allRefs, refsForVariable) => allRefs.concat(refsForVariable), []) .map(ref => ref.identifier)); }, /** * Insert a given property into a given object literal. * @param {SourceCodeFixer} fixer The fixer. * @param {Node} node The ObjectExpression node to insert a property. * @param {string} propertyText The property code to insert. * @returns {void} */ insertProperty (fixer, node, propertyText, sourceCode) { if (node.properties.length === 0) { return fixer.replaceText(node, `{\n${propertyText}\n}`); } return fixer.insertTextAfter( sourceCode.getLastToken(node.properties[node.properties.length - 1]), `,\n${propertyText}` ); }, }; eslint-plugin-eslint-plugin-2.3.0/package.json000066400000000000000000000026131367425336200214010ustar00rootroot00000000000000{ "name": "eslint-plugin-eslint-plugin", "version": "2.3.0", "description": "An ESLint plugin for linting ESLint plugins", "author": "Teddy Katz", "main": "lib/index.js", "license": "MIT", "scripts": { "lint": "eslint . --ignore-pattern \"!.*\"", "pretest": "npm run lint", "generate-readme-table": "node build/generate-readme-table.js", "generate-release": "node-release-script", "test": "mocha tests --recursive" }, "files": [ "lib/" ], "keywords": [ "eslint", "eslintplugin", "eslint-plugin" ], "repository": { "type": "git", "url": "git+https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin.git" }, "bugs": { "url": "https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues" }, "homepage": "https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin#readme", "dependencies": {}, "devDependencies": { "@not-an-aardvark/node-release-script": "^0.1.0", "chai": "^4.1.0", "dirty-chai": "^2.0.1", "escope": "^3.6.0", "eslint": "^7.0.0-alpha.3", "eslint-config-not-an-aardvark": "^2.1.0", "eslint-plugin-node": "^11.1.0", "eslint-plugin-self": "^1.0.1", "espree": "^6.2.1", "estraverse": "^5.0.0", "lodash": "^4.17.2", "mocha": "^7.1.1" }, "peerDependencies": { "eslint": ">=5.0.0" }, "engines": { "node": "^6.14.0 || ^8.10.0 || >=9.10.0" } } eslint-plugin-eslint-plugin-2.3.0/tests/000077500000000000000000000000001367425336200202535ustar00rootroot00000000000000eslint-plugin-eslint-plugin-2.3.0/tests/.eslintrc.yml000066400000000000000000000000231367425336200226720ustar00rootroot00000000000000env: mocha: true eslint-plugin-eslint-plugin-2.3.0/tests/build/000077500000000000000000000000001367425336200213525ustar00rootroot00000000000000eslint-plugin-eslint-plugin-2.3.0/tests/build/generate-readme-table.js000066400000000000000000000010161367425336200260200ustar00rootroot00000000000000'use strict'; const fs = require('fs'); const path = require('path'); const assert = require('chai').assert; describe('table in README.md', () => { it('is up-to-date', () => { const actualReadme = fs.readFileSync(path.resolve(__dirname, '..', '..', 'README.md'), 'utf8'); const expectedReadme = require('../../build/generate-readme-table'); assert( actualReadme === expectedReadme, 'The table in README.md is out of date. Please use `npm run generate-readme-table` to update it.' ); }); }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/000077500000000000000000000000001367425336200210215ustar00rootroot00000000000000eslint-plugin-eslint-plugin-2.3.0/tests/lib/index.js000066400000000000000000000007711367425336200224730ustar00rootroot00000000000000'use strict'; const assert = require('chai').assert; const plugin = require('../..'); describe('exported plugin', () => { describe('adds a meta.docs.url property to each rule', () => { Object.keys(plugin.rules).forEach(ruleName => { it(ruleName, () => { assert.match( plugin.rules[ruleName].meta.docs.url, /^https:\/\/github.com\/not-an-aardvark\/eslint-plugin-eslint-plugin\/tree\/v\d+\.\d+\.\d+\/docs\/rules\/[\w-]+\.md$/ ); }); }); }); }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/000077500000000000000000000000001367425336200221535ustar00rootroot00000000000000eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/consistent-output.js000066400000000000000000000046051367425336200262450ustar00rootroot00000000000000/** * @fileoverview Enforce consistent use of output assertions in rule tests * @author Teddy Katz */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/consistent-output'); const RuleTester = require('eslint').RuleTester; const ERROR = { message: 'This test case should have an output assertion.', type: 'ObjectExpression' }; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester(); ruleTester.run('consistent-output', rule, { valid: [ ` new RuleTester().run('foo', bar, { valid: [], invalid: [ { code: 'foo', errors: ['bar'] }, { code: 'baz', errors: ['qux'] } ] }); `, ` new RuleTester().run('foo', bar, { valid: [], invalid: [ { code: 'foo', output: 'baz', errors: ['bar'], }, { code: 'foo', output: 'qux', errors: ['bar'] } ] }); `, { code: ` new RuleTester().run('foo', bar, { valid: [], invalid: [ { code: 'foo', output: 'baz', errors: ['bar'] }, ] }); `, options: ['always'], }, ], invalid: [ { code: ` new RuleTester().run('foo', bar, { valid: [], invalid: [ { code: 'foo', output: 'baz', errors: ['bar'], }, { code: 'foo', errors: ['bar'] }, { code: 'foo bar', errors: ['bar'] } ] }); `, errors: [ERROR, ERROR], }, { code: ` new RuleTester().run('foo', bar, { valid: [], invalid: [ { code: 'foo', errors: ['bar'], }, ] }); `, options: ['always'], errors: [ERROR], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/fixer-return.js000066400000000000000000000044501367425336200251460ustar00rootroot00000000000000/** * @fileoverview enforces always return from a fixer function * @author 薛定谔的猫 */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/fixer-return'); const RuleTester = require('eslint').RuleTester; const ERROR = { message: 'Expected fixer function to always return a value.' }; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run('fixer-return', rule, { valid: [ ` module.exports = { create: function(context) { context.report( { fix: function(fixer) { return fixer.foo(); } }); } }; `, ` module.exports = { create: function(context) { context.report( { fix: function(fixer) { return [ fixer.foo(), fixer.bar() ]; } }); } }; `, ` module.exports = { create: function(context) { context.report({ fix: fixer => fixer.foo() }); } }; `, ` module.exports = { create: function (context) { context.report({ fix: function* (fixer) { yield fixer.foo(); } }); } }; `, ], invalid: [ { code: ` module.exports = { create: function(context) { context.report({ fix(fixer) { fixer.foo(); } }); } }; `, errors: [ERROR], }, { code: ` module.exports = { create: function(context) { context.report({ *fix(fixer) { fixer.foo(); } }); } }; `, errors: [ERROR], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/meta-property-ordering.js000066400000000000000000000056341367425336200271400ustar00rootroot00000000000000/** * @fileoverview Enforces the order of meta properties */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/meta-property-ordering'); const RuleTester = require('eslint').RuleTester; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ /** * @param {string[]} order * @returns {string} */ function getMessage (order) { return `The meta properties should be placed in a consistent order: [${order.join(', ')}].`; } const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run('test-case-property-ordering', rule, { valid: [ ` module.exports = { meta: {type, docs, fixable, schema, messages}, create() {}, };`, ` module.exports = { meta: {docs, schema, messages}, create() {}, };`, ` module.exports = { meta: {docs, messages, foo, bar}, create() {}, };`, ` module.exports = { meta: { type: 'problem', docs: {}, fixable: 'code', schema: [], messages: {} }, create() {}, };`, { code: ` module.exports = { meta: {schema, docs, fixable}, create() {}, };`, options: [['schema', 'docs']], }, ` module.exports = { meta: {}, create() {}, };`, ], invalid: [ { code: ` module.exports = { meta: { docs, fixable, type: 'problem', }, create() {}, };`, output: ` module.exports = { meta: { type: 'problem', docs, fixable, }, create() {}, };`, errors: [{ message: getMessage(['type', 'docs', 'fixable']) }], }, { code: ` module.exports = { meta: {schema, fixable, type, docs}, create() {}, };`, output: ` module.exports = { meta: {type, docs, fixable, schema}, create() {}, };`, errors: [ { message: getMessage(['type', 'docs', 'fixable', 'schema']) }, { message: getMessage(['type', 'docs', 'fixable', 'schema']) }, ], }, { code: ` module.exports = { meta: {fixable, fooooooooo, doc, type}, create() {}, };`, output: ` module.exports = { meta: {type, doc, fixable, fooooooooo}, create() {}, };`, options: [['type', 'doc', 'fixable']], errors: [ { message: getMessage(['type', 'doc', 'fixable']) }, { message: getMessage(['type', 'doc', 'fixable']) }, ], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/no-deprecated-context-methods.js000066400000000000000000000041251367425336200303500ustar00rootroot00000000000000/** * @fileoverview Disallows usage of deprecated methods on rule context objects * @author Teddy Katz */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/no-deprecated-context-methods'); const RuleTester = require('eslint').RuleTester; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run('no-deprecated-context-methods', rule, { valid: [ ` module.exports = { create(context) { context.getSourceCode(); } } `, ` module.exports = context => { const sourceCode = context.getSourceCode(); sourceCode.getFirstToken(); } `, ], invalid: [ { code: ` module.exports = { create(context) { return { Program(node) { context.getSource(node); } } } } `, output: ` module.exports = { create(context) { return { Program(node) { context.getSourceCode().getText(node); } } } } `, errors: [ { message: 'Use `context.getSourceCode().getText` instead of `context.getSource`.', type: 'MemberExpression', }, ], }, { code: ` module.exports = myRuleContext => { myRuleContext.getFirstToken; } `, output: ` module.exports = myRuleContext => { myRuleContext.getSourceCode().getFirstToken; } `, errors: [ { message: 'Use `myRuleContext.getSourceCode().getFirstToken` instead of `myRuleContext.getFirstToken`.', type: 'MemberExpression', }, ], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/no-deprecated-report-api.js000066400000000000000000000122101367425336200272770ustar00rootroot00000000000000/** * @fileoverview disallow use of the deprecated context.report() API * @author Teddy Katz */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/no-deprecated-report-api'); const RuleTester = require('eslint').RuleTester; const ERROR = { message: 'Use the new-style context.report() API.', type: 'Identifier' }; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run('no-deprecated-report-api', rule, { valid: [ ` module.exports = { create(context) { context.report({ node, message: "Foo." }); } }; `, ` module.exports = { create(context) { foo.report(bar, baz); } }; `, ` module.exports = function(context) { context.report({node, message: "Foo"}); }; `, ` module.exports = (context) => { context.report({node, message: "Foo"}); }; `, ` module.exports = { create(notContext) { notContext.report({node, message: "foo"}); } }; `, ` module.exports = { create([context]) { context.report(node, message); } }; `, ], invalid: [ { code: ` module.exports = { create(context) { context.report(node, "This {{thing}} is bad", { thing: foo ? "node" : "token" }, fix); } }; `, output: ` module.exports = { create(context) { context.report({node: node, message: "This {{thing}} is bad", data: { thing: foo ? "node" : "token" }, fix: fix}); } }; `, errors: [ERROR], }, { code: ` module.exports = { create(context) { context.report(theNode, { line: foo, column: bar }, theMessage, theData, theFix); } }; `, output: ` module.exports = { create(context) { context.report({node: theNode, loc: { line: foo, column: bar }, message: theMessage, data: theData, fix: theFix}); } }; `, errors: [ERROR], }, { code: ` module.exports = { create(context) { context.report(theNode, "theMessage", theData, theFix); } }; `, output: ` module.exports = { create(context) { context.report({node: theNode, message: "theMessage", data: theData, fix: theFix}); } }; `, errors: [ERROR], }, { code: ` module.exports = { create(context) { context.report(theNode, theMessage, theData, theFix); } }; `, output: null, errors: [ERROR], }, { code: ` module.exports = { create(context) { context.report(theNode, 'foo', theData); } }; `, output: ` module.exports = { create(context) { context.report({node: theNode, message: 'foo', data: theData}); } }; `, errors: [ERROR], }, { code: ` module.exports = { create(context) { context.report(theNode, 'foo'); } }; `, output: ` module.exports = { create(context) { context.report({node: theNode, message: 'foo'}); } }; `, errors: [ERROR], }, { code: ` module.exports = { create(notContext) { notContext.report(theNode, theMessage, theData, theFix); } }; `, output: null, errors: [ERROR], }, { code: ` module.exports.create = context => { context.report(theNode, \`blah\`, theData, theFix); }; `, output: ` module.exports.create = context => { context.report({node: theNode, message: \`blah\`, data: theData, fix: theFix}); }; `, errors: [ERROR], }, { code: ` module.exports.create = context => { context.report(theNode, 5, foo, bar); }; `, output: ` module.exports.create = context => { context.report({node: theNode, loc: 5, message: foo, data: bar}); }; `, errors: [ERROR], }, { code: ` module.exports = { create(context) { context.report(theNode, theLocation, theMessage, theData, theFix, somethingElse, somethingElse, somethingElse); } }; `, output: null, errors: [ERROR], }, { code: ` module.exports = { create(context) { context.report(...error); } }; `, output: null, errors: [ERROR], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/no-identical-tests.js000066400000000000000000000064231367425336200262240ustar00rootroot00000000000000/** * @fileoverview disallow identical tests * @author 薛定谔的猫 */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/no-identical-tests'); const RuleTester = require('eslint').RuleTester; const ERROR = { message: 'This test case is identical to another case.' }; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester(); ruleTester.run('no-identical-tests', rule, { valid: [ ` new RuleTester().run('foo', bar, { valid: [ { code: 'foo' }, { code: 'bar' }, ], invalid: [] }); `, ` new RuleTester().run('foo', bar, { valid: [ { code: 'foo' } ], invalid: [] }); `, ` new RuleTester().run('foo', bar, { valid: [ 'foo', ], invalid: [] }); `, ], invalid: [ { code: ` new RuleTester().run('foo', bar, { valid: [ { code: 'foo' }, { code: 'foo' }, ], invalid: [] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ { code: 'foo' }, ], invalid: [] }); `, errors: [ERROR], }, { code: ` new RuleTester().run('foo', bar, { valid: [ { code: 'foo' }, { code: 'foo' } ], invalid: [] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ { code: 'foo' }, ], invalid: [] }); `, errors: [ERROR], }, { code: ` new RuleTester().run('foo', bar, { valid: [ { code: 'foo' }, { code: 'foo' }, ], invalid: [ { code: 'foo', errors: ['bar'] }, { code: 'foo', errors: ['bar'] }, ] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ { code: 'foo' }, ], invalid: [ { code: 'foo', errors: ['bar'] }, ] }); `, errors: [ERROR, ERROR], }, { code: ` new RuleTester().run('foo', bar, { valid: [ { code: 'foo', options: ['bar'] }, { options: ['bar'], code: 'foo' }, ], invalid: [] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ { code: 'foo', options: ['bar'] }, ], invalid: [] }); `, errors: [ERROR], }, { code: ` new RuleTester().run('foo', bar, { valid: [ 'foo', 'foo', ], invalid: [] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ 'foo', ], invalid: [] }); `, errors: [ERROR], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/no-missing-placeholders.js000066400000000000000000000101061367425336200272350ustar00rootroot00000000000000/** * @fileoverview Disallow missing placeholders in rule report messages * @author Teddy Katz */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/no-missing-placeholders'); const RuleTester = require('eslint').RuleTester; /** * Create an error for the given key * @param {string} missingKey The placeholder that is missing * @returns {object} An expected error */ function error (missingKey) { return { type: 'Literal', message: `The placeholder {{${missingKey}}} does not exist.` }; } // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run('no-missing-placeholders', rule, { valid: [ ` module.exports = { create(context) { context.report({ node, message: 'foo bar' }); } }; `, ` module.exports = { create(context) { context.report({ node, message: 'foo {{bar}}', data: { bar: 'baz' } }); } }; `, ` module.exports = { create(context) { context.report({ node, message: 'foo {{bar}}', data: { 'bar': 'baz' } }); } }; `, ` module.exports = { create(context) { context.report({ node, message: 'foo {{bar}}', data: { bar } }); } }; `, ` module.exports = { create(context) { context.report({ node, message: 'foo{{bar}}' + baz }); } }; `, ` module.exports = context => { context.report(node, 'foo {{bar}}', { bar: 'baz' }); }; `, ` module.exports = context => { context.report(node, { line: 1, column: 3 }, 'foo {{bar}}', { bar: 'baz' }); }; `, ` module.exports = { create(context) { context.report({ node, message: 'foo{{ bar }}', data: { bar: 'baz' } }); } }; `, ` module.exports = { create(context) { context.report({ node, message: 'foo{{ bar }}', data: baz }); } }; `, ], invalid: [ { code: ` module.exports = { create(context) { context.report({ node, message: 'foo {{bar}}' }); } }; `, errors: [error('bar')], }, { code: ` module.exports = { create(context) { context.report({ node, message: 'foo {{bar}}', data: { baz: 'qux' } }); } }; `, errors: [error('bar')], }, { code: ` module.exports = { create(context) { context.report({ node, message: 'foo {{hasOwnProperty}}', data: {} }); } }; `, errors: [error('hasOwnProperty')], }, { code: ` module.exports = context => { context.report(node, 'foo {{bar}}', { baz: 'qux' }); }; `, errors: [error('bar')], }, { code: ` module.exports = context => { context.report(node, { line: 1, column: 3 }, 'foo {{bar}}', { baz: 'baz' }); }; `, errors: [error('bar')], }, { code: ` module.exports = { create(context) { context.report({ node, message: 'foo{{ bar }}', data: { ' bar ': 'baz' } }); } }; `, errors: [error('bar')], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/no-unused-placeholders.js000066400000000000000000000061411367425336200270730ustar00rootroot00000000000000/** * @fileoverview Disallow unused placeholders in rule report messages * @author 薛定谔的猫 */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/no-unused-placeholders'); const RuleTester = require('eslint').RuleTester; /** * Create an error for the given key * @param {string} unusedKey The placeholder that is unused * @returns {object} An expected error */ function error (unusedKey) { return { type: 'Literal', message: `The placeholder {{${unusedKey}}} is unused.` }; } // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run('no-unused-placeholders', rule, { valid: [ ` module.exports = { create(context) { context.report({ node, message: 'foo{{ bar }}', data: { bar: 'baz' } }); } }; `, ` module.exports = { create(context) { context.report({ node, message: 'foo bar' }); } }; `, ` module.exports = { create(context) { context.report({ node, message: 'foo {{bar}}', data: { bar: 'baz' } }); } }; `, ` module.exports = { create(context) { context.report({ node, message: 'foo {{bar}}', data: { 'bar': 'baz' } }); } }; `, ` module.exports = { create(context) { context.report({ node, message: 'foo {{bar}}', data: { bar } }); } }; `, ` module.exports = context => { context.report(node, 'foo {{bar}}', { bar: 'baz' }); }; `, ` module.exports = context => { context.report(node, { line: 1, column: 3 }, 'foo {{bar}}', { bar: 'baz' }); }; `, ], invalid: [ { code: ` module.exports = { create(context) { context.report({ node, message: 'foo', data: { bar } }); } }; `, errors: [error('bar')], }, { code: ` module.exports = { create(context) { context.report({ node, message: 'foo', data: { bar: '' } }); } }; `, errors: [error('bar')], }, { code: ` module.exports = { create(context) { context.report({ node, message: 'foo {{bar}}', data: { baz: '' } }); } }; `, errors: [error('baz')], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/no-useless-token-range.js000066400000000000000000000054571367425336200270310ustar00rootroot00000000000000/** * @fileoverview Disallow unnecessary calls to sourceCode.getFirstToken and sourceCode.getLastToken * @author Teddy Katz */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/no-useless-token-range'); const RuleTester = require('eslint').RuleTester; /** * Wraps a code sample as an eslint rule * @param {string} code source text given a `sourceCode` variable * @returns {string} rule code containing that source text */ function wrapRule (code) { return ` module.exports = { create(context) { const sourceCode = context.getSourceCode(); ${code} } }; `; } // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run('no-useless-token-range', rule, { valid: [ 'sourceCode.getLastToken(foo).range[0]', 'sourceCode.getFirstToken(foo).range[1]', 'sourceCode.getLastToken(foo).start', 'sourceCode.getFirstToken(foo).end', 'sourceCode.getSomethingElse(foo).range[0]', 'notSourceCode.getFirstToken(foo).range[0]', 'sourceCode.getFirstToken(foo, bar).range[0]', 'sourceCode.getFirstToken(foo, { skip: 1 }).start', 'sourceCode.getLastToken(foo, bar).range[1]', 'sourceCode.getLastToken(foo, { skip: 1 }).end', ].map(wrapRule), invalid: [ { code: 'sourceCode.getFirstToken(foo).range[0]', output: 'foo.range[0]', errors: [{ message: "Use 'foo.range[0]' instead.", type: 'CallExpression' }], }, { code: 'sourceCode.getFirstToken(foo).start', output: 'foo.start', errors: [{ message: "Use 'foo.start' instead.", type: 'CallExpression' }], }, { code: 'sourceCode.getLastToken(foo).range[1]', output: 'foo.range[1]', errors: [{ message: "Use 'foo.range[1]' instead.", type: 'CallExpression' }], }, { code: 'sourceCode.getLastToken(foo).end', output: 'foo.end', errors: [{ message: "Use 'foo.end' instead.", type: 'CallExpression' }], }, { code: 'sourceCode.getFirstToken(foo, { includeComments: true }).range[0]', output: 'foo.range[0]', errors: [{ message: "Use 'foo.range[0]' instead.", type: 'CallExpression' }], }, { code: 'sourceCode.getLastToken(foo, { includeComments: true }).range[1]', output: 'foo.range[1]', errors: [{ message: "Use 'foo.range[1]' instead.", type: 'CallExpression' }], }, ].map(invalidCase => Object.assign(invalidCase, { code: wrapRule(invalidCase.code), output: wrapRule(invalidCase.output) })), }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/prefer-object-rule.js000066400000000000000000000051231367425336200262060ustar00rootroot00000000000000/** * @author Brad Zacher */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/prefer-object-rule'); const RuleTester = require('eslint').RuleTester; const ERROR = { messageId: 'preferObject', line: 2, column: 26 }; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run('prefer-object-rule', rule, { valid: [ ` module.exports = { create(context) { return { Program() { context.report() } }; }, }; `, ` module.exports = { create: (context) => { return { Program() { context.report() } }; }, }; `, ` module.exports.create = (context) => { return { Program() { context.report() } }; }; `, ` module.exports.create = function (context) { return { Program() { context.report() } }; }; `, ` module.exports.create = function create(context) { return { Program() { context.report() } }; }; `, ` function create(context) { return { Program() { context.report() } }; }; module.exports.create = create; `, ` const rule = { create(context) { return { Program() { context.report() } }; }, }; module.exports = rule; `, ], invalid: [ { code: ` module.exports = function (context) { return { Program() { context.report() } }; }; `, output: ` module.exports = {create(context) { return { Program() { context.report() } }; }}; `, errors: [ERROR], }, { code: ` module.exports = function create(context) { return { Program() { context.report() } }; }; `, output: ` module.exports = {create(context) { return { Program() { context.report() } }; }}; `, errors: [ERROR], }, { code: ` module.exports = (context) => { return { Program() { context.report() } }; }; `, output: ` module.exports = {create: (context) => { return { Program() { context.report() } }; }}; `, errors: [ERROR], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/prefer-output-null.js000066400000000000000000000033101367425336200262770ustar00rootroot00000000000000/** * @fileoverview disallows invalid RuleTester test cases with the output the same as the code. * @author 薛定谔的猫 */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/prefer-output-null'); const RuleTester = require('eslint').RuleTester; const ERROR = { message: 'Use `output: null` to assert that a test case is not autofixed.' }; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester(); ruleTester.run('prefer-output-null', rule, { valid: [ ` new RuleTester().run('foo', bar, { valid: [], invalid: [ {code: 'foo', output: 'bar', errors: ['bar']}, ] }); `, ` new RuleTester().run('foo', bar, { valid: [], invalid: [ {code: 'foo', output: null, errors: ['bar']}, ] }); `, ` new RuleTester().run('foo', bar, { valid: [ 'foo' ], invalid: [] }); `, ], invalid: [ { code: ` new RuleTester().run('foo', bar, { valid: [], invalid: [ {code: 'foo', output: 'foo', errors: ['bar']}, ] }); `, output: ` new RuleTester().run('foo', bar, { valid: [], invalid: [ {code: 'foo', output: null, errors: ['bar']}, ] }); `, errors: [ERROR], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/prefer-placeholders.js000066400000000000000000000042241367425336200264410ustar00rootroot00000000000000/** * @fileoverview disallow template literals as report messages * @author Teddy Katz */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/prefer-placeholders'); const RuleTester = require('eslint').RuleTester; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); const ERROR = { message: 'Use report message placeholders instead of string concatenation.' }; ruleTester.run('prefer-placeholders', rule, { valid: [ ` module.exports = { create(context) { context.report({ node, message: '{{foo}} is bad.', data: { foo }, }); } }; `, ` module.exports = { create(context) { context.report({ node, message: 'foo is bad.' }); } }; `, ` module.exports = { create(context) { context.report({ node, message: foo }); } }; `, ` module.exports = { create(context) { context.report(node, 'foo is bad.'); } }; `, ], invalid: [ { code: ` module.exports = { create(context) { context.report({ node, message: \`\${foo} is bad.\` }); } }; `, errors: [ERROR], }, { code: ` module.exports = { create(context) { context.report({ node, message: foo + ' is bad.' }); } }; `, errors: [ERROR], }, { code: ` module.exports = { create(context) { context.report(node, \`\${foo} is bad.\`); } }; `, errors: [ERROR], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/prefer-replace-text.js000066400000000000000000000056351367425336200264000ustar00rootroot00000000000000/** * @fileoverview prefer using replaceText instead of replaceTextRange * @author 薛定谔的猫 */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/prefer-replace-text'); const RuleTester = require('eslint').RuleTester; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); const ERROR = { message: 'Use replaceText instead of replaceTextRange.' }; ruleTester.run('prefer-placeholders', rule, { valid: [ ` module.exports = { create(context) { context.report({ fix(fixer) { return fixer.replaceTextRange([start, end], ''); } }); } }; `, ` module.exports = { create(context) { context.report({ fix(fixer) { return fixer.replaceTextRange([node1[0], node2[1]], ''); } }); } }; `, ` module.exports = { create(context) {} }; `, ` fixer.replaceTextRange([node.range[0], node.range[1]], ''); `, ], invalid: [ { code: ` module.exports = { create(context) { context.report({ fix(fixer) { return fixer.replaceTextRange([node.range[0], node.range[1]], ''); } }); } }; `, errors: [ERROR], }, { code: ` module.exports = { create(context) { context.report({ fix: function(fixer) { return fixer.replaceTextRange([node.range[0], node.range[1]], ''); } }); } }; `, errors: [ERROR], }, { code: ` module.exports = { create(context) { context.report({ fix: function(fixer) { if (foo) {return fixer.replaceTextRange([node.range[0], node.range[1]], '')} } }); } }; `, errors: [ERROR], }, { code: ` module.exports = { create(context) { context.report({ fix: fixer => fixer.replaceTextRange([node.range[0], node.range[1]], '') }); } }; `, errors: [ERROR], }, { code: ` module.exports = { create(context) { context.report({ fix(fixer) { return fixer.replaceTextRange([node.start, node.end], ''); } }); } }; `, errors: [ERROR], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/report-message-format.js000066400000000000000000000103231367425336200267330ustar00rootroot00000000000000/** * @fileoverview enforce a consistent format for rule report messages * @author Teddy Katz */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/report-message-format'); const RuleTester = require('eslint').RuleTester; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run('report-message-format', rule, { valid: [ // with no configuration, everything is allowed 'module.exports = context => context.report(node, "foo");', { code: ` module.exports = { create(context) { context.report(node, 'foo'); } }; `, options: ['foo'], }, { code: ` module.exports = { create(context) { context.report(node, 'foo'); } }; `, options: ['f'], }, { code: ` module.exports = { create(context) { context.report(node, message); } }; `, options: ['foo'], }, { code: ` module.exports = { create(context) { context.report(node, 'not foo' + message); } }; `, options: ['^foo$'], }, { code: ` module.exports = { create(context) { context.report({node, message: 'foo'}); } }; `, options: ['^foo$'], }, { code: ` module.exports = { create(context) { context.report({node, message: 'foobarbaz'}); } }; `, options: ['bar'], }, { code: ` module.exports = { create(context) { context.report({node, message: \`foobarbaz\`}); } }; `, options: ['bar'], }, { code: ` module.exports = { create(context) { context.report(); } }; `, options: ['bar'], }, { code: ` module.exports = { create(context) { context.report({}); } }; `, options: ['foo'], }, { code: ` module.exports = { meta: { messages: { message1: 'foo bar', message2: 'bar foobar' } }, create: context => ({}) } `, options: ['foo'], }, ], invalid: [ { code: ` module.exports = { create(context) { context.report(node, 'bar'); } }; `, options: ['foo'], }, { code: ` module.exports = { create(context) { context.report(node, 'foobar'); } }; `, options: ['^foo$'], }, { code: ` module.exports = { create(context) { context.report(node, 'FOO'); } }; `, options: ['foo'], }, { code: ` module.exports = { create(context) { context.report(node, \`FOO\`); } }; `, options: ['foo'], }, { code: ` module.exports = { create(context) { context.report({node, message: 'FOO'}); } }; `, options: ['foo'], }, { code: ` module.exports = { create(context) { context.report({node, message: \`FOO\`}); } }; `, options: ['foo'], }, { code: ` module.exports = { meta: { messages: { message1: 'bar' } }, create: context => ({}) }; `, options: ['foo'], }, ].map(invalidCase => { return Object.assign({ errors: [{ message: `Report message does not match the pattern '${invalidCase.options[0]}'.` }], }, invalidCase); }), }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/require-meta-docs-description.js000066400000000000000000000075421367425336200303700ustar00rootroot00000000000000'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/require-meta-docs-description'); const RuleTester = require('eslint').RuleTester; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run('require-meta-docs-description', rule, { valid: [ ` module.exports = { meta: { docs: { description: 'disallow unused variables' } }, create(context) {} }; `, ` module.exports = { meta: { docs: { description: 'enforce a maximum line length' } }, create(context) {} }; `, ` module.exports = { meta: { docs: { description: 'require or disallow newline at the end of files' } }, create(context) {} }; `, { code: ` module.exports = { meta: { docs: { description: 'myPrefix foo bar' } }, create(context) {} }; `, options: [{ pattern: '^myPrefix' }], }, { code: ` module.exports = { meta: { docs: { description: 'random message' } }, create(context) {} }; `, options: [{ pattern: '.+' }], // any description allowed }, ], invalid: [ { code: ` module.exports = { meta: {}, create(context) {} }; `, output: null, errors: [{ messageId: 'missing', type: 'ObjectExpression' }], }, { code: ` module.exports = { meta: { docs: {} }, create(context) {} }; `, output: null, errors: [{ messageId: 'missing', type: 'Property' }], }, { code: ` module.exports = { meta: { docs: { description: [] } }, create(context) {} }; `, output: null, errors: [{ messageId: 'wrongType', type: 'ArrayExpression' }], }, { code: ` module.exports = { meta: { docs: { description: \`enforce with template literal\` } }, create(context) {} }; `, output: null, errors: [{ messageId: 'wrongType', type: 'TemplateLiteral' }], }, { code: ` module.exports = { meta: { docs: { description: SOME_DESCRIPTION } }, create(context) {} }; `, output: null, errors: [{ messageId: 'wrongType', type: 'Identifier' }], }, { code: ` module.exports = { meta: { docs: { description: '' } }, create(context) {} }; `, output: null, errors: [{ messageId: 'wrongType', type: 'Literal' }], }, { code: ` module.exports = { meta: { docs: { description: 'enforce something with trailing whitespace ' } }, create(context) {} }; `, output: null, errors: [{ messageId: 'extraWhitespace', type: 'Literal' }], }, { code: ` module.exports = { meta: { docs: { description: 'this rule does ...' } }, create(context) {} }; `, output: null, errors: [{ message: '`meta.docs.description` must match the regexp /^(enforce|require|disallow)/.', type: 'Literal' }], }, { code: ` module.exports = { meta: { docs: { description: 'this rule does ...' } }, create(context) {} }; `, output: null, options: [{ pattern: '^myPrefix' }], errors: [{ message: '`meta.docs.description` must match the regexp /^myPrefix/.', type: 'Literal' }], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/require-meta-docs-url.js000066400000000000000000000330241367425336200266410ustar00rootroot00000000000000/** * @author Toru Nagashima * @copyright 2016 Toru Nagashima. All rights reserved. * See LICENSE file in root directory for full license. */ 'use strict'; // ----------------------------------------------------------------------------- // Requirements // ----------------------------------------------------------------------------- const RuleTester = require('eslint').RuleTester; const rule = require('../../../lib/rules/require-meta-docs-url'); // ----------------------------------------------------------------------------- // Tests // ----------------------------------------------------------------------------- const tester = new RuleTester({ parserOptions: { ecmaVersion: 2018, }, }); tester.run('require-meta-docs-url', rule, { valid: [ 'foo()', ` module.exports.meta = {docs: {url: ""}} module.exports.create = function() {} `, ` module.exports = { meta: {docs: {url: ""}}, create() {} } `, ` module.exports = { ["meta"]: {["docs"]: {["url"]: ""}}, create() {} } `, { code: ` // If filename is not provided, don't check the value. module.exports = { meta: {docs: {url: ""}}, create() {} } `, options: [{ pattern: 'path/to/{{name}}.md', }], }, { code: ` module.exports = { meta: {docs: {url: "path/to/test-rule.md"}}, create() {} } `, options: [{ pattern: 'path/to/{{name}}.md', }], filename: 'test-rule', }, ], invalid: [ { code: ` module.exports = function() {} `, output: null, errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta, create() {} } `, output: null, errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: 100, create() {} } `, output: null, errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: {}, create() {} } `, output: null, errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: { fixable: null }, create() {} } `, output: null, errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: { fixable: null, }, create() {} } `, output: null, errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: { docs }, create() {} } `, output: null, errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: { docs: {} }, create() {} } `, output: null, errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: { docs: { description: "" } }, create() {} } `, output: null, errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: { docs: { description: "", } }, create() {} } `, output: null, errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: { docs: { url: 100, } }, create() {} } `, output: null, errors: ['`meta.docs.url` property must be a string.'], }, { code: ` module.exports = { meta: { docs: { ...url } }, create() {} } `, output: null, errors: ['Rules should export a `meta.docs.url` property.'], }, // ------------------------------------------------------------------------- // pattern option without filename // ------------------------------------------------------------------------- { code: ` module.exports = function() {} `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta, create() {} } `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: 100, create() {} } `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: {}, create() {} } `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: { fixable: null }, create() {} } `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: { fixable: null, }, create() {} } `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: { docs }, create() {} } `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: { docs: {} }, create() {} } `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: { docs: { description: "" } }, create() {} } `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: { docs: { description: "", } }, create() {} } `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], }, { code: ` module.exports = { meta: { docs: { url: 100, } }, create() {} } `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['`meta.docs.url` property must be a string.'], }, { code: ` module.exports = { meta: { docs: { ...url } }, create() {} } `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], }, // ------------------------------------------------------------------------- // pattern option with filename // ------------------------------------------------------------------------- { code: ` module.exports = function() {} `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], filename: 'test.js', }, { code: ` module.exports = { meta, create() {} } `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], filename: 'test.js', }, { code: ` module.exports = { meta: 100, create() {} } `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], filename: 'test.js', }, { code: ` module.exports = { meta: {}, create() {} } `, output: ` module.exports = { meta: { docs: { url: "plugin-name/test.md" } }, create() {} } `, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], filename: 'test.js', }, { code: ` module.exports = { meta: { fixable: null }, create() {} } `, output: ` module.exports = { meta: { fixable: null, docs: { url: "plugin-name/test.md" } }, create() {} } `, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], filename: 'test.js', }, { code: ` module.exports = { meta: { fixable: null, }, create() {} } `, output: ` module.exports = { meta: { fixable: null, docs: { url: "plugin-name/test.md" }, }, create() {} } `, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], filename: 'test.js', }, { code: ` module.exports = { meta: { docs }, create() {} } `, output: null, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], filename: 'test.js', }, { code: ` module.exports = { meta: { docs: {} }, create() {} } `, output: ` module.exports = { meta: { docs: { url: "plugin-name/test.md" } }, create() {} } `, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], filename: 'test.js', }, { code: ` module.exports = { meta: { docs: { description: "" } }, create() {} } `, output: ` module.exports = { meta: { docs: { description: "", url: "plugin-name/test.md" } }, create() {} } `, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], filename: 'test.js', }, { code: ` module.exports = { meta: { docs: { description: "", } }, create() {} } `, output: ` module.exports = { meta: { docs: { description: "", url: "plugin-name/test.md", } }, create() {} } `, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], filename: 'test.js', }, { code: ` module.exports = { meta: { docs: { url: 100, } }, create() {} } `, output: ` module.exports = { meta: { docs: { url: "plugin-name/test.md", } }, create() {} } `, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['`meta.docs.url` property must be `plugin-name/test.md`.'], filename: 'test.js', }, { code: ` module.exports = { meta: { docs: { ...url } }, create() {} } `, output: ` module.exports = { meta: { docs: { ...url, url: "plugin-name/test.md" } }, create() {} } `, options: [{ pattern: 'plugin-name/{{ name }}.md', }], errors: ['Rules should export a `meta.docs.url` property.'], filename: 'test.js', }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/require-meta-fixable.js000066400000000000000000000077061367425336200265330ustar00rootroot00000000000000/** * @fileoverview require rules to implement a meta.fixable property * @author Teddy Katz */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/require-meta-fixable'); const RuleTester = require('eslint').RuleTester; const MISSING_ERROR = { message: 'Fixable rules must export a `meta.fixable` property.', type: 'FunctionExpression' }; const INVALID_ERROR = { message: '`meta.fixable` must be either `code`, `whitespace` or `null`.', type: 'Property' }; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run('require-meta-fixable', rule, { valid: [ ` module.exports = { meta: {}, create(context) {} }; `, 'module.exports = context => {};', ` module.exports = { meta: { fixable: 'code' }, create(context) { context.report({node, message, fix: foo}); } }; `, ` module.exports = { meta: { fixable: 'whitespace' }, create(context) { context.report({node, message, fix: foo}); } }; `, ` module.exports = { meta: { 'fixable': 'code' }, create(context) { context.report({node, message, fix: foo}); } }; `, ` module.exports = { meta: { ['fixable']: 'code' }, create(context) { context.report({node, message, fix: foo}); } }; `, ` module.exports = { meta: { [\`fixable\`]: 'code' }, create(context) { context.report({node, message, fix: foo}); } }; `, ` module.exports = { meta: { fixable: 'code' }, create(context) { context.report({node, message}); } }; `, ` module.exports = { meta: { fixable: null }, create(context) { context.report({node, message}); } }; `, ` module.exports = { meta: { fixable: undefined }, create(context) { context.report({node, message}); } }; `, ` module.exports = { meta: {}, create(context) { context.report(node, loc, message); } }; `, ` module.exports = { meta: {}, create(context) { context.report(node, message, data, fix); } }; `, { code: ` const meta = {}; module.exports = { ...meta, meta: {}, create(context) { context.report(node, message, data, fix); } }; `, parserOptions: { ecmaVersion: 9, }, }, ], invalid: [ { code: ` module.exports = { meta: {}, create(context) { context.report({node, message, fix: foo}); } }; `, errors: [MISSING_ERROR], }, { code: ` module.exports = { meta: {}, create(context) { context.report(node, loc, message, data, fix); } }; `, errors: [MISSING_ERROR], }, { code: ` module.exports = { meta: { fixable: 'invalid' }, create(context) { context.report({node, message}); } }; `, errors: [INVALID_ERROR], }, { code: ` module.exports = { meta: { fixable: 'invalid' }, create(context) { context.report({node, message, fix: foo}); } }; `, errors: [INVALID_ERROR], }, { code: ` module.exports = { meta: { fixable: foo }, create(context) { context.report({node, message, fix: foo}); } }; `, errors: [INVALID_ERROR], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/require-meta-schema.js000066400000000000000000000035531367425336200263550ustar00rootroot00000000000000'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/require-meta-schema'); const RuleTester = require('eslint').RuleTester; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run('require-meta-schema', rule, { valid: [ ` module.exports = { meta: { schema: [] }, create(context) {} }; `, ` module.exports = { meta: { schema: [ { "enum": ["always", "never"] } ] }, create(context) {} }; `, ` module.exports = { meta: { schema: { "enum": ["always", "never"] } }, create(context) {} }; `, ], invalid: [ { code: ` module.exports = { meta: {}, create(context) {} }; `, output: ` module.exports = { meta: { schema: [] }, create(context) {} }; `, errors: [{ messageId: 'missing', type: 'ObjectExpression' }], }, { code: ` module.exports = { meta: { type: 'problem' }, create(context) {} }; `, output: ` module.exports = { meta: { type: 'problem', schema: [] }, create(context) {} }; `, errors: [{ messageId: 'missing', type: 'ObjectExpression' }], }, { code: ` module.exports = { meta: { schema: null }, create(context) {} }; `, output: null, errors: [{ messageId: 'wrongType', type: 'Literal' }], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/require-meta-type.js000066400000000000000000000043241367425336200260730ustar00rootroot00000000000000/** * @fileoverview require rules to implement a meta.type property * @author 唯然 */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/require-meta-type'); const RuleTester = require('eslint').RuleTester; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run('require-meta-type', rule, { valid: [ ` module.exports = { meta: { type: 'problem' }, create(context) {} }; `, ` module.exports = { meta: { type: 'suggestion' }, create(context) {} }; `, ` module.exports = { meta: { type: 'layout' }, create(context) {} }; `, `module.exports = { create(context) {} }`, { code: ` const create = {}; module.exports = { meta: {}, create, }; `, errors: [{ messageId: 'missing' }], }, ], invalid: [ { code: ` module.exports = { meta: {}, create(context) {} }; `, errors: [{ messageId: 'missing' }], }, { code: ` function create(context) {} module.exports = { meta: {}, create, }; `, errors: [{ messageId: 'missing' }], }, { code: ` const create = function(context) {}; module.exports = { meta: {}, create, }; `, errors: [{ messageId: 'missing' }], }, { code: ` const create = (context) => {}; module.exports = { meta: {}, create, }; `, errors: [{ messageId: 'missing' }], }, { code: ` module.exports = { meta: { type: 'invalid-type' }, create(context) {} }; `, errors: [{ messageId: 'unexpected' }], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/test-case-property-ordering.js000066400000000000000000000076411367425336200301020ustar00rootroot00000000000000/** * @fileoverview Requires the properties of a test case to be placed in a consistent order. * @author 薛定谔的猫 */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/test-case-property-ordering'); const RuleTester = require('eslint').RuleTester; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester(); ruleTester.run('test-case-property-ordering', rule, { valid: [ ` new RuleTester().run('foo', bar, { valid: [ { code: "foo", output: "bar", options: ["baz"], }, ] }); `, ` new RuleTester().run('foo', bar, { valid: [ { code: "foo",output: "bar",options: ["baz"],env: { es6: true }, }, ] }); `, { code: ` new RuleTester().run('foo', bar, { valid: [ { code: "foo", options: ["baz"], output: "bar", }, ] }); `, options: [['code', 'errors', 'options', 'output', 'parserOptions']], }, ], invalid: [ { code: ` new RuleTester().run('foo', bar, { valid: [ { code: "foo", options: ["baz"], output: "bar", }, ] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ { code: "foo", output: "bar", options: ["baz"], }, ] }); `, errors: [{ message: 'The properties of a test case should be placed in a consistent order: [code, output, options].' }], }, { code: ` new RuleTester().run('foo', bar, { valid: [ { env: { es6: true }, code: "foo", output: "bar", options: ["baz"], }, ] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ { code: "foo", output: "bar", options: ["baz"], env: { es6: true }, }, ] }); `, errors: [{ message: 'The properties of a test case should be placed in a consistent order: [code, output, options, env].' }], }, { code: ` new RuleTester().run('foo', bar, { valid: [ { code: "foo", env: { es6: true }, output: "bar", options: ["baz"], }, ] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ { code: "foo", output: "bar", options: ["baz"], env: { es6: true }, }, ] }); `, errors: [{ message: 'The properties of a test case should be placed in a consistent order: [code, output, options, env].' }], }, { code: ` new RuleTester().run('foo', bar, { valid: [ { code: "foo", output: "bar", options: ["baz"], }, ] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ { code: "foo", options: ["baz"], output: "bar", }, ] }); `, options: [['code', 'errors', 'options', 'output', 'parserOptions']], errors: [{ message: 'The properties of a test case should be placed in a consistent order: [code, options, output].' }], }, { code: ` new RuleTester().run('foo', bar, { valid: [ {\ncode: "foo",\noutput: "",\nerrors: ["baz"],\nparserOptions: "",\n}, ] }); `, output: ` new RuleTester().run('foo', bar, { valid: [ {\ncode: "foo",\noutput: "",\nparserOptions: "",\nerrors: ["baz"],\n}, ] }); `, errors: [{ message: 'The properties of a test case should be placed in a consistent order: [code, output, parserOptions, errors].' }], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/rules/test-case-shorthand-strings.js000066400000000000000000000140641367425336200300650ustar00rootroot00000000000000/** * @fileoverview Enforce consistent usage of shorthand strings for test cases with no options * @author Teddy Katz */ 'use strict'; // ------------------------------------------------------------------------------ // Requirements // ------------------------------------------------------------------------------ const rule = require('../../../lib/rules/test-case-shorthand-strings'); const RuleTester = require('eslint').RuleTester; /** * Returns the code for some valid test cases * @param {string[]} cases The code representation of valid test cases * @returns {string} Code representing the test cases */ function getTestCases (cases) { return ` new RuleTester().run('foo', bar, { valid: [ ${cases.join(',\n ')}, ], invalid: [] }); `; } const EXPECTED_SHORTHAND_ERROR = { message: 'Use a string for this test case instead of an object.' }; const UNEXPECTED_SHORTHAND_ERROR = { message: 'Use an object for this test case instead of a string.' }; // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run('test-case-shorthand-strings', rule, { valid: [ // default (as-needed) getTestCases(['"foo"']), getTestCases(['"foo"', '"bar"']), getTestCases(['"foo"', '"bar"', '{ code: "foo", options: ["bar"] }']), getTestCases(['"foo"', '"bar"', '{ code: "foo", parserOptions: ["bar"] }']), getTestCases(['`foo`']), getTestCases(['tag`foo`']), // as-needed { code: getTestCases(['"foo"']), options: ['as-needed'], }, { code: getTestCases(['"foo"', '"bar"']), options: ['as-needed'], }, { code: getTestCases(['"foo"', '"bar"', '{ code: "foo", options: ["bar"] }']), options: ['as-needed'], }, { code: getTestCases(['"foo"', '"bar"', '{ code: "foo", parserOptions: ["bar"] }']), options: ['as-needed'], }, { code: getTestCases(['`foo`']), options: ['as-needed'], }, { code: getTestCases(['tag`foo`']), options: ['as-needed'], }, // never { code: getTestCases(['{ code: "foo" }', '{ code: "bar" }']), options: ['never'], }, { code: getTestCases(['notAString', '{ code: "bar" }']), options: ['never'], }, { code: getTestCases(['notAString()', '{ code: "bar" }']), options: ['never'], }, // consistent { code: getTestCases(['"foo"', '"bar"']), options: ['consistent'], }, { code: getTestCases(['{ code: "foo" }', '{ code: "bar" }']), options: ['consistent'], }, { code: getTestCases(['{ code: "foo" }', '{ code: "bar", options: ["foo"] }']), options: ['consistent'], }, { code: getTestCases(['"foo"', "'bar'", '`baz`']), options: ['consistent'], }, // consistent-as-needed { code: getTestCases(['"foo"', '"bar"']), options: ['consistent-as-needed'], }, { code: getTestCases(['{ code: "foo" }', '{ code: "bar", options: ["foo"] }']), options: ['consistent-as-needed'], }, { code: getTestCases(['"foo"', "'bar'", '`baz`']), options: ['consistent-as-needed'], }, ], invalid: [ // as-needed { code: getTestCases(['{ code: "foo" }']), output: getTestCases(['"foo"']), errors: [EXPECTED_SHORTHAND_ERROR], }, { code: getTestCases(['{ code: `foo` }']), output: getTestCases(['`foo`']), errors: [EXPECTED_SHORTHAND_ERROR], }, { code: getTestCases(['"foo"', '{ code: `foo` }']), output: getTestCases(['"foo"', '`foo`']), errors: [EXPECTED_SHORTHAND_ERROR], }, { code: getTestCases(['"foo"', '{ code: "foo" }', '{ code: `bar` }']), output: getTestCases(['"foo"', '"foo"', '`bar`']), errors: [EXPECTED_SHORTHAND_ERROR, EXPECTED_SHORTHAND_ERROR], }, // never { code: getTestCases(['"foo"']), output: getTestCases(['{code: "foo"}']), options: ['never'], errors: [UNEXPECTED_SHORTHAND_ERROR], }, { code: getTestCases(['foo', '"bar"']), output: getTestCases(['foo', '{code: "bar"}']), options: ['never'], errors: [UNEXPECTED_SHORTHAND_ERROR], }, { code: getTestCases(['`foo`']), output: getTestCases(['{code: `foo`}']), options: ['never'], errors: [UNEXPECTED_SHORTHAND_ERROR], }, { code: getTestCases(['"foo"']) + getTestCases(['"foo"']), output: getTestCases(['{code: "foo"}']) + getTestCases(['{code: "foo"}']), options: ['never'], errors: [UNEXPECTED_SHORTHAND_ERROR, UNEXPECTED_SHORTHAND_ERROR], }, // consistent { code: getTestCases(['"foo"', '{ code: "bar" }', '{ code: "baz" }']), output: getTestCases(['"foo"', '"bar"', '"baz"']), errors: [EXPECTED_SHORTHAND_ERROR, EXPECTED_SHORTHAND_ERROR], }, { code: getTestCases(['{ code: "bar" }', '"foo"', '{ code: "baz" }']), output: getTestCases(['"bar"', '"foo"', '"baz"']), errors: [EXPECTED_SHORTHAND_ERROR, EXPECTED_SHORTHAND_ERROR], }, // consistent-as-needed { code: getTestCases(['{ code: "foo" }', '{ code: "bar" }']), output: getTestCases(['"foo"', '"bar"']), options: ['consistent-as-needed'], errors: [EXPECTED_SHORTHAND_ERROR, EXPECTED_SHORTHAND_ERROR], }, { code: getTestCases(['"foo"', '"bar"', '{ code: "baz", options: ["foo"] }']), output: getTestCases(['{code: "foo"}', '{code: "bar"}', '{ code: "baz", options: ["foo"] }']), options: ['consistent-as-needed'], errors: [UNEXPECTED_SHORTHAND_ERROR, UNEXPECTED_SHORTHAND_ERROR], }, { code: getTestCases(['"foo"', '{ code: "baz", options: ["foo"] }', '"bar"']), output: getTestCases(['{code: "foo"}', '{ code: "baz", options: ["foo"] }', '{code: "bar"}']), options: ['consistent-as-needed'], errors: [UNEXPECTED_SHORTHAND_ERROR, UNEXPECTED_SHORTHAND_ERROR], }, ], }); eslint-plugin-eslint-plugin-2.3.0/tests/lib/utils.js000066400000000000000000000333441367425336200225260ustar00rootroot00000000000000'use strict'; const util = require('util'); const lodash = require('lodash'); const espree = require('espree'); const escope = require('escope'); const estraverse = require('estraverse'); const assert = require('chai').assert; const utils = require('../../lib/utils'); describe('utils', () => { describe('getRuleInfo', () => { describe('the file does not have a valid rule', () => { [ '', 'module.exports;', 'module.exports = foo;', 'module.boop = function() {};', 'exports = function() {};', 'module.exports = function* () {};', 'module.exports = async function () {};', 'module.exports = {};', 'module.exports = { meta: {} }', 'module.exports = { create: {} }', 'module.exports = { create: foo }', 'module.exports = { create: function* foo() {} }', 'module.exports = { create: async function foo() {} }', ].forEach(noRuleCase => { it(`returns null for ${noRuleCase}`, () => { const ast = espree.parse(noRuleCase, { ecmaVersion: 8 }); assert.isNull(utils.getRuleInfo(ast), 'Expected no rule to be found'); }); }); }); describe('the file has a valid rule', () => { const CASES = { 'module.exports = { create: function foo() {} };': { create: { type: 'FunctionExpression', id: { name: 'foo' } }, // (This property will actually contain the AST node.) meta: null, isNewStyle: true, }, 'module.exports = { create: () => { } };': { create: { type: 'ArrowFunctionExpression' }, meta: null, isNewStyle: true, }, 'module.exports = { create() {}, meta: { } };': { create: { type: 'FunctionExpression' }, meta: { type: 'ObjectExpression' }, isNewStyle: true, }, 'module.exports.create = function foo() {}; module.exports.meta = {}': { create: { type: 'FunctionExpression', id: { name: 'foo' } }, meta: { type: 'ObjectExpression' }, isNewStyle: true, }, 'exports.create = function foo() {}; exports.meta = {};': { create: { type: 'FunctionExpression', id: { name: 'foo' } }, meta: { type: 'ObjectExpression' }, isNewStyle: true, }, 'module.exports = { create: () => { } }; exports.create = function foo() {}; exports.meta = {};': { create: { type: 'ArrowFunctionExpression' }, meta: null, isNewStyle: true, }, 'exports.meta = {}; module.exports = { create: () => { } };': { create: { type: 'ArrowFunctionExpression' }, meta: null, isNewStyle: true, }, 'module.exports = { create: () => { } }; module.exports.meta = {};': { create: { type: 'ArrowFunctionExpression' }, meta: { type: 'ObjectExpression' }, isNewStyle: true, }, 'module.exports = { meta: {} }; module.exports.create = () => { };': { create: { type: 'ArrowFunctionExpression' }, meta: { type: 'ObjectExpression' }, isNewStyle: true, }, 'module.exports = { "meta": {} }; module.exports.create = () => { };': { create: { type: 'ArrowFunctionExpression' }, meta: { type: 'ObjectExpression' }, isNewStyle: true, }, 'module.exports = { create: () => { } }; exports.meta = {};': { create: { type: 'ArrowFunctionExpression' }, meta: null, isNewStyle: true, }, 'module.exports = function foo() {}': { create: { type: 'FunctionExpression', id: { name: 'foo' } }, meta: null, isNewStyle: false, }, 'module.exports = () => {}': { create: { type: 'ArrowFunctionExpression' }, meta: null, isNewStyle: false, }, 'exports.meta = {}; module.exports = () => {}': { create: { type: 'ArrowFunctionExpression' }, meta: null, isNewStyle: false, }, 'module.exports = () => {}; module.exports.meta = {};': { create: { type: 'ArrowFunctionExpression' }, meta: null, isNewStyle: false, }, }; Object.keys(CASES).forEach(ruleSource => { it(ruleSource, () => { const ast = espree.parse(ruleSource, { ecmaVersion: 6 }); const ruleInfo = utils.getRuleInfo(ast); assert( lodash.isMatch(ruleInfo, CASES[ruleSource]), `Expected \n${util.inspect(ruleInfo)}\nto match\n${util.inspect(CASES[ruleSource])}` ); }); }); }); }); describe('getContextIdentifiers', () => { const CASES = { 'module.exports = context => { context; context; context; }' (ast) { return [ ast.body[0].expression.right.body.body[0].expression, ast.body[0].expression.right.body.body[1].expression, ast.body[0].expression.right.body.body[2].expression, ]; }, 'module.exports = { meta: {}, create(context, foo = context) {} }' (ast) { return [ast.body[0].expression.right.properties[1].value.params[1].right]; }, 'module.exports = { meta: {}, create(notContext) { notContext; notContext; notContext; } }' (ast) { return [ ast.body[0].expression.right.properties[1].value.body.body[0].expression, ast.body[0].expression.right.properties[1].value.body.body[1].expression, ast.body[0].expression.right.properties[1].value.body.body[2].expression, ]; }, }; Object.keys(CASES).forEach(ruleSource => { it(ruleSource, () => { const ast = espree.parse(ruleSource, { ecmaVersion: 6 }); const scope = escope.analyze(ast, { ignoreEval: true, ecmaVersion: 6, sourceType: 'script', nodejsScope: true }); const identifiers = utils.getContextIdentifiers(scope, ast); assert(identifiers instanceof Set, 'getContextIdentifiers should return a Set'); Array.from(identifiers).forEach((identifier, index) => { assert.strictEqual(identifier, CASES[ruleSource](ast)[index]); }); }); }); }); describe('getKeyName', () => { const CASES = { '({ foo: 1 })': 'foo', '({ "foo": 1 })': 'foo', '({ ["foo"]: 1 })': 'foo', '({ [`foo`]: 1 })': 'foo', '({ foo() {} })': 'foo', '({ "foo"() {} })': 'foo', '({ ["foo"]() {} })': 'foo', '({ [`foo`]() {} })': 'foo', '({ 5: 1 })': '5', '({ 0x123: 1 })': '291', '({ [foo]: 1 })': null, '({ [tag`foo`]: 1 })': null, '({ ["foo" + "bar"]: 1 })': null, }; Object.keys(CASES).forEach(objectSource => { it(objectSource, () => { const ast = espree.parse(objectSource, { ecmaVersion: 6 }); assert.strictEqual(utils.getKeyName(ast.body[0].expression.properties[0]), CASES[objectSource]); }); }); const CASES_ES9 = { '({ ...foo })': null, }; Object.keys(CASES_ES9).forEach(objectSource => { it(objectSource, () => { const ast = espree.parse(objectSource, { ecmaVersion: 9 }); assert.strictEqual(utils.getKeyName(ast.body[0].expression.properties[0]), CASES_ES9[objectSource]); }); }); }); describe('getTestInfo', () => { describe('the file does not have valid tests', () => { [ '', 'module.exports = context => context.report(foo);', 'new (require("eslint").NotRuleTester).run(foo, bar, { valid: [] })', 'new NotRuleTester().run(foo, bar, { valid: [] })', 'new RuleTester()', 'const foo = new RuleTester; bar.run(foo, bar, { valid: [] })', 'new RuleTester().run()', 'new RuleTester().run(foo)', 'new RuleTester().run(foo, bar)', 'new RuleTester().run(foo, bar, notAnObject)', ].forEach(noTestsCase => { it(`returns no tests for ${noTestsCase}`, () => { const ast = espree.parse(noTestsCase, { ecmaVersion: 8 }); const scope = escope.analyze(ast, { ignoreEval: true, ecmaVersion: 6, sourceType: 'script', nodejsScope: true }); assert.deepEqual(utils.getTestInfo(scope, ast), [], 'Expected no tests to be found'); }); }); }); describe('the file has valid tests', () => { const CASES = { 'new RuleTester().run(bar, baz, { valid: [foo], invalid: [bar, baz] })': { valid: 1, invalid: 2 }, 'var foo = new RuleTester(); foo.run(bar, baz, { valid: [foo], invalid: [bar] })': { valid: 1, invalid: 1 }, 'var foo = new (require("eslint")).RuleTester; foo.run(bar, baz, { valid: [], invalid: [] })': { valid: 0, invalid: 0 }, 'var foo = new bar.RuleTester; foo.run(bar, baz, { valid: [], invalid: [bar, baz] })': { valid: 0, invalid: 2 }, 'var foo = new bar.RuleTester; foo.run(bar, baz, { valid: [,], invalid: [bar, , baz] })': { valid: 0, invalid: 2 }, }; Object.keys(CASES).forEach(testSource => { it(testSource, () => { const ast = espree.parse(testSource, { ecmaVersion: 6 }); const scope = escope.analyze(ast, { ignoreEval: true, ecmaVersion: 6, sourceType: 'script', nodejsScope: true }); const testInfo = utils.getTestInfo(scope, ast); assert.strictEqual(testInfo.length, 1, 'Expected to find one test run'); assert.strictEqual( testInfo[0].valid.length, CASES[testSource].valid, `Expected ${CASES[testSource].valid} valid cases but got ${testInfo[0].valid.length}` ); assert.strictEqual( testInfo[0].invalid.length, CASES[testSource].invalid, `Expected ${CASES[testSource].invalid} invalid cases but got ${testInfo[0].invalid.length}` ); }); }); }); describe('the file has multiple test runs', () => { const CASES = { [` new RuleTester().run(foo, bar, { valid: [foo], invalid: [] }); new RuleTester().run(foo, bar, { valid: [], invalid: [foo, bar] }); `]: [{ valid: 1, invalid: 0 }, { valid: 0, invalid: 2 }], [` var foo = new RuleTester; var bar = new RuleTester; foo.run(foo, bar, { valid: [foo, bar, baz], invalid: [foo] }); bar.run(foo, bar, { valid: [], invalid: [foo, bar] }); `]: [{ valid: 3, invalid: 1 }, { valid: 0, invalid: 2 }], [` var foo = new RuleTester, bar = new RuleTester; foo.run(foo, bar, { valid: [foo, bar, baz], invalid: [foo] }); bar.run(foo, bar, { valid: [], invalid: [foo, bar] }); `]: [{ valid: 3, invalid: 1 }, { valid: 0, invalid: 2 }], }; Object.keys(CASES).forEach(testSource => { it(testSource, () => { const ast = espree.parse(testSource, { ecmaVersion: 6 }); const scope = escope.analyze(ast, { ignoreEval: true, ecmaVersion: 6, sourceType: 'script', nodejsScope: true }); const testInfo = utils.getTestInfo(scope, ast); assert.strictEqual( testInfo.length, CASES[testSource].length, `Expected to find ${CASES[testSource].length} test runs but got ${testInfo.length}` ); CASES[testSource].forEach((testRun, index) => { assert.strictEqual( testRun.valid, testInfo[index].valid.length, `On run ${index + 1}, expected ${testRun.valid} valid cases but got ${testInfo[index].valid.length}` ); assert.strictEqual( testRun.invalid, testInfo[index].invalid.length, `On run ${index + 1}, expected ${testRun.invalid} valid cases but got ${testInfo[index].invalid.length}` ); }); }); }); }); }); describe('getReportInfo', () => { const CASES = new Map([ [[], () => null], [['foo', 'bar'], () => null], [['foo', '"bar"', 'baz', 'qux', 'boop'], args => ({ node: args[0], message: args[1], data: args[2], fix: args[3] })], [['foo', '`bar`', 'baz', 'qux', 'boop'], args => ({ node: args[0], message: args[1], data: args[2], fix: args[3] })], [ ['foo', '{ bar: 1 }', 'baz', 'qux', 'boop'], args => ({ node: args[0], loc: args[1], message: args[2], data: args[3], fix: args[4] }), ], [['foo', 'bar', 'baz'], () => null], [ ['{ node, message }'], () => ({ node: { type: 'Identifier', name: 'node', start: 17, end: 21 }, message: { type: 'Identifier', name: 'message', start: 23, end: 30 }, }), ], ]); for (const args of CASES.keys()) { it(args.join(', '), () => { const parsedArgs = espree.parse( `context.report(${args.join(', ')})`, { ecmaVersion: 6, loc: false, range: false } ).body[0].expression.arguments; const reportInfo = utils.getReportInfo(parsedArgs); assert.deepEqual(reportInfo, CASES.get(args)(parsedArgs)); }); } }); describe('getSourceCodeIdentifiers', () => { const CASES = { 'module.exports = context => { const sourceCode = context.getSourceCode(); sourceCode; foo; }': 2, 'module.exports = context => { const x = 1, sc = context.getSourceCode(); sc; sc; sc; sourceCode; }': 4, 'module.exports = context => { const sourceCode = context.getNotSourceCode(); }': 0, }; Object.keys(CASES).forEach(testSource => { it(testSource, () => { const ast = espree.parse(testSource, { ecmaVersion: 6 }); const scope = escope.analyze(ast, { ignoreEval: true, ecmaVersion: 6, sourceType: 'script', nodejsScope: true }); estraverse.traverse(ast, { enter (node, parent) { node.parent = parent; }, }); assert.strictEqual(utils.getSourceCodeIdentifiers(scope, ast).size, CASES[testSource]); }); }); }); });