@mouse_484/eslint-config 4.0.4 → 4.2.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/bin/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { execSync, spawn } from 'node:child_process'
3
- import fs from 'node:fs/promises'
4
- import path from 'node:path'
5
- import process from 'node:process'
6
- import { resolveCommand } from 'package-manager-detector/commands'
7
- import { detect } from 'package-manager-detector/detect'
2
+ import { execSync, spawn } from 'node:child_process';
3
+ import fs from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import process from 'node:process';
6
+ import { resolveCommand } from 'package-manager-detector/commands';
7
+ import { detect } from 'package-manager-detector/detect';
8
8
 
9
9
  /**
10
10
  * @typedef {object} PackageInfo
@@ -17,20 +17,20 @@ import { detect } from 'package-manager-detector/detect'
17
17
  const SOURCE = {
18
18
  name: '@antfu/eslint-config',
19
19
  import: 'antfu',
20
- }
20
+ };
21
21
 
22
22
  /** @type {PackageInfo} */
23
23
  const TARGET = {
24
24
  name: '@mouse_484/eslint-config',
25
25
  import: 'mouse',
26
- }
26
+ };
27
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'
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
31
 
32
32
  // infinite loop prevention
33
- const isRunningFromSourcePackage = process.argv[1].includes(SOURCE.name)
33
+ const isRunningFromSourcePackage = process.argv[1].includes(SOURCE.name);
34
34
 
35
35
  /**
36
36
  * Execute command with spawn
@@ -39,114 +39,114 @@ const isRunningFromSourcePackage = process.argv[1].includes(SOURCE.name)
39
39
  * @returns {Promise<void>}
40
40
  */
41
41
  function runCommand(command, args = []) {
42
- console.info(`Running: ${command} ${args.join(' ')}`)
43
- const spawnedProcess = spawn(command, args, { stdio: 'inherit' })
42
+ console.info(`Running: ${command} ${args.join(' ')}`);
43
+ const spawnedProcess = spawn(command, args, { stdio: 'inherit' });
44
44
 
45
45
  return new Promise((resolve, reject) => {
46
46
  spawnedProcess.on('close', (code) => {
47
47
  if (code === 0) {
48
48
  setTimeout(() => {
49
- resolve()
50
- }, 300)
49
+ resolve();
50
+ }, 300);
51
+ } else {
52
+ reject(new Error(`Command failed with exit code ${code}`));
51
53
  }
52
- else {
53
- reject(new Error(`Command failed with exit code ${code}`))
54
- }
55
- })
56
- spawnedProcess.on('error', reject)
57
- })
54
+ });
55
+ spawnedProcess.on('error', reject);
56
+ });
58
57
  }
59
58
 
60
59
  /**
61
60
  * Update JSON file with transform function
62
61
  * @param {string} filePath - JSON file path
63
- * @param {(data: any) => any} updateFn - Transform function
62
+ * @param {(data: any) => any} updateFunction - Transform function
64
63
  */
65
- async function updateJSONFile(filePath, updateFn) {
66
- const content = await fs.readFile(filePath, 'utf-8')
67
- const data = JSON.parse(content)
68
- const updated = updateFn(data)
69
- await fs.writeFile(filePath, JSON.stringify(updated, null, 2))
70
- return updated
64
+ async function updateJSONFile(filePath, updateFunction) {
65
+ const content = await fs.readFile(filePath, 'utf8');
66
+ const data = JSON.parse(content);
67
+ const updated = updateFunction(data);
68
+ await fs.writeFile(filePath, JSON.stringify(updated, undefined, 2));
69
+ return updated;
71
70
  }
72
71
 
73
72
  async function main() {
74
- console.info('Starting ESLint config setup...')
73
+ console.info('Starting ESLint config setup...');
75
74
 
76
75
  if (isRunningFromSourcePackage) {
77
76
  console.error(
78
77
  `Please run this script from the root of your project, not from ${SOURCE.name} package.`,
79
- )
80
- process.exitCode = 1
81
- return
78
+ );
79
+ process.exitCode = 1;
80
+ return;
82
81
  }
83
82
 
84
- const pm = await detect()
83
+ const pm = await detect();
85
84
  if (!pm) {
86
85
  console.error(
87
86
  'Could not detect package manager. '
88
87
  + 'Please ensure you are in a project with a package.json file.',
89
- )
90
- process.exitCode = 1
91
- return
88
+ );
89
+ process.exitCode = 1;
90
+ return;
92
91
  }
