@prairielearn/eslint-config 0.0.1 → 1.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.
Files changed (71) hide show
  1. package/.turbo/turbo-build.log +0 -0
  2. package/CHANGELOG.md +13 -0
  3. package/README.md +111 -43
  4. package/dist/configs/base.d.ts +7 -0
  5. package/dist/configs/base.d.ts.map +1 -0
  6. package/dist/configs/base.js +121 -0
  7. package/dist/configs/base.js.map +1 -0
  8. package/dist/configs/imports.d.ts +6 -0
  9. package/dist/configs/imports.d.ts.map +1 -0
  10. package/dist/configs/imports.js +44 -0
  11. package/dist/configs/imports.js.map +1 -0
  12. package/dist/configs/jsdoc.d.ts +6 -0
  13. package/dist/configs/jsdoc.d.ts.map +1 -0
  14. package/dist/configs/jsdoc.js +70 -0
  15. package/dist/configs/jsdoc.js.map +1 -0
  16. package/dist/configs/lodash.d.ts +6 -0
  17. package/dist/configs/lodash.d.ts.map +1 -0
  18. package/dist/configs/lodash.js +24 -0
  19. package/dist/configs/lodash.js.map +1 -0
  20. package/dist/configs/perfectionist.d.ts +8 -0
  21. package/dist/configs/perfectionist.d.ts.map +1 -0
  22. package/dist/configs/perfectionist.js +43 -0
  23. package/dist/configs/perfectionist.js.map +1 -0
  24. package/dist/configs/prairielearn.d.ts +13 -0
  25. package/dist/configs/prairielearn.d.ts.map +1 -0
  26. package/dist/configs/prairielearn.js +29 -0
  27. package/dist/configs/prairielearn.js.map +1 -0
  28. package/dist/configs/react.d.ts +6 -0
  29. package/dist/configs/react.d.ts.map +1 -0
  30. package/dist/configs/react.js +63 -0
  31. package/dist/configs/react.js.map +1 -0
  32. package/dist/configs/stylistic.d.ts +6 -0
  33. package/dist/configs/stylistic.d.ts.map +1 -0
  34. package/dist/configs/stylistic.js +51 -0
  35. package/dist/configs/stylistic.js.map +1 -0
  36. package/dist/configs/tanstack.d.ts +6 -0
  37. package/dist/configs/tanstack.d.ts.map +1 -0
  38. package/dist/configs/tanstack.js +19 -0
  39. package/dist/configs/tanstack.js.map +1 -0
  40. package/dist/configs/typescript.d.ts +11 -0
  41. package/dist/configs/typescript.d.ts.map +1 -0
  42. package/dist/configs/typescript.js +106 -0
  43. package/dist/configs/typescript.js.map +1 -0
  44. package/dist/configs/unicorn.d.ts +6 -0
  45. package/dist/configs/unicorn.d.ts.map +1 -0
  46. package/dist/configs/unicorn.js +74 -0
  47. package/dist/configs/unicorn.js.map +1 -0
  48. package/dist/configs/vitest.d.ts +6 -0
  49. package/dist/configs/vitest.d.ts.map +1 -0
  50. package/dist/configs/vitest.js +26 -0
  51. package/dist/configs/vitest.js.map +1 -0
  52. package/dist/index.d.ts +76 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +112 -0
  55. package/dist/index.js.map +1 -0
  56. package/package.json +49 -7
  57. package/src/configs/base.ts +127 -0
  58. package/src/configs/imports.ts +50 -0
  59. package/src/configs/jsdoc.ts +72 -0
  60. package/src/configs/lodash.ts +26 -0
  61. package/src/configs/perfectionist.ts +48 -0
  62. package/src/configs/prairielearn.ts +42 -0
  63. package/src/configs/react.ts +82 -0
  64. package/src/configs/stylistic.ts +54 -0
  65. package/src/configs/tanstack.ts +21 -0
  66. package/src/configs/typescript.ts +108 -0
  67. package/src/configs/unicorn.ts +84 -0
  68. package/src/configs/vitest.ts +31 -0
  69. package/src/index.ts +190 -0
  70. package/src/types.d.ts +6 -0
  71. package/tsconfig.json +7 -0
