@mouse_484/eslint-config 5.4.0 → 5.4.2

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/README.md CHANGED
@@ -2,10 +2,48 @@
2
2
 
3
3
  ESLint Config based on [@antfu/eslint-config](https://github.com/antfu/eslint-config)
4
4
 
5
+ ## Requirements
6
+ - ESLint: v9 or higher (Flat Config supported)
7
+
5
8
  ## Usage
9
+ Run the setup command:
6
10
  ```
7
- @mouse_484/eslint-config@latest
11
+ npx @mouse_484/eslint-config@latest
8
12
  ```
9
13
 
10
- > [!WARNING]
11
- > `npx` does not work. Use `pnpx` or run bin/cli.js directly after installation.
14
+ ## Features
15
+
16
+ - More flexible adjustments for opinionated rules than [`lessOpinionated`](https://github.com/antfu/eslint-config?tab=readme-ov-file#top-level-function-style-etc).
17
+ - Disables `antfu/no-top-level-await` and `antfu/if-newline`.
18
+ - Includes additional configurations by default:
19
+ - Recommended rules from [unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn).
20
+ - Rules from [stylistic](https://eslint.style/).
21
+ - Customized rules:
22
+ - Stylistic rules adjustments.
23
+ - JSX properties sort order.
24
+ - File naming convention rules.
25
+ - Additional plugins:
26
+ - [`eslint-plugin-better-tailwindcss`](https://github.com/schoero/eslint-plugin-better-tailwindcss) for Tailwind CSS.
27
+
28
+ ## Advanced Configuration
29
+
30
+ #### TypeScript
31
+
32
+ for type-aware linting
33
+
34
+ ```js
35
+ export default mouse({
36
+ typescript: {
37
+ tsconfigPath: './tsconfig.json',
38
+ }
39
+ })
40
+ ```
41
+
42
+ #### Tailwind CSS
43
+
44
+ ```js
45
+ export default mouse({
46
+ tailwind: {
47
+ entryPoint: './src/index.css',
48
+ },
49
+ })
package/bin/cli.js CHANGED
@@ -1,182 +1,114 @@
1
1
  #!/usr/bin/env node
2
- import { execSync, spawn } from 'node:child_process'
3
- import fs from 'node:fs/promises'
2
+ import { spawn } from 'node:child_process'
3
+ import { readFile, writeFile } from 'node:fs/promises'
4
4
  import path from 'node:path'
5
5
  import process from 'node:process'
6
6
  import { resolveCommand } from 'package-manager-detector/commands'
7
7
  import { detect } from 'package-manager-detector/detect'
8
8
 
9
- /**
10
- * @typedef {object} PackageInfo
11
- * @property {string} name - Package name
12
- * @property {string} import - Import name in config
13
- * @property {string} [version] - Package version
14
- */
15
-
16
- /** @type {PackageInfo} */
17
- const SOURCE = {
18
- name: '@antfu/eslint-config',
19
- import: 'antfu',
9
+ const PACKAGE_NAME = {
10
+ BASE: '@antfu/eslint-config',
11
+ CUSTOM: '@mouse_484/eslint-config',
20
12
  }
21
13
 
22
- /** @type {PackageInfo} */
23
- const TARGET = {
24
- name: '@mouse_484/eslint-config',
25
- import: 'mouse',
26
- }
27
-
28
- const PACKAGE_JSON_FILE = 'package.json'
29
- const ESLINT_CONFIG_JS_FILE = 'eslint.config.js'
30
- const ESLINT_CONFIG_MJS_FILE = 'eslint.config.mjs'
31
-
32
- // infinite loop prevention
33
- const isRunningFromSourcePackage = process.argv[1].includes(SOURCE.name)
34
-
35
14
  /**
36
- * Execute command with spawn
37
- * @param {string} command - Command to execute
38
- * @param {string[]} args - Command arguments
39
- * @returns {Promise<void>}
15
+ * Simple logger function
16
+ * @param {*} message
40
17
  */
41
- function runCommand(command, args = []) {
42
- console.info(`Running: ${command} ${args.join(' ')}`)
43
- const spawnedProcess = spawn(command, args, { stdio: 'inherit', shell: true })
44
-
45
- return new Promise((resolve, reject) => {
46
- spawnedProcess.on('close', (code) => {
47
- if (code === 0) {
48
- setTimeout(() => {
49
- resolve()
50
- }, 300)
51
- } else {
52
- reject(new Error(`Command failed with exit code ${code}`))
53
- }
54
- })
55
- spawnedProcess.on('error', reject)
56
- })
18
+ function logger(message) {
19
+ console.info('@mouse_484/eslint-config:', message)
57
20
  }
58
21
 
59
22
  /**
60
- * Execute antfu's CLI directly via node
61
- * @returns {Promise<void>}
23
+ * @type {(...args: Parameters<typeof import("package-manager-detector/commands").resolveCommand>) => Promise<void>}
62
24
  */
63
- async function runAntfuCLI() {
64
- console.info('Running @antfu/eslint-config setup...')
65
-
66
- const cwd = process.cwd()
67
- const cliPath = path.join(cwd, 'node_modules', SOURCE.name, 'bin', 'index.js')
68
-
25
+ function runAgentCommand(agent, command_, args_) {
26
+ const { command, args } = resolveCommand(agent, command_, args_)
69
27
  return new Promise((resolve, reject) => {
70
- const nodeProcess = spawn('node', [cliPath], {
71
- stdio: 'inherit',
72
- cwd,
73
- shell: true,
74
- })
28
+ const child = spawn(
29
+ command,
30
+ args,
31
+ {
32
+ stdio: 'inherit',
33
+ },
34
+ )
75
35
 
76
- nodeProcess.on('close', (code) => {
36
+ child.on('close', (code) => {
77
37
  if (code === 0) {
78
- setTimeout(() => {
79
- resolve()
80
- }, 300)
38
+ resolve()
81
39
  } else {
82
- reject(new Error(`Antfu CLI failed with exit code ${code}`))
40
+ reject(new Error(`Command failed: ${code} (${command} ${args.join(' ')})`))
83
41
  }
84
42
  })
85
- nodeProcess.on('error', reject)
43
+ child.on('error', (error) => {
44
+ reject(error)
45
+ })
86
46
  })
87
47
  }
88
48
 
89
- /**
90
- * Update JSON file with transform function
91
- * @param {string} filePath - JSON file path
92
- * @param {(data: any) => any} updateFunction - Transform function
93
- */
94
- async function updateJSONFile(filePath, updateFunction) {
95
- const content = await fs.readFile(filePath, 'utf8')
96
- const data = JSON.parse(content)
97
- const updated = updateFunction(data)
98
- await fs.writeFile(filePath, JSON.stringify(updated, undefined, 2))
99
- return updated
100
- }
101
-
102
49
  async function main() {
103
- console.info('Starting ESLint config setup...')
50
+ const cwd = process.cwd()
51
+ logger('Starting setup')
104
52
 
105
- if (isRunningFromSourcePackage) {
106
- console.error(
107
- `Please run this script from the root of your project, not from ${SOURCE.name} package.`,
108
- )
109
- process.exitCode = 1
110
- return
53
+ const packageManager = await detect() ?? {
54
+ name: 'npm',
55
+ agent: 'npm',
56
+ version: 'unknown',
111
57
  }
112
58
 
113
- const pm = await detect()
114
- if (!pm) {
115
- console.error(
116
- 'Could not detect package manager. '
117
- + 'Please ensure you are in a project with a package.json file.',
118
- )
119
- process.exitCode = 1
120
- return
59
+ logger(`Detected package manager: ${packageManager.name}`)
60
+
61
+ logger(`Setting up base package ${PACKAGE_NAME.BASE}`)
62
+ await runAgentCommand(
63
+ packageManager.agent,
64
+ 'execute',
65
+ [PACKAGE_NAME.BASE],
66
+ )
67
+ logger('Modifying base config to custom config')
68
+
69
+ logger(`Uninstalling base package ${PACKAGE_NAME.BASE}`)
70
+ await runAgentCommand(
71
+ packageManager.agent,
72
+ 'uninstall',
73
+ [PACKAGE_NAME.BASE],
74
+ )
75
+ logger(`Installing custom package ${PACKAGE_NAME.CUSTOM}`)
76
+ await runAgentCommand(
77
+ packageManager.agent,
78
+ 'install',
79
+ ['-D', PACKAGE_NAME.CUSTOM],
80
+ )
81
+
82
+ logger('Updating package.json scripts')
83
+ const packageJsonPath = path.join(cwd, 'package.json')
84
+ /**
85
+ * @type {{ scripts: Record<string, string>, type?: "module" }}
86
+ */
87
+ const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'))
88
+ packageJson.scripts = {
89
+ ...packageJson.scripts,
90
+ 'lint': 'eslint .',
91
+ 'lint:fix': 'eslint --fix .',
121
92
  }
122
-
123
- const installCmd = resolveCommand(pm.agent, 'add', ['-D', SOURCE.name])
124
- await runCommand(installCmd.command, installCmd.args)
125
- console.info(`Installed ${SOURCE.name}`)
126
-
127
- await runAntfuCLI()
128
-
129
- console.info(`Start replacing the config from ${SOURCE.name} to ${TARGET.name}`)
130
-
131
- const cwd = process.cwd()
132
-
133
- const packageJSONPath = path.join(cwd, PACKAGE_JSON_FILE)
134
-
135
- const package_ = await updateJSONFile(packageJSONPath, (packageData) => {
136
- packageData.devDependencies = packageData.devDependencies || {}
137
- delete packageData.devDependencies[SOURCE.name]
138
-
139
- let targetVersion
140
- try {
141
- targetVersion = execSync(`npm view ${TARGET.name} dist-tags.latest`).toString().trim()
142
- } catch (error) {
143
- console.warn(
144
- `Warning: Could not fetch latest version for ${TARGET.name}, using 'latest'. `
145
- + `Error: ${error.message}`,
146
- )
147
- targetVersion = 'latest'
148
- }
149
- TARGET.version = targetVersion
150
- packageData.devDependencies[TARGET.name] = targetVersion
151
-
152
- packageData.scripts = {
153
- ...packageData.scripts,
154
- 'lint': 'eslint .',
155
- 'lint:fix': 'eslint --fix .',
156
- }
157
-
158
- return packageData
93
+ await writeFile(packageJsonPath, JSON.stringify(packageJson, undefined, 2), 'utf8')
94
+
95
+ logger('Updating config file')
96
+ const configPath = path.join(cwd, `eslint.config.${packageJson.type === 'module' ? 'js' : 'mjs'}`)
97
+ await writeFile(configPath, `
98
+ import mouse from '${PACKAGE_NAME.CUSTOM}'
99
+
100
+ export default mouse()
101
+ `.trim(), 'utf8')
102
+
103
+ logger('Linting the project to verify setup')
104
+ await runAgentCommand(
105
+ packageManager.agent,
106
+ 'run',
107
+ ['lint:fix'],
108
+ ).catch((error) => {
109
+ logger(`Linting failed: ${error.message}`)
159
110
  })
160
-
161
- const configExtension = package_.type === 'module' ? 'js' : 'mjs'
162
- const eslintConfigFile = configExtension === 'js'
163
- ? ESLINT_CONFIG_JS_FILE
164
- : ESLINT_CONFIG_MJS_FILE
165
- const configPath = path.join(cwd, eslintConfigFile)
166
-
167
- let configContent = await fs.readFile(configPath, 'utf8')
168
- configContent = configContent
169
- .replace(
170
- `import ${SOURCE.import} from '${SOURCE.name}'`,
171
- `import ${TARGET.import} from '${TARGET.name}'`,
172
- )
173
- .replaceAll(new RegExp(`(?<!['"])${SOURCE.import}(?!['"])`, 'g'), TARGET.import)
174
- await fs.writeFile(configPath, configContent)
175
-
176
- const finalInstallCmd = resolveCommand(pm.agent, 'install', [])
177
- await runCommand(finalInstallCmd.command, finalInstallCmd.args)
178
-
179
- console.info(`Successfully replaced the config from ${SOURCE.name} to ${TARGET.name}`)
180
111
  }
181
112
 
182
113
  await main()
114
+ console.info('---------------- Setup Complete ----------------')
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mouse_484/eslint-config",
3
3
  "type": "module",
4
- "version": "5.4.0",
4
+ "version": "5.4.2",
5
5
  "author": "mouse_484",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/mouse484/config/tree/main/packages/eslint",
package/src/index.js CHANGED
@@ -15,7 +15,6 @@ async function mouse(options, ...userConfigs) {
15
15
  allRecommended: true,
16
16
  },
17
17
  stylistic: true,
18
- typescript: true,
19
18
  ...options,
20
19
  }
21
20
 
@@ -33,7 +32,12 @@ async function mouse(options, ...userConfigs) {
33
32
  ...tailwind(options),
34
33
  ]
35
34
 
36
- return antfu(options, ...configs, ...userConfigs)
35
+ const normalizedOptions = {
36
+ ...options,
37
+ ignores: typeof options?.ignores === 'function' ? options.ignores([]) : options?.ignores,
38
+ }
39
+
40
+ return antfu(normalizedOptions, ...configs, ...userConfigs)
37
41
  }
38
42
 
39
43
  export default mouse