93
92
 
94
- const installCmd = resolveCommand(pm.agent, 'add', ['-D', SOURCE.name])
95
- await runCommand(installCmd.command, installCmd.args)
96
- console.info(`Installed ${SOURCE.name}`)
93
+ const installCmd = resolveCommand(pm.agent, 'add', ['-D', SOURCE.name]);
94
+ await runCommand(installCmd.command, installCmd.args);
95
+ console.info(`Installed ${SOURCE.name}`);
97
96
 
98
- const execCmd = resolveCommand(pm.agent, 'execute', [SOURCE.name])
99
- await runCommand(execCmd.command, execCmd.args)
97
+ const execCmd = resolveCommand(pm.agent, 'execute', [SOURCE.name]);
98
+ await runCommand(execCmd.command, execCmd.args);
100
99
 
101
- console.info(`Start replacing the config from ${SOURCE.name} to ${TARGET.name}`)
100
+ console.info(`Start replacing the config from ${SOURCE.name} to ${TARGET.name}`);
102
101
 
103
- const cwd = process.cwd()
104
- const packageJSONPath = path.join(cwd, PACKAGE_JSON_FILE)
102
+ const cwd = process.cwd();
103
+ const packageJSONPath = path.join(cwd, PACKAGE_JSON_FILE);
105
104
 
106
- const pkg = await updateJSONFile(packageJSONPath, (pkgData) => {
107
- pkgData.devDependencies = pkgData.devDependencies || {}
108
- delete pkgData.devDependencies[SOURCE.name]
105
+ const package_ = await updateJSONFile(packageJSONPath, (packageData) => {
106
+ packageData.devDependencies = packageData.devDependencies || {};
107
+ delete packageData.devDependencies[SOURCE.name];
109
108
 
110
- let targetVersion
109
+ let targetVersion;
111
110
  try {
112
- targetVersion = execSync(`npm view ${TARGET.name} dist-tags.latest`).toString().trim()
113
- }
114
- catch (error) {
111
+ targetVersion = execSync(`npm view ${TARGET.name} dist-tags.latest`).toString().trim();
112
+ } catch (error) {
115
113
  console.warn(
116
114
  `Warning: Could not fetch latest version for ${TARGET.name}, using 'latest'. `
117
115
  + `Error: ${error.message}`,
118
- )
119
- targetVersion = 'latest'
116
+ );
117
+ targetVersion = 'latest';
120
118
  }
121
- TARGET.version = targetVersion
122
- pkgData.devDependencies[TARGET.name] = targetVersion
119
+ TARGET.version = targetVersion;
120
+ packageData.devDependencies[TARGET.name] = targetVersion;
123
121
 
124
- pkgData.scripts = {
125
- ...pkgData.scripts,
122
+ packageData.scripts = {
123
+ ...packageData.scripts,
126
124
  'lint': 'eslint .',
127
125
  'lint:fix': 'eslint --fix .',
128
- }
126
+ };
129
127
 
130
- return pkgData
131
- })
128
+ return packageData;
129
+ });
132
130
 
133
- const configExt = pkg.type === 'module' ? 'js' : 'mjs'
134
- const eslintConfigFile = configExt === 'js' ? ESLINT_CONFIG_JS_FILE : ESLINT_CONFIG_MJS_FILE
135
- const configPath = path.join(cwd, eslintConfigFile)
131
+ const configExtension = package_.type === 'module' ? 'js' : 'mjs';
132
+ const eslintConfigFile = configExtension === 'js'
133
+ ? ESLINT_CONFIG_JS_FILE
134
+ : ESLINT_CONFIG_MJS_FILE;
135
+ const configPath = path.join(cwd, eslintConfigFile);
136
136
 
