-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds ESLint package @react-three/eslint-plugin #2698
Changes from 7 commits
b47a114
c4bf524
9128957
fc17848
45a4fcb
3ec1fc2
143e435
d67f238
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@react-three/eslint-plugin': minor | ||
--- | ||
|
||
Initial release. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,16 +9,8 @@ module.exports = { | |
'<rootDir>/packages/test-renderer/dist', | ||
'<rootDir>/test-utils', | ||
], | ||
// coverageThreshold: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed this since it was commented out. |
||
// global: { | ||
// statements: 80, | ||
// branches: 68, | ||
// functions: 80, | ||
// lines: 80, | ||
// }, | ||
// }, | ||
coverageDirectory: './coverage/', | ||
collectCoverage: true, | ||
collectCoverage: false, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Turned this to false since it was on for all unit tests, annoying! It's still enabled for |
||
moduleFileExtensions: ['js', 'ts', 'tsx'], | ||
verbose: false, | ||
testTimeout: 30000, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,7 @@ | |
"validate": "preconstruct validate", | ||
"release": "yarn build && yarn changeset publish", | ||
"vers": "yarn changeset version", | ||
"codegen:eslint": "cd packages/eslint-plugin && yarn codegen", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does yarn@1 have workspaces-run inbuilt? Need to search over docs. |
||
"analyze-fiber": "cd packages/fiber && npm publish --dry-run", | ||
"analyze-test": "cd packages/test-renderer && npm publish --dry-run" | ||
}, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
scripts/ | ||
src/ | ||
index.js |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<!--- THIS FILE WAS GENERATED DO NOT MODIFY BY HAND --> | ||
<!--- @command yarn codegen:eslint --> | ||
|
||
# @react-three/eslint-plugin | ||
|
||
[![Version](https://img.shields.io/npm/v/@react-three/eslint-plugin?style=flat&colorA=000000&colorB=000000)](https://npmjs.com/package/@react-three/eslint-plugin) | ||
[![Twitter](https://img.shields.io/twitter/follow/pmndrs?label=%40pmndrs&style=flat&colorA=000000&colorB=000000&logo=twitter&logoColor=000000)](https://twitter.com/pmndrs) | ||
[![Discord](https://img.shields.io/discord/740090768164651008?style=flat&colorA=000000&colorB=000000&label=discord&logo=discord&logoColor=000000)](https://discord.gg/ZZjjNvJ) | ||
[![Open Collective](https://img.shields.io/opencollective/all/react-three-fiber?style=flat&colorA=000000&colorB=000000)](https://opencollective.com/react-three-fiber) | ||
[![ETH](https://img.shields.io/badge/ETH-f5f5f5?style=flat&colorA=000000&colorB=000000)](https://blockchain.com/eth/address/0x6E3f79Ea1d0dcedeb33D3fC6c34d2B1f156F2682) | ||
[![BTC](https://img.shields.io/badge/BTC-f5f5f5?style=flat&colorA=000000&colorB=000000)](https://blockchain.com/btc/address/36fuguTPxGCNnYZSRdgdh6Ea94brCAjMbH) | ||
|
||
An ESLint plugin which provides lint rules for [@react-three/fiber](https://github.com/pmndrs/react-three-fiber). | ||
|
||
## Installation | ||
|
||
```bash | ||
npm install @react-three/eslint-plugin --save-dev | ||
``` | ||
|
||
## Configuration | ||
|
||
Use the recommended [config](#recommended) to get reasonable defaults: | ||
|
||
```json | ||
"extends": [ | ||
"plugin:@react-three/recommended" | ||
] | ||
``` | ||
|
||
If you do not use a config you will need to specify individual rules and add extra configuration. | ||
|
||
Add "@react-three" to the plugins section. | ||
|
||
```json | ||
"plugins": [ | ||
"@react-three" | ||
] | ||
``` | ||
|
||
Enable the rules that you would like to use. | ||
|
||
```json | ||
"rules": { | ||
"@react-three/no-clone-in-frame-loop": "error" | ||
} | ||
``` | ||
|
||
## Rules | ||
|
||
✅ Enabled in the `recommended` [configuration](#recommended).<br> | ||
🔧 Automatically fixable by the `--fix` [CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).<br> | ||
💡 Manually fixable by [editor suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions). | ||
|
||
| Rule | Description | ✅ | 🔧 | 💡 | | ||
| ---------------------- | --------------------------------------- | --- | --- | --- | | ||
| no-clone-in-frame-loop | Disallow `.clone()` inside frame loops. | | | | | ||
|
||
## Shareable configs | ||
|
||
<!-- This part of the readme is not currently codegen'd. If you add more configs make sure to update this. --> | ||
|
||
### Recommended | ||
|
||
This plugin exports a `recommended` configuration that enforces rules appropriate for everyone using React Three Fiber. | ||
|
||
```json | ||
"extends": [ | ||
"plugin:@react-three/recommended" | ||
] | ||
``` | ||
|
||
### All | ||
|
||
This plugin also exports an `all` configuration that includes every available rule. | ||
|
||
```json | ||
"extends": [ | ||
"plugin:@react-three/all" | ||
] | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
{ | ||
"name": "@react-three/eslint-plugin", | ||
"version": "0.0.0", | ||
"description": "An ESLint plugin which provides lint rules for @react-three/fiber.", | ||
"keywords": [ | ||
"react", | ||
"renderer", | ||
"fiber", | ||
"three", | ||
"threejs", | ||
"eslint" | ||
], | ||
"author": "Michael Dougall (https://github.com/itsdouges)", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/pmndrs/react-three-fiber/issues" | ||
}, | ||
"homepage": "https://github.com/pmndrs/react-three-fiber/packages/eslint-plugin#readme", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/pmndrs/react-three-fiber.git" | ||
}, | ||
"collective": { | ||
"type": "opencollective", | ||
"url": "https://opencollective.com/react-three-fiber" | ||
}, | ||
"main": "dist/react-three-eslint-plugin.cjs.js", | ||
"module": "dist/react-three-eslint-plugin.esm.js", | ||
"types": "dist/react-three-eslint-plugin.cjs.d.ts", | ||
"sideEffects": false, | ||
"preconstruct": { | ||
"entrypoints": [ | ||
"index.ts" | ||
] | ||
}, | ||
"dependencies": { | ||
"@babel/runtime": "^7.17.8", | ||
"eslint": "^8.12.0" | ||
}, | ||
"devDependencies": { | ||
"@types/eslint": "^8.4.10", | ||
"@types/lodash": "^4.14.191", | ||
"ts-node": "^10.9.1", | ||
"lodash": "^4.17.19", | ||
"prettier": "^2.6.1" | ||
}, | ||
"scripts": { | ||
"codegen": "ts-node scripts/codegen.ts" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
import type { Rule } from 'eslint' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This module generates most content inside the eslint plugin, including: rule index, configs, and readme. It is a very simple implementation. |
||
import fs from 'fs/promises' | ||
import { join, extname, relative } from 'path' | ||
import { camelCase } from 'lodash' | ||
import { format, resolveConfig } from 'prettier' | ||
|
||
const jsHeader = (file: string) => | ||
`// THIS FILE WAS GENERATED DO NOT MODIFY BY HAND | ||
// @command yarn codegen:eslint | ||
` + file | ||
|
||
const mdHeader = (file: string) => | ||
`<!--- THIS FILE WAS GENERATED DO NOT MODIFY BY HAND --> | ||
<!--- @command yarn codegen:eslint --> | ||
` + file | ||
|
||
interface FoundRule { | ||
module: Rule.RuleModule | ||
moduleName: string | ||
} | ||
|
||
interface GeneratedConfig { | ||
name: string | ||
path: string | ||
} | ||
|
||
const ignore = ['index.ts'] | ||
const srcDir = join(__dirname, '../src') | ||
const rulesDir = join(srcDir, 'rules') | ||
const configsDir = join(srcDir, 'configs') | ||
const generatedConfigs: GeneratedConfig[] = [] | ||
|
||
async function generateConfig(name: string, rules: FoundRule[]) { | ||
const code = ` | ||
export default { | ||
plugins: ['@react-three'], | ||
rules: { | ||
${rules.map((rule) => `'@react-three/${rule.moduleName}': 'error'`)} | ||
}, | ||
} | ||
` | ||
|
||
const filepath = join(configsDir, `${name}.ts`) | ||
await writeFile(filepath, code) | ||
|
||
generatedConfigs.push({ name: camelCase(name), path: './' + relative(srcDir, join(configsDir, name)) }) | ||
} | ||
|
||
async function writeFile(filepath: string, code: string) { | ||
const config = await resolveConfig(filepath) | ||
await fs.writeFile( | ||
filepath, | ||
format(extname(filepath) === '.md' ? mdHeader(code) : jsHeader(code), { ...config, filepath }), | ||
) | ||
} | ||
|
||
async function generateRuleIndex(rules: FoundRule[]) { | ||
const code = ` | ||
${rules.map((rule) => `import ${camelCase(rule.moduleName)} from './${rule.moduleName}'`)} | ||
|
||
export default { | ||
${rules.map((rule) => `'${rule.moduleName}': ${camelCase(rule.moduleName)}`)} | ||
} | ||
` | ||
|
||
const filepath = join(rulesDir, 'index.ts') | ||
await writeFile(filepath, code) | ||
} | ||
|
||
async function generatePluginIndex() { | ||
const code = ` | ||
${generatedConfigs.map((config) => `import ${config.name} from '${config.path}'`).join('\n')} | ||
|
||
export { default as rules } from './rules/index' | ||
|
||
export const configs = { | ||
${generatedConfigs.map((config) => `${config.name},`).join('\n')} | ||
} | ||
` | ||
|
||
const filepath = join(srcDir, 'index.ts') | ||
await writeFile(filepath, code) | ||
} | ||
|
||
const conditional = (cond: string, content?: boolean | string) => (content ? cond : '') | ||
const link = (content: string, url?: string) => (url ? `<a href="${url}">${content}</a>` : content) | ||
|
||
async function generateReadme(rules: FoundRule[]) { | ||
const code = ` | ||
# @react-three/eslint-plugin | ||
|
||
[![Version](https://img.shields.io/npm/v/@react-three/eslint-plugin?style=flat&colorA=000000&colorB=000000)](https://npmjs.com/package/@react-three/eslint-plugin) | ||
[![Twitter](https://img.shields.io/twitter/follow/pmndrs?label=%40pmndrs&style=flat&colorA=000000&colorB=000000&logo=twitter&logoColor=000000)](https://twitter.com/pmndrs) | ||
[![Discord](https://img.shields.io/discord/740090768164651008?style=flat&colorA=000000&colorB=000000&label=discord&logo=discord&logoColor=000000)](https://discord.gg/ZZjjNvJ) | ||
[![Open Collective](https://img.shields.io/opencollective/all/react-three-fiber?style=flat&colorA=000000&colorB=000000)](https://opencollective.com/react-three-fiber) | ||
[![ETH](https://img.shields.io/badge/ETH-f5f5f5?style=flat&colorA=000000&colorB=000000)](https://blockchain.com/eth/address/0x6E3f79Ea1d0dcedeb33D3fC6c34d2B1f156F2682) | ||
[![BTC](https://img.shields.io/badge/BTC-f5f5f5?style=flat&colorA=000000&colorB=000000)](https://blockchain.com/btc/address/36fuguTPxGCNnYZSRdgdh6Ea94brCAjMbH) | ||
|
||
An ESLint plugin which provides lint rules for [@react-three/fiber](https://github.com/pmndrs/react-three-fiber). | ||
|
||
## Installation | ||
|
||
\`\`\`bash | ||
npm install @react-three/eslint-plugin --save-dev | ||
\`\`\` | ||
|
||
## Configuration | ||
|
||
Use the recommended [config](#recommended) to get reasonable defaults: | ||
|
||
\`\`\`json | ||
"extends": [ | ||
"plugin:@react-three/recommended" | ||
] | ||
\`\`\` | ||
|
||
If you do not use a config you will need to specify individual rules and add extra configuration. | ||
|
||
Add "@react-three" to the plugins section. | ||
|
||
\`\`\`json | ||
"plugins": [ | ||
"@react-three" | ||
] | ||
\`\`\` | ||
|
||
Enable the rules that you would like to use. | ||
|
||
\`\`\`json | ||
"rules": { | ||
"@react-three/no-clone-in-frame-loop": "error" | ||
} | ||
\`\`\` | ||
|
||
## Rules | ||
|
||
✅ Enabled in the \`recommended\` [configuration](#recommended).<br> | ||
🔧 Automatically fixable by the \`--fix\` [CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).<br> | ||
💡 Manually fixable by [editor suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions). | ||
|
||
| Rule | Description | ✅ | 🔧 | 💡 | | ||
| ---- | -- | -- | -- | -- | | ||
${rules | ||
.map( | ||
(rule) => | ||
`| ${link(rule.moduleName, rule.module.meta?.docs?.url)} | ${rule.module.meta?.docs?.description} | ${conditional( | ||
'✅', | ||
rule.module.meta?.docs?.recommended, | ||
)} | ${conditional('🔧', rule.module.meta?.fixable)} | ${conditional('💡', rule.module.meta?.hasSuggestions)} |`, | ||
) | ||
.join('\n')} | ||
|
||
## Shareable configs | ||
|
||
<!-- This part of the readme is not currently codegen'd. If you add more configs make sure to update this. --> | ||
|
||
### Recommended | ||
|
||
This plugin exports a \`recommended\` configuration that enforces rules appropriate for everyone using React Three Fiber. | ||
|
||
\`\`\`json | ||
"extends": [ | ||
"plugin:@react-three/recommended" | ||
] | ||
\`\`\` | ||
|
||
### All | ||
|
||
This plugin also exports an \`all\` configuration that includes every available rule. | ||
|
||
\`\`\`json | ||
"extends": [ | ||
"plugin:@react-three/all" | ||
] | ||
\`\`\` | ||
` | ||
|
||
const filepath = join(srcDir, '../', 'README.md') | ||
await writeFile(filepath, code) | ||
} | ||
|
||
async function generate() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Surprised this doesn't exist as a standalone npm pkg! Let me know if it does and my searchfu needs work. |
||
const rulePaths = await fs.readdir(rulesDir) | ||
const recommended: FoundRule[] = [] | ||
const rules: FoundRule[] = [] | ||
|
||
for (const moduleName of rulePaths) { | ||
if (ignore.includes(moduleName)) { | ||
continue | ||
} | ||
|
||
const rule: Rule.RuleModule = (await import(join(rulesDir, moduleName))).default | ||
const foundRule = { module: rule, moduleName: moduleName.replace(extname(moduleName), '') } | ||
rules.push(foundRule) | ||
|
||
if (rule.meta?.docs?.recommended) { | ||
recommended.push(foundRule) | ||
} | ||
} | ||
|
||
await generateRuleIndex(rules) | ||
await generateConfig('all', rules) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we ever want to add another config it's just a matter of calling generate config again. Perhaps we could introduce a native config if that made sense? |
||
await generateConfig('recommended', recommended) | ||
await generatePluginIndex() | ||
await generateReadme(rules) | ||
} | ||
|
||
generate() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Figured we just keep bumping minors until we release a major version. This will release the package under v0.1.0.