@10stars/config 14.0.0 → 15.0.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/.oxfmtrc.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "arrowParentheses": "always",
3
+ "trailingCommas": "all",
4
+ "indentWidth": 2,
5
+ "semi": false,
6
+ "useTabs": false,
7
+ "bracketSpacing": true
8
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "$schema": "./node_modules/oxlint/configuration.schema.json",
3
+ "plugins": ["react", "typescript", "import"],
4
+ "env": {
5
+ "browser": true
6
+ },
7
+ "rules": {
8
+ "import/export": "off",
9
+ "import/namespace": "off",
10
+ "import/no-named-as-default": "off",
11
+ "import/no-unresolved": "off",
12
+ "import/order": "off",
13
+ "no-case-declarations": "off",
14
+ "no-console": "off",
15
+ "no-magic-numbers": "off",
16
+ "no-unused-vars": "off",
17
+ "no-useless-constructor": "off",
18
+ "react/display-name": "off",
19
+ "react/jsx-no-bind": "warn",
20
+ "react/jsx-no-target-blank": "error",
21
+ "react/no-children-prop": "off",
22
+ "react/no-unknown-property": [
23
+ "error",
24
+ {
25
+ "ignore": ["sx"]
26
+ }
27
+ ],
28
+ "react/prop-types": "off",
29
+ "react/react-in-jsx-scope": "off",
30
+ "sort-imports": "off",
31
+ "typescript/await-thenable": "off",
32
+ "typescript/ban-ts-comment": "off",
33
+ "typescript/ban-types": "off",
34
+ "typescript/consistent-indexed-object-style": "off",
35
+ "typescript/no-confusing-void-expression": "off",
36
+ "typescript/no-dynamic-delete": "off",
37
+ "typescript/no-empty-function": "off",
38
+ "typescript/no-empty-interface": "off",
39
+ "typescript/no-empty-object-type": "off",
40
+ "typescript/no-explicit-any": "off",
41
+ "typescript/no-invalid-void-type": "off",
42
+ "typescript/no-magic-numbers": "off",
43
+ "typescript/no-non-null-assertion": "off",
44
+ "typescript/no-throw-literal": "off",
45
+ "typescript/no-unnecessary-condition": "off",
46
+ "typescript/no-unnecessary-type-constraint": "off",
47
+ "typescript/no-unnecessary-type-parameters": "off",
48
+ "typescript/no-unsafe-argument": "off",
49
+ "typescript/no-unsafe-assignment": "off",
50
+ "typescript/no-unsafe-call": "off",
51
+ "typescript/no-unsafe-declaration-merging": "off",
52
+ "typescript/no-unsafe-enum-comparison": "off",
53
+ "typescript/no-unsafe-member-access": "off",
54
+ "typescript/no-unsafe-return": "off",
55
+ "typescript/no-unused-vars": "off",
56
+ "typescript/no-useless-constructor": "off",
57
+ "typescript/only-throw-error": "off",
58
+ "typescript/prefer-nullish-coalescing": "off",
59
+ "typescript/unbound-method": "off",
60
+ "typescript/use-unknown-in-catch-callback-variable": "off"
61
+ }
62
+ }
@@ -0,0 +1,50 @@
1
+ {
2
+ "$schema": "./node_modules/oxlint/configuration.schema.json",
3
+ "plugins": ["typescript", "import"],
4
+ "env": {
5
+ "node": true
6
+ },
7
+ "rules": {
8
+ "import/export": "off",
9
+ "import/namespace": "off",
10
+ "import/no-named-as-default": "off",
11
+ "import/no-unresolved": "off",
12
+ "import/order": "off",
13
+ "no-case-declarations": "off",
14
+ "no-console": "off",
15
+ "no-magic-numbers": "off",
16
+ "no-unused-vars": "off",
17
+ "no-useless-constructor": "off",
18
+ "sort-imports": "off",
19
+ "typescript/await-thenable": "off",
20
+ "typescript/ban-ts-comment": "off",
21
+ "typescript/ban-types": "off",
22
+ "typescript/consistent-indexed-object-style": "off",
23
+ "typescript/no-confusing-void-expression": "off",
24
+ "typescript/no-dynamic-delete": "off",
25
+ "typescript/no-empty-function": "off",
26
+ "typescript/no-empty-interface": "off",
27
+ "typescript/no-empty-object-type": "off",
28
+ "typescript/no-explicit-any": "off",
29
+ "typescript/no-invalid-void-type": "off",
30
+ "typescript/no-magic-numbers": "off",
31
+ "typescript/no-non-null-assertion": "off",
32
+ "typescript/no-throw-literal": "off",
33
+ "typescript/no-unnecessary-condition": "off",
34
+ "typescript/no-unnecessary-type-constraint": "off",
35
+ "typescript/no-unnecessary-type-parameters": "off",
36
+ "typescript/no-unsafe-argument": "off",
37
+ "typescript/no-unsafe-assignment": "off",
38
+ "typescript/no-unsafe-call": "off",
39
+ "typescript/no-unsafe-declaration-merging": "off",
40
+ "typescript/no-unsafe-enum-comparison": "off",
41
+ "typescript/no-unsafe-member-access": "off",
42
+ "typescript/no-unsafe-return": "off",
43
+ "typescript/no-unused-vars": "off",
44
+ "typescript/no-useless-constructor": "off",
45
+ "typescript/only-throw-error": "off",
46
+ "typescript/prefer-nullish-coalescing": "off",
47
+ "typescript/unbound-method": "off",
48
+ "typescript/use-unknown-in-catch-callback-variable": "off"
49
+ }
50
+ }
package/package.json CHANGED
@@ -1,50 +1,28 @@
1
1
  {
2
- "private": false,
3
- "publishConfig": {
4
- "access": "public"
5
- },
6
2
  "name": "@10stars/config",
7
- "version": "14.0.0",
8
- "author": "10stars.dev <web@alexandrov.co> (https://alexandrov.co)",
9
- "license": "MIT",
3
+ "version": "15.0.0",
4
+ "private": false,
10
5
  "bin": {
11
6
  "config": "./src/index.ts"
12
7
  },
13
8
  "files": [
9
+ ".oxfmtrc.json",
10
+ "oxlint.config.browser.json",
11
+ "oxlint.config.node.json",
14
12
  "src",
15
- "eslint.config.all.ts",
16
- "eslint.config.common.ts",
17
- "eslint.config.browser.ts",
18
- "eslint.config.node.ts",
19
- ".prettierrc.js",
20
- "commitlint.config.js",
21
13
  "tsconfig.base.json"
22
14
  ],
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
23
18
  "dependencies": {
24
- "@10stars/eslint-plugin-react-hooks": "^5.1.0",
25
- "@commitlint/cli": "^20.0.0",
26
- "@commitlint/config-conventional": "^20.0.0",
27
- "eslint": "^9.0.0",
28
- "@eslint/js": "^9.0.0",
29
- "@eslint-react/eslint-plugin": "^2.0.0",
30
- "@stylistic/eslint-plugin": "^5.0.0",
31
- "@types/lodash": "^4.0.0",
19
+ "@oxc-node/core": "0.0.35",
32
20
  "@types/node": "^24.0.0",
33
21
  "@types/react": "^19.0.0",
34
- "esbuild": "~0.27.0",
35
- "tsx": "^4.20.6",
36
- "eslint-config-prettier": "^10.0.0",
37
- "eslint-plugin-import": "^2.0.0",
38
- "eslint-plugin-no-relative-import-paths": "^1.5.4",
39
- "eslint-plugin-react": "^7.0.0",
40
- "eslint-plugin-react-compiler": "^19.1.0-rc.2",
41
- "eslint-plugin-regexp": "^2.0.0",
42
- "eslint-plugin-simple-import-sort": "^12.0.0",
43
- "globals": "^16.0.0",
44
22
  "husky": "^9.0.0",
45
- "prettier": "^3.0.0",
23
+ "oxfmt": "0.21.0",
24
+ "oxlint": "1.36.0",
46
25
  "type-fest": "^5.0.0",
47
- "typescript": "~5.9.3",
48
- "typescript-eslint": "^8.39.0"
26
+ "typescript": "~5.9.3"
49
27
  }
50
28
  }