137
- let configContent = await fs.readFile(configPath, 'utf-8')
137
+ let configContent = await fs.readFile(configPath, 'utf8');
138
138
  configContent = configContent
139
139
  .replace(
140
140
  `import ${SOURCE.import} from '${SOURCE.name}'`,
141
141
  `import ${TARGET.import} from '${TARGET.name}'`,
142
142
  )
143
- .replace(new RegExp(`(?<!['"])${SOURCE.import}(?!['"])`, 'g'), TARGET.import)
144
- await fs.writeFile(configPath, configContent)
143
+ .replaceAll(new RegExp(`(?<!['"])${SOURCE.import}(?!['"])`, 'g'), TARGET.import);
144
+ await fs.writeFile(configPath, configContent);
145
145
 
146
- const finalInstallCmd = resolveCommand(pm.agent, 'install', [])
147
- await runCommand(finalInstallCmd.command, finalInstallCmd.args)
146
+ const finalInstallCmd = resolveCommand(pm.agent, 'install', []);
147
+ await runCommand(finalInstallCmd.command, finalInstallCmd.args);
148
148
 
149
- console.info(`Successfully replaced the config from ${SOURCE.name} to ${TARGET.name}`)
149
+ console.info(`Successfully replaced the config from ${SOURCE.name} to ${TARGET.name}`);
150
150
  }
151
151
 
152
- main()
152
+ await main();
package/jsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "noEmit": true,
4
+ "strict": true,
5
+ "checkJs": true,
6
+ "target": "ES2020",
7
+ "moduleResolution": "node"
8
+ },
9
+ "include": ["src"]
10
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mouse_484/eslint-config",
3
3
  "type": "module",
4
- "version": "4.0.4",
4
+ "version": "4.2.0",
5
5
  "author": "mouse_484",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/mouse484/config/tree/main/packages/eslint",
