@naturalcycles/dev-lib 20.0.10 → 20.1.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.
@@ -193,14 +193,15 @@ export default {
193
193
  'import-x/no-duplicates': [2, { 'prefer-inline': false }],
194
194
  'import-x/export': 2,
195
195
  'import-x/no-empty-named-blocks': 2,
196
- 'import-x/no-cycle': [
197
- 2,
198
- {
199
- ignoreExternal: true,
200
- allowUnsafeDynamicCyclicDependency: true,
201
- maxDepth: 10,
202
- },
203
- ],
196
+ // Disabling no-cycle as the slowest rule. Oxlint is to be adopted instead
197
+ // 'import-x/no-cycle': [
198
+ // 2,
199
+ // {
200
+ // ignoreExternal: true,
201
+ // allowUnsafeDynamicCyclicDependency: true,
202
+ // maxDepth: 10,
203
+ // },
204
+ // ],
204
205
  'import-x/no-useless-path-segments': 2,
205
206
  'import-x/no-default-export': 0, // biome
206
207
  // 'import-x/no-commonjs': 2, // biome `noCommonJs`
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @naturalcycles/dev-lib/cfg/eslint.config.js
2
+ * `@naturalcycles/dev-lib/cfg/eslint.config.js`
3
3
  *
4
4
  * Shared eslint FLAT config.
5
5
  */
@@ -1,7 +1,6 @@
1
1
  /*
2
2
  Default config for `lint-staged`.
3
3
  Extendable.
4
- Supports default configs for `prettier`, `stylelint`, `eslint`, if they are not found in target project.
5
4
  */
6
5
 
7
6
  const {
@@ -28,6 +27,8 @@ const stylelintConfigPath = [`stylelint.config.js`].find(fs.existsSync)
28
27
 
29
28
  const eslintConfigPath = ['eslint.config.js'].find(fs.existsSync)
30
29
 
30
+ const oxlintConfigPath = ['.oxlintrc.json'].find(fs.existsSync)
31
+
31
32
  let prettierCmd = undefined
32
33
 
33
34
  if (prettierConfigPath) {
@@ -61,6 +62,12 @@ if (eslintConfigPath) {
61
62
  .join(' ')
62
63
  }
63
64
 
65
+ let oxlintCmd = undefined
66
+
67
+ if (oxlintConfigPath) {
68
+ oxlintCmd = ['oxlint', '--fix', '--max-warnings=1'].filter(Boolean).join(' ')
69
+ }
70
+
64
71
  const stylelintExists =
65
72
  !!stylelintConfigPath &&
66
73
  fs.existsSync('node_modules/stylelint') &&
@@ -71,7 +78,7 @@ const biomeConfigPath = ['biome.jsonc'].find(p => fs.existsSync(p))
71
78
  const biomeCmd = biomeConfigPath && `biome lint --write --unsafe --no-errors-on-unmatched`
72
79
 
73
80
  const linters = {
74
- // biome, eslint, stylelint, prettier
81
+ // biome, oxlint, eslint, stylelint, prettier
75
82
  [`./{src,scripts,e2e}/**/*.{${prettierExtensionsAll}}`]: match =>
76
83
  runBiomeEslintStylelintPrettier(match),
77
84
 
@@ -88,11 +95,17 @@ export function runBiomeEslintStylelintPrettier(match) {
88
95
  const filesList = getFilesList(match)
89
96
  if (!filesList) return []
90
97
 
91
- return [biomeCmd, eslintCmd, stylelintCmd, prettierCmd]
98
+ return [biomeCmd, oxlintCmd, eslintCmd, stylelintCmd, prettierCmd]
92
99
  .filter(Boolean)
93
100
  .map(s => `${s} ${filesList}`)
94
101
  }
95
102
 
103
+ export function runOxlintPrettier(match) {
104
+ const filesList = getFilesList(match)
105
+ if (!filesList) return []
106
+ return [oxlintCmd, prettierCmd].filter(Boolean).map(s => `${s} ${filesList}`)
107
+ }
108
+
96
109
  export function runPrettier(match) {
97
110
  const filesList = getFilesList(match)
98
111
  if (!filesList || !prettierCmd) return []
@@ -0,0 +1,84 @@
1
+ {
2
+ "plugins": [
3
+ "oxc",
4
+ "eslint",
5
+ "typescript",
6
+ "unicorn",
7
+ "import",
8
+ "jsdoc",
9
+ "node",
10
+ "promise",
11
+ "vitest"
12
+ ],
13
+ "rules": {
14
+ "no-this-alias": 0,
15
+ "no-async-promise-executor": 0,
16
+ "no-standalone-expect": 0,
17
+ "no-conditional-expect": 0,
18
+ "expect-expect": 0,
19
+ "no-disabled-tests": 0,
20
+ "valid-expect": 0,
21
+ "valid-title": 0,
22
+ "valid-describe-callback": 0,
23
+ "no-useless-call": 2,
24
+ "no-accumulating-spread": 2,
25
+ "prefer-array-find": 2,
26
+ "prefer-array-flat-map": 2,
27
+ "prefer-set-has": 2,
28
+ "no-bitwise": 2,
29
+ "no-empty": [2, { "allowEmptyCatch": true }],
30
+ "no-regex-spaces": 2,
31
+ "no-restricted-globals": [2, "event", "__dirname", "__filename"],
32
+ "no-unused-expressions": 2,
33
+ "no-var": 2,
34
+ "unicode-bom": 2,
35
+ "import/extensions": [2, "always"],
36
+ "import/no-amd": 2,
37
+ "import/no-commonjs": 2,
38
+ "import/no-cycle": 2,
39
+ "import/no-default-export": 2,
40
+ "import/no-webpack-loader-syntax": 2,
41
+ "oxc/bad-bitwise-operator": 2,
42
+ "oxc/no-const-enum": 2,
43
+ "promise/spec-only": 2,
44
+ "typescript/explicit-function-return-type": [2, { "allowExpressions": true }],
45
+ // "typescript/explicit-module-boundary-types": [2, {"allowArgumentsExplicitlyTypedAsAny": true}]
46
+ "typescript/no-empty-object-type": [2, { "allowInterfaces": "always" }],
47
+ "typescript/no-import-type-side-effects": 2,
48
+ // "typescript/no-namespace": 2,
49
+ "typescript/no-non-null-asserted-nullish-coalescing": 2,
50
+ "typescript/no-require-imports": 2,
51
+ "typescript/no-var-requires": 2,
52
+ "typescript/non-nullable-type-assertion-style": 2,
53
+ "typescript/prefer-literal-enum-member": 2,
54
+ "typescript/promise-function-async": [
55
+ 2,
56
+ {
57
+ "checkArrowFunctions": false,
58
+ "checkFunctionDeclarations": true,
59
+ "checkFunctionExpressions": true,
60
+ "checkMethodDeclarations": true
61
+ }
62
+ ],
63
+ "unicorn/no-anonymous-default-export": 2,
64
+ "unicorn/no-array-reduce": [
65
+ 2,
66
+ {
67
+ "allowSimpleOperations": true
68
+ }
69
+ ],
70
+ "unicorn/no-document-cookie": 2,
71
+ "unicorn/no-length-as-slice-end": 2,
72
+ "unicorn/no-magic-array-flat-depth": 2,
73
+ "unicorn/prefer-modern-math-apis": 2,
74
+ "unicorn/prefer-node-protocol": 2,
75
+ "vue/no-multiple-slot-args": 2
76
+ },
77
+ "settings": {
78
+ "jsdoc": {
79
+ "tagNamePreference": {
80
+ "experimental": "experimental"
81
+ }
82
+ }
83
+ }
84
+ }
@@ -5,7 +5,7 @@ import { _assert } from '@naturalcycles/js-lib/error/assert.js';
5
5
  import { fs2 } from '@naturalcycles/nodejs-lib/fs2';
6
6
  import { runScript } from '@naturalcycles/nodejs-lib/runScript';
7
7
  import { buildCopy, buildProd, runTSCInFolders } from '../build.util.js';
8
- import { eslintAll, lintAllCommand, lintStagedCommand, runBiome, runCommitlintCommand, runPrettier, stylelintAll, } from '../lint.util.js';
8
+ import { eslintAll, lintAllCommand, lintStagedCommand, runBiome, runCommitlintCommand, runOxlint, runPrettier, stylelintAll, } from '../lint.util.js';
9
9
  import { runTest } from '../test.util.js';
10
10
  const commands = [
11
11
  new Separator(), // build
@@ -65,13 +65,21 @@ const commands = [
65
65
  desc: 'Run "lint-staged", which runs linter on git staged files.',
66
66
  },
67
67
  { name: 'eslint', fn: eslintAll, desc: 'Run eslint on all files.' },
68
- { name: 'eslint-no-fix', deprecated: true, fn: async () => await eslintAll({ fix: false }) },
68
+ { name: 'eslint-no-fix', deprecated: true, fn: () => eslintAll({ fix: false }) },
69
69
  {
70
70
  name: 'eslint --no-fix',
71
- fn: async () => await eslintAll({ fix: false }),
71
+ fn: () => eslintAll({ fix: false }),
72
72
  desc: 'Run eslint on all files with "auto-fix" disabled. Useful for debugging.',
73
73
  interactiveOnly: true,
74
74
  },
75
+ { name: 'oxlint', fn: runOxlint, desc: 'Run oxlint on all files.' },
76
+ { name: 'oxlint-no-fix', deprecated: true, fn: () => runOxlint(false) },
77
+ {
78
+ name: 'oxlint --no-fix',
79
+ fn: () => runOxlint(false),
80
+ desc: 'Run oxlint on all files with "auto-fix" disabled. Useful for debugging.',
81
+ interactiveOnly: true,
82
+ },
75
83
  {
76
84
  name: 'biome',
77
85
  fn: () => runBiome(),
@@ -10,7 +10,8 @@ interface EslintAllOptions {
10
10
  /**
11
11
  * Runs `eslint` command for all predefined paths (e.g /src, /scripts, etc).
12
12
  */
13
- export declare function eslintAll(opt?: EslintAllOptions): Promise<void>;
13
+ export declare function eslintAll(opt?: EslintAllOptions): void;
14
+ export declare function runOxlint(fix?: boolean): void;
14
15
  interface RunPrettierOptions {
15
16
  experimentalCli?: boolean;
16
17
  fix?: boolean;
package/dist/lint.util.js CHANGED
@@ -42,10 +42,11 @@ export async function lintAllCommand() {
42
42
  const fix = !CI;
43
43
  // Fast linters (that run in <1 second) go first
44
44
  runActionLint();
45
+ runOxlint(fix);
45
46
  runBiome(fix);
46
47
  // From this point we start the "slow" linters, with ESLint leading the way
47
48
  // We run eslint BEFORE Prettier, because eslint can delete e.g unused imports.
48
- await eslintAll({
49
+ eslintAll({
49
50
  fix,
50
51
  });
51
52
  if (existsSync(`node_modules/stylelint`) &&
@@ -78,7 +79,7 @@ export async function lintAllCommand() {
78
79
  /**
79
80
  * Runs `eslint` command for all predefined paths (e.g /src, /scripts, etc).
80
81
  */
81
- export async function eslintAll(opt) {
82
+ export function eslintAll(opt) {
82
83
  const { argv } = _yargs().options({
83
84
  ext: {
84
85
  type: 'string',
@@ -94,9 +95,9 @@ export async function eslintAll(opt) {
94
95
  ...opt,
95
96
  };
96
97
  const extensions = ext.split(',');
97
- await runESLint(extensions, fix);
98
+ runESLint(extensions, fix);
98
99
  }
99
- async function runESLint(extensions = eslintExtensions.split(','), fix = true) {
100
+ function runESLint(extensions = eslintExtensions.split(','), fix = true) {
100
101
  const eslintConfigPath = `eslint.config.js`;
101
102
  if (!existsSync(eslintConfigPath)) {
102
103
  // faster to bail-out like this
@@ -107,10 +108,10 @@ async function runESLint(extensions = eslintExtensions.split(','), fix = true) {
107
108
  const cacheLocation = `node_modules/.cache/eslint`;
108
109
  const cacheFound = existsSync(cacheLocation);
109
110
  console.log(dimGrey(`${check(cacheFound)}eslint cache found: ${cacheFound}`));
110
- await exec2.spawnAsync(eslintPath, {
111
+ exec2.spawn(eslintPath, {
111
112
  name: ['eslint', !fix && '--no-fix'].filter(Boolean).join(' '),
112
113
  args: [
113
- `--config`,
114
+ '--config',
114
115
  eslintConfigPath,
115
116
  `{src,scripts,e2e}/**/*.{${extensions.join(',')}}`,
116
117
  // `--parser-options=project:${tsconfigPath}`,
@@ -120,8 +121,8 @@ async function runESLint(extensions = eslintExtensions.split(','), fix = true) {
120
121
  '--cache',
121
122
  '--cache-location',
122
123
  cacheLocation,
123
- `--no-error-on-unmatched-pattern`,
124
- fix ? `--fix` : '--no-fix',
124
+ '--no-error-on-unmatched-pattern',
125
+ fix ? '--fix' : '--no-fix',
125
126
  ].filter(_isTruthy),
126
127
  shell: false,
127
128
  env: _filterFalsyValues({
@@ -130,6 +131,23 @@ async function runESLint(extensions = eslintExtensions.split(','), fix = true) {
130
131
  }),
131
132
  });
132
133
  }
134
+ export function runOxlint(fix = true) {
135
+ const oxlintConfigPath = `.oxlintrc.json`;
136
+ if (!existsSync(oxlintConfigPath)) {
137
+ return;
138
+ }
139
+ const oxlintPath = findPackageBinPath('oxlint', 'oxlint');
140
+ exec2.spawn(oxlintPath, {
141
+ name: ['oxlintPath', !fix && '--no-fix'].filter(Boolean).join(' '),
142
+ args: [
143
+ // '--report-unused-disable-directives',
144
+ '--max-warnings=1',
145
+ fix ? '--fix' : '--no-fix',
146
+ ].filter(_isTruthy),
147
+ logFinish: false,
148
+ shell: false,
149
+ });
150
+ }
133
151
  const prettierPaths = [
134
152
  // Everything inside these folders
135
153
  `./{${prettierDirs}}/**/*.{${prettierExtensionsAll}}`,
@@ -1,7 +1,7 @@
1
1
  import { AppError } from '@naturalcycles/js-lib/error/error.util.js';
2
2
  import { red } from '@naturalcycles/nodejs-lib/colors';
3
3
  import createMitm from 'mitm';
4
- const LOCAL_HOSTS = ['localhost', '127.0.0.1'];
4
+ const LOCAL_HOSTS = new Set(['localhost', '127.0.0.1']);
5
5
  const detectLeaks = process.argv.some(a => a.includes('detectLeaks'));
6
6
  let mitm;
7
7
  /**
@@ -17,7 +17,7 @@ export function testOffline(opt) {
17
17
  mitm = createMitm();
18
18
  mitm.on('connect', (socket, socketOptions) => {
19
19
  const { host } = socketOptions;
20
- if (!LOCAL_HOSTS.includes(host)) {
20
+ if (!LOCAL_HOSTS.has(host)) {
21
21
  process.stderr.write(red(`Network request forbidden by testOffline: ${host}\n`));
22
22
  opt?.onForbiddenRequest?.(host);
23
23
  throw new AppError(`Network request forbidden by testOffline: ${host}`, {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/dev-lib",
3
3
  "type": "module",
4
- "version": "20.0.10",
4
+ "version": "20.1.0",
5
5
  "dependencies": {
6
6
  "@biomejs/biome": "^2",
7
7
  "@commitlint/cli": "^20",
@@ -23,6 +23,7 @@
23
23
  "lint-staged": "^16",
24
24
  "micromatch": "^4",
25
25
  "mitm": "^1",
26
+ "oxlint": "^1",
26
27
  "prettier": "^3",
27
28
  "typescript-eslint": "^8",
28
29
  "vue-eslint-parser": "^10"
@@ -42,14 +43,15 @@
42
43
  }
43
44
  },
44
45
  "devDependencies": {
45
- "@types/node": "^24",
46
- "@types/mitm": "^1"
46
+ "@types/mitm": "^1",
47
+ "@types/node": "^24"
47
48
  },
48
49
  "exports": {
49
50
  "./cfg/": "./cfg/",
50
51
  "./cfg/biome.jsonc": "./cfg/biome.jsonc",
51
52
  "./cfg/commitlint.config.js": "./cfg/commitlint.config.js",
52
53
  "./cfg/eslint.config.js": "./cfg/eslint.config.js",
54
+ "./cfg/oxlint.config.json": "./cfg/oxlint.config.json",
53
55
  "./cfg/prettier.config.js": "./cfg/prettier.config.js",
54
56
  "./cfg/stylelint.config.js": "./cfg/stylelint.config.js",
55
57
  "./cfg/tsconfig.src.json": "./cfg/tsconfig.src.json",
@@ -93,8 +95,8 @@
93
95
  "scripts": {
94
96
  "tsx-debug": "tsx scripts/testScript.ts",
95
97
  "dev-lib": "tsx ./src/bin/dev-lib.ts",
96
- "bt": "tsx ./src/bin/dev-lib.ts bt && tsx scripts/eslintPrintConfig.script.ts",
97
- "check": "tsx ./src/bin/dev-lib.ts check && tsx scripts/eslintPrintConfig.script.ts",
98
+ "bt": "tsx ./src/bin/dev-lib.ts bt && tsx scripts/eslintPrintConfig.script.ts && tsx scripts/oxlintPrintConfig.script.ts",
99
+ "check": "tsx ./src/bin/dev-lib.ts check && tsx scripts/eslintPrintConfig.script.ts && tsx scripts/oxlintPrintConfig.script.ts",
98
100
  "typecheck": "tsx ./src/bin/dev-lib.ts typecheck",
99
101
  "clean": "tsx ./src/bin/dev-lib.ts clean",
100
102
  "build": "tsx ./src/bin/dev-lib.ts build",
@@ -103,10 +105,12 @@
103
105
  "test-leaks": "tsx ./src/bin/dev-lib.ts test-leaks",
104
106
  "test-integration": "tsx ./src/bin/dev-lib.ts test-integration",
105
107
  "test-manual": "tsx ./src/bin/dev-lib.ts test-manual",
106
- "lint": "tsx scripts/eslintPrintConfig.script.ts && tsx ./src/bin/dev-lib.ts lint",
108
+ "lint": "tsx scripts/eslintPrintConfig.script.ts && tsx scripts/oxlintPrintConfig.script.ts && tsx ./src/bin/dev-lib.ts lint",
107
109
  "eslint": "tsx ./src/bin/dev-lib.ts eslint",
108
110
  "eslint-no-fix": "tsx ./src/bin/dev-lib.ts eslint-no-fix",
109
111
  "biome-no-fix": "tsx ./src/bin/dev-lib.ts biome-no-fix",
112
+ "oxlint": "tsx ./src/bin/dev-lib.ts oxlint",
113
+ "oxlint-no-fix": "tsx ./src/bin/dev-lib.ts oxlint-no-fix",
110
114
  "lint-staged-debug": "tsx ./src/bin/dev-lib.ts lint-staged"
111
115
  }
112
116
  }