@prairielearn/eslint-config 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @prairielearn/eslint-config
2
2
 
3
+ ## 2.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 18391d4: Add rule for noreferrer in target=\_blank links
8
+ - 240b216: Enable the new `@prairielearn/no-hydrate-reslocals` rule as an error.
9
+
10
+ ### Patch Changes
11
+
12
+ - 393a0ba: Use modern lodash rule config
13
+ - 07dfbca: Disable `checkFromLast` in `unicorn/prefer-array-find` rule since `findLast` is unavailable in our target lib
14
+ - b6e03e9: Upgrade dependencies
15
+ - 6612675: update dependencies
16
+ - Updated dependencies [240b216]
17
+ - Updated dependencies [aaeb317]
18
+ - Updated dependencies [b6e03e9]
19
+ - @prairielearn/eslint-plugin@4.1.0
20
+
3
21
  ## 2.0.1
4
22
 
5
23
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"lodash.d.ts","sourceRoot":"","sources":["../../src/configs/lodash.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAKzD;;GAEG;AACH,wBAAgB,YAAY,IAAI,QAAQ,CAAC,UAAU,CAAC,WAAW,CAgB9D","sourcesContent":["import { FlatCompat } from '@eslint/eslintrc';\nimport type { TSESLint } from '@typescript-eslint/utils';\nimport youDontNeedLodashUnderscore from 'eslint-plugin-you-dont-need-lodash-underscore';\n\nconst compat = new FlatCompat();\n\n/**\n * Lodash/underscore replacement rules.\n */\nexport function lodashConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n 'you-dont-need-lodash-underscore': youDontNeedLodashUnderscore,\n },\n },\n // Use FlatCompat to extend the legacy config\n ...compat.extends('plugin:you-dont-need-lodash-underscore/all'),\n {\n rules: {\n // The _.omit function is still useful in some contexts.\n 'you-dont-need-lodash-underscore/omit': 'off',\n },\n },\n ];\n}\n"]}
1
+ {"version":3,"file":"lodash.d.ts","sourceRoot":"","sources":["../../src/configs/lodash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAUzD;;GAEG;AACH,wBAAgB,YAAY,IAAI,QAAQ,CAAC,UAAU,CAAC,WAAW,CAa9D","sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\nimport youDontNeedLodashUnderscore from 'eslint-plugin-you-dont-need-lodash-underscore';\n\nconst allRules = Object.fromEntries(\n Object.keys(youDontNeedLodashUnderscore.rules).map((rule) => [\n `you-dont-need-lodash-underscore/${rule}`,\n 'error',\n ]),\n);\n\n/**\n * Lodash/underscore replacement rules.\n */\nexport function lodashConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n 'you-dont-need-lodash-underscore': youDontNeedLodashUnderscore,\n },\n rules: {\n ...allRules,\n // The _.omit function is still useful in some contexts.\n 'you-dont-need-lodash-underscore/omit': 'off',\n },\n },\n ];\n}\n"]}
@@ -1,6 +1,8 @@
1
- import { FlatCompat } from '@eslint/eslintrc';
2
1
  import youDontNeedLodashUnderscore from 'eslint-plugin-you-dont-need-lodash-underscore';
3
- const compat = new FlatCompat();
2
+ const allRules = Object.fromEntries(Object.keys(youDontNeedLodashUnderscore.rules).map((rule) => [
3
+ `you-dont-need-lodash-underscore/${rule}`,
4
+ 'error',
5
+ ]));
4
6
  /**
5
7
  * Lodash/underscore replacement rules.
6
8
  */