@@ -0,0 +1,16 @@
1
+ import { GLOB_ASTRO } from '@antfu/eslint-config';
2
+ import { createConfigs } from '../lib/factory.js';
3
+
4
+ export default createConfigs({
5
+ name: 'astro',
6
+ baseWithOption: 'astro',
7
+ configs: [
8
+ {
9
+ name: 'general',
10
+ files: [GLOB_ASTRO],
11
+ rules: {
12
+ 'astro/no-set-html-directive': 'error',
13
+ },
14
+ },
15
+ ],
16
+ });
@@ -0,0 +1,13 @@
1
+ import { createConfigs } from '../lib/factory.js';
2
+
3
+ export default createConfigs({
4
+ name: 'base',
5
+ configs: [
6
+ {
7
+ name: 'antfu',
8
+ rules: {
9
+ 'antfu/top-level-function': 'off',
10
+ },
11
+ },
12
+ ],
13
+ });
@@ -0,0 +1,41 @@
1
+ import { GLOB_MARKDOWN } from '@antfu/eslint-config';
2
+ import { createConfigs } from '../lib/factory.js';
3
+
4
+ export default createConfigs({
5
+ name: 'stylistic',
6
+ baseWithOption: 'stylistic',
7
+ configs: [
8
+ {
9
+ name: 'general',
10
+ rules: {
11
+ 'style/max-len': [
12
+ 'error',
13
+ {
14
+ code: 100,
15
+ tabWidth: 2,
16
+ comments: 120,
17
+ ignoreUrls: true,
18
+ },
19
+ ],
20
+ 'style/brace-style': [
21
+ 'error',
22
+ '1tbs',
23
+ ],
24
+ 'style/semi': ['error', 'always'],
25
+ },
26
+ },
27
+ {
28
+ name: 'markdown',
29
+ files: [GLOB_MARKDOWN],
30
+ rules: {
31
+ 'style/max-len': [
32
+ 'error',
33
+ {
34
+ ignoreUrls: true,
35
+ ignorePattern: String.raw`^\s*\|`,
36
+ },
37
+ ],
38
+ },
39
+ },
40
+ ],
41
+ });
@@ -0,0 +1,32 @@
1
+ import { GLOB_SVELTE } from '@antfu/eslint-config';
2
+ import { CASES } from '../const/cases.js';
3
+ import { GLOB_SVELTE_ROUTES } from '../const/glob.js';
4
+ import { createConfigs } from '../lib/factory.js';
5
+
6
+ export default createConfigs({
7
+ name: 'svelte',
8
+ baseWithOption: 'svelte',
9
+ configs: [
10
+ {
11
+ name: 'components',
12
+ withOptions: ['unicorn'],
13
+ files: [GLOB_SVELTE],
14
+ rules: {
15
+ 'unicorn/filename-case': [
16
+ 'error',
17
+ {
18
+ case: CASES.camelCase,
19
+ },
20
+ ],
21
+ },
22
+ },
23
+ {
24
+ name: 'kit/routes',
25
+ withOptions: ['unicorn'],
26
+ files: [GLOB_SVELTE_ROUTES],
27
+ rules: {
28
+ 'unicorn/filename-case': 'off',
29
+ },
30
+ },
31
+ ],
32
+ });
@@ -0,0 +1,28 @@
1
+ import eslintPluginReadableTailwind from 'eslint-plugin-readable-tailwind';
2
+ import { createConfigs } from '../lib/factory.js';
3
+
4
+ export default createConfigs({
5
+ name: 'tailwind',
6
+ baseWithOption: 'tailwind',
7
+ configs: [
8
+ (meta) => {
9
+ return {
10
+ name: 'readable-tailwind',
11
+ plugins: {
12
+ 'readable-tailwind': eslintPluginReadableTailwind,
13
+ },
14
+ rules: {
15
+ ...eslintPluginReadableTailwind.configs.warning.rules,
16
+ 'readable-tailwind/multiline': ['warn', {
17
+ group: 'emptyLine',
18
+ }],
19
+ },
20
+ settings: {
21
+ 'readable-tailwind': {
22
+ entryPoint: meta?.entryPoint,
23
+ },
24
+ },
25
+ };
26
+ },
27
+ ],
28
+ });
@@ -0,0 +1,30 @@
1
+ import { GLOB_MARKDOWN_CODE_BLOCK, GLOB_README } from '../const/glob.js';
2
+ import { createConfigs } from '../lib/factory.js';
3
+
4
+ export default createConfigs({
5
+ name: 'unicorn',
6
+ baseWithOption: 'unicorn',
7
+ configs: [
8
+ {
9
+ name: 'general',
10
+ rules: {
11
+ 'unicorn/prevent-abbreviations': [
12
+ 'error',
13
+ {
14
+ allowList: {
15
+ Props: true,
16
+ args: true,
17
+ },
18
+ },
19
+ ],
20
+ },
21
+ },
22
+ {
23
+ name: 'filename-case',
24
+ files: [GLOB_README, GLOB_MARKDOWN_CODE_BLOCK],
25
+ rules: {
26
+ 'unicorn/filename-case': 'off',
27
+ },
28
+ },
29
+ ],
30
+ });
@@ -0,0 +1,6 @@
1
+ export const CASES = /** @type {const} */({
2
+ 'camelCase': 'camelCase',
3
+ 'PascalCase': 'pascalCase',
4
+ 'snake_case': 'snakeCase',
5
+ 'kebab-case': 'kebabCase',
6
+ });
@@ -0,0 +1,11 @@
1
+ export { GLOB_SVELTE as GLOB_SVELTE_COMPONENTS } from '@antfu/eslint-config';
2
+
3
+ export const GLOB_SVELTE_ROUTES = '**/src/routes/**/\+*.svelte';
4
+
5
+ export const GLOB_README = '**/README.md';
6
+
7
+ /**
8
+ * Code block in markdown
9
+ * @see https://github.com/eslint/markdown/blob/32d8cbd8b6d2d121225b5291c2f9a0ea6c2ccd00/docs/processors/markdown.md?plain=1#L96
10
+ */
11
+ export const GLOB_MARKDOWN_CODE_BLOCK = '**/*.md/**';
package/src/index.js CHANGED
@@ -1,125 +1,37 @@
1
- // @ts-check
2
- import antfu, {
3
- GLOB_ASTRO,
4
- GLOB_SVELTE,
5
- } from '@antfu/eslint-config'
6
-
7
- /** @type {Record<string, "camelCase" | "pascalCase" | "snakeCase" | "kebabCase">} */
8
- const CASES = {
9
- 'camelCase': 'camelCase',
10
- 'PascalCase': 'pascalCase',
11
- 'snake_case': 'snakeCase',
12
- 'kebab-case': 'kebabCase',
13
- }
14
-
15
- /** @type {import('@antfu/eslint-config')["antfu"]} */
1
+ import antfu from '@antfu/eslint-config';
2
+ import astro from './configs/astro.js';
3
+ import base from './configs/base.js';
4
+ import stylistic from './configs/stylistic.js';
5
+ import svelte from './configs/svelte.js';
6
+ import tailwind from './configs/tailwind.js';
7
+ import unicorn from './configs/unicorn.js';
8
+
9
+ /** @type {import('./lib/type.js').mouse} */
16
10
  async function mouse(options, ...userConfigs) {
17
11
  options = {
18
- lessOpinionated: true,
19
12
  unicorn: {
20
13
  allRecommended: true,
21
14
  },
15
+ stylistic: true,
22
16
  ...options,
23
- }
17
+ };
24
18
 
