diff --git a/package.json b/package.json index e291712..81e1c16 100644 --- a/package.json +++ b/package.json @@ -102,6 +102,7 @@ "nx": "22.5.4", "prettier": "3.2.5", "reflect-metadata": "0.2.2", + "rimraf": "6.1.3", "ts-jest": "29.4.2", "ts-node": "10.9.1", "typescript": "5.9.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6ecc5b8..6f80e32 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -249,6 +249,9 @@ importers: reflect-metadata: specifier: 0.2.2 version: 0.2.2 + rimraf: + specifier: 6.1.3 + version: 6.1.3 ts-jest: specifier: 29.4.2 version: 29.4.2(@babel/core@7.29.0)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.1.2(@babel/core@7.29.0))(esbuild@0.25.9)(jest-util@30.0.5)(jest@30.0.5(@types/node@20.19.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@types/node@20.19.9)(typescript@5.9.2)))(typescript@5.9.2) @@ -1695,10 +1698,6 @@ packages: resolution: {integrity: sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==} engines: {node: '>=6.9.0'} - '@babel/runtime@7.28.4': - resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} - engines: {node: '>=6.9.0'} - '@babel/runtime@7.28.6': resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} @@ -8412,10 +8411,6 @@ packages: resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - lru-cache@10.2.2: - resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} - engines: {node: 14 || >=16.14} - lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -8783,10 +8778,6 @@ packages: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} - minimatch@9.0.4: - resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} - engines: {node: '>=16 || 14 >=14.17'} - minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -8818,10 +8809,6 @@ packages: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} - minipass@7.1.3: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} @@ -10230,6 +10217,11 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + rimraf@6.1.3: + resolution: {integrity: sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==} + engines: {node: 20 || >=22} + hasBin: true + rolldown@1.0.0-rc.4: resolution: {integrity: sha512-V2tPDUrY3WSevrvU2E41ijZlpF+5PbZu4giH+VpNraaadsJGHa4fR6IFwsocVwEXDoAdIv5qgPPxgrvKAOIPtA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -15131,8 +15123,6 @@ snapshots: '@babel/runtime@7.28.3': {} - '@babel/runtime@7.28.4': {} - '@babel/runtime@7.28.6': {} '@babel/template@7.27.2': @@ -15513,7 +15503,7 @@ snapshots: '@babel/preset-env': 7.28.3(@babel/core@7.28.5) '@babel/preset-react': 7.27.1(@babel/core@7.28.5) '@babel/preset-typescript': 7.27.1(@babel/core@7.28.5) - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 '@babel/runtime-corejs3': 7.28.4 '@babel/traverse': 7.28.4 '@docusaurus/logger': 3.8.1 @@ -22315,8 +22305,8 @@ snapshots: dependencies: foreground-child: 3.1.1 jackspeak: 3.4.3 - minimatch: 9.0.4 - minipass: 7.1.2 + minimatch: 9.0.5 + minipass: 7.1.3 package-json-from-dist: 1.0.1 path-scurry: 1.11.1 @@ -24098,8 +24088,6 @@ snapshots: lowercase-keys@3.0.0: {} - lru-cache@10.2.2: {} - lru-cache@10.4.3: {} lru-cache@11.2.1: {} @@ -24783,10 +24771,6 @@ snapshots: dependencies: brace-expansion: 2.0.1 - minimatch@9.0.4: - dependencies: - brace-expansion: 2.0.1 - minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -24821,8 +24805,6 @@ snapshots: dependencies: yallist: 4.0.0 - minipass@7.1.2: {} - minipass@7.1.3: {} minizlib@3.1.0: @@ -25361,8 +25343,8 @@ snapshots: path-scurry@1.11.1: dependencies: - lru-cache: 10.2.2 - minipass: 7.1.2 + lru-cache: 10.4.3 + minipass: 7.1.3 path-scurry@2.0.2: dependencies: @@ -26089,7 +26071,7 @@ snapshots: react-loadable-ssr-addon-v5-slorber@1.0.1(@docusaurus/react-loadable@6.0.0(react@19.1.1))(webpack@5.101.3(@swc/core@1.15.8(@swc/helpers@0.5.19))): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 react-loadable: '@docusaurus/react-loadable@6.0.0(react@19.1.1)' webpack: 5.101.3(@swc/core@1.15.8(@swc/helpers@0.5.19)) @@ -26097,13 +26079,13 @@ snapshots: react-router-config@5.1.1(react-router@5.3.4(react@19.1.1))(react@19.1.1): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 react: 19.1.1 react-router: 5.3.4(react@19.1.1) react-router-dom@5.3.4(react@19.1.1): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 history: 4.10.1 loose-envify: 1.4.0 prop-types: 15.8.1 @@ -26114,7 +26096,7 @@ snapshots: react-router@5.3.4(react@19.1.1): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 history: 4.10.1 hoist-non-react-statics: 3.3.2 loose-envify: 1.4.0 @@ -26431,6 +26413,11 @@ snapshots: dependencies: glob: 7.2.3 + rimraf@6.1.3: + dependencies: + glob: 13.0.6 + package-json-from-dist: 1.0.1 + rolldown@1.0.0-rc.4: dependencies: '@oxc-project/types': 0.113.0 diff --git a/tools/cook/infra.ts b/tools/cook/infra.ts index e53e74a..4b92e75 100644 --- a/tools/cook/infra.ts +++ b/tools/cook/infra.ts @@ -1,18 +1,12 @@ -import { workspaceRoot } from '@nx/devkit'; import inquirer from 'enquirer'; -import { - mkdirSync, - readdirSync, - readFileSync, - renameSync, - rmSync, - writeFileSync, -} from 'fs'; +import { readFileSync, writeFileSync } from 'fs'; import { execSync } from 'node:child_process'; +import { mkdirSync, readdirSync, renameSync, rmSync } from 'node:fs'; import { basename, join, relative } from 'node:path'; const { prompt } = inquirer; +const TRASH_PATH = join(process.cwd(), 'tmp', 'trash'); export class CommandRunner { executeCommand( command: string, @@ -29,8 +23,6 @@ export class CommandRunner { } } -export const TRASH_PATH = join(workspaceRoot, 'tmp', 'trash'); - export class FileSystemAdapter { readFile(path: string): string { return readFileSync(path, { @@ -48,18 +40,29 @@ export class FileSystemAdapter { return readdirSync(path); } + /** + * Windows antiviruses can be a pain (e.g. EBUSY errors). + * This method will try to remove the folder multiple times, + * then if it fails, it will try to move the folder to tmp/trash, + * and finally if that fails, it will warn the user that they may need to remove it manually. + * + * Note that I've tried to use rimraf and its backoff but that wasn't enough. + */ removeDir(path: string): void { - mkdirSync(TRASH_PATH, { recursive: true }); - const targetPath = join(TRASH_PATH, `${basename(path)}-${Date.now()}`); - renameSync(path, targetPath); try { - rmSync(targetPath, { maxRetries: 5, recursive: true }); - } catch (error: unknown) { - const relativeTargetPath = relative(workspaceRoot, targetPath); - const reason = error instanceof Error ? error.message : error; - console.warn( - `⚠️ Failed to remove ${relativeTargetPath}. You may need to remove it manually. Reason: ${reason}`, - ); + rmSync(path, { maxRetries: 10, recursive: true }); + } catch { + try { + mkdirSync(TRASH_PATH, { recursive: true }); + const targetPath = join(TRASH_PATH, `${basename(path)}-${Date.now()}`); + renameSync(path, targetPath); + } catch (error: unknown) { + const relativeTargetPath = relative(process.cwd(), path); + const reason = error instanceof Error ? error.message : error; + console.warn( + `⚠️ Failed to remove ${relativeTargetPath}. You may need to remove it manually. Reason: ${reason}`, + ); + } } } } diff --git a/tools/cook/infra.wide.spec.ts b/tools/cook/infra.wide.spec.ts deleted file mode 100644 index b9637e8..0000000 --- a/tools/cook/infra.wide.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { - existsSync, - mkdirSync, - mkdtempSync, - readdirSync, - rmSync, - writeFileSync, -} from 'node:fs'; -import { tmpdir } from 'node:os'; -import { join } from 'node:path'; -import { describe, expect, it } from 'vitest'; -import { FileSystemAdapter, TRASH_PATH } from './infra'; - -describe(FileSystemAdapter, () => { - it('moves directories to tmp before removing them', () => { - const { tmpPath } = setUp(); - const folderToBeRemoved = join(tmpPath, 'file-system-adapter-test'); - mkdirSync(folderToBeRemoved, { recursive: true }); - writeFileSync(join(folderToBeRemoved, 'test.txt'), 'test'); - - new FileSystemAdapter().removeDir(folderToBeRemoved); - - expect.soft(existsSync(folderToBeRemoved)).toBe(false); - expect.soft(readdirSync(TRASH_PATH)).toHaveLength(0); - }); -}); - -function setUp() { - rmSync(TRASH_PATH, { force: true, recursive: true }); - return { - tmpPath: mkdtempSync(join(tmpdir(), 'file-system-adapter-test')), - }; -} diff --git a/tools/vitest.config.mts b/tools/vitest.config.mts index 5590d5b..4d47182 100644 --- a/tools/vitest.config.mts +++ b/tools/vitest.config.mts @@ -1,9 +1,6 @@ import { defineConfig, mergeConfig } from 'vitest/config'; import viteConfig from './vite.config.mjs'; -const narrowTestPatterns = ['**/!(*.wide).spec.ts']; -const wideTestPatterns = ['**/*.wide.spec.ts']; - export default mergeConfig( viteConfig, defineConfig({ @@ -15,25 +12,10 @@ export default mergeConfig( provider: 'v8', }, environment: 'node', + include: ['**/*.spec.ts'], watch: false, pool: 'threads', isolate: false, - projects: [ - { - extends: true, - test: { - name: 'narrow', - include: narrowTestPatterns, - }, - }, - { - extends: true, - test: { - name: 'wide', - include: wideTestPatterns, - }, - }, - ], }, }), );