@@ -10,11 +12,8 @@ export function lodashConfig() {
10
12
  plugins: {
11
13
  'you-dont-need-lodash-underscore': youDontNeedLodashUnderscore,
12
14
  },
13
- },
14
- // Use FlatCompat to extend the legacy config
15
- ...compat.extends('plugin:you-dont-need-lodash-underscore/all'),
16
- {
17
15
  rules: {
16
+ ...allRules,
18
17
  // The _.omit function is still useful in some contexts.
19
18
  'you-dont-need-lodash-underscore/omit': 'off',
20
19
  },
@@ -1 +1 @@
1
- {"version":3,"file":"lodash.js","sourceRoot":"","sources":["../../src/configs/lodash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,2BAA2B,MAAM,+CAA+C,CAAC;AAExF,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;AAEhC;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO;QACL;YACE,OAAO,EAAE;gBACP,iCAAiC,EAAE,2BAA2B;aAC/D;SACF;QACD,6CAA6C;QAC7C,GAAG,MAAM,CAAC,OAAO,CAAC,4CAA4C,CAAC;QAC/D;YACE,KAAK,EAAE;gBACL,wDAAwD;gBACxD,sCAAsC,EAAE,KAAK;aAC9C;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { FlatCompat } from '@eslint/eslintrc';\nimport type { TSESLint } from '@typescript-eslint/utils';\nimport youDontNeedLodashUnderscore from 'eslint-plugin-you-dont-need-lodash-underscore';\n\nconst compat = new FlatCompat();\n\n/**\n * Lodash/underscore replacement rules.\n */\nexport function lodashConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n 'you-dont-need-lodash-underscore': youDontNeedLodashUnderscore,\n },\n },\n // Use FlatCompat to extend the legacy config\n ...compat.extends('plugin:you-dont-need-lodash-underscore/all'),\n {\n rules: {\n // The _.omit function is still useful in some contexts.\n 'you-dont-need-lodash-underscore/omit': 'off',\n },\n },\n ];\n}\n"]}
1
+ {"version":3,"file":"lodash.js","sourceRoot":"","sources":["../../src/configs/lodash.ts"],"names":[],"mappings":"AACA,OAAO,2BAA2B,MAAM,+CAA+C,CAAC;AAExF,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CACjC,MAAM,CAAC,IAAI,CAAC,2BAA2B,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;IAC3D,mCAAmC,IAAI,EAAE;IACzC,OAAO;CACR,CAAC,CACH,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO;QACL;YACE,OAAO,EAAE;gBACP,iCAAiC,EAAE,2BAA2B;aAC/D;YACD,KAAK,EAAE;gBACL,GAAG,QAAQ;gBACX,wDAAwD;gBACxD,sCAAsC,EAAE,KAAK;aAC9C;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\nimport youDontNeedLodashUnderscore from 'eslint-plugin-you-dont-need-lodash-underscore';\n\nconst allRules = Object.fromEntries(\n Object.keys(youDontNeedLodashUnderscore.rules).map((rule) => [\n `you-dont-need-lodash-underscore/${rule}`,\n 'error',\n ]),\n);\n\n/**\n * Lodash/underscore replacement rules.\n */\nexport function lodashConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n 'you-dont-need-lodash-underscore': youDontNeedLodashUnderscore,\n },\n rules: {\n ...allRules,\n // The _.omit function is still useful in some contexts.\n 'you-dont-need-lodash-underscore/omit': 'off',\n },\n },\n ];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"prairielearn.d.ts","sourceRoot":"","sources":["../../src/configs/prairielearn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAIzD,MAAM,WAAW,yBAAyB;IACxC;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,CAAC,EAAE,yBAAyB,GAClC,QAAQ,CAAC,UAAU,CAAC,WAAW,CAwBjC","sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\n\nimport prairielearn from '@prairielearn/eslint-plugin';\n\nexport interface PrairieLearnPluginOptions {\n /**\n * Types to allow when using the safe-db-types rule.\n */\n allowDbTypes?: string[];\n}\n\n/**\n * PrairieLearn-specific ESLint plugin rules.\n * Includes AWS client configuration, JSX safety, SQL blocks, and database type safety.\n */\nexport function prairieLearnConfig(\n options?: PrairieLearnPluginOptions,\n): TSESLint.FlatConfig.ConfigArray {\n const { allowDbTypes = [] } = options ?? {};\n\n return [\n {\n plugins: {\n '@prairielearn': prairielearn,\n },\n\n rules: {\n '@prairielearn/aws-client-mandatory-config': 'error',\n '@prairielearn/aws-client-shared-config': 'error',\n '@prairielearn/jsx-no-dollar-interpolation': 'error',\n '@prairielearn/no-current-target-in-callback': 'error',\n '@prairielearn/no-unused-sql-blocks': 'error',\n '@prairielearn/safe-db-types': [\n 'error',\n {\n allowDbTypes,\n },\n ],\n },\n },\n ];\n}\n"]}
1
+ {"version":3,"file":"prairielearn.d.ts","sourceRoot":"","sources":["../../src/configs/prairielearn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAIzD,MAAM,WAAW,yBAAyB;IACxC;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,CAAC,EAAE,yBAAyB,GAClC,QAAQ,CAAC,UAAU,CAAC,WAAW,CAyBjC","sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\n\nimport prairielearn from '@prairielearn/eslint-plugin';\n\nexport interface PrairieLearnPluginOptions {\n /**\n * Types to allow when using the safe-db-types rule.\n */\n allowDbTypes?: string[];\n}\n\n/**\n * PrairieLearn-specific ESLint plugin rules.\n * Includes AWS client configuration, JSX safety, SQL blocks, and database type safety.\n */\nexport function prairieLearnConfig(\n options?: PrairieLearnPluginOptions,\n): TSESLint.FlatConfig.ConfigArray {\n const { allowDbTypes = [] } = options ?? {};\n\n return [\n {\n plugins: {\n '@prairielearn': prairielearn,\n },\n\n rules: {\n '@prairielearn/aws-client-mandatory-config': 'error',\n '@prairielearn/aws-client-shared-config': 'error',\n '@prairielearn/jsx-no-dollar-interpolation': 'error',\n '@prairielearn/no-current-target-in-callback': 'error',\n '@prairielearn/no-hydrate-reslocals': 'error',\n '@prairielearn/no-unused-sql-blocks': 'error',\n '@prairielearn/safe-db-types': [\n 'error',\n {\n allowDbTypes,\n },\n ],\n },\n },\n ];\n}\n"]}
@@ -15,6 +15,7 @@ export function prairieLearnConfig(options) {
15
15
  '@prairielearn/aws-client-shared-config': 'error',
16
16
  '@prairielearn/jsx-no-dollar-interpolation': 'error',
17
17
  '@prairielearn/no-current-target-in-callback': 'error',
18
+ '@prairielearn/no-hydrate-reslocals': 'error',
18
19
  '@prairielearn/no-unused-sql-blocks': 'error',
19
20
  '@prairielearn/safe-db-types': [
20
21
  'error',
@@ -1 +1 @@
1
- {"version":3,"file":"prairielearn.js","sourceRoot":"","sources":["../../src/configs/prairielearn.ts"],"names":[],"mappings":"AAEA,OAAO,YAAY,MAAM,6BAA6B,CAAC;AASvD;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAmC;IAEnC,MAAM,EAAE,YAAY,GAAG,EAAE,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;IAE5C,OAAO;QACL;YACE,OAAO,EAAE;gBACP,eAAe,EAAE,YAAY;aAC9B;YAED,KAAK,EAAE;gBACL,2CAA2C,EAAE,OAAO;gBACpD,wCAAwC,EAAE,OAAO;gBACjD,2CAA2C,EAAE,OAAO;gBACpD,6CAA6C,EAAE,OAAO;gBACtD,oCAAoC,EAAE,OAAO;gBAC7C,6BAA6B,EAAE;oBAC7B,OAAO;oBACP;wBACE,YAAY;qBACb;iBACF;aACF;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\n\nimport prairielearn from '@prairielearn/eslint-plugin';\n\nexport interface PrairieLearnPluginOptions {\n /**\n * Types to allow when using the safe-db-types rule.\n */\n allowDbTypes?: string[];\n}\n\n/**\n * PrairieLearn-specific ESLint plugin rules.\n * Includes AWS client configuration, JSX safety, SQL blocks, and database type safety.\n */\nexport function prairieLearnConfig(\n options?: PrairieLearnPluginOptions,\n): TSESLint.FlatConfig.ConfigArray {\n const { allowDbTypes = [] } = options ?? {};\n\n return [\n {\n plugins: {\n '@prairielearn': prairielearn,\n },\n\n rules: {\n '@prairielearn/aws-client-mandatory-config': 'error',\n '@prairielearn/aws-client-shared-config': 'error',\n '@prairielearn/jsx-no-dollar-interpolation': 'error',\n '@prairielearn/no-current-target-in-callback': 'error',\n '@prairielearn/no-unused-sql-blocks': 'error',\n '@prairielearn/safe-db-types': [\n 'error',\n {\n allowDbTypes,\n },\n ],\n },\n },\n ];\n}\n"]}
1
+ {"version":3,"file":"prairielearn.js","sourceRoot":"","sources":["../../src/configs/prairielearn.ts"],"names":[],"mappings":"AAEA,OAAO,YAAY,MAAM,6BAA6B,CAAC;AASvD;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAmC;IAEnC,MAAM,EAAE,YAAY,GAAG,EAAE,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;IAE5C,OAAO;QACL;YACE,OAAO,EAAE;gBACP,eAAe,EAAE,YAAY;aAC9B;YAED,KAAK,EAAE;gBACL,2CAA2C,EAAE,OAAO;gBACpD,wCAAwC,EAAE,OAAO;gBACjD,2CAA2C,EAAE,OAAO;gBACpD,6CAA6C,EAAE,OAAO;gBACtD,oCAAoC,EAAE,OAAO;gBAC7C,oCAAoC,EAAE,OAAO;gBAC7C,6BAA6B,EAAE;oBAC7B,OAAO;oBACP;wBACE,YAAY;qBACb;iBACF;aACF;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\n\nimport prairielearn from '@prairielearn/eslint-plugin';\n\nexport interface PrairieLearnPluginOptions {\n /**\n * Types to allow when using the safe-db-types rule.\n */\n allowDbTypes?: string[];\n}\n\n/**\n * PrairieLearn-specific ESLint plugin rules.\n * Includes AWS client configuration, JSX safety, SQL blocks, and database type safety.\n */\nexport function prairieLearnConfig(\n options?: PrairieLearnPluginOptions,\n): TSESLint.FlatConfig.ConfigArray {\n const { allowDbTypes = [] } = options ?? {};\n\n return [\n {\n plugins: {\n '@prairielearn': prairielearn,\n },\n\n rules: {\n '@prairielearn/aws-client-mandatory-config': 'error',\n '@prairielearn/aws-client-shared-config': 'error',\n '@prairielearn/jsx-no-dollar-interpolation': 'error',\n '@prairielearn/no-current-target-in-callback': 'error',\n '@prairielearn/no-hydrate-reslocals': 'error',\n '@prairielearn/no-unused-sql-blocks': 'error',\n '@prairielearn/safe-db-types': [\n 'error',\n {\n allowDbTypes,\n },\n ],\n },\n },\n ];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/configs/react.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAYzD;;GAEG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAAC,UAAU,CAAC,WAAW,CAiE7D","sourcesContent":["import eslintReact from '@eslint-react/eslint-plugin';\nimport type { TSESLint } from '@typescript-eslint/utils';\nimport jsxA11yX from 'eslint-plugin-jsx-a11y-x';\nimport reactHooks from 'eslint-plugin-react-hooks';\nimport reactYouMightNotNeedAnEffect from 'eslint-plugin-react-you-might-not-need-an-effect';\n\n// The eslint-react config has plugins/settings/rules but the type doesn't expose them all\nconst eslintReactConfig = eslintReact.configs['recommended-typescript'] as {\n plugins?: TSESLint.FlatConfig.Plugins;\n rules?: TSESLint.FlatConfig.Rules;\n settings?: TSESLint.FlatConfig.Settings;\n};\n\n/**\n * React, React hooks, accessibility, and related rules.\n */\nexport function reactConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n 'jsx-a11y-x': jsxA11yX,\n 'react-hooks': reactHooks,\n 'react-you-might-not-need-an-effect': reactYouMightNotNeedAnEffect,\n ...eslintReactConfig.plugins,\n },\n\n rules: {\n // React hooks\n 'react-hooks/exhaustive-deps': 'error',\n 'react-hooks/rules-of-hooks': 'error',\n\n // react-you-might-not-need-an-effect rules as errors\n ...Object.fromEntries(\n Object.keys(reactYouMightNotNeedAnEffect.configs?.recommended?.rules ?? {}).map(\n (ruleName: string) => [ruleName, 'error'],\n ),\n ),\n\n // eslint-react recommended rules as errors\n ...Object.fromEntries(\n Object.entries(eslintReactConfig.rules ?? {}).map(\n ([ruleName, severity]: [string, unknown]) => [\n ruleName,\n severity === 'off' ? 'off' : 'error',\n ],\n ),\n ),\n // We want to be able to use `useState` without the setter function for\n // https://tkdodo.eu/blog/react-query-fa-qs#2-the-queryclient-is-not-stable\n '@eslint-react/naming-convention/use-state': 'off',\n // Forbid `snake_case` props.\n '@eslint-react/no-forbidden-props': ['error', { forbid: ['/_/'] }],\n\n // jsx-a11y strict rules\n ...jsxA11yX.configs.strict.rules,\n 'jsx-a11y-x/anchor-ambiguous-text': 'error',\n 'jsx-a11y-x/lang': 'error',\n 'jsx-a11y-x/no-aria-hidden-on-focusable': 'error',\n // Bootstrap turns some elements into interactive elements.\n 'jsx-a11y-x/no-noninteractive-element-to-interactive-role': [\n 'error',\n {\n li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],\n ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],\n table: ['grid'],\n td: ['gridcell'],\n ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid', 'role'],\n },\n ],\n },\n\n settings: {\n 'jsx-a11y-x': {\n attributes: {\n for: ['htmlFor'],\n },\n },\n ...eslintReactConfig.settings,\n },\n },\n ];\n}\n"]}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/configs/react.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAezD;;GAEG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAAC,UAAU,CAAC,WAAW,CAgE7D","sourcesContent":["import eslintReact from '@eslint-react/eslint-plugin';\nimport type { TSESLint } from '@typescript-eslint/utils';\nimport jsxA11yX from 'eslint-plugin-jsx-a11y-x';\nimport reactHooks from 'eslint-plugin-react-hooks';\nimport reactYouMightNotNeedAnEffect from 'eslint-plugin-react-you-might-not-need-an-effect';\n\n// The eslint-react config has plugins/settings/rules but the type doesn't expose them all\nconst eslintReactConfig = eslintReact.configs['recommended-typescript'] as {\n plugins?: TSESLint.FlatConfig.Plugins;\n rules?: TSESLint.FlatConfig.Rules;\n settings?: TSESLint.FlatConfig.Settings;\n};\n\nconst disableConflictReactHooksConfig =\n eslintReact.configs['disable-conflict-eslint-plugin-react-hooks'];\n\n/**\n * React, React hooks, accessibility, and related rules.\n */\nexport function reactConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n 'jsx-a11y-x': jsxA11yX,\n 'react-hooks': reactHooks,\n 'react-you-might-not-need-an-effect': reactYouMightNotNeedAnEffect,\n ...eslintReactConfig.plugins,\n },\n\n rules: {\n // https://www.eslint-react.xyz/docs/migrating-from-eslint-plugin-react-hooks#migration-preset\n ...disableConflictReactHooksConfig.rules,\n\n // react-you-might-not-need-an-effect rules as errors\n ...Object.fromEntries(\n Object.keys(reactYouMightNotNeedAnEffect.configs?.recommended?.rules ?? {}).map(\n (ruleName: string) => [ruleName, 'error'],\n ),\n ),\n\n // eslint-react recommended rules as errors\n ...Object.fromEntries(\n Object.entries(eslintReactConfig.rules ?? {}).map(\n ([ruleName, severity]: [string, unknown]) => [\n ruleName,\n severity === 'off' ? 'off' : 'error',\n ],\n ),\n ),\n // We want to be able to use `useState` without the setter function for\n // https://tkdodo.eu/blog/react-query-fa-qs#2-the-queryclient-is-not-stable\n '@eslint-react/use-state': 'off',\n // Forbid `target=\"_blank\"` without `rel=\"noreferrer\"` for security reasons.\n '@eslint-react/dom-no-unsafe-target-blank': 'error',\n\n // jsx-a11y strict rules\n ...jsxA11yX.configs.strict.rules,\n 'jsx-a11y-x/anchor-ambiguous-text': 'error',\n 'jsx-a11y-x/lang': 'error',\n 'jsx-a11y-x/no-aria-hidden-on-focusable': 'error',\n // Bootstrap turns some elements into interactive elements.\n 'jsx-a11y-x/no-noninteractive-element-to-interactive-role': [\n 'error',\n {\n li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],\n ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],\n table: ['grid'],\n td: ['gridcell'],\n ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid', 'role'],\n },\n ],\n },\n\n settings: {\n 'jsx-a11y-x': {\n attributes: {\n for: ['htmlFor'],\n },\n },\n ...eslintReactConfig.settings,\n },\n },\n ];\n}\n"]}
@@ -4,6 +4,7 @@ import reactHooks from 'eslint-plugin-react-hooks';
4
4
  import reactYouMightNotNeedAnEffect from 'eslint-plugin-react-you-might-not-need-an-effect';
5
5
  // The eslint-react config has plugins/settings/rules but the type doesn't expose them all
6
6
  const eslintReactConfig = eslintReact.configs['recommended-typescript'];
7
+ const disableConflictReactHooksConfig = eslintReact.configs['disable-conflict-eslint-plugin-react-hooks'];
7
8
  /**
8
9
  * React, React hooks, accessibility, and related rules.
9
10
  */
@@ -17,9 +18,8 @@ export function reactConfig() {
17
18
  ...eslintReactConfig.plugins,
18
19
  },
19
20
  rules: {
20
- // React hooks
21
- 'react-hooks/exhaustive-deps': 'error',
22
- 'react-hooks/rules-of-hooks': 'error',
21
+ // https://www.eslint-react.xyz/docs/migrating-from-eslint-plugin-react-hooks#migration-preset
22
+ ...disableConflictReactHooksConfig.rules,
23
23
  // react-you-might-not-need-an-effect rules as errors
24
24
  ...Object.fromEntries(Object.keys(reactYouMightNotNeedAnEffect.configs?.recommended?.rules ?? {}).map((ruleName) => [ruleName, 'error'])),
25
25
  // eslint-react recommended rules as errors
@@ -29,9 +29,9 @@ export function reactConfig() {
29
29
  ])),
30
30
  // We want to be able to use `useState` without the setter function for
31
31
  // https://tkdodo.eu/blog/react-query-fa-qs#2-the-queryclient-is-not-stable
32
- '@eslint-react/naming-convention/use-state': 'off',
33
- // Forbid `snake_case` props.
34
- '@eslint-react/no-forbidden-props': ['error', { forbid: ['/_/'] }],
32
+ '@eslint-react/use-state': 'off',
33
+ // Forbid `target="_blank"` without `rel="noreferrer"` for security reasons.
34
+ '@eslint-react/dom-no-unsafe-target-blank': 'error',
35
35
  // jsx-a11y strict rules
36
36
  ...jsxA11yX.configs.strict.rules,
37
37
  'jsx-a11y-x/anchor-ambiguous-text': 'error',
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","sourceRoot":"","sources":["../../src/configs/react.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,6BAA6B,CAAC;AAEtD,OAAO,QAAQ,MAAM,0BAA0B,CAAC;AAChD,OAAO,UAAU,MAAM,2BAA2B,CAAC;AACnD,OAAO,4BAA4B,MAAM,kDAAkD,CAAC;AAE5F,0FAA0F;AAC1F,MAAM,iBAAiB,GAAG,WAAW,CAAC,OAAO,CAAC,wBAAwB,CAIrE,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO;QACL;YACE,OAAO,EAAE;gBACP,YAAY,EAAE,QAAQ;gBACtB,aAAa,EAAE,UAAU;gBACzB,oCAAoC,EAAE,4BAA4B;gBAClE,GAAG,iBAAiB,CAAC,OAAO;aAC7B;YAED,KAAK,EAAE;gBACL,cAAc;gBACd,6BAA6B,EAAE,OAAO;gBACtC,4BAA4B,EAAE,OAAO;gBAErC,qDAAqD;gBACrD,GAAG,MAAM,CAAC,WAAW,CACnB,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAC7E,CAAC,QAAgB,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAC1C,CACF;gBAED,2CAA2C;gBAC3C,GAAG,MAAM,CAAC,WAAW,CACnB,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAC/C,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAoB,EAAE,EAAE,CAAC;oBAC3C,QAAQ;oBACR,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO;iBACrC,CACF,CACF;gBACD,uEAAuE;gBACvE,2EAA2E;gBAC3E,2CAA2C,EAAE,KAAK;gBAClD,6BAA6B;gBAC7B,kCAAkC,EAAE,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;gBAElE,wBAAwB;gBACxB,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK;gBAChC,kCAAkC,EAAE,OAAO;gBAC3C,iBAAiB,EAAE,OAAO;gBAC1B,wCAAwC,EAAE,OAAO;gBACjD,2DAA2D;gBAC3D,0DAA0D,EAAE;oBAC1D,OAAO;oBACP;wBACE,EAAE,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC;wBACpD,EAAE,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC;wBAC/E,KAAK,EAAE,CAAC,MAAM,CAAC;wBACf,EAAE,EAAE,CAAC,UAAU,CAAC;wBAChB,EAAE,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC;qBACxF;iBACF;aACF;YAED,QAAQ,EAAE;gBACR,YAAY,EAAE;oBACZ,UAAU,EAAE;wBACV,GAAG,EAAE,CAAC,SAAS,CAAC;qBACjB;iBACF;gBACD,GAAG,iBAAiB,CAAC,QAAQ;aAC9B;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["import eslintReact from '@eslint-react/eslint-plugin';\nimport type { TSESLint } from '@typescript-eslint/utils';\nimport jsxA11yX from 'eslint-plugin-jsx-a11y-x';\nimport reactHooks from 'eslint-plugin-react-hooks';\nimport reactYouMightNotNeedAnEffect from 'eslint-plugin-react-you-might-not-need-an-effect';\n\n// The eslint-react config has plugins/settings/rules but the type doesn't expose them all\nconst eslintReactConfig = eslintReact.configs['recommended-typescript'] as {\n plugins?: TSESLint.FlatConfig.Plugins;\n rules?: TSESLint.FlatConfig.Rules;\n settings?: TSESLint.FlatConfig.Settings;\n};\n\n/**\n * React, React hooks, accessibility, and related rules.\n */\nexport function reactConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n 'jsx-a11y-x': jsxA11yX,\n 'react-hooks': reactHooks,\n 'react-you-might-not-need-an-effect': reactYouMightNotNeedAnEffect,\n ...eslintReactConfig.plugins,\n },\n\n rules: {\n // React hooks\n 'react-hooks/exhaustive-deps': 'error',\n 'react-hooks/rules-of-hooks': 'error',\n\n // react-you-might-not-need-an-effect rules as errors\n ...Object.fromEntries(\n Object.keys(reactYouMightNotNeedAnEffect.configs?.recommended?.rules ?? {}).map(\n (ruleName: string) => [ruleName, 'error'],\n ),\n ),\n\n // eslint-react recommended rules as errors\n ...Object.fromEntries(\n Object.entries(eslintReactConfig.rules ?? {}).map(\n ([ruleName, severity]: [string, unknown]) => [\n ruleName,\n severity === 'off' ? 'off' : 'error',\n ],\n ),\n ),\n // We want to be able to use `useState` without the setter function for\n // https://tkdodo.eu/blog/react-query-fa-qs#2-the-queryclient-is-not-stable\n '@eslint-react/naming-convention/use-state': 'off',\n // Forbid `snake_case` props.\n '@eslint-react/no-forbidden-props': ['error', { forbid: ['/_/'] }],\n\n // jsx-a11y strict rules\n ...jsxA11yX.configs.strict.rules,\n 'jsx-a11y-x/anchor-ambiguous-text': 'error',\n 'jsx-a11y-x/lang': 'error',\n 'jsx-a11y-x/no-aria-hidden-on-focusable': 'error',\n // Bootstrap turns some elements into interactive elements.\n 'jsx-a11y-x/no-noninteractive-element-to-interactive-role': [\n 'error',\n {\n li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],\n ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],\n table: ['grid'],\n td: ['gridcell'],\n ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid', 'role'],\n },\n ],\n },\n\n settings: {\n 'jsx-a11y-x': {\n attributes: {\n for: ['htmlFor'],\n },\n },\n ...eslintReactConfig.settings,\n },\n },\n ];\n}\n"]}
1
+ {"version":3,"file":"react.js","sourceRoot":"","sources":["../../src/configs/react.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,6BAA6B,CAAC;AAEtD,OAAO,QAAQ,MAAM,0BAA0B,CAAC;AAChD,OAAO,UAAU,MAAM,2BAA2B,CAAC;AACnD,OAAO,4BAA4B,MAAM,kDAAkD,CAAC;AAE5F,0FAA0F;AAC1F,MAAM,iBAAiB,GAAG,WAAW,CAAC,OAAO,CAAC,wBAAwB,CAIrE,CAAC;AAEF,MAAM,+BAA+B,GACnC,WAAW,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAC;AAEpE;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO;QACL;YACE,OAAO,EAAE;gBACP,YAAY,EAAE,QAAQ;gBACtB,aAAa,EAAE,UAAU;gBACzB,oCAAoC,EAAE,4BAA4B;gBAClE,GAAG,iBAAiB,CAAC,OAAO;aAC7B;YAED,KAAK,EAAE;gBACL,8FAA8F;gBAC9F,GAAG,+BAA+B,CAAC,KAAK;gBAExC,qDAAqD;gBACrD,GAAG,MAAM,CAAC,WAAW,CACnB,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAC7E,CAAC,QAAgB,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAC1C,CACF;gBAED,2CAA2C;gBAC3C,GAAG,MAAM,CAAC,WAAW,CACnB,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAC/C,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAoB,EAAE,EAAE,CAAC;oBAC3C,QAAQ;oBACR,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO;iBACrC,CACF,CACF;gBACD,uEAAuE;gBACvE,2EAA2E;gBAC3E,yBAAyB,EAAE,KAAK;gBAChC,4EAA4E;gBAC5E,0CAA0C,EAAE,OAAO;gBAEnD,wBAAwB;gBACxB,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK;gBAChC,kCAAkC,EAAE,OAAO;gBAC3C,iBAAiB,EAAE,OAAO;gBAC1B,wCAAwC,EAAE,OAAO;gBACjD,2DAA2D;gBAC3D,0DAA0D,EAAE;oBAC1D,OAAO;oBACP;wBACE,EAAE,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC;wBACpD,EAAE,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC;wBAC/E,KAAK,EAAE,CAAC,MAAM,CAAC;wBACf,EAAE,EAAE,CAAC,UAAU,CAAC;wBAChB,EAAE,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC;qBACxF;iBACF;aACF;YAED,QAAQ,EAAE;gBACR,YAAY,EAAE;oBACZ,UAAU,EAAE;wBACV,GAAG,EAAE,CAAC,SAAS,CAAC;qBACjB;iBACF;gBACD,GAAG,iBAAiB,CAAC,QAAQ;aAC9B;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["import eslintReact from '@eslint-react/eslint-plugin';\nimport type { TSESLint } from '@typescript-eslint/utils';\nimport jsxA11yX from 'eslint-plugin-jsx-a11y-x';\nimport reactHooks from 'eslint-plugin-react-hooks';\nimport reactYouMightNotNeedAnEffect from 'eslint-plugin-react-you-might-not-need-an-effect';\n\n// The eslint-react config has plugins/settings/rules but the type doesn't expose them all\nconst eslintReactConfig = eslintReact.configs['recommended-typescript'] as {\n plugins?: TSESLint.FlatConfig.Plugins;\n rules?: TSESLint.FlatConfig.Rules;\n settings?: TSESLint.FlatConfig.Settings;\n};\n\nconst disableConflictReactHooksConfig =\n eslintReact.configs['disable-conflict-eslint-plugin-react-hooks'];\n\n/**\n * React, React hooks, accessibility, and related rules.\n */\nexport function reactConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n 'jsx-a11y-x': jsxA11yX,\n 'react-hooks': reactHooks,\n 'react-you-might-not-need-an-effect': reactYouMightNotNeedAnEffect,\n ...eslintReactConfig.plugins,\n },\n\n rules: {\n // https://www.eslint-react.xyz/docs/migrating-from-eslint-plugin-react-hooks#migration-preset\n ...disableConflictReactHooksConfig.rules,\n\n // react-you-might-not-need-an-effect rules as errors\n ...Object.fromEntries(\n Object.keys(reactYouMightNotNeedAnEffect.configs?.recommended?.rules ?? {}).map(\n (ruleName: string) => [ruleName, 'error'],\n ),\n ),\n\n // eslint-react recommended rules as errors\n ...Object.fromEntries(\n Object.entries(eslintReactConfig.rules ?? {}).map(\n ([ruleName, severity]: [string, unknown]) => [\n ruleName,\n severity === 'off' ? 'off' : 'error',\n ],\n ),\n ),\n // We want to be able to use `useState` without the setter function for\n // https://tkdodo.eu/blog/react-query-fa-qs#2-the-queryclient-is-not-stable\n '@eslint-react/use-state': 'off',\n // Forbid `target=\"_blank\"` without `rel=\"noreferrer\"` for security reasons.\n '@eslint-react/dom-no-unsafe-target-blank': 'error',\n\n // jsx-a11y strict rules\n ...jsxA11yX.configs.strict.rules,\n 'jsx-a11y-x/anchor-ambiguous-text': 'error',\n 'jsx-a11y-x/lang': 'error',\n 'jsx-a11y-x/no-aria-hidden-on-focusable': 'error',\n // Bootstrap turns some elements into interactive elements.\n 'jsx-a11y-x/no-noninteractive-element-to-interactive-role': [\n 'error',\n {\n li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],\n ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],\n table: ['grid'],\n td: ['gridcell'],\n ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid', 'role'],\n },\n ],\n },\n\n settings: {\n 'jsx-a11y-x': {\n attributes: {\n for: ['htmlFor'],\n },\n },\n ...eslintReactConfig.settings,\n },\n },\n ];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tanstack.d.ts","sourceRoot":"","sources":["../../src/configs/tanstack.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEzD;;GAEG;AACH,wBAAgB,cAAc,IAAI,QAAQ,CAAC,UAAU,CAAC,WAAW,CAchE","sourcesContent":["import pluginQuery from '@tanstack/eslint-plugin-query';\nimport type { TSESLint } from '@typescript-eslint/utils';\n\n/**\n * TanStack Query (React Query) rules.\n */\nexport function tanstackConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n '@tanstack/query': pluginQuery,\n },\n\n rules: {\n // https://github.com/TanStack/query/blob/6402d756b702ac560b69a5ce84d6e4e764b96451/packages/eslint-plugin-query/src/index.ts#L43\n ...pluginQuery.configs['flat/recommended'][0].rules,\n '@tanstack/query/no-rest-destructuring': 'error',\n },\n },\n ];\n}\n"]}
1
+ {"version":3,"file":"tanstack.d.ts","sourceRoot":"","sources":["../../src/configs/tanstack.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEzD;;GAEG;AACH,wBAAgB,cAAc,IAAI,QAAQ,CAAC,UAAU,CAAC,WAAW,CAiBhE","sourcesContent":["import pluginQuery from '@tanstack/eslint-plugin-query';\nimport type { TSESLint } from '@typescript-eslint/utils';\n\n/**\n * TanStack Query (React Query) rules.\n */\nexport function tanstackConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n '@tanstack/query': pluginQuery,\n },\n\n rules: {\n // https://github.com/TanStack/query/blob/6402d756b702ac560b69a5ce84d6e4e764b96451/packages/eslint-plugin-query/src/index.ts#L43\n ...pluginQuery.configs['flat/recommended'][0].rules,\n // Disabled: tRPC proxy objects in query keys trigger false positives\n // since the proxy is not serializable and the rule can't introspect it.\n '@tanstack/query/exhaustive-deps': 'off',\n '@tanstack/query/no-rest-destructuring': 'error',\n },\n },\n ];\n}\n"]}
@@ -11,6 +11,9 @@ export function tanstackConfig() {
11
11
  rules: {
12
12
  // https://github.com/TanStack/query/blob/6402d756b702ac560b69a5ce84d6e4e764b96451/packages/eslint-plugin-query/src/index.ts#L43
13
13
  ...pluginQuery.configs['flat/recommended'][0].rules,
14
+ // Disabled: tRPC proxy objects in query keys trigger false positives
15
+ // since the proxy is not serializable and the rule can't introspect it.
16
+ '@tanstack/query/exhaustive-deps': 'off',
14
17
  '@tanstack/query/no-rest-destructuring': 'error',
15
18
  },
16
19
  },
@@ -1 +1 @@
1
- {"version":3,"file":"tanstack.js","sourceRoot":"","sources":["../../src/configs/tanstack.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,+BAA+B,CAAC;AAGxD;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL;YACE,OAAO,EAAE;gBACP,iBAAiB,EAAE,WAAW;aAC/B;YAED,KAAK,EAAE;gBACL,gIAAgI;gBAChI,GAAG,WAAW,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK;gBACnD,uCAAuC,EAAE,OAAO;aACjD;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["import pluginQuery from '@tanstack/eslint-plugin-query';\nimport type { TSESLint } from '@typescript-eslint/utils';\n\n/**\n * TanStack Query (React Query) rules.\n */\nexport function tanstackConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n '@tanstack/query': pluginQuery,\n },\n\n rules: {\n // https://github.com/TanStack/query/blob/6402d756b702ac560b69a5ce84d6e4e764b96451/packages/eslint-plugin-query/src/index.ts#L43\n ...pluginQuery.configs['flat/recommended'][0].rules,\n '@tanstack/query/no-rest-destructuring': 'error',\n },\n },\n ];\n}\n"]}
1
+ {"version":3,"file":"tanstack.js","sourceRoot":"","sources":["../../src/configs/tanstack.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,+BAA+B,CAAC;AAGxD;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL;YACE,OAAO,EAAE;gBACP,iBAAiB,EAAE,WAAW;aAC/B;YAED,KAAK,EAAE;gBACL,gIAAgI;gBAChI,GAAG,WAAW,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK;gBACnD,qEAAqE;gBACrE,wEAAwE;gBACxE,iCAAiC,EAAE,KAAK;gBACxC,uCAAuC,EAAE,OAAO;aACjD;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["import pluginQuery from '@tanstack/eslint-plugin-query';\nimport type { TSESLint } from '@typescript-eslint/utils';\n\n/**\n * TanStack Query (React Query) rules.\n */\nexport function tanstackConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n '@tanstack/query': pluginQuery,\n },\n\n rules: {\n // https://github.com/TanStack/query/blob/6402d756b702ac560b69a5ce84d6e4e764b96451/packages/eslint-plugin-query/src/index.ts#L43\n ...pluginQuery.configs['flat/recommended'][0].rules,\n // Disabled: tRPC proxy objects in query keys trigger false positives\n // since the proxy is not serializable and the rule can't introspect it.\n '@tanstack/query/exhaustive-deps': 'off',\n '@tanstack/query/no-rest-destructuring': 'error',\n },\n },\n ];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"unicorn.d.ts","sourceRoot":"","sources":["../../src/configs/unicorn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGzD;;GAEG;AACH,wBAAgB,aAAa,IAAI,QAAQ,CAAC,UAAU,CAAC,WAAW,CA6E/D","sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\nimport eslintPluginUnicorn from 'eslint-plugin-unicorn';\n\n/**\n * Unicorn plugin rules with PrairieLearn-specific overrides.\n */\nexport function unicornConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n unicorn: eslintPluginUnicorn,\n },\n\n rules: {\n ...eslintPluginUnicorn.configs.recommended.rules,\n\n // These rules don't align with our own style guidelines\n 'unicorn/filename-case': 'off', // We don't enforce specific styles for filenames\n 'unicorn/no-anonymous-default-export': 'off', // We use this for all of our pages\n 'unicorn/no-array-callback-reference': 'off',\n 'unicorn/no-array-method-this-argument': 'off',\n 'unicorn/no-array-reduce': 'off', // Sometimes, an array reduce is more readable\n 'unicorn/no-array-reverse': 'off', // `Array.prototype.toReversed` is not yet supported by our TypeScript config\n 'unicorn/no-array-sort': 'off', // Disabling for the time being to avoid unnecessary diffs\n 'unicorn/no-hex-escape': 'off',\n 'unicorn/no-lonely-if': 'off', // https://github.com/PrairieLearn/PrairieLearn/pull/12546#discussion_r2252261293\n 'unicorn/no-null': 'off',\n 'unicorn/no-useless-undefined': 'off', // Explicit undefined is more readable than implicit undefined\n 'unicorn/prefer-code-point': 'off',\n 'unicorn/prefer-dom-node-dataset': 'off', // https://github.com/PrairieLearn/PrairieLearn/pull/12546#discussion_r2261095992\n 'unicorn/prefer-export-from': 'off', // https://github.com/PrairieLearn/PrairieLearn/pull/12546#discussion_r2252265000\n 'unicorn/prefer-string-raw': 'off', // We don't use `String.raw` in our codebase\n 'unicorn/prefer-ternary': 'off', // if/else can be more readable than a ternary\n 'unicorn/prefer-top-level-await': 'off', // we use this on a lot of pages\n 'unicorn/prefer-type-error': 'off',\n 'unicorn/prevent-abbreviations': 'off',\n\n // These rules have many violations. Decisions about enabling the rules have been deferred.\n 'unicorn/catch-error-name': 'off', // 200+ violations\n 'unicorn/no-array-for-each': 'off', // 300+ violations\n 'unicorn/no-await-expression-member': 'off', // 400+ violations\n 'unicorn/no-negated-condition': 'off', // 150+ violations\n 'unicorn/prefer-global-this': 'off', // 150+ violations\n 'unicorn/prefer-node-protocol': 'off', // 100+ violations\n 'unicorn/switch-case-braces': 'off', // 200+ violations\n\n // TODO: investigate, < 100 violations\n 'unicorn/consistent-assert': 'off',\n 'unicorn/consistent-function-scoping': 'off',\n 'unicorn/escape-case': 'off',\n 'unicorn/import-style': 'off',\n 'unicorn/numeric-separators-style': 'off',\n 'unicorn/prefer-query-selector': 'off',\n 'unicorn/prefer-spread': 'off',\n 'unicorn/prefer-switch': 'off',\n 'unicorn/text-encoding-identifier-case': 'off',\n\n // TODO: investigated and manual fixes are required\n 'unicorn/no-object-as-default-parameter': 'off',\n 'unicorn/prefer-add-event-listener': 'off',\n 'unicorn/prefer-dom-node-text-content': 'off',\n 'unicorn/prefer-event-target': 'off',\n\n // False positives\n 'unicorn/error-message': 'off',\n 'unicorn/prefer-at': 'off', // https://github.com/microsoft/TypeScript/issues/47660#issuecomment-3146907649\n 'unicorn/throw-new-error': 'off',\n\n // Duplicated from other lint rules\n 'unicorn/no-static-only-class': 'off',\n 'unicorn/no-this-assignment': 'off',\n 'unicorn/prefer-module': 'off',\n\n // https://github.com/PrairieLearn/PrairieLearn/pull/12545/files#r2252069292\n 'unicorn/no-for-loop': 'off',\n\n // Conflicts with prettier\n 'unicorn/no-nested-ternary': 'off',\n 'unicorn/number-literal-case': 'off',\n 'unicorn/template-indent': 'off',\n },\n },\n ];\n}\n"]}
1
+ {"version":3,"file":"unicorn.d.ts","sourceRoot":"","sources":["../../src/configs/unicorn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGzD;;GAEG;AACH,wBAAgB,aAAa,IAAI,QAAQ,CAAC,UAAU,CAAC,WAAW,CA8E/D","sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\nimport eslintPluginUnicorn from 'eslint-plugin-unicorn';\n\n/**\n * Unicorn plugin rules with PrairieLearn-specific overrides.\n */\nexport function unicornConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n unicorn: eslintPluginUnicorn,\n },\n\n rules: {\n ...eslintPluginUnicorn.configs.recommended.rules,\n\n // These rules don't align with our own style guidelines\n 'unicorn/filename-case': 'off', // We don't enforce specific styles for filenames\n 'unicorn/no-anonymous-default-export': 'off', // We use this for all of our pages\n 'unicorn/no-array-callback-reference': 'off',\n 'unicorn/no-array-method-this-argument': 'off',\n 'unicorn/no-array-reduce': 'off', // Sometimes, an array reduce is more readable\n 'unicorn/no-array-reverse': 'off', // `Array.prototype.toReversed` is not yet supported by our TypeScript config\n 'unicorn/no-array-sort': 'off', // Disabling for the time being to avoid unnecessary diffs\n 'unicorn/no-hex-escape': 'off',\n 'unicorn/no-lonely-if': 'off', // https://github.com/PrairieLearn/PrairieLearn/pull/12546#discussion_r2252261293\n 'unicorn/no-null': 'off',\n 'unicorn/no-useless-undefined': 'off', // Explicit undefined is more readable than implicit undefined\n 'unicorn/prefer-code-point': 'off',\n 'unicorn/prefer-dom-node-dataset': 'off', // https://github.com/PrairieLearn/PrairieLearn/pull/12546#discussion_r2261095992\n 'unicorn/prefer-export-from': 'off', // https://github.com/PrairieLearn/PrairieLearn/pull/12546#discussion_r2252265000\n 'unicorn/prefer-string-raw': 'off', // We don't use `String.raw` in our codebase\n 'unicorn/prefer-ternary': 'off', // if/else can be more readable than a ternary\n 'unicorn/prefer-top-level-await': 'off', // we use this on a lot of pages\n 'unicorn/prefer-type-error': 'off',\n 'unicorn/prevent-abbreviations': 'off',\n\n // These rules have many violations. Decisions about enabling the rules have been deferred.\n 'unicorn/catch-error-name': 'off', // 200+ violations\n 'unicorn/no-array-for-each': 'off', // 300+ violations\n 'unicorn/no-await-expression-member': 'off', // 400+ violations\n 'unicorn/no-negated-condition': 'off', // 150+ violations\n 'unicorn/prefer-global-this': 'off', // 150+ violations\n 'unicorn/prefer-node-protocol': 'off', // 100+ violations\n 'unicorn/switch-case-braces': 'off', // 200+ violations\n\n // TODO: investigate, < 100 violations\n 'unicorn/consistent-assert': 'off',\n 'unicorn/consistent-function-scoping': 'off',\n 'unicorn/escape-case': 'off',\n 'unicorn/import-style': 'off',\n 'unicorn/numeric-separators-style': 'off',\n 'unicorn/prefer-query-selector': 'off',\n 'unicorn/prefer-spread': 'off',\n 'unicorn/prefer-switch': 'off',\n 'unicorn/text-encoding-identifier-case': 'off',\n\n // TODO: investigated and manual fixes are required\n 'unicorn/no-object-as-default-parameter': 'off',\n 'unicorn/prefer-add-event-listener': 'off',\n 'unicorn/prefer-dom-node-text-content': 'off',\n 'unicorn/prefer-event-target': 'off',\n\n // False positives\n 'unicorn/error-message': 'off',\n 'unicorn/prefer-array-find': ['error', { checkFromLast: false }], // findLast is unavailable in our target lib\n 'unicorn/prefer-at': 'off', // https://github.com/microsoft/TypeScript/issues/47660#issuecomment-3146907649\n 'unicorn/throw-new-error': 'off',\n\n // Duplicated from other lint rules\n 'unicorn/no-static-only-class': 'off',\n 'unicorn/no-this-assignment': 'off',\n 'unicorn/prefer-module': 'off',\n\n // https://github.com/PrairieLearn/PrairieLearn/pull/12545/files#r2252069292\n 'unicorn/no-for-loop': 'off',\n\n // Conflicts with prettier\n 'unicorn/no-nested-ternary': 'off',\n 'unicorn/number-literal-case': 'off',\n 'unicorn/template-indent': 'off',\n },\n },\n ];\n}\n"]}
@@ -55,6 +55,7 @@ export function unicornConfig() {
55
55
  'unicorn/prefer-event-target': 'off',
56
56
  // False positives
57
57
  'unicorn/error-message': 'off',
58
+ 'unicorn/prefer-array-find': ['error', { checkFromLast: false }], // findLast is unavailable in our target lib
58
59
  'unicorn/prefer-at': 'off', // https://github.com/microsoft/TypeScript/issues/47660#issuecomment-3146907649
59
60
  'unicorn/throw-new-error': 'off',
60
61
  // Duplicated from other lint rules
@@ -1 +1 @@
1
- {"version":3,"file":"unicorn.js","sourceRoot":"","sources":["../../src/configs/unicorn.ts"],"names":[],"mappings":"AACA,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AAExD;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO;QACL;YACE,OAAO,EAAE;gBACP,OAAO,EAAE,mBAAmB;aAC7B;YAED,KAAK,EAAE;gBACL,GAAG,mBAAmB,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK;gBAEhD,wDAAwD;gBACxD,uBAAuB,EAAE,KAAK,EAAE,iDAAiD;gBACjF,qCAAqC,EAAE,KAAK,EAAE,mCAAmC;gBACjF,qCAAqC,EAAE,KAAK;gBAC5C,uCAAuC,EAAE,KAAK;gBAC9C,yBAAyB,EAAE,KAAK,EAAE,8CAA8C;gBAChF,0BAA0B,EAAE,KAAK,EAAE,6EAA6E;gBAChH,uBAAuB,EAAE,KAAK,EAAE,0DAA0D;gBAC1F,uBAAuB,EAAE,KAAK;gBAC9B,sBAAsB,EAAE,KAAK,EAAE,iFAAiF;gBAChH,iBAAiB,EAAE,KAAK;gBACxB,8BAA8B,EAAE,KAAK,EAAE,8DAA8D;gBACrG,2BAA2B,EAAE,KAAK;gBAClC,iCAAiC,EAAE,KAAK,EAAE,iFAAiF;gBAC3H,4BAA4B,EAAE,KAAK,EAAE,iFAAiF;gBACtH,2BAA2B,EAAE,KAAK,EAAE,4CAA4C;gBAChF,wBAAwB,EAAE,KAAK,EAAE,8CAA8C;gBAC/E,gCAAgC,EAAE,KAAK,EAAE,gCAAgC;gBACzE,2BAA2B,EAAE,KAAK;gBAClC,+BAA+B,EAAE,KAAK;gBAEtC,2FAA2F;gBAC3F,0BAA0B,EAAE,KAAK,EAAE,kBAAkB;gBACrD,2BAA2B,EAAE,KAAK,EAAE,kBAAkB;gBACtD,oCAAoC,EAAE,KAAK,EAAE,kBAAkB;gBAC/D,8BAA8B,EAAE,KAAK,EAAE,kBAAkB;gBACzD,4BAA4B,EAAE,KAAK,EAAE,kBAAkB;gBACvD,8BAA8B,EAAE,KAAK,EAAE,kBAAkB;gBACzD,4BAA4B,EAAE,KAAK,EAAE,kBAAkB;gBAEvD,sCAAsC;gBACtC,2BAA2B,EAAE,KAAK;gBAClC,qCAAqC,EAAE,KAAK;gBAC5C,qBAAqB,EAAE,KAAK;gBAC5B,sBAAsB,EAAE,KAAK;gBAC7B,kCAAkC,EAAE,KAAK;gBACzC,+BAA+B,EAAE,KAAK;gBACtC,uBAAuB,EAAE,KAAK;gBAC9B,uBAAuB,EAAE,KAAK;gBAC9B,uCAAuC,EAAE,KAAK;gBAE9C,mDAAmD;gBACnD,wCAAwC,EAAE,KAAK;gBAC/C,mCAAmC,EAAE,KAAK;gBAC1C,sCAAsC,EAAE,KAAK;gBAC7C,6BAA6B,EAAE,KAAK;gBAEpC,kBAAkB;gBAClB,uBAAuB,EAAE,KAAK;gBAC9B,mBAAmB,EAAE,KAAK,EAAE,+EAA+E;gBAC3G,yBAAyB,EAAE,KAAK;gBAEhC,mCAAmC;gBACnC,8BAA8B,EAAE,KAAK;gBACrC,4BAA4B,EAAE,KAAK;gBACnC,uBAAuB,EAAE,KAAK;gBAE9B,4EAA4E;gBAC5E,qBAAqB,EAAE,KAAK;gBAE5B,0BAA0B;gBAC1B,2BAA2B,EAAE,KAAK;gBAClC,6BAA6B,EAAE,KAAK;gBACpC,yBAAyB,EAAE,KAAK;aACjC;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\nimport eslintPluginUnicorn from 'eslint-plugin-unicorn';\n\n/**\n * Unicorn plugin rules with PrairieLearn-specific overrides.\n */\nexport function unicornConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n unicorn: eslintPluginUnicorn,\n },\n\n rules: {\n ...eslintPluginUnicorn.configs.recommended.rules,\n\n // These rules don't align with our own style guidelines\n 'unicorn/filename-case': 'off', // We don't enforce specific styles for filenames\n 'unicorn/no-anonymous-default-export': 'off', // We use this for all of our pages\n 'unicorn/no-array-callback-reference': 'off',\n 'unicorn/no-array-method-this-argument': 'off',\n 'unicorn/no-array-reduce': 'off', // Sometimes, an array reduce is more readable\n 'unicorn/no-array-reverse': 'off', // `Array.prototype.toReversed` is not yet supported by our TypeScript config\n 'unicorn/no-array-sort': 'off', // Disabling for the time being to avoid unnecessary diffs\n 'unicorn/no-hex-escape': 'off',\n 'unicorn/no-lonely-if': 'off', // https://github.com/PrairieLearn/PrairieLearn/pull/12546#discussion_r2252261293\n 'unicorn/no-null': 'off',\n 'unicorn/no-useless-undefined': 'off', // Explicit undefined is more readable than implicit undefined\n 'unicorn/prefer-code-point': 'off',\n 'unicorn/prefer-dom-node-dataset': 'off', // https://github.com/PrairieLearn/PrairieLearn/pull/12546#discussion_r2261095992\n 'unicorn/prefer-export-from': 'off', // https://github.com/PrairieLearn/PrairieLearn/pull/12546#discussion_r2252265000\n 'unicorn/prefer-string-raw': 'off', // We don't use `String.raw` in our codebase\n 'unicorn/prefer-ternary': 'off', // if/else can be more readable than a ternary\n 'unicorn/prefer-top-level-await': 'off', // we use this on a lot of pages\n 'unicorn/prefer-type-error': 'off',\n 'unicorn/prevent-abbreviations': 'off',\n\n // These rules have many violations. Decisions about enabling the rules have been deferred.\n 'unicorn/catch-error-name': 'off', // 200+ violations\n 'unicorn/no-array-for-each': 'off', // 300+ violations\n 'unicorn/no-await-expression-member': 'off', // 400+ violations\n 'unicorn/no-negated-condition': 'off', // 150+ violations\n 'unicorn/prefer-global-this': 'off', // 150+ violations\n 'unicorn/prefer-node-protocol': 'off', // 100+ violations\n 'unicorn/switch-case-braces': 'off', // 200+ violations\n\n // TODO: investigate, < 100 violations\n 'unicorn/consistent-assert': 'off',\n 'unicorn/consistent-function-scoping': 'off',\n 'unicorn/escape-case': 'off',\n 'unicorn/import-style': 'off',\n 'unicorn/numeric-separators-style': 'off',\n 'unicorn/prefer-query-selector': 'off',\n 'unicorn/prefer-spread': 'off',\n 'unicorn/prefer-switch': 'off',\n 'unicorn/text-encoding-identifier-case': 'off',\n\n // TODO: investigated and manual fixes are required\n 'unicorn/no-object-as-default-parameter': 'off',\n 'unicorn/prefer-add-event-listener': 'off',\n 'unicorn/prefer-dom-node-text-content': 'off',\n 'unicorn/prefer-event-target': 'off',\n\n // False positives\n 'unicorn/error-message': 'off',\n 'unicorn/prefer-at': 'off', // https://github.com/microsoft/TypeScript/issues/47660#issuecomment-3146907649\n 'unicorn/throw-new-error': 'off',\n\n // Duplicated from other lint rules\n 'unicorn/no-static-only-class': 'off',\n 'unicorn/no-this-assignment': 'off',\n 'unicorn/prefer-module': 'off',\n\n // https://github.com/PrairieLearn/PrairieLearn/pull/12545/files#r2252069292\n 'unicorn/no-for-loop': 'off',\n\n // Conflicts with prettier\n 'unicorn/no-nested-ternary': 'off',\n 'unicorn/number-literal-case': 'off',\n 'unicorn/template-indent': 'off',\n },\n },\n ];\n}\n"]}
1
+ {"version":3,"file":"unicorn.js","sourceRoot":"","sources":["../../src/configs/unicorn.ts"],"names":[],"mappings":"AACA,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AAExD;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO;QACL;YACE,OAAO,EAAE;gBACP,OAAO,EAAE,mBAAmB;aAC7B;YAED,KAAK,EAAE;gBACL,GAAG,mBAAmB,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK;gBAEhD,wDAAwD;gBACxD,uBAAuB,EAAE,KAAK,EAAE,iDAAiD;gBACjF,qCAAqC,EAAE,KAAK,EAAE,mCAAmC;gBACjF,qCAAqC,EAAE,KAAK;gBAC5C,uCAAuC,EAAE,KAAK;gBAC9C,yBAAyB,EAAE,KAAK,EAAE,8CAA8C;gBAChF,0BAA0B,EAAE,KAAK,EAAE,6EAA6E;gBAChH,uBAAuB,EAAE,KAAK,EAAE,0DAA0D;gBAC1F,uBAAuB,EAAE,KAAK;gBAC9B,sBAAsB,EAAE,KAAK,EAAE,iFAAiF;gBAChH,iBAAiB,EAAE,KAAK;gBACxB,8BAA8B,EAAE,KAAK,EAAE,8DAA8D;gBACrG,2BAA2B,EAAE,KAAK;gBAClC,iCAAiC,EAAE,KAAK,EAAE,iFAAiF;gBAC3H,4BAA4B,EAAE,KAAK,EAAE,iFAAiF;gBACtH,2BAA2B,EAAE,KAAK,EAAE,4CAA4C;gBAChF,wBAAwB,EAAE,KAAK,EAAE,8CAA8C;gBAC/E,gCAAgC,EAAE,KAAK,EAAE,gCAAgC;gBACzE,2BAA2B,EAAE,KAAK;gBAClC,+BAA+B,EAAE,KAAK;gBAEtC,2FAA2F;gBAC3F,0BAA0B,EAAE,KAAK,EAAE,kBAAkB;gBACrD,2BAA2B,EAAE,KAAK,EAAE,kBAAkB;gBACtD,oCAAoC,EAAE,KAAK,EAAE,kBAAkB;gBAC/D,8BAA8B,EAAE,KAAK,EAAE,kBAAkB;gBACzD,4BAA4B,EAAE,KAAK,EAAE,kBAAkB;gBACvD,8BAA8B,EAAE,KAAK,EAAE,kBAAkB;gBACzD,4BAA4B,EAAE,KAAK,EAAE,kBAAkB;gBAEvD,sCAAsC;gBACtC,2BAA2B,EAAE,KAAK;gBAClC,qCAAqC,EAAE,KAAK;gBAC5C,qBAAqB,EAAE,KAAK;gBAC5B,sBAAsB,EAAE,KAAK;gBAC7B,kCAAkC,EAAE,KAAK;gBACzC,+BAA+B,EAAE,KAAK;gBACtC,uBAAuB,EAAE,KAAK;gBAC9B,uBAAuB,EAAE,KAAK;gBAC9B,uCAAuC,EAAE,KAAK;gBAE9C,mDAAmD;gBACnD,wCAAwC,EAAE,KAAK;gBAC/C,mCAAmC,EAAE,KAAK;gBAC1C,sCAAsC,EAAE,KAAK;gBAC7C,6BAA6B,EAAE,KAAK;gBAEpC,kBAAkB;gBAClB,uBAAuB,EAAE,KAAK;gBAC9B,2BAA2B,EAAE,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,EAAE,4CAA4C;gBAC9G,mBAAmB,EAAE,KAAK,EAAE,+EAA+E;gBAC3G,yBAAyB,EAAE,KAAK;gBAEhC,mCAAmC;gBACnC,8BAA8B,EAAE,KAAK;gBACrC,4BAA4B,EAAE,KAAK;gBACnC,uBAAuB,EAAE,KAAK;gBAE9B,4EAA4E;gBAC5E,qBAAqB,EAAE,KAAK;gBAE5B,0BAA0B;gBAC1B,2BAA2B,EAAE,KAAK;gBAClC,6BAA6B,EAAE,KAAK;gBACpC,yBAAyB,EAAE,KAAK;aACjC;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\nimport eslintPluginUnicorn from 'eslint-plugin-unicorn';\n\n/**\n * Unicorn plugin rules with PrairieLearn-specific overrides.\n */\nexport function unicornConfig(): TSESLint.FlatConfig.ConfigArray {\n return [\n {\n plugins: {\n unicorn: eslintPluginUnicorn,\n },\n\n rules: {\n ...eslintPluginUnicorn.configs.recommended.rules,\n\n // These rules don't align with our own style guidelines\n 'unicorn/filename-case': 'off', // We don't enforce specific styles for filenames\n 'unicorn/no-anonymous-default-export': 'off', // We use this for all of our pages\n 'unicorn/no-array-callback-reference': 'off',\n 'unicorn/no-array-method-this-argument': 'off',\n 'unicorn/no-array-reduce': 'off', // Sometimes, an array reduce is more readable\n 'unicorn/no-array-reverse': 'off', // `Array.prototype.toReversed` is not yet supported by our TypeScript config\n 'unicorn/no-array-sort': 'off', // Disabling for the time being to avoid unnecessary diffs\n 'unicorn/no-hex-escape': 'off',\n 'unicorn/no-lonely-if': 'off', // https://github.com/PrairieLearn/PrairieLearn/pull/12546#discussion_r2252261293\n 'unicorn/no-null': 'off',\n 'unicorn/no-useless-undefined': 'off', // Explicit undefined is more readable than implicit undefined\n 'unicorn/prefer-code-point': 'off',\n 'unicorn/prefer-dom-node-dataset': 'off', // https://github.com/PrairieLearn/PrairieLearn/pull/12546#discussion_r2261095992\n 'unicorn/prefer-export-from': 'off', // https://github.com/PrairieLearn/PrairieLearn/pull/12546#discussion_r2252265000\n 'unicorn/prefer-string-raw': 'off', // We don't use `String.raw` in our codebase\n 'unicorn/prefer-ternary': 'off', // if/else can be more readable than a ternary\n 'unicorn/prefer-top-level-await': 'off', // we use this on a lot of pages\n 'unicorn/prefer-type-error': 'off',\n 'unicorn/prevent-abbreviations': 'off',\n\n // These rules have many violations. Decisions about enabling the rules have been deferred.\n 'unicorn/catch-error-name': 'off', // 200+ violations\n 'unicorn/no-array-for-each': 'off', // 300+ violations\n 'unicorn/no-await-expression-member': 'off', // 400+ violations\n 'unicorn/no-negated-condition': 'off', // 150+ violations\n 'unicorn/prefer-global-this': 'off', // 150+ violations\n 'unicorn/prefer-node-protocol': 'off', // 100+ violations\n 'unicorn/switch-case-braces': 'off', // 200+ violations\n\n // TODO: investigate, < 100 violations\n 'unicorn/consistent-assert': 'off',\n 'unicorn/consistent-function-scoping': 'off',\n 'unicorn/escape-case': 'off',\n 'unicorn/import-style': 'off',\n 'unicorn/numeric-separators-style': 'off',\n 'unicorn/prefer-query-selector': 'off',\n 'unicorn/prefer-spread': 'off',\n 'unicorn/prefer-switch': 'off',\n 'unicorn/text-encoding-identifier-case': 'off',\n\n // TODO: investigated and manual fixes are required\n 'unicorn/no-object-as-default-parameter': 'off',\n 'unicorn/prefer-add-event-listener': 'off',\n 'unicorn/prefer-dom-node-text-content': 'off',\n 'unicorn/prefer-event-target': 'off',\n\n // False positives\n 'unicorn/error-message': 'off',\n 'unicorn/prefer-array-find': ['error', { checkFromLast: false }], // findLast is unavailable in our target lib\n 'unicorn/prefer-at': 'off', // https://github.com/microsoft/TypeScript/issues/47660#issuecomment-3146907649\n 'unicorn/throw-new-error': 'off',\n\n // Duplicated from other lint rules\n 'unicorn/no-static-only-class': 'off',\n 'unicorn/no-this-assignment': 'off',\n 'unicorn/prefer-module': 'off',\n\n // https://github.com/PrairieLearn/PrairieLearn/pull/12545/files#r2252069292\n 'unicorn/no-for-loop': 'off',\n\n // Conflicts with prettier\n 'unicorn/no-nested-ternary': 'off',\n 'unicorn/number-literal-case': 'off',\n 'unicorn/template-indent': 'off',\n },\n },\n ];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AASzD,OAAO,EAAE,KAAK,yBAAyB,EAAsB,MAAM,2BAA2B,CAAC;AAQ/F,MAAM,WAAW,+BAA+B;IAC9C;;;OAGG;IACH,eAAe,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE/B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,mBAAmB,CAAC,EAAE,yBAAyB,CAAC;IAEhD;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB;;OAEG;IACH,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,+BAA+B,GACvC,QAAQ,CAAC,UAAU,CAAC,WAAW,CAyFjC;AAGD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAC/F,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC","sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\nimport { globalIgnores } from 'eslint/config';\nimport tseslint from 'typescript-eslint';\n\nimport { baseConfig } from './configs/base.js';\nimport { importsConfig } from './configs/imports.js';\nimport { jsdocConfig } from './configs/jsdoc.js';\nimport { lodashConfig } from './configs/lodash.js';\nimport { perfectionistConfig } from './configs/perfectionist.js';\nimport { type PrairieLearnPluginOptions, prairieLearnConfig } from './configs/prairielearn.js';\nimport { reactConfig } from './configs/react.js';\nimport { stylisticConfig } from './configs/stylistic.js';\nimport { tanstackConfig } from './configs/tanstack.js';\nimport { typescriptConfig, typescriptTypeAwareRules } from './configs/typescript.js';\nimport { unicornConfig } from './configs/unicorn.js';\nimport { vitestConfig } from './configs/vitest.js';\n\nexport interface PrairieLearnEslintConfigOptions {\n /**\n * Root directory for TypeScript project service.\n * Required for type-aware linting.\n */\n tsconfigRootDir: string;\n\n /**\n * Glob patterns for files to apply type-aware rules to.\n * @default ['**\\/*.{ts,tsx}']\n */\n typeAwareFiles?: string[];\n\n /**\n * Files to allow in defaultProject for type-aware linting.\n * Useful for config files outside the main tsconfig.\n * @default ['*.config.ts', '*.config.mts', 'vitest.config.ts']\n */\n allowDefaultProject?: string[];\n\n /**\n * Enable `@prairielearn/eslint-plugin` rules.\n * @default true\n */\n prairielearn?: boolean;\n\n /**\n * Options for the `@prairielearn/eslint-plugin` rules.\n */\n prairieLearnOptions?: PrairieLearnPluginOptions;\n\n /**\n * Global ignores to apply.\n * Will be merged with default ignores.\n */\n ignores?: string[];\n\n /**\n * Disable specific config modules.\n */\n disable?: {\n react?: boolean;\n vitest?: boolean;\n perfectionist?: boolean;\n unicorn?: boolean;\n jsdoc?: boolean;\n tanstack?: boolean;\n lodash?: boolean;\n };\n}\n\n/**\n * Creates a PrairieLearn ESLint configuration array.\n *\n * @example\n * ```js\n * // eslint.config.mjs\n * import { prairielearn } from '@prairielearn/eslint-config';\n *\n * export default [\n * ...prairielearn({\n * tsconfigRootDir: import.meta.dirname,\n * }),\n * // Add your project-specific rules here\n * ];\n * ```\n */\nexport function prairielearn(\n options: PrairieLearnEslintConfigOptions,\n): TSESLint.FlatConfig.ConfigArray {\n const {\n tsconfigRootDir,\n typeAwareFiles = ['**/*.{ts,tsx}'],\n allowDefaultProject = ['*.config.ts', '*.config.mts', 'vitest.config.ts'],\n prairielearn: enablePrairielearn = true,\n prairieLearnOptions,\n ignores = [],\n disable = {},\n } = options;\n\n const jsFiles = ['**/*.{js,jsx,ts,tsx,mjs,cjs,mts,cts}'];\n\n const configs: TSESLint.FlatConfig.ConfigArray = [\n // Base typescript-eslint configs (scoped to JS/TS files)\n ...tseslint.config({\n extends: [...tseslint.configs.stylistic, ...tseslint.configs.strict],\n files: jsFiles,\n }),\n // Base configs (always included)\n ...baseConfig(),\n // TypeScript config (scoped to JS/TS files)\n {\n files: jsFiles,\n ...typescriptConfig()[0],\n },\n ...importsConfig(),\n ...stylisticConfig(),\n ];\n\n // Optional configs\n if (!disable.react) {\n configs.push(...reactConfig());\n }\n\n if (!disable.vitest) {\n configs.push(...vitestConfig());\n }\n\n if (!disable.perfectionist) {\n configs.push(...perfectionistConfig());\n }\n\n if (!disable.unicorn) {\n configs.push(...unicornConfig());\n }\n\n if (!disable.jsdoc) {\n configs.push(...jsdocConfig());\n }\n\n if (!disable.tanstack) {\n configs.push(...tanstackConfig());\n }\n\n if (!disable.lodash) {\n configs.push(...lodashConfig());\n }\n\n if (enablePrairielearn) {\n configs.push(...prairieLearnConfig(prairieLearnOptions));\n }\n\n // Type-aware rules (applied to specified files)\n // We use tseslint.config() to properly handle the extends syntax\n configs.push(\n ...tseslint.config({\n extends: [\n tseslint.configs.recommendedTypeCheckedOnly,\n tseslint.configs.stylisticTypeCheckedOnly,\n ],\n files: typeAwareFiles,\n languageOptions: {\n parserOptions: {\n projectService: {\n allowDefaultProject,\n },\n tsconfigRootDir,\n },\n },\n rules: typescriptTypeAwareRules(),\n }),\n );\n\n // Default ignores\n return [\n ...configs,\n globalIgnores(['.yarn/*', 'node_modules/*', 'dist/*', 'coverage/*', ...ignores]),\n ];\n}\n\n// Re-export individual configs for advanced use\nexport { baseConfig } from './configs/base.js';\nexport { importsConfig } from './configs/imports.js';\nexport { jsdocConfig } from './configs/jsdoc.js';\nexport { lodashConfig } from './configs/lodash.js';\nexport { perfectionistConfig } from './configs/perfectionist.js';\nexport { prairieLearnConfig, type PrairieLearnPluginOptions } from './configs/prairielearn.js';\nexport { reactConfig } from './configs/react.js';\nexport { stylisticConfig } from './configs/stylistic.js';\nexport { tanstackConfig } from './configs/tanstack.js';\nexport { typescriptConfig, typescriptTypeAwareRules } from './configs/typescript.js';\nexport { unicornConfig } from './configs/unicorn.js';\nexport { vitestConfig } from './configs/vitest.js';\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAQzD,OAAO,EAAE,KAAK,yBAAyB,EAAsB,MAAM,2BAA2B,CAAC;AAQ/F,MAAM,WAAW,+BAA+B;IAC9C;;;OAGG;IACH,eAAe,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE/B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,mBAAmB,CAAC,EAAE,yBAAyB,CAAC;IAEhD;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB;;OAEG;IACH,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,+BAA+B,GACvC,QAAQ,CAAC,UAAU,CAAC,WAAW,CAyFjC;AAGD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAC/F,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC","sourcesContent":["import { globalIgnores } from '@eslint/config-helpers';\nimport type { TSESLint } from '@typescript-eslint/utils';\nimport tseslint from 'typescript-eslint';\n\nimport { baseConfig } from './configs/base.js';\nimport { importsConfig } from './configs/imports.js';\nimport { jsdocConfig } from './configs/jsdoc.js';\nimport { lodashConfig } from './configs/lodash.js';\nimport { perfectionistConfig } from './configs/perfectionist.js';\nimport { type PrairieLearnPluginOptions, prairieLearnConfig } from './configs/prairielearn.js';\nimport { reactConfig } from './configs/react.js';\nimport { stylisticConfig } from './configs/stylistic.js';\nimport { tanstackConfig } from './configs/tanstack.js';\nimport { typescriptConfig, typescriptTypeAwareRules } from './configs/typescript.js';\nimport { unicornConfig } from './configs/unicorn.js';\nimport { vitestConfig } from './configs/vitest.js';\n\nexport interface PrairieLearnEslintConfigOptions {\n /**\n * Root directory for TypeScript project service.\n * Required for type-aware linting.\n */\n tsconfigRootDir: string;\n\n /**\n * Glob patterns for files to apply type-aware rules to.\n * @default ['**\\/*.{ts,tsx}']\n */\n typeAwareFiles?: string[];\n\n /**\n * Files to allow in defaultProject for type-aware linting.\n * Useful for config files outside the main tsconfig.\n * @default ['*.config.ts', '*.config.mts', 'vitest.config.ts']\n */\n allowDefaultProject?: string[];\n\n /**\n * Enable `@prairielearn/eslint-plugin` rules.\n * @default true\n */\n prairielearn?: boolean;\n\n /**\n * Options for the `@prairielearn/eslint-plugin` rules.\n */\n prairieLearnOptions?: PrairieLearnPluginOptions;\n\n /**\n * Global ignores to apply.\n * Will be merged with default ignores.\n */\n ignores?: string[];\n\n /**\n * Disable specific config modules.\n */\n disable?: {\n react?: boolean;\n vitest?: boolean;\n perfectionist?: boolean;\n unicorn?: boolean;\n jsdoc?: boolean;\n tanstack?: boolean;\n lodash?: boolean;\n };\n}\n\n/**\n * Creates a PrairieLearn ESLint configuration array.\n *\n * @example\n * ```js\n * // eslint.config.mjs\n * import { prairielearn } from '@prairielearn/eslint-config';\n *\n * export default [\n * ...prairielearn({\n * tsconfigRootDir: import.meta.dirname,\n * }),\n * // Add your project-specific rules here\n * ];\n * ```\n */\nexport function prairielearn(\n options: PrairieLearnEslintConfigOptions,\n): TSESLint.FlatConfig.ConfigArray {\n const {\n tsconfigRootDir,\n typeAwareFiles = ['**/*.{ts,tsx}'],\n allowDefaultProject = ['*.config.ts', '*.config.mts', 'vitest.config.ts'],\n prairielearn: enablePrairielearn = true,\n prairieLearnOptions,\n ignores = [],\n disable = {},\n } = options;\n\n const jsFiles = ['**/*.{js,jsx,ts,tsx,mjs,cjs,mts,cts}'];\n\n const configs: TSESLint.FlatConfig.ConfigArray = [\n // Base typescript-eslint configs (scoped to JS/TS files)\n ...tseslint.config({\n extends: [...tseslint.configs.stylistic, ...tseslint.configs.strict],\n files: jsFiles,\n }),\n // Base configs (always included)\n ...baseConfig(),\n // TypeScript config (scoped to JS/TS files)\n {\n files: jsFiles,\n ...typescriptConfig()[0],\n },\n ...importsConfig(),\n ...stylisticConfig(),\n ];\n\n // Optional configs\n if (!disable.react) {\n configs.push(...reactConfig());\n }\n\n if (!disable.vitest) {\n configs.push(...vitestConfig());\n }\n\n if (!disable.perfectionist) {\n configs.push(...perfectionistConfig());\n }\n\n if (!disable.unicorn) {\n configs.push(...unicornConfig());\n }\n\n if (!disable.jsdoc) {\n configs.push(...jsdocConfig());\n }\n\n if (!disable.tanstack) {\n configs.push(...tanstackConfig());\n }\n\n if (!disable.lodash) {\n configs.push(...lodashConfig());\n }\n\n if (enablePrairielearn) {\n configs.push(...prairieLearnConfig(prairieLearnOptions));\n }\n\n // Type-aware rules (applied to specified files)\n // We use tseslint.config() to properly handle the extends syntax\n configs.push(\n ...tseslint.config({\n extends: [\n tseslint.configs.recommendedTypeCheckedOnly,\n tseslint.configs.stylisticTypeCheckedOnly,\n ],\n files: typeAwareFiles,\n languageOptions: {\n parserOptions: {\n projectService: {\n allowDefaultProject,\n },\n tsconfigRootDir,\n },\n },\n rules: typescriptTypeAwareRules(),\n }),\n );\n\n // Default ignores\n return [\n ...configs,\n globalIgnores(['.yarn/*', 'node_modules/*', 'dist/*', 'coverage/*', ...ignores]),\n ];\n}\n\n// Re-export individual configs for advanced use\nexport { baseConfig } from './configs/base.js';\nexport { importsConfig } from './configs/imports.js';\nexport { jsdocConfig } from './configs/jsdoc.js';\nexport { lodashConfig } from './configs/lodash.js';\nexport { perfectionistConfig } from './configs/perfectionist.js';\nexport { prairieLearnConfig, type PrairieLearnPluginOptions } from './configs/prairielearn.js';\nexport { reactConfig } from './configs/react.js';\nexport { stylisticConfig } from './configs/stylistic.js';\nexport { tanstackConfig } from './configs/tanstack.js';\nexport { typescriptConfig, typescriptTypeAwareRules } from './configs/typescript.js';\nexport { unicornConfig } from './configs/unicorn.js';\nexport { vitestConfig } from './configs/vitest.js';\n"]}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { globalIgnores } from 'eslint/config';
1
+ import { globalIgnores } from '@eslint/config-helpers';
2
2
  import tseslint from 'typescript-eslint';
3
3
  import { baseConfig } from './configs/base.js';
4
4
  import { importsConfig } from './configs/imports.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\nimport { globalIgnores } from 'eslint/config';\nimport tseslint from 'typescript-eslint';\n\nimport { baseConfig } from './configs/base.js';\nimport { importsConfig } from './configs/imports.js';\nimport { jsdocConfig } from './configs/jsdoc.js';\nimport { lodashConfig } from './configs/lodash.js';\nimport { perfectionistConfig } from './configs/perfectionist.js';\nimport { type PrairieLearnPluginOptions, prairieLearnConfig } from './configs/prairielearn.js';\nimport { reactConfig } from './configs/react.js';\nimport { stylisticConfig } from './configs/stylistic.js';\nimport { tanstackConfig } from './configs/tanstack.js';\nimport { typescriptConfig, typescriptTypeAwareRules } from './configs/typescript.js';\nimport { unicornConfig } from './configs/unicorn.js';\nimport { vitestConfig } from './configs/vitest.js';\n\nexport interface PrairieLearnEslintConfigOptions {\n /**\n * Root directory for TypeScript project service.\n * Required for type-aware linting.\n */\n tsconfigRootDir: string;\n\n /**\n * Glob patterns for files to apply type-aware rules to.\n * @default ['**\\/*.{ts,tsx}']\n */\n typeAwareFiles?: string[];\n\n /**\n * Files to allow in defaultProject for type-aware linting.\n * Useful for config files outside the main tsconfig.\n * @default ['*.config.ts', '*.config.mts', 'vitest.config.ts']\n */\n allowDefaultProject?: string[];\n\n /**\n * Enable `@prairielearn/eslint-plugin` rules.\n * @default true\n */\n prairielearn?: boolean;\n\n /**\n * Options for the `@prairielearn/eslint-plugin` rules.\n */\n prairieLearnOptions?: PrairieLearnPluginOptions;\n\n /**\n * Global ignores to apply.\n * Will be merged with default ignores.\n */\n ignores?: string[];\n\n /**\n * Disable specific config modules.\n */\n disable?: {\n react?: boolean;\n vitest?: boolean;\n perfectionist?: boolean;\n unicorn?: boolean;\n jsdoc?: boolean;\n tanstack?: boolean;\n lodash?: boolean;\n };\n}\n\n/**\n * Creates a PrairieLearn ESLint configuration array.\n *\n * @example\n * ```js\n * // eslint.config.mjs\n * import { prairielearn } from '@prairielearn/eslint-config';\n *\n * export default [\n * ...prairielearn({\n * tsconfigRootDir: import.meta.dirname,\n * }),\n * // Add your project-specific rules here\n * ];\n * ```\n */\nexport function prairielearn(\n options: PrairieLearnEslintConfigOptions,\n): TSESLint.FlatConfig.ConfigArray {\n const {\n tsconfigRootDir,\n typeAwareFiles = ['**/*.{ts,tsx}'],\n allowDefaultProject = ['*.config.ts', '*.config.mts', 'vitest.config.ts'],\n prairielearn: enablePrairielearn = true,\n prairieLearnOptions,\n ignores = [],\n disable = {},\n } = options;\n\n const jsFiles = ['**/*.{js,jsx,ts,tsx,mjs,cjs,mts,cts}'];\n\n const configs: TSESLint.FlatConfig.ConfigArray = [\n // Base typescript-eslint configs (scoped to JS/TS files)\n ...tseslint.config({\n extends: [...tseslint.configs.stylistic, ...tseslint.configs.strict],\n files: jsFiles,\n }),\n // Base configs (always included)\n ...baseConfig(),\n // TypeScript config (scoped to JS/TS files)\n {\n files: jsFiles,\n ...typescriptConfig()[0],\n },\n ...importsConfig(),\n ...stylisticConfig(),\n ];\n\n // Optional configs\n if (!disable.react) {\n configs.push(...reactConfig());\n }\n\n if (!disable.vitest) {\n configs.push(...vitestConfig());\n }\n\n if (!disable.perfectionist) {\n configs.push(...perfectionistConfig());\n }\n\n if (!disable.unicorn) {\n configs.push(...unicornConfig());\n }\n\n if (!disable.jsdoc) {\n configs.push(...jsdocConfig());\n }\n\n if (!disable.tanstack) {\n configs.push(...tanstackConfig());\n }\n\n if (!disable.lodash) {\n configs.push(...lodashConfig());\n }\n\n if (enablePrairielearn) {\n configs.push(...prairieLearnConfig(prairieLearnOptions));\n }\n\n // Type-aware rules (applied to specified files)\n // We use tseslint.config() to properly handle the extends syntax\n configs.push(\n ...tseslint.config({\n extends: [\n tseslint.configs.recommendedTypeCheckedOnly,\n tseslint.configs.stylisticTypeCheckedOnly,\n ],\n files: typeAwareFiles,\n languageOptions: {\n parserOptions: {\n projectService: {\n allowDefaultProject,\n },\n tsconfigRootDir,\n },\n },\n rules: typescriptTypeAwareRules(),\n }),\n );\n\n // Default ignores\n return [\n ...configs,\n globalIgnores(['.yarn/*', 'node_modules/*', 'dist/*', 'coverage/*', ...ignores]),\n ];\n}\n\n// Re-export individual configs for advanced use\nexport { baseConfig } from './configs/base.js';\nexport { importsConfig } from './configs/imports.js';\nexport { jsdocConfig } from './configs/jsdoc.js';\nexport { lodashConfig } from './configs/lodash.js';\nexport { perfectionistConfig } from './configs/perfectionist.js';\nexport { prairieLearnConfig, type PrairieLearnPluginOptions } from './configs/prairielearn.js';\nexport { reactConfig } from './configs/react.js';\nexport { stylisticConfig } from './configs/stylistic.js';\nexport { tanstackConfig } from './configs/tanstack.js';\nexport { typescriptConfig, typescriptTypeAwareRules } from './configs/typescript.js';\nexport { unicornConfig } from './configs/unicorn.js';\nexport { vitestConfig } from './configs/vitest.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { globalIgnores } from '@eslint/config-helpers';\nimport type { TSESLint } from '@typescript-eslint/utils';\nimport tseslint from 'typescript-eslint';\n\nimport { baseConfig } from './configs/base.js';\nimport { importsConfig } from './configs/imports.js';\nimport { jsdocConfig } from './configs/jsdoc.js';\nimport { lodashConfig } from './configs/lodash.js';\nimport { perfectionistConfig } from './configs/perfectionist.js';\nimport { type PrairieLearnPluginOptions, prairieLearnConfig } from './configs/prairielearn.js';\nimport { reactConfig } from './configs/react.js';\nimport { stylisticConfig } from './configs/stylistic.js';\nimport { tanstackConfig } from './configs/tanstack.js';\nimport { typescriptConfig, typescriptTypeAwareRules } from './configs/typescript.js';\nimport { unicornConfig } from './configs/unicorn.js';\nimport { vitestConfig } from './configs/vitest.js';\n\nexport interface PrairieLearnEslintConfigOptions {\n /**\n * Root directory for TypeScript project service.\n * Required for type-aware linting.\n */\n tsconfigRootDir: string;\n\n /**\n * Glob patterns for files to apply type-aware rules to.\n * @default ['**\\/*.{ts,tsx}']\n */\n typeAwareFiles?: string[];\n\n /**\n * Files to allow in defaultProject for type-aware linting.\n * Useful for config files outside the main tsconfig.\n * @default ['*.config.ts', '*.config.mts', 'vitest.config.ts']\n */\n allowDefaultProject?: string[];\n\n /**\n * Enable `@prairielearn/eslint-plugin` rules.\n * @default true\n */\n prairielearn?: boolean;\n\n /**\n * Options for the `@prairielearn/eslint-plugin` rules.\n */\n prairieLearnOptions?: PrairieLearnPluginOptions;\n\n /**\n * Global ignores to apply.\n * Will be merged with default ignores.\n */\n ignores?: string[];\n\n /**\n * Disable specific config modules.\n */\n disable?: {\n react?: boolean;\n vitest?: boolean;\n perfectionist?: boolean;\n unicorn?: boolean;\n jsdoc?: boolean;\n tanstack?: boolean;\n lodash?: boolean;\n };\n}\n\n/**\n * Creates a PrairieLearn ESLint configuration array.\n *\n * @example\n * ```js\n * // eslint.config.mjs\n * import { prairielearn } from '@prairielearn/eslint-config';\n *\n * export default [\n * ...prairielearn({\n * tsconfigRootDir: import.meta.dirname,\n * }),\n * // Add your project-specific rules here\n * ];\n * ```\n */\nexport function prairielearn(\n options: PrairieLearnEslintConfigOptions,\n): TSESLint.FlatConfig.ConfigArray {\n const {\n tsconfigRootDir,\n typeAwareFiles = ['**/*.{ts,tsx}'],\n allowDefaultProject = ['*.config.ts', '*.config.mts', 'vitest.config.ts'],\n prairielearn: enablePrairielearn = true,\n prairieLearnOptions,\n ignores = [],\n disable = {},\n } = options;\n\n const jsFiles = ['**/*.{js,jsx,ts,tsx,mjs,cjs,mts,cts}'];\n\n const configs: TSESLint.FlatConfig.ConfigArray = [\n // Base typescript-eslint configs (scoped to JS/TS files)\n ...tseslint.config({\n extends: [...tseslint.configs.stylistic, ...tseslint.configs.strict],\n files: jsFiles,\n }),\n // Base configs (always included)\n ...baseConfig(),\n // TypeScript config (scoped to JS/TS files)\n {\n files: jsFiles,\n ...typescriptConfig()[0],\n },\n ...importsConfig(),\n ...stylisticConfig(),\n ];\n\n // Optional configs\n if (!disable.react) {\n configs.push(...reactConfig());\n }\n\n if (!disable.vitest) {\n configs.push(...vitestConfig());\n }\n\n if (!disable.perfectionist) {\n configs.push(...perfectionistConfig());\n }\n\n if (!disable.unicorn) {\n configs.push(...unicornConfig());\n }\n\n if (!disable.jsdoc) {\n configs.push(...jsdocConfig());\n }\n\n if (!disable.tanstack) {\n configs.push(...tanstackConfig());\n }\n\n if (!disable.lodash) {\n configs.push(...lodashConfig());\n }\n\n if (enablePrairielearn) {\n configs.push(...prairieLearnConfig(prairieLearnOptions));\n }\n\n // Type-aware rules (applied to specified files)\n // We use tseslint.config() to properly handle the extends syntax\n configs.push(\n ...tseslint.config({\n extends: [\n tseslint.configs.recommendedTypeCheckedOnly,\n tseslint.configs.stylisticTypeCheckedOnly,\n ],\n files: typeAwareFiles,\n languageOptions: {\n parserOptions: {\n projectService: {\n allowDefaultProject,\n },\n tsconfigRootDir,\n },\n },\n rules: typescriptTypeAwareRules(),\n }),\n );\n\n // Default ignores\n return [\n ...configs,\n globalIgnores(['.yarn/*', 'node_modules/*', 'dist/*', 'coverage/*', ...ignores]),\n ];\n}\n\n// Re-export individual configs for advanced use\nexport { baseConfig } from './configs/base.js';\nexport { importsConfig } from './configs/imports.js';\nexport { jsdocConfig } from './configs/jsdoc.js';\nexport { lodashConfig } from './configs/lodash.js';\nexport { perfectionistConfig } from './configs/perfectionist.js';\nexport { prairieLearnConfig, type PrairieLearnPluginOptions } from './configs/prairielearn.js';\nexport { reactConfig } from './configs/react.js';\nexport { stylisticConfig } from './configs/stylistic.js';\nexport { tanstackConfig } from './configs/tanstack.js';\nexport { typescriptConfig, typescriptTypeAwareRules } from './configs/typescript.js';\nexport { unicornConfig } from './configs/unicorn.js';\nexport { vitestConfig } from './configs/vitest.js';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prairielearn/eslint-config",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,30 +23,31 @@
23
23
  "typescript": "^5.0.0"
24
24
  },
25
25
  "dependencies": {
26
- "@eslint-react/eslint-plugin": "^2.13.0",
27
- "@eslint/eslintrc": "^3.3.4",
26
+ "@eslint-react/eslint-plugin": "^4.2.3",
27
+ "@eslint/config-helpers": "^0.5.4",
28
+ "@eslint/eslintrc": "^3.3.5",
28
29
  "@eslint/js": "^10.0.1",
29
- "@prairielearn/eslint-plugin": "^4.0.0",
30
- "@stylistic/eslint-plugin": "^5.9.0",
31
- "@tanstack/eslint-plugin-query": "^5.91.4",
32
- "@typescript-eslint/utils": "^8.56.1",
33
- "@vitest/eslint-plugin": "^1.6.9",
30
+ "@prairielearn/eslint-plugin": "^4.1.0",
31
+ "@stylistic/eslint-plugin": "^5.10.0",
32
+ "@tanstack/eslint-plugin-query": "^5.96.2",
33
+ "@typescript-eslint/utils": "^8.58.0",
34
+ "@vitest/eslint-plugin": "^1.6.14",
34
35
  "eslint-import-resolver-typescript": "^4.4.4",
35
- "eslint-plugin-import-x": "^4.16.1",
36
- "eslint-plugin-jsdoc": "^62.7.1",
36
+ "eslint-plugin-import-x": "^4.16.2",
37
+ "eslint-plugin-jsdoc": "^62.9.0",
37
38
  "eslint-plugin-jsx-a11y-x": "^0.1.1",
38
39
  "eslint-plugin-no-floating-promise": "^2.0.0",
39
- "eslint-plugin-perfectionist": "^5.6.0",
40
+ "eslint-plugin-perfectionist": "^5.8.0",
40
41
  "eslint-plugin-react-hooks": "^7.0.1",
41
42
  "eslint-plugin-react-you-might-not-need-an-effect": "^0.9.2",
42
- "eslint-plugin-unicorn": "^63.0.0",
43
+ "eslint-plugin-unicorn": "^64.0.0",
43
44
  "eslint-plugin-you-dont-need-lodash-underscore": "^6.14.0",
44
45
  "globals": "^17.4.0",
45
- "typescript-eslint": "^8.56.1"
46
+ "typescript-eslint": "^8.58.0"
46
47
  },
47
48
  "devDependencies": {
48
49
  "@prairielearn/tsconfig": "^2.0.0",
49
- "@types/node": "^24.11.0",
50
+ "@types/node": "^24.12.2",
50
51
  "@typescript/native-preview": "^7.0.0-dev.20260305.1"
51
52
  }
52
53
  }
@@ -1,8 +1,12 @@
1
- import { FlatCompat } from '@eslint/eslintrc';
2
1
  import type { TSESLint } from '@typescript-eslint/utils';
3
2
  import youDontNeedLodashUnderscore from 'eslint-plugin-you-dont-need-lodash-underscore';
4
3
 
5
- const compat = new FlatCompat();
4
+ const allRules = Object.fromEntries(
5
+ Object.keys(youDontNeedLodashUnderscore.rules).map((rule) => [
6
+ `you-dont-need-lodash-underscore/${rule}`,
7
+ 'error',
8
+ ]),
9
+ );
6
10
 
7
11
  /**
8
12
  * Lodash/underscore replacement rules.
@@ -13,11 +17,8 @@ export function lodashConfig(): TSESLint.FlatConfig.ConfigArray {
13
17
  plugins: {
14
18
  'you-dont-need-lodash-underscore': youDontNeedLodashUnderscore,
15
19
  },
16
- },
17
- // Use FlatCompat to extend the legacy config
18
- ...compat.extends('plugin:you-dont-need-lodash-underscore/all'),
19
- {
20
20
  rules: {
21
+ ...allRules,
21
22
  // The _.omit function is still useful in some contexts.
22
23
  'you-dont-need-lodash-underscore/omit': 'off',
23
24
  },
@@ -29,6 +29,7 @@ export function prairieLearnConfig(
29
29
  '@prairielearn/aws-client-shared-config': 'error',
30
30
  '@prairielearn/jsx-no-dollar-interpolation': 'error',
31
31
  '@prairielearn/no-current-target-in-callback': 'error',
32
+ '@prairielearn/no-hydrate-reslocals': 'error',
32
33
  '@prairielearn/no-unused-sql-blocks': 'error',
33
34
  '@prairielearn/safe-db-types': [
34
35
  'error',
@@ -11,6 +11,9 @@ const eslintReactConfig = eslintReact.configs['recommended-typescript'] as {
11
11
  settings?: TSESLint.FlatConfig.Settings;
12
12
  };
13
13
 
14
+ const disableConflictReactHooksConfig =
15
+ eslintReact.configs['disable-conflict-eslint-plugin-react-hooks'];
16
+
14
17
  /**
15
18
  * React, React hooks, accessibility, and related rules.
16
19
  */
@@ -25,9 +28,8 @@ export function reactConfig(): TSESLint.FlatConfig.ConfigArray {
25
28
  },
26
29
 
27
30
  rules: {
28
- // React hooks
29
- 'react-hooks/exhaustive-deps': 'error',
30
- 'react-hooks/rules-of-hooks': 'error',
31
+ // https://www.eslint-react.xyz/docs/migrating-from-eslint-plugin-react-hooks#migration-preset
32
+ ...disableConflictReactHooksConfig.rules,
31
33
 
32
34
  // react-you-might-not-need-an-effect rules as errors
33
35
  ...Object.fromEntries(
@@ -47,9 +49,9 @@ export function reactConfig(): TSESLint.FlatConfig.ConfigArray {
47
49
  ),
48
50
  // We want to be able to use `useState` without the setter function for
49
51
  // https://tkdodo.eu/blog/react-query-fa-qs#2-the-queryclient-is-not-stable
50
- '@eslint-react/naming-convention/use-state': 'off',
51
- // Forbid `snake_case` props.
52
- '@eslint-react/no-forbidden-props': ['error', { forbid: ['/_/'] }],
52
+ '@eslint-react/use-state': 'off',
53
+ // Forbid `target="_blank"` without `rel="noreferrer"` for security reasons.
54
+ '@eslint-react/dom-no-unsafe-target-blank': 'error',
53
55
 
54
56
  // jsx-a11y strict rules
55
57
  ...jsxA11yX.configs.strict.rules,
@@ -14,6 +14,9 @@ export function tanstackConfig(): TSESLint.FlatConfig.ConfigArray {
14
14
  rules: {
15
15
  // https://github.com/TanStack/query/blob/6402d756b702ac560b69a5ce84d6e4e764b96451/packages/eslint-plugin-query/src/index.ts#L43
16
16
  ...pluginQuery.configs['flat/recommended'][0].rules,
17
+ // Disabled: tRPC proxy objects in query keys trigger false positives
18
+ // since the proxy is not serializable and the rule can't introspect it.
19
+ '@tanstack/query/exhaustive-deps': 'off',
17
20
  '@tanstack/query/no-rest-destructuring': 'error',
18
21
  },
19
22
  },
@@ -63,6 +63,7 @@ export function unicornConfig(): TSESLint.FlatConfig.ConfigArray {
63
63
 
64
64
  // False positives
65
65
  'unicorn/error-message': 'off',
66
+ 'unicorn/prefer-array-find': ['error', { checkFromLast: false }], // findLast is unavailable in our target lib
66
67
  'unicorn/prefer-at': 'off', // https://github.com/microsoft/TypeScript/issues/47660#issuecomment-3146907649
67
68
  'unicorn/throw-new-error': 'off',
68
69
 
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
+ import { globalIgnores } from '@eslint/config-helpers';
1
2
  import type { TSESLint } from '@typescript-eslint/utils';
2
- import { globalIgnores } from 'eslint/config';
3
3
  import tseslint from 'typescript-eslint';
4
4
 
5
5
  import { baseConfig } from './configs/base.js';