2026-07-10 10:47:41 +01:00
/*
Copyright 2026 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { defineConfig } from "oxlint" ;
2026-07-29 09:26:07 +01:00
function buildRestrictedPropertiesOptions (
properties : string [],
message : string ,
) : { object ?: string ; property : string ; message : string }[] {
return properties . map (( prop ) => {
const [ object , property ] = prop . split ( "." );
return {
object : object === "*" ? undefined : object ,
property ,
message ,
};
});
}
2026-07-10 10:47:41 +01:00
const defaultRestrictedProperties = [
{ object : "window" , property : "setImmediate" , message : "Use setTimeout instead" },
2026-07-29 09:26:07 +01:00
... buildRestrictedPropertiesOptions ([ "React.forwardRef" , "*.forwardRef" , "forwardRef" ], "Use ref props instead." ),
2026-07-10 10:47:41 +01:00
] as const ;
const defaultRestrictedGlobals = [
{
name : "setImmediate" ,
message : "Use setTimeout instead." ,
},
];
export default defineConfig ({
$schema : "./node_modules/oxlint/configuration_schema.json" ,
plugins : [
"eslint" ,
"typescript" ,
"unicorn" ,
"import" ,
"jsdoc" ,
"node" ,
"promise" ,
"vitest" ,
"react" ,
"react-perf" ,
"jsx-a11y" ,
],
jsPlugins : [ "eslint-plugin-element-call" ],
categories : {
correctness : "error" ,
perf : "error" ,
2026-07-29 09:26:07 +01:00
suspicious : "error" ,
2026-08-04 10:15:07 +01:00
restriction : "warn" ,
2026-07-10 10:47:41 +01:00
},
options : {
typeAware : true ,
2026-07-17 08:55:31 +01:00
reportUnusedDisableDirectives : "warn" ,
2026-07-10 10:47:41 +01:00
maxWarnings : 0 ,
denyWarnings : true ,
},
env : {
es6 : true ,
},
ignorePatterns : [
"**/lib" ,
"**/dist" ,
"**/node_modules" ,
"**/coverage" ,
"apps/web/src/vector/modernizr.cjs" ,
// Legacy skinning file that some people might still have
"apps/web/src/component-index.js" ,
// Auto-generated files
"apps/web/src/modules.ts" ,
"apps/web/src/modules.js" ,
// Test result files
"**/test-results" ,
"**/html-report" ,
// Shared components generated files
"/packages/shared-components/dist/" ,
"/packages/shared-components/src/i18n/i18nKeys.d.ts" ,
"/packages/shared-components/typedoc/" ,
],
settings : {
2026-08-04 10:15:07 +01:00
"jsdoc" : {
2026-07-10 10:47:41 +01:00
tagNamePreference : {
remark : "remarks" ,
privateRemarks : "privateRemarks" ,
experimental : "experimental" ,
deprecated : "deprecated" ,
typeParam : "typeParam" ,
defaultValue : "defaultValue" ,
packageDocumentation : "packageDocumentation" ,
alpha : "alpha" ,
knipignore : "knipignore" ,
resolves : "resolves" ,
},
},
2026-08-04 10:15:07 +01:00
"vitest" : {
typecheck : true ,
},
"jsx-a11y" : {
components : {
Button : "button" ,
IconButton : "button" ,
AccessibleButton : "button" ,
RovingAccessibleButton : "button" ,
ContextMenuButton : "button" ,
ContextMenuTooltipButton : "button" ,
},
// polymorphicPropName: "as", // Would be good to enable in the future
},
"react" : {
componentWrapperFunctions : [ "withMatrixClientHOC" ],
},
2026-07-10 10:47:41 +01:00
},
rules : {
"no-constant-condition" : [ "error" , { checkLoops : "allExceptWhileTrue" }],
"typescript/unbound-method" : [ "error" , { ignoreStatic : true }],
"typescript/no-empty-object-type" : [
"error" ,
{
allowInterfaces : "with-single-extends" ,
},
],
"prefer-const" : [ "error" , { destructuring : "all" }],
"import/first" : "error" ,
2026-07-17 08:55:31 +01:00
"new-cap" : "error" ,
"typescript/no-unsafe-function-type" : "error" ,
"react/rules-of-hooks" : "error" ,
"no-extend-native" : "error" ,
"no-inner-declarations" : "error" ,
"typescript/no-unnecessary-type-constraint" : "error" ,
2026-07-17 10:50:57 +01:00
"jsx-filename-extension" : [ "error" , { allow : "as-needed" , extensions : [ "tsx" ] }],
2026-07-10 10:47:41 +01:00
2026-08-04 10:15:07 +01:00
// Tune restriction ruleset
"no-undefined" : "off" ,
"typescript/use-unknown-in-catch-callback-variable" : "off" ,
"typescript/promise-function-async" : "off" ,
"typescript/no-non-null-assertion" : "off" ,
"typescript/no-invalid-void-type" : "off" ,
"typescript/no-explicit-any" : "off" ,
"typescript/no-import-type-side-effects" : "off" ,
"typescript/no-dynamic-delete" : "off" ,
"typescript/explicit-module-boundary-types" : "off" ,
"no-param-reassign" : "off" ,
"no-use-before-define" : "off" ,
"class-methods-use-this" : "off" ,
"no-plusplus" : "off" ,
"no-default-export" : "off" ,
"no-console" : "off" ,
"complexity" : "off" ,
"no-void" : "off" ,
"no-empty-function" : "off" ,
"default-case" : "off" ,
"no-implicit-globals" : "off" ,
"no-bitwise" : "off" ,
"no-empty" : "off" ,
"no-eq-null" : "off" ,
"promise/catch-or-return" : "off" ,
"node/no-process-env" : "off" , // We enable this for src in overrides
"unicorn/no-array-reduce" : "off" ,
"unicorn/no-anonymous-default-export" : "off" ,
"import/no-relative-parent-imports" : "off" ,
"import/unambiguous" : "off" ,
"import/no-cycle" : "off" ,
"jsdoc/empty-tags" : "off" ,
"vitest/require-test-timeout" : "off" ,
"react/jsx-no-literals" : "off" ,
"react/prefer-function-component" : "off" ,
"react/forbid-component-props" : "off" ,
"react/no-multi-comp" : "off" ,
"react/no-danger" : "off" ,
"react/only-export-components" : "off" ,
"react/no-react-children" : "off" ,
"react/no-clone-element" : "off" ,
2026-07-10 10:47:41 +01:00
"unicorn/no-instanceof-array" : "error" ,
"no-restricted-globals" : [ "error" , ... defaultRestrictedGlobals ],
"no-restricted-properties" : [ "error" , ... defaultRestrictedProperties ],
"import/no-duplicates" : [ "error" ],
"element-call/copyright-header" : [
"error" ,
"/*\nCopyright %%CURRENT_YEAR%% Element Creations Ltd.\n\nSPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial\nPlease see LICENSE in the repository root for full details.\n*/\n\n" ,
],
// Allow the use of underscore to show args are not used.
// This is helpful for seeing that a function implements
// an interface but won't be using one of it's arguments.
2026-07-17 08:55:31 +01:00
"no-unused-vars" : [ "error" , { args : "none" , ignoreRestSiblings : true }],
2026-07-10 10:47:41 +01:00
2026-07-17 08:55:31 +01:00
// Require method signatures to be explicit to help make signature changes more obvious in review
"typescript/explicit-function-return-type" : [
"error" ,
{
allowExpressions : true ,
},
],
2026-07-10 10:47:41 +01:00
// Prevent invalid non-type re-exports of types, these can cause downstream build failures
"typescript/consistent-type-exports" : [ "error" ],
// Prevent unnecessary runtime dependencies between files
"typescript/consistent-type-imports" : [ "error" , { fixStyle : "inline-type-imports" }],
2026-08-10 13:25:55 +01:00
"jsx-a11y/control-has-associated-label" : [
"error" ,
{
labelAttributes : [ "label" , "value" ],
depth : 3 ,
},
],
2026-07-10 10:47:41 +01:00
// Disable some perf rules
"no-await-in-loop" : "off" ,
// Disable some opinionated rules
"unicorn/switch-case-braces" : "off" ,
"sort-keys" : "off" ,
"typescript/require-array-sort-compare" : "off" ,
2026-08-10 13:25:55 +01:00
"no-extra-boolean-cast" : "off" ,
2026-07-10 10:47:41 +01:00
// These would be nice to enable at some point
"unicorn/prefer-set-has" : "off" ,
"unicorn/prefer-string-slice" : "off" ,
"unicorn/prefer-number-properties" : "off" ,
"unicorn/prefer-at" : "off" ,
"unicorn/no-new-array" : "off" ,
"unicorn/no-array-for-each" : "off" ,
"unicorn/explicit-length-check" : "off" ,
"unicorn/catch-error-name" : "off" ,
"require-unicode-regexp" : "off" ,
"typescript/restrict-template-expressions" : "off" ,
"typescript/no-redundant-type-constituents" : "off" ,
"typescript/no-useless-default-assignment" : "off" ,
"typescript/no-duplicate-type-constituents" : "off" ,
"typescript/no-floating-promises" : "off" ,
"typescript/no-implied-eval" : "off" ,
"typescript/no-misused-spread" : "off" ,
"promise/valid-params" : "off" ,
"react-perf/jsx-no-new-function-as-prop" : "off" ,
"react-perf/jsx-no-new-object-as-prop" : "off" ,
"react-perf/jsx-no-jsx-as-prop" : "off" ,
"jsx-a11y/prefer-tag-over-role" : "off" ,
"jsx-a11y/no-autofocus" : "off" ,
"react/no-children-prop" : "off" ,
"react-perf/jsx-no-new-array-as-prop" : "off" ,
"react/no-did-update-set-state" : "off" ,
"react/no-did-mount-set-state" : "off" ,
"jsx-a11y/no-static-element-interactions" : "off" ,
"jsx-a11y/no-noninteractive-element-interactions" : "off" ,
"jsx-a11y/media-has-caption" : "off" ,
"jsx-a11y/no-noninteractive-element-to-interactive-role" : "off" ,
"jsx-a11y/aria-activedescendant-has-tabindex" : "off" ,
2026-07-29 09:26:07 +01:00
// Rules within `suspicious` we do not yet comply with but probably should
"typescript/no-unsafe-type-assertion" : "off" ,
"no-shadow" : "off" ,
"unicorn/consistent-function-scoping" : "off" ,
"typescript/consistent-return" : "off" ,
"typescript/no-unsafe-enum-comparison" : "off" ,
"typescript/no-unnecessary-type-conversion" : "off" ,
"typescript/no-unnecessary-type-parameters" : "off" ,
"typescript/no-unnecessary-boolean-literal-compare" : "off" ,
"react/no-unstable-nested-components" : "off" ,
"unicorn/no-array-sort" : "off" ,
"unicorn/no-array-reverse" : "off" ,
"unicorn/prefer-add-event-listener" : "off" ,
"no-underscore-dangle" : "off" ,
"import/no-named-as-default" : "off" ,
"import/no-unassigned-import" : "off" ,
"import/no-named-as-default-member" : "off" ,
"promise/always-return" : "off" ,
"preserve-caught-error" : "off" ,
"react/react-in-jsx-scope" : "off" ,
"unicorn/require-post-message-target-origin" : "off" ,
2026-07-10 10:47:41 +01:00
},
overrides : [
{
2026-07-17 08:55:31 +01:00
files : [ "apps/web/src/**/*" , "{packages,modules}/*/src/**/*" ],
rules : {
"no-restricted-globals" : [
"error" ,
defaultRestrictedGlobals ,
{
name : "Buffer" ,
message : "Buffer is not available in the web." ,
},
],
2026-08-04 10:15:07 +01:00
"node/no-process-env" : "error" ,
"unicorn/prefer-node-protocol" : "off" ,
2026-07-17 08:55:31 +01:00
},
},
{
files : [ "{packages,apps,modules}/*/src/**/*" ],
rules : {
// Enable this in the future, it has a lot of false positives right now
// "react/react-compiler": "error",
},
},
{
files : [ "packages/shared-components/**/*" ],
rules : {
"no-restricted-imports" : [
"error" ,
{
paths : [
{
name : "react" ,
importNames : [ "act" ],
message : "Please use @test-utils instead." ,
},
{
name : "@testing-library/react" ,
message : "Please use @test-utils instead" ,
},
],
},
],
// This would be good to apply globally in the future
"react/forbid-elements" : [
"error" ,
{
forbid : [
{ element : "h1" , message : "Use Compound <Heading> instead" },
{ element : "h2" , message : "Use Compound <Heading> instead" },
{ element : "h3" , message : "Use Compound <Heading> instead" },
{ element : "h4" , message : "Use Compound <Heading> instead" },
{ element : "h5" , message : "Use Compound <Heading> instead" },
{ element : "h6" , message : "Use Compound <Heading> instead" },
],
},
],
},
},
2026-08-04 10:15:07 +01:00
{
files : [
"apps/desktop/src/**/*" ,
"packages/playwright-common/src/**/*" ,
"**/scripts/**/*" ,
"apps/web/module_system/**/*" ,
2026-08-05 22:29:30 +01:00
"apps/web/webpack.config.ts" ,
2026-08-04 10:15:07 +01:00
],
rules : {
"no-restricted-globals" : "off" ,
"unicorn/prefer-node-protocol" : "error" ,
// These files can use envvars
"node/no-process-env" : "off" ,
// They do not depend on js-sdk for access to TypedEventEmitter so disable this rule
"no-restricted-imports" : "off" ,
// They can use process.exit
"unicorn/no-process-exit" : "off" ,
2026-08-05 22:29:30 +01:00
// They can use top level await
"node/no-top-level-await" : "off" ,
2026-08-04 10:15:07 +01:00
},
},
2026-07-17 08:55:31 +01:00
{
files : [ "apps/web/**/*" ],
2026-07-10 10:47:41 +01:00
rules : {
"no-restricted-properties" : [
"error" ,
... defaultRestrictedProperties ,
... buildRestrictedPropertiesOptions (
[ "window.innerHeight" , "window.innerWidth" , "window.visualViewport" ],
"Use UIStore to access window dimensions instead." ,
),
... buildRestrictedPropertiesOptions (
[ "*.mxcUrlToHttp" , "*.getHttpUriForMxc" ],
"Use Media helper instead to centralise access for customisation." ,
),
],
// Ban matrix-js-sdk/src imports in favour of matrix-js-sdk/src/matrix imports to prevent unleashing hell.
// Ban compound-design-tokens raw svg imports in favour of their React component counterparts
"no-restricted-imports" : [
"error" ,
{
paths : [
2026-08-04 10:15:07 +01:00
{
name : "events" ,
message : "Please use TypedEventEmitter instead" ,
},
2026-07-10 10:47:41 +01:00
{
name : "react" ,
importNames : [ "forwardRef" ],
message : "Use ref props instead." ,
},
{
name : "@testing-library/react" ,
message : "Please use jest-matrix-react instead" ,
},
{
name : "matrix-js-sdk" ,
message : "Please use matrix-js-sdk/src/matrix instead" ,
},
{
name : "matrix-js-sdk/" ,
message : "Please use matrix-js-sdk/src/matrix instead" ,
},
{
name : "matrix-js-sdk/src" ,
message : "Please use matrix-js-sdk/src/matrix instead" ,
},
{
name : "matrix-js-sdk/src/" ,
message : "Please use matrix-js-sdk/src/matrix instead" ,
},
{
name : "matrix-js-sdk/src/index" ,
message : "Please use matrix-js-sdk/src/matrix instead" ,
},
{
name : "emojibase-regex" ,
message :
"This regex doesn't actually test for emoji. See the docs at https://emojibase.dev/docs/regex/ and prefer our own EMOJI_REGEX from HtmlUtils." ,
},
],
patterns : [
{
group : [
"matrix-js-sdk/src/**" ,
"!matrix-js-sdk/src/matrix" ,
"!matrix-js-sdk/src/crypto-api" ,
"!matrix-js-sdk/src/types" ,
"!matrix-js-sdk/src/testing" ,
"!matrix-js-sdk/src/utils/**" ,
"matrix-js-sdk/src/utils/internal/**" ,
"matrix-js-sdk/lib" ,
"matrix-js-sdk/lib/" ,
"matrix-js-sdk/lib/**" ,
// XXX: Temporarily allow these as they are not available via the main export
"!matrix-js-sdk/src/logger" ,
"!matrix-js-sdk/src/errors" ,
"!matrix-js-sdk/src/utils" ,
"!matrix-js-sdk/src/version-support" ,
"!matrix-js-sdk/src/randomstring" ,
"!matrix-js-sdk/src/sliding-sync" ,
"!matrix-js-sdk/src/browser-index" ,
"!matrix-js-sdk/src/feature" ,
"!matrix-js-sdk/src/NamespacedValue" ,
"!matrix-js-sdk/src/ReEmitter" ,
"!matrix-js-sdk/src/event-mapper" ,
"!matrix-js-sdk/src/interactive-auth" ,
"!matrix-js-sdk/src/secret-storage" ,
"!matrix-js-sdk/src/room-hierarchy" ,
"!matrix-js-sdk/src/rendezvous" ,
"!matrix-js-sdk/src/indexeddb-worker" ,
"!matrix-js-sdk/src/pushprocessor" ,
"!matrix-js-sdk/src/extensible_events_v1" ,
"!matrix-js-sdk/src/extensible_events_v1/PollStartEvent" ,
"!matrix-js-sdk/src/extensible_events_v1/PollResponseEvent" ,
"!matrix-js-sdk/src/extensible_events_v1/PollEndEvent" ,
"!matrix-js-sdk/src/extensible_events_v1/InvalidEventError" ,
"!matrix-js-sdk/src/oidc" ,
"!matrix-js-sdk/src/oidc/discovery" ,
"!matrix-js-sdk/src/oidc/authorize" ,
"!matrix-js-sdk/src/oidc/validate" ,
"!matrix-js-sdk/src/oidc/error" ,
"!matrix-js-sdk/src/oidc/register" ,
"!matrix-js-sdk/src/webrtc" ,
"!matrix-js-sdk/src/webrtc/call" ,
"!matrix-js-sdk/src/webrtc/callFeed" ,
"!matrix-js-sdk/src/webrtc/mediaHandler" ,
"!matrix-js-sdk/src/webrtc/callEventTypes" ,
"!matrix-js-sdk/src/webrtc/callEventHandler" ,
"!matrix-js-sdk/src/webrtc/groupCallEventHandler" ,
"!matrix-js-sdk/src/models" ,
"!matrix-js-sdk/src/models/read-receipt" ,
"!matrix-js-sdk/src/models/relations-container" ,
"!matrix-js-sdk/src/models/related-relations" ,
"!matrix-js-sdk/src/matrixrtc" ,
],
message : "Please use matrix-js-sdk/src/matrix instead" ,
},
{
group : [ "emojibase-regex/emoji*" ],
message :
"This regex doesn't actually test for emoji. See the docs at https://emojibase.dev/docs/regex/ and prefer our own EMOJI_REGEX from HtmlUtils." ,
},
{
group : [ "@vector-im/compound-design-tokens/icons/*" ],
message : "Please use @vector-im/compound-design-tokens/assets/web/icons/* instead" ,
},
{
group : [ "**/packages/shared-components/**" , "../packages/shared-components/**" ],
message : "Please use @element-hq/web-shared-components" ,
},
],
},
],
},
},
{
2026-07-17 08:55:31 +01:00
files : [
"apps/*/playwright/**/*" ,
"packages/playwright-common/**/*" ,
"modules/*/e2e/**/*" ,
"modules/playwright/**/*" ,
],
2026-07-10 10:47:41 +01:00
rules : {
2026-07-17 08:55:31 +01:00
// This is a common pattern for Playwright fixtures
"no-empty-pattern" : "off" ,
// Playwright has a `use` method for fixtures which confuses this rule
"react-hooks/rules-of-hooks" : "off" ,
2026-07-10 10:47:41 +01:00
},
},
{
files : [
"{packages,apps,modules}/*/src/**/*.{test,stories}.{ts,tsx}" ,
2026-07-17 08:55:31 +01:00
"{packages,apps,modules}/*/src/{tests,test}/*.{ts,tsx}" ,
"{packages,apps,modules}/*/src/**/__mocks__/*.{ts,tsx}" ,
2026-07-10 10:47:41 +01:00
"{packages,apps,modules}/*/{test,playwright,e2e}/**/*" ,
"{packages,apps,modules}/*/playwright.config.ts" ,
"{packages,apps,modules}/*/.storybook/**/*" ,
2026-07-29 09:26:07 +01:00
"{packages,apps,modules}/*/__mocks__/**/*" ,
2026-07-10 10:47:41 +01:00
"packages/playwright-common/src/**/*" ,
],
rules : {
// Tests can be linted a little more flexibly
// We don't need super strict typing in test utilities
"no-import-assign" : "off" ,
"no-unsafe-optional-chaining" : "off" ,
"typescript/no-empty-object-type" : "off" ,
"typescript/unbound-method" : "off" ,
"typescript/no-floating-promises" : "off" ,
"vitest/require-mock-type-parameters" : "off" ,
"vitest/no-disabled-tests" : "off" ,
"vitest/no-conditional-expect" : "off" ,
"vitest/warn-todo" : "off" ,
"vitest/require-to-throw-message" : "off" ,
"vitest/prefer-snapshot-hint" : "off" ,
"vitest/no-standalone-expect" : [
"error" ,
{
additionalTestBlockFunctions : [ "beforeAll" , "beforeEach" ],
},
],
"vitest/expect-expect" : [
"error" ,
{
assertFunctionNames : [ "expect*" , "*Test" , "assert*" , "test*Factory" ],
},
],
"jsdoc/check-tag-names" : "off" ,
2026-07-17 08:55:31 +01:00
"typescript/explicit-function-return-type" : "off" ,
2026-08-04 10:15:07 +01:00
"typescript/explicit-module-boundary-types" : "off" ,
2026-07-17 08:55:31 +01:00
"typescript/explicit-member-accessibility" : "off" ,
2026-08-04 10:15:07 +01:00
"no-proto" : "off" ,
2026-07-10 10:47:41 +01:00
2026-07-16 18:29:49 +01:00
// Disable a11y rules for components in tests
"jsx-a11y/role-has-required-aria-props" : "off" ,
2026-08-04 10:15:07 +01:00
"react/button-has-type" : "off" ,
2026-07-10 10:47:41 +01:00
"jsx-a11y/interactive-supports-focus" : "off" ,
"jsx-a11y/no-static-element-interactions" : "off" ,
2026-08-04 10:15:07 +01:00
"jsx-a11y/anchor-ambiguous-text" : "off" ,
2026-07-10 10:47:41 +01:00
"jsx-a11y/click-events-have-key-events" : "off" ,
"jsx-a11y/media-has-caption" : "off" ,
"jsx-a11y/no-noninteractive-element-to-interactive-role" : "off" ,
2026-07-16 18:29:49 +01:00
"jsx-a11y/role-supports-aria-props" : "off" ,
"react/jsx-no-constructed-context-values" : "off" ,
"react/no-array-index-key" : "off" ,
2026-07-10 10:47:41 +01:00
"react/forbid-elements" : "off" ,
2026-07-29 09:26:07 +01:00
"typescript/no-extraneous-class" : "off" ,
"no-new" : "off" ,
"react/iframe-missing-sandbox" : "off" ,
"promise/no-promise-in-callback" : "off" ,
2026-08-10 13:25:55 +01:00
2026-07-10 10:47:41 +01:00
// This would be good to enable in the future
"typescript/await-thenable" : "off" ,
"promise/no-callback-in-promise" : "off" ,
2026-07-29 09:26:07 +01:00
// This rule requires strictNullChecks enabled
"typescript/no-unnecessary-boolean-literal-compare" : "off" ,
"typescript/no-unnecessary-type-assertion" : "off" ,
2026-07-10 10:47:41 +01:00
},
},
{
files : [ "{packages,apps,modules}/*/src/**/*.stories.{ts,tsx}" ],
jsPlugins : [ "eslint-plugin-element-call" , "eslint-plugin-storybook" ],
rules : {
"storybook/meta-satisfies-type" : "error" ,
"storybook/default-exports" : "error" ,
"storybook/hierarchy-separator" : "error" ,
"storybook/no-redundant-story-name" : "error" ,
"storybook/no-renderer-packages" : "error" ,
"storybook/no-stories-of" : "error" ,
"storybook/story-exports" : "error" ,
"storybook/use-storybook-expect" : "error" ,
"storybook/use-storybook-testing-library" : "error" ,
"storybook/no-uninstalled-addons" : "error" ,
2026-07-17 10:50:57 +01:00
"jsx-filename-extension" : [ "error" , { allow : "always" , extensions : [ "tsx" ] }],
2026-07-10 10:47:41 +01:00
},
},
2026-07-17 08:55:31 +01:00
{
files : [ "**/*.{cjs,js}" ],
rules : {
"typescript/no-require-imports" : "off" ,
2026-08-04 10:15:07 +01:00
"import/no-commonjs" : "off" ,
"unicorn/prefer-module" : "off" ,
},
},
{
files : [ "apps/web/test/**/*-test.*" ],
rules : {
// Jest is still CommonJS
"unicorn/prefer-module" : "off" ,
2026-07-17 08:55:31 +01:00
},
},
2026-07-29 09:26:07 +01:00
{
files : [ "**/*.d.ts" ],
rules : {
"unicorn/require-module-specifiers" : "off" ,
},
},
2026-07-10 10:47:41 +01:00
],
});