Skip to content

style: update to ESLint v9 and rework lint config #438

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

Merged
merged 1 commit into from
May 9, 2025
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
6 changes: 0 additions & 6 deletions .eslintignore

This file was deleted.

45 changes: 0 additions & 45 deletions .eslintrc.cjs

This file was deleted.

9 changes: 0 additions & 9 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,6 @@ updates:
development:
dependency-type: 'development'

# TODO(mcous, 2024-04-30): update to ESLint v9 + flat config
ignore:
- dependency-name: 'eslint'
versions: ['>=9']
- dependency-name: 'eslint-plugin-n'
versions: ['>=17']
- dependency-name: 'eslint-plugin-promise'
versions: ['>=7']

# Update GitHub Actions dependencies
- package-ecosystem: 'github-actions'
directory: '/'
Expand Down
3 changes: 0 additions & 3 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
scripts/*
.eslintignore
.prettierignore
.all-contributorsrc
9 changes: 0 additions & 9 deletions .prettierrc.yaml

This file was deleted.

95 changes: 95 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import js from '@eslint/js'
import eslintPluginVitest from '@vitest/eslint-plugin'
import eslintConfigPrettier from 'eslint-config-prettier'
import eslintPluginJestDom from 'eslint-plugin-jest-dom'
import eslintPluginPromise from 'eslint-plugin-promise'
import eslintPluginSimpleImportSort from 'eslint-plugin-simple-import-sort'
import eslintPluginSvelte from 'eslint-plugin-svelte'
import eslintPluginTestingLibrary from 'eslint-plugin-testing-library'
import eslintPluginUnicorn from 'eslint-plugin-unicorn'
import globals from 'globals'
import tseslint from 'typescript-eslint'

export default tseslint.config(
js.configs.recommended,
tseslint.configs.strict,
tseslint.configs.stylistic,
eslintPluginUnicorn.configs['flat/recommended'],
eslintPluginPromise.configs['flat/recommended'],
eslintPluginSvelte.configs['flat/recommended'],
eslintPluginSvelte.configs['flat/prettier'],
eslintConfigPrettier,
{
name: 'settings',
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
parserOptions: {
parser: tseslint.parser,
extraFileExtensions: ['.svelte'],
},
globals: {
...globals.browser,
...globals.node,
...globals.jest,
},
},
},
{
name: 'ignores',
ignores: ['coverage', 'types'],
},
{
name: 'simple-import-sort',
plugins: {
'simple-import-sort': eslintPluginSimpleImportSort,
},
rules: {
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
},
},
{
name: 'tests',
files: ['**/*.test.js'],
extends: [
eslintPluginVitest.configs.recommended,
eslintPluginJestDom.configs['flat/recommended'],
eslintPluginTestingLibrary.configs['flat/dom'],
],
rules: {
'testing-library/no-node-access': [
'error',
{ allowContainerFirstChild: true },
],
},
},
{
name: 'extras',
rules: {
'unicorn/prevent-abbreviations': 'off',
},
},
{
name: 'svelte-extras',
files: ['**/*.svelte'],
rules: {
'svelte/no-unused-svelte-ignore': 'off',
'unicorn/filename-case': ['error', { case: 'pascalCase' }],
'unicorn/no-useless-undefined': 'off',
},
},
{
name: 'ts-extras',
files: ['**/*.ts'],
extends: [
tseslint.configs.strictTypeChecked,
tseslint.configs.stylisticTypeChecked,
],
languageOptions: {
parserOptions: {
projectService: true,
},
},
}
)
6 changes: 4 additions & 2 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { VERSION as SVELTE_VERSION } from 'svelte/compiler'

const SVELTE_TRANSFORM_PATTERN =
SVELTE_VERSION >= '5' ? '^.+\\.svelte(?:\\.js)?$' : '^.+\\.svelte$'
SVELTE_VERSION >= '5'
? String.raw`^.+\.svelte(?:\.js)?$`
: String.raw`^.+\.svelte$`

