@naturalcycles/dev-lib 19.29.0 → 19.31.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.
@@ -1,5 +1,5 @@
1
1
  import { existsSync } from 'node:fs';
2
- import { grey } from '@naturalcycles/nodejs-lib/colors';
2
+ import { dimGrey } from '@naturalcycles/nodejs-lib/colors';
3
3
  import { exec2 } from '@naturalcycles/nodejs-lib/exec2';
4
4
  import { fs2 } from '@naturalcycles/nodejs-lib/fs2';
5
5
  import { kpySync } from '@naturalcycles/nodejs-lib/kpy';
@@ -38,7 +38,7 @@ export async function runTSCInFolder(dir, args = []) {
38
38
  const tscPath = findPackageBinPath('typescript', 'tsc');
39
39
  const cacheLocation = `node_modules/.cache/${dir}.tsbuildinfo`;
40
40
  const cacheFound = existsSync(cacheLocation);
41
- console.log(grey(`tsc ${dir} cache found: ${cacheFound}`));
41
+ console.log(dimGrey(`${check(cacheFound)} tsc ${dir} cache found: ${cacheFound}`));
42
42
  await exec2.spawnAsync(tscPath, {
43
43
  args: ['-P', tsconfigPath, ...args],
44
44
  shell: false,
@@ -49,7 +49,7 @@ export async function runTSCProd(args = []) {
49
49
  const tscPath = findPackageBinPath('typescript', 'tsc');
50
50
  const cacheLocation = `node_modules/.cache/src.tsbuildinfo`;
51
51
  const cacheFound = existsSync(cacheLocation);
52
- console.log(grey(`tsc src cache found: ${cacheFound}`));
52
+ console.log(dimGrey(` tsc src cache found: ${cacheFound}`));
53
53
  await exec2.spawnAsync(tscPath, {
54
54
  args: ['-P', tsconfigPath, '--noEmit', 'false', '--noCheck', ...args],
55
55
  shell: false,
@@ -73,3 +73,6 @@ export function buildCopy() {
73
73
  dotfiles: true,
74
74
  });
75
75
  }
76
+ function check(predicate) {
77
+ return predicate ? '✔️ ' : ' ';
78
+ }
@@ -11,8 +11,12 @@ interface EslintAllOptions {
11
11
  * Runs `eslint` command for all predefined paths (e.g /src, /scripts, etc).
12
12
  */
13
13
  export declare function eslintAll(opt?: EslintAllOptions): Promise<void>;
14
- export declare function runPrettier(experimentalCli?: boolean): void;
15
- export declare function stylelintAll(): void;
14
+ interface RunPrettierOptions {
15
+ experimentalCli?: boolean;
16
+ fix?: boolean;
17
+ }
18
+ export declare function runPrettier(opt?: RunPrettierOptions): void;
19
+ export declare function stylelintAll(fix?: boolean): void;
16
20
  export declare function lintStagedCommand(): Promise<void>;
17
21
  export declare function runCommitlintCommand(): void;
18
22
  export declare function requireActionlintVersion(): void;
package/dist/lint.util.js CHANGED
@@ -7,9 +7,8 @@ import { _since } from '@naturalcycles/js-lib/datetime/time.util.js';
7
7
  import { _assert } from '@naturalcycles/js-lib/error/assert.js';
8
8
  import { _filterFalsyValues } from '@naturalcycles/js-lib/object/object.util.js';
9
9
  import { semver2 } from '@naturalcycles/js-lib/semver';
10
- import { _truncate } from '@naturalcycles/js-lib/string/string.util.js';
11
10
  import { git2 } from '@naturalcycles/nodejs-lib';
12
- import { boldGrey, dimGrey, grey } from '@naturalcycles/nodejs-lib/colors';
11
+ import { boldGrey, dimGrey } from '@naturalcycles/nodejs-lib/colors';
13
12
  import { exec2 } from '@naturalcycles/nodejs-lib/exec2';
14
13
  import { fs2 } from '@naturalcycles/nodejs-lib/fs2';
15
14
  import { _yargs } from '@naturalcycles/nodejs-lib/yargs';
@@ -21,52 +20,60 @@ const { CI, ESLINT_CONCURRENCY } = process.env;
21
20
  */
22
21
  export async function lintAllCommand() {
23
22
  const started = Date.now();
24
- const { commitOnChanges, failOnChanges } = _yargs().options({
25
- commitOnChanges: {
26
- type: 'boolean',
27
- default: false,
28
- },
29
- failOnChanges: {
30
- type: 'boolean',
31
- default: false,
32
- },
33
- }).argv;
34
- const needToTrackChanges = commitOnChanges || failOnChanges;
35
- const gitStatusAtStart = gitStatus();
36
- if (needToTrackChanges && gitStatusAtStart) {
37
- console.log('lint-all: git shows changes before run:');
38
- console.log(gitStatusAtStart);
39
- }
23
+ // const { commitOnChanges, failOnChanges } = _yargs().options({
24
+ // commitOnChanges: {
25
+ // type: 'boolean',
26
+ // default: false,
27
+ // },
28
+ // failOnChanges: {
29
+ // type: 'boolean',
30
+ // default: false,
31
+ // },
32
+ // }).argv
33
+ // const needToTrackChanges = commitOnChanges || failOnChanges
34
+ // const gitStatusAtStart = gitStatus()
35
+ // if (needToTrackChanges && gitStatusAtStart) {
36
+ // console.log('lint-all: git shows changes before run:')
37
+ // console.log(gitStatusAtStart)
38
+ // }
39
+ // In CI, Github Actions doesn't allow us to push and then run CI on changes again
40
+ // (known limitation / "infinite run loop" prevention)
41
+ // That's why we run in "no-fix" mode in CI, and "fix" mode locally
42
+ const fix = !CI;
40
43
  // Fast linters (that run in <1 second) go first
41
44
  runActionLint();
42
- runBiome();
45
+ runBiome(fix);
43
46
  // From this point we start the "slow" linters, with ESLint leading the way
44
47
  // We run eslint BEFORE Prettier, because eslint can delete e.g unused imports.
45
- await eslintAll();
48
+ await eslintAll({
49
+ fix,
50
+ });
46
51
  if (existsSync(`node_modules/stylelint`) &&
47
52
  existsSync(`node_modules/stylelint-config-standard-scss`)) {
48
- stylelintAll();
49
- }
50
- runPrettier();
51
- await runKTLint();
52
- console.log(`${boldGrey('lint-all')} ${dimGrey(`took ` + _since(started))}`);
53
- if (needToTrackChanges) {
54
- const gitStatusAfter = gitStatus();
55
- const hasChanges = gitStatusAfter !== gitStatusAtStart;
56
- if (!hasChanges)
57
- return;
58
- const msg = 'style(ci): ' + _truncate(git2.commitMessageToTitleMessage(git2.getLastGitCommitMsg()), 60);
59
- // pull, commit, push changes
60
- git2.pull();
61
- git2.commitAll(msg);
62
- git2.push();
63
- // fail on changes
64
- if (failOnChanges) {
65
- console.log(gitStatusAfter);
66
- console.log('lint-all failOnChanges: exiting with status 1');
67
- process.exitCode = 1;
68
- }
53
+ stylelintAll(fix);
69
54
  }
55
+ runPrettier({ fix });
56
+ await runKTLint(fix);
57
+ console.log(`${boldGrey(`${check(true)} lint-all`)} ${dimGrey(`took ` + _since(started))}`);
58
+ // if (needToTrackChanges) {
59
+ // const gitStatusAfter = gitStatus()
60
+ // const hasChanges = gitStatusAfter !== gitStatusAtStart
61
+ // if (!hasChanges) return
62
+ // const msg =
63
+ // 'style(ci): ' + _truncate(git2.commitMessageToTitleMessage(git2.getLastGitCommitMsg()), 60)
64
+ //
65
+ // // pull, commit, push changes
66
+ // git2.pull()
67
+ // git2.commitAll(msg)
68
+ // git2.push()
69
+ //
70
+ // // fail on changes
71
+ // if (failOnChanges) {
72
+ // console.log(gitStatusAfter)
73
+ // console.log('lint-all failOnChanges: exiting with status 1')
74
+ // process.exitCode = 1
75
+ // }
76
+ // }
70
77
  }
71
78
  /**
72
79
  * Runs `eslint` command for all predefined paths (e.g /src, /scripts, etc).
@@ -80,7 +87,7 @@ export async function eslintAll(opt) {
80
87
  },
81
88
  fix: {
82
89
  type: 'boolean',
83
- default: true,
90
+ default: !CI, // defaults to false in CI, true otherwise
84
91
  },
85
92
  });
86
93
  const { ext, fix } = {
@@ -88,26 +95,22 @@ export async function eslintAll(opt) {
88
95
  ...opt,
89
96
  };
90
97
  const extensions = ext.split(',');
91
- if (fix) {
98
+ // The only time we don't parallelize is when run locally with no-fix,
99
+ // so errors can be seen properly
100
+ const runInParallel = fix || !!CI;
101
+ if (runInParallel) {
92
102
  await Promise.all([
93
- // /src
94
103
  runESLint(`src`, extensions, fix),
95
- // /scripts
96
104
  runESLint(`scripts`, extensions, fix),
97
- // /e2e
98
105
  runESLint(`e2e`, extensions, fix),
99
106
  ]);
100
107
  }
101
108
  else {
102
- // with no-fix - let's run serially
103
- // /src
104
109
  await runESLint(`src`, extensions, fix);
105
- // /scripts
106
110
  await runESLint(`scripts`, extensions, fix);
107
- // /e2e
108
111
  await runESLint(`e2e`, extensions, fix);
109
112
  }
110
- console.log(`${boldGrey('eslint-all')} ${dimGrey(`took ` + _since(started))}`);
113
+ console.log(`${boldGrey(`${check(true)} eslint-all`)} ${dimGrey(`took ` + _since(started))}`);
111
114
  }
112
115
  async function runESLint(dir, extensions = eslintExtensions.split(','), fix = true) {
113
116
  let configDir = dir;
@@ -123,8 +126,9 @@ async function runESLint(dir, extensions = eslintExtensions.split(','), fix = tr
123
126
  const eslintPath = findPackageBinPath('eslint', 'eslint');
124
127
  const cacheLocation = `node_modules/.cache/eslint_${dir}`;
125
128
  const cacheFound = existsSync(cacheLocation);
126
- console.log(grey(`eslint ${dir} cache found: ${cacheFound}`));
129
+ console.log(dimGrey(`${check(cacheFound)} eslint ${dir} cache found: ${cacheFound}`));
127
130
  await exec2.spawnAsync(eslintPath, {
131
+ name: ['eslint', dir, !fix && '--no-fix'].filter(Boolean).join(' '),
128
132
  args: [
129
133
  `--config`,
130
134
  eslintConfigPath,
@@ -138,7 +142,7 @@ async function runESLint(dir, extensions = eslintExtensions.split(','), fix = tr
138
142
  cacheLocation,
139
143
  `--no-error-on-unmatched-pattern`,
140
144
  `--report-unused-disable-directives`, // todo: unnecessary with flat, as it's defined in the config
141
- fix ? `--fix` : '',
145
+ fix ? `--fix` : '--no-fix',
142
146
  ].filter(_isTruthy),
143
147
  shell: false,
144
148
  env: _filterFalsyValues({
@@ -155,18 +159,20 @@ const prettierPaths = [
155
159
  // Exclude
156
160
  ...lintExclude.map((s) => `!${s}`),
157
161
  ];
158
- export function runPrettier(experimentalCli = true) {
162
+ export function runPrettier(opt = {}) {
163
+ const { experimentalCli = true, fix = true } = opt;
159
164
  const prettierConfigPath = [`./prettier.config.js`].find(f => existsSync(f));
160
165
  if (!prettierConfigPath)
161
166
  return;
162
167
  const prettierPath = findPackageBinPath('prettier', 'prettier');
163
168
  const cacheLocation = 'node_modules/.cache/prettier';
164
169
  const cacheFound = existsSync(cacheLocation);
165
- console.log(grey(`prettier cache found: ${cacheFound}`));
170
+ console.log(dimGrey(`${check(cacheFound)} prettier cache found: ${cacheFound}`));
166
171
  // prettier --write 'src/**/*.{js,ts,css,scss,graphql}'
167
172
  exec2.spawn(prettierPath, {
173
+ name: fix ? 'prettier' : 'prettier --check',
168
174
  args: [
169
- `--write`,
175
+ fix ? `--write` : '--check',
170
176
  `--log-level=warn`,
171
177
  '--cache-location',
172
178
  cacheLocation,
@@ -184,18 +190,20 @@ const stylelintPaths = [
184
190
  // Exclude
185
191
  ...lintExclude.map((s) => `!${s}`),
186
192
  ];
187
- export function stylelintAll() {
188
- const { fix } = _yargs().options({
193
+ export function stylelintAll(fix) {
194
+ const argv = _yargs().options({
189
195
  fix: {
190
196
  type: 'boolean',
191
- default: true,
197
+ default: !CI, // defaults to false in CI, true otherwise
192
198
  },
193
199
  }).argv;
200
+ fix ??= argv.fix;
194
201
  const config = [`./stylelint.config.js`].find(f => existsSync(f));
195
202
  if (!config)
196
203
  return;
197
204
  // stylelint is never hoisted from dev-lib, so, no need to search for its path
198
205
  exec2.spawn('stylelint', {
206
+ name: fix ? 'stylelint' : 'stylelint --no-fix',
199
207
  args: [fix ? `--fix` : '', `--allow-empty-input`, `--config`, config, ...stylelintPaths].filter(Boolean),
200
208
  shell: false,
201
209
  });
@@ -229,12 +237,12 @@ export function runCommitlintCommand() {
229
237
  log: false,
230
238
  });
231
239
  }
232
- async function runKTLint() {
240
+ async function runKTLint(fix = true) {
233
241
  if (!existsSync(`node_modules/@naturalcycles/ktlint`))
234
242
  return;
235
243
  // @ts-expect-error ktlint is not installed (due to size in node_modules), but it's ok
236
244
  const { ktlintAll } = await import('@naturalcycles/ktlint');
237
- await ktlintAll();
245
+ await ktlintAll(fix ? ['-F'] : []);
238
246
  }
239
247
  function runActionLint() {
240
248
  // Only run if there is a folder of `.github/workflows`, otherwise actionlint will fail
@@ -261,12 +269,6 @@ export function getActionLintVersion() {
261
269
  return exec2.exec('actionlint --version').split('\n')[0];
262
270
  }
263
271
  export function runBiome(fix = true) {
264
- // if (!fs.existsSync(`node_modules/@biomejs/biome`)) {
265
- // if (verbose) {
266
- // console.log(`biome is not installed (checked in node_modules/@biomejs/biome), skipping`)
267
- // }
268
- // return
269
- // }
270
272
  const configPath = `biome.jsonc`;
271
273
  if (!existsSync(configPath)) {
272
274
  console.log(`biome is skipped, because ./biome.jsonc is not present`);
@@ -275,6 +277,7 @@ export function runBiome(fix = true) {
275
277
  const biomePath = findPackageBinPath('@biomejs/biome', 'biome');
276
278
  const dirs = [`src`, `scripts`, `e2e`].filter(d => existsSync(d));
277
279
  exec2.spawn(biomePath, {
280
+ name: fix ? 'biome' : 'biome --no-fix',
278
281
  args: [`lint`, fix && '--write', fix && '--unsafe', '--no-errors-on-unmatched', ...dirs].filter(_isTruthy),
279
282
  logFinish: false,
280
283
  shell: false,
@@ -289,17 +292,19 @@ function canRunBinary(name) {
289
292
  return false;
290
293
  }
291
294
  }
292
- function gitStatus() {
293
- try {
294
- return execSync('git status -s', {
295
- encoding: 'utf8',
296
- });
297
- }
298
- catch { }
299
- }
295
+ // function gitStatus(): string | undefined {
296
+ // try {
297
+ // return execSync('git status -s', {
298
+ // encoding: 'utf8',
299
+ // })
300
+ // } catch {}
301
+ // }
300
302
  const require = createRequire(import.meta.url);
301
303
  export function findPackageBinPath(pkg, cmd) {
302
304
  const packageJsonPath = require.resolve(`${pkg}/package.json`);
303
305
  const { bin } = fs2.readJson(packageJsonPath);
304
306
  return path.join(path.dirname(packageJsonPath), typeof bin === 'string' ? bin : bin[cmd]);
305
307
  }
308
+ function check(predicate) {
309
+ return predicate ? '✔️ ' : ' ';
310
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/dev-lib",
3
3
  "type": "module",
4
- "version": "19.29.0",
4
+ "version": "19.31.0",
5
5
  "dependencies": {
6
6
  "@biomejs/biome": "^2",
7
7
  "@commitlint/cli": "^19",