@@ -0,0 +1,76 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
+ import { type PrairieLearnPluginOptions } from './configs/prairielearn.js';
3
+ export interface PrairieLearnEslintConfigOptions {
4
+ /**
5
+ * Root directory for TypeScript project service.
6
+ * Required for type-aware linting.
7
+ */
8
+ tsconfigRootDir: string;
9
+ /**
10
+ * Glob patterns for files to apply type-aware rules to.
11
+ * @default ['**\/*.{ts,tsx}']
12
+ */
13
+ typeAwareFiles?: string[];
14
+ /**
15
+ * Files to allow in defaultProject for type-aware linting.
16
+ * Useful for config files outside the main tsconfig.
17
+ * @default ['*.config.ts', '*.config.mts', 'vitest.config.ts']
18
+ */
19
+ allowDefaultProject?: string[];
20
+ /**
21
+ * Enable `@prairielearn/eslint-plugin` rules.
22
+ * @default true
23
+ */
24
+ prairielearn?: boolean;
25
+ /**
26
+ * Options for the `@prairielearn/eslint-plugin` rules.
27
+ */
28
+ prairieLearnOptions?: PrairieLearnPluginOptions;
29
+ /**
30
+ * Global ignores to apply.
31
+ * Will be merged with default ignores.
32
+ */
33
+ ignores?: string[];
34
+ /**
35
+ * Disable specific config modules.
36
+ */
37
+ disable?: {
38
+ react?: boolean;
39
+ vitest?: boolean;
40
+ perfectionist?: boolean;
41
+ unicorn?: boolean;
42
+ jsdoc?: boolean;
43
+ tanstack?: boolean;
44
+ lodash?: boolean;
45
+ };
46
+ }
47
+ /**
48
+ * Creates a PrairieLearn ESLint configuration array.
49
+ *
50
+ * @example
51
+ * ```js
52
+ * // eslint.config.mjs
53
+ * import { prairielearn } from '@prairielearn/eslint-config';
54
+ *
55
+ * export default [
56
+ * ...prairielearn({
57
+ * tsconfigRootDir: import.meta.dirname,
58
+ * }),
59
+ * // Add your project-specific rules here
60
+ * ];
61
+ * ```
62
+ */
63
+ export declare function prairielearn(options: PrairieLearnEslintConfigOptions): TSESLint.FlatConfig.ConfigArray;
64
+ export { baseConfig } from './configs/base.js';
65
+ export { importsConfig } from './configs/imports.js';
66
+ export { jsdocConfig } from './configs/jsdoc.js';
67
+ export { lodashConfig } from './configs/lodash.js';
68
+ export { perfectionistConfig } from './configs/perfectionist.js';
69
+ export { prairieLearnConfig, type PrairieLearnPluginOptions } from './configs/prairielearn.js';
70
+ export { reactConfig } from './configs/react.js';
71
+ export { stylisticConfig } from './configs/stylistic.js';
72
+ export { tanstackConfig } from './configs/tanstack.js';
73
+ export { typescriptConfig, typescriptTypeAwareRules } from './configs/typescript.js';
74
+ export { unicornConfig } from './configs/unicorn.js';
75
+ export { vitestConfig } from './configs/vitest.js';
76
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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"]}
package/dist/index.js ADDED
@@ -0,0 +1,112 @@
1
+ import { globalIgnores } from 'eslint/config';
2
+ import tseslint from 'typescript-eslint';
3
+ import { baseConfig } from './configs/base.js';
4
+ import { importsConfig } from './configs/imports.js';
5
+ import { jsdocConfig } from './configs/jsdoc.js';
6
+ import { lodashConfig } from './configs/lodash.js';
7
+ import { perfectionistConfig } from './configs/perfectionist.js';
8
+ import { prairieLearnConfig } from './configs/prairielearn.js';
9
+ import { reactConfig } from './configs/react.js';
10
+ import { stylisticConfig } from './configs/stylistic.js';
11
+ import { tanstackConfig } from './configs/tanstack.js';
12
+ import { typescriptConfig, typescriptTypeAwareRules } from './configs/typescript.js';
13
+ import { unicornConfig } from './configs/unicorn.js';
14
+ import { vitestConfig } from './configs/vitest.js';
15
+ /**
16
+ * Creates a PrairieLearn ESLint configuration array.
17
+ *
18
+ * @example
19
+ * ```js
20
+ * // eslint.config.mjs
21
+ * import { prairielearn } from '@prairielearn/eslint-config';
22
+ *
23
+ * export default [
24
+ * ...prairielearn({
25
+ * tsconfigRootDir: import.meta.dirname,
26
+ * }),
27
+ * // Add your project-specific rules here
28
+ * ];
29
+ * ```
30
+ */
31
+ export function prairielearn(options) {
32
+ const { tsconfigRootDir, typeAwareFiles = ['**/*.{ts,tsx}'], allowDefaultProject = ['*.config.ts', '*.config.mts', 'vitest.config.ts'], prairielearn: enablePrairielearn = true, prairieLearnOptions, ignores = [], disable = {}, } = options;
33
+ const jsFiles = ['**/*.{js,jsx,ts,tsx,mjs,cjs,mts,cts}'];
34
+ const configs = [
35
+ // Base typescript-eslint configs (scoped to JS/TS files)
36
+ ...tseslint.config({
37
+ extends: [...tseslint.configs.stylistic, ...tseslint.configs.strict],
38
+ files: jsFiles,
39
+ }),
40
+ // Base configs (always included)
41
+ ...baseConfig(),
42
+ // TypeScript config (scoped to JS/TS files)
43
+ {
44
+ files: jsFiles,
45
+ ...typescriptConfig()[0],
46
+ },
47
+ ...importsConfig(),
48
+ ...stylisticConfig(),
49
+ ];
50
+ // Optional configs
51
+ if (!disable.react) {
52
+ configs.push(...reactConfig());
53
+ }
54
+ if (!disable.vitest) {
55
+ configs.push(...vitestConfig());
56
+ }
57
+ if (!disable.perfectionist) {
58
+ configs.push(...perfectionistConfig());
59
+ }
60
+ if (!disable.unicorn) {
61
+ configs.push(...unicornConfig());
62
+ }
63
+ if (!disable.jsdoc) {
64
+ configs.push(...jsdocConfig());
65
+ }
66
+ if (!disable.tanstack) {
67
+ configs.push(...tanstackConfig());
68
+ }
69
+ if (!disable.lodash) {
70
+ configs.push(...lodashConfig());
71
+ }
72
+ if (enablePrairielearn) {
73
+ configs.push(...prairieLearnConfig(prairieLearnOptions));
74
+ }
75
+ // Type-aware rules (applied to specified files)
76
+ // We use tseslint.config() to properly handle the extends syntax
77
+ configs.push(...tseslint.config({
78
+ extends: [
79
+ tseslint.configs.recommendedTypeCheckedOnly,
80
+ tseslint.configs.stylisticTypeCheckedOnly,
81
+ ],
82
+ files: typeAwareFiles,
83
+ languageOptions: {
84
+ parserOptions: {
85
+ projectService: {
86
+ allowDefaultProject,
87
+ },
88
+ tsconfigRootDir,
89
+ },
90
+ },
91
+ rules: typescriptTypeAwareRules(),
92
+ }));
93
+ // Default ignores
94
+ return [
95
+ ...configs,
96
+ globalIgnores(['.yarn/*', 'node_modules/*', 'dist/*', 'coverage/*', ...ignores]),
97
+ ];
98
+ }
99
+ // Re-export individual configs for advanced use
100
+ export { baseConfig } from './configs/base.js';
101
+ export { importsConfig } from './configs/imports.js';
102
+ export { jsdocConfig } from './configs/jsdoc.js';
103
+ export { lodashConfig } from './configs/lodash.js';
104
+ export { perfectionistConfig } from './configs/perfectionist.js';
105
+ export { prairieLearnConfig } from './configs/prairielearn.js';
106
+ export { reactConfig } from './configs/react.js';
107
+ export { stylisticConfig } from './configs/stylistic.js';
108
+ export { tanstackConfig } from './configs/tanstack.js';
109
+ export { typescriptConfig, typescriptTypeAwareRules } from './configs/typescript.js';
110
+ export { unicornConfig } from './configs/unicorn.js';
111
+ export { vitestConfig } from './configs/vitest.js';
112
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"]}
package/package.json CHANGED
@@ -1,10 +1,52 @@
1
1
  {
2
2
  "name": "@prairielearn/eslint-config",
3
- "version": "0.0.1",
4
- "description": "OIDC trusted publishing setup package for @prairielearn/eslint-config",
5
- "keywords": [
6
- "oidc",
7
- "trusted-publishing",
8
- "setup"
9
- ]
3
+ "version": "1.1.0",
4
+ "type": "module",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/PrairieLearn/PrairieLearn.git",
8
+ "directory": "packages/eslint-config"
9
+ },
10
+ "engines": {
11
+ "node": ">=24.0.0"
12
+ },
13
+ "main": "./dist/index.js",
14
+ "exports": {
15
+ ".": "./dist/index.js"
16
+ },
17
+ "scripts": {
18
+ "build": "tsgo",
19
+ "dev": "tsgo --watch --preserveWatchOutput"
20
+ },
21
+ "peerDependencies": {
22
+ "eslint": "^9.0.0",
23
+ "typescript": "^5.0.0"
24
+ },
25
+ "dependencies": {
26
+ "@eslint-react/eslint-plugin": "^2.9.4",
27
+ "@eslint/eslintrc": "^3.0.0",
28
+ "@eslint/js": "^9.29.0",
29
+ "@prairielearn/eslint-plugin": "^3.1.1",
30
+ "@stylistic/eslint-plugin": "^5.7.0",
31
+ "@tanstack/eslint-plugin-query": "^5.91.2",
32
+ "@typescript-eslint/utils": "^8.53.0",
33
+ "@vitest/eslint-plugin": "^1.6.6",
34
+ "eslint-import-resolver-typescript": "^4.4.4",
35
+ "eslint-plugin-import-x": "^4.16.1",
36
+ "eslint-plugin-jsdoc": "^62.0.0",
37
+ "eslint-plugin-jsx-a11y-x": "^0.1.1",
38
+ "eslint-plugin-no-floating-promise": "^2.0.0",
39
+ "eslint-plugin-perfectionist": "^5.3.1",
40
+ "eslint-plugin-react-hooks": "^7.0.1",
41
+ "eslint-plugin-react-you-might-not-need-an-effect": "^0.8.5",
42
+ "eslint-plugin-unicorn": "^62.0.0",
43
+ "eslint-plugin-you-dont-need-lodash-underscore": "^6.14.0",
44
+ "globals": "^16.5.0",
45
+ "typescript-eslint": "^8.53.0"
46
+ },
47
+ "devDependencies": {
48
+ "@prairielearn/tsconfig": "^2.0.0",
49
+ "@types/node": "^24.10.9",
50
+ "@typescript/native-preview": "^7.0.0-dev.20260106.1"
51
+ }
10
52
  }
