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

feat: New modular config for (and with) ESLint v9 support #887

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
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
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
# SPDX-License-Identifier: AGPL-3.0-or-later

# Logs
logs
*.log
Expand Down Expand Up @@ -36,10 +37,9 @@ build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/
# Output
dist/

# Optional npm cache directory
.npm
Expand Down
6 changes: 0 additions & 6 deletions .npmignore

This file was deleted.

60 changes: 25 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@
[![Dependabot status](https://img.shields.io/badge/Dependabot-enabled-brightgreen.svg?longCache=true&style=flat-square&logo=dependabot)](https://dependabot.com)


This is a package containing the unified global eslint config used by all nextcloud apps.
This is a package containing the unified global eslint config used by all nextcloud apps and libraries.
It contains the necessary dependencies and peerDependencies so that other apps cannot update if this config does not support it.
Please always use dependabot to update your apps, OR pay attention to the peer dependencies error messages!


## Installation

```bash
Expand All @@ -23,45 +22,36 @@ npm install @nextcloud/eslint-config --save-dev

## Usage

Add a file `.eslintrc.js` in the root directory of your app repository with the following content:

```js
module.exports = {
extends: [
'@nextcloud',
],
}
```

### Usage with Typescript projects

If your projects uses Typescript for vue files, like `<script lang="ts">` then use the Typescript config instead:
> [!NOTE]
> Since version 9 this package depends on ESLint 9, which uses the new flat config system.

Add a file `.eslintrc.js` in the root directory of your app repository with the following content:
This package provides some predefined configurations you can choose from.
For the recommended setup add a file `eslint.config.js` in the root directory of your app repository with the following content:

```js
module.exports = {
extends: [
'@nextcloud/eslint-config/typescript',
],
}
```

### Usage with Vue 3 projects

If your projects uses Vue 3 you have to use the `vue3` sub-configuration.
This configuration also includes Typescript support by default.
import { recommended } from './dist/index.mjs'

Add a file `.eslintrc.js` in the root directory of your app repository with the following content:

```js
module.exports = {
extends: [
'@nextcloud/eslint-config/vue3',
],
}
export default [
...recommended,
]
```

### Available configurations

Instead of the `recommended` configuration this package also provides some alternatives, depending on your app setup you can also choose:

* `recommended`
* General rules including code style
* Support for Typescript
* Support for Vue **3**
* Support Vue files with Typescript syntax (the script within `.vue` files will be handled as Typescript).
* `recommendedJavascript`
* Same as `recommended` but Vue files (the script part) will be handled as Javascript.
* `recommendedVue2`
* Same as `recommended` but Vue files are considered in Vue 2 syntax.
* `recommendedVue2Javascript`
* Same as `recommended` but Vue files are considered in Vue 2 syntax and the script part will be handled as Javascript instead of Typescript.

## Release new version

1. Update CHANGELOG.md file with the latest changes
Expand Down
19 changes: 19 additions & 0 deletions REUSE.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
# SPDX-License-Identifier: AGPL-3.0-or-later

version = 1
SPDX-PackageName = "eslint-config"
SPDX-PackageSupplier = "Nextcloud <[email protected]>"
Expand All @@ -10,3 +11,21 @@ path = ["package-lock.json", "package.json"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2019 Nextcloud GmbH and Nextcloud contributors"
SPDX-License-Identifier = "AGPL-3.0-or-later"

[[annotations]]
path = ["tsconfig.json", "tests/tsconfig.json"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2025 Nextcloud GmbH and Nextcloud contributors"
SPDX-License-Identifier = "CC0-1.0"

# Test fixtures might not be able to have headers (as e.g. the header is tested)
[[annotations]]
path = [
"tests/fixtures/codestyle/input/*.ts",
"tests/fixtures/codestyle/input/*.js",
"tests/fixtures/codestyle/output/*.ts",
"tests/fixtures/codestyle/output/*.js"
]
precedence = "aggregate"
SPDX-FileCopyrightText = "2025 Nextcloud GmbH and Nextcloud contributors"
SPDX-License-Identifier = "AGPL-3.0-or-later"
13 changes: 13 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*!
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: CC0-1.0
*/

import { recommended } from './dist/index.mjs'

export default [
{
ignores: ['tests/fixtures/'],
},
...recommended,
]
25 changes: 0 additions & 25 deletions index.js

This file was deleted.

173 changes: 173 additions & 0 deletions lib/configs/codeStyle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*!
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import type { Linter } from 'eslint'
import stylistic from '@stylistic/eslint-plugin'
import {
GLOB_FILES_JAVASCRIPT,
GLOB_FILES_TYPESCRIPT,
GLOB_FILES_VUE,
} from '../globs.ts'
import { ConfigOptions } from '../types'

/**
* Config factory for general code style related rules
* See also: https://docs.nextcloud.com/server/latest/developer_manual/getting_started/coding_standards/javascript.html#code-style
*
* @param options options defining the config preset flavor
*/
export function codeStyle(options: ConfigOptions): (Linter.Config | Linter.BaseConfig)[] {
return [
// Nextcloud code style
{
name: '@stylistic/configs/recommended',
files: [
...GLOB_FILES_JAVASCRIPT,
...GLOB_FILES_TYPESCRIPT,
...GLOB_FILES_VUE,
],
...stylistic.configs.customize({
flat: true,
indent: 'tab',
semi: false,
quotes: 'single',
quoteProps: 'as-needed',
commaDangle: 'always-multiline',
arrowParens: true,
braceStyle: '1tbs',
}),
},

{
files: [
...GLOB_FILES_JAVASCRIPT,
...GLOB_FILES_TYPESCRIPT,
...GLOB_FILES_VUE,
],
rules: {
// Overrides for the stylistic recommended rules

// Tabs should only be used for indention
'@stylistic/no-tabs': [
'error',
{ allowIndentationTabs: true },
],
// allow spaces after tabs for alignment
'@stylistic/no-mixed-spaces-and-tabs': [
'error',
'smart-tabs',
],
// allow backticks for strings that contain single quotes
'@stylistic/quotes': [
'error',
'single',
{
allowTemplateLiterals: false,
avoidEscape: true,
},
],

// Not included in stylistic preset but set by us:

// Enforce camelCase but allow legacy webpack variables
camelcase: [
'error',
{
allow: ['^__webpack_'],
properties: 'never',
ignoreGlobals: true,
},
],

// Make sure to use object shorthand properties
'object-shorthand': [
'error',
'properties',
{ avoidQuotes: true },
],

// Enforce new lines after [ and before ] if there are multiline entries or more than 1 item in the array (better git diff)
'@stylistic/array-bracket-newline': [
'error',
{
multiline: true,
minItems: 2,
},
],
// Enforce new lines between array elements (better git diff)
'@stylistic/array-element-newline': [
'error',
'always',
],
// Same for objects as for arrays
'@stylistic/object-curly-newline': [
'error',
{
consistent: true,
multiline: true,
},
],
'@stylistic/object-property-newline': 'error',

// No space between function name and parenthesis. Enforce fn() instead of fn ()
'@stylistic/function-call-spacing': [
'error',
'never',
],
// Enforce consistent newlines in function parameters, if one parameter is separated by newline, than all should
'@stylistic/function-call-argument-newline': [
'error',
'consistent',
],
// If parameters are separated by newlines, then the first one should also be separated by a newline from the parenthesis
'@stylistic/function-paren-newline': [
'error',
'multiline',
],
// Generator functions should have the * on the function keyword as this defines the type of function. "function* generator()"
'@stylistic/generator-star-spacing': [
'error',
'after',
],
// Arrow functions with implicit return should not have line breaks
// TODO: Discuss
'@stylistic/implicit-arrow-linebreak': [
'error',
'beside',
],
// Prevent issues with different OS by enforcing single line feed for new lien
'@stylistic/linebreak-style': [
'error',
'unix',
],
// Chained calls should be separated by newline (e.g. foo().forEach().map()...)
'@stylistic/newline-per-chained-call': ['error'],
// No useless semicolons
'@stylistic/no-extra-semi': ['error'],
'no-useless-concat': 'error',
// Prefer { ...foo } over Object.assign({}, foo)
'prefer-object-spread': 'warn',
// Prefer string templates
'prefer-template': 'warn',
},
name: 'nextcloud/stylistic/rules',
},

{
files: [
...GLOB_FILES_TYPESCRIPT,
...(options.vueIsTypescript ? GLOB_FILES_VUE : []),
],
rules: {
// consistent spacing for types
'@stylistic/type-annotation-spacing': 'error',
// consistent spacing for generics
'@stylistic/type-generic-spacing': 'error',
'@stylistic/type-named-tuple-spacing': 'error',
},
name: 'nextcloud/stylistic/ts-rules',
},
]
}
Loading
Loading