@jterrazz/typescript 9.2.1 → 10.0.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/README.md +20 -16
  2. package/bin/commands/check.sh +348 -117
  3. package/bin/typescript.sh +55 -0
  4. package/lib/check-architecture.js +89 -0
  5. package/lib/check-baseline.js +144 -0
  6. package/lib/check-docs.js +4 -3
  7. package/lib/check-drift.js +209 -0
  8. package/lib/check-gitignore.js +4 -4
  9. package/lib/check-markdown.js +279 -0
  10. package/lib/check-names.js +125 -0
  11. package/lib/check-publish.js +150 -0
  12. package/lib/check-secrets.js +115 -0
  13. package/lib/check-suppressions.js +355 -0
  14. package/lib/doctor.js +185 -0
  15. package/lib/merge-knip-config.js +57 -25
  16. package/lib/tracked-files.js +165 -0
  17. package/lib/workspace-members.js +5 -6
  18. package/package.json +19 -8
  19. package/presets/oxfmt/index.js +49 -5
  20. package/presets/oxlint/profiles/astro.js +10 -0
  21. package/presets/oxlint/profiles/bun.js +7 -0
  22. package/presets/oxlint/profiles/expo.js +7 -0
  23. package/presets/oxlint/profiles/library.js +16 -0
  24. package/presets/oxlint/profiles/next.js +7 -0
  25. package/presets/oxlint/profiles/node.js +7 -0
  26. package/presets/prettier/astro.json +6 -0
  27. package/presets/tsconfig/expo.json +16 -6
  28. package/presets/tsconfig/library.json +18 -0
  29. package/presets/tsconfig/next.json +12 -2
  30. package/presets/tsconfig/node.json +18 -4
  31. package/rules/README.md +23 -0
  32. package/rules/_contract.js +191 -0
  33. package/rules/_contract.test.ts +81 -0
  34. package/rules/a11y.js +51 -0
  35. package/rules/architecture/hexagonal.js +56 -0
  36. package/rules/architecture/layers.js +75 -0
  37. package/rules/astro.js +49 -0
  38. package/rules/catalog.js +134 -0
  39. package/rules/catalog.test.ts +84 -0
  40. package/rules/compile.js +125 -0
  41. package/rules/core/eslint.js +234 -0
  42. package/rules/core/import.js +107 -0
  43. package/rules/core/jsdoc.js +52 -0
  44. package/rules/core/node.js +36 -0
  45. package/rules/core/oxc.js +54 -0
  46. package/rules/core/promise.js +39 -0
  47. package/rules/core/typescript.js +204 -0
  48. package/rules/core/unicorn.js +200 -0
  49. package/rules/next.js +53 -0
  50. package/rules/profiles.js +89 -0
  51. package/rules/react-native.js +48 -0
  52. package/rules/react.js +148 -0
  53. package/rules/sorted.js +41 -0
  54. package/rules/vitest.js +153 -0
  55. package/src/docs.d.ts +4 -4
  56. package/src/docs.js +75 -47
  57. package/src/docs.test.ts +136 -29
  58. package/src/index.d.ts +13 -9
  59. package/src/index.js +15 -8
  60. package/src/oxfmt.d.ts +15 -2
  61. package/src/oxfmt.test.ts +10 -0
  62. package/src/oxlint.d.ts +57 -10
  63. package/src/oxlint.js +35 -50
  64. package/src/oxlint.test.ts +82 -28
  65. package/presets/oxlint/architectures/hexagonal-rules.js +0 -39
  66. package/presets/oxlint/architectures/hexagonal.js +0 -13
  67. package/presets/oxlint/base.js +0 -145
  68. package/presets/oxlint/expo.js +0 -36
  69. package/presets/oxlint/next.js +0 -43
  70. package/presets/oxlint/node.js +0 -14
  71. package/presets/oxlint/plugins/codestyle.js +0 -231
