chore: switch to @eslint-react/eslint-plugin, lint entire codebase (#7119)

This commit is contained in:
Elliot DeNolf
2024-07-11 16:19:07 -04:00
committed by GitHub
415 changed files with 8666 additions and 8014 deletions

View File

@@ -19,3 +19,6 @@ fb7d1be2f3325d076b7c967b1730afcef37922c2
# 3.0 prettier & lint everywhere
6789e61488a1d3de56f472ac3214faf344030005
# 3.0 prettier & lint everywhere again
83fd4c66222d7846eeb5cc332dfa99bf1e830831

View File

@@ -1,13 +1,15 @@
import { jest } from '@jest/globals'
import fs from 'fs'
import fse from 'fs-extra'
import globby from 'globby'
import * as os from 'node:os'
import path from 'path'
import type { CliArgs, DbType, ProjectTemplate } from '../types.js'
import { createProject } from './create-project.js'
import { dbReplacements } from './replacements.js'
import { getValidTemplates } from './templates.js'
import globby from 'globby'
import { jest } from '@jest/globals'
import fs from 'fs'
import * as os from 'node:os'
describe('createProject', () => {
let projectDir: string
@@ -27,7 +29,6 @@ describe('createProject', () => {
})
describe('#createProject', () => {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const args = {
_: ['project-name'],
'--db': 'mongodb',
@@ -41,15 +42,15 @@ describe('createProject', () => {
const template: ProjectTemplate = {
name: 'plugin',
type: 'plugin',
url: 'https://github.com/payloadcms/payload-plugin-template',
description: 'Template for creating a Payload plugin',
url: 'https://github.com/payloadcms/payload-plugin-template',
}
await createProject({
cliArgs: args,
projectName,
projectDir,
template,
packageManager,
projectDir,
projectName,
template,
})
const packageJsonPath = path.resolve(projectDir, 'package.json')
@@ -84,14 +85,14 @@ describe('createProject', () => {
await createProject({
cliArgs,
projectName,
projectDir,
template: template as ProjectTemplate,
packageManager,
dbDetails: {
dbUri: `${db}://localhost:27017/create-project-test`,
type: db as DbType,
dbUri: `${db}://localhost:27017/create-project-test`,
},
packageManager,
projectDir,
projectName,
template: template as ProjectTemplate,
})
const dbReplacement = dbReplacements[db as DbType]

View File

@@ -24,13 +24,13 @@ const writeFile = promisify(fs.writeFile)
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
type InitNextArgs = Pick<CliArgs, '--debug'> & {
type InitNextArgs = {
dbType: DbType
nextAppDetails?: NextAppDetails
packageManager: PackageManager
projectDir: string
useDistFiles?: boolean
}
} & Pick<CliArgs, '--debug'>
type InitNextResult =
| {
@@ -144,11 +144,11 @@ async function addPayloadConfigToTsConfig(projectDir: string, isSrcDir: boolean)
}
function installAndConfigurePayload(
args: InitNextArgs & {
args: {
nextAppDetails: NextAppDetails
nextConfigType: NextConfigType
useDistFiles?: boolean
},
} & InitNextArgs,
):
| { payloadConfigPath: string; success: true }
| { payloadConfigPath?: string; reason: string; success: false } {

View File

@@ -1,11 +1,16 @@
import { parseAndModifyConfigContent, withPayloadStatement } from './wrap-next-config.js'
import * as p from '@clack/prompts'
import { jest } from '@jest/globals'
import { parseAndModifyConfigContent, withPayloadStatement } from './wrap-next-config.js'
const esmConfigs = {
defaultNextConfig: `/** @type {import('next').NextConfig} */
const nextConfig = {};
export default nextConfig;
`,
nextConfigExportNamedDefault: `const nextConfig = {};
const wrapped = someFunc(asdf);
export { wrapped as default };
`,
nextConfigWithFunc: `const nextConfig = {};
export default someFunc(nextConfig);
@@ -14,10 +19,6 @@ export default someFunc(nextConfig);
export default someFunc(
nextConfig
);
`,
nextConfigExportNamedDefault: `const nextConfig = {};
const wrapped = someFunc(asdf);
export { wrapped as default };
`,
nextConfigWithSpread: `const nextConfig = {
...someConfig,
@@ -27,12 +28,16 @@ export default nextConfig;
}
const cjsConfigs = {
anonConfig: `module.exports = {};`,
defaultNextConfig: `
/** @type {import('next').NextConfig} */
const nextConfig = {};
module.exports = nextConfig;
`,
anonConfig: `module.exports = {};`,
nextConfigExportNamedDefault: `const nextConfig = {};
const wrapped = someFunc(asdf);
module.exports = wrapped;
`,
nextConfigWithFunc: `const nextConfig = {};
module.exports = someFunc(nextConfig);
`,
@@ -40,10 +45,6 @@ module.exports = someFunc(nextConfig);
module.exports = someFunc(
nextConfig
);
`,
nextConfigExportNamedDefault: `const nextConfig = {};
const wrapped = someFunc(asdf);
module.exports = wrapped;
`,
nextConfigWithSpread: `const nextConfig = { ...someConfig };
module.exports = nextConfig;
@@ -76,7 +77,7 @@ describe('parseAndInsertWithPayload', () => {
configType,
)
expect(modifiedConfigContent).toContain(importStatement)
expect(modifiedConfigContent).toMatch(/withPayload\(someFunc\(\n nextConfig\n\)\)/)
expect(modifiedConfigContent).toMatch(/withPayload\(someFunc\(\n {2}nextConfig\n\)\)/)
})
it('should parse the config with a spread', () => {
@@ -137,7 +138,7 @@ describe('parseAndInsertWithPayload', () => {
configType,
)
expect(modifiedConfigContent).toContain(requireStatement)
expect(modifiedConfigContent).toMatch(/withPayload\(someFunc\(\n nextConfig\n\)\)/)
expect(modifiedConfigContent).toMatch(/withPayload\(someFunc\(\n {2}nextConfig\n\)\)/)
})
it('should parse the config with a named export as default', () => {
const { modifiedConfigContent } = parseAndModifyConfigContent(

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-console */
import * as p from '@clack/prompts'
import chalk from 'chalk'

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import type { ConnectOptions } from 'mongoose'
import type { Connect } from 'payload'
@@ -24,7 +23,7 @@ export const connect: Connect = async function connect(
const urlToConnect = this.url
const connectionOptions: ConnectOptions & { useFacet: undefined } = {
const connectionOptions: { useFacet: undefined } & ConnectOptions = {
autoIndex: true,
...this.connectOptions,
useFacet: undefined,

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-restricted-syntax, no-await-in-loop */
import type { CreateMigration, MigrationTemplateArgs } from 'payload'
import fs from 'fs'

View File

@@ -86,7 +86,6 @@ export const find: Find = async function find(
return {
...result,
docs: docs.map((doc) => {
// eslint-disable-next-line no-param-reassign
doc.id = doc._id
return sanitizeInternalFields(doc)
}),

View File

@@ -104,7 +104,6 @@ export const findGlobalVersions: FindGlobalVersions = async function findGlobalV
return {
...result,
docs: docs.map((doc) => {
// eslint-disable-next-line no-param-reassign
doc.id = doc._id
return sanitizeInternalFields(doc)
}),

View File

@@ -101,7 +101,6 @@ export const findVersions: FindVersions = async function findVersions(
return {
...result,
docs: docs.map((doc) => {
// eslint-disable-next-line no-param-reassign
doc.id = doc._id
return sanitizeInternalFields(doc)
}),

View File

@@ -43,10 +43,10 @@ export interface Args {
/** Set to false to disable auto-pluralization of collection names, Defaults to true */
autoPluralization?: boolean
/** Extra configuration options */
connectOptions?: ConnectOptions & {
connectOptions?: {
/** Set false to disable $facet aggregation in non-supporting databases, Defaults to true */
useFacet?: boolean
}
} & ConnectOptions
/** Set to true to disable hinting to MongoDB to use 'id' as index. This is currently done when counting documents for pagination. Disabling this optimization might fix some problems with AWS DocumentDB. Defaults to false */
disableIndexHints?: boolean
migrationDir?: string
@@ -59,19 +59,19 @@ export interface Args {
url: false | string
}
export type MongooseAdapter = BaseDatabaseAdapter &
Args & {
collections: {
[slug: string]: CollectionModel
}
connection: Connection
globals: GlobalModel
mongoMemoryServer: MongoMemoryReplSet
sessions: Record<number | string, ClientSession>
versions: {
[slug: string]: CollectionModel
}
export type MongooseAdapter = {
collections: {
[slug: string]: CollectionModel
}
connection: Connection
globals: GlobalModel
mongoMemoryServer: MongoMemoryReplSet
sessions: Record<number | string, ClientSession>
versions: {
[slug: string]: CollectionModel
}
} & Args &
BaseDatabaseAdapter
declare module 'payload' {
export interface DatabaseAdapter

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-param-reassign */
import type { PaginateOptions } from 'mongoose'
import type { Init, SanitizedCollectionConfig } from 'payload'

View File

@@ -1,6 +1,3 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable class-methods-use-this */
/* eslint-disable @typescript-eslint/no-use-before-define */
import type { IndexOptions, Schema, SchemaOptions, SchemaTypeOptions } from 'mongoose'
import type {
ArrayField,
@@ -196,12 +193,10 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
if (field.localized && config.localization) {
config.localization.localeCodes.forEach((localeCode) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error Possible incorrect typing in mongoose types, this works
schema.path(`${field.name}.${localeCode}`).discriminator(blockItem.slug, blockSchema)
})
} else {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error Possible incorrect typing in mongoose types, this works
schema.path(field.name).discriminator(blockItem.slug, blockSchema)
}

View File

@@ -20,11 +20,10 @@ export async function buildAndOrConditions({
const completedConditions = []
// Loop over all AND / OR operations and add them to the AND / OR query param
// Operations should come through as an array
// eslint-disable-next-line no-restricted-syntax
for (const condition of where) {
// If the operation is properly formatted as an object
if (typeof condition === 'object') {
// eslint-disable-next-line no-await-in-loop
const result = await parseParams({
collectionSlug,
fields,

View File

@@ -1,22 +1,23 @@
import { SanitizedConfig, sanitizeConfig } from 'payload'
import { Config } from 'payload'
import type { Config, SanitizedConfig } from 'payload'
import { sanitizeConfig } from 'payload'
import { getLocalizedSortProperty } from './getLocalizedSortProperty.js'
let config: SanitizedConfig
describe('get localized sort property', () => {
beforeAll(async () => {
config = (await sanitizeConfig({
config = await sanitizeConfig({
localization: {
locales: ['en', 'es'],
defaultLocale: 'en',
fallback: true,
locales: ['en', 'es'],
},
} as Config)) as SanitizedConfig
} as Config)
})
it('passes through a non-localized sort property', async () => {
const result = getLocalizedSortProperty({
segments: ['title'],
config,
fields: [
{
@@ -25,6 +26,7 @@ describe('get localized sort property', () => {
},
],
locale: 'en',
segments: ['title'],
})
expect(result).toStrictEqual('title')
@@ -32,7 +34,6 @@ describe('get localized sort property', () => {
it('properly localizes an un-localized sort property', () => {
const result = getLocalizedSortProperty({
segments: ['title'],
config,
fields: [
{
@@ -42,6 +43,7 @@ describe('get localized sort property', () => {
},
],
locale: 'en',
segments: ['title'],
})
expect(result).toStrictEqual('title.en')
@@ -49,7 +51,6 @@ describe('get localized sort property', () => {
it('keeps specifically asked-for localized sort properties', () => {
const result = getLocalizedSortProperty({
segments: ['title', 'es'],
config,
fields: [
{
@@ -59,6 +60,7 @@ describe('get localized sort property', () => {
},
],
locale: 'en',
segments: ['title', 'es'],
})
expect(result).toStrictEqual('title.es')
@@ -66,7 +68,6 @@ describe('get localized sort property', () => {
it('properly localizes nested sort properties', () => {
const result = getLocalizedSortProperty({
segments: ['group', 'title'],
config,
fields: [
{
@@ -82,6 +83,7 @@ describe('get localized sort property', () => {
},
],
locale: 'en',
segments: ['group', 'title'],
})
expect(result).toStrictEqual('group.title.en')
@@ -89,7 +91,6 @@ describe('get localized sort property', () => {
it('keeps requested locale with nested sort properties', () => {
const result = getLocalizedSortProperty({
segments: ['group', 'title', 'es'],
config,
fields: [
{
@@ -105,6 +106,7 @@ describe('get localized sort property', () => {
},
],
locale: 'en',
segments: ['group', 'title', 'es'],
})
expect(result).toStrictEqual('group.title.es')
@@ -112,7 +114,6 @@ describe('get localized sort property', () => {
it('properly localizes field within row', () => {
const result = getLocalizedSortProperty({
segments: ['title'],
config,
fields: [
{
@@ -127,6 +128,7 @@ describe('get localized sort property', () => {
},
],
locale: 'en',
segments: ['title'],
})
expect(result).toStrictEqual('title.en')
@@ -134,7 +136,6 @@ describe('get localized sort property', () => {
it('properly localizes field within named tab', () => {
const result = getLocalizedSortProperty({
segments: ['tab', 'title'],
config,
fields: [
{
@@ -154,6 +155,7 @@ describe('get localized sort property', () => {
},
],
locale: 'en',
segments: ['tab', 'title'],
})
expect(result).toStrictEqual('tab.title.en')
@@ -161,14 +163,12 @@ describe('get localized sort property', () => {
it('properly localizes field within unnamed tab', () => {
const result = getLocalizedSortProperty({
segments: ['title'],
config,
fields: [
{
type: 'tabs',
tabs: [
{
label: 'Tab',
fields: [
{
name: 'title',
@@ -176,11 +176,13 @@ describe('get localized sort property', () => {
localized: true,
},
],
label: 'Tab',
},
],
},
],
locale: 'en',
segments: ['title'],
})
expect(result).toStrictEqual('title.en')

View File

@@ -1,5 +1,3 @@
/* eslint-disable no-restricted-syntax */
/* eslint-disable no-await-in-loop */
import type { FilterQuery } from 'mongoose'
import type { Field, Operator, Payload, Where } from 'payload'

View File

@@ -87,7 +87,6 @@ export const queryDrafts: QueryDrafts = async function queryDrafts(
return {
...result,
docs: docs.map((doc) => {
// eslint-disable-next-line no-param-reassign
doc = {
_id: doc.parent,
id: doc.parent,

View File

@@ -1,7 +1,9 @@
import { resendAdapter } from './index.js'
import { Payload } from 'payload'
import type { Payload } from 'payload'
import { jest } from '@jest/globals'
import { resendAdapter } from './index.js'
describe('email-resend', () => {
const defaultFromAddress = 'dev@payloadcms.com'
const defaultFromName = 'Payload CMS'
@@ -29,16 +31,16 @@ describe('email-resend', () => {
) as jest.Mock
const adapter = resendAdapter({
apiKey,
defaultFromAddress,
defaultFromName,
apiKey,
})
await adapter({ payload: mockPayload }).sendEmail({
from,
to,
subject,
text,
to,
})
// @ts-expect-error
@@ -48,16 +50,16 @@ describe('email-resend', () => {
expect(request.headers.Authorization).toStrictEqual(`Bearer ${apiKey}`)
expect(JSON.parse(request.body)).toMatchObject({
from,
to,
subject,
text,
to,
})
})
it('should throw an error if the email fails to send', async () => {
const errorResponse = {
message: 'error information',
name: 'validation_error',
message: 'error information',
statusCode: 403,
}
global.fetch = jest.spyOn(global, 'fetch').mockImplementation(
@@ -69,17 +71,17 @@ describe('email-resend', () => {
) as jest.Mock
const adapter = resendAdapter({
apiKey,
defaultFromAddress,
defaultFromName,
apiKey,
})
await expect(() =>
adapter({ payload: mockPayload }).sendEmail({
from,
to,
subject,
text,
to,
}),
).rejects.toThrow(
`Error sending email: ${errorResponse.statusCode} ${errorResponse.name} - ${errorResponse.message}`,

View File

@@ -4,17 +4,20 @@ import jestDom from 'eslint-plugin-jest-dom'
import jest from 'eslint-plugin-jest'
import { deepMerge } from '../../deepMerge.js'
/** @type {import('eslint').Linter.FlatConfig} */
export const index = deepMerge(
jestRules,
jestDomRules,
{
rules: jestRules,
},
{
rules: jestDomRules,
},
{
plugins: {
jest,
'jest-dom': jestDom,
},
}
},
)
export default index

View File

@@ -1,12 +1,10 @@
/** @type {import('eslint').Linter.FlatConfig} */
export const index = {
rules: {
'jest-dom/prefer-checked': 'error',
'jest-dom/prefer-enabled-disabled': 'error',
'jest-dom/prefer-focus': 'error',
'jest-dom/prefer-required': 'error',
'jest-dom/prefer-to-have-attribute': 'error',
},
'jest-dom/prefer-checked': 'error',
'jest-dom/prefer-enabled-disabled': 'error',
'jest-dom/prefer-focus': 'error',
'jest-dom/prefer-required': 'error',
'jest-dom/prefer-to-have-attribute': 'error',
}
export default index

View File

@@ -1,40 +1,38 @@
/** @type {import('eslint').Linter.FlatConfig} */
export const index = {
rules: {
'jest/consistent-test-it': ['error', { fn: 'it' }],
'jest/expect-expect': 'error',
'jest/prefer-lowercase-title': ['error', { ignore: ['describe'] }],
'jest/no-alias-methods': 'error',
'jest/no-commented-out-tests': 'off',
'jest/no-disabled-tests': 'off',
'jest/no-duplicate-hooks': 'error',
'jest/no-export': 'error',
'jest/no-focused-tests': 'error',
'jest/no-hooks': 'off',
'jest/no-identical-title': 'error',
'jest/no-conditional-in-test': 'error',
'jest/no-jasmine-globals': 'error',
'jest/no-large-snapshots': 'error',
'jest/no-mocks-import': 'error',
'jest/no-standalone-expect': 'error',
'jest/no-done-callback': 'error',
'jest/no-test-prefixes': 'error',
'jest/no-test-return-statement': 'error',
'jest/prefer-called-with': 'error',
'jest/prefer-expect-assertions': 'off',
'jest/prefer-hooks-on-top': 'error',
'jest/prefer-spy-on': 'error',
'jest/prefer-strict-equal': 'error',
'jest/prefer-to-contain': 'error',
'jest/prefer-to-have-length': 'error',
'jest/prefer-todo': 'error',
'jest/require-top-level-describe': 'error',
'jest/require-to-throw-message': 'error',
'jest/valid-describe-callback': 'error',
'jest/valid-expect-in-promise': 'error',
'jest/valid-expect': 'error',
'jest/valid-title': 'error',
},
'jest/consistent-test-it': ['error', { fn: 'it' }],
'jest/expect-expect': 'error',
'jest/prefer-lowercase-title': ['error', { ignore: ['describe'] }],
'jest/no-alias-methods': 'error',
'jest/no-commented-out-tests': 'off',
'jest/no-disabled-tests': 'off',
'jest/no-duplicate-hooks': 'error',
'jest/no-export': 'error',
'jest/no-focused-tests': 'error',
'jest/no-hooks': 'off',
'jest/no-identical-title': 'error',
'jest/no-conditional-in-test': 'warn',
'jest/no-jasmine-globals': 'error',
'jest/no-large-snapshots': 'error',
'jest/no-mocks-import': 'error',
'jest/no-standalone-expect': 'error',
'jest/no-done-callback': 'error',
'jest/no-test-prefixes': 'error',
'jest/no-test-return-statement': 'error',
'jest/prefer-called-with': 'error',
'jest/prefer-expect-assertions': 'off',
'jest/prefer-hooks-on-top': 'error',
'jest/prefer-spy-on': 'off', // broken in packages/create-payload-app/src/lib/create-project.spec.ts
'jest/prefer-strict-equal': 'warn',
'jest/prefer-to-contain': 'error',
'jest/prefer-to-have-length': 'error',
'jest/prefer-todo': 'error',
'jest/require-top-level-describe': 'error',
'jest/require-to-throw-message': 'error',
'jest/valid-describe-callback': 'error',
'jest/valid-expect-in-promise': 'error',
'jest/valid-expect': 'error',
'jest/valid-title': 'error',
}
export default index

View File

@@ -1,23 +1,20 @@
import reactRules from './rules/react.mjs'
import reactA11yRules from './rules/react-a11y.mjs'
import jsxA11y from 'eslint-plugin-jsx-a11y'
import eslintPluginReactConfig from 'eslint-plugin-react/configs/recommended.js'
import eslintPluginReact from 'eslint-plugin-react'
import react from '@eslint-react/eslint-plugin'
import reactHooks from 'eslint-plugin-react-hooks'
import globals from 'globals';
import { fixupPluginRules } from '@eslint/compat'
import globals from 'globals'
import { deepMerge } from '../../deepMerge.js'
/** @type {import('eslint').Linter.FlatConfig} */
export const index = deepMerge(
react.configs['recommended-type-checked'],
{
rules: eslintPluginReact.configs.recommended.rules
rules: reactRules,
},
{
rules: eslintPluginReactConfig.rules // Only take rules from the config, not plugins, as plugins there are on the old eslint v8 format => add react-hooks plugin myself below
rules: reactA11yRules,
},
reactRules,
reactA11yRules,
{
languageOptions: {
globals: {
@@ -26,12 +23,11 @@ export const index = deepMerge(
parserOptions: {
ecmaFeatures: {
jsx: true,
}
}
},
},
},
plugins: {
'jsx-a11y': jsxA11y,
react: fixupPluginRules(eslintPluginReact),
'react-hooks': reactHooks,
},
settings: {
@@ -39,6 +35,6 @@ export const index = deepMerge(
version: 'detect',
},
},
}
},
)
export default index

View File

@@ -1,249 +1,246 @@
// Sourced from https://github.com/airbnb/javascript/blob/master/packages/eslint-config-airbnb/rules/react-a11y.js
/** @type {import('eslint').Linter.FlatConfig} */
export const index = {
rules: {
// Enforce that anchors have content
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-has-content.md
'jsx-a11y/anchor-has-content': ['error', { components: [] }],
// Enforce that anchors have content
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-has-content.md
'jsx-a11y/anchor-has-content': ['error', { components: [] }],
// Require ARIA roles to be valid and non-abstract
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-role.md
'jsx-a11y/aria-role': ['error', { ignoreNonDom: false }],
// Require ARIA roles to be valid and non-abstract
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-role.md
'jsx-a11y/aria-role': ['error', { ignoreNonDom: false }],
// Enforce all aria-* props are valid.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-props.md
'jsx-a11y/aria-props': 'error',
// Enforce all aria-* props are valid.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-props.md
'jsx-a11y/aria-props': 'error',
// Enforce ARIA state and property values are valid.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-proptypes.md
'jsx-a11y/aria-proptypes': 'error',
// Enforce ARIA state and property values are valid.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-proptypes.md
'jsx-a11y/aria-proptypes': 'error',
// Enforce that elements that do not support ARIA roles, states, and
// properties do not have those attributes.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-unsupported-elements.md
'jsx-a11y/aria-unsupported-elements': 'error',
// Enforce that elements that do not support ARIA roles, states, and
// properties do not have those attributes.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-unsupported-elements.md
'jsx-a11y/aria-unsupported-elements': 'error',
// Enforce that all elements that require alternative text have meaningful information
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/alt-text.md
'jsx-a11y/alt-text': [
'error',
{
elements: ['img', 'object', 'area', 'input[type="image"]'],
img: [],
object: [],
area: [],
'input[type="image"]': [],
// Enforce that all elements that require alternative text have meaningful information
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/alt-text.md
'jsx-a11y/alt-text': [
'error',
{
elements: ['img', 'object', 'area', 'input[type="image"]'],
img: [],
object: [],
area: [],
'input[type="image"]': [],
},
],
// Prevent img alt text from containing redundant words like "image", "picture", or "photo"
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-redundant-alt.md
'jsx-a11y/img-redundant-alt': 'error',
// require that JSX labels use "htmlFor"
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/label-has-for.md
// deprecated: replaced by `label-has-associated-control` rule
'jsx-a11y/label-has-for': [
'off',
{
components: [],
required: {
every: ['nesting', 'id'],
},
],
allowChildren: false,
},
],
// Prevent img alt text from containing redundant words like "image", "picture", or "photo"
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-redundant-alt.md
'jsx-a11y/img-redundant-alt': 'error',
// Enforce that a label tag has a text label and an associated control.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/b800f40a2a69ad48015ae9226fbe879f946757ed/docs/rules/label-has-associated-control.md
'jsx-a11y/label-has-associated-control': [
'error',
{
labelComponents: [],
labelAttributes: [],
controlComponents: [],
assert: 'both',
depth: 25,
},
],
// require that JSX labels use "htmlFor"
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/label-has-for.md
// deprecated: replaced by `label-has-associated-control` rule
'jsx-a11y/label-has-for': [
'off',
{
components: [],
required: {
every: ['nesting', 'id'],
},
allowChildren: false,
},
],
// Enforce that a control (an interactive element) has a text label.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/control-has-associated-label.md
'jsx-a11y/control-has-associated-label': [
'error',
{
labelAttributes: ['label'],
controlComponents: [],
ignoreElements: ['audio', 'canvas', 'embed', 'input', 'textarea', 'tr', 'video'],
ignoreRoles: [
'grid',
'listbox',
'menu',
'menubar',
'radiogroup',
'row',
'tablist',
'toolbar',
'tree',
'treegrid',
],
depth: 5,
},
],
// Enforce that a label tag has a text label and an associated control.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/b800f40a2a69ad48015ae9226fbe879f946757ed/docs/rules/label-has-associated-control.md
'jsx-a11y/label-has-associated-control': [
'error',
{
labelComponents: [],
labelAttributes: [],
controlComponents: [],
assert: 'both',
depth: 25,
},
],
// require that mouseover/out come with focus/blur, for keyboard-only users
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/mouse-events-have-key-events.md
'jsx-a11y/mouse-events-have-key-events': 'error',
// Enforce that a control (an interactive element) has a text label.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/control-has-associated-label.md
'jsx-a11y/control-has-associated-label': [
'error',
{
labelAttributes: ['label'],
controlComponents: [],
ignoreElements: ['audio', 'canvas', 'embed', 'input', 'textarea', 'tr', 'video'],
ignoreRoles: [
'grid',
'listbox',
'menu',
'menubar',
'radiogroup',
'row',
'tablist',
'toolbar',
'tree',
'treegrid',
],
depth: 5,
},
],
// Prevent use of `accessKey`
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md
'jsx-a11y/no-access-key': 'error',
// require that mouseover/out come with focus/blur, for keyboard-only users
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/mouse-events-have-key-events.md
'jsx-a11y/mouse-events-have-key-events': 'error',
// require onBlur instead of onChange
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-onchange.md
'jsx-a11y/no-onchange': 'off',
// Prevent use of `accessKey`
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md
'jsx-a11y/no-access-key': 'error',
// Elements with an interactive role and interaction handlers must be focusable
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/interactive-supports-focus.md
'jsx-a11y/interactive-supports-focus': 'error',
// require onBlur instead of onChange
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-onchange.md
'jsx-a11y/no-onchange': 'off',
// Enforce that elements with ARIA roles must have all required attributes
// for that role.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/role-has-required-aria-props.md
'jsx-a11y/role-has-required-aria-props': 'error',
// Elements with an interactive role and interaction handlers must be focusable
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/interactive-supports-focus.md
'jsx-a11y/interactive-supports-focus': 'error',
// Enforce that elements with explicit or implicit roles defined contain
// only aria-* properties supported by that role.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/role-supports-aria-props.md
'jsx-a11y/role-supports-aria-props': 'error',
// Enforce that elements with ARIA roles must have all required attributes
// for that role.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/role-has-required-aria-props.md
'jsx-a11y/role-has-required-aria-props': 'error',
// Enforce tabIndex value is not greater than zero.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/tabindex-no-positive.md
'jsx-a11y/tabindex-no-positive': 'error',
// Enforce that elements with explicit or implicit roles defined contain
// only aria-* properties supported by that role.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/role-supports-aria-props.md
'jsx-a11y/role-supports-aria-props': 'error',
// ensure <hX> tags have content and are not aria-hidden
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/heading-has-content.md
'jsx-a11y/heading-has-content': ['error', { components: [''] }],
// Enforce tabIndex value is not greater than zero.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/tabindex-no-positive.md
'jsx-a11y/tabindex-no-positive': 'error',
// require HTML elements to have a "lang" prop
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/html-has-lang.md
'jsx-a11y/html-has-lang': 'error',
// ensure <hX> tags have content and are not aria-hidden
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/heading-has-content.md
'jsx-a11y/heading-has-content': ['error', { components: [''] }],
// require HTML element's lang prop to be valid
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/lang.md
'jsx-a11y/lang': 'error',
// require HTML elements to have a "lang" prop
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/html-has-lang.md
'jsx-a11y/html-has-lang': 'error',
// prevent distracting elements, like <marquee> and <blink>
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-distracting-elements.md
'jsx-a11y/no-distracting-elements': [
'error',
{
elements: ['marquee', 'blink'],
},
],
// require HTML element's lang prop to be valid
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/lang.md
'jsx-a11y/lang': 'error',
// only allow <th> to have the "scope" attr
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/scope.md
'jsx-a11y/scope': 'error',
// prevent distracting elements, like <marquee> and <blink>
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-distracting-elements.md
'jsx-a11y/no-distracting-elements': [
'error',
{
elements: ['marquee', 'blink'],
},
],
// require onClick be accompanied by onKeyUp/onKeyDown/onKeyPress
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/click-events-have-key-events.md
'jsx-a11y/click-events-have-key-events': 'error',
// only allow <th> to have the "scope" attr
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/scope.md
'jsx-a11y/scope': 'error',
// Enforce that DOM elements without semantic behavior not have interaction handlers
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-static-element-interactions.md
'jsx-a11y/no-static-element-interactions': [
'error',
{
handlers: ['onClick', 'onMouseDown', 'onMouseUp', 'onKeyPress', 'onKeyDown', 'onKeyUp'],
},
],
// require onClick be accompanied by onKeyUp/onKeyDown/onKeyPress
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/click-events-have-key-events.md
'jsx-a11y/click-events-have-key-events': 'error',
// A non-interactive element does not support event handlers (mouse and key handlers)
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-element-interactions.md
'jsx-a11y/no-noninteractive-element-interactions': [
'error',
{
handlers: ['onClick', 'onMouseDown', 'onMouseUp', 'onKeyPress', 'onKeyDown', 'onKeyUp'],
},
],
// Enforce that DOM elements without semantic behavior not have interaction handlers
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-static-element-interactions.md
'jsx-a11y/no-static-element-interactions': [
'error',
{
handlers: ['onClick', 'onMouseDown', 'onMouseUp', 'onKeyPress', 'onKeyDown', 'onKeyUp'],
},
],
// ensure emoji are accessible
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/accessible-emoji.md
'jsx-a11y/accessible-emoji': 'error',
// A non-interactive element does not support event handlers (mouse and key handlers)
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-element-interactions.md
'jsx-a11y/no-noninteractive-element-interactions': [
'error',
{
handlers: ['onClick', 'onMouseDown', 'onMouseUp', 'onKeyPress', 'onKeyDown', 'onKeyUp'],
},
],
// elements with aria-activedescendant must be tabbable
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-activedescendant-has-tabindex.md
'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
// ensure emoji are accessible
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/accessible-emoji.md
'jsx-a11y/accessible-emoji': 'error',
// ensure iframe elements have a unique title
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/iframe-has-title.md
'jsx-a11y/iframe-has-title': 'error',
// elements with aria-activedescendant must be tabbable
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-activedescendant-has-tabindex.md
'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
// prohibit autoFocus prop
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-autofocus.md
'jsx-a11y/no-autofocus': ['error', { ignoreNonDOM: true }],
// ensure iframe elements have a unique title
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/iframe-has-title.md
'jsx-a11y/iframe-has-title': 'error',
// ensure HTML elements do not specify redundant ARIA roles
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-redundant-roles.md
'jsx-a11y/no-redundant-roles': 'error',
// prohibit autoFocus prop
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-autofocus.md
'jsx-a11y/no-autofocus': ['error', { ignoreNonDOM: true }],
// media elements must have captions
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/media-has-caption.md
'jsx-a11y/media-has-caption': [
'error',
{
audio: [],
video: [],
track: [],
},
],
// ensure HTML elements do not specify redundant ARIA roles
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-redundant-roles.md
'jsx-a11y/no-redundant-roles': 'error',
// WAI-ARIA roles should not be used to convert an interactive element to non-interactive
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-interactive-element-to-noninteractive-role.md
'jsx-a11y/no-interactive-element-to-noninteractive-role': [
'error',
{
tr: ['none', 'presentation'],
},
],
// media elements must have captions
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/media-has-caption.md
'jsx-a11y/media-has-caption': [
'error',
{
audio: [],
video: [],
track: [],
},
],
// WAI-ARIA roles should not be used to convert a non-interactive element to interactive
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-element-to-interactive-role.md
'jsx-a11y/no-noninteractive-element-to-interactive-role': [
'error',
{
ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],
table: ['grid'],
td: ['gridcell'],
},
],
// WAI-ARIA roles should not be used to convert an interactive element to non-interactive
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-interactive-element-to-noninteractive-role.md
'jsx-a11y/no-interactive-element-to-noninteractive-role': [
'error',
{
tr: ['none', 'presentation'],
},
],
// Tab key navigation should be limited to elements on the page that can be interacted with.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-tabindex.md
'jsx-a11y/no-noninteractive-tabindex': [
'error',
{
tags: [],
roles: ['tabpanel'],
},
],
// WAI-ARIA roles should not be used to convert a non-interactive element to interactive
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-element-to-interactive-role.md
'jsx-a11y/no-noninteractive-element-to-interactive-role': [
'error',
{
ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],
table: ['grid'],
td: ['gridcell'],
},
],
// Tab key navigation should be limited to elements on the page that can be interacted with.
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-tabindex.md
'jsx-a11y/no-noninteractive-tabindex': [
'error',
{
tags: [],
roles: ['tabpanel'],
},
],
// ensure <a> tags are valid
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/0745af376cdc8686d85a361ce36952b1fb1ccf6e/docs/rules/anchor-is-valid.md
'jsx-a11y/anchor-is-valid': [
'error',
{
components: ['Link'],
specialLink: ['to'],
aspects: ['noHref', 'invalidHref', 'preferButton'],
},
],
},
// ensure <a> tags are valid
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/0745af376cdc8686d85a361ce36952b1fb1ccf6e/docs/rules/anchor-is-valid.md
'jsx-a11y/anchor-is-valid': [
'error',
{
components: ['Link'],
specialLink: ['to'],
aspects: ['noHref', 'invalidHref', 'preferButton'],
},
],
}
export default index

View File

@@ -1,549 +1,18 @@
/** @type {import('eslint').Linter.FlatConfig} */
export const index = {
rules: {
// View link below for react rules documentation
// https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules
// Specify whether double or single quotes should be used in JSX attributes
// https://eslint.org/docs/rules/jsx-quotes
'jsx-quotes': ['error', 'prefer-double'],
'class-methods-use-this': [
'error',
{
exceptMethods: [
'render',
'getInitialState',
'getDefaultProps',
'getChildContext',
'componentWillMount',
'UNSAFE_componentWillMount',
'componentDidMount',
'componentWillReceiveProps',
'UNSAFE_componentWillReceiveProps',
'shouldComponentUpdate',
'componentWillUpdate',
'UNSAFE_componentWillUpdate',
'componentDidUpdate',
'componentWillUnmount',
'componentDidCatch',
'getSnapshotBeforeUpdate',
],
},
],
// Prevent missing displayName in a React component definition
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md
'react/display-name': ['off', { ignoreTranspilerName: false }],
// Forbid certain propTypes (any, array, object)
// https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/forbid-prop-types.md
'react/forbid-prop-types': [
'error',
{
forbid: ['any', 'array', 'object'],
checkContextTypes: true,
checkChildContextTypes: true,
},
],
// Forbid certain props on DOM Nodes
// https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/forbid-dom-props.md
'react/forbid-dom-props': ['off', { forbid: [] }],
// Enforce boolean attributes notation in JSX
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md
'react/jsx-boolean-value': ['error', 'never', { always: [] }],
// Validate closing bracket location in JSX
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md
'react/jsx-closing-bracket-location': ['error', 'line-aligned'],
// Validate closing tag location in JSX
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-tag-location.md
'react/jsx-closing-tag-location': 'error',
// Enforce or disallow spaces inside of curly braces in JSX attributes
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md
'react/jsx-curly-spacing': ['error', 'never', { allowMultiline: true }],
// Enforce event handler naming conventions in JSX
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-handler-names.md
'react/jsx-handler-names': [
'off',
{
eventHandlerPrefix: 'handle',
eventHandlerPropPrefix: 'on',
},
],
// Validate props indentation in JSX
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-indent-props.md
'react/jsx-indent-props': ['error', 2],
// Validate JSX has key prop when in array or iterator
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-key.md
'react/jsx-key': 'off',
// Limit maximum of props on a single line in JSX
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-max-props-per-line.md
'react/jsx-max-props-per-line': ['error', { maximum: 1 }],
// Prevent usage of .bind() in JSX props
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md
'react/jsx-no-bind': [
'error',
{
ignoreRefs: true,
allowArrowFunctions: true,
allowFunctions: false,
allowBind: false,
ignoreDOMComponents: true,
},
],
// Prevent duplicate props in JSX
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-duplicate-props.md
'react/jsx-no-duplicate-props': ['error', { ignoreCase: true }],
// Prevent usage of unwrapped JSX strings
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-literals.md
'react/jsx-no-literals': ['off', { noStrings: true }],
// Disallow undeclared variables in JSX
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-undef.md
'react/jsx-no-undef': 'error',
// Enforce PascalCase for user-defined JSX components
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md
'react/jsx-pascal-case': [
'error',
{
allowAllCaps: true,
ignore: [],
},
],
// Enforce propTypes declarations alphabetical sorting
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-prop-types.md
'react/sort-prop-types': [
'off',
{
ignoreCase: true,
callbacksLast: false,
requiredFirst: false,
sortShapeProp: true,
},
],
// Deprecated in favor of react/jsx-sort-props
'react/jsx-sort-prop-types': 'off',
// Enforce props alphabetical sorting
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-sort-props.md
'react/jsx-sort-props': [
'off',
{
ignoreCase: true,
callbacksLast: false,
shorthandFirst: false,
shorthandLast: false,
noSortAlphabetically: false,
reservedFirst: true,
},
],
// Enforce defaultProps declarations alphabetical sorting
// https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/jsx-sort-default-props.md
'react/jsx-sort-default-props': [
'off',
{
ignoreCase: true,
},
],
// Prevent React to be incorrectly marked as unused
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md
'react/jsx-uses-react': ['error'],
// Prevent variables used in JSX to be incorrectly marked as unused
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md
'react/jsx-uses-vars': 'error',
// Prevent usage of dangerous JSX properties
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger.md
'react/no-danger': 'off',
// Prevent usage of deprecated methods
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-deprecated.md
'react/no-deprecated': ['error'],
// Prevent usage of setState in componentDidMount
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-mount-set-state.md
// this is necessary for server-rendering
'react/no-did-mount-set-state': 'off',
// Prevent usage of setState in componentDidUpdate
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-update-set-state.md
'react/no-did-update-set-state': 'off',
// Prevent usage of setState in componentWillUpdate
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-will-update-set-state.md
'react/no-will-update-set-state': 'error',
// Prevent direct mutation of this.state
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-direct-mutation-state.md
'react/no-direct-mutation-state': 'off',
// Prevent usage of isMounted
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md
'react/no-is-mounted': 'error',
// Prevent multiple component definition per file
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md
'react/no-multi-comp': 'off',
// Prevent usage of setState
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-set-state.md
'react/no-set-state': 'off',
// Prevent using string references
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md
'react/no-string-refs': 'error',
// Prevent usage of unknown DOM property
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md
'react/no-unknown-property': 'error',
// Require ES6 class declarations over React.createClass
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md
'react/prefer-es6-class': ['error', 'always'],
// Require stateless functions when not using lifecycle methods, setState or ref
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md
'react/prefer-stateless-function': ['error', { ignorePureComponents: true }],
// Prevent missing props validation in a React component definition
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prop-types.md
'react/prop-types': [
'error',
{
ignore: [],
customValidators: [],
skipUndeclared: false,
},
],
// Prevent missing React when using JSX
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md
'react/react-in-jsx-scope': 'error',
// Require render() methods to return something
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-render-return.md
'react/require-render-return': 'error',
// Prevent extra closing tags for components without children
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md
'react/self-closing-comp': 'error',
// Enforce component methods order
// https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/sort-comp.md
'react/sort-comp': [
'error',
{
order: [
'static-variables',
'static-methods',
'instance-variables',
'lifecycle',
'/^on.+$/',
'getters',
'setters',
'/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/',
'instance-methods',
'everything-else',
'rendering',
],
groups: {
lifecycle: [
'displayName',
'propTypes',
'contextTypes',
'childContextTypes',
'mixins',
'statics',
'defaultProps',
'constructor',
'getDefaultProps',
'getInitialState',
'state',
'getChildContext',
'getDerivedStateFromProps',
'componentWillMount',
'UNSAFE_componentWillMount',
'componentDidMount',
'componentWillReceiveProps',
'UNSAFE_componentWillReceiveProps',
'shouldComponentUpdate',
'componentWillUpdate',
'UNSAFE_componentWillUpdate',
'getSnapshotBeforeUpdate',
'componentDidUpdate',
'componentDidCatch',
'componentWillUnmount',
],
rendering: ['/^render.+$/', 'render'],
},
},
],
// Prevent missing parentheses around multilines JSX
// https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/jsx-wrap-multilines.md
'react/jsx-wrap-multilines': [
'error',
{
declaration: 'parens-new-line',
assignment: 'parens-new-line',
return: 'parens-new-line',
arrow: 'parens-new-line',
condition: 'parens-new-line',
logical: 'parens-new-line',
prop: 'parens-new-line',
},
],
// Require that the first prop in a JSX element be on a new line when the element is multiline
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-first-prop-new-line.md
'react/jsx-first-prop-new-line': ['error', 'multiline-multiprop'],
// Enforce spacing around jsx equals signs
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-equals-spacing.md
'react/jsx-equals-spacing': ['error', 'never'],
// Enforce JSX indentation
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-indent.md
'react/jsx-indent': ['error', 2],
// Disallow target="_blank" on links
// https://github.com/yannickcr/eslint-plugin-react/blob/ac102885765be5ff37847a871f239c6703e1c7cc/docs/rules/jsx-no-target-blank.md
'react/jsx-no-target-blank': ['error', { enforceDynamicLinks: 'always' }],
// only .jsx files may have JSX
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md
'react/jsx-filename-extension': ['error', { extensions: ['.js', '.jsx', '.ts', '.tsx'] }],
// prevent accidental JS comments from being injected into JSX as text
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-comment-textnodes.md
'react/jsx-no-comment-textnodes': 'error',
// disallow using React.render/ReactDOM.render's return value
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-render-return-value.md
'react/no-render-return-value': 'error',
// require a shouldComponentUpdate method, or PureRenderMixin
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-optimization.md
'react/require-optimization': ['off', { allowDecorators: [] }],
// warn against using findDOMNode()
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-find-dom-node.md
'react/no-find-dom-node': 'error',
// Forbid certain props on Components
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-component-props.md
'react/forbid-component-props': ['off', { forbid: [] }],
// Forbid certain elements
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-elements.md
'react/forbid-elements': ['off', { forbid: [] }],
// Prevent problem with children and props.dangerouslySetInnerHTML
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger-with-children.md
'react/no-danger-with-children': 'error',
// Prevent unused propType definitions
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unused-prop-types.md
'react/no-unused-prop-types': [
'error',
{
customValidators: [],
skipShapeProps: true,
},
],
// Require style prop value be an object or var
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/style-prop-object.md
'react/style-prop-object': 'error',
// Prevent invalid characters from appearing in markup
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unescaped-entities.md
'react/no-unescaped-entities': 'error',
// Prevent passing of children as props
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-children-prop.md
'react/no-children-prop': 'error',
// Validate whitespace in and around the JSX opening and closing brackets
// https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/jsx-tag-spacing.md
'react/jsx-tag-spacing': [
'error',
{
closingSlash: 'never',
beforeSelfClosing: 'always',
afterOpening: 'never',
beforeClosing: 'never',
},
],
// Enforce spaces before the closing bracket of self-closing JSX elements
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-space-before-closing.md
// Deprecated in favor of jsx-tag-spacing
'react/jsx-space-before-closing': ['off', 'always'],
// Prevent usage of Array index in keys
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-array-index-key.md
'react/no-array-index-key': 'off',
// Enforce a defaultProps definition for every prop that is not a required prop
// https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/require-default-props.md
'react/require-default-props': [
'error',
{
forbidDefaultForRequired: true,
},
],
// Forbids using non-exported propTypes
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-foreign-prop-types.md
// this is intentionally set to "warn". it would be "error",
// but it's only critical if you're stripping propTypes in production.
'react/forbid-foreign-prop-types': ['warn', { allowInPropTypes: true }],
// Prevent void DOM elements from receiving children
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/void-dom-elements-no-children.md
'react/void-dom-elements-no-children': 'error',
// Enforce all defaultProps have a corresponding non-required PropType
// https://github.com/yannickcr/eslint-plugin-react/blob/9e13ae2c51e44872b45cc15bf1ac3a72105bdd0e/docs/rules/default-props-match-prop-types.md
'react/default-props-match-prop-types': ['error', { allowRequiredDefaults: false }],
// Prevent usage of shouldComponentUpdate when extending React.PureComponent
// https://github.com/yannickcr/eslint-plugin-react/blob/9e13ae2c51e44872b45cc15bf1ac3a72105bdd0e/docs/rules/no-redundant-should-component-update.md
'react/no-redundant-should-component-update': 'error',
// Prevent unused state values
// https://github.com/yannickcr/eslint-plugin-react/pull/1103/
'react/no-unused-state': 'error',
// Enforces consistent naming for boolean props
// https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/boolean-prop-naming.md
'react/boolean-prop-naming': [
'off',
{
propTypeNames: ['bool', 'mutuallyExclusiveTrueProps'],
rule: '^(is|has)[A-Z]([A-Za-z0-9]?)+',
message: '',
},
],
// Prevents common casing typos
// https://github.com/yannickcr/eslint-plugin-react/blob/73abadb697034b5ccb514d79fb4689836fe61f91/docs/rules/no-typos.md
'react/no-typos': 'error',
// Enforce curly braces or disallow unnecessary curly braces in JSX props and/or children
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-brace-presence.md
'react/jsx-curly-brace-presence': ['error', { props: 'never', children: 'never' }],
// One JSX Element Per Line
// https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/jsx-one-expression-per-line.md
'react/jsx-one-expression-per-line': ['error', { allow: 'single-child' }],
// Enforce consistent usage of destructuring assignment of props, state, and context
// https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/destructuring-assignment.md
'react/destructuring-assignment': ['error', 'always'],
// Prevent using this.state within a this.setState
// https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/no-access-state-in-setstate.md
'react/no-access-state-in-setstate': 'error',
// Prevent usage of button elements without an explicit type attribute
// https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/button-has-type.md
'react/button-has-type': [
'error',
{
button: true,
submit: true,
reset: false,
},
],
// Ensures inline tags are not rendered without spaces between them
'react/jsx-child-element-spacing': 'off',
// Prevent this from being used in stateless functional components
// https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/no-this-in-sfc.md
'react/no-this-in-sfc': 'error',
// Validate JSX maximum depth
// https://github.com/yannickcr/eslint-plugin-react/blob/abe8381c0d6748047224c430ce47f02e40160ed0/docs/rules/jsx-max-depth.md
'react/jsx-max-depth': 'off',
// Disallow multiple spaces between inline JSX props
// https://github.com/yannickcr/eslint-plugin-react/blob/ac102885765be5ff37847a871f239c6703e1c7cc/docs/rules/jsx-props-no-multi-spaces.md
'react/jsx-props-no-multi-spaces': 'error',
// Prevent usage of UNSAFE_ methods
// https://github.com/yannickcr/eslint-plugin-react/blob/157cc932be2cfaa56b3f5b45df6f6d4322a2f660/docs/rules/no-unsafe.md
'react/no-unsafe': 'off',
// Enforce shorthand or standard form for React fragments
// https://github.com/yannickcr/eslint-plugin-react/blob/bc976b837abeab1dffd90ac6168b746a83fc83cc/docs/rules/jsx-fragments.md
'react/jsx-fragments': ['error', 'element'],
// Enforce linebreaks in curly braces in JSX attributes and expressions.
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-newline.md
'react/jsx-curly-newline': [
'error',
{
multiline: 'consistent',
singleline: 'consistent',
},
],
// Enforce state initialization style
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/state-in-constructor.md
// TODO: set to "never" once babel-preset-airbnb supports public class fields
'react/state-in-constructor': ['error', 'always'],
// Enforces where React component static properties should be positioned
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/static-property-placement.md
// TODO: set to "static public field" once babel-preset-airbnb supports public class fields
'react/static-property-placement': ['error', 'property assignment'],
// Disallow JSX props spreading
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-props-no-spreading.md
'react/jsx-props-no-spreading': 'off',
// Enforce that props are read-only
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-read-only-props.md
'react/prefer-read-only-props': 'off',
},
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.json'],
},
},
react: {
pragma: 'React',
version: 'detect',
},
propWrapperFunctions: [
'forbidExtraProps', // https://www.npmjs.com/package/airbnb-prop-types
'exact', // https://www.npmjs.com/package/prop-types-exact
'Object.freeze', // https://tc39.github.io/ecma262/#sec-object.freeze
],
},
'@eslint-react/dom/no-dangerously-set-innerhtml': 'off',
'@eslint-react/dom/no-dangerously-set-innerhtml-with-children': 'off',
'@eslint-react/no-unsafe-component-will-mount': 'off',
'@eslint-react/no-unsafe-component-will-receive-props': 'off',
'@eslint-react/no-unsafe-component-will-update': 'off',
'@eslint-react/no-set-state-in-component-did-mount': 'off',
'@eslint-react/no-set-state-in-component-did-update': 'off',
'@eslint-react/no-set-state-in-component-will-update': 'off',
'@eslint-react/no-missing-component-display-name': 'off',
'@eslint-react/no-direct-mutation-state': 'off',
'@eslint-react/no-array-index-key': 'off',
'@eslint-react/no-unstable-default-props': 'off', // TODO: Evaluate enabling this
'@eslint-react/no-unstable-context-value': 'off', // TODO: Evaluate enabling this
}
export default index

View File

@@ -2,11 +2,11 @@ import js from '@eslint/js'
import tseslint from 'typescript-eslint'
import perfectionistNatural from 'eslint-plugin-perfectionist/configs/recommended-natural'
import { configs as regexpPluginConfigs } from 'eslint-plugin-regexp'
import eslintConfigPrettier from 'eslint-config-prettier';
import eslintConfigPrettier from 'eslint-config-prettier'
import payloadPlugin from '@payloadcms/eslint-plugin'
import reactExtends from './configs/react/index.mjs'
import jestExtends from './configs/jest/index.mjs'
import globals from 'globals';
import globals from 'globals'
import importX from 'eslint-plugin-import-x'
import typescriptParser from '@typescript-eslint/parser'
import { deepMerge } from './deepMerge.js'
@@ -52,12 +52,7 @@ const baseRules = {
'payload/no-jsx-import-statements': 'error',
}
const reactRules = {
'react/no-unused-prop-types': 'off',
'react/prop-types': 'off',
'react/require-default-props': 'off',
'react/destructuring-assignment': 'warn',
'react/no-unescaped-entities': 'warn',
const reactA11yRules = {
'jsx-a11y/anchor-is-valid': 'warn',
'jsx-a11y/control-has-associated-label': 'warn',
'jsx-a11y/no-static-element-interactions': 'warn',
@@ -107,9 +102,11 @@ const typescriptRules = {
let FlatConfig
/** @type {FlatConfig} */
const baseExtends = deepMerge(js.configs.recommended, perfectionistNatural , regexpPluginConfigs['flat/recommended'])
const baseExtends = deepMerge(
js.configs.recommended,
perfectionistNatural,
regexpPluginConfigs['flat/recommended'],
)
/** @type {FlatConfig[]} */
export const rootEslintConfig = [
@@ -149,7 +146,7 @@ export const rootEslintConfig = [
...baseRules,
...typescriptRules,
},
}
},
),
files: ['**/*.ts'],
},
@@ -169,33 +166,30 @@ export const rootEslintConfig = [
rules: {
...baseRules,
...typescriptRules,
...reactRules,
...reactA11yRules,
},
}
},
),
files: ['**/*.tsx'],
},
{
name: 'Unit Tests',
...deepMerge(
jestExtends,
{
plugins: {
payload: payloadPlugin
},
rules: {
...baseRules,
...typescriptRules,
'@typescript-eslint/unbound-method': 'off',
},
}
),
...deepMerge(jestExtends, {
plugins: {
payload: payloadPlugin,
},
rules: {
...baseRules,
...typescriptRules,
'@typescript-eslint/unbound-method': 'off',
},
}),
files: ['**/*.spec.ts'],
},
{
name: 'Payload Config',
plugins: {
payload: payloadPlugin
payload: payloadPlugin,
},
rules: {
...baseRules,

View File

@@ -17,24 +17,23 @@
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"@eslint/compat": "1.1.0",
"@eslint-react/eslint-plugin": "1.5.25-next.4",
"@eslint/js": "9.6.0",
"@payloadcms/eslint-plugin": "workspace:*",
"@types/eslint": "8.56.10",
"@types/eslint__js": "8.42.3",
"@typescript-eslint/parser": "7.15.0",
"@typescript-eslint/parser": "7.16.0",
"eslint": "9.6.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-import-x": "0.5.3",
"eslint-plugin-import-x": "3.0.0",
"eslint-plugin-jest": "28.6.0",
"eslint-plugin-jest-dom": "5.4.0",
"eslint-plugin-jsx-a11y": "6.9.0",
"eslint-plugin-perfectionist": "2.11.0",
"eslint-plugin-react": "7.34.3",
"eslint-plugin-react-hooks": "5.1.0-rc-f38c22b244-20240704",
"eslint-plugin-react-hooks": "5.1.0-rc-85acf2d195-20240711",
"eslint-plugin-regexp": "2.6.0",
"globals": "15.8.0",
"typescript": "5.5.3",
"typescript-eslint": "7.15.0"
"typescript-eslint": "7.16.0"
}
}

View File

@@ -4,7 +4,6 @@ import noRelativeMonorepoImports from './customRules/no-relative-monorepo-import
import noImportsFromExportsDir from './customRules/no-imports-from-exports-dir.js'
import noFlakyAssertions from './customRules/no-flaky-assertions.js'
/**
* @type {import('eslint').ESLint.Plugin}
*/

View File

@@ -17,23 +17,22 @@
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"@eslint/compat": "1.1.0",
"@eslint-react/eslint-plugin": "1.5.25-next.4",
"@eslint/js": "9.6.0",
"@types/eslint": "8.56.10",
"@types/eslint__js": "8.42.3",
"@typescript-eslint/parser": "7.15.0",
"@typescript-eslint/parser": "7.16.0",
"eslint": "9.6.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-import-x": "0.5.3",
"eslint-plugin-import-x": "3.0.0",
"eslint-plugin-jest": "28.6.0",
"eslint-plugin-jest-dom": "5.4.0",
"eslint-plugin-jsx-a11y": "6.9.0",
"eslint-plugin-perfectionist": "2.11.0",
"eslint-plugin-react": "7.34.3",
"eslint-plugin-react-hooks": "5.1.0-rc-f38c22b244-20240704",
"eslint-plugin-react-hooks": "5.1.0-rc-85acf2d195-20240711",
"eslint-plugin-regexp": "2.6.0",
"globals": "15.8.0",
"typescript": "5.5.3",
"typescript-eslint": "7.15.0"
"typescript-eslint": "7.16.0"
}
}

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-floating-promises */
import type { SanitizedConfig } from 'payload'
import fs from 'fs'

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-param-reassign */
import type { OperationArgs } from 'graphql-http'
import type { GraphQLInfo, SanitizedConfig } from 'payload'

View File

@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-use-before-define */
/* eslint-disable @typescript-eslint/no-unsafe-enum-comparison */
/**
* Created by Ivo Meißner on 28.07.17.

View File

@@ -16,7 +16,6 @@ function ensureObject(value) {
function parseObject(typeName, ast, variables) {
const value = Object.create(null)
ast.fields.forEach((field) => {
// eslint-disable-next-line no-use-before-define
value[field.name.value] = parseLiteral(typeName, field.value, variables)
})

View File

@@ -14,7 +14,6 @@ export type Resolver = (
context: {
req: PayloadRequest
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) => Promise<{ totalDocs: number }>
export function countResolver(collection: Collection): Resolver {

View File

@@ -1,6 +1,3 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
/* eslint-disable no-await-in-loop */
/* eslint-disable no-restricted-syntax */
import type { GraphQLFieldConfig, GraphQLType } from 'graphql'
import type {
ArrayField,

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
import type { Field, FieldAffectingData } from 'payload'
import { GraphQLInputObjectType, GraphQLList } from 'graphql'

View File

@@ -1,6 +1,10 @@
/* eslint-disable no-param-reassign */
import type { GraphQLInfo } from 'payload'
import type { Collection, Field, SanitizedCollectionConfig, SanitizedConfig } from 'payload'
import type {
Collection,
Field,
GraphQLInfo,
SanitizedCollectionConfig,
SanitizedConfig,
} from 'payload'
import {
GraphQLBoolean,

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-param-reassign */
import { GraphQLBoolean, GraphQLInt, GraphQLNonNull, GraphQLString } from 'graphql'
import pluralize from 'pluralize'
const { singular } = pluralize

View File

@@ -45,19 +45,19 @@ const GeoJSONObject = new GraphQLInputObjectType({
})
type DefaultsType = {
[key in staticTypes]: {
operators: {
name: string
type: ((field: FieldAffectingData, parentName: string) => GraphQLType) | GraphQLType
}[]
}
} & {
[key in dynamicTypes]: {
operators: {
name: string
type: (field: FieldAffectingData, parentName: string) => GraphQLType
}[]
}
} & {
[key in staticTypes]: {
operators: {
name: string
type: ((field: FieldAffectingData, parentName: string) => GraphQLType) | GraphQLType
}[]
}
}
const defaults: DefaultsType = {

View File

@@ -1,4 +1,3 @@
/* eslint-disable indent */
/* eslint-disable jest/prefer-strict-equal */
import formatName from './formatName'

View File

@@ -34,9 +34,9 @@ export const mergeData = async <T>(args: {
returnNumberOfRequests?: boolean
serverURL: string
}): Promise<
T & {
{
_numberOfRequests?: number
}
} & T
> => {
const {
apiRoute,

View File

@@ -7,7 +7,7 @@ import './index.scss'
export const baseClass = 'doc-tab'
export const DocumentTab: React.FC<DocumentTabProps & DocumentTabConfig> = (props) => {
export const DocumentTab: React.FC<DocumentTabConfig & DocumentTabProps> = (props) => {
const {
Pill,
apiURL,

View File

@@ -16,9 +16,9 @@ export type DocumentViewKey = (typeof documentViewKeys)[number]
export const tabs: Record<
DocumentViewKey,
DocumentTabConfig & {
{
order?: number // TODO: expose this to the globalConfig config
}
} & DocumentTabConfig
> = {
API: {
condition: ({ collectionConfig, globalConfig }) =>

View File

@@ -109,7 +109,6 @@ export const RootLayout = async ({
fallbackLang={clientConfig.i18n.fallbackLanguage}
languageCode={languageCode}
languageOptions={languageOptions}
// eslint-disable-next-line react/jsx-no-bind
switchLanguageServerAction={switchLanguageServerAction}
theme={theme}
translations={i18n.translations}

View File

@@ -50,7 +50,6 @@ const handleError = async (
let cached = global._payload_graphql
if (!cached) {
// eslint-disable-next-line no-multi-assign
cached = global._payload_graphql = { graphql: null, promise: null }
}

View File

@@ -11,11 +11,11 @@ import './index.scss'
const baseClass = 'template-default'
export type DefaultTemplateProps = ServerProps & {
export type DefaultTemplateProps = {
children?: React.ReactNode
className?: string
visibleEntities: VisibleEntities
}
} & ServerProps
export const DefaultTemplate: React.FC<DefaultTemplateProps> = ({
children,

View File

@@ -10,7 +10,6 @@ let cached: {
} = global._payload
if (!cached) {
// eslint-disable-next-line no-multi-assign
cached = global._payload = { payload: null, promise: null, reload: false }
}

View File

@@ -12,7 +12,7 @@ const defaultOpenGraph = {
title: 'Payload App',
}
export const meta = async (args: MetaConfig & { serverURL: string }): Promise<any> => {
export const meta = async (args: { serverURL: string } & MetaConfig): Promise<any> => {
const {
defaultOGImageType,
description,

View File

@@ -10,12 +10,12 @@ import './index.scss'
const baseClass = 'dashboard'
export type DashboardProps = ServerProps & {
export type DashboardProps = {
Link: React.ComponentType<any>
navGroups?: ReturnType<typeof groupNavItems>
permissions: Permissions
visibleEntities: VisibleEntities
}
} & ServerProps
export const DefaultDashboard: React.FC<DashboardProps> = (props) => {
const {

View File

@@ -12,10 +12,10 @@ import { generateMetadata as versionMeta } from '../Version/meta.js'
import { generateMetadata as versionsMeta } from '../Versions/meta.js'
export type GenerateEditViewMetadata = (
args: Parameters<GenerateViewMetadata>[0] & {
args: {
collectionConfig?: SanitizedCollectionConfig | null
globalConfig?: SanitizedGlobalConfig | null
},
} & Parameters<GenerateViewMetadata>[0],
) => Promise<Metadata>
export const getMetaBySegment: GenerateEditViewMetadata = async ({

View File

@@ -28,7 +28,7 @@ export const getViewsFromConfig = ({
}: {
collectionConfig?: SanitizedCollectionConfig
config: SanitizedConfig
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
docPermissions: CollectionPermission | GlobalPermission
globalConfig?: SanitizedGlobalConfig
routeSegments: string[]

View File

@@ -8,9 +8,9 @@ import type { GenerateViewMetadata } from '../Root/index.js'
import { meta } from '../../utilities/meta.js'
export const generateListMetadata = async (
args: Parameters<GenerateViewMetadata>[0] & {
args: {
collectionConfig: SanitizedCollectionConfig
},
} & Parameters<GenerateViewMetadata>[0],
): Promise<Metadata> => {
const { collectionConfig, config, i18n } = args

View File

@@ -56,9 +56,9 @@ const StaticToolbar: React.FC<EditViewProps> = (props) => {
}
export const LivePreviewToolbar: React.FC<
EditViewProps & {
{
draggable?: boolean
}
} & EditViewProps
> = (props) => {
const { draggable } = props

View File

@@ -14,7 +14,7 @@ export interface PopupMessage {
export const usePopupWindow = (props: {
eventType?: string
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onMessage?: (searchParams: PopupMessage['searchParams']) => Promise<void>
url: string
}): {

View File

@@ -10,9 +10,9 @@ const baseClass = 'logout'
export { generateLogoutMetadata } from './meta.js'
export const LogoutView: React.FC<
AdminViewProps & {
{
inactivity?: boolean
}
} & AdminViewProps
> = ({ inactivity, initPageResult, searchParams }) => {
const {
req: {

View File

@@ -15,7 +15,6 @@ export const generatePageMetadata = async ({
}: {
config: Promise<SanitizedConfig> | SanitizedConfig
params?: { [key: string]: string | string[] }
//eslint-disable-next-line @typescript-eslint/require-await
}): Promise<Metadata> => {
const config = await configPromise

View File

@@ -47,9 +47,9 @@ const getTranslatedOptions = (
}
const Select: React.FC<
Omit<Props, 'field'> & {
{
field: MappedField & SelectFieldProps
}
} & Omit<Props, 'field'>
> = ({ comparison, diffMethod, field, i18n, locale, version }) => {
let placeholder = ''

View File

@@ -10,9 +10,9 @@ import Nested from '../Nested/index.js'
const baseClass = 'tabs-diff'
const Tabs: React.FC<
Omit<Props, 'field'> & {
{
field: MappedField & TabsFieldProps
}
} & Omit<Props, 'field'>
> = ({ comparison, diffComponents, field, i18n, locale, locales, permissions, version }) => {
return (
<div className={baseClass}>

View File

@@ -15,8 +15,8 @@ export type Props = {
version: Record<string, any>
}
export type FieldDiffProps = Props & {
export type FieldDiffProps = {
diffMethod: DiffMethod
field: MappedField
isRichText: boolean
}
} & Props

View File

@@ -9,13 +9,9 @@ import type { SanitizedGlobalConfig } from '../globals/config/types.js'
import type { PayloadRequest, RequestContext } from '../types/index.js'
import type { WithServerSidePropsComponentProps } from './elements/WithServerSideProps.js'
export type RichTextFieldProps<
Value extends object,
AdapterProps,
ExtraFieldProperties = {},
> = Omit<RichTextField<Value, AdapterProps, ExtraFieldProperties>, 'type'> & {
export type RichTextFieldProps<Value extends object, AdapterProps, ExtraFieldProperties = {}> = {
path?: string
}
} & Omit<RichTextField<Value, AdapterProps, ExtraFieldProperties>, 'type'>
export type AfterReadRichTextHookArgs<
TData extends TypeWithID = any,
@@ -146,8 +142,8 @@ export type AfterReadRichTextHook<
TValue = any,
TSiblingData = any,
> = (
args: BaseRichTextHookArgs<TData, TValue, TSiblingData> &
AfterReadRichTextHookArgs<TData, TValue, TSiblingData>,
args: AfterReadRichTextHookArgs<TData, TValue, TSiblingData> &
BaseRichTextHookArgs<TData, TValue, TSiblingData>,
) => Promise<TValue> | TValue
export type AfterChangeRichTextHook<
@@ -155,8 +151,8 @@ export type AfterChangeRichTextHook<
TValue = any,
TSiblingData = any,
> = (
args: BaseRichTextHookArgs<TData, TValue, TSiblingData> &
AfterChangeRichTextHookArgs<TData, TValue, TSiblingData>,
args: AfterChangeRichTextHookArgs<TData, TValue, TSiblingData> &
BaseRichTextHookArgs<TData, TValue, TSiblingData>,
) => Promise<TValue> | TValue
export type BeforeChangeRichTextHook<
@@ -252,10 +248,10 @@ export type RichTextAdapter<
Value extends object = object,
AdapterProps = any,
ExtraFieldProperties = {},
> = RichTextAdapterBase<Value, AdapterProps, ExtraFieldProperties> & {
> = {
CellComponent: React.FC<any>
FieldComponent: React.FC<RichTextFieldProps<Value, AdapterProps, ExtraFieldProperties>>
}
} & RichTextAdapterBase<Value, AdapterProps, ExtraFieldProperties>
export type RichTextAdapterProvider<
Value extends object = object,

View File

@@ -35,11 +35,11 @@ export type CellComponentProps = {
schemaPath: string
}
export type DefaultCellComponentProps<T = any> = CellComponentProps & {
export type DefaultCellComponentProps<T = any> = {
cellData: T
customCellContext?: {
collectionSlug?: SanitizedCollectionConfig['slug']
uploadConfig?: SanitizedCollectionConfig['upload']
}
rowData: RowData
}
} & CellComponentProps

View File

@@ -25,23 +25,23 @@ export type MonthPickerProps = {
}
export type ConditionalDateProps =
| (SharedProps &
DayPickerProps &
TimePickerProps & {
pickerAppearance?: 'dayAndTime'
})
| (SharedProps &
DayPickerProps & {
pickerAppearance: 'dayOnly'
})
| (SharedProps &
MonthPickerProps & {
pickerAppearance: 'monthOnly'
})
| (SharedProps &
TimePickerProps & {
pickerAppearance: 'timeOnly'
})
| (SharedProps & {
| ({
pickerAppearance: 'dayOnly'
} & DayPickerProps &
SharedProps)
| ({
pickerAppearance: 'monthOnly'
} & MonthPickerProps &
SharedProps)
| ({
pickerAppearance: 'timeOnly'
} & SharedProps &
TimePickerProps)
| ({
pickerAppearance?: 'dayAndTime'
} & DayPickerProps &
SharedProps &
TimePickerProps)
| ({
pickerAppearance?: 'default'
})
} & SharedProps)

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-param-reassign */
import type { CollectionConfig } from '../collections/config/types.js'
import type { Field, TabAsField } from '../fields/config/types.js'
import type { PayloadRequest } from '../types/index.js'

View File

@@ -1,4 +1,4 @@
export * from './types.js'
export * from './cookies.js'
export { extractJWT } from './extractJWT.js'
export * from './cookies.js'
export * from './types.js'

View File

@@ -27,7 +27,7 @@ export type Options<TSlug extends CollectionSlug> = {
async function localLogin<TSlug extends CollectionSlug>(
payload: Payload,
options: Options<TSlug>,
): Promise<Result & { user: DataFromCollectionSlug<TSlug> }> {
): Promise<{ user: DataFromCollectionSlug<TSlug> } & Result> {
const {
collection: collectionSlug,
data,

View File

@@ -39,7 +39,7 @@ export type Arguments<TSlug extends CollectionSlug> = {
export const loginOperation = async <TSlug extends CollectionSlug>(
incomingArgs: Arguments<TSlug>,
): Promise<Result & { user: DataFromCollectionSlug<TSlug> }> => {
): Promise<{ user: DataFromCollectionSlug<TSlug> } & Result> => {
let args = incomingArgs
try {
@@ -253,7 +253,7 @@ export const loginOperation = async <TSlug extends CollectionSlug>(
})) || user
}, Promise.resolve())
let result: Result & { user: DataFromCollectionSlug<TSlug> } = {
let result: { user: DataFromCollectionSlug<TSlug> } & Result = {
exp: (jwt.decode(token) as jwt.JwtPayload).exp,
token,
user,

View File

@@ -14,8 +14,8 @@ import { killTransaction } from '../../utilities/killTransaction.js'
export type Arguments<TSlug extends CollectionSlug> = {
collection: Collection
data: RequiredDataFromCollectionSlug<TSlug> &
AuthOperationsFromCollectionSlug<TSlug>['registerFirstUser']
data: AuthOperationsFromCollectionSlug<TSlug>['registerFirstUser'] &
RequiredDataFromCollectionSlug<TSlug>
req: PayloadRequest
}

View File

@@ -16,7 +16,7 @@ export const JWTAuthentication: AuthStrategyFunction = async ({
}) => {
try {
const token = extractJWT({ headers, payload })
const decodedPayload = jwt.verify(token, payload.secret) as jwt.JwtPayload & JWTToken
const decodedPayload = jwt.verify(token, payload.secret) as JWTToken & jwt.JwtPayload
const collection = payload.collections[decodedPayload.collection]

View File

@@ -3,7 +3,7 @@ import scmp from 'scmp'
import type { TypeWithID } from '../../../collections/config/types.js'
type Doc = TypeWithID & Record<string, unknown>
type Doc = Record<string, unknown> & TypeWithID
type Args = {
doc: Doc

View File

@@ -4,7 +4,7 @@ import type { PayloadRequest } from '../../../types/index.js'
type Args = {
collection: SanitizedCollectionConfig
doc: TypeWithID & Record<string, unknown>
doc: Record<string, unknown> & TypeWithID
payload: Payload
req: PayloadRequest
}

View File

@@ -4,7 +4,7 @@ import type { PayloadRequest } from '../../../types/index.js'
type Args = {
collection: SanitizedCollectionConfig
doc: TypeWithID & Record<string, unknown>
doc: Record<string, unknown> & TypeWithID
payload: Payload
req: PayloadRequest
}

View File

@@ -26,7 +26,7 @@ const injectInlineSourceMap = ({
export async function compile(
sourcecode: string,
filename: string,
options: ts.CompilerOptions & { fallbackToTs?: (filename: string) => boolean },
options: { fallbackToTs?: (filename: string) => boolean } & ts.CompilerOptions,
): Promise<string> {
if (filename.endsWith('.d.ts')) {
return ''

View File

@@ -10,18 +10,15 @@ export type ServerOnlyCollectionAdminProperties = keyof Pick<
'components' | 'hidden' | 'preview'
>
export type ClientCollectionConfig = Omit<
SanitizedCollectionConfig,
'admin' | 'fields' | ServerOnlyCollectionProperties
> & {
admin: Omit<
export type ClientCollectionConfig = {
admin: {
livePreview?: Omit<LivePreviewConfig, ServerOnlyLivePreviewProperties>
} & Omit<
SanitizedCollectionConfig['admin'],
'fields' | 'livePreview' | ServerOnlyCollectionAdminProperties
> & {
livePreview?: Omit<LivePreviewConfig, ServerOnlyLivePreviewProperties>
}
>
fields: ClientFieldConfig[]
}
} & Omit<SanitizedCollectionConfig, 'admin' | 'fields' | ServerOnlyCollectionProperties>
import type { TFunction } from '@payloadcms/translations'

View File

@@ -111,7 +111,6 @@ export const deleteOperation = async <TSlug extends CollectionSlug>(
const errors = []
/* eslint-disable no-param-reassign */
const promises = docs.map(async (doc) => {
let result

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-underscore-dangle */
import type { FindOneArgs } from '../../database/types.js'
import type { CollectionSlug } from '../../index.js'
import type { PayloadRequest } from '../../types/index.js'

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-underscore-dangle */
import httpStatus from 'http-status'
import type { PayloadRequest } from '../../types/index.js'

View File

@@ -22,15 +22,15 @@ export type BaseOptions<TSlug extends CollectionSlug> = {
user?: Document
}
export type ByIDOptions<TSlug extends CollectionSlug> = BaseOptions<TSlug> & {
export type ByIDOptions<TSlug extends CollectionSlug> = {
id: number | string
where?: never
}
} & BaseOptions<TSlug>
export type ManyOptions<TSlug extends CollectionSlug> = BaseOptions<TSlug> & {
export type ManyOptions<TSlug extends CollectionSlug> = {
id?: never
where: Where
}
} & BaseOptions<TSlug>
export type Options<TSlug extends CollectionSlug> = ByIDOptions<TSlug> | ManyOptions<TSlug>

View File

@@ -36,15 +36,15 @@ export type BaseOptions<TSlug extends CollectionSlug> = {
user?: Document
}
export type ByIDOptions<TSlug extends CollectionSlug> = BaseOptions<TSlug> & {
export type ByIDOptions<TSlug extends CollectionSlug> = {
id: number | string
where?: never
}
} & BaseOptions<TSlug>
export type ManyOptions<TSlug extends CollectionSlug> = BaseOptions<TSlug> & {
export type ManyOptions<TSlug extends CollectionSlug> = {
id?: never
where: Where
}
} & BaseOptions<TSlug>
export type Options<TSlug extends CollectionSlug> = ByIDOptions<TSlug> | ManyOptions<TSlug>

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-underscore-dangle */
import httpStatus from 'http-status'
import type { FindOneArgs } from '../../database/types.js'

View File

@@ -98,7 +98,7 @@ export const buildAfterOperation = async <
TOperationGeneric extends CollectionSlug,
O extends keyof AfterOperationMap<TOperationGeneric> = keyof AfterOperationMap<TOperationGeneric>,
>(
operationArgs: Omit<AfterOperationArg<TOperationGeneric>, 'req'> & { operation: O },
operationArgs: { operation: O } & Omit<AfterOperationArg<TOperationGeneric>, 'req'>,
): Promise<OperationResult<TOperationGeneric, O> | any> => {
const { args, collection, operation, result } = operationArgs

View File

@@ -34,17 +34,14 @@ export type ServerOnlyRootProperties = keyof Pick<
export type ServerOnlyRootAdminProperties = keyof Pick<SanitizedConfig['admin'], 'components'>
export type ClientConfig = Omit<
SanitizedConfig,
'admin' | 'collections' | 'globals' | ServerOnlyRootProperties
> & {
admin: Omit<SanitizedConfig['admin'], ServerOnlyRootAdminProperties & 'livePreview'> & {
export type ClientConfig = {
admin: {
livePreview?: Omit<LivePreviewConfig, ServerOnlyLivePreviewProperties>
}
} & Omit<SanitizedConfig['admin'], 'livePreview' & ServerOnlyRootAdminProperties>
collections: ClientCollectionConfig[]
custom?: Record<string, any>
globals: ClientGlobalConfig[]
}
} & Omit<SanitizedConfig, 'admin' | 'collections' | 'globals' | ServerOnlyRootProperties>
export const createClientConfig = async ({
config,

View File

@@ -73,7 +73,6 @@ export const findConfig = (): string => {
? [configPath, outPath, srcPath, rootPath]
: [configPath, srcPath, rootPath]
// eslint-disable-next-line no-restricted-syntax
for (const searchPath of searchPaths) {
if (!searchPath) continue

View File

@@ -41,7 +41,6 @@ type Prettify<T> = {
[K in keyof T]: T[K]
} & NonNullable<unknown>
// eslint-disable-next-line no-use-before-define
export type Plugin = (config: Config) => Config | Promise<Config>
export type LivePreviewConfig = {
@@ -347,7 +346,7 @@ export const serverProps: (keyof ServerProps)[] = [
]
export type CustomComponent<TAdditionalProps extends any = any> = React.ComponentType<
TAdditionalProps & Partial<ServerProps>
Partial<ServerProps> & TAdditionalProps
>
export type Locale = {
@@ -382,17 +381,17 @@ export type BaseLocalizationConfig = {
}
export type LocalizationConfigWithNoLabels = Prettify<
BaseLocalizationConfig & {
{
/**
* List of supported locales
* @example `["en", "es", "fr", "nl", "de", "jp"]`
*/
locales: string[]
}
} & BaseLocalizationConfig
>
export type LocalizationConfigWithLabels = Prettify<
BaseLocalizationConfig & {
{
/**
* List of supported locales with labels
* @example {
@@ -402,17 +401,17 @@ export type LocalizationConfigWithLabels = Prettify<
* }
*/
locales: Locale[]
}
} & BaseLocalizationConfig
>
export type SanitizedLocalizationConfig = Prettify<
LocalizationConfigWithLabels & {
{
/**
* List of supported locales
* @example `["en", "es", "fr", "nl", "de", "jp"]`
*/
localeCodes: string[]
}
} & LocalizationConfigWithLabels
>
/**
@@ -547,10 +546,10 @@ export type Config = {
dateFormat?: string
/** If set to true, the entire Admin panel will be disabled. */
disable?: boolean
livePreview?: LivePreviewConfig & {
livePreview?: {
collections?: string[]
globals?: string[]
}
} & LivePreviewConfig
/** Base meta data to use for the Admin Panel. Included properties are titleSuffix, ogImage, and favicon. */
meta?: MetaConfig
routes?: {
@@ -758,10 +757,7 @@ export type Config = {
upload?: ExpressFileUploadOptions
}
export type SanitizedConfig = Omit<
DeepRequired<Config>,
'collections' | 'editor' | 'endpoint' | 'globals' | 'i18n' | 'localization' | 'upload'
> & {
export type SanitizedConfig = {
collections: SanitizedCollectionConfig[]
/** Default richtext editor to use for richText fields */
editor?: RichTextAdapter<any, any, any>
@@ -774,13 +770,16 @@ export type SanitizedConfig = Omit<
configDir: string
rawConfig: string
}
upload: ExpressFileUploadOptions & {
upload: {
/**
* Deduped list of adapters used in the project
*/
adapters: string[]
}
}
} & ExpressFileUploadOptions
} & Omit<
DeepRequired<Config>,
'collections' | 'editor' | 'endpoint' | 'globals' | 'i18n' | 'localization' | 'upload'
>
export type EditConfig =
| (

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-param-reassign */
import type { MarkOptional } from 'ts-essentials'
import type {

View File

@@ -129,7 +129,6 @@ export async function getLocalizedPaths({
if (nestedPathToQuery) {
const relatedCollection = payload.collections[matchedField.relationTo].config
// eslint-disable-next-line no-await-in-loop
const remainingPaths = await getLocalizedPaths({
collectionSlug: relatedCollection.slug,
fields: relatedCollection.fields,

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-restricted-syntax, no-await-in-loop */
import fs from 'fs'
import type { CreateMigration } from '../types.js'

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-restricted-syntax, no-await-in-loop */
import type { PayloadRequest } from '../../types/index.js'
import type { BaseDatabaseAdapter } from '../types.js'
@@ -23,7 +22,7 @@ export async function migrate(this: BaseDatabaseAdapter): Promise<void> {
// Run migration if not found in database
if (existingMigration) {
continue // eslint-disable-line no-continue
continue
}
const start = Date.now()

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-restricted-syntax, no-await-in-loop */
import type { PayloadRequest } from '../../types/index.js'
import type { BaseDatabaseAdapter } from '../types.js'

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-restricted-syntax, no-await-in-loop */
import type { PayloadRequest } from '../../types/index.js'
import type { BaseDatabaseAdapter } from '../types.js'

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-restricted-syntax, no-await-in-loop */
import type { PayloadRequest } from '../../types/index.js'
import type { BaseDatabaseAdapter } from '../types.js'

View File

@@ -25,7 +25,7 @@ export async function migrateStatus(this: BaseDatabaseAdapter): Promise<void> {
const existingMigration = existingMigrations.find((m) => m.name === migration.name)
return {
Name: migration.name,
// eslint-disable-next-line perfectionist/sort-objects
Batch: existingMigration?.batch,
Ran: existingMigration ? 'Yes' : 'No',
}

View File

@@ -1,8 +1,6 @@
/* eslint-disable no-restricted-syntax */
import type { SanitizedCollectionConfig } from '../../collections/config/types.js'
import type { Field, FieldAffectingData } from '../../fields/config/types.js'
import type { SanitizedGlobalConfig } from '../../globals/config/types.js'
/* eslint-disable no-await-in-loop */
import type { Operator, PayloadRequest, Where, WhereField } from '../../types/index.js'
import type { EntityPolicies } from './types.js'

View File

@@ -51,10 +51,8 @@ export async function validateSearchParam({
const { slug } = collectionConfig || globalConfig
if (globalConfig && !policies.globals[slug]) {
// eslint-disable-next-line no-param-reassign
globalConfig.fields = fields
// eslint-disable-next-line no-param-reassign
policies.globals[slug] = await getEntityPolicies({
type: 'global',
entity: globalConfig,
@@ -85,7 +83,6 @@ export async function validateSearchParam({
if (!overrideAccess && fieldAffectsData(field)) {
if (collectionSlug) {
if (!policies.collections[collectionSlug]) {
// eslint-disable-next-line no-param-reassign
policies.collections[collectionSlug] = await getEntityPolicies({
type: 'collection',
entity: req.payload.collections[collectionSlug].config,

View File

@@ -222,17 +222,17 @@ type BaseVersionArgs = {
where?: Where
}
export type FindVersionsArgs = BaseVersionArgs & {
export type FindVersionsArgs = {
collection: string
}
} & BaseVersionArgs
export type FindVersions = <T = TypeWithID>(
args: FindVersionsArgs,
) => Promise<PaginatedDocs<TypeWithVersion<T>>>
export type FindGlobalVersionsArgs = BaseVersionArgs & {
export type FindGlobalVersionsArgs = {
global: string
}
} & BaseVersionArgs
export type FindGlobalArgs = {
locale?: string
@@ -395,10 +395,10 @@ export type DeleteManyArgs = {
export type DeleteMany = (args: DeleteManyArgs) => Promise<void>
export type Migration = MigrationData & {
export type Migration = {
down: ({ payload, req }: { payload: Payload; req: PayloadRequest }) => Promise<boolean>
up: ({ payload, req }: { payload: Payload; req: PayloadRequest }) => Promise<boolean>
}
} & MigrationData
export type MigrationData = {
batch?: number

View File

@@ -1,4 +1,3 @@
/* eslint-disable max-classes-per-file */
import httpStatus from 'http-status'
class ExtendableError<TData extends object = { [key: string]: unknown }> extends Error {

View File

@@ -1,7 +1,5 @@
export * from '../fields/validations.js'
export { defaults as collectionDefaults } from '../collections/config/defaults.js'
export { serverProps } from '../config/types.js'
export {
fieldAffectsData,
fieldHasMaxDepth,
@@ -19,6 +17,8 @@ export {
valueIsValueWithRelation,
} from '../fields/config/types.js'
export * from '../fields/validations.js'
export { validOperators } from '../types/constants.js'
export { formatFilesize } from '../uploads/formatFilesize.js'

View File

@@ -1,6 +1,4 @@
import { Config } from '../../config/types.js'
import { InvalidFieldName, InvalidFieldRelationship, MissingFieldType } from '../../errors/index.js'
import { sanitizeFields } from './sanitize.js'
import type { Config } from '../../config/types.js'
import type {
ArrayField,
Block,
@@ -11,14 +9,17 @@ import type {
TextField,
} from './types.js'
import { InvalidFieldName, InvalidFieldRelationship, MissingFieldType } from '../../errors/index.js'
import { sanitizeFields } from './sanitize.js'
describe('sanitizeFields', () => {
const config = {} as Config
it('should throw on missing type field', async () => {
const fields: Field[] = [
// @ts-expect-error
{
label: 'some-collection',
name: 'Some Collection',
label: 'some-collection',
},
]
await expect(async () => {
@@ -32,9 +33,9 @@ describe('sanitizeFields', () => {
it('should throw on invalid field name', async () => {
const fields: Field[] = [
{
label: 'some.collection',
name: 'some.collection',
type: 'text',
label: 'some.collection',
},
]
await expect(async () => {
@@ -68,9 +69,9 @@ describe('sanitizeFields', () => {
it('should allow auto-label override', async () => {
const fields: Field[] = [
{
label: 'Do not label',
name: 'someField',
type: 'text',
label: 'Do not label',
},
]
const sanitizedField = (
@@ -89,9 +90,9 @@ describe('sanitizeFields', () => {
it('should allow label opt-out', async () => {
const fields: Field[] = [
{
label: false,
name: 'someField',
type: 'text',
label: false,
},
]
const sanitizedField = (
@@ -108,6 +109,8 @@ describe('sanitizeFields', () => {
it('should allow label opt-out for arrays', async () => {
const arrayField: ArrayField = {
name: 'items',
type: 'array',
fields: [
{
name: 'itemName',
@@ -115,8 +118,6 @@ describe('sanitizeFields', () => {
},
],
label: false,
name: 'items',
type: 'array',
}
const sanitizedField = (
await sanitizeFields({
@@ -133,20 +134,20 @@ describe('sanitizeFields', () => {
it('should allow label opt-out for blocks', async () => {
const fields: Field[] = [
{
name: 'noLabelBlock',
type: 'blocks',
blocks: [
{
slug: 'number',
fields: [
{
name: 'testNumber',
type: 'number',
},
],
slug: 'number',
},
],
label: false,
name: 'noLabelBlock',
type: 'blocks',
},
]
const sanitizedField = (
@@ -166,14 +167,14 @@ describe('sanitizeFields', () => {
it('should label arrays with plural and singular', async () => {
const fields: Field[] = [
{
name: 'items',
type: 'array',
fields: [
{
name: 'itemName',
type: 'text',
},
],
name: 'items',
type: 'array',
},
]
const sanitizedField = (
@@ -192,14 +193,14 @@ describe('sanitizeFields', () => {
it('should label blocks with plural and singular', async () => {
const fields: Field[] = [
{
blocks: [
{
fields: [{ name: 'testNumber', type: 'number' }],
slug: 'number',
},
],
name: 'specialBlock',
type: 'blocks',
blocks: [
{
slug: 'number',
fields: [{ name: 'testNumber', type: 'number' }],
},
],
},
]
const sanitizedField = (
@@ -225,10 +226,10 @@ describe('sanitizeFields', () => {
const validRelationships = ['some-collection']
const fields: Field[] = [
{
label: 'my-relationship',
name: 'My Relationship',
relationTo: 'some-collection',
type: 'relationship',
label: 'my-relationship',
relationTo: 'some-collection',
},
]
await expect(async () => {
@@ -240,10 +241,10 @@ describe('sanitizeFields', () => {
const validRelationships = ['some-collection', 'another-collection']
const fields: Field[] = [
{
label: 'my-relationship',
name: 'My Relationship',
relationTo: ['some-collection', 'another-collection'],
type: 'relationship',
label: 'my-relationship',
relationTo: ['some-collection', 'another-collection'],
},
]
await expect(async () => {
@@ -254,22 +255,22 @@ describe('sanitizeFields', () => {
it('should not throw on valid relationship inside blocks', async () => {
const validRelationships = ['some-collection']
const relationshipBlock: Block = {
slug: 'relationshipBlock',
fields: [
{
label: 'my-relationship',
name: 'My Relationship',
relationTo: 'some-collection',
type: 'relationship',
label: 'my-relationship',
relationTo: 'some-collection',
},
],
slug: 'relationshipBlock',
}
const fields: Field[] = [
{
blocks: [relationshipBlock],
label: 'Layout Blocks',
name: 'layout',
type: 'blocks',
blocks: [relationshipBlock],
label: 'Layout Blocks',
},
]
await expect(async () => {
@@ -281,10 +282,10 @@ describe('sanitizeFields', () => {
const validRelationships = ['some-collection']
const fields: Field[] = [
{
label: 'my-relationship',
name: 'My Relationship',
relationTo: 'not-valid',
type: 'relationship',
label: 'my-relationship',
relationTo: 'not-valid',
},
]
await expect(async () => {
@@ -296,10 +297,10 @@ describe('sanitizeFields', () => {
const validRelationships = ['some-collection', 'another-collection']
const fields: Field[] = [
{
label: 'my-relationship',
name: 'My Relationship',
relationTo: ['some-collection', 'not-valid'],
type: 'relationship',
label: 'my-relationship',
relationTo: ['some-collection', 'not-valid'],
},
]
await expect(async () => {
@@ -310,22 +311,22 @@ describe('sanitizeFields', () => {
it('should throw on invalid relationship inside blocks', async () => {
const validRelationships = ['some-collection']
const relationshipBlock: Block = {
slug: 'relationshipBlock',
fields: [
{
label: 'my-relationship',
name: 'My Relationship',
relationTo: 'not-valid',
type: 'relationship',
label: 'my-relationship',
relationTo: 'not-valid',
},
],
slug: 'relationshipBlock',
}
const fields: Field[] = [
{
blocks: [relationshipBlock],
label: 'Layout Blocks',
name: 'layout',
type: 'blocks',
blocks: [relationshipBlock],
label: 'Layout Blocks',
},
]
await expect(async () => {
@@ -337,8 +338,8 @@ describe('sanitizeFields', () => {
const fields: Field[] = [
{
name: 'My Checkbox',
required: true,
type: 'checkbox',
required: true,
},
]

View File

@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable no-use-before-define */
import type { EditorProps } from '@monaco-editor/react'
import type { CSSProperties } from 'react'
@@ -241,8 +241,8 @@ export interface FieldBase {
validate?: Validate
}
export type NumberField = FieldBase & {
admin?: Admin & {
export type NumberField = {
admin?: {
/** Set this property to a string that will be used for browser autocomplete. */
autoComplete?: string
components?: {
@@ -255,33 +255,34 @@ export type NumberField = FieldBase & {
placeholder?: Record<string, string> | string
/** Set a value for the number field to increment / decrement using browser controls. */
step?: number
}
} & Admin
/** Maximum value accepted. Used in the default `validation` function. */
max?: number
/** Minimum value accepted. Used in the default `validation` function. */
min?: number
type: 'number'
} & (
| {
/** Makes this field an ordered array of numbers instead of just a single number. */
hasMany: true
/** Maximum number of numbers in the numbers array, if `hasMany` is set to true. */
maxRows?: number
/** Minimum number of numbers in the numbers array, if `hasMany` is set to true. */
minRows?: number
}
| {
/** Makes this field an ordered array of numbers instead of just a single number. */
hasMany?: false | undefined
/** Maximum number of numbers in the numbers array, if `hasMany` is set to true. */
maxRows?: undefined
/** Minimum number of numbers in the numbers array, if `hasMany` is set to true. */
minRows?: undefined
}
)
| {
/** Makes this field an ordered array of numbers instead of just a single number. */
hasMany: true
/** Maximum number of numbers in the numbers array, if `hasMany` is set to true. */
maxRows?: number
/** Minimum number of numbers in the numbers array, if `hasMany` is set to true. */
minRows?: number
}
| {
/** Makes this field an ordered array of numbers instead of just a single number. */
hasMany?: false | undefined
/** Maximum number of numbers in the numbers array, if `hasMany` is set to true. */
maxRows?: undefined
/** Minimum number of numbers in the numbers array, if `hasMany` is set to true. */
minRows?: undefined
}
) &
FieldBase
export type TextField = FieldBase & {
admin?: Admin & {
export type TextField = {
admin?: {
autoComplete?: string
components?: {
Error?: CustomComponent<ErrorProps>
@@ -291,31 +292,32 @@ export type TextField = FieldBase & {
}
placeholder?: Record<string, string> | string
rtl?: boolean
}
} & Admin
maxLength?: number
minLength?: number
type: 'text'
} & (
| {
/** Makes this field an ordered array of strings instead of just a single string. */
hasMany: true
/** Maximum number of strings in the strings array, if `hasMany` is set to true. */
maxRows?: number
/** Minimum number of strings in the strings array, if `hasMany` is set to true. */
minRows?: number
}
| {
/** Makes this field an ordered array of strings instead of just a single string. */
hasMany?: false | undefined
/** Maximum number of strings in the strings array, if `hasMany` is set to true. */
maxRows?: undefined
/** Minimum number of strings in the strings array, if `hasMany` is set to true. */
minRows?: undefined
}
)
| {
/** Makes this field an ordered array of strings instead of just a single string. */
hasMany: true
/** Maximum number of strings in the strings array, if `hasMany` is set to true. */
maxRows?: number
/** Minimum number of strings in the strings array, if `hasMany` is set to true. */
minRows?: number
}
| {
/** Makes this field an ordered array of strings instead of just a single string. */
hasMany?: false | undefined
/** Maximum number of strings in the strings array, if `hasMany` is set to true. */
maxRows?: undefined
/** Minimum number of strings in the strings array, if `hasMany` is set to true. */
minRows?: undefined
}
) &
FieldBase
export type EmailField = FieldBase & {
admin?: Admin & {
export type EmailField = {
admin?: {
autoComplete?: string
components?: {
Error?: CustomComponent<ErrorProps>
@@ -324,12 +326,12 @@ export type EmailField = FieldBase & {
beforeInput?: CustomComponent[]
}
placeholder?: Record<string, string> | string
}
} & Admin
type: 'email'
}
} & FieldBase
export type TextareaField = FieldBase & {
admin?: Admin & {
export type TextareaField = {
admin?: {
components?: {
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
@@ -339,26 +341,26 @@ export type TextareaField = FieldBase & {
placeholder?: Record<string, string> | string
rows?: number
rtl?: boolean
}
} & Admin
maxLength?: number
minLength?: number
type: 'textarea'
}
} & FieldBase
export type CheckboxField = FieldBase & {
admin?: Admin & {
export type CheckboxField = {
admin?: {
components?: {
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
afterInput?: CustomComponent[]
beforeInput?: CustomComponent[]
}
}
} & Admin
type: 'checkbox'
}
} & FieldBase
export type DateField = FieldBase & {
admin?: Admin & {
export type DateField = {
admin?: {
components?: {
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
@@ -367,14 +369,14 @@ export type DateField = FieldBase & {
}
date?: ConditionalDateProps
placeholder?: Record<string, string> | string
}
} & Admin
type: 'date'
}
} & FieldBase
export type GroupField = Omit<FieldBase, 'required' | 'validation'> & {
admin?: Admin & {
export type GroupField = {
admin?: {
hideGutter?: boolean
}
} & Admin
fields: Field[]
/** Customize generated GraphQL and Typescript schema names.
* By default, it is bound to the collection.
@@ -384,47 +386,48 @@ export type GroupField = Omit<FieldBase, 'required' | 'validation'> & {
*/
interfaceName?: string
type: 'group'
}
} & Omit<FieldBase, 'required' | 'validation'>
export type RowAdmin = Omit<Admin, 'description'>
export type RowField = Omit<FieldBase, 'admin' | 'label' | 'name'> & {
export type RowField = {
admin?: RowAdmin
fields: Field[]
type: 'row'
}
} & Omit<FieldBase, 'admin' | 'label' | 'name'>
export type CollapsibleField = Omit<FieldBase, 'label' | 'name'> & {
export type CollapsibleField = {
fields: Field[]
type: 'collapsible'
} & (
| {
admin: Admin & {
components: {
RowLabel: RowLabelComponent
} & Admin['components']
initCollapsed?: boolean
}
label?: Required<FieldBase['label']>
}
| {
admin?: Admin & {
initCollapsed?: boolean
}
label: Required<FieldBase['label']>
}
)
| {
admin: {
components: {
RowLabel: RowLabelComponent
} & Admin['components']
initCollapsed?: boolean
} & Admin
label?: Required<FieldBase['label']>
}
| {
admin?: {
initCollapsed?: boolean
} & Admin
label: Required<FieldBase['label']>
}
) &
Omit<FieldBase, 'label' | 'name'>
export type TabsAdmin = Omit<Admin, 'description'>
type TabBase = Omit<FieldBase, 'required' | 'validation'> & {
type TabBase = {
description?: Description
fields: Field[]
interfaceName?: string
saveToJWT?: boolean | string
}
} & Omit<FieldBase, 'required' | 'validation'>
export type NamedTab = TabBase & {
export type NamedTab = {
/** Customize generated GraphQL and Typescript schema names.
* The slug is used by default.
*
@@ -432,9 +435,9 @@ export type NamedTab = TabBase & {
* **Note**: Top level types can collide, ensure they are unique amongst collections, arrays, groups, blocks, tabs.
*/
interfaceName?: string
}
} & TabBase
export type UnnamedTab = Omit<TabBase, 'name'> & {
export type UnnamedTab = {
interfaceName?: never
/**
* Can be either:
@@ -448,20 +451,20 @@ export type UnnamedTab = Omit<TabBase, 'name'> & {
| LabelFunction
| string
localized?: never
}
} & Omit<TabBase, 'name'>
export type Tab = NamedTab | UnnamedTab
export type TabsField = Omit<FieldBase, 'admin' | 'localized' | 'name' | 'saveToJWT'> & {
export type TabsField = {
admin?: TabsAdmin
tabs: Tab[]
type: 'tabs'
}
} & Omit<FieldBase, 'admin' | 'localized' | 'name' | 'saveToJWT'>
export type TabAsField = Tab & {
export type TabAsField = {
name?: string
type: 'tab'
}
} & Tab
export type UIField = {
admin: {
@@ -492,7 +495,7 @@ export type UIField = {
type: 'ui'
}
export type UploadField = FieldBase & {
export type UploadField = {
admin?: {
components?: {
Error?: CustomComponent<ErrorProps>
@@ -508,33 +511,33 @@ export type UploadField = FieldBase & {
maxDepth?: number
relationTo: CollectionSlug
type: 'upload'
}
} & FieldBase
type CodeAdmin = Admin & {
type CodeAdmin = {
components?: {
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
}
editorOptions?: EditorProps['options']
language?: string
}
} & Admin
export type CodeField = Omit<FieldBase, 'admin'> & {
export type CodeField = {
admin?: CodeAdmin
maxLength?: number
minLength?: number
type: 'code'
}
} & Omit<FieldBase, 'admin'>
type JSONAdmin = Admin & {
type JSONAdmin = {
components?: {
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
}
editorOptions?: EditorProps['options']
}
} & Admin
export type JSONField = Omit<FieldBase, 'admin'> & {
export type JSONField = {
admin?: JSONAdmin
jsonSchema?: {
fileMatch: string[]
@@ -542,17 +545,17 @@ export type JSONField = Omit<FieldBase, 'admin'> & {
uri: string
}
type: 'json'
}
} & Omit<FieldBase, 'admin'>
export type SelectField = FieldBase & {
admin?: Admin & {
export type SelectField = {
admin?: {
components?: {
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
}
isClearable?: boolean
isSortable?: boolean
}
} & Admin
/**
* Customize the SQL table name
*/
@@ -564,9 +567,9 @@ export type SelectField = FieldBase & {
hasMany?: boolean
options: Option[]
type: 'select'
}
} & FieldBase
type SharedRelationshipProperties = FieldBase & {
type SharedRelationshipProperties = {
filterOptions?: FilterOptions
hasMany?: boolean
/**
@@ -577,54 +580,55 @@ type SharedRelationshipProperties = FieldBase & {
maxDepth?: number
type: 'relationship'
} & (
| {
hasMany: true
/**
* @deprecated Use 'maxRows' instead
*/
max?: number
maxRows?: number
/**
* @deprecated Use 'minRows' instead
*/
min?: number
minRows?: number
}
| {
hasMany?: false | undefined
/**
* @deprecated Use 'maxRows' instead
*/
max?: undefined
maxRows?: undefined
/**
* @deprecated Use 'minRows' instead
*/
min?: undefined
minRows?: undefined
}
)
| {
hasMany: true
/**
* @deprecated Use 'maxRows' instead
*/
max?: number
maxRows?: number
/**
* @deprecated Use 'minRows' instead
*/
min?: number
minRows?: number
}
| {
hasMany?: false | undefined
/**
* @deprecated Use 'maxRows' instead
*/
max?: undefined
maxRows?: undefined
/**
* @deprecated Use 'minRows' instead
*/
min?: undefined
minRows?: undefined
}
) &
FieldBase
type RelationshipAdmin = Admin & {
type RelationshipAdmin = {
allowCreate?: boolean
components?: {
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
}
isSortable?: boolean
}
export type PolymorphicRelationshipField = SharedRelationshipProperties & {
admin?: RelationshipAdmin & {
} & Admin
export type PolymorphicRelationshipField = {
admin?: {
sortOptions?: { [collectionSlug: CollectionSlug]: string }
}
} & RelationshipAdmin
relationTo: CollectionSlug[]
}
export type SingleRelationshipField = SharedRelationshipProperties & {
admin?: RelationshipAdmin & {
} & SharedRelationshipProperties
export type SingleRelationshipField = {
admin?: {
sortOptions?: string
}
} & RelationshipAdmin
relationTo: CollectionSlug
}
} & SharedRelationshipProperties
export type RelationshipField = PolymorphicRelationshipField | SingleRelationshipField
export type ValueWithRelation = {
@@ -646,13 +650,13 @@ export type RichTextField<
Value extends object = any,
AdapterProps = any,
ExtraProperties = object,
> = FieldBase & {
admin?: Admin & {
> = {
admin?: {
components?: {
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
}
}
} & Admin
editor?:
| RichTextAdapter<Value, AdapterProps, AdapterProps>
| RichTextAdapterProvider<Value, AdapterProps, AdapterProps>
@@ -663,10 +667,11 @@ export type RichTextField<
*/
maxDepth?: number
type: 'richText'
} & ExtraProperties
} & ExtraProperties &
FieldBase
export type ArrayField = FieldBase & {
admin?: Admin & {
export type ArrayField = {
admin?: {
components?: {
RowLabel?: RowLabelComponent
} & Admin['components']
@@ -675,7 +680,7 @@ export type ArrayField = FieldBase & {
* Disable drag and drop sorting
*/
isSortable?: boolean
}
} & Admin
/**
* Customize the SQL table name
*/
@@ -692,16 +697,16 @@ export type ArrayField = FieldBase & {
maxRows?: number
minRows?: number
type: 'array'
}
} & FieldBase
export type RadioField = FieldBase & {
admin?: Admin & {
export type RadioField = {
admin?: {
components?: {
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
}
layout?: 'horizontal' | 'vertical'
}
} & Admin
/**
* Customize the SQL table name
*/
@@ -712,7 +717,7 @@ export type RadioField = FieldBase & {
enumName?: DBIdentifierName
options: Option[]
type: 'radio'
}
} & FieldBase
export type Block = {
admin?: {
@@ -743,25 +748,25 @@ export type Block = {
slug: string
}
export type BlockField = FieldBase & {
admin?: Admin & {
export type BlockField = {
admin?: {
initCollapsed?: boolean
/**
* Disable drag and drop sorting
*/
isSortable?: boolean
}
} & Admin
blocks: Block[]
defaultValue?: unknown
labels?: Labels
maxRows?: number
minRows?: number
type: 'blocks'
}
} & FieldBase
export type PointField = FieldBase & {
export type PointField = {
type: 'point'
}
} & FieldBase
export type Field =
| ArrayField
@@ -828,9 +833,9 @@ export type NonPresentationalField =
| TextareaField
| UploadField
export type FieldWithPath = Field & {
export type FieldWithPath = {
path?: string
}
} & Field
export type FieldWithSubFields = ArrayField | CollapsibleField | GroupField | RowField

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-param-reassign */
import type { RichTextAdapter } from '../../../admin/RichText.js'
import type { SanitizedCollectionConfig } from '../../../collections/config/types.js'
import type { SanitizedGlobalConfig } from '../../../globals/config/types.js'

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-param-reassign */
import type { RichTextAdapter } from '../../../admin/RichText.js'
import type { SanitizedCollectionConfig } from '../../../collections/config/types.js'
import type { SanitizedGlobalConfig } from '../../../globals/config/types.js'

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-param-reassign */
import type { RichTextAdapter } from '../../../admin/RichText.js'
import type { SanitizedCollectionConfig } from '../../../collections/config/types.js'
import type { SanitizedGlobalConfig } from '../../../globals/config/types.js'

Some files were not shown because too many files have changed in this diff Show More