@10stars/config 13.0.2 → 13.0.3

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.
@@ -1,6 +1,7 @@
1
- import baseConfig from "./eslint.config"
2
- import globals from "globals"
3
1
  import type { Linter } from "eslint"
2
+ import globals from "globals"
3
+
4
+ import baseConfig from "./eslint.config"
4
5
 
5
6
  export default [
6
7
  ...baseConfig,
@@ -1,6 +1,7 @@
1
- import baseConfig from "./eslint.config"
2
- import globals from "globals"
3
1
  import type { Linter } from "eslint"
2
+ import globals from "globals"
3
+
4
+ import baseConfig from "./eslint.config"
4
5
 
5
6
  export default [
6
7
  ...baseConfig,
package/eslint.config.ts CHANGED
@@ -1,155 +1,176 @@
1
- import typescriptEslint from "@typescript-eslint/eslint-plugin"
2
- import _import from "eslint-plugin-import"
3
- import react from "eslint-plugin-react"
4
- import builtinModules from "builtin-modules"
5
- // import 10StarsReactHooks from "@10stars/eslint-plugin-react-hooks";
6
- import regexp from "eslint-plugin-regexp"
1
+ import { builtinModules } from "node:module"
2
+
3
+ import eslint from "@eslint/js"
4
+ import stylistic from "@stylistic/eslint-plugin"
5
+ import type { Linter } from "eslint"
6
+ import eslintConfigPrettier from "eslint-config-prettier"
7
+ import importPlugin from "eslint-plugin-import"
7
8
  import noRelativeImportPaths from "eslint-plugin-no-relative-import-paths"
9
+ import reactPlugin from "eslint-plugin-react"
10
+ import * as regexpPlugin from "eslint-plugin-regexp"
8
11
  import simpleImportSort from "eslint-plugin-simple-import-sort"
9
- import sortKeysFix from "eslint-plugin-sort-keys-fix"
10
- import { fixupPluginRules } from "@eslint/compat"
11
- import globals from "globals"
12
- // @ts-expect-error TypeScript requires a different module resolution strategy to import this package
13
- import tsParser from "@typescript-eslint/parser"
14
- import path from "node:path"
15
- import { fileURLToPath } from "node:url"
16
- import js from "@eslint/js"
17
- import { FlatCompat } from "@eslint/eslintrc"
18
- import type { Linter } from "eslint"
19
-
20
- const __filename = fileURLToPath(import.meta.url)
21
- const __dirname = path.dirname(__filename)
22
- const compat = new FlatCompat({
23
- baseDirectory: __dirname,
24
- recommendedConfig: js.configs.recommended,
25
- allConfig: js.configs.all,
26
- })
12
+ import tseslint from "typescript-eslint"
27
13
 
28
- export default [
29
- {
30
- ignores: ["**/node_modules", "**/.git", "**/dist", "**/tmp"],
31
- },
32
- ...(compat.extends(
33
- "eslint:recommended",
34
- "plugin:@typescript-eslint/strict-type-checked",
35
- "plugin:@typescript-eslint/stylistic-type-checked",
36
- "plugin:react/recommended",
37
- // "plugin:@10stars/react-hooks/recommended",
38
- "plugin:regexp/recommended",
39
- "prettier",
40
- ) as any),
41
- {
42
- plugins: {
43
- "@typescript-eslint": typescriptEslint,
44
- import: fixupPluginRules(_import),
45
- react,
46
- // "@10stars/react-hooks": 10StarsReactHooks,
47
- regexp,
48
- "no-relative-import-paths": noRelativeImportPaths,
49
- "simple-import-sort": simpleImportSort,
50
- "sort-keys-fix": sortKeysFix,
51
- },
52
-
53
- languageOptions: {
54
- parser: tsParser,
55
- ecmaVersion: "latest",
56
- sourceType: "module",
14
+ // import 10StarsReactHooks from "@10stars/eslint-plugin-react-hooks";
57
15
 
58
- parserOptions: {
59
- ecmaFeatures: {
60
- jsx: true,
61
- },
16
+ const addPluginRegexp = () =>
17
+ [
18
+ regexpPlugin.configs[`flat/recommended`],
19
+ {
20
+ rules: {
21
+ "regexp/no-useless-escape": 1,
22
+ "regexp/use-ignore-case": 0,
62
23
  },
63
24
  },
25
+ ] satisfies Linter.Config[]
64
26
 
65
- settings: {
66
- "import/parsers": {
67
- "@typescript-eslint/parser": [".ts", ".tsx"],
68
- },
69
-
70
- "import/extensions": [".ts", ".tsx", ".js", ".jsx"],
71
-
72
- react: {
73
- version: "18.0.0",
74
- },
27
+ const addPluginNoRelativeImportPaths = () =>
28
+ ({
29
+ plugins: {
30
+ "no-relative-import-paths": noRelativeImportPaths,
75
31
  },
76
-
77
32
  rules: {
78
- "no-case-declarations": 0,
79
-
80
33
  "no-relative-import-paths/no-relative-import-paths": [
81
34
  1,
82
- {
83
- allowSameFolder: true,
84
- allowedDepth: 2,
85
- },
35
+ { allowSameFolder: true, allowedDepth: 2 },
86
36
  ],
37
+ },
38
+ }) satisfies Linter.Config
87
39
 
88
- "import/order": 0,
89
- "import/no-unresolved": 0,
90
- "import/no-duplicates": 1,
91
- "import/no-nodejs-modules": [
92
- 2,
93
- {
94
- allow: builtinModules.flatMap((v) => [
95
- `node:${v}`,
96
- `node:${v}/promises`,
97
- ]),
40
+ const addPluginReact = () =>
41
+ [
42
+ reactPlugin.configs.flat.recommended, // This is not a plugin object, but a shareable config object
43
+ reactPlugin.configs.flat["jsx-runtime"], // Add this if you are using React 17+
44
+ {
45
+ settings: {
46
+ react: {
47
+ version: "18",
98
48
  },
99
- ],
49
+ },
50
+ rules: {
51
+ "react/display-name": 0,
52
+ "react/no-children-prop": 0,
100
53
 
101
- "sort-imports": 0,
102
- "simple-import-sort/imports": 1,
103
- "simple-import-sort/exports": 1,
104
- "react/display-name": 0,
105
- "react/no-children-prop": 0,
54
+ "react/no-unknown-property": [
55
+ 2,
56
+ {
57
+ ignore: [`sx`],
58
+ },
59
+ ],
106
60
 
107
- "react/no-unknown-property": [
108
- 2,
109
- {
110
- ignore: ["sx"],
111
- },
112
- ],
61
+ "react/prop-types": 0,
62
+ "react/react-in-jsx-scope": 0,
63
+
64
+ "react/jsx-filename-extension": [
65
+ 1,
66
+ {
67
+ extensions: [`.jsx`, `.tsx`],
68
+ },
69
+ ],
113
70
 
114
- "react/prop-types": 0,
115
- "react/react-in-jsx-scope": 0,
71
+ "react/no-invalid-html-attribute": 2,
72
+ "react/prefer-stateless-function": 2,
73
+ "react/jsx-boolean-value": [1, `never`],
74
+ "react/jsx-curly-brace-presence": [1, `always`],
75
+ "react/jsx-fragments": 1,
76
+ "react/jsx-no-bind": 1,
77
+ "react/jsx-no-constructed-context-values": 1,
116
78
 
117
- "react/jsx-filename-extension": [
118
- 1,
119
- {
120
- extensions: [".jsx", ".tsx"],
121
- },
122
- ],
79
+ "react/jsx-no-script-url": [
80
+ 2,
81
+ [
82
+ {
83
+ name: `Link`,
84
+ props: [`to`],
85
+ },
86
+ {
87
+ name: `NavLink`,
88
+ props: [`to`],
89
+ },
90
+ {
91
+ name: `a`,
92
+ props: [`href`, `to`],
93
+ },
94
+ ],
95
+ ],
123
96
 
124
- "react/no-invalid-html-attribute": 2,
125
- "react/prefer-stateless-function": 2,
126
- "react/jsx-boolean-value": [1, "never"],
127
- "react/jsx-curly-brace-presence": [1, "always"],
128
- "react/jsx-fragments": 1,
129
- "react/jsx-no-bind": 1,
130
- "react/jsx-no-constructed-context-values": 1,
97
+ "react/jsx-no-useless-fragment": 1,
98
+ "react/jsx-no-target-blank": 2,
99
+ "react/jsx-sort-props": 1,
100
+ },
101
+ },
102
+ ] satisfies Linter.Config[]
131
103
 
132
- "react/jsx-no-script-url": [
133
- 2,
134
- [
135
- {
136
- name: "Link",
137
- props: ["to"],
138
- },
104
+ const addPluginImport = () =>
105
+ [
106
+ importPlugin.flatConfigs.recommended,
107
+ {
108
+ rules: {
109
+ "import/order": 0,
110
+ "import/no-unresolved": 0,
111
+ "import/no-duplicates": 1,
112
+ "import/no-nodejs-modules": [
113
+ 2,
139
114
  {
140
- name: "NavLink",
141
- props: ["to"],
142
- },
143
- {
144
- name: "a",
145
- props: ["href", "to"],
115
+ allow: builtinModules
116
+ .filter((v) => !v.startsWith(`_`))
117
+ .map((v) => `node:${v}`),
146
118
  },
147
119
  ],
148
- ],
120
+ },
121
+ },
122
+ ] satisfies Linter.Config[]
149
123
 
150
- "react/jsx-no-useless-fragment": 1,
151
- "react/jsx-no-target-blank": 2,
152
- "react/jsx-sort-props": 1,
124
+ const addPluginSimpleImportSort = () =>
125
+ ({
126
+ plugins: {
127
+ "simple-import-sort": simpleImportSort,
128
+ },
129
+ rules: {
130
+ "simple-import-sort/imports": 1,
131
+ "simple-import-sort/exports": 1,
132
+ },
133
+ }) satisfies Linter.Config
134
+
135
+ const addPluginStylistic = () =>
136
+ ({
137
+ plugins: {
138
+ stylistic,
139
+ },
140
+ rules: {
141
+ "@stylistic/quotes": [1, `backtick`],
142
+ },
143
+ }) satisfies Linter.Config
144
+
145
+ export default tseslint.config(
146
+ eslint.configs.recommended,
147
+ tseslint.configs.strictTypeChecked,
148
+ tseslint.configs.stylisticTypeChecked,
149
+ ...addPluginRegexp(),
150
+ addPluginNoRelativeImportPaths(),
151
+ ...addPluginReact(),
152
+ ...addPluginImport(),
153
+ addPluginSimpleImportSort(),
154
+ addPluginStylistic(),
155
+ eslintConfigPrettier, // must be last
156
+
157
+ {
158
+ ignores: [`**/node_modules`, `**/.git`, `**/dist`, `**/tmp`],
159
+ },
160
+ {
161
+ languageOptions: {
162
+ parserOptions: {
163
+ projectService: true,
164
+ tsconfigRootDir: import.meta.dirname,
165
+ ecmaFeatures: {
166
+ jsx: true,
167
+ },
168
+ },
169
+ },
170
+
171
+ rules: {
172
+ "no-case-declarations": 0,
173
+ "sort-imports": 0,
153
174
 
154
175
  // "@10stars/react-hooks/exhaustive-deps": [
155
176
  // 1,
@@ -161,7 +182,7 @@ export default [
161
182
  // ],
162
183
 
163
184
  "@typescript-eslint/restrict-template-expressions": [
164
- "error",
185
+ `error`,
165
186
  {
166
187
  allowNumber: true,
167
188
  },
@@ -181,23 +202,23 @@ export default [
181
202
  "@typescript-eslint/ban-types": 0,
182
203
  "@typescript-eslint/only-throw-error": 0,
183
204
  "@typescript-eslint/use-unknown-in-catch-callback-variable": 0,
205
+ "@typescript-eslint/no-unsafe-call": 0,
206
+ "@typescript-eslint/no-unsafe-argument": 0,
184
207
  "@typescript-eslint/no-unsafe-assignment": 0,
185
208
  "@typescript-eslint/no-unsafe-member-access": 0,
186
209
  "@typescript-eslint/no-unsafe-return": 0,
187
210
  "@typescript-eslint/no-unsafe-enum-comparison": 0,
188
211
  "@typescript-eslint/no-non-null-assertion": 0,
189
212
  "@typescript-eslint/unbound-method": 0,
190
- quotes: 0,
191
213
 
192
214
  "@typescript-eslint/array-type": [
193
215
  1,
194
216
  {
195
- default: "array",
217
+ default: `array`,
196
218
  },
197
219
  ],
198
220
 
199
- "@typescript-eslint/quotes": [1, "backtick"],
200
- "@typescript-eslint/consistent-type-definitions": [1, "interface"],
221
+ "@typescript-eslint/consistent-type-definitions": [1, `interface`],
201
222
  "no-magic-numbers": 0,
202
223
 
203
224
  "@typescript-eslint/no-magic-numbers": [
@@ -250,23 +271,21 @@ export default [
250
271
  1,
251
272
  {
252
273
  default: [
253
- "public-static-field",
254
- "public-instance-field",
255
- "public-constructor",
256
- "private-static-field",
257
- "private-instance-field",
258
- "private-constructor",
259
- "public-instance-method",
260
- "protected-instance-method",
261
- "private-instance-method",
274
+ `public-static-field`,
275
+ `public-instance-field`,
276
+ `public-constructor`,
277
+ `private-static-field`,
278
+ `private-instance-field`,
279
+ `private-constructor`,
280
+ `public-instance-method`,
281
+ `protected-instance-method`,
282
+ `private-instance-method`,
262
283
  ],
263
284
  },
264
285
  ],
265
286
 
266
287
  "no-useless-constructor": 0,
267
288
  "@typescript-eslint/no-useless-constructor": 1,
268
- "regexp/no-useless-escape": 1,
269
- "regexp/use-ignore-case": 0,
270
289
  },
271
290
  },
272
- ] satisfies Linter.Config[]
291
+ )
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "name": "@10stars/config",
7
- "version": "13.0.2",
7
+ "version": "13.0.3",
8
8
  "author": "10stars.dev <web@alexandrov.co> (https://alexandrov.co)",
9
9
  "license": "MIT",
10
10
  "bin": {
@@ -19,21 +19,16 @@
19
19
  "commitlint.config.js",
20
20
  "tsconfig.base.json"
21
21
  ],
22
- "scripts": {
23
- "config": "tsx ./src/index.ts"
24
- },
25
22
  "comments-dependencies": {
26
23
  "tsx": "newer tsx breaks ladle"
27
24
  },
28
25
  "dependencies": {
29
26
  "@commitlint/cli": "^19.0.0",
30
27
  "@commitlint/config-conventional": "^19.0.0",
28
+ "@stylistic/eslint-plugin": "^4.0.0",
31
29
  "@types/lodash": "^4.0.0",
32
30
  "@types/node": "^22.0.0",
33
31
  "@types/react": "^18.0.0",
34
- "@typescript-eslint/eslint-plugin": "^8.0.0",
35
- "@typescript-eslint/parser": "^8.0.0",
36
- "builtin-modules": "^5.0.0",
37
32
  "esbuild": "~0.25.0",
38
33
  "tsx": "4.11.2",
39
34
  "@eslint/compat": "^1.0.0",
@@ -45,11 +40,11 @@
45
40
  "eslint-plugin-react": "^7.0.0",
46
41
  "eslint-plugin-regexp": "^2.0.0",
47
42
  "eslint-plugin-simple-import-sort": "^12.0.0",
48
- "eslint-plugin-sort-keys-fix": "^1.0.0",
49
43
  "globals": "^16.0.0",
50
44
  "husky": "^9.0.0",
51
45
  "prettier": "^3.0.0",
52
46
  "type-fest": "^4.0.0",
53
- "typescript": "~5.7.2"
47
+ "typescript": "~5.7.2",
48
+ "typescript-eslint": "^8.0.0"
54
49
  }
55
50
  }
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { execSync } from "node:child_process"
2
2
  import path from "node:path"
3
3
 
4
- import { linkPackages, checkIsMonorepo } from "./link-packages"
4
+ import { checkIsMonorepo, linkPackages } from "./link-packages"
5
5
 
6
6
  const cwd = process.env.PWD!
7
7
 
@@ -11,11 +11,11 @@ interface Config {
11
11
 
12
12
  const exec = (cmd: string) => {
13
13
  console.info(`Executing: ${cmd}`)
14
- execSync(cmd, { cwd, stdio: "inherit" }) // make execSync process to use the parent's: "stdin", "stdout", "stderr" streams
14
+ execSync(cmd, { cwd, stdio: `inherit` }) // make execSync process to use the parent's: "stdin", "stdout", "stderr" streams
15
15
  }
16
16
 
17
17
  const getConfig = async (): Promise<Config> =>
18
- import(path.join(cwd, "10stars.config")).catch(() => {
18
+ import(path.join(cwd, `10stars.config`)).catch(() => {
19
19
  throw new Error(
20
20
  `10stars.config.ts not found.\nYou need to place it in the root of the repository.`,
21
21
  )
@@ -26,13 +26,13 @@ const getESLintCommonCmd = async () => {
26
26
  return `--ext .ts,.tsx --no-error-on-unmatched-pattern ${isMonorepo ? `*/src */*.ts` : `src *.ts`} ${process.env.CI ? `--quiet` : ``}`
27
27
  }
28
28
 
29
- const typecheck = () => exec("tsc --project ./tsconfig.json --watch --noEmit")
29
+ const typecheck = () => exec(`tsc --project ./tsconfig.json --watch --noEmit`)
30
30
 
31
31
  const actions = {
32
32
  prepare: {
33
- info: "Runs husky and links packages",
33
+ info: `Runs husky and links packages`,
34
34
  action: async () => {
35
- exec("husky")
35
+ exec(`husky`)
36
36
  if (process.env.CI) return
37
37
 
38
38
  const config = await getConfig()
@@ -40,7 +40,7 @@ const actions = {
40
40
  },
41
41
  },
42
42
  format: {
43
- info: "Format code",
43
+ info: `Format code`,
44
44
  action: async () => {
45
45
  const isMonorepo = await checkIsMonorepo(cwd)
46
46
  exec(
@@ -49,23 +49,19 @@ const actions = {
49
49
  },
50
50
  },
51
51
  typecheck: {
52
- info: "Typecheck code (in watch mode)",
52
+ info: `Typecheck code (in watch mode)`,
53
53
  action: typecheck,
54
54
  },
55
55
  ts: {
56
- info: "alias for 'typecheck'",
56
+ info: `alias for 'typecheck'`,
57
57
  action: typecheck,
58
58
  },
59
59
  typecheckOnce: {
60
- info: "Typecheck code (once)",
61
- action: () => exec("tsc --project ./tsconfig.json --noEmit"),
60
+ info: `Typecheck code (once)`,
61
+ action: () => exec(`tsc --project ./tsconfig.json --noEmit`),
62
62
  },
63
63
  lint: {
64
- info: "Lint code (in watch mode)",
65
- action: async () => exec(`esw --watch ${await getESLintCommonCmd()}`),
66
- },
67
- lintOnce: {
68
- info: "Lint code (once)",
64
+ info: `Lint code (once)`,
69
65
  action: async () => exec(`eslint --fix ${await getESLintCommonCmd()}`),
70
66
  },
71
67
  } satisfies Record<string, { info: string; action: () => void | Promise<void> }>
@@ -78,7 +74,7 @@ export const run = async () => {
78
74
  `Unknown command: ${cmd}\n`,
79
75
  `Example CLI cmd: $ config lint`,
80
76
  `Available commands:`,
81
- ].join("\n")
77
+ ].join(`\n`)
82
78
  for (const availableAction of availableActions) {
83
79
  error += `\n ${availableAction} - ${actions[availableAction].info}`
84
80
  }
@@ -87,4 +83,4 @@ export const run = async () => {
87
83
  await actions[cmd].action()
88
84
  }
89
85
 
90
- run()
86
+ void run()
@@ -19,7 +19,7 @@ const symlink = async (pathTarget: string, pathSymlink: string) => {
19
19
  }
20
20
 
21
21
  export const checkIsMonorepo = async (pathPkg: string) => {
22
- const pkgJson = await import(path.join(pathPkg, "package.json"))
22
+ const pkgJson = await import(path.join(pathPkg, `package.json`))
23
23
  return Boolean(pkgJson.workspaces)
24
24
  }
25
25
 
@@ -41,35 +41,37 @@ export const linkPackages = async (cwd: string, packagesToLink: string[]) => {
41
41
  const promises: Promise<unknown>[] = []
42
42
  for (const relativePath of packagesToLink) {
43
43
  const pathPkg = path.join(cwd, relativePath)
44
- checkIsMonorepo(pathPkg)
45
- .catch(() => null) // relative path might point to a non-existing directory for a particular developer; skip linking a particular package in that case
46
- .then(async (isMonorepo) => {
47
- if (!isMonorepo) return promises.push(linkPackage(pathPkg))
44
+ promises.push(
45
+ checkIsMonorepo(pathPkg)
46
+ .catch(() => null) // relative path might point to a non-existing directory for a particular developer; skip linking a particular package in that case
47
+ .then(async (isMonorepo) => {
48
+ if (!isMonorepo) return promises.push(linkPackage(pathPkg))
48
49
 
49
- const files = await fs
50
- .readdir(relativePath, { withFileTypes: true })
51
- .catch(() => null)
52
- if (!files) return
50
+ const files = await fs
51
+ .readdir(relativePath, { withFileTypes: true })
52
+ .catch(() => null)
53
+ if (!files) return
53
54
 
54
- const directories = files
55
- .filter((v) => v.isDirectory())
56
- .map((v) => v.name)
57
- const packages = (
58
- await Promise.all(
59
- directories.map(async (v) => {
60
- const pathPkg = path.join(cwd, relativePath, v)
61
- const pkgJson: TF.PackageJson = await import(
62
- path.join(pathPkg, `package.json`)
63
- ).catch(() => null)
64
- if (pkgJson) return v
65
- }),
66
- )
67
- ).filter(Boolean)
68
- for (const pkg of packages) {
69
- const relativePathToPkg = path.join(cwd, relativePath, pkg!)
70
- promises.push(linkPackage(relativePathToPkg))
71
- }
72
- })
55
+ const directories = files
56
+ .filter((v) => v.isDirectory())
57
+ .map((v) => v.name)
58
+ const packages = (
59
+ await Promise.all(
60
+ directories.map(async (v) => {
61
+ const pathPkg = path.join(cwd, relativePath, v)
62
+ const pkgJson: TF.PackageJson = await import(
63
+ path.join(pathPkg, `package.json`)
64
+ ).catch(() => null)
65
+ if (pkgJson) return v
66
+ }),
67
+ )
68
+ ).filter(Boolean)
69
+ for (const pkg of packages) {
70
+ const relativePathToPkg = path.join(cwd, relativePath, pkg!)
71
+ promises.push(linkPackage(relativePathToPkg))
72
+ }
73
+ }),
74
+ )
73
75
  }
74
76
 
75
77
  await Promise.all(promises)