@@ -0,0 +1,54 @@
1
+ import { allOn, fragment, off } from '../_contract.js';
2
+
3
+ /*
4
+ * The `oxc` plugin, all 27 rules decided by name. Three of them are
5
+ * downlevel-syntax restrictions — they exist for a target older than the one
6
+ * the estate compiles to — and they are the only three that are off.
7
+ */
8
+ export default fragment({
9
+ id: 'core/oxc',
10
+ plugins: ['oxc'],
11
+ rules: {
12
+ ...allOn(
13
+ [
14
+ 'approx-constant',
15
+ 'bad-array-method-on-arguments',
16
+ 'bad-bitwise-operator',
17
+ 'bad-char-at-comparison',
18
+ 'bad-comparison-sequence',
19
+ 'bad-match-all-arg',
20
+ 'bad-min-max-func',
21
+ 'bad-object-literal-comparison',
22
+ 'bad-replace-all-arg',
23
+ 'branches-sharing-code',
24
+ 'const-comparisons',
25
+ 'double-comparisons',
26
+ 'erasing-op',
27
+ 'misrefactored-assign-op',
28
+ 'missing-throw',
29
+ 'no-accumulating-spread',
30
+ 'no-async-endpoint-handlers',
31
+ 'no-barrel-file',
32
+ 'no-const-enum',
33
+ 'no-map-spread',
34
+ 'no-this-in-exported-function',
35
+ 'number-arg-out-of-range',
36
+ 'only-used-in-recursion',
37
+ 'uninvoked-array-callback',
38
+ ].map((rule) => `oxc/${rule}`),
39
+ ),
40
+
41
+ 'oxc/no-async-await': off({
42
+ by: 'promise/prefer-await-to-then — one rule demands await, the other forbids it',
43
+ kind: 'exclusive',
44
+ }),
45
+ 'oxc/no-optional-chaining': off({
46
+ by: 'docs/07-lint-presets.md — the estate compiles to ESNext on Node 24, where optional chaining is native syntax',
47
+ kind: 'convention',
48
+ }),
49
+ 'oxc/no-rest-spread-properties': off({
50
+ by: 'docs/07-lint-presets.md — the estate compiles to ESNext on Node 24, where object rest and spread are native syntax',
51
+ kind: 'convention',
52
+ }),
53
+ },
54
+ });
@@ -0,0 +1,39 @@
1
+ import { allOn, fragment, off } from '../_contract.js';
2
+
3
+ /*
4
+ * The `promise` plugin, all 15 non-nursery rules decided by name. The estate
5
+ * writes `await`, so the two rules that describe a well-behaved `.then()`
6
+ * chain are the ones that cannot hold beside `prefer-await-to-then`.
7
+ */
8
+ export default fragment({
9
+ id: 'core/promise',
10
+ plugins: ['promise'],
11
+ rules: {
12
+ ...allOn(
13
+ [
14
+ 'avoid-new',
15
+ 'no-callback-in-promise',
16
+ 'no-multiple-resolved',
17
+ 'no-nesting',
18
+ 'no-new-statics',
19
+ 'no-promise-in-callback',
20
+ 'no-return-wrap',
21
+ 'param-names',
22
+ 'prefer-await-to-callbacks',
23
+ 'prefer-await-to-then',
24
+ 'prefer-catch',
25
+ 'spec-only',
26
+ 'valid-params',
27
+ ].map((rule) => `promise/${rule}`),
28
+ ),
29
+
30
+ 'promise/always-return': off({
31
+ by: 'promise/prefer-await-to-then — it describes a .then() chain the estate does not write',
32
+ kind: 'exclusive',
33
+ }),
34
+ 'promise/catch-or-return': off({
35
+ by: 'promise/prefer-await-to-then — it describes a .then() chain the estate does not write',
36
+ kind: 'exclusive',
37
+ }),
38
+ },
39
+ });
@@ -0,0 +1,204 @@
1
+ import { allOn, fragment, off, on, scoped, typeAware } from '../_contract.js';
2
+
3
+ /*
4
+ * The `typescript` plugin, all 108 non-nursery rules decided by name. Fifty-one
5
+ * of them need type information: they run because every profile ships
6
+ * `options.typeAware`, which `oxlint-tsgolint` answers (it embeds its own
7
+ * TypeScript, so a consumer is not forced onto TypeScript 7 to get them).
8
+ */
9
+ /*
10
+ * A JavaScript file has no parameter types. Every value flowing through one is
11
+ * `any` by construction, so the unsafe-any family reports the LANGUAGE, not a
12
+ * defect — measured on this package's own tree, 530 reports of which not one
13
+ * named a bug. The family stays armed everywhere TypeScript types the code.
14
+ */
15
+ const UNTYPED_BY_CONSTRUCTION = {
16
+ by: 'TypeScript — a .js file has no parameter types, so every value in it is `any` and the rule reports the language, not a defect',
17
+ kind: 'covered',
18
+ };
19
+
20
+ const UNTYPED_IN_JAVASCRIPT = [
21
+ 'no-unsafe-argument',
22
+ 'no-unsafe-assignment',
23
+ 'no-unsafe-call',
24
+ 'no-unsafe-enum-comparison',
25
+ 'no-unsafe-member-access',
26
+ 'no-unsafe-return',
27
+ 'no-unsafe-type-assertion',
28
+ 'no-unsafe-unary-minus',
29
+ 'strict-boolean-expressions',
30
+ ].map((rule) => [`typescript/${rule}`, off(UNTYPED_BY_CONSTRUCTION)]);
31
+
32
+ export default fragment({
33
+ id: 'core/typescript',
34
+ plugins: ['typescript'],
35
+ overrides: [
36
+ scoped({
37
+ files: ['**/*.js', '**/*.cjs', '**/*.mjs'],
38
+ rules: Object.fromEntries(UNTYPED_IN_JAVASCRIPT),
39
+ }),
40
+ ],
41
+ rules: {
42
+ ...allOn(
43
+ [
44
+ 'adjacent-overload-signatures',
45
+ 'ban-tslint-comment',
46
+ 'class-literal-property-style',
47
+ 'consistent-generic-constructors',
48
+ 'consistent-indexed-object-style',
49
+ 'consistent-type-assertions',
50
+ 'no-confusing-non-null-assertion',
51
+ 'no-duplicate-enum-values',
52
+ 'no-dynamic-delete',
53
+ 'no-empty-object-type',
54
+ 'no-explicit-any',
55
+ 'no-extra-non-null-assertion',
56
+ 'no-extraneous-class',
57
+ 'no-inferrable-types',
58
+ 'no-invalid-void-type',
59
+ 'no-misused-new',
60
+ 'no-namespace',
61
+ 'no-non-null-asserted-nullish-coalescing',
62
+ 'no-non-null-asserted-optional-chain',
63
+ 'no-non-null-assertion',
64
+ 'no-require-imports',
65
+ 'no-restricted-types',
66
+ 'no-this-alias',
67
+ 'no-unnecessary-parameter-property-assignment',
68
+ 'no-unnecessary-type-constraint',
69
+ 'no-unsafe-declaration-merging',
70
+ 'no-unsafe-function-type',
71
+ 'no-useless-empty-export',
72
+ 'no-wrapper-object-types',
73
+ 'parameter-properties',
74
+ 'prefer-as-const',
75
+ 'prefer-enum-initializers',
76
+ 'prefer-for-of',
77
+ 'prefer-function-type',
78
+ 'prefer-literal-enum-member',
79
+ 'prefer-namespace-keyword',
80
+ 'prefer-ts-expect-error',
81
+ 'triple-slash-reference',
82
+ 'unified-signatures',
83
+ ].map((rule) => `typescript/${rule}`),
84
+ ),
85
+
86
+ // -- On, and type-aware ----------------------------------------------
87
+ ...Object.fromEntries(
88
+ [
89
+ 'await-thenable',
90
+ 'consistent-return',
91
+ 'consistent-type-exports',
92
+ 'dot-notation',
93
+ 'no-array-delete',
94
+ 'no-base-to-string',
95
+ 'no-confusing-void-expression',
96
+ 'no-deprecated',
97
+ 'no-duplicate-type-constituents',
98
+ 'no-floating-promises',
99
+ 'no-for-in-array',
100
+ 'no-implied-eval',
101
+ 'no-meaningless-void-operator',
102
+ 'no-misused-promises',
103
+ 'no-misused-spread',
104
+ 'no-mixed-enums',
105
+ 'no-redundant-type-constituents',
106
+ 'no-unnecessary-boolean-literal-compare',
107
+ 'no-unnecessary-qualifier',
108
+ 'no-unnecessary-template-expression',
109
+ 'no-unnecessary-type-arguments',
110
+ 'no-unnecessary-type-assertion',
111
+ 'no-unnecessary-type-conversion',
112
+ 'no-unnecessary-type-parameters',
113
+ 'no-unsafe-argument',
114
+ 'no-unsafe-assignment',
115
+ 'no-unsafe-call',
116
+ 'no-unsafe-enum-comparison',
117
+ 'no-unsafe-member-access',
118
+ 'no-unsafe-return',
119
+ 'no-unsafe-type-assertion',
120
+ 'no-unsafe-unary-minus',
121
+ 'no-useless-default-assignment',
122
+ 'non-nullable-type-assertion-style',
123
+ 'only-throw-error',
124
+ 'prefer-find',
125
+ 'prefer-includes',
126
+ 'prefer-promise-reject-errors',
127
+ 'prefer-readonly',
128
+ 'prefer-reduce-type-parameter',
129
+ 'prefer-regexp-exec',
130
+ 'prefer-return-this-type',
131
+ 'prefer-string-starts-ends-with',
132
+ 'promise-function-async',
133
+ 'related-getter-setter-pairs',
134
+ 'require-array-sort-compare',
135
+ 'require-await',
136
+ 'restrict-plus-operands',
137
+ 'restrict-template-expressions',
138
+ 'strict-boolean-expressions',
139
+ 'strict-void-return',
140
+ 'switch-exhaustiveness-check',
141
+ 'unbound-method',
142
+ 'use-unknown-in-catch-callback-variable',
143
+ ].map((rule) => [`typescript/${rule}`, typeAware()]),
144
+ ),
145
+
146
+ // -- On, at the strictest value the option carries ---------------------
147
+ 'typescript/array-type': on([{ default: 'array' }]),
148
+ 'typescript/ban-ts-comment': on([
149
+ {
150
+ 'ts-check': false,
151
+ 'ts-expect-error': 'allow-with-description',
152
+ 'ts-ignore': true,
153
+ 'ts-nocheck': true,
154
+ },
155
+ ]),
156
+ 'typescript/consistent-type-definitions': on(['type']),
157
+ 'typescript/consistent-type-imports': on([
158
+ {
159
+ disallowTypeAnnotations: true,
160
+ fixStyle: 'inline-type-imports',
161
+ prefer: 'type-imports',
162
+ },
163
+ ]),
164
+ 'typescript/explicit-member-accessibility': on([{ accessibility: 'no-public' }]),
165
+ /* Booleans excepted: `false ?? x` is `false` and `false || x` is `x`,
166
+ * so on a boolean the two operators mean different things and the
167
+ * rewrite the rule asks for is not the same expression. */
168
+ 'typescript/prefer-nullish-coalescing': typeAware([
169
+ { ignorePrimitives: { boolean: true } },
170
+ ]),
171
+ 'typescript/method-signature-style': on(['property']),
172
+ 'typescript/return-await': typeAware(['always']),
173
+
174
+ // -- Off, each with its one reason -------------------------------------
175
+ 'typescript/ban-types': off({
176
+ by: 'typescript/no-empty-object-type, no-unsafe-function-type, no-wrapper-object-types — its three successors',
177
+ kind: 'covered',
178
+ }),
179
+ 'typescript/explicit-function-return-type': off({
180
+ by: 'presets/tsconfig/library.json — isolatedDeclarations requires the annotation exactly where it is load-bearing',
181
+ kind: 'covered',
182
+ }),
183
+ 'typescript/explicit-module-boundary-types': off({
184
+ by: 'presets/tsconfig/library.json — isolatedDeclarations requires the annotation exactly where it is load-bearing',
185
+ kind: 'covered',
186
+ }),
187
+ 'typescript/no-import-type-side-effects': off({
188
+ by: 'import/consistent-type-specifier-style (prefer-inline) — an import whose specifiers are all inline types is exactly the form that rule asks for',
189
+ kind: 'exclusive',
190
+ }),
191
+ 'typescript/no-empty-interface': off({
192
+ by: 'typescript/no-empty-object-type — its upstream successor',
193
+ kind: 'covered',
194
+ }),
195
+ 'typescript/no-var-requires': off({
196
+ by: 'typescript/no-require-imports — its upstream successor',
197
+ kind: 'covered',
198
+ }),
199
+ 'typescript/prefer-readonly-parameter-types': off({
200
+ by: 'no-param-reassign, typescript/prefer-readonly — the defect is mutation, and both name it',
201
+ kind: 'covered',
202
+ }),
203
+ },
204
+ });
@@ -0,0 +1,200 @@
1
+ import { allOn, fragment, off, on } from '../_contract.js';
2
+
3
+ /*
4
+ * The `unicorn` plugin, all 137 non-nursery rules decided by name. Two of the
5
+ * offs are the formatter's: unicorn's fixer and oxfmt disagree about the same
6
+ * bytes, and the fixpoint suite is what proves it (specs/cli/preset).
7
+ */
8
+ export default fragment({
9
+ id: 'core/unicorn',
10
+ plugins: ['unicorn'],
11
+ rules: {
12
+ ...allOn(
13
+ [
14
+ 'catch-error-name',
15
+ 'consistent-assert',
16
+ 'consistent-date-clone',
17
+ 'consistent-empty-array-spread',
18
+ 'consistent-existence-index-check',
19
+ 'consistent-function-scoping',
20
+ 'consistent-template-literal-escape',
21
+ 'custom-error-definition',
22
+ 'empty-brace-spaces',
23
+ 'error-message',
24
+ 'escape-case',
25
+ 'explicit-timer-delay',
26
+ 'max-nested-calls',
27
+ 'new-for-builtins',
28
+ 'no-abusive-eslint-disable',
29
+ 'no-accessor-recursion',
30
+ 'no-anonymous-default-export',
31
+ 'no-array-fill-with-reference-type',
32
+ 'no-array-for-each',
33
+ 'no-array-method-this-argument',
34
+ 'no-array-reduce',
35
+ 'no-array-reverse',
36
+ 'no-array-sort',
37
+ 'no-await-expression-member',
38
+ 'no-await-in-promise-methods',
39
+ 'no-confusing-array-with',
40
+ 'no-console-spaces',
41
+ 'no-document-cookie',
42
+ 'no-empty-file',
43
+ 'no-hex-escape',
44
+ 'no-immediate-mutation',
45
+ 'no-instanceof-builtins',
46
+ 'no-invalid-fetch-options',
47
+ 'no-invalid-remove-event-listener',
48
+ 'no-length-as-slice-end',
49
+ 'no-lonely-if',
50
+ 'no-magic-array-flat-depth',
51
+ 'no-negated-condition',
52
+ 'no-negation-in-equality-check',
53
+ 'no-new-array',
54
+ 'no-new-buffer',
55
+ 'no-object-as-default-parameter',
56
+ 'no-process-exit',
57
+ 'no-single-promise-in-promise-methods',
58
+ 'no-static-only-class',
59
+ 'no-thenable',
60
+ 'no-this-assignment',
61
+ 'no-typeof-undefined',
62
+ 'no-unnecessary-array-flat-depth',
63
+ 'no-unnecessary-array-splice-count',
64
+ 'no-unnecessary-await',
65
+ 'no-unnecessary-slice-end',
66
+ 'no-unreadable-array-destructuring',
67
+ 'no-unreadable-iife',
68
+ 'no-useless-collection-argument',
69
+ 'no-useless-error-capture-stack-trace',
70
+ 'no-useless-fallback-in-spread',
71
+ 'no-useless-length-check',
72
+ 'no-useless-promise-resolve-reject',
73
+ 'no-useless-spread',
74
+ 'no-useless-switch-case',
75
+ 'no-useless-undefined',
76
+ 'no-zero-fractions',
77
+ 'numeric-separators-style',
78
+ 'prefer-add-event-listener',
79
+ 'prefer-array-find',
80
+ 'prefer-array-flat',
81
+ 'prefer-array-flat-map',
82
+ 'prefer-array-index-of',
83
+ 'prefer-array-some',
84
+ 'prefer-at',
85
+ 'prefer-bigint-literals',
86
+ 'prefer-blob-reading-methods',
87
+ 'prefer-class-fields',
88
+ 'prefer-classlist-toggle',
89
+ 'prefer-code-point',
90
+ 'prefer-date-now',
91
+ 'prefer-default-parameters',
92
+ 'prefer-dom-node-append',
93
+ 'prefer-dom-node-dataset',
94
+ 'prefer-dom-node-remove',
95
+ 'prefer-dom-node-text-content',
96
+ 'prefer-event-target',
97
+ 'prefer-export-from',
98
+ 'prefer-global-this',
99
+ 'prefer-import-meta-properties',
100
+ 'prefer-keyboard-event-key',
101
+ 'prefer-logical-operator-over-ternary',
102
+ 'prefer-math-min-max',
103
+ 'prefer-math-trunc',
104
+ 'prefer-modern-dom-apis',
105
+ 'prefer-modern-math-apis',
106
+ 'prefer-module',
107
+ 'prefer-native-coercion-functions',
108
+ 'prefer-negative-index',
109
+ 'prefer-node-protocol',
110
+ 'prefer-number-properties',
111
+ 'prefer-object-from-entries',
112
+ 'prefer-optional-catch-binding',
113
+ 'prefer-prototype-methods',
114
+ 'prefer-query-selector',
115
+ 'prefer-reflect-apply',
116
+ 'prefer-regexp-test',
117
+ 'prefer-response-static-json',
118
+ 'prefer-set-has',
119
+ 'prefer-set-size',
120
+ 'prefer-single-call',
121
+ 'prefer-spread',
122
+ 'prefer-string-raw',
123
+ 'prefer-string-replace-all',
124
+ 'prefer-string-slice',
125
+ 'prefer-string-trim-start-end',
126
+ 'prefer-structured-clone',
127
+ 'prefer-ternary',
128
+ 'prefer-top-level-await',
129
+ 'prefer-type-error',
130
+ 'relative-url-style',
131
+ 'require-array-join-separator',
132
+ 'require-module-attributes',
133
+ 'require-module-specifiers',
134
+ 'require-number-to-fixed-digits-argument',
135
+ 'require-post-message-target-origin',
136
+ 'switch-case-braces',
137
+ 'switch-case-break-position',
138
+ 'throw-new-error',
139
+ ].map((rule) => `unicorn/${rule}`),
140
+ ),
141
+
142
+ // -- On, at the strictest value the option carries ---------------------
143
+ 'unicorn/filename-case': on([{ case: 'kebabCase' }]),
144
+ /* The estate imports a Node builtin by name — `import { resolve } from
145
+ * 'node:path'` — because that is what the type-aware rules read and what
146
+ * `verbatimModuleSyntax` keeps. The rule's default asks for the default
147
+ * import on exactly these three. */
148
+ 'unicorn/import-style': on([
149
+ {
150
+ styles: {
151
+ 'node:path': { named: true },
152
+ 'node:util': { named: true },
153
+ path: { named: true },
154
+ util: { named: true },
155
+ },
156
+ },
157
+ ]),
158
+ /* No `withDash`: the estate writes `'utf8'`, which is the rule's own
159
+ * default preference, and `'utf-8'` is the same encoding spelled longer. */
160
+ 'unicorn/text-encoding-identifier-case': on(),
161
+
162
+ // -- Off, each with its one reason -------------------------------------
163
+ 'unicorn/explicit-length-check': off({
164
+ by: 'typescript/strict-boolean-expressions — it already refuses a length used as a condition',
165
+ kind: 'covered',
166
+ }),
167
+ 'unicorn/no-array-callback-reference': off({
168
+ by: 'measured on this package — every report was a correct point-free callback',
169
+ kind: 'evidence',
170
+ }),
171
+ 'unicorn/no-instanceof-array': off({
172
+ by: 'unicorn/no-instanceof-builtins — its upstream successor',
173
+ kind: 'covered',
174
+ }),
175
+ 'unicorn/no-nested-ternary': off({
176
+ by: 'oxfmt — its fixer parenthesises the inner ternary and the formatter strips the parentheses, so every fix round ping-pongs',
177
+ kind: 'formatter',
178
+ }),
179
+ 'unicorn/no-null': off({
180
+ by: 'docs/07-lint-presets.md — null is what the platform and JSON APIs return, and a codebase that refuses it grows a translation layer at every boundary',
181
+ kind: 'convention',
182
+ }),
183
+ 'unicorn/prefer-number-coercion': off({
184
+ by: 'measured on this package — it rewrites `Number.parseInt("01-architecture.md", 10)`, which is 1, into `Math.trunc(Number(...))`, which is NaN; the rule assumes the string holds nothing but digits',
185
+ kind: 'evidence',
186
+ }),
187
+ 'unicorn/number-literal-case': off({
188
+ by: 'oxfmt — oxc#21949: the two disagree on the case of a hex literal and rewrite each other',
189
+ kind: 'formatter',
190
+ }),
191
+ 'unicorn/prefer-includes': off({
192
+ by: 'typescript/prefer-includes — the type-aware rule of the same name',
193
+ kind: 'covered',
194
+ }),
195
+ 'unicorn/prefer-string-starts-ends-with': off({
196
+ by: 'typescript/prefer-string-starts-ends-with — the type-aware rule of the same name',
197
+ kind: 'covered',
198
+ }),
199
+ },
200
+ });
package/rules/next.js ADDED
@@ -0,0 +1,53 @@
1
+ import { allOn, fragment, off, scoped } from './_contract.js';
2
+ import { EXTENSIONS_NEVER } from './core/import.js';
3
+
4
+ /*
5
+ * The `nextjs` plugin, all 21 rules on, plus the two decisions Next's own
6
+ * resolution forces: a bundler resolves an import, so a specifier carries no
7
+ * extension, and `next-env.d.ts` is a side-effect import Next writes itself.
8
+ */
9
+ export default fragment({
10
+ id: 'next',
11
+ plugins: ['nextjs'],
12
+ ignorePatterns: ['.next/**', 'next-env.d.ts', 'assets/**', 'public/**'],
13
+ overrides: [
14
+ scoped({
15
+ files: ['**/next-env.d.ts'],
16
+ rules: {
17
+ 'import/no-unassigned-import': off({
18
+ by: 'Next writes this file, and its whole body is a triple-slash reference',
19
+ kind: 'convention',
20
+ }),
21
+ },
22
+ }),
23
+ ],
24
+ rules: {
25
+ ...allOn(
26
+ [
27
+ 'google-font-display',
28
+ 'google-font-preconnect',
29
+ 'inline-script-id',
30
+ 'next-script-for-ga',
31
+ 'no-assign-module-variable',
32
+ 'no-async-client-component',
33
+ 'no-before-interactive-script-outside-document',
34
+ 'no-css-tags',
35
+ 'no-document-import-in-page',
36
+ 'no-duplicate-head',
37
+ 'no-head-element',
38
+ 'no-head-import-in-document',
39
+ 'no-html-link-for-pages',
40
+ 'no-img-element',
41
+ 'no-page-custom-font',
42
+ 'no-script-component-in-head',
43
+ 'no-styled-jsx-in-document',
44
+ 'no-sync-scripts',
45
+ 'no-title-in-document-head',
46
+ 'no-typos',
47
+ 'no-unwanted-polyfillio',
48
+ ].map((rule) => `nextjs/${rule}`),
49
+ ),
50
+
51
+ 'import/extensions': EXTENSIONS_NEVER,
52
+ },
53
+ });
@@ -0,0 +1,89 @@
1
+ import a11y from './a11y.js';
2
+ import astro from './astro.js';
3
+ import eslint from './core/eslint.js';
4
+ import importPlugin from './core/import.js';
5
+ import jsdoc from './core/jsdoc.js';
6
+ import node from './core/node.js';
7
+ import oxc from './core/oxc.js';
8
+ import promise from './core/promise.js';
9
+ import typescript from './core/typescript.js';
10
+ import unicorn from './core/unicorn.js';
11
+ import next from './next.js';
12
+ import reactNative from './react-native.js';
13
+ import react from './react.js';
14
+ import sorted from './sorted.js';
15
+ import vitest from './vitest.js';
16
+
17
+ /*
18
+ * Which fragments each profile carries. A profile ADDS a framework's plugins
19
+ * and its ignore patterns to the core rulebook; it never subtracts from it, and
20
+ * no profile sets a core rule to `off`
21
+ * ([Lint presets](../docs/07-lint-presets.md)).
22
+ *
23
+ * `presets/oxlint/profiles/<name>.js` is this table compiled; nothing else
24
+ * decides what a profile holds.
25
+ */
26
+
27
+ /** The rulebook every profile carries, whatever it is written in. */
28
+ export const CORE = Object.freeze([
29
+ eslint,
30
+ typescript,
31
+ unicorn,
32
+ oxc,
33
+ importPlugin,
34
+ promise,
35
+ node,
36
+ jsdoc,
37
+ sorted,
38
+ vitest,
39
+ ]);
40
+
41
+ /*
42
+ * Trees no profile lints. `.artifacts/` is deliberately absent: it is
43
+ * gitignored and oxlint reads `.gitignore` on its own, so naming it here too
44
+ * would make it unlintable even where a caller asks for it by name.
45
+ */
46
+ const IGNORED = Object.freeze([
47
+ 'dist/**',
48
+ 'node_modules/**',
49
+ // What a spec stands on and what it is measured against are @jterrazz/test
50
+ // 14's underscored trees: an input is deliberately broken and a golden is
51
+ // Byte-for-byte, so neither is source and neither is linted.
52
+ '**/_fixtures/**',
53
+ '**/_expected/**',
54
+ ]);
55
+
56
+ /** Every profile, by the name a consumer imports. */
57
+ export const PROFILES = Object.freeze({
58
+ astro: {
59
+ env: { astro: true, browser: true, builtin: true, node: true },
60
+ fragments: [...CORE, react, a11y, astro],
61
+ ignorePatterns: [...IGNORED],
62
+ },
63
+ bun: {
64
+ env: { builtin: true, node: true },
65
+ fragments: [...CORE],
66
+ globals: { Bun: 'readonly' },
67
+ ignorePatterns: [...IGNORED],
68
+ },
69
+ expo: {
70
+ env: { browser: true, builtin: true, node: true },
71
+ fragments: [...CORE, react, a11y, reactNative],
72
+ ignorePatterns: [...IGNORED],
73
+ },
74
+ library: {
75
+ env: { builtin: true, node: true },
76
+ fragments: [...CORE],
77
+ ignorePatterns: [...IGNORED, 'docs/reference/**'],
78
+ },
79
+ next: {
80
+ env: { browser: true, builtin: true, node: true },
81
+ fragments: [...CORE, react, a11y, next],
82
+ ignorePatterns: [...IGNORED],
83
+ },
84
+ node: {
85
+ env: { builtin: true, node: true },
86
+ fragments: [...CORE],
87
+ ignorePatterns: [...IGNORED],
88
+ },
89
+ });