@naturalcycles/dev-lib 20.23.0 → 20.24.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.
@@ -3,12 +3,10 @@ import { _by } from '@naturalcycles/js-lib/array/array.util.js';
3
3
  import { _assert } from '@naturalcycles/js-lib/error/assert.js';
4
4
  import { fs2 } from '@naturalcycles/nodejs-lib/fs2';
5
5
  import { runScript } from '@naturalcycles/nodejs-lib/runScript';
6
- import { buildCopy, buildProd, runTSCInFolders } from '../build.util.js';
6
+ import { buildCopy, buildProd, eslintAll, lintStagedCommand, requireOxlintConfig, runBiome, runCheck, runOxlint, runPrettier, runTest, stylelintAll, typecheckWithTSC, } from '../check.util.js';
7
7
  import { runCommitlint } from '../commitlint.js';
8
- import { eslintAll, lintAllCommand, lintStagedCommand, requireOxlintConfig, runBiome, runOxlint, runPrettier, stylelintAll, } from '../lint.util.js';
9
- import { runTest } from '../test.util.js';
10
8
  const commands = [
11
- { name: 'check', fn: check, desc: '"Run all possible checks": lint, typecheck, then test.' },
9
+ { name: 'check', fn: runCheck, desc: '"Run all possible checks": lint, typecheck, then test.' },
12
10
  {
13
11
  name: 'quick-check',
14
12
  fn: quickCheck,
@@ -64,7 +62,10 @@ const commands = [
64
62
  },
65
63
  {
66
64
  name: 'lint',
67
- fn: lintAllCommand,
65
+ fn: () => runCheck({
66
+ typecheckWithTSC: false,
67
+ test: false,
68
+ }),
68
69
  desc: 'Run all linters: eslint, prettier, stylelint, ktlint, actionlint.',
69
70
  },
70
71
  {
@@ -156,14 +157,13 @@ runScript(async () => {
156
157
  }
157
158
  await commandMap[cmd].fn();
158
159
  });
159
- async function check() {
160
- await lintAllCommand();
161
- await typecheckWithTSC(); // unfortunately still needed since oxlint doesn't catch all ts errors
162
- runTest();
163
- }
164
160
  async function quickCheck() {
165
- await lintAllCommand(false);
166
- runTest();
161
+ await runCheck({
162
+ eslint: false,
163
+ prettier: false,
164
+ stylelint: false,
165
+ typecheckWithTSC: false,
166
+ });
167
167
  }
168
168
  async function bt() {
169
169
  // Still using tsc, as oxlint is found to fail in certain cases
@@ -177,10 +177,6 @@ async function _typecheckWithOxlint() {
177
177
  const fix = !CI;
178
178
  runOxlint(fix);
179
179
  }
180
- async function typecheckWithTSC() {
181
- // todo: try tsgo
182
- await runTSCInFolders(['src', 'scripts', 'e2e'], ['--noEmit']);
183
- }
184
180
  async function cleanDist() {
185
181
  fs2.emptyDir('./dist'); // it doesn't delete the dir itself, to prevent IDE jumping
186
182
  }
@@ -1,10 +1,23 @@
1
1
  import type { SemVerString } from '@naturalcycles/js-lib/types';
2
+ /**
3
+ * Every boolean defaults to true, so, by default - everything is being run.
4
+ * Pass false to skip it.
5
+ */
6
+ export interface CheckOptions {
7
+ fastLinters?: boolean;
8
+ eslint?: boolean;
9
+ stylelint?: boolean;
10
+ prettier?: boolean;
11
+ ktlint?: boolean;
12
+ typecheckWithTSC?: boolean;
13
+ test?: boolean;
14
+ }
2
15
  /**
3
16
  * Run all linters.
4
17
  *
5
18
  * If full=false - the "slow" linters are skipped.
6
19
  */
7
- export declare function lintAllCommand(full?: boolean): Promise<void>;
20
+ export declare function runCheck(opt?: CheckOptions): Promise<void>;
8
21
  interface EslintAllOptions {
9
22
  ext?: string;
10
23
  fix?: boolean;
@@ -26,5 +39,19 @@ export declare function lintStagedCommand(): Promise<void>;
26
39
  export declare function requireActionlintVersion(): void;
27
40
  export declare function getActionLintVersion(): SemVerString | undefined;
28
41
  export declare function runBiome(fix?: boolean): void;
42
+ export declare function buildProd(): Promise<void>;
43
+ export declare function typecheckWithTSC(): Promise<void>;
44
+ /**
45
+ * Use 'src' to indicate root.
46
+ */
47
+ export declare function runTSCInFolders(dirs: string[], args?: string[], parallel?: boolean): Promise<void>;
48
+ export declare function runTSCProd(args?: string[]): Promise<void>;
49
+ export declare function buildCopy(): void;
50
+ interface RunTestOptions {
51
+ integration?: boolean;
52
+ manual?: boolean;
53
+ leaks?: boolean;
54
+ }
55
+ export declare function runTest(opt?: RunTestOptions): void;
29
56
  export declare function findPackageBinPath(pkg: string, cmd: string): string;
30
57
  export {};
@@ -3,6 +3,7 @@ import { existsSync } from 'node:fs';
3
3
  import { createRequire } from 'node:module';
4
4
  import path from 'node:path';
5
5
  import { _isTruthy } from '@naturalcycles/js-lib';
6
+ import { _uniq } from '@naturalcycles/js-lib/array';
6
7
  import { _since } from '@naturalcycles/js-lib/datetime/time.util.js';
7
8
  import { _assert } from '@naturalcycles/js-lib/error/assert.js';
8
9
  import { _filterFalsyValues } from '@naturalcycles/js-lib/object/object.util.js';
@@ -10,6 +11,7 @@ import { semver2 } from '@naturalcycles/js-lib/semver';
10
11
  import { dimGrey, white } from '@naturalcycles/nodejs-lib/colors';
11
12
  import { exec2 } from '@naturalcycles/nodejs-lib/exec2';
12
13
  import { fs2 } from '@naturalcycles/nodejs-lib/fs2';
14
+ import { kpySync } from '@naturalcycles/nodejs-lib/kpy';
13
15
  import { _yargs } from '@naturalcycles/nodejs-lib/yargs';
14
16
  import { eslintExtensions, lintExclude, minActionlintVersion, prettierDirs, prettierExtensionsAll, stylelintExtensions, } from '../cfg/_cnst.js';
15
17
  import { cfgDir } from './paths.js';
@@ -19,7 +21,8 @@ const { CI, ESLINT_CONCURRENCY } = process.env;
19
21
  *
20
22
  * If full=false - the "slow" linters are skipped.
21
23
  */
22
- export async function lintAllCommand(full = true) {
24
+ export async function runCheck(opt = {}) {
25
+ const { fastLinters = true, eslint = true, stylelint = true, prettier = true, ktlint = true, typecheckWithTSC: runTSC = true, test = true, } = opt;
23
26
  const started = Date.now();
24
27
  // const { commitOnChanges, failOnChanges } = _yargs().options({
25
28
  // commitOnChanges: {
@@ -41,24 +44,37 @@ export async function lintAllCommand(full = true) {
41
44
  // (known limitation / "infinite run loop" prevention)
42
45
  // That's why we run in "no-fix" mode in CI, and "fix" mode locally
43
46
  const fix = !CI;
44
- // Fast linters (that run in <1 second) go first
45
- runActionLint();
46
- runBiome(fix);
47
- runOxlint(fix);
47
+ if (fastLinters) {
48
+ // Fast linters (that run in <1 second) go first
49
+ runActionLint();
50
+ runBiome(fix);
51
+ runOxlint(fix);
52
+ }
48
53
  // From this point we start the "slow" linters, with ESLint leading the way
49
- if (full) {
54
+ if (eslint) {
50
55
  // We run eslint BEFORE Prettier, because eslint can delete e.g unused imports.
51
56
  eslintAll({
52
57
  fix,
53
58
  });
54
- if (existsSync(`node_modules/stylelint`) &&
55
- existsSync(`node_modules/stylelint-config-standard-scss`)) {
56
- stylelintAll(fix);
57
- }
59
+ }
60
+ if (stylelint &&
61
+ existsSync(`node_modules/stylelint`) &&
62
+ existsSync(`node_modules/stylelint-config-standard-scss`)) {
63
+ stylelintAll(fix);
64
+ }
65
+ if (prettier) {
58
66
  runPrettier({ fix });
67
+ }
68
+ if (ktlint) {
59
69
  await runKTLint(fix);
60
70
  }
61
- console.log(`${check(true)}${white(`lint-all`)} ${dimGrey(`took ` + _since(started))}`);
71
+ if (runTSC) {
72
+ await typecheckWithTSC();
73
+ }
74
+ if (test) {
75
+ runTest();
76
+ }
77
+ console.log(`${check(true)}${white(`check`)} ${dimGrey(`took ` + _since(started))}`);
62
78
  // if (needToTrackChanges) {
63
79
  // const gitStatusAfter = gitStatus()
64
80
  // const hasChanges = gitStatusAfter !== gitStatusAtStart
@@ -279,6 +295,113 @@ export function runBiome(fix = true) {
279
295
  shell: false,
280
296
  });
281
297
  }
298
+ export async function buildProd() {
299
+ // fs2.emptyDir('./dist') // it doesn't delete the dir itself, to prevent IDE jumping
300
+ buildCopy();
301
+ await runTSCProd();
302
+ }
303
+ export async function typecheckWithTSC() {
304
+ // todo: try tsgo
305
+ await runTSCInFolders(['src', 'scripts', 'e2e'], ['--noEmit']);
306
+ }
307
+ /**
308
+ * Use 'src' to indicate root.
309
+ */
310
+ export async function runTSCInFolders(dirs, args = [], parallel = true) {
311
+ if (parallel) {
312
+ await Promise.all(dirs.map(dir => runTSCInFolder(dir, args)));
313
+ }
314
+ else {
315
+ for (const dir of dirs) {
316
+ await runTSCInFolder(dir, args);
317
+ }
318
+ }
319
+ }
320
+ /**
321
+ * Pass 'src' to run in root.
322
+ */
323
+ async function runTSCInFolder(dir, args = []) {
324
+ let configDir = dir;
325
+ if (dir === 'src') {
326
+ configDir = '';
327
+ }
328
+ const tsconfigPath = [configDir, 'tsconfig.json'].filter(Boolean).join('/');
329
+ if (!fs2.pathExists(tsconfigPath) || !fs2.pathExists(dir)) {
330
+ // console.log(`Skipping to run tsc for ${tsconfigPath}, as it doesn't exist`)
331
+ return;
332
+ }
333
+ const tscPath = findPackageBinPath('typescript', 'tsc');
334
+ const cacheLocation = `node_modules/.cache/${dir}.tsbuildinfo`;
335
+ const cacheFound = existsSync(cacheLocation);
336
+ console.log(dimGrey(`${check(cacheFound)}tsc ${dir} cache found: ${cacheFound}`));
337
+ await exec2.spawnAsync(tscPath, {
338
+ args: ['-P', tsconfigPath, ...args],
339
+ shell: false,
340
+ });
341
+ }
342
+ export async function runTSCProd(args = []) {
343
+ const tsconfigPath = [`./tsconfig.prod.json`].find(p => fs2.pathExists(p)) || 'tsconfig.json';
344
+ const tscPath = findPackageBinPath('typescript', 'tsc');
345
+ await exec2.spawnAsync(tscPath, {
346
+ args: ['-P', tsconfigPath, '--noEmit', 'false', '--noCheck', '--incremental', 'false', ...args],
347
+ shell: false,
348
+ });
349
+ }
350
+ export function buildCopy() {
351
+ const baseDir = 'src';
352
+ const inputPatterns = [
353
+ '**',
354
+ '!**/*.ts',
355
+ '!**/__snapshots__',
356
+ '!**/__exclude',
357
+ '!test',
358
+ '!**/*.test.js',
359
+ ];
360
+ const outputDir = 'dist';
361
+ kpySync({
362
+ baseDir,
363
+ inputPatterns,
364
+ outputDir,
365
+ dotfiles: true,
366
+ });
367
+ }
368
+ export function runTest(opt = {}) {
369
+ // if (nodeModuleExists('vitest')) {
370
+ if (fs2.pathExists('vitest.config.ts')) {
371
+ runVitest(opt);
372
+ return;
373
+ }
374
+ console.log(dimGrey(`vitest.config.ts not found, skipping tests`));
375
+ }
376
+ function runVitest(opt) {
377
+ const { integration, manual } = opt;
378
+ const processArgs = process.argv.slice(3);
379
+ const args = [...processArgs];
380
+ const env = {};
381
+ if (integration) {
382
+ Object.assign(env, {
383
+ TEST_TYPE: 'integration',
384
+ });
385
+ }
386
+ else if (manual) {
387
+ Object.assign(env, {
388
+ TEST_TYPE: 'manual',
389
+ });
390
+ }
391
+ const vitestPath = findPackageBinPath('vitest', 'vitest');
392
+ exec2.spawn(vitestPath, {
393
+ args: _uniq(args),
394
+ logFinish: false,
395
+ shell: false,
396
+ env,
397
+ });
398
+ }
399
+ /**
400
+ * Returns true if module with given name exists in _target project's_ node_modules.
401
+ */
402
+ // function nodeModuleExists(moduleName: string): boolean {
403
+ // return existsSync(`./node_modules/${moduleName}`)
404
+ // }
282
405
  function canRunBinary(name) {
283
406
  try {
284
407
  execSync(`which ${name}`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/dev-lib",
3
3
  "type": "module",
4
- "version": "20.23.0",
4
+ "version": "20.24.0",
5
5
  "dependencies": {
6
6
  "@biomejs/biome": "^2",
7
7
  "@eslint/js": "^9",
@@ -1,9 +0,0 @@
1
- export declare function buildProd(): Promise<void>;
2
- /**
3
- * Use 'src' to indicate root.
4
- *
5
- * @deprecated - oxlint should be used for type-checking instead, it's faster.
6
- */
7
- export declare function runTSCInFolders(dirs: string[], args?: string[], parallel?: boolean): Promise<void>;
8
- export declare function runTSCProd(args?: string[]): Promise<void>;
9
- export declare function buildCopy(): void;
@@ -1,77 +0,0 @@
1
- import { existsSync } from 'node:fs';
2
- import { dimGrey } from '@naturalcycles/nodejs-lib/colors';
3
- import { exec2 } from '@naturalcycles/nodejs-lib/exec2';
4
- import { fs2 } from '@naturalcycles/nodejs-lib/fs2';
5
- import { kpySync } from '@naturalcycles/nodejs-lib/kpy';
6
- import { findPackageBinPath } from './lint.util.js';
7
- export async function buildProd() {
8
- // fs2.emptyDir('./dist') // it doesn't delete the dir itself, to prevent IDE jumping
9
- buildCopy();
10
- await runTSCProd();
11
- }
12
- /**
13
- * Use 'src' to indicate root.
14
- *
15
- * @deprecated - oxlint should be used for type-checking instead, it's faster.
16
- */
17
- export async function runTSCInFolders(dirs, args = [], parallel = true) {
18
- if (parallel) {
19
- await Promise.all(dirs.map(dir => runTSCInFolder(dir, args)));
20
- }
21
- else {
22
- for (const dir of dirs) {
23
- await runTSCInFolder(dir, args);
24
- }
25
- }
26
- }
27
- /**
28
- * Pass 'src' to run in root.
29
- */
30
- async function runTSCInFolder(dir, args = []) {
31
- let configDir = dir;
32
- if (dir === 'src') {
33
- configDir = '';
34
- }
35
- const tsconfigPath = [configDir, 'tsconfig.json'].filter(Boolean).join('/');
36
- if (!fs2.pathExists(tsconfigPath) || !fs2.pathExists(dir)) {
37
- // console.log(`Skipping to run tsc for ${tsconfigPath}, as it doesn't exist`)
38
- return;
39
- }
40
- const tscPath = findPackageBinPath('typescript', 'tsc');
41
- const cacheLocation = `node_modules/.cache/${dir}.tsbuildinfo`;
42
- const cacheFound = existsSync(cacheLocation);
43
- console.log(dimGrey(`${check(cacheFound)}tsc ${dir} cache found: ${cacheFound}`));
44
- await exec2.spawnAsync(tscPath, {
45
- args: ['-P', tsconfigPath, ...args],
46
- shell: false,
47
- });
48
- }
49
- export async function runTSCProd(args = []) {
50
- const tsconfigPath = [`./tsconfig.prod.json`].find(p => fs2.pathExists(p)) || 'tsconfig.json';
51
- const tscPath = findPackageBinPath('typescript', 'tsc');
52
- await exec2.spawnAsync(tscPath, {
53
- args: ['-P', tsconfigPath, '--noEmit', 'false', '--noCheck', '--incremental', 'false', ...args],
54
- shell: false,
55
- });
56
- }
57
- export function buildCopy() {
58
- const baseDir = 'src';
59
- const inputPatterns = [
60
- '**',
61
- '!**/*.ts',
62
- '!**/__snapshots__',
63
- '!**/__exclude',
64
- '!test',
65
- '!**/*.test.js',
66
- ];
67
- const outputDir = 'dist';
68
- kpySync({
69
- baseDir,
70
- inputPatterns,
71
- outputDir,
72
- dotfiles: true,
73
- });
74
- }
75
- function check(predicate) {
76
- return predicate ? ' ✓ ' : ' ';
77
- }
@@ -1,10 +0,0 @@
1
- interface RunTestOptions {
2
- integration?: boolean;
3
- manual?: boolean;
4
- leaks?: boolean;
5
- }
6
- export declare function runTest(opt?: RunTestOptions): void;
7
- export {};
8
- /**
9
- * Returns true if module with given name exists in _target project's_ node_modules.
10
- */
package/dist/test.util.js DELETED
@@ -1,42 +0,0 @@
1
- import { _uniq } from '@naturalcycles/js-lib/array/array.util.js';
2
- import { dimGrey } from '@naturalcycles/nodejs-lib/colors';
3
- import { exec2 } from '@naturalcycles/nodejs-lib/exec2';
4
- import { fs2 } from '@naturalcycles/nodejs-lib/fs2';
5
- import { findPackageBinPath } from './lint.util.js';
6
- export function runTest(opt = {}) {
7
- // if (nodeModuleExists('vitest')) {
8
- if (fs2.pathExists('vitest.config.ts')) {
9
- runVitest(opt);
10
- return;
11
- }
12
- console.log(dimGrey(`vitest.config.ts not found, skipping tests`));
13
- }
14
- function runVitest(opt) {
15
- const { integration, manual } = opt;
16
- const processArgs = process.argv.slice(3);
17
- const args = [...processArgs];
18
- const env = {};
19
- if (integration) {
20
- Object.assign(env, {
21
- TEST_TYPE: 'integration',
22
- });
23
- }
24
- else if (manual) {
25
- Object.assign(env, {
26
- TEST_TYPE: 'manual',
27
- });
28
- }
29
- const vitestPath = findPackageBinPath('vitest', 'vitest');
30
- exec2.spawn(vitestPath, {
31
- args: _uniq(args),
32
- logFinish: false,
33
- shell: false,
34
- env,
35
- });
36
- }
37
- /**
38
- * Returns true if module with given name exists in _target project's_ node_modules.
39
- */
40
- // function nodeModuleExists(moduleName: string): boolean {
41
- // return existsSync(`./node_modules/${moduleName}`)
42
- // }