@@ -0,0 +1,127 @@
1
+ import js from '@eslint/js';
2
+ import type { TSESLint } from '@typescript-eslint/utils';
3
+ import noFloatingPromise from 'eslint-plugin-no-floating-promise';
4
+ import globals from 'globals';
5
+
6
+ /**
7
+ * Base JavaScript/TypeScript configuration.
8
+ * Core rules that apply to all JS/TS files.
9
+ */
10
+ export function baseConfig(): TSESLint.FlatConfig.ConfigArray {
11
+ return [
12
+ {
13
+ languageOptions: {
14
+ globals: { ...globals.node },
15
+ },
16
+
17
+ linterOptions: {
18
+ reportUnusedDisableDirectives: 'error',
19
+ },
20
+
21
+ plugins: {
22
+ 'no-floating-promise': noFloatingPromise,
23
+ },
24
+
25
+ rules: {
26
+ ...js.configs.all.rules,
27
+ 'array-callback-return': 'off',
28
+ 'arrow-body-style': 'off',
29
+ camelcase: 'off',
30
+ 'capitalized-comments': 'off',
31
+ 'class-methods-use-this': 'off',
32
+ complexity: 'off',
33
+ 'consistent-return': 'off',
34
+ 'consistent-this': 'off',
35
+ curly: ['error', 'multi-line', 'consistent'],
36
+ 'default-case': 'off',
37
+ 'dot-notation': 'off',
38
+ eqeqeq: ['error', 'smart'],
39
+ 'func-names': 'off',
40
+ 'func-style': 'off',
41
+ 'guard-for-in': 'off',
42
+ 'handle-callback-err': 'error',
43
+ 'id-length': 'off',
44
+ 'init-declarations': 'off',
45
+ 'logical-assignment-operators': 'off',
46
+ 'max-classes-per-file': 'off',
47
+ 'max-depth': 'off',
48
+ 'max-lines': 'off',
49
+ 'max-lines-per-function': 'off',
50
+ 'max-params': ['error', { max: 6 }],
51
+ 'max-statements': 'off',
52
+ 'new-cap': 'off',
53
+ 'no-await-in-loop': 'off',
54
+ 'no-bitwise': 'off',
55
+ 'no-console': ['error', { allow: ['warn', 'error', 'table', 'trace'] }],
56
+ 'no-continue': 'off',
57
+ 'no-duplicate-imports': 'error',
58
+ 'no-else-return': 'off',
59
+ 'no-empty-function': 'off',
60
+ 'no-eq-null': 'off',
61
+ 'no-implicit-coercion': 'off',
62
+ 'no-inline-comments': 'off',
63
+ 'no-invalid-this': 'off',
64
+ 'no-lonely-if': 'off',
65
+ 'no-loop-func': 'off',
66
+ 'no-magic-numbers': 'off',
67
+ 'no-negated-condition': 'off',
68
+ 'no-nested-ternary': 'off',
69
+ 'no-new': 'off',
70
+ 'no-param-reassign': 'off',
71
+ 'no-plusplus': 'off',
72
+ 'no-promise-executor-return': 'off',
73
+ 'no-redeclare': 'off',
74
+ 'no-restricted-globals': [
75
+ 'error',
76
+ // These are not available in ES modules.
77
+ '__filename',
78
+ '__dirname',
79
+ ],
80
+ 'no-shadow': 'off',
81
+ 'no-template-curly-in-string': 'error',
82
+ 'no-ternary': 'off',
83
+ 'no-undef': 'off',
84
+ 'no-undef-init': 'off',
85
+ 'no-undefined': 'off',
86
+ 'no-underscore-dangle': 'off',
87
+ 'no-unmodified-loop-condition': 'off',
88
+ 'no-unneeded-ternary': 'off',
89
+ 'no-unused-vars': 'off',
90
+ 'no-use-before-define': 'off',
91
+ 'no-useless-assignment': 'off',
92
+ 'no-useless-concat': 'off',
93
+ 'no-useless-constructor': 'off',
94
+ 'no-useless-return': 'off',
95
+ 'no-void': 'off', // https://typescript-eslint.io/rules/no-floating-promises/#ignorevoid
96
+ 'no-warning-comments': 'off',
97
+ 'object-shorthand': 'error',
98
+ 'one-var': ['off', 'never'],
99
+ 'prefer-arrow-callback': 'off',
100
+ 'prefer-const': ['error', { destructuring: 'all' }],
101
+ 'prefer-destructuring': 'off',
102
+ 'prefer-named-capture-group': 'off',
103
+ 'prefer-object-has-own': 'off',
104
+ 'prefer-template': 'off',
105
+ radix: ['error', 'as-needed'],
106
+ 'require-atomic-updates': 'off',
107
+ 'require-await': 'off',
108
+ 'require-unicode-regexp': 'off',
109
+ 'sort-vars': 'off',
110
+ 'sort-keys': 'off',
111
+
112
+ // Floating promise detection
113
+ 'no-floating-promise/no-floating-promise': 'error',
114
+
115
+ // Sort imports within a single import statement
116
+ 'sort-imports': [
117
+ 'error',
118
+ {
119
+ ignoreDeclarationSort: true,
120
+ ignoreMemberSort: false,
121
+ memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
122
+ },
123
+ ],
124
+ },
125
+ },
126
+ ];
127
+ }
@@ -0,0 +1,50 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
+ import importX from 'eslint-plugin-import-x';
3
+
4
+ /**
5
+ * Import ordering and resolution rules.
6
+ */
7
+ export function importsConfig(): TSESLint.FlatConfig.ConfigArray {
8
+ return [
9
+ {
10
+ plugins: {
11
+ 'import-x': importX,
12
+ },
13
+
14
+ rules: {
15
+ // Enforce alphabetical order of import specifiers within each import group.
16
+ // The import-x/order rule handles the overall sorting of the import groups.
17
+ 'import-x/order': [
18
+ 'error',
19
+ {
20
+ alphabetize: {
21
+ order: 'asc',
22
+ },
23
+
24
+ 'newlines-between': 'always',
25
+
26
+ pathGroups: [
27
+ {
28
+ group: 'external',
29
+ pattern: '@prairielearn/**',
30
+ position: 'after',
31
+ },
32
+ ],
33
+
34
+ pathGroupsExcludedImportTypes: ['builtin'],
35
+ },
36
+ ],
37
+ },
38
+
39
+ settings: {
40
+ 'import-x/parsers': {
41
+ '@typescript-eslint/parser': ['.ts', '.js'],
42
+ },
43
+ 'import-x/resolver': {
44
+ node: true,
45
+ typescript: true,
46
+ },
47
+ },
48
+ },
49
+ ];
50
+ }
@@ -0,0 +1,72 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
+ import jsdoc from 'eslint-plugin-jsdoc';
3
+
4
+ /**
5
+ * JSDoc documentation rules.
6
+ */
7
+ export function jsdocConfig(): TSESLint.FlatConfig.ConfigArray {
8
+ return [
9
+ {
10
+ plugins: {
11
+ jsdoc,
12
+ },
13
+
14
+ settings: {
15
+ jsdoc: {
16
+ contexts: [
17
+ // We don't want to require documentation of a 'locals' (res.locals) variable
18
+ // AST Parser: https://github.com/es-joy/jsdoccomment
19
+ {
20
+ comment: 'JsdocBlock:not(:has(JsdocTag[tag="param"][name="locals"]))',
21
+ context: 'FunctionDeclaration',
22
+ },
23
+ {
24
+ comment: 'JsdocBlock:not(:has(JsdocTag[tag="param"][name="locals"]))',
25
+ context: 'FunctionExpression',
26
+ },
27
+ 'ArrowFunctionExpression',
28
+ 'TSDeclareFunction',
29
+ ],
30
+ exemptDestructuredRootsFromChecks: true,
31
+ },
32
+ },
33
+ },
34
+ // TypeScript files
35
+ {
36
+ files: ['**/*.{ts,tsx}'],
37
+ rules: {
38
+ ...jsdoc.configs['flat/recommended-typescript-error'].rules,
39
+ 'jsdoc/check-line-alignment': 'error',
40
+ 'jsdoc/check-tag-names': ['error', { definedTags: ['knipignore'] }],
41
+ 'jsdoc/convert-to-jsdoc-comments': [
42
+ 'error',
43
+ {
44
+ allowedPrefixes: ['@ts-', 'istanbul ', 'c8 ', 'v8 ', 'eslint', 'prettier-', 'global'],
45
+ contexts: ['FunctionDeclaration', 'TSDeclareFunction'],
46
+ contextsBeforeAndAfter: ['TSPropertySignature'],
47
+ enforceJsdocLineStyle: 'single',
48
+ },
49
+ ],
50
+ 'jsdoc/require-asterisk-prefix': 'error',
51
+ 'jsdoc/require-jsdoc': 'off',
52
+ 'jsdoc/require-param': 'off',
53
+ 'jsdoc/require-returns': 'off',
54
+ 'jsdoc/tag-lines': 'off',
55
+ },
56
+ },
57
+ // JavaScript files
58
+ {
59
+ files: ['**/*.js'],
60
+ rules: {
61
+ ...jsdoc.configs['flat/recommended-typescript-flavor-error'].rules,
62
+ 'jsdoc/check-line-alignment': 'error',
63
+ 'jsdoc/require-asterisk-prefix': 'error',
64
+ 'jsdoc/require-jsdoc': 'off',
65
+ 'jsdoc/require-param': 'off',
66
+ 'jsdoc/require-param-description': 'off',
67
+ 'jsdoc/require-returns': 'off',
68
+ 'jsdoc/tag-lines': 'off',
69
+ },
70
+ },
71
+ ];
72
+ }
@@ -0,0 +1,26 @@
1
+ import { FlatCompat } from '@eslint/eslintrc';
2
+ import type { TSESLint } from '@typescript-eslint/utils';
3
+ import youDontNeedLodashUnderscore from 'eslint-plugin-you-dont-need-lodash-underscore';
4
+
5
+ const compat = new FlatCompat();
6
+
7
+ /**
8
+ * Lodash/underscore replacement rules.
9
+ */
10
+ export function lodashConfig(): TSESLint.FlatConfig.ConfigArray {
11
+ return [
12
+ {
13
+ plugins: {
14
+ 'you-dont-need-lodash-underscore': youDontNeedLodashUnderscore,
15
+ },
16
+ },
17
+ // Use FlatCompat to extend the legacy config
18
+ ...compat.extends('plugin:you-dont-need-lodash-underscore/all'),
19
+ {
20
+ rules: {
21
+ // The _.omit function is still useful in some contexts.
22
+ 'you-dont-need-lodash-underscore/omit': 'off',
23
+ },
24
+ },
25
+ ];
26
+ }
@@ -0,0 +1,48 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
+ import perfectionist from 'eslint-plugin-perfectionist';
3
+
4
+ /**
5
+ * Perfectionist sorting rules.
6
+ * Most rules are off by default but pre-configured for convenient inline enabling.
7
+ * `sort-jsx-props` is enabled by default with callback grouping.
8
+ */
9
+ export function perfectionistConfig(): TSESLint.FlatConfig.ConfigArray {
10
+ return [
11
+ {
12
+ plugins: {
13
+ perfectionist,
14
+ },
15
+
16
+ rules: {
17
+ // Configure all perfectionist rules to be off by default but with options preset
18
+ ...Object.fromEntries(
19
+ Object.keys(perfectionist.rules ?? {}).map((ruleName) => [
20
+ 'perfectionist/' + ruleName,
21
+ [
22
+ // Configure the options for every rule, to make inline usage more convenient.
23
+ 'off',
24
+ // These rules don't have a comment partition
25
+ ['sort-heritage-clauses', 'sort-jsx-props', 'sort-switch-case'].includes(ruleName)
26
+ ? { type: 'natural' }
27
+ : { partitionByComment: true, type: 'natural' },
28
+ ],
29
+ ]),
30
+ ),
31
+
32
+ // Enable sort-jsx-props with callback grouping
33
+ 'perfectionist/sort-jsx-props': [
34
+ 'error',
35
+ {
36
+ customGroups: [
37
+ { elementNamePattern: '^on[A-Z]', groupName: 'callback' },
38
+ { elementNamePattern: '^(key|ref)$', groupName: 'reserved' },
39
+ ],
40
+ groups: ['reserved', 'unknown', 'shorthand-prop', 'callback'],
41
+ ignoreCase: true,
42
+ type: 'unsorted',
43
+ },
44
+ ],
45
+ },
46
+ },
47
+ ];
48
+ }
@@ -0,0 +1,42 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
+
3
+ import prairielearn from '@prairielearn/eslint-plugin';
4
+
5
+ export interface PrairieLearnPluginOptions {
6
+ /**
7
+ * Types to allow when using the safe-db-types rule.
8
+ */
9
+ allowDbTypes?: string[];
10
+ }
11
+
12
+ /**
13
+ * PrairieLearn-specific ESLint plugin rules.
14
+ * Includes AWS client configuration, JSX safety, SQL blocks, and database type safety.
15
+ */
16
+ export function prairieLearnConfig(
17
+ options?: PrairieLearnPluginOptions,
18
+ ): TSESLint.FlatConfig.ConfigArray {
19
+ const { allowDbTypes = [] } = options ?? {};
20
+
21
+ return [
22
+ {
23
+ plugins: {
24
+ '@prairielearn': prairielearn,
25
+ },
26
+
27
+ rules: {
28
+ '@prairielearn/aws-client-mandatory-config': 'error',
29
+ '@prairielearn/aws-client-shared-config': 'error',
30
+ '@prairielearn/jsx-no-dollar-interpolation': 'error',
31
+ '@prairielearn/no-current-target-in-callback': 'error',
32
+ '@prairielearn/no-unused-sql-blocks': 'error',
33
+ '@prairielearn/safe-db-types': [
34
+ 'error',
35
+ {
36
+ allowDbTypes,
37
+ },
38
+ ],
39
+ },
40
+ },
41
+ ];
42
+ }