@naturalcycles/dev-lib 15.5.0 → 15.7.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.
@@ -0,0 +1,77 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
3
+ "files": {
4
+ "ignore": ["**/__exclude", "*.compact.json"]
5
+ },
6
+ "formatter": {
7
+ "enabled": true,
8
+ "formatWithErrors": false,
9
+ "indentStyle": "space",
10
+ "indentWidth": 2,
11
+ "lineEnding": "lf",
12
+ "lineWidth": 100,
13
+ "attributePosition": "auto"
14
+ },
15
+ "organizeImports": { "enabled": true },
16
+ "linter": {
17
+ "enabled": true,
18
+ "rules": {
19
+ "recommended": true,
20
+ "performance": {
21
+ "noDelete": "off" // todo
22
+ },
23
+ "correctness": {
24
+ // noUnusedImports + noUnusedVariables can replace eslint-plugin-unused-vars!
25
+ "noUnusedImports": "error",
26
+ "noUnusedVariables": "error",
27
+ "useArrayLiterals": "error"
28
+ },
29
+ "style": {
30
+ "useShorthandFunctionType": "error",
31
+ "useShorthandAssign": "error",
32
+ "useForOf": "error",
33
+ "useConsistentArrayType": "error",
34
+ "useShorthandArrayType": "error",
35
+ "noDefaultExport": "error",
36
+ "noCommaOperator": "error",
37
+ "noArguments": "error",
38
+ "noNonNullAssertion": "off",
39
+ "useImportType": "off",
40
+ "noParameterAssign": "off",
41
+ "useTemplate": "off",
42
+ "useNumberNamespace": "off",
43
+ "noUnusedTemplateLiteral": "off"
44
+ },
45
+ "suspicious": {
46
+ "noExplicitAny": "off",
47
+ "noAssignInExpressions": "off",
48
+ "noAsyncPromiseExecutor": "off",
49
+ "noPrototypeBuiltins": "off",
50
+ "noGlobalIsNan": "off", // todo,
51
+ "noThenProperty": "off",
52
+ "noImportAssign": "off",
53
+ "noEmptyInterface": "off"
54
+ },
55
+ "complexity": {
56
+ "noForEach": "off",
57
+ "noUselessThisAlias": "off",
58
+ "useLiteralKeys": "off",
59
+ "noBannedTypes": "off"
60
+ }
61
+ }
62
+ },
63
+ "javascript": {
64
+ "formatter": {
65
+ "jsxQuoteStyle": "double",
66
+ "quoteProperties": "asNeeded",
67
+ "trailingCommas": "all",
68
+ "semicolons": "asNeeded",
69
+ "arrowParentheses": "asNeeded",
70
+ "bracketSpacing": true,
71
+ "bracketSameLine": false,
72
+ "quoteStyle": "single",
73
+ "attributePosition": "auto"
74
+ }
75
+ },
76
+ "overrides": [{ "include": ["tsconfig.json", "tsconfig.*.json"] }]
77
+ }
@@ -324,11 +324,12 @@ module.exports = {
324
324
  argsIgnorePattern: '^_',
325
325
  },
326
326
  ],
327
- 'unused-imports/no-unused-imports': 2,
328
- 'unused-imports/no-unused-vars': [
329
- 2,
330
- { vars: 'all', varsIgnorePattern: '^_', args: 'after-used', argsIgnorePattern: '^_' },
331
- ],
327
+ // unused-imports/* rules are replaced by biome
328
+ // 'unused-imports/no-unused-imports': 2,
329
+ // 'unused-imports/no-unused-vars': [
330
+ // 2,
331
+ // { vars: 'all', varsIgnorePattern: '^_', args: 'after-used', argsIgnorePattern: '^_' },
332
+ // ],
332
333
  '@typescript-eslint/no-duplicate-enum-values': 2,