25
- /** @type {import('@antfu/eslint-config').TypedFlatConfigItem[]} */
26
19
  const configs = [
27
- {
28
- name: 'mouse/antfu-config',
29
- rules: {
30
- 'antfu/top-level-function': 'off',
31
- },
32
- },
33
- ]
34
-
35
- if (options?.stylistic) {
36
- configs.push({
37
- name: 'mouse/stylistic',
38
- rules: {
39
- 'style/max-len': [
40
- 'error',
41
- {
42
- code: 100,
43
- tabWidth: 2,
44
- comments: 120,
45
- ignoreUrls: true,
46
- },
47
- ],
48
- 'style/brace-style': [
49
- 'error',
50
- '1tbs',
51
- ],
52
- 'style/semi': ['error', 'always'],
53
- },
54
- })
55
- }
56
-
57
- if (options?.astro) {
58
- configs.push({
59
- name: 'mouse/astro',
60
- files: [GLOB_ASTRO],
61
- rules: {
62
- 'astro/no-set-html-directive': 'error',
63
- },
64
- })
65
- }
66
-
67
- if (options?.svelte) {
68
- configs.push(
69
- {
70
- name: 'mouse/svelte/components',
71
- files: [GLOB_SVELTE],
72
- rules: {
73
- 'unicorn/filename-case': [
74
- 'error',
75
- {
76
- case: CASES.PascalCase,
77
- },
78
- ],
79
- },
80
- },
81
- {
82
- name: 'mouse/svelte/kit-routes',
83
- files: ['**/src/routes/**/\+*.svelte'],
84
- rules: {
85
- 'unicorn/filename-case': 'off',
86
- },
87
- },
88
- )
89
- }
90
-
91
- if (options?.unicorn) {
92
- configs.push({
93
- name: 'mouse/unicorn',
94
- rules: {
95
- 'unicorn/prevent-abbreviations': [
96
- 'error',
97
- {
98
- allowList: {
99
- Props: true,
100
- },
101
- },
102
- ],
103
- },
104
- }, {
105
- name: 'mouse/unicorn/filename-case',
106
- files: [
107
- '**/README.md',
108
- /**
109
- * Code block in markdown
110
- * @see https://github.com/eslint/markdown/blob/32d8cbd8b6d2d121225b5291c2f9a0ea6c2ccd00/docs/processors/markdown.md?plain=1#L96
111
- */
112
- '**/*.md/**',
113
- ],
114
- rules: {
115
- 'unicorn/filename-case': 'off',
116
- },
117
- })
118
- }
119
-
120
- return antfu(options, ...configs, ...userConfigs)
20
+ ...base(options),
21
+ // Code style
22
+ ...stylistic(options),
23
+ ...unicorn(options),
24
+ // Language specific
25
+ ...astro(options),
26
+ ...svelte(options),
27
+ // Tools
28
+ ...tailwind(options),
29
+ ];
30
+
31
+ return antfu(options, ...configs, ...userConfigs);
121
32
  }