package/readme.md CHANGED
@@ -6,9 +6,3 @@
6
6
 
7
7
  - Not intended for global installation
8
8
  - Use it as part of your project's `devDependencies`
9
-
10
- ### Add VS Code extension - [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
11
-
12
- ## Usage
13
-
14
- You can learn more about [ESLint Shareable Configs](http://eslint.org/docs/developer-guide/shareable-configs) on the official ESLint website.
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ import { execSync } from "node:child_process"
2
2
  import path from "node:path"
3
3
 
4
4
  import { checkIsMonorepo, linkPackages } from "./link-packages"
5
+ import { setupVSCode } from "./vscode-config"
5
6
 
6
7
  const cwd = process.env.PWD!
7
8
 
@@ -11,25 +12,21 @@ interface Config {
11
12
 
12
13
  const exec = (cmd: string) => {
13
14
  console.info(`Executing: ${cmd}`)
14
- execSync(cmd, { cwd, stdio: `inherit` }) // make execSync process to use the parent's: "stdin", "stdout", "stderr" streams
15
+ // bunx is optimized for running scripts
16
+ execSync(`bunx ${cmd}`, { cwd, stdio: `inherit` }) // make execSync process to use the parent's: "stdin", "stdout", "stderr" streams
15
17
  }
16
18
 
17
19
  const getConfig = async (): Promise<Config | null> =>
18
20
  import(path.join(cwd, `10stars.config`)).catch(() => null)
19
21
 
20
- const getESLintCommonCmd = async () => {
22
+ const getOxlintCommonCmd = async () => {
21
23
  const isMonorepo = await checkIsMonorepo(cwd)
22
- return `--ext .ts,.tsx --no-error-on-unmatched-pattern ${[
23
- `src`,
24
- `scripts`,
25
- `*.ts`,
26
- ]
27
- .map((p) => (isMonorepo ? `*/${p}` : p))
28
- .join(` `)} ${process.env.CI ? `--quiet` : ``}`
24
+ const paths = [`src`, `scripts`, `.`].map((p) => (isMonorepo ? `*/${p}` : p)).join(` `)
25
+ // Use standard oxlint which picks up localized .oxlintrc.json if present, or defaults
26
+ return `${paths} --ignore-pattern '**/node_modules/**' --ignore-pattern '**/dist/**'`
29
27
  }
30
28
 
31
- const typecheck = () =>
32
- exec(`bun run tsc --project ./tsconfig.json --noEmit --watch`)
29
+ const typecheckAndWatch = () => exec(`tsc --project ./tsconfig.json --noEmit --watch`)
33
30
 
34
31
  const actions = {
35
32
  prepare: {
@@ -37,42 +34,42 @@ const actions = {
37
34
  action: async () => {
38
35
  if (process.env.CI) return
39
36
  exec(`husky`) // husky is intended only for local development (not in CI)
37
+ setupVSCode(cwd) // create/update .vscode directory with standardized extensions.json and settings.json
40
38
  const config = await getConfig()
41
39
  if (config?.linkPackages) await linkPackages(cwd, config.linkPackages)
42
40
  },
43
41
  },
44
- format: {
45
- info: `Format code`,
46
- action: async () => {
47
- const isMonorepo = await checkIsMonorepo(cwd)
48
- exec(
49
- `bun run prettier -l --write './${isMonorepo ? `*/` : ``}src/**/*.{t,j}s{x,}'`,
50
- )
51
- },
52
- },
53
- typecheck: {
54
- info: `Typecheck code (in watch mode)`,
55
- action: typecheck,
42
+ typecheckWatch: {
43
+ info: "Typecheck code (in watch mode)",
44
+ action: typecheckAndWatch,
56
45
  },
57
46
  ts: {
58
- info: `alias for 'typecheck'`,
59
- action: typecheck,
47
+ info: `alias for 'typecheckWatch'`,
48
+ action: typecheckAndWatch,
60
49
  },
61
- typecheckOnce: {
50
+ typecheck: {
62
51
  info: `Typecheck code (once)`,
63
- action: () => exec(`bun run tsc --project ./tsconfig.json --noEmit`),
52
+ action: () => exec(`tsc --project ./tsconfig.json --noEmit`),
64
53
  },
65
54
  lint: {
66
55
  info: `Lint code (once)`,
67
- action: async () =>
68
- exec(`bun run eslint --fix ${await getESLintCommonCmd()}`),
56
+ action: async () => exec(`oxfmt && oxlint --fix ${await getOxlintCommonCmd()}`),
69
57
  },
70
58
  precommit: {
71
59
  info: `Run pre-commit hooks`,
72
- action: () => {
73
- const pathCommitlint = new URL(`../commitlint.config.js`, import.meta.url)
74
- .pathname
75
- exec(`bun run commitlint --edit --config ${pathCommitlint}`)
60
+ action: async () => {
61
+ const fs = await import(`node:fs`)
62
+ const commitMsgFile = process.argv[3] || `.git/COMMIT_EDITMSG`
63
+ const message = fs.readFileSync(commitMsgFile, `utf8`)
64
+ const firstLine = message.split(`\n`)[0] || ``
65
+ const VALID_LABELS = [`ADDED`, `CHANGED`, `DEPRECATED`, `REMOVED`, `FIXED`, `SECURITY`]
66
+ const isValid = VALID_LABELS.some((label) => firstLine.startsWith(`${label}:`))
67
+
68
+ if (!isValid) {
69
+ console.error(`Invalid commit message format.`)
70
+ console.error(`Must start with one of: ${VALID_LABELS.map((l) => `${l}:`).join(`, `)}`)
71
+ process.exit(1)
72
+ }
76
73
  },
77
74
  },
78
75
  } satisfies Record<string, { info: string; action: () => void | Promise<void> }>
@@ -27,9 +27,9 @@ export const linkPackages = async (cwd: string, packagesToLink: string[]) => {
27
27
  console.info(`Linking local packages`)
28
28
 
29
29
  const linkPackage = async (pathPkg: string) => {
30
- const pkgJson: TF.PackageJson = await import(
31
- path.join(pathPkg, `package.json`)
32
- ).catch(() => null)
30
+ const pkgJson: TF.PackageJson = await import(path.join(pathPkg, `package.json`)).catch(
31
+ () => null,
32
+ )
33
33
  if (!pkgJson) return
34
34
 
35
35
  const [orgName, pkgName] = pkgJson.name!.split(`/`)
@@ -47,14 +47,10 @@ export const linkPackages = async (cwd: string, packagesToLink: string[]) => {
47
47
  .then(async (isMonorepo) => {
48
48
  if (!isMonorepo) return promises.push(linkPackage(pathPkg))
49
49
 
50
- const files = await fs
51
- .readdir(relativePath, { withFileTypes: true })
52
- .catch(() => null)
50
+ const files = await fs.readdir(relativePath, { withFileTypes: true }).catch(() => null)
53
51
  if (!files) return
54
52
 
55
- const directories = files
56
- .filter((v) => v.isDirectory())
57
- .map((v) => v.name)
53
+ const directories = files.filter((v) => v.isDirectory()).map((v) => v.name)
58
54
  const packages = (
59
55
  await Promise.all(
60
56
  directories.map(async (v) => {
@@ -0,0 +1,111 @@
1
+ import fs from "node:fs/promises"
2
+ import path from "node:path"
3
+
4
+ const extensionsJson = {
5
+ recommendations: ["oxc.oxc-vscode"],
6
+ unwantedRecommendations: [
7
+ "ms-vscode.vscode-typescript-tslint-plugin",
8
+ "eg2.tslint",
9
+ "zuoez02.tslint-snippets",
10
+ "dbaeumer.jshint",
11
+ "hookyqr.beautify",
12
+ "felipecaputo.git-project-manager",
13
+ "donjayamanne.githistory",
14
+ "ms-azuretools.vscode-docker",
15
+ "dbaeumer.vscode-eslint",
16
+ "esbenp.prettier-vscode",
17
+ ],
18
+ }
19
+
20
+ const settingsJson = {
21
+ // General optimizations
22
+ "extensions.ignoreRecommendations": false,
23
+ "editor.tabSize": 2,
24
+ "editor.formatOnSave": true,
25
+ "editor.suggest.snippetsPreventQuickSuggestions": false,
26
+ "editor.defaultFormatter": "oxc.oxc-vscode",
27
+ "editor.codeActionsOnSave": {
28
+ "source.fixAll": "explicit",
29
+ "source.organizeImports": "never",
30
+ },
31
+ "files.insertFinalNewline": true,
32
+ "files.associations": {
33
+ "tsconfig.json": "jsonc",
34
+ },
35
+ "files.watcherExclude": {
36
+ "**/.git/objects/**": true,
37
+ "**/.git/subtree-cache/**": true,
38
+ "**/node_modules/**": true,
39
+ "**/dist/**": true,
40
+ "**/tmp/**": true,
41
+ "**/public/**": true,
42
+ },
43
+ "task.autoDetect": "off",
44
+ "npm.autoDetect": "off",
45
+ // VSCode CodeLens
46
+ "javascript.referencesCodeLens.enabled": true,
47
+ "typescript.implementationsCodeLens.enabled": true,
48
+ "typescript.referencesCodeLens.enabled": true,
49
+
50
+ // TypeScript
51
+ "typescript.tsdk": "node_modules/typescript/lib",
52
+ "typescript.tsserver.maxTsServerMemory": 8192,
53
+ "typescript.disableAutomaticTypeAcquisition": true,
54
+ "typescript.check.npmIsInstalled": false,
55
+ "typescript.tsserver.log": "off",
56
+ "typescript.autoClosingTags": true,
57
+ "typescript.format.enable": false,
58
+ "typescript.tsserver.useSyntaxServer": "auto",
59
+ "typescript.validate.enable": true,
60
+ "typescript.preferences.importModuleSpecifier": "non-relative",
61
+ "typescript.preferences.importModuleSpecifierEnding": "minimal",
62
+ // Todo
63
+ "todo-tree.ripgrep.ripgrepArgs": "--max-columns=1000 --no-config -i",
64
+ "todo-tree.regex.regex": "((\\*|//|#|<!--|;|/\\*|^)\\s*($TAGS)|^\\s*- \\[ \\])",
65
+ "todo-tree.general.tags": ["@todo", "TODO"],
66
+ }
67
+
68
+ const sortObjectKeys = <T extends Record<string, unknown>>(obj: T): T => {
69
+ const sorted = {} as T
70
+ for (const key of Object.keys(obj).sort()) {
71
+ sorted[key as keyof T] = obj[key as keyof T]
72
+ }
73
+ return sorted
74
+ }
75
+
76
+ export const setupVSCode = async (cwd: string) => {
77
+ const vscodeDir = path.join(cwd, ".vscode")
78
+
79
+ await fs.mkdir(vscodeDir, { recursive: true })
80
+
81
+ const extensionsPath = path.join(vscodeDir, "extensions.json")
82
+ const sortedExtensions = {
83
+ recommendations: extensionsJson.recommendations.sort(),
84
+ unwantedRecommendations: extensionsJson.unwantedRecommendations.sort(),
85
+ }
86
+ await fs.writeFile(extensionsPath, JSON.stringify(sortedExtensions, null, 2) + "\n")
87
+ console.info(`Written: ${extensionsPath}`)
88
+
89
+ const settingsPath = path.join(vscodeDir, "settings.json")
90
+
91
+ // Preserve certain settings from existing file
92
+ let existingSettings: Record<string, unknown> = {}
93
+ try {
94
+ const existingContent = await fs.readFile(settingsPath, "utf8")
95
+ // Strip comments (JSONC support)
96
+ const jsonWithoutComments = existingContent.replace(/\/\/.*|\/\*[\s\S]*?\*\//g, "")
97
+ existingSettings = JSON.parse(jsonWithoutComments)
98
+ } catch {
99
+ // File doesn't exist or is invalid JSON, start fresh
100
+ }
101
+
102
+ const sortedSettings: Record<string, unknown> = sortObjectKeys(settingsJson)
103
+
104
+ // Add serverlessConsole.services last (after sorting) to keep it at the bottom
105
+ if (existingSettings["serverlessConsole.services"]) {
106
+ sortedSettings["serverlessConsole.services"] = existingSettings["serverlessConsole.services"]
107
+ }
108
+
109
+ await fs.writeFile(settingsPath, JSON.stringify(sortedSettings, null, 2) + "\n")
110
+ console.info(`Written: ${settingsPath}`)
111
+ }
package/.prettierrc.js DELETED
@@ -1,38 +0,0 @@
1
- module.exports = {
2
- parser: "typescript",
3
- arrowParens: "always",
4
- trailingComma: "all",
5
- tabWidth: 2,
6
- semi: false,
7
- singleQuote: false,
8
- overrides: [
9
- {
10
- files: "*.yml",
11
- options: { parser: "yaml" },
12
- },
13
- {
14
- files: "*.yaml",
15
- options: { parser: "yaml" },
16
- },
17
- {
18
- files: "*.md",
19
- options: { parser: "markdown" },
20
- },
21
- {
22
- files: "*.mdx",
23
- options: { parser: "mdx" },
24
- },
25
- {
26
- files: "*.json",
27
- options: { parser: "json" },
28
- },
29
- {
30
- files: "*.html",
31
- options: { parser: "html" },
32
- },
33
- {
34
- files: "*.css",
35
- options: { parser: "css" },
36
- },
37
- ],
38
- }
package/LICENSE DELETED
@@ -1,20 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) Alexandrov.co
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy of
6
- this software and associated documentation files (the "Software"), to deal in
7
- the Software without restriction, including without limitation the rights to
8
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
- the Software, and to permit persons to whom the Software is furnished to do so,
10
- subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,29 +0,0 @@
1
- module.exports = {
2
- extends: [`@commitlint/config-conventional`],
3
- /**
4
- * For explanation on how to write rules @see https://commitlint.js.org/#/reference-rules
5
- */
6
- rules: {
7
- "body-leading-blank": [1, `always`],
8
- "footer-leading-blank": [1, `always`],
9
- "header-max-length": [2, `always`, 72],
10
- "scope-case": [2, `always`, `lower-case`],
11
- "subject-case": [2, `never`, [`start-case`, `pascal-case`, `upper-case`]],
12
- "subject-empty": [2, `never`],
13
- "subject-full-stop": [2, `never`, `.`],
14
- "type-case": [2, `always`, `upper-case`],
15
- "type-empty": [2, `never`],
16
- "type-enum": [
17
- 2,
18
- `always`,
19
- [
20
- `ADDED`, // new features
21
- `CHANGED`, // changes in existing functionality
22
- `DEPRECATED`, // soon-to-be removed features
23
- `FIXED`, // any bug fixes
24
- `REMOVED`, // removed features
25
- `SECURITY`, // in case of vulnerabilities
26
- ],
27
- ],
28
- },
29
- }
@@ -1,9 +0,0 @@
1
- import { onlyBrowserWithoutCommon } from "./eslint.config.browser"
2
- import baseConfig, { type Config } from "./eslint.config.common"
3
- import { onlyNodeWithoutCommon } from "./eslint.config.node"
4
-
5
- export default [
6
- ...baseConfig,
7
- ...onlyBrowserWithoutCommon,
8
- ...onlyNodeWithoutCommon,
9
- ] as Config[]
@@ -1,105 +0,0 @@
1
- import reactHooks from "@10stars/eslint-plugin-react-hooks"
2
- import type { ConfigObject } from "@eslint/core"
3
- import eslintReact from "@eslint-react/eslint-plugin"
4
- import reactPlugin from "eslint-plugin-react"
5
- // import * as reactCompiler from "eslint-plugin-react-compiler"
6
- import globals from "globals"
7
-
8
- import baseConfig, { type Config } from "./eslint.config.common"
9
-
10
- const addPluginReact = () =>
11
- [
12
- {
13
- ...reactPlugin.configs.flat.recommended,
14
- settings: { react: { version: `detect` } },
15
- },
16
- reactPlugin.configs.flat[`jsx-runtime`], // Add this if you are using React 17+
17
- // reactCompiler.configs.recommended,
18
- {
19
- rules: {
20
- "react/display-name": 0,
21
- "react/no-children-prop": 0,
22
-
23
- "react/no-unknown-property": [
24
- 2,
25
- {
26
- ignore: [`sx`],
27
- },
28
- ],
29
-
30
- "react/prop-types": 0,
31
- "react/react-in-jsx-scope": 0,
32
-
33
- "react/jsx-filename-extension": [
34
- 1,
35
- {
36
- extensions: [`.jsx`, `.tsx`],
37
- },
38
- ],
39
-
40
- "react/no-invalid-html-attribute": 2,
41
- "react/prefer-stateless-function": 2,
42
- "react/jsx-boolean-value": [1, `never`],
43
- "react/jsx-curly-brace-presence": [1, `always`],
44
- "react/jsx-fragments": 1,
45
- "react/jsx-no-bind": 1,
46
- "react/jsx-no-constructed-context-values": 1,
47
-
48
- "react/jsx-no-script-url": [
49
- 2,
50
- [
51
- {
52
- name: `Link`,
53
- props: [`to`],
54
- },
55
- {
56
- name: `NavLink`,
57
- props: [`to`],
58
- },
59
- {
60
- name: `a`,
61
- props: [`href`, `to`],
62
- },
63
- ],
64
- ],
65
-
66
- "react/jsx-no-useless-fragment": 1,
67
- "react/jsx-no-target-blank": 2,
68
- "react/jsx-sort-props": 1,
69
- },
70
- },
71
- ] satisfies ConfigObject[] as Config[]
72
-
73
- const addPluginReactExtra = () =>
74
- [
75
- eslintReact.configs[`recommended-typescript`],
76
- {
77
- rules: {
78
- "@eslint-react/dom/no-dangerously-set-innerhtml": 0, // we use for specific cases
79
- "@eslint-react/hooks-extra/no-direct-set-state-in-use-effect": 0, // there are valid use cases
80
- },
81
- },
82
- ] satisfies ConfigObject[] as Config[]
83
-
84
- const addStorybookOverrides = () =>
85
- ({
86
- files: [`**/*stories.tsx`],
87
- rules: {
88
- "react/jsx-no-bind": 0, // allow inline functions
89
- "@eslint-react/no-array-index-key": 0, // allow array index as key
90
- },
91
- }) satisfies ConfigObject as Config
92
-
93
- export const onlyBrowserWithoutCommon = [
94
- {
95
- languageOptions: {
96
- globals: globals.browser,
97
- },
98
- },
99
- ...addPluginReact(),
100
- ...addPluginReactExtra(),
101
- reactHooks.configs.recommended,
102
- addStorybookOverrides(),
103
- ] as Config[]
104
-
105
- export default [...baseConfig, ...onlyBrowserWithoutCommon] as Config[]
@@ -1,246 +0,0 @@
1
- import { builtinModules } from "node:module"
2
-
3
- import type { ConfigObject } from "@eslint/core"
4
- import eslint from "@eslint/js"
5
- import stylistic from "@stylistic/eslint-plugin"
6
- import { defineConfig } from "eslint/config"
7
- import eslintConfigPrettier from "eslint-config-prettier"
8
- import importPlugin from "eslint-plugin-import"
9
- import noRelativeImportPaths from "eslint-plugin-no-relative-import-paths"
10
- import * as regexpPlugin from "eslint-plugin-regexp"
11
- import simpleImportSort from "eslint-plugin-simple-import-sort"
12
- import tseslint from "typescript-eslint"
13
-
14
- export type Config = Parameters<typeof defineConfig>[number]
15
-
16
- const addPluginRegexp = () =>
17
- [
18
- regexpPlugin.configs[`flat/recommended`],
19
- {
20
- rules: {
21
- "regexp/no-useless-escape": 1,
22
- "regexp/use-ignore-case": 0,
23
- },
24
- },
25
- ] satisfies ConfigObject[] as Config[]
26
-
27
- const addPluginNoRelativeImportPaths = () =>
28
- ({
29
- plugins: {
30
- "no-relative-import-paths": noRelativeImportPaths,
31
- },
32
- rules: {
33
- "no-relative-import-paths/no-relative-import-paths": [
34
- 1,
35
- { allowSameFolder: true, allowedDepth: 2 },
36
- ],
37
- },
38
- }) satisfies ConfigObject as Config
39
-
40
- const addPluginImport = () =>
41
- [
42
- importPlugin.flatConfigs.recommended,
43
- {
44
- files: [`**/*.{ts,tsx}`], // https://github.com/import-js/eslint-plugin-import/tree/4f145a2c64af4931f4bf3ae951c8b719b544718f?tab=readme-ov-file#config---flat-with-config-in-typescript-eslint
45
- ...importPlugin.flatConfigs.recommended,
46
- ...importPlugin.flatConfigs.typescript,
47
- rules: {
48
- ...importPlugin.configs.recommended.rules,
49
- ...importPlugin.configs.typescript.rules,
50
- },
51
- },
52
- {
53
- rules: {
54
- "import/order": 0,
55
- "import/no-unresolved": 0,
56
- "import/namespace": 0, // we use "import * as x" and then use "x" (ex. Object.keys(x))
57
- "import/no-duplicates": 1,
58
- "import/no-named-as-default": 0,
59
- "import/export": 0, // don't work correctly with "import * as"
60
- "import/no-nodejs-modules": [
61
- 2, // to enforce importing with "node:" prefix
62
- {
63
- allow: builtinModules
64
- .filter((v) => !v.startsWith(`_`))
65
- .map((v) => `node:${v}`),
66
- },
67
- ],
68
- },
69
- },
70
- ] satisfies ConfigObject[] as Config[]
71
-
72
- const addPluginSimpleImportSort = () =>
73
- ({
74
- plugins: {
75
- "simple-import-sort": simpleImportSort,
76
- },
77
- rules: {
78
- "simple-import-sort/imports": 1,
79
- "simple-import-sort/exports": 1,
80
- },
81
- }) satisfies ConfigObject as Config
82
-
83
- const addPluginStylistic = () =>
84
- ({
85
- plugins: {
86
- "@stylistic": stylistic,
87
- },
88
- rules: {
89
- "@stylistic/quotes": [1, `backtick`],
90
- },
91
- }) satisfies ConfigObject as Config
92
-
93
- export default defineConfig(
94
- eslint.configs.recommended,
95
- tseslint.configs.strictTypeChecked,
96
- tseslint.configs.stylisticTypeChecked,
97
- ...addPluginRegexp(),
98
- addPluginNoRelativeImportPaths(),
99
- ...addPluginImport(),
100
- addPluginSimpleImportSort(),
101
- eslintConfigPrettier, // must be one before last
102
- addPluginStylistic(), // must be after eslintConfigPrettier
103
- /** @todo switch to recommended stylistic + customization */
104
- // stylistic.configs.customize({
105
- // // the following options are the default values
106
- // indent: 2,
107
- // quotes: 'single',
108
- // semi: false,
109
- // jsx: true,
110
- // // ...
111
- // }),
112
-
113
- {
114
- ignores: [`**/node_modules`, `**/.git`, `**/dist`, `**/tmp`],
115
- },
116
- {
117
- linterOptions: {
118
- reportUnusedDisableDirectives: false,
119
- },
120
- languageOptions: {
121
- parserOptions: {
122
- projectService: true,
123
- tsconfigRootDir: import.meta.dirname,
124
- ecmaFeatures: {
125
- jsx: true,
126
- },
127
- },
128
- },
129
-
130
- rules: {
131
- "no-case-declarations": 0,
132
- "sort-imports": 0,
133
-
134
- "@typescript-eslint/restrict-template-expressions": [
135
- `error`,
136
- {
137
- allowNumber: true,
138
- },
139
- ],
140
-
141
- "@typescript-eslint/await-thenable": 0, // we want to allow conditional await Promise([ "true/false" && promise ])
142
- "@typescript-eslint/prefer-nullish-coalescing": 0,
143
- "@typescript-eslint/consistent-indexed-object-style": 0,
144
- "@typescript-eslint/no-throw-literal": 0,
145
- "@typescript-eslint/no-unnecessary-type-parameters": 0,
146
- "@typescript-eslint/no-unnecessary-condition": 0,
147
- "@typescript-eslint/no-unnecessary-type-arguments": 1,
148
- "@typescript-eslint/no-unnecessary-qualifier": 1,
149
- "@typescript-eslint/no-confusing-void-expression": 0,
150
- "@typescript-eslint/no-invalid-void-type": 0,
151
- "@typescript-eslint/no-dynamic-delete": 0,
152
- "@typescript-eslint/no-empty-interface": 0,
153
- "@typescript-eslint/no-empty-object-type": 0,
154
- "@typescript-eslint/no-empty-function": 0,
155
- "@typescript-eslint/no-unused-vars": 0,
156
- "@typescript-eslint/no-explicit-any": 0,
157
- "@typescript-eslint/no-namespace": [0, { allowDeclarations: true }], // allow "declare namespace" in .d.ts files
158
- "@typescript-eslint/ban-types": 0,
159
- "@typescript-eslint/ban-ts-comment": 0,
160
- "@typescript-eslint/only-throw-error": 0,
161
- "@typescript-eslint/use-unknown-in-catch-callback-variable": 0,
162
- "@typescript-eslint/no-unsafe-call": 0,
163
- "@typescript-eslint/no-unsafe-argument": 0,
164
- "@typescript-eslint/no-unsafe-assignment": 0,
165
- "@typescript-eslint/no-unsafe-member-access": 0,
166
- "@typescript-eslint/no-unsafe-return": 0,
167
- "@typescript-eslint/no-unsafe-enum-comparison": 0,
168
- "@typescript-eslint/no-non-null-assertion": 0,
169
- "@typescript-eslint/unbound-method": 0,
170
-
171
- "@typescript-eslint/array-type": [
172
- 1,
173
- {
174
- default: `array`,
175
- },
176
- ],
177
-
178
- "@typescript-eslint/consistent-type-definitions": [1, `interface`],
179
- "no-magic-numbers": 0,
180
-
181
- "@typescript-eslint/no-magic-numbers": [
182
- 1,
183
- {
184
- ignore: [
185
- 0, 0.25, -0.25, 0.5, -0.5, 0.75, -0.75, 1, -1, 1.25, -1.25, 1.5,
186
- -1.5, 1.75, -1.75, 2, -2, 2.25, -2.25, 2.5, -2.5, 2.75, -2.75, 3,
187
- -3, 3.25, -3.25, 3.5, -3.5, 3.75, -3.75, 4, -4, 4.25, -4.25, 4.5,
188
- -4.5, 4.75, -4.75, 5, -5, 5.25, -5.25, 5.5, -5.5, 5.75, -5.75, 6,
189
- -6, 6.25, -6.25, 6.5, -6.5, 6.75, -6.75, 7, -7, 7.25, -7.25, 7.5,
190
- -7.5, 7.75, -7.75, 8, -8, 8.25, -8.25, 8.5, -8.5, 8.75, -8.75, 9,
191
- -9, 9.25, -9.25, 9.5, -9.5, 9.75, -9.75, 10, -10,
192
- ],
193
-
194
- ignoreTypeIndexes: true,
195
- ignoreReadonlyClassProperties: true,
196
- ignoreNumericLiteralTypes: true,
197
- ignoreEnums: true,
198
- },
199
- ],
200
-
201
- "@typescript-eslint/unified-signatures": 1,
202
- "@typescript-eslint/prefer-string-starts-ends-with": 1,
203
- "@typescript-eslint/prefer-regexp-exec": 1,
204
- "@typescript-eslint/prefer-includes": 1,
205
- "@typescript-eslint/require-array-sort-compare": 1,
206
- "@typescript-eslint/prefer-for-of": 1,
207
-
208
- "@typescript-eslint/no-misused-promises": [
209
- 1,
210
- {
211
- checksVoidReturn: false,
212
- },
213
- ],
214
-
215
- "@typescript-eslint/no-floating-promises": [
216
- 1,
217
- {
218
- ignoreVoid: true,
219
- },
220
- ],
221
-
222
- "@typescript-eslint/no-extraneous-class": 1,
223
- "@typescript-eslint/explicit-member-accessibility": 1,
224
-
225
- "@typescript-eslint/member-ordering": [
226
- 1,
227
- {
228
- default: [
229
- `public-static-field`,
230
- `public-instance-field`,
231
- `public-constructor`,
232
- `private-static-field`,
233
- `private-instance-field`,
234
- `private-constructor`,
235
- `public-instance-method`,
236
- `protected-instance-method`,
237
- `private-instance-method`,
238
- ],
239
- },
240
- ],
241
-
242
- "no-useless-constructor": 0,
243
- "@typescript-eslint/no-useless-constructor": 1,
244
- },
245
- },
246
- )
@@ -1,17 +0,0 @@
1
- import type { ConfigObject } from "@eslint/core"
2
- import globals from "globals"
3
-
4
- import baseConfig, { type Config } from "./eslint.config.common"
5
-
6
- export const onlyNodeWithoutCommon = [
7
- {
8
- languageOptions: {
9
- globals: globals.node,
10
- },
11
- },
12
- ] satisfies ConfigObject[] as Config[]
13
-
14
- export default [
15
- ...baseConfig,
16
- ...onlyNodeWithoutCommon, //
17
- ] as Config[]