@mouse_484/oxc-config 0.8.11 → 0.8.12
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/package.json +1 -1
- package/scripts/typegen.js +9 -5
- package/src/configs/eslint.js +15 -3
- package/src/configs/import.js +18 -7
- package/src/configs/index.js +10 -3
- package/src/configs/opinionated.js +10 -5
- package/src/configs/react.js +16 -3
- package/src/configs/tanstack.js +10 -2
- package/src/format.js +4 -1
- package/src/lib/factory.js +13 -3
- package/src/lib/packages.test.js +21 -11
- package/src/lint.js +36 -13
- package/src/lint.test.js +17 -0
package/package.json
CHANGED
package/scripts/typegen.js
CHANGED
|
@@ -77,12 +77,16 @@ dtsFile.addInterface({
|
|
|
77
77
|
}
|
|
78
78
|
return {
|
|
79
79
|
name,
|
|
80
|
-
type: options
|
|
80
|
+
type: options
|
|
81
|
+
? `boolean | ${options.getText()}`
|
|
82
|
+
: 'boolean',
|
|
81
83
|
hasQuestionToken: true,
|
|
82
|
-
docs: [
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
docs: [
|
|
85
|
+
{
|
|
86
|
+
description: `\`${name}\` option`,
|
|
87
|
+
tags,
|
|
88
|
+
},
|
|
89
|
+
],
|
|
86
90
|
}
|
|
87
91
|
}),
|
|
88
92
|
})
|
package/src/configs/eslint.js
CHANGED
|
@@ -8,13 +8,25 @@ export default createConfigs({
|
|
|
8
8
|
plugins: ['eslint'],
|
|
9
9
|
rules: {
|
|
10
10
|
'id-length': 'off',
|
|
11
|
-
'func-style': [
|
|
12
|
-
|
|
11
|
+
'func-style': [
|
|
12
|
+
'error',
|
|
13
|
+
'declaration',
|
|
14
|
+
{ allowArrowFunctions: true },
|
|
15
|
+
],
|
|
16
|
+
'no-magic-numbers': [
|
|
17
|
+
'error',
|
|
18
|
+
{
|
|
19
|
+
ignore: [0, 1, -1],
|
|
20
|
+
},
|
|
21
|
+
],
|
|
13
22
|
'no-undefined': 'off',
|
|
14
23
|
'no-ternary': 'off',
|
|
15
24
|
'no-nested-ternary': 'error',
|
|
16
25
|
'no-unneeded-ternary': 'error',
|
|
17
|
-
'no-void': [
|
|
26
|
+
'no-void': [
|
|
27
|
+
'error',
|
|
28
|
+
{ allowAsStatement: true },
|
|
29
|
+
],
|
|
18
30
|
'one-var': 'off',
|
|
19
31
|
'no-warning-comments': 'off',
|
|
20
32
|
'capitalized-comments': 'off',
|
package/src/configs/import.js
CHANGED
|
@@ -5,16 +5,27 @@ export default createConfigs({
|
|
|
5
5
|
enable: true,
|
|
6
6
|
configs: [
|
|
7
7
|
{
|
|
8
|
-
jsPlugins: [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
jsPlugins: [
|
|
9
|
+
{
|
|
10
|
+
name: 'perfectionist',
|
|
11
|
+
specifier: import.meta.resolve('eslint-plugin-perfectionist'),
|
|
12
|
+
},
|
|
13
|
+
],
|
|
12
14
|
rules: {
|
|
13
15
|
// `sort-imports` is handled by oxfmt (`sortImports`)
|
|
14
16
|
'perfectionist/sort-imports': 'off',
|
|
15
|
-
'perfectionist/sort-named-imports': [
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
'perfectionist/sort-named-imports': [
|
|
18
|
+
'error',
|
|
19
|
+
{ type: 'natural', order: 'asc' },
|
|
20
|
+
],
|
|
21
|
+
'perfectionist/sort-named-exports': [
|
|
22
|
+
'error',
|
|
23
|
+
{ type: 'natural', order: 'asc' },
|
|
24
|
+
],
|
|
25
|
+
'perfectionist/sort-exports': [
|
|
26
|
+
'error',
|
|
27
|
+
{ type: 'natural', order: 'asc' },
|
|
28
|
+
],
|
|
18
29
|
},
|
|
19
30
|
},
|
|
20
31
|
{
|
package/src/configs/index.js
CHANGED
|
@@ -30,19 +30,26 @@ const CONFIGS = /** @type {const} */[
|
|
|
30
30
|
@returns {import("oxlint").OxlintConfig[]} Generated configs for the enabled options
|
|
31
31
|
*/
|
|
32
32
|
export default function buildConfigs(options) {
|
|
33
|
-
const context = {
|
|
33
|
+
const context = {
|
|
34
|
+
isPackageExists: createPackageDetector(),
|
|
35
|
+
options,
|
|
36
|
+
}
|
|
34
37
|
return CONFIGS.flatMap(({ name, build, enable = true }) => {
|
|
35
38
|
const option = options[name]
|
|
36
39
|
if (option === false) {
|
|
37
40
|
return []
|
|
38
41
|
}
|
|
39
42
|
if (option === undefined) {
|
|
40
|
-
const isEnabled = typeof enable === 'function'
|
|
43
|
+
const isEnabled = typeof enable === 'function'
|
|
44
|
+
? enable(context)
|
|
45
|
+
: enable
|
|
41
46
|
if (!isEnabled) {
|
|
42
47
|
return []
|
|
43
48
|
}
|
|
44
49
|
}
|
|
45
50
|
// @ts-expect-error - build configs with options
|
|
46
|
-
return build(context, typeof option === 'object'
|
|
51
|
+
return build(context, typeof option === 'object'
|
|
52
|
+
? option
|
|
53
|
+
: undefined)
|
|
47
54
|
})
|
|
48
55
|
}
|
|
@@ -5,14 +5,19 @@ export default createConfigs({
|
|
|
5
5
|
enable: true,
|
|
6
6
|
configs: [
|
|
7
7
|
{
|
|
8
|
-
jsPlugins: [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
jsPlugins: [
|
|
9
|
+
{
|
|
10
|
+
name: 'antfu',
|
|
11
|
+
specifier: import.meta.resolve('eslint-plugin-antfu'),
|
|
12
|
+
},
|
|
13
|
+
],
|
|
12
14
|
rules: {
|
|
13
15
|
'antfu/top-level-function': 'error',
|
|
14
16
|
'antfu/import-dedupe': 'error',
|
|
15
|
-
'antfu/indent-unindent': [
|
|
17
|
+
'antfu/indent-unindent': [
|
|
18
|
+
'error',
|
|
19
|
+
{ indent: 2 },
|
|
20
|
+
],
|
|
16
21
|
'antfu/no-ts-export-equal': 'error',
|
|
17
22
|
},
|
|
18
23
|
},
|
package/src/configs/react.js
CHANGED
|
@@ -9,10 +9,23 @@ export default createConfigs({
|
|
|
9
9
|
rules: {
|
|
10
10
|
'react/react-in-jsx-scope': 'off',
|
|
11
11
|
'react/jsx-props-no-spreading': 'off',
|
|
12
|
-
'react/jsx-max-depth': [
|
|
13
|
-
|
|
12
|
+
'react/jsx-max-depth': [
|
|
13
|
+
'error',
|
|
14
|
+
{ max: 5 },
|
|
15
|
+
],
|
|
16
|
+
'react/jsx-filename-extension': [
|
|
17
|
+
'error',
|
|
18
|
+
{
|
|
19
|
+
extensions: ['.jsx', '.tsx'],
|
|
20
|
+
},
|
|
21
|
+
],
|
|
14
22
|
'react/jsx-no-literals': 'off',
|
|
15
|
-
'react/forbid-component-props': [
|
|
23
|
+
'react/forbid-component-props': [
|
|
24
|
+
'error',
|
|
25
|
+
{
|
|
26
|
+
forbid: ['style'],
|
|
27
|
+
},
|
|
28
|
+
],
|
|
16
29
|
},
|
|
17
30
|
},
|
|
18
31
|
{
|
package/src/configs/tanstack.js
CHANGED
|
@@ -11,8 +11,16 @@ export default createConfigs({
|
|
|
11
11
|
{
|
|
12
12
|
files: ['src/routes/**/*.tsx'],
|
|
13
13
|
rules: {
|
|
14
|
-
'no-use-before-define': [
|
|
15
|
-
|
|
14
|
+
'no-use-before-define': [
|
|
15
|
+
'error',
|
|
16
|
+
{ functions: false },
|
|
17
|
+
],
|
|
18
|
+
'react/only-export-components': [
|
|
19
|
+
'error',
|
|
20
|
+
{
|
|
21
|
+
customHOCs: ['createRootRoute', 'createFileRoute', 'createRootRouteWithContext'],
|
|
22
|
+
},
|
|
23
|
+
],
|
|
16
24
|
},
|
|
17
25
|
},
|
|
18
26
|
],
|
package/src/format.js
CHANGED
|
@@ -13,5 +13,8 @@ const DEFAULT_FORMAT = /** @type {import('oxfmt').OxfmtConfig} */ ({
|
|
|
13
13
|
* @param {import('oxfmt').OxfmtConfig} [config]
|
|
14
14
|
*/
|
|
15
15
|
export function format(config = {}) {
|
|
16
|
-
return {
|
|
16
|
+
return {
|
|
17
|
+
...DEFAULT_FORMAT,
|
|
18
|
+
...config,
|
|
19
|
+
}
|
|
17
20
|
}
|
package/src/lib/factory.js
CHANGED
|
@@ -7,10 +7,20 @@ export function createConfigs({ name, enable = true, options, configs }) {
|
|
|
7
7
|
enable,
|
|
8
8
|
options,
|
|
9
9
|
build: (context, overriddenOptions) => {
|
|
10
|
-
const local = {
|
|
10
|
+
const local = {
|
|
11
|
+
...context,
|
|
12
|
+
options: {
|
|
13
|
+
...options,
|
|
14
|
+
...overriddenOptions,
|
|
15
|
+
},
|
|
16
|
+
}
|
|
11
17
|
return configs.flatMap((item) => {
|
|
12
|
-
const config = typeof item === 'function'
|
|
13
|
-
|
|
18
|
+
const config = typeof item === 'function'
|
|
19
|
+
? item(local)
|
|
20
|
+
: item
|
|
21
|
+
return config
|
|
22
|
+
? [config]
|
|
23
|
+
: []
|
|
14
24
|
})
|
|
15
25
|
},
|
|
16
26
|
}
|
package/src/lib/packages.test.js
CHANGED
|
@@ -13,11 +13,21 @@ void test('detects packages from the consumer, including import-only and types-o
|
|
|
13
13
|
const project = path.join(root, 'project')
|
|
14
14
|
mkdirSync(project)
|
|
15
15
|
const fixtures = {
|
|
16
|
-
'import-only': {
|
|
16
|
+
'import-only': {
|
|
17
|
+
exports: { import: './index.js' },
|
|
18
|
+
type: 'module',
|
|
19
|
+
},
|
|
17
20
|
'hidden-manifest': { exports: './index.js', type: 'module' },
|
|
18
|
-
'types-only-export': {
|
|
21
|
+
'types-only-export': {
|
|
22
|
+
exports: {
|
|
23
|
+
'.': { types: './index.d.ts' },
|
|
24
|
+
},
|
|
25
|
+
},
|
|
19
26
|
'@types/example': { types: './index.d.ts' },
|
|
20
|
-
'conditional': {
|
|
27
|
+
'conditional': {
|
|
28
|
+
exports: { import: './index.js', require: './missing.cjs' },
|
|
29
|
+
type: 'module',
|
|
30
|
+
},
|
|
21
31
|
}
|
|
22
32
|
for (const [name, manifest] of Object.entries(fixtures)) {
|
|
23
33
|
const directory = path.join(root, 'node_modules', name)
|
|
@@ -29,28 +39,28 @@ void test('detects packages from the consumer, including import-only and types-o
|
|
|
29
39
|
writeFileSync(path.join(directory, 'index.d.ts'), 'export {}\n')
|
|
30
40
|
}
|
|
31
41
|
|
|
32
|
-
const
|
|
42
|
+
const isPackageInstalled = createPackageDetector(project)
|
|
33
43
|
for (const name of Object.keys(fixtures)) {
|
|
34
|
-
assert.equal(
|
|
44
|
+
assert.equal(isPackageInstalled(name), true, name)
|
|
35
45
|
}
|
|
36
|
-
assert.equal(
|
|
46
|
+
assert.equal(isPackageInstalled('missing-package'), false)
|
|
37
47
|
// Packages installed beside the config must not enable consumer presets.
|
|
38
|
-
assert.equal(
|
|
48
|
+
assert.equal(isPackageInstalled('eslint-plugin-antfu'), false)
|
|
39
49
|
|
|
40
50
|
symlinkSync(path.join(root, 'node_modules/import-only'), path.join(root, 'node_modules/linked-package'), 'junction')
|
|
41
|
-
assert.equal(
|
|
51
|
+
assert.equal(isPackageInstalled('linked-package'), true)
|
|
42
52
|
|
|
43
53
|
const broken = path.join(root, 'node_modules/broken-export')
|
|
44
54
|
mkdirSync(broken)
|
|
45
55
|
writeFileSync(path.join(broken, 'package.json'), JSON.stringify({ exports: './missing.js' }))
|
|
46
|
-
assert.equal(
|
|
56
|
+
assert.equal(isPackageInstalled('broken-export'), false)
|
|
47
57
|
})
|
|
48
58
|
|
|
49
59
|
void test('a new detector observes the current project and newly installed packages', (context) => {
|
|
50
60
|
const root = mkdtempSync(path.join(tmpdir(), 'oxc-package-detection-'))
|
|
51
61
|
context.after(() => rmSync(root, { recursive: true, force: true }))
|
|
52
|
-
const
|
|
53
|
-
assert.equal(
|
|
62
|
+
const isPackageInstalled = createPackageDetector(root)
|
|
63
|
+
assert.equal(isPackageInstalled('react'), false)
|
|
54
64
|
|
|
55
65
|
const directory = path.join(root, 'node_modules/react')
|
|
56
66
|
mkdirSync(directory, { recursive: true })
|
package/src/lint.js
CHANGED
|
@@ -10,22 +10,41 @@ const DEFAULT_CATEGORIES = {
|
|
|
10
10
|
nursery: 'warn',
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const OBJECT_KEYS = [
|
|
13
|
+
const OBJECT_KEYS = [
|
|
14
|
+
'settings',
|
|
15
|
+
'env',
|
|
16
|
+
'globals',
|
|
17
|
+
'options',
|
|
18
|
+
]
|
|
14
19
|
const ARRAY_KEYS = ['ignorePatterns']
|
|
15
|
-
const HOISTED_KEYS = [
|
|
20
|
+
const HOISTED_KEYS = [
|
|
21
|
+
...OBJECT_KEYS,
|
|
22
|
+
...ARRAY_KEYS,
|
|
23
|
+
'categories',
|
|
24
|
+
]
|
|
16
25
|
|
|
17
26
|
/**
|
|
18
27
|
@type {import('.').lint}
|
|
19
28
|
*/
|
|
20
29
|
export function lint(options, config = {}) {
|
|
21
|
-
const all = [
|
|
30
|
+
const all = [
|
|
31
|
+
...buildConfigs(options),
|
|
32
|
+
config,
|
|
33
|
+
]
|
|
22
34
|
|
|
23
35
|
/**
|
|
24
36
|
@type {Record<string, any>}
|
|
25
37
|
*/
|
|
26
38
|
const root = {
|
|
27
|
-
categories: {
|
|
39
|
+
categories: {
|
|
40
|
+
...DEFAULT_CATEGORIES,
|
|
41
|
+
...config.categories,
|
|
42
|
+
},
|
|
28
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
@type {string[]}
|
|
46
|
+
*/
|
|
47
|
+
let ignorePatterns = []
|
|
29
48
|
|
|
30
49
|
for (const item of all) {
|
|
31
50
|
for (const key of OBJECT_KEYS) {
|
|
@@ -34,18 +53,22 @@ export function lint(options, config = {}) {
|
|
|
34
53
|
const value = item[key]
|
|
35
54
|
if (value !== undefined) {
|
|
36
55
|
// eslint-disable-next-line ts/no-unsafe-assignment
|
|
37
|
-
root[key] = {
|
|
56
|
+
root[key] = {
|
|
57
|
+
...root[key],
|
|
58
|
+
...value,
|
|
59
|
+
}
|
|
38
60
|
}
|
|
39
61
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// eslint-disable-next-line ts/no-unsafe-assignment
|
|
43
|
-
const value = item[key]
|
|
44
|
-
if (value !== undefined) {
|
|
45
|
-
// eslint-disable-next-line ts/no-unsafe-assignment
|
|
46
|
-
root[key] = [...new Set([...(root[key] ?? []), ...value])]
|
|
47
|
-
}
|
|
62
|
+
if (item.ignorePatterns === undefined) {
|
|
63
|
+
continue
|
|
48
64
|
}
|
|
65
|
+
ignorePatterns = [
|
|
66
|
+
...new Set([
|
|
67
|
+
...ignorePatterns,
|
|
68
|
+
...item.ignorePatterns,
|
|
69
|
+
]),
|
|
70
|
+
]
|
|
71
|
+
root.ignorePatterns = ignorePatterns
|
|
49
72
|
}
|
|
50
73
|
|
|
51
74
|
return {
|
package/src/lint.test.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
// eslint-disable-next-line test/no-import-node-test -- This package uses the built-in test runner.
|
|
3
|
+
import { test } from 'node:test'
|
|
4
|
+
import { lint } from './lint.js'
|
|
5
|
+
|
|
6
|
+
void test('merges and deduplicates ignore patterns in order', () => {
|
|
7
|
+
const config = lint({ tanstack: true }, {
|
|
8
|
+
ignorePatterns: ['**/src/routeTree.gen.ts', 'custom/**'],
|
|
9
|
+
})
|
|
10
|
+
assert.deepEqual(config.ignorePatterns, ['**/src/routeTree.gen.ts', 'custom/**'])
|
|
11
|
+
assert.equal(config.extends?.some(item => item.ignorePatterns !== undefined), false)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
void test('preserves an explicitly empty ignore list', () => {
|
|
15
|
+
const config = lint({ tanstack: false }, { ignorePatterns: [] })
|
|
16
|
+
assert.deepEqual(config.ignorePatterns, [])
|
|
17
|
+
})
|