333
334
  '@typescript-eslint/no-redundant-type-constituents': 0, // `'a' | string` is still useful for DX
334
335
  '@typescript-eslint/no-empty-function': 0,
@@ -54,7 +54,7 @@ function getConfig() {
54
54
  plugins: {
55
55
  '@typescript-eslint': tseslint.plugin,
56
56
  'import-x': require('eslint-plugin-import-x'),
57
- 'unused-imports': require('eslint-plugin-unused-imports'),
57
+ // 'unused-imports': require('eslint-plugin-unused-imports'), // disabled in favor of biome rules
58
58
  'simple-import-sort': require('eslint-plugin-simple-import-sort'),
59
59
  jsdoc: require('eslint-plugin-jsdoc'),
60
60
  ...(hasJest ? { jest: require('eslint-plugin-jest') } : {}),
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
3
+ "extends": ["node_modules/@naturalcycles/dev-lib/cfg/biome.jsonc"]
4
+ }
@@ -34,6 +34,10 @@ const stylelintExists =
34
34
  fs.existsSync('node_modules/stylelint-config-standard-scss')
35
35
  const stylelintCmd = stylelintExists ? `stylelint --fix --config ${stylelintConfigPath}` : undefined
36
36
 
37
+ const biomeInstalled = fs.existsSync('node_modules/@biomejs/biome')
38
+ const biomeConfigPath = biomeInstalled && ['biome.jsonc'].find(p => fs.existsSync(p))
39
+ const biomeCmd = biomeConfigPath && `biome lint --write --unsafe --`
40
+
37
41
  if (!eslintConfigPathRoot) {
38
42
  console.log('eslint is skipped, because ./eslint.config.js is not present')
39
43
  }
@@ -47,11 +51,15 @@ if (!stylelintCmd) {
47
51
  }
48
52
 
49
53
  const linters = {
50
- // *.{ts,tsx,vue} files: eslint, prettier
54
+ // *.{ts,tsx,vue} files: biome, eslint, prettier
51
55
  './src/**/*.{ts,tsx,vue}': match => {
52
56
  const filesList = getFilesList(match)
53
57
  if (!filesList) return []
54
- return [eslintConfigPathRoot && `${eslintCmd} --config ${eslintConfigPathRoot}`, prettierCmd]
58
+ return [
59
+ biomeCmd,
60
+ eslintConfigPathRoot && `${eslintCmd} --config ${eslintConfigPathRoot}`,
61
+ prettierCmd,
62
+ ]
55
63
  .filter(Boolean)
56
64
  .map(s => `${s} ${filesList}`)
57
65
  },
@@ -74,20 +82,21 @@ const linters = {
74
82
  // prettierCmd].map(s => `${s} ${filesList}`)
75
83
  // },
76
84
 
77
- // Files for Stylelint + Prettier
85
+ // Files for Biome + Stylelint + Prettier
78
86
  [`./{${prettierDirs}}/**/*.{${stylelintExtensions}}`]: match => {
79
87
  const filesList = getFilesList(match)
80
88
  if (!filesList) return []
81
- return [stylelintCmd, prettierCmd].filter(Boolean).map(s => `${s} ${filesList}`)
89
+ return [biomeCmd, stylelintCmd, prettierCmd].filter(Boolean).map(s => `${s} ${filesList}`)
82
90
  },
83
91
 
84
- // Files in root dir
92
+ // Files in root dir: prettier
85
93
  [`./*.{${prettierExtensionsAll}}`]: match => {
86
94
  const filesList = getFilesList(match)
87
95
  if (!filesList || !prettierCmd) return []
88
96
  return [prettierCmd].map(s => `${s} ${filesList}`)
89
97
  },
90
98
 
99
+ // ktlint
91
100
  '**/*.{kt,kts}': match => {
92
101
  const filesList = getFilesList(match)
93
102
  if (!filesList) return []
@@ -122,11 +131,12 @@ if (fs.existsSync(`./scripts`)) {
122
131
  fs.existsSync(p),
123
132
  )
124
133
  Object.assign(linters, {
125
- // eslint, Prettier
134
+ // biome, eslint, Prettier
126
135
  './scripts/**/*.{ts,tsx}': match => {
127
136
  const filesList = getFilesList(match)
128
137
  if (!filesList) return []
129
138
  return [
139
+ biomeCmd,
130
140
  eslintConfigPathScripts &&
131
141
  `${eslintCmd} --config ${eslintConfigPathScripts} --parser-options=project:./scripts/tsconfig.json`,
132
142
  prettierCmd,
@@ -144,11 +154,12 @@ if (fs.existsSync(`./e2e`)) {
144
154
  )
145
155
 
146
156
  Object.assign(linters, {
147
- // eslint, Prettier
157
+ // biome, eslint, Prettier
148
158
  './e2e/**/*.{ts,tsx}': match => {
149
159
  const filesList = getFilesList(match)
150
160
  if (!filesList) return []
151
161
  return [
162
+ biomeCmd,
152
163
  eslintConfigPathE2e &&
153
164
  `${eslintCmd} --config ${eslintConfigPathE2e} --parser-options=project:./e2e/tsconfig.json`,
154
165
  prettierCmd,
@@ -166,11 +177,12 @@ if (fs.existsSync(`./playwright`)) {
166
177
  )
167
178
 
168
179
  Object.assign(linters, {
169
- // eslint, Prettier
180
+ // biome, eslint, Prettier
170
181
  './playwright/**/*.{ts,tsx}': match => {
171
182
  const filesList = getFilesList(match)
172
183
  if (!filesList) return []
173
184
  return [
185
+ biomeCmd,
174
186
  eslintConfigPathE2e &&
175
187
  `${eslintCmd} --config ${eslintConfigPathE2e} --parser-options=project:./playwright/tsconfig.json`,
176
188
  prettierCmd,
@@ -67,6 +67,17 @@ const commands = [
67
67
  desc: 'Run eslint on all files with "auto-fix" disabled. Useful for debugging.',
68
68
  interactiveOnly: true,
69
69
  },
70
+ {
71
+ name: 'biome',
72
+ fn: () => (0, lint_util_1.runBiome)(true),
73
+ desc: 'Run biome linter on all files.',
74
+ },
75
+ {
76
+ name: 'biome --no-fix',
77
+ fn: () => (0, lint_util_1.runBiome)(true, false),
78
+ desc: 'Run biome linter on all files with "auto-fix" disabled. Useful for debugging.',
79
+ interactiveOnly: true,
80
+ },
70
81
  { name: 'prettier', fn: lint_util_1.runPrettier, desc: 'Run prettier on all files.' },
71
82
  { name: 'stylelint', fn: lint_util_1.stylelintAll, desc: 'Run stylelint on all files.' },
72
83
  { name: 'commitlint', fn: lint_util_1.runCommitlintCommand, desc: 'Run commitlint.', cliOnly: true },
package/dist/index.d.ts CHANGED
@@ -1 +1 @@
1
- export {};
1
+ export type {};
@@ -14,4 +14,5 @@ export declare function runPrettier(): void;
14
14
  export declare function stylelintAll(): void;
15
15
  export declare function lintStagedCommand(): Promise<void>;
16
16
  export declare function runCommitlintCommand(): void;
17
+ export declare function runBiome(verbose?: boolean, fix?: boolean): void;
17
18
  export {};
package/dist/lint.util.js CHANGED
@@ -6,6 +6,7 @@ exports.runPrettier = runPrettier;
6
6
  exports.stylelintAll = stylelintAll;
7
7
  exports.lintStagedCommand = lintStagedCommand;
8
8
  exports.runCommitlintCommand = runCommitlintCommand;
9
+ exports.runBiome = runBiome;
9
10
  const tslib_1 = require("tslib");
10
11
  const node_child_process_1 = tslib_1.__importDefault(require("node:child_process"));
11
12
  const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
@@ -35,6 +36,10 @@ async function lintAllCommand() {
35
36
  console.log('lint-all: git shows changes before run:');
36
37
  console.log(gitStatusAtStart);
37
38
  }
39
+ // Fast linters (that run in <1 second) go first
40
+ runActionLint();
41
+ runBiome();
42
+ // From this point we start the "slow" linters, with ESLint leading the way
38
43
  // We run eslint BEFORE Prettier, because eslint can delete e.g unused imports.
39
44
  await eslintAll();
40
45
  if (node_fs_1.default.existsSync(`node_modules/stylelint`) &&
@@ -42,7 +47,6 @@ async function lintAllCommand() {
42
47
  stylelintAll();
43
48
  }
44
49
  runPrettier();
45
- runActionLint();
46
50
  await runKTLint();
47
51
  console.log(`${(0, nodejs_lib_1.boldGrey)('lint-all')} ${(0, nodejs_lib_1.dimGrey)(`took ` + (0, js_lib_1._since)(started))}`);
48
52
  if (needToTrackChanges) {
@@ -181,7 +185,8 @@ async function lintStagedCommand() {
181
185
  // const lintStaged = require('lint-staged')
182
186
  // lint-staged is ESM since 12.0
183
187
  // const lintStaged = await import('lint-staged')
184
- // eslint-disable-next-line no-eval
188
+ /* eslint-disable no-eval */
189
+ // biome-ignore lint/security/noGlobalEval: ok
185
190
  const { default: lintStaged } = await eval(`import('lint-staged')`);
186
191
  const success = await lintStaged({
187
192
  configPath: config,
@@ -206,10 +211,10 @@ function runCommitlintCommand() {
206
211
  });
207
212
  }
208
213
  async function runKTLint() {
209
- if (node_fs_1.default.existsSync(`node_modules/@naturalcycles/ktlint`)) {
210
- const ktlintLib = require('@naturalcycles/ktlint');
211
- await ktlintLib.ktlintAll();
212
- }
214
+ if (!node_fs_1.default.existsSync(`node_modules/@naturalcycles/ktlint`))
215
+ return;
216
+ const ktlintLib = require('@naturalcycles/ktlint');
217
+ await ktlintLib.ktlintAll();
213
218
  }
214
219
  function runActionLint() {
215
220
  // Only run if there is a folder of `.github/workflows`, otherwise actionlint will fail
@@ -224,6 +229,22 @@ function runActionLint() {
224
229
  console.log(`actionlint is not installed and won't be run.\nThis is how to install it: https://github.com/rhysd/actionlint/blob/main/docs/install.md`);
225
230
  }
226
231
  }
232
+ function runBiome(verbose = false, fix = true) {
233
+ if (!node_fs_1.default.existsSync(`node_modules/@biomejs/biome`)) {
234
+ if (verbose) {
235
+ console.log(`biome is not installed (checked in node_modules/@biomejs/biome), skipping`);
236
+ }
237
+ return;
238
+ }
239
+ const configPath = `biome.jsonc`;
240
+ if (!node_fs_1.default.existsSync(configPath)) {
241
+ if (verbose)
242
+ console.log(`biome is installed, but biome.jsonc config file is missing`);
243
+ return;
244
+ }
245
+ const dirs = [`src`, `scripts`, `e2e`, `playwright`].filter(d => node_fs_1.default.existsSync(d));
246
+ (0, nodejs_lib_1.execVoidCommandSync)(`biome`, [`lint`, fix && '--write', fix && '--unsafe', ...dirs].filter(js_lib_1._isTruthy));
247
+ }
227
248
  function canRunBinary(name) {
228
249
  try {
229
250
  execSync(`which ${name}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/dev-lib",
3
- "version": "15.5.0",
3
+ "version": "15.7.0",
4
4
  "scripts": {
5
5
  "prepare": "husky",
6
6
  "tsn-debug": "tsn testScript.ts",
@@ -34,7 +34,6 @@
34
34
  "eslint-plugin-jsdoc": "^50.0.0",
35
35
  "eslint-plugin-simple-import-sort": "^12.1.1",
36
36
  "eslint-plugin-unicorn": "^55.0.0",
37
- "eslint-plugin-unused-imports": "4.0.1",
38
37
  "eslint-plugin-vue": "^9.0.0",
39
38
  "expect-type": "^0.19.0",
40
39
  "globals": "^15.8.0",
@@ -51,6 +50,7 @@
51
50
  "yargs": "^17.0.0"
52
51
  },
53
52
  "devDependencies": {
53
+ "@biomejs/biome": "^1.8.3",
54
54
  "jest": "^29.0.0",
55
55
  "stylelint": "^16.0.2",
56
56
  "stylelint-config-standard-scss": "^13.0.0"
package/readme.md CHANGED
@@ -11,6 +11,17 @@
11
11
  [![Known Vulnerabilities](https://snyk.io/package/npm/snyk/badge.svg)](https://snyk.io/package/npm/@naturalcycles/dev-lib)
12
12
  [![Actions](https://github.com/NaturalCycles/dev-lib/workflows/default/badge.svg)](https://github.com/NaturalCycles/dev-lib/actions)
13
13
 
14
+ ## Tools that dev-lib enables
15
+
16
+ - Prettier
17
+ - ESLint
18
+ - Biome
19
+ - Stylelint
20
+ - Jest
21
+ - ktlint
22
+ - actionlint
23
+ - lint-staged
24
+
14
25
  ## How to use
15
26
 
16
27
  Install it:
@@ -20,7 +31,7 @@ Install it:
20
31
  This unlocks all commands listed below, e.g:
21
32
 
22
33
  yarn dev-lib test
23
- yarn dev-lib lint-all
34
+ yarn dev-lib lint
24
35
 
25
36
  `yarn dev-lib` runs "interactive mode" that lets you explore available commands.
26
37
 
@@ -143,12 +154,13 @@ If you need to execute shards **in parallel**, you can follow e.g
143
154
 
144
155
  #### Lint commands
145
156
 
146
- - `lint`: runs ESLint, Stylelint, Prettier, actionlint, ktlint in the right order.
157
+ - `lint`: runs Biome, ESLint, Stylelint, Prettier, actionlint, ktlint in the right order.
147
158
 
148
159
  - `--commitOnChanges` will commit lint-modified changes and push them
149
160
  - `--failOnChanges` will exit with status 1 in the end (will fail the command)
150
161
 
151
162
  - `eslint`: runs `eslint` on needed paths
163
+ - `biome`: runs `biome` on needed paths
152
164
  - `stylelint`: runs `stylelint` on needed paths
153
165
  - `prettier`: runs just Prettier on needed paths
154
166
 
@@ -163,6 +175,12 @@ For Stylelint to be run, you need to manually install it in the target project:
163
175
 
164
176
  `yarn add -D stylelint stylelint-config-standard-scss`
165
177
 
178
+ For Biome to run you need to install it like this:
179
+
180
+ `yarn add -D @biomejs/biome`
181
+
182
+ and add `biome.jsonc` config to the root.
183
+
166
184
  ##### ktlint
167
185
 
168
186
  `ktlint` will be used by lint-staged for all `**/*.{kt,kts}` files.
@@ -198,6 +216,7 @@ These files are meant to be extended in target project, so act as _recommended d
198
216
  - `lint-staged.config.js`
199
217
  - `prettier.config.js`
200
218
  - `eslint.config.js`
219
+ - `biome.jsonc`
201
220
  - `jest.config.js`
202
221
 
203
222
  ## eslint