export default {
testMatch: ['<rootDir>/tests/**/*.test.js'],
Expand All @@ -15,7 +17,7 @@ export default {
injectGlobals: false,
moduleNameMapper: {
'^vitest$': '<rootDir>/tests/_jest-vitest-alias.js',
'^@testing-library\\/svelte$': '<rootDir>/src/index.js',
[String.raw`^@testing-library\/svelte$`]: '<rootDir>/src/index.js',
},
resetMocks: true,
restoreMocks: true,
Expand Down
20 changes: 11 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,24 +90,25 @@
"@testing-library/dom": "9.x.x || 10.x.x"
},
"devDependencies": {
"@eslint/js": "^9.26.0",
"@jest/globals": "^29.7.0",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/user-event": "^14.6.1",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",
"@vitest/coverage-v8": "^3.1.3",
"@vitest/eslint-plugin": "^1.1.44",
"all-contributors-cli": "^6.26.1",
"doctoc": "^2.2.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-n": "^16.6.2",
"eslint-plugin-promise": "^6.4.0",
"eslint": "^9.26.0",
"eslint-config-prettier": "^10.1.5",
"eslint-plugin-jest-dom": "^5.5.0",
"eslint-plugin-promise": "^7.2.1",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-svelte": "^2.42.0",
"eslint-plugin-svelte": "^3.5.1",
"eslint-plugin-testing-library": "^7.1.1",
"eslint-plugin-unicorn": "^59.0.1",
"expect-type": "^1.2.1",
"globals": "^16.1.0",
"happy-dom": "^17.4.6",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
Expand All @@ -119,6 +120,7 @@
"svelte-check": "^4.1.7",
"svelte-jester": "^5.0.0",
"typescript": "^5.8.3",
"typescript-eslint": "^8.32.0",
"typescript-svelte-plugin": "^0.3.46",
"vite": "^6.3.5",
"vitest": "^3.1.3"
Expand Down
14 changes: 14 additions & 0 deletions prettier.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export default {
semi: false,
singleQuote: true,
trailingComma: 'es5',
plugins: ['prettier-plugin-svelte'],
overrides: [
{
files: '*.svelte',
options: {
parser: 'svelte',
},
},
],
}
14 changes: 3 additions & 11 deletions src/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,13 @@
*/
import * as LegacyCore from './legacy.js'
import * as ModernCore from './modern.svelte.js'
import {
createValidateOptions,
UnknownSvelteOptionsError,
} from './validate-options.js'
import { createValidateOptions } from './validate-options.js'

const { mount, unmount, updateProps, allowedOptions } =
ModernCore.IS_MODERN_SVELTE ? ModernCore : LegacyCore

/** Validate component options. */
const validateOptions = createValidateOptions(allowedOptions)

export {
mount,
UnknownSvelteOptionsError,
unmount,
updateProps,
validateOptions,
}
export { mount, unmount, updateProps, validateOptions }
export { UnknownSvelteOptionsError } from './validate-options.js'
1 change: 0 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable import/export */
import { act, cleanup } from './pure.js'

// If we're running in a test runner that supports afterEach
Expand Down
17 changes: 11 additions & 6 deletions src/pure.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const render = (Component, options = {}, renderOptions = {}) => {
const queries = getQueriesForElement(baseElement, renderOptions.queries)

const target =
// eslint-disable-next-line unicorn/prefer-dom-node-append
options.target ?? baseElement.appendChild(document.createElement('div'))

targetCache.add(target)
Expand Down Expand Up @@ -116,14 +117,18 @@ const cleanupTarget = (target) => {
const inCache = targetCache.delete(target)

if (inCache && target.parentNode === document.body) {
document.body.removeChild(target)
target.remove()
}
}

/** Unmount all components and remove elements added to `<body>`. */
const cleanup = () => {
componentCache.forEach(cleanupComponent)
targetCache.forEach(cleanupTarget)
for (const component of componentCache) {
cleanupComponent(component)
}
for (const target of targetCache) {
cleanupTarget(target)
}
}

/**
Expand Down Expand Up @@ -163,12 +168,12 @@ const fireEvent = async (...args) => {
return event
}

Object.keys(baseFireEvent).forEach((key) => {
for (const [key, baseEvent] of Object.entries(baseFireEvent)) {
fireEvent[key] = async (...args) => {
const event = baseFireEvent[key](...args)
const event = baseEvent(...args)
await tick()
return event
}
})
}

export { act, cleanup, fireEvent, render }
12 changes: 7 additions & 5 deletions src/vite.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import path from 'node:path'
import url from 'node:url'

/**
* Vite plugin to configure @testing-library/svelte.
Expand Down Expand Up @@ -50,8 +50,8 @@ const addBrowserCondition = (config) => {
const browserConditionIndex = conditions.indexOf('browser')

if (
nodeConditionIndex >= 0 &&
(nodeConditionIndex < browserConditionIndex || browserConditionIndex < 0)
nodeConditionIndex !== -1 &&
(nodeConditionIndex < browserConditionIndex || browserConditionIndex === -1)
) {
conditions.splice(nodeConditionIndex, 0, 'browser')
}
Expand All @@ -77,7 +77,9 @@ const addAutoCleanup = (config) => {
setupFiles = [setupFiles]
}

setupFiles.push(join(dirname(fileURLToPath(import.meta.url)), './vitest.js'))
setupFiles.push(
path.join(path.dirname(url.fileURLToPath(import.meta.url)), './vitest.js')
)

test.setupFiles = setupFiles
config.test = test
Expand Down
2 changes: 1 addition & 1 deletion tests/_env.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { VERSION as SVELTE_VERSION } from 'svelte/compiler'

export const IS_JSDOM = window.navigator.userAgent.includes('jsdom')
export const IS_JSDOM = globalThis.navigator.userAgent.includes('jsdom')

export const IS_HAPPYDOM = !IS_JSDOM // right now it's happy or js

Expand Down
Loading