Skip to content
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

Update filenames #578

Merged
merged 10 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ This config will be interpreted in the following way:
| [async-currenttarget](docs/rules/async-currenttarget.md) | disallow `event.currentTarget` calls inside of async functions | 🔍 | | |
| [async-preventdefault](docs/rules/async-preventdefault.md) | disallow `event.preventDefault` calls inside of async functions | 🔍 | | |
| [authenticity-token](docs/rules/authenticity-token.md) | disallow usage of CSRF tokens in JavaScript | 🔐 | | |
| [filenames-match-regex](docs/rules/filenames-match-regex.md) | ensure filenames match a regex naming convention | ✅ | | |
| [get-attribute](docs/rules/get-attribute.md) | disallow wrong usage of attribute names | 🔍 | 🔧 | |
| [js-class-name](docs/rules/js-class-name.md) | enforce a naming convention for js- prefixed classes | 🔐 | | |
| [no-blur](docs/rules/no-blur.md) | disallow usage of `Element.prototype.blur()` | 🔍 | | |
Expand Down
35 changes: 35 additions & 0 deletions docs/rules/filenames-match-regex.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Ensure filenames match a regex naming convention (`github/filenames-match-regex`)

💼 This rule is enabled in the ✅ `recommended` config.

<!-- end auto-generated rule header -->

## Rule Details

Rule to ensure that filenames match a convention, with a default of camelCase.

👎 Examples of **incorrect** filename for this default rule:

`file-name.js`

👍 Examples of **correct** code for this rule:

`fileName.js`

## Options

regex - Regex to match the filename structure. Defaults to camelCase.


```json
{
"filenames-match-regex": [
"error",
"^[a-z0-9-]+(.[a-z0-9-]+)?$"
]
}
```

## Version

