@naturalcycles/dev-lib 20.18.2 → 20.20.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,26 @@
1
+ import { _ms } from '@naturalcycles/js-lib/datetime'
2
+
3
+ /**
4
+ * A minimal reporter that only shows failures and the final summary.
5
+ * No per-test, no per-file output - just failures and final summary.
6
+ *
7
+ * Use via: VITEST_REPORTER=summary vitest run
8
+ */
9
+ export class SummaryOnlyReporter {
10
+ onTestRunEnd(testModules) {
11
+ let files = 0
12
+ let duration = 0
13
+
14
+ for (const mod of testModules) {
15
+ files++
16
+ duration += mod.diagnostic().duration
17
+ }
18
+
19
+ console.log()
20
+ console.log(` Files: ${files}`)
21
+ console.log(` Duration: ${_ms(duration)}`)
22
+ console.log()
23
+ }
24
+ }
25
+
26
+ export default SummaryOnlyReporter
@@ -21,4 +21,7 @@ export function defineVitestConfig(config?: Partial<ViteUserConfig>, cwd?: strin
21
21
  export function getSharedConfig(cwd?: string): InlineConfig
22
22
 
23
23
  export const CollectReporter: any
24
- export const SummaryReporter: any
24
+
25
+ export class SummaryReporter {}
26
+
27
+ export class SummaryOnlyReporter {}
@@ -2,8 +2,10 @@ import fs from 'node:fs'
2
2
  import { VitestAlphabeticSequencer } from './vitestAlphabeticSequencer.js'
3
3
  import { defineConfig } from 'vitest/config'
4
4
  import { SummaryReporter } from './summaryReporter.js'
5
+ import { SummaryOnlyReporter } from './summaryOnlyReporter.js'
5
6
  export { SummaryReporter } from './summaryReporter.js'
6
7
  export { CollectReporter } from './collectReporter.js'
8
+ export { SummaryOnlyReporter } from './summaryOnlyReporter.js'
7
9
 
8
10
  const runsInIDE = doesItRunInIDE()
9
11
  const testType = getTestType(runsInIDE)
@@ -47,19 +49,19 @@ export function defineVitestConfig(config, cwd) {
47
49
 
48
50
  const { silent, pool, maxWorkers, isolate } = mergedConfig.test
49
51
 
50
- console.log({
51
- testType,
52
- silent,
53
- isCI,
54
- runsInIDE,
55
- // include,
56
- // exclude,
57
- pool,
58
- isolate,
59
- maxWorkers,
60
- // setupFiles,
61
- // cwd,
62
- })
52
+ // In workspace mode, cwd differs from process.cwd() (which is the monorepo root)
53
+ const isWorkspaceMode = cwd && process.cwd() !== cwd
54
+ if (!isWorkspaceMode) {
55
+ console.log({
56
+ testType,
57
+ silent,
58
+ isCI,
59
+ runsInIDE,
60
+ pool,
61
+ isolate,
62
+ maxWorkers,
63
+ })
64
+ }
63
65
 
64
66
  return mergedConfig
65
67
  }
@@ -90,17 +92,7 @@ export function getSharedConfig(cwd) {
90
92
  },
91
93
  include,
92
94
  exclude,
93
- reporters: [
94
- 'default',
95
- new SummaryReporter(),
96
- junitReporterEnabled && [
97
- 'junit',
98
- {
99
- suiteName: `${testType} tests`,
100
- // classNameTemplate: '{filename} - {classname}',
101
- },
102
- ],
103
- ].filter(Boolean),
95
+ reporters: getReporters(junitReporterEnabled, testType),
104
96
  // outputFile location is specified for compatibility with the previous jest config
105
97
  outputFile: junitReporterEnabled ? `./tmp/jest/${testType}.xml` : undefined,
106
98
  coverage: {
@@ -130,6 +122,30 @@ export function getSharedConfig(cwd) {
130
122
  }
131
123
  }
132
124
 
125
+ function getReporters(junitReporterEnabled, testType) {
126
+ // VITEST_REPORTER env var allows overriding the default reporter
127
+ // e.g., VITEST_REPORTER=summary for minimal output
128
+ const { VITEST_REPORTER, CLAUDE_CODE } = process.env
129
+
130
+ if (VITEST_REPORTER === 'summary' || CLAUDE_CODE) {
131
+ return [new SummaryOnlyReporter()]
132
+ }
133
+ if (VITEST_REPORTER === 'dot') {
134
+ return ['dot']
135
+ }
136
+
137
+ return [
138
+ 'default',
139
+ new SummaryReporter(),
140
+ junitReporterEnabled && [
141
+ 'junit',
142
+ {
143
+ suiteName: `${testType} tests`,
144
+ },
145
+ ],
146
+ ].filter(Boolean)
147
+ }
148
+
133
149
  function doesItRunInIDE() {
134
150
  // example command line below:
135
151
  // /usr/local/bin/node /Users/some/Idea/some/node_modules/vitest/vitest.mjs --run --reporter /Users/some/Library/Application Support/JetBrains/IntelliJIdea2025.2/plugins/javascript-plugin/helpers/vitest-intellij/node_modules/vitest-intellij-reporter-safe.js --testNamePattern=^ ?case 001: empty data$ /Users/some/Idea/some/src/some/some.integration.test.ts
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { select, Separator } from '@inquirer/prompts';
3
2
  import { _by } from '@naturalcycles/js-lib/array/array.util.js';
4
3
  import { _assert } from '@naturalcycles/js-lib/error/assert.js';
5
4
  import { fs2 } from '@naturalcycles/nodejs-lib/fs2';
@@ -9,8 +8,12 @@ import { runCommitlint } from '../commitlint.js';
9
8
  import { eslintAll, lintAllCommand, lintStagedCommand, requireOxlintConfig, runBiome, runOxlint, runPrettier, stylelintAll, } from '../lint.util.js';
10
9
  import { runTest } from '../test.util.js';
11
10
  const commands = [
12
- new Separator(), // build
13
11
  { name: 'check', fn: check, desc: '"Run all possible checks": lint, typecheck, then test.' },
12
+ {
13
+ name: 'quick-check',
14
+ fn: quickCheck,
15
+ desc: 'Like check, but without slow parts, to perform preliminary checks',
16
+ },
14
17
  { name: 'bt', fn: bt, desc: 'Build & Test: run "typecheck" (via oxlint) and then "test".' },
15
18
  {
16
19
  name: 'typecheck',
@@ -42,7 +45,6 @@ const commands = [
42
45
  fn: cleanBuild,
43
46
  desc: 'Cleans ./dist, then runs the build.',
44
47
  },
45
- new Separator(), // test
46
48
  { name: 'test', fn: runTest, desc: 'Run vitest for *.test.ts files.' },
47
49
  {
48
50
  name: 'test-integration',
@@ -59,7 +61,6 @@ const commands = [
59
61
  fn: () => runTest({ leaks: true }),
60
62
  desc: 'Run vitest --detectLeaks for *.test.ts files.',
61
63
  },
62
- new Separator(), // lint
63
64
  {
64
65
  name: 'lint',
65
66
  fn: lintAllCommand,
@@ -107,7 +108,6 @@ const commands = [
107
108
  },
108
109
  { name: 'stylelint-no-fix', cliOnly: true, fn: () => stylelintAll(false) },
109
110
  { name: 'commitlint', fn: runCommitlint, desc: 'Run commitlint.', cliOnly: true },
110
- new Separator(), // interactive-only
111
111
  {
112
112
  name: 'exit',
113
113
  fn: () => console.log('see you!'),
@@ -127,27 +127,31 @@ const commands = [
127
127
  // })
128
128
  // },
129
129
  ];
130
- const commandMap = _by(commands.filter(c => !(c instanceof Separator)), c => c.name);
130
+ const commandMap = _by(commands, c => c.name);
131
131
  const { CI } = process.env;
132
132
  runScript(async () => {
133
133
  let cmd = process.argv.find(s => commandMap[s] && !commandMap[s].interactiveOnly);
134
134
  if (!cmd) {
135
135
  // interactive mode
136
136
  _assert(!CI, 'interactive dev-lib should not be run in CI');
137
- cmd = await select({
137
+ const { default: prompts } = await import('prompts');
138
+ const response = await prompts({
139
+ type: 'select',
140
+ name: 'cmd',
138
141
  message: 'Select command',
139
- pageSize: 30,
142
+ // @ts-expect-error types are wrong
143
+ optionsPerPage: 30,
140
144
  choices: commands
141
- .filter(c => c instanceof Separator || !c.cliOnly)
142
- .map(c => {
143
- if (c instanceof Separator)
144
- return c;
145
- return {
146
- value: c.name,
147
- description: c.desc,
148
- };
149
- }),
145
+ .filter(c => !c.cliOnly)
146
+ .map(c => ({
147
+ title: c.name,
148
+ value: c.name,
149
+ description: c.desc,
150
+ })),
150
151
  });
152
+ cmd = response.cmd;
153
+ if (!cmd)
154
+ return; // user cancelled
151
155
  }
152
156
  await commandMap[cmd].fn();
153
157
  });
@@ -155,6 +159,10 @@ async function check() {
155
159
  await lintAllCommand();
156
160
  runTest();
157
161
  }
162
+ async function quickCheck() {
163
+ await lintAllCommand(false);
164
+ runTest();
165
+ }
158
166
  async function bt() {
159
167
  await typecheckWithOxlint();
160
168
  runTest();
@@ -1,8 +1,10 @@
1
1
  import type { SemVerString } from '@naturalcycles/js-lib/types';
2
2
  /**
3
3
  * Run all linters.
4
+ *
5
+ * If full=false - the "slow" linters are skipped.
4
6
  */
5
- export declare function lintAllCommand(): Promise<void>;
7
+ export declare function lintAllCommand(full?: boolean): Promise<void>;
6
8
  interface EslintAllOptions {
7
9
  ext?: string;
8
10
  fix?: boolean;
package/dist/lint.util.js CHANGED
@@ -16,8 +16,10 @@ import { cfgDir } from './paths.js';
16
16
  const { CI, ESLINT_CONCURRENCY } = process.env;
17
17
  /**
18
18
  * Run all linters.
19
+ *
20
+ * If full=false - the "slow" linters are skipped.
19
21
  */
20
- export async function lintAllCommand() {
22
+ export async function lintAllCommand(full = true) {
21
23
  const started = Date.now();
22
24
  // const { commitOnChanges, failOnChanges } = _yargs().options({
23
25
  // commitOnChanges: {
@@ -44,16 +46,18 @@ export async function lintAllCommand() {
44
46
  runBiome(fix);
45
47
  runOxlint(fix);
46
48
  // From this point we start the "slow" linters, with ESLint leading the way
47
- // We run eslint BEFORE Prettier, because eslint can delete e.g unused imports.
48
- eslintAll({
49
- fix,
50
- });
51
- if (existsSync(`node_modules/stylelint`) &&
52
- existsSync(`node_modules/stylelint-config-standard-scss`)) {
53
- stylelintAll(fix);
49
+ if (full) {
50
+ // We run eslint BEFORE Prettier, because eslint can delete e.g unused imports.
51
+ eslintAll({
52
+ fix,
53
+ });
54
+ if (existsSync(`node_modules/stylelint`) &&
55
+ existsSync(`node_modules/stylelint-config-standard-scss`)) {
56
+ stylelintAll(fix);
57
+ }
58
+ runPrettier({ fix });
59
+ await runKTLint(fix);
54
60
  }
55
- runPrettier({ fix });
56
- await runKTLint(fix);
57
61
  console.log(`${check(true)}${white(`lint-all`)} ${dimGrey(`took ` + _since(started))}`);
58
62
  // if (needToTrackChanges) {
59
63
  // const gitStatusAfter = gitStatus()
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@naturalcycles/dev-lib",
3
3
  "type": "module",
4
- "version": "20.18.2",
4
+ "version": "20.20.0",
5
5
  "dependencies": {
6
6
  "@biomejs/biome": "^2",
7
7
  "@eslint/js": "^9",
8
- "@inquirer/prompts": "^8",
8
+ "prompts": "^2",
9
9
  "@naturalcycles/js-lib": "^15",
10
10
  "@naturalcycles/nodejs-lib": "^15",
11
11
  "@vitest/coverage-v8": "^4",
@@ -16,7 +16,7 @@
16
16
  "eslint-plugin-simple-import-sort": "^12",
17
17
  "eslint-plugin-unicorn": "^62",
18
18
  "eslint-plugin-vue": "^10",
19
- "globals": "^16",
19
+ "globals": "^17",
20
20
  "lint-staged": "^16",
21
21
  "micromatch": "^4",
22
22
  "mitm": "^1",
@@ -42,7 +42,8 @@
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/mitm": "^1",
45
- "@types/node": "^25"
45
+ "@types/node": "^25",
46
+ "@types/prompts": "^2"
46
47
  },
47
48
  "exports": {
48
49
  "./cfg/": "./cfg/",