@mouse_484/eslint-config 4.1.0 → 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,22 +39,21 @@ 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
  /**
@@ -63,90 +62,91 @@ function runCommand(command, args = []) {
63
62
  * @param {(data: any) => any} updateFunction - Transform function
64
63
  */
65
64
  async function updateJSONFile(filePath, updateFunction) {
66
- const content = await fs.readFile(filePath, 'utf8')
67
- const data = JSON.parse(content)
68
- const updated = updateFunction(data)
69
- await fs.writeFile(filePath, JSON.stringify(updated, undefined, 2))
70
- return updated
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
105
  const package_ = await updateJSONFile(packageJSONPath, (packageData) => {
107
- packageData.devDependencies = packageData.devDependencies || {}
108
- delete packageData.devDependencies[SOURCE.name]
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
- packageData.devDependencies[TARGET.name] = targetVersion
119
+ TARGET.version = targetVersion;
120
+ packageData.devDependencies[TARGET.name] = targetVersion;
123
121
 
124
122
  packageData.scripts = {
125
123
  ...packageData.scripts,
126
124
  'lint': 'eslint .',
127
125
  'lint:fix': 'eslint --fix .',
128
- }
126
+ };
129
127
 
130
- return packageData
131
- })
128
+ return packageData;
129
+ });
132
130
 
133
- const configExtension = package_.type === 'module' ? 'js' : 'mjs'
134
- const eslintConfigFile = configExtension === '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, 'utf8')
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
- .replaceAll(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
- await main()
152
+ await main();
package/jsconfig.json CHANGED
@@ -2,7 +2,9 @@
2
2
  "compilerOptions": {
3
3
  "noEmit": true,
4
4
  "strict": true,
5
- "checkJs": true
5
+ "checkJs": true,
6
+ "target": "ES2020",
7
+ "moduleResolution": "node"
6
8
  },
7
- "include": ["./src/**/*.js"]
9
+ "include": ["src"]
8
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.1.0",
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
+ });
@@ -3,4 +3,4 @@ export const CASES = /** @type {const} */({
3
3
  'PascalCase': 'pascalCase',
4
4
  'snake_case': 'snakeCase',
5
5
  'kebab-case': 'kebabCase',
6
- })
6
+ });
package/src/const/glob.js CHANGED
@@ -1,11 +1,11 @@
1
- export { GLOB_SVELTE as GLOB_SVELTE_COMPONENTS } from '@antfu/eslint-config'
1
+ export { GLOB_SVELTE as GLOB_SVELTE_COMPONENTS } from '@antfu/eslint-config';
2
2
 
3
- export const GLOB_SVELTE_ROUTES = '**/src/routes/**/\+*.svelte'
3
+ export const GLOB_SVELTE_ROUTES = '**/src/routes/**/\+*.svelte';
4
4
 
5
- export const GLOB_README = '**/README.md'
5
+ export const GLOB_README = '**/README.md';
6
6
 
7
7
  /**
8
8
  * Code block in markdown
9
9
  * @see https://github.com/eslint/markdown/blob/32d8cbd8b6d2d121225b5291c2f9a0ea6c2ccd00/docs/processors/markdown.md?plain=1#L96
10
10
  */
11
- export const GLOB_MARKDOWN_CODE_BLOCK = '**/*.md/**'
11
+ export const GLOB_MARKDOWN_CODE_BLOCK = '**/*.md/**';
package/src/index.js CHANGED
@@ -1,116 +1,37 @@
1
- import antfu, {
2
- GLOB_ASTRO,
3
- GLOB_SVELTE,
4
- } from '@antfu/eslint-config'
5
- import { CASES } from './const/cases.js'
6
- import { GLOB_MARKDOWN_CODE_BLOCK, GLOB_README, GLOB_SVELTE_ROUTES } from './const/glob.js'
7
-
8
- /** @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} */
9
10
  async function mouse(options, ...userConfigs) {
10
11
  options = {
11
- lessOpinionated: true,
12
12
  unicorn: {
13
13
  allRecommended: true,
14
14
  },
15
+ stylistic: true,
15
16
  ...options,
16
- }
17
+ };
17
18
 
18
- /** @type {import('@antfu/eslint-config').TypedFlatConfigItem[]} */
19
19
  const configs = [
20
- {
21
- name: 'mouse/antfu-config',
22
- rules: {
23
- 'antfu/top-level-function': 'off',
24
- },
25
- },
26
- ]
27
-
28
- if (options?.stylistic) {
29
- configs.push({
30
- name: 'mouse/stylistic',
31
- rules: {
32
- 'style/max-len': [
33
- 'error',
34
- {
35
- code: 100,
36
- tabWidth: 2,
37
- comments: 120,
38
- ignoreUrls: true,
39
- },
40
- ],
41
- 'style/brace-style': [
42
- 'error',
43
- '1tbs',
44
- ],
45
- 'style/semi': ['error', 'always'],
46
- },
47
- })
48
- }
49
-
50
- if (options?.astro) {
51
- configs.push({
52
- name: 'mouse/astro',
53
- files: [GLOB_ASTRO],
54
- rules: {
55
- 'astro/no-set-html-directive': 'error',
56
- },
57
- })
58
- }
59
-
60
- if (options?.svelte) {
61
- configs.push(
62
- {
63
- name: 'mouse/svelte/components',
64
- files: [GLOB_SVELTE],
65
- rules: {
66
- 'unicorn/filename-case': [
67
- 'error',
68
- {
69
- case: CASES.camelCase,
70
- },
71
- ],
72
- },
73
- },
74
- {
75
- name: 'mouse/svelte/kit-routes',
76
- files: [GLOB_SVELTE_ROUTES],
77
- rules: {
78
- 'unicorn/filename-case': 'off',
79
- },
80
- },
81
- )
82
- }
83
-
84
- if (options?.unicorn) {
85
- configs.push({
86
- name: 'mouse/unicorn',
87
- rules: {
88
- 'unicorn/prevent-abbreviations': [
89
- 'error',
90
- {
91
- allowList: {
92
- Props: true,
93
- args: true,
94
- },
95
- },
96
- ],
97
- },
98
- }, {
99
- name: 'mouse/unicorn/filename-case',
100
- files: [
101
- GLOB_README,
102
- GLOB_MARKDOWN_CODE_BLOCK,
103
- ],
104
- rules: {
105
- 'unicorn/filename-case': 'off',
106
- },
107
- })
108
- }
109
-
110
- 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);
111
32
  }
112
33
 
113
- export default mouse
114
- export { mouse }
115
- export * from './const/glob.js'
116
- 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[];