122
33
 
123
- export default mouse
124
- export { mouse }
125
- export * from '@antfu/eslint-config'
34
+ export default mouse;
35
+ export { mouse };
36
+ export * from './const/glob.js';
37
+ export * from '@antfu/eslint-config';
@@ -0,0 +1,43 @@
1
+ /**
2
+ *
3
+ * @param {string} name
4
+ * @param {(keyof import('./type').Options)[]} withOptions
5
+ * @param {Omit<import('@antfu/eslint-config').TypedFlatConfigItem,'name'>} config
6
+ * @returns {(options: import('./type').Options) => import('@antfu/eslint-config').TypedFlatConfigItem|[]} _
7
+ */
8
+ function createConfig(name, withOptions, config) {
9
+ return (options) => {
10
+ const allowApply = withOptions
11
+ ? withOptions.every(key => key in options)
12
+ : true;
13
+ if (!allowApply) {
14
+ return [];
15
+ }
16
+ return {
17
+ name: `mouse/${name}`,
18
+ ...config,
19
+ };
20
+ };
21
+ }
22
+
23
+ /** @type {import('./type').createConfigs} */
24
+ export function createConfigs({ name, baseWithOption, configs }) {
25
+ return (options) => {
26
+ return configs.flatMap((configItem) => {
27
+ if (typeof configItem === 'function') {
28
+ if (!baseWithOption) {
29
+ throw new Error('baseWithOption is required when configItem is a function');
30
+ }
31
+ const meta = options[baseWithOption];
32
+ // @ts-ignore
33
+ configItem = configItem(typeof meta === 'object' ? meta : undefined);
34
+ }
35
+ const { name: configName, withOptions = [], ...restConfig } = configItem;
36
+ return createConfig(
37
+ `${name}/${configName}`,
38
+ baseWithOption ? [baseWithOption, ...withOptions] : withOptions,
39
+ restConfig,
40
+ )(options);
41
+ });
42
+ };
43
+ }
@@ -0,0 +1,24 @@
1
+ import type antfu from '@antfu/eslint-config';
2
+ import type { TypedFlatConfigItem } from '@antfu/eslint-config';
3
+
4
+ type AntfuParameters = Parameters<typeof antfu>;
5
+ type AntfuOptions = AntfuParameters['0'];
6
+ type AntfuUserConfigs = AntfuParameters['1'][];
7
+
8
+ export type Options = AntfuOptions & {
9
+ tailwind?: boolean | { entryPoint?: string }
10
+ };
11
+
12
+ export declare function mouse(
13
+ options: Options,
14
+ ...configs: AntfuUserConfigs
15
+ ): ReturnType<typeof antfu>;
16
+
17
+ // factoty
18
+ type ConfigItem = TypedFlatConfigItem & { withOptions?: (keyof Options)[], name: string };
19
+ type OnlyObject<T> = T extends object ? T : never;
20
+ export declare function createConfigs<T extends keyof Options = undefined>(parameters: {
21
+ name: string
22
+ baseWithOption?: T
23
+ configs: (ConfigItem | ((meta?: OnlyObject<Options[T]>) => ConfigItem))[]
24
+ }): (options: Options) => TypedFlatConfigItem[];
package/src/index.d.ts DELETED
@@ -1,10 +0,0 @@
1
- import type { Awaitable, OptionsConfig, TypedFlatConfigItem } from '@antfu/eslint-config'
2
-
3
- declare function mouse(
4
- options: OptionsConfig & TypedFlatConfigItem,
5
- ...userConfigs: Awaitable<TypedFlatConfigItem | TypedFlatConfigItem[]>[]
6
- ): Promise<TypedFlatConfigItem>
7
-
8
- export default mouse
9
- export { mouse }
10
- export * from '@antfu/eslint-config'