4.3.2
4 changes: 1 addition & 3 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const globals = require('globals')
const eslintPlugin = require('eslint-plugin-eslint-plugin')
const importPlugin = require('eslint-plugin-import')
const filenames = require('eslint-plugin-filenames')
const i18nTextPlugin = require('eslint-plugin-i18n-text')
const recommendedGitHub = require('./lib/configs/flat/recommended')
const {fixupPluginRules} = require('@eslint/compat')
Expand All @@ -23,13 +22,12 @@ module.exports = [
plugins: {
eslintPlugin,
importPlugin,
filenames,
'i18n-text': fixupPluginRules(i18nTextPlugin),
},
rules: {
'importPlugin/extensions': 'off',
'importPlugin/no-commonjs': 'off',
'filenamesPlugin/match-regex': 'off',
'github/filenames-match-regex': 'off',
'i18n-text/no-en': 'off',
'eslint-plugin/prefer-placeholders': 'off',
'eslint-plugin/test-case-shorthand-strings': 'off',
Expand Down
3 changes: 2 additions & 1 deletion lib/configs/flat/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const globals = require('globals')
const github = require('../../plugin')
const importPlugin = require('eslint-plugin-import')
const escompatPlugin = require('eslint-plugin-escompat')
const {fixupPluginRules} = require('@eslint/compat')

module.exports = {
...escompatPlugin.configs['flat/recommended'],
Expand All @@ -10,7 +11,7 @@ module.exports = {
...globals.browser,
},
},
plugins: {importPlugin, escompatPlugin, github},
plugins: {importPlugin, escompatPlugin, github: fixupPluginRules(github)},
rules: {
'escompatPlugin/no-dynamic-imports': 'off',
'github/async-currenttarget': 'error',
Expand Down
3 changes: 2 additions & 1 deletion lib/configs/flat/internal.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const github = require('../../plugin')
const {fixupPluginRules} = require('@eslint/compat')

module.exports = {
plugins: {github},
plugins: {github: fixupPluginRules(github)},
rules: {
'github/authenticity-token': 'error',
'github/js-class-name': 'error',
Expand Down
3 changes: 2 additions & 1 deletion lib/configs/flat/react.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const github = require('../../plugin')
const jsxA11yPlugin = require('eslint-plugin-jsx-a11y')
const {fixupPluginRules} = require('@eslint/compat')

module.exports = {
...jsxA11yPlugin.flatConfigs.recommended,
Expand All @@ -11,7 +12,7 @@ module.exports = {
},
},
},
plugins: {github, jsxA11yPlugin},
plugins: {github: fixupPluginRules(github), jsxA11yPlugin},
rules: {
'jsxA11yPlugin/role-supports-aria-props': 'off', // Override with github/a11y-role-supports-aria-props until https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/910 is resolved
'github/a11y-aria-label-is-well-formatted': 'error',
Expand Down
6 changes: 2 additions & 4 deletions lib/configs/flat/recommended.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ const github = require('../../plugin')
const prettierPlugin = require('eslint-plugin-prettier')
const eslintComments = require('eslint-plugin-eslint-comments')
const importPlugin = require('eslint-plugin-import')
const filenames = require('eslint-plugin-filenames')
const i18nTextPlugin = require('eslint-plugin-i18n-text')
const noOnlyTestsPlugin = require('eslint-plugin-no-only-tests')
const {fixupPluginRules} = require('@eslint/compat')
Expand All @@ -17,13 +16,12 @@ module.exports = {
},
},
plugins: {
filenamesPlugin: fixupPluginRules(filenames),
prettierPlugin,
eslintComments,
importPlugin,
'i18n-text': fixupPluginRules(i18nTextPlugin),
noOnlyTestsPlugin,
github,
github: fixupPluginRules(github),
},
rules: {
'constructor-super': 'error',
Expand All @@ -34,7 +32,7 @@ module.exports = {
'eslintComments/no-unused-disable': 'error',
'eslintComments/no-unused-enable': 'error',
'eslintComments/no-use': ['error', {allow: ['eslint', 'eslint-disable-next-line', 'eslint-env', 'globals']}],
'filenamesPlugin/match-regex': ['error', '^[a-z0-9-]+(.[a-z0-9-]+)?$'],
'github/filenames-match-regex': ['error', '^[a-z0-9-]+(.[a-z0-9-]+)?$'],
'func-style': ['error', 'declaration', {allowArrowFunctions: true}],
'github/array-foreach': 'error',
'github/no-implicit-buggy-globals': 'error',
Expand Down
3 changes: 2 additions & 1 deletion lib/configs/flat/typescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ const eslint = require('@eslint/js')
const tseslint = require('typescript-eslint')
const escompatPlugin = require('eslint-plugin-escompat')
const github = require('../../plugin')
const {fixupPluginRules} = require('@eslint/compat')

module.exports = tseslint.config(eslint.configs.recommended, ...tseslint.configs.recommended, {
languageOptions: {
parser: tseslint.parser,
},
plugins: {'@typescript-eslint': tseslint.plugin, escompatPlugin, github},
plugins: {'@typescript-eslint': tseslint.plugin, escompatPlugin, github: fixupPluginRules(github)},
rules: {
camelcase: 'off',
'no-unused-vars': 'off',
Expand Down
4 changes: 2 additions & 2 deletions lib/configs/recommended.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module.exports = {
env: {
es6: true,
},
plugins: ['github', 'prettier', 'eslint-comments', 'import', 'filenames', 'i18n-text', 'no-only-tests'],
plugins: ['github', 'prettier', 'eslint-comments', 'import', 'i18n-text', 'no-only-tests'],
rules: {
'constructor-super': 'error',
'eslint-comments/disable-enable-pair': 'off',
Expand All @@ -18,7 +18,7 @@ module.exports = {
'eslint-comments/no-unused-disable': 'error',
'eslint-comments/no-unused-enable': 'error',
'eslint-comments/no-use': ['error', {allow: ['eslint', 'eslint-disable-next-line', 'eslint-env', 'globals']}],
'filenames/match-regex': ['error', '^[a-z0-9-]+(.[a-z0-9-]+)?$'],
'github/filenames-match-regex': ['error', '^[a-z0-9-]+(.[a-z0-9-]+)?$'],
'func-style': ['error', 'declaration', {allowArrowFunctions: true}],
'github/array-foreach': 'error',
'github/no-implicit-buggy-globals': 'error',
Expand Down
1 change: 1 addition & 0 deletions lib/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module.exports = {
'async-currenttarget': require('./rules/async-currenttarget'),
'async-preventdefault': require('./rules/async-preventdefault'),
'authenticity-token': require('./rules/authenticity-token'),
'filenames-match-regex': require('./rules/filenames-match-regex'),
'get-attribute': require('./rules/get-attribute'),
'js-class-name': require('./rules/js-class-name'),
'no-blur': require('./rules/no-blur'),
Expand Down
51 changes: 51 additions & 0 deletions lib/rules/filenames-match-regex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// This is adapted from https://github.com/selaux/eslint-plugin-filenames since it's no longer actively maintained
// and needed a fix for eslint v9
const path = require('path')
const parseFilename = require('../utils/parse-filename')
const getExportedName = require('../utils/get-exported-name')
const isIgnoredFilename = require('../utils/is-ignored-filename')

module.exports = {
meta: {
type: 'problem',
docs: {
description: 'ensure filenames match a regex naming convention',
url: require('../url')(module),
},
schema: {
type: 'array',
minItems: 0,
maxItems: 1,
items: [
{
type: 'string',
},
],
},
},

create(context) {
const defaultRegexp = /^([a-z0-9]+)([A-Z][a-z0-9]+)*$/g
const conventionRegexp = context.options[0] ? new RegExp(context.options[0]) : defaultRegexp
const ignoreExporting = context.options[1] ? context.options[1] : false

return {
Program(node) {
const filename = context.getFilename()
const absoluteFilename = path.resolve(filename)
const parsed = parseFilename(absoluteFilename)
const shouldIgnore = isIgnoredFilename(filename)
const isExporting = Boolean(getExportedName(node))
const matchesRegex = conventionRegexp.test(parsed.name)

if (shouldIgnore) return
if (ignoreExporting && isExporting) return
if (!matchesRegex) {
context.report(node, "Filename '{{name}}' does not match the regex naming convention.", {
name: parsed.base,
})
}
},
}
},
}
37 changes: 37 additions & 0 deletions lib/utils/get-exported-name.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
function getNodeName(node, options) {
const op = options || []

if (node.type === 'Identifier') {
return node.name
}

if (node.id && node.id.type === 'Identifier') {
return node.id.name
}

if (op[2] && node.type === 'CallExpression' && node.callee.type === 'Identifier') {
return node.callee.name
}
}

module.exports = function getExportedName(programNode, options) {
for (let i = 0; i < programNode.body.length; i += 1) {
const node = programNode.body[i]

if (node.type === 'ExportDefaultDeclaration') {
return getNodeName(node.declaration, options)
}

if (
node.type === 'ExpressionStatement' &&
node.expression.type === 'AssignmentExpression' &&
node.expression.left.type === 'MemberExpression' &&
node.expression.left.object.type === 'Identifier' &&
node.expression.left.object.name === 'module' &&
node.expression.left.property.type === 'Identifier' &&
node.expression.left.property.name === 'exports'
) {
return getNodeName(node.expression.right, options)
}
}
}
5 changes: 5 additions & 0 deletions lib/utils/is-ignored-filename.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const ignoredFilenames = ['<text>', '<input>']

module.exports = function isIgnoredFilename(filename) {
return ignoredFilenames.indexOf(filename) !== -1
}
12 changes: 12 additions & 0 deletions lib/utils/parse-filename.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const path = require('path')

module.exports = function parseFilename(filename) {
const ext = path.extname(filename)

return {
dir: path.dirname(filename),
base: path.basename(filename),
ext,
name: path.basename(filename, ext),
}
}
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
"eslint-config-prettier": ">=8.0.0",
"eslint-plugin-escompat": "^3.11.3",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-i18n-text": "^1.0.1",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-jsx-a11y": "^6.7.1",
Expand Down
4 changes: 2 additions & 2 deletions test-examples/flat/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import github from 'eslint-plugin-github'

export default [
github.getFlatConfigs().browser,
github.getFlatConfigs().recommended,
github.getFlatConfigs().browser,
github.getFlatConfigs().react,
...github.getFlatConfigs().typescript,
{
files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
ignores: ['eslint.config.mjs'],
rules: {
'github/array-foreach': 'error',
'github/async-preventdefault': 'warn',
'github/no-then': 'error',
'github/no-blur': 'error',
'github/async-preventdefault': 'error',
},
},
]
2 changes: 1 addition & 1 deletion test-examples/flat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"@eslint/js": "^9.5.0",
"@types/node": "^20.14.5",
"cross-env": "^7.0.3",
"eslint": "^8.57.0",
"eslint": "^9.14.0",
"eslint-plugin-github": "file:../..",
"typescript": "^5.6.3",
"typescript-eslint": "^8.12.2"
Expand Down
6 changes: 6 additions & 0 deletions test-examples/flat/src/getAttribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ const title = document.createElement('h1')
title.textContent = `${title}!`

foobar(title)

document.addEventListener('click', async function (event) {
const data = await fetch()

event.preventDefault()
})