Skip to content

3.3.2#115

Merged
matteobruni merged 8 commits intomainfrom
dev
Mar 10, 2026
Merged

3.3.2#115
matteobruni merged 8 commits intomainfrom
dev

Conversation

@matteobruni
Copy link
Contributor

@matteobruni matteobruni commented Mar 10, 2026

Summary by CodeRabbit

Release Notes

  • Chores

    • Bumped version to 3.3.2
    • Removed external filesystem dependency in favor of native Node.js APIs
    • Updated development tooling versions and pnpm package manager to 10.32.0
  • Documentation

    • Refined architecture, naming conventions, and testing documentation with clearer guidance and examples
    • Updated security and error handling best practices documentation

Copilot AI review requested due to automatic review settings March 10, 2026 22:34
@coderabbitai
Copy link

coderabbitai bot commented Mar 10, 2026

Warning

Rate limit exceeded

@matteobruni has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 16 minutes and 44 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 50820cb6-e14d-461d-bb9e-d9d8d91bf93c

📥 Commits

Reviewing files that changed from the base of the PR and between 0cedb62 and dfbd1ad.

📒 Files selected for processing (3)
  • package.json
  • src/build/build-distfiles.ts
  • src/utils/file-utils.ts
📝 Walkthrough

Walkthrough

The pull request migrates the codebase from fs-extra to native Node.js fs/promises APIs, updates configuration and dependency versions, and substantially revises architectural and procedural planning documentation to reflect refined module organization, error handling, and testing patterns.

Changes

Cohort / File(s) Summary
Planning & Documentation
.planning/codebase/ARCHITECTURE.md, .planning/codebase/CONCERNS.md, .planning/codebase/CONVENTIONS.md, .planning/codebase/INTEGRATIONS.md, .planning/codebase/STACK.md, .planning/codebase/STRUCTURE.md, .planning/codebase/TESTING.md
Comprehensive documentation refactoring: updated architecture to emphasize command/core/build layers; reframed error handling and cross-cutting concerns around RegExp token replacement robustness; clarified naming conventions, code style, and module design; expanded integration, stack, and structure documentation with granular details; enriched testing guidance with concrete patterns and examples. Analysis dates bumped from 2026-03-08 to 2026-03-10.
Dependency & Package Configuration
package.json, files/empty-project/package.json
Bumped project version to 3.3.2; updated @tsparticles config packages to ^3.3.1; removed fs-extra and @types/fs-extra; updated typescript-eslint, @types/node, and terser-webpack-plugin to newer patch versions; bumped packageManager from pnpm@10.31.0 to pnpm@10.32.0.
Build & TypeScript Configuration
tsconfig.json, webpack.config.js, files/empty-project/webpack.config.js
Removed fs-extra from TypeScript ambient types; migrated webpack config from fs-extra readJson to native readFile + JSON.parse; updated path and fs imports to node:path and node:fs/promises; added esModuleInterop to tests/tsconfig.json.
Filesystem API Migration — CLI & Core
src/cli.ts, src/create/plugin/create-plugin.ts, src/create/preset/create-preset.ts, src/create/shape/create-shape.ts
Replaced fs-extra imports with native node:fs/promises equivalents; swapped fs.readJson for JSON.parse(await readFile(...)); replaced fs.copy with cp(..., { recursive: true, force: true }); updated URL imports to use node:url.
Filesystem API Migration — Build & Utilities
src/build/build.ts, src/build/build-distfiles.ts, src/build/build-diststats.ts, src/build/build-prettier.ts, src/build/build-tsc.ts, src/utils/file-utils.ts, src/utils/template-utils.ts
Migrated all build and utility modules from fs-extra to node:fs/promises; replaced pathExists with existsSync; swapped readFile/writeFile/copyFile/mkdir/readdir operations to native APIs; adjusted control flow for existence checks (e.g., mkdir preconditions) while preserving functionality.
Test Updates
tests/create-plugin.test.ts, tests/create-preset.test.ts, tests/create-shape.test.ts, tests/file-utils.test.ts, tests/tsconfig.json
Updated test files to use node:fs/promises; replaced fs.readJSON with JSON.parse(await readFile(...)); swapped fs.remove with rm(..., { recursive: true, force: true }); adjusted test setup/teardown and assertions to async patterns; reformatted indentation for consistency.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • tsparticles/cli#62 — Overlapping filesystem I/O refactoring in src/utils/file-utils.ts, src/cli.ts, and src/create/* modules with similar fs-extra-to-native migration patterns.
  • tsparticles/cli#110 — Touches src/build/build-prettier.ts with related changes to prettifyPackageDistJson and build pipeline modifications.
  • tsparticles/cli#89 — Shared modifications to src/utils/file-utils.ts and src/build/* filesystem utilities affecting the same code paths.

Poem

🐰 Hop, skip, and native Node we go,
fs-extra fades, let built-ins show,
With cp and rm, readFile so bright,
Our fuzzy CLI files dance just right!
Less sugar, more speed—the future's here,
A refactored warren we hold dear!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title '3.3.2' is a version number that does not describe the actual changes made in the pull request, which involves replacing fs-extra with native Node.js modules across the codebase. Use a descriptive title that summarizes the main change, such as 'Replace fs-extra with native Node.js modules' or 'Remove fs-extra dependency and migrate to node:fs APIs'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the CLI codebase away from fs-extra toward Node’s built-in node:fs / node:fs/promises, updates related tests/config, and bumps several internal/tooling dependencies.

Changes:

  • Replace fs-extra usage with node:fs/promises APIs (readFile, writeFile, cp, etc.) across CLI/build/template code and tests.
  • Update TypeScript configs to remove fs-extra types and adjust test compiler options.
  • Bump package/tooling versions and remove fs-extra / @types/fs-extra from direct dependencies.

Reviewed changes

Copilot reviewed 26 out of 28 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
tsconfig.json Removes fs-extra typings and reformats compiler options.
tests/tsconfig.json Adds esModuleInterop and reformats.
tests/file-utils.test.ts Migrates tests from fs-extra to node:fs/promises.
tests/create-shape.test.ts Migrates test file IO and cleanup to node:fs/promises.
tests/create-preset.test.ts Migrates test file IO and cleanup to node:fs/promises.
tests/create-plugin.test.ts Migrates test file IO and cleanup to node:fs/promises.
src/utils/template-utils.ts Replaces template copy from fs-extra to cp.
src/utils/file-utils.ts Replaces fs-extra usage with readFile/writeFile, existsSync, and mkdir.
src/create/shape/create-shape.ts Replaces template copy from fs-extra to cp.
src/create/preset/create-preset.ts Replaces template copy from fs-extra to cp.
src/create/plugin/create-plugin.ts Replaces template copy from fs-extra to cp.
src/cli.ts Replaces fs-extra JSON read with readFile + JSON.parse.
src/build/build.ts Replaces dynamic fs-extra path check with existsSync and static node:path.
src/build/build-tsc.ts Replaces fs-extra checks/reads with existsSync + readFile.
src/build/build-prettier.ts Replaces fs-extra reads/writes/exists with Node built-ins.
src/build/build-diststats.ts Replaces fs-extra folder ops with Node built-ins.
src/build/build-distfiles.ts Replaces fs-extra reads/writes/copy with Node built-ins.
package.json Removes fs-extra deps, bumps internal/tooling versions, bumps package version and pnpm.
pnpm-lock.yaml Reflects dependency removals/bumps.
files/empty-project/webpack.config.js Replaces fs-extra JSON read with readFile + JSON.parse.
files/empty-project/package.json Bumps template devDependency versions.
.planning/codebase/TESTING.md Updates analysis date/content (but still references fs-extra in places).
.planning/codebase/STRUCTURE.md Updates analysis date/content.
.planning/codebase/STACK.md Updates analysis date/content (but still lists fs-extra as critical).
.planning/codebase/INTEGRATIONS.md Updates analysis date/content (but still references fs-extra).
.planning/codebase/CONVENTIONS.md Updates analysis date/content (but still includes fs-extra example).
.planning/codebase/CONCERNS.md Updates analysis date/content.
.planning/codebase/ARCHITECTURE.md Updates analysis date/content (but still says core depends on fs-extra).
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🧹 Nitpick comments (4)
src/build/build-tsc.ts (1)

19-23: Minor cleanup: reuse tsconfigPath for read.

You already compute tsconfigPath; reusing it for readFile avoids duplicate path composition and keeps the block tighter.

♻️ Suggested small refactor
   const tsconfigPath = path.join(basePath, file);

   if (existsSync(tsconfigPath)) {
-    const data = await readFile(path.join(basePath, file));
+    const data = await readFile(tsconfigPath);

     return data.toString();
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/build/build-tsc.ts` around lines 19 - 23, Reuse the previously computed
tsconfigPath instead of recomputing the path: when checking
existsSync(tsconfigPath) and then calling readFile(...), change the readFile
call to use readFile(tsconfigPath) so you avoid duplicating path.join(basePath,
file); update the block around tsconfigPath, existsSync and readFile
accordingly.
.planning/codebase/STRUCTURE.md (1)

7-38: Add language specifier to the directory tree code block.

For consistency and proper rendering, specify a language (e.g., text or plaintext) for the directory tree.

-```
+```text
 [project-root]/
 ├── src/                 # TypeScript source for CLI and build tasks
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.planning/codebase/STRUCTURE.md around lines 7 - 38, The fenced code block
showing the directory tree in .planning/codebase/STRUCTURE.md lacks a language
specifier; update the opening fence from ``` to ```text (or ```plaintext) so the
tree renders consistently, i.e., modify the code block that begins with the
directory tree under the [project-root]/ listing to include the language
specifier.
.planning/codebase/TESTING.md (1)

33-36: Add language specifier to fenced code block.

The code block should specify a language for proper syntax highlighting and linting compliance.

-```
+```text
 tests/
 ├── <feature>.test.ts   # top-level test file for a single module/feature

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @.planning/codebase/TESTING.md around lines 33 - 36, Update the fenced code
block in TESTING.md to include a language specifier (e.g., text or bash)
so the snippet "tests/ ├── .test.ts # top-level test file for a
single module/feature" is fenced as text tests/ ... which enables proper
syntax highlighting and satisfies linting rules for fenced code blocks.


</details>

</blockquote></details>
<details>
<summary>tests/create-plugin.test.ts (1)</summary><blockquote>

`11-15`: **Consider improving error handling in tests.**

The current pattern swallows errors from `createPluginTemplate` with only `console.error`, allowing the test to continue. If `createPluginTemplate` fails, the subsequent `readFile` will throw a different error, obscuring the root cause.

Consider removing the try/catch to let test failures surface directly, or use `expect` assertions for error cases:

```typescript
// Option 1: Let errors propagate naturally
await createPluginTemplate("foo", "Foo", "", destDir);

// Option 2: If errors are expected in some scenarios
await expect(createPluginTemplate(...)).resolves.not.toThrow();
```




Also applies to: 27-31

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against the current code and only fix it if needed.

In `@tests/create-plugin.test.ts` around lines 11 - 15, The test currently catches
errors from createPluginTemplate("foo", "Foo", "", destDir) and only logs them,
which hides failures and causes later reads (e.g., readFile) to throw unrelated
errors; remove the try/catch so the promise can reject and fail the test, or
replace the catch with an explicit assertion such as await
expect(createPluginTemplate("foo","Foo","", destDir)).resolves.not.toThrow();
apply the same change to the other occurrence around the second
createPluginTemplate call so failures surface clearly.
```

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.planning/codebase/ARCHITECTURE.md:

  • Around line 31-32: Update the Core/Template Layer dependency list in
    ARCHITECTURE.md to remove the obsolete fs-extra entry and instead reference
    the native node:fs/promises API; keep the other entries (lookpath,
    child_process exec) and the "Used by: Command actions in src/create/*" note
    unchanged so the document matches the current implementation.
  • Around line 59-62: The architecture doc incorrectly documents using fs.copy
    (fs-extra) for copying project-specific files; update the text to reference the
    native Node API cp from node:fs/promises instead. Specifically, change the
    bullet that mentions "copy project-specific files via fs.copy" to say "copy
    project-specific files via cp (node:fs/promises)" and ensure any mention of the
    utility function name(s) such as copyEmptyTemplateFiles, replaceTokensInFile,
    runInstall, and runBuild remains intact so readers can locate the implementation
    when they search the docs.

In @.planning/codebase/CONCERNS.md:

  • Line 26: The recommendation currently suggests fs-extra
    (fs.readJSON/fs.writeJSON) which contradicts the project's migration away from
    fs-extra; update the guidance to use native fs/promises APIs in the example for
    updatePackageFile: read the file at pkgPath with fs.readFile and JSON.parse to
    get pkg, set pkg.name = packageName (and other fields), then write back using
    fs.writeFile with JSON.stringify(pkg, null, 2) plus a trailing newline and UTF-8
    encoding; mention these specific symbols (updatePackageFile, pkgPath,
    packageName) so the example aligns with the native fs approach.

In @.planning/codebase/CONVENTIONS.md:

  • Around line 56-59: The example import block in CONVENTIONS.md still shows the
    removed fs-extra package; update the example to use native Node APIs and reflect
    the intended import order: third-party packages, Node built-ins (using the node:
    namespace), then local relative imports. Replace the import fs from "fs-extra"
    line with the appropriate native import such as import { promises as fs } from "node:fs" or import fs from "node:fs" (or import path from "node:path" as
    already shown), and ensure the example still includes the local import import { camelize, capitalize, dash } from "../../utils/string-utils.js"; to demonstrate
    final ordering.

In @.planning/codebase/INTEGRATIONS.md:

  • Line 26: Update the filesystem integration note to remove the reference to
    fs-extra and state that the CLI now uses native Node.js filesystem APIs;
    update the sentence that mentions src/utils/file-utils.ts, src/create/*
    helpers and examples like src/create/plugin/create-plugin.ts (which used
    files/create-plugin) to indicate those create/template helpers now rely on the
    native fs/fs/promises implementations instead of fs-extra, and adjust any
    wording so the planning doc accurately reflects the migration.

In @.planning/codebase/STACK.md:

  • Line 50: Update the STACK.md entry that still lists fs-extra ^11.x: remove
    that bullet or replace it to state that the project no longer depends on
    fs-extra and now uses native node:fs/promises APIs (and optionally note the
    example file src/utils/file-utils.ts and package.json no longer reference
    fs-extra) so the stack documentation matches the codebase change.

In @.planning/codebase/TESTING.md:

  • Around line 46-47: The docs still reference fs-extra APIs (fs.ensureDir,
    fs.remove, and import fs from "fs-extra") though the codebase now uses native
    node:fs/promises; update all occurrences mentioned (lines referencing
    fs.ensureDir, fs.remove, "actual fs-extra operations", "using fs-extra", and
    the example import block) to use the native API names and import pattern:
    replace import fs from "fs-extra" with import { mkdir, rm, readFile, writeFile }
    from "node:fs/promises" and change calls to use mkdir (with { recursive: true })
    for ensureDir, rm for remove, and readFile/writeFile for file IO, adjusting
    example templates and explanatory text accordingly so the docs match the
    migrated codebase.

In @src/build/build-distfiles.ts:

  • Around line 94-96: The writeFile calls in buildDistFiles (the lines writing
    package.json into dist/cjs, dist/esm, and dist/browser) can fail with ENOENT if
    those directories don't exist; before each writeFile (or once for distPath),
    ensure the directories exist by creating the parent directories with mkdir
    (fs.promises.mkdir) using { recursive: true } for "cjs", "esm", and "browser"
    (or for distPath itself) so writeFile won't error when --dist is run without
    prior TypeScript compilation.

In @src/utils/file-utils.ts:

  • Around line 50-64: getDestinationDir currently calls mkdir(destPath)
    unconditionally which throws EEXIST for an existing empty directory and loses
    the original "ensureDir" behavior for nested paths; update the function to
    either (a) only call mkdir when !existsSync(destPath) or (b) call
    mkdir(destPath, { recursive: true }) so parents are created and no error is
    thrown if the directory already exists, and ensure the function returns destPath
    at the end. Reference: getDestinationDir, destPath, existsSync, mkdir.

In @tests/create-preset.test.ts:

  • Around line 10-21: The test currently catches and swallows errors from
    createPresetTemplate("foo", "Foo", "", destDir); which masks failures; remove
    the empty catch (or rethrow the caught error) and instead wrap the code that
    reads and asserts package.json (the JSON parse + expect(pkgInfo.name).toBe(...))
    in a try block with the cleanup rm(destDir, { recursive: true, force: true })
    moved into a finally block so any error from createPresetTemplate or the
    assertions fails the test while cleanup always runs; reference
    createPresetTemplate, readFile/pkgPath/pkgInfo/expect, and rm when applying the
    change.

In @tests/create-shape.test.ts:

  • Around line 10-21: The test currently swallows scaffold failures and doesn't
    guarantee cleanup: when calling createShapeTemplate(...) in
    tests/create-shape.test.ts, remove the silent catch that only console.errors and
    instead let the error propagate (or rethrow) so the test fails where the
    scaffold fails, and move the rm(destDir, { recursive: true, force: true })
    cleanup into a finally block to ensure the temporary directory is removed on
    both success and failure; apply the same try/finally (or
    try/catch+rethrow+finally) pattern to the second test block (lines 27-38) that
    also calls createShapeTemplate so both tests fail on scaffold errors and always
    clean up.

In @tests/file-utils.test.ts:

  • Around line 11-107: The test suite is performing async filesystem work inside
    describe callbacks which must be synchronous; move all await calls
    (mkdir(baseDir), writeFile(...) calls, replaceTokensInFiles(...),
    replaceTokensInFile(...), and getDestinationDir(...) setup) into appropriate
    beforeAll or beforeEach hooks and keep describe callbacks synchronous; make the
    mkdir call idempotent by calling mkdir(baseDir, { recursive: true }) in a
    beforeAll that runs before any file writes; keep the assertions and afterAll
    cleanup (rm(...)) as-is.

Nitpick comments:
In @.planning/codebase/STRUCTURE.md:

  • Around line 7-38: The fenced code block showing the directory tree in
    .planning/codebase/STRUCTURE.md lacks a language specifier; update the opening
    fence from totext (or ```plaintext) so the tree renders consistently,
    i.e., modify the code block that begins with the directory tree under the
    [project-root]/ listing to include the language specifier.

In @.planning/codebase/TESTING.md:

  • Around line 33-36: Update the fenced code block in TESTING.md to include a
    language specifier (e.g., text or bash) so the snippet "tests/ ├──
    .test.ts # top-level test file for a single module/feature" is fenced
    as text tests/ ... which enables proper syntax highlighting and satisfies
    linting rules for fenced code blocks.

In @src/build/build-tsc.ts:

  • Around line 19-23: Reuse the previously computed tsconfigPath instead of
    recomputing the path: when checking existsSync(tsconfigPath) and then calling
    readFile(...), change the readFile call to use readFile(tsconfigPath) so you
    avoid duplicating path.join(basePath, file); update the block around
    tsconfigPath, existsSync and readFile accordingly.

In @tests/create-plugin.test.ts:

  • Around line 11-15: The test currently catches errors from
    createPluginTemplate("foo", "Foo", "", destDir) and only logs them, which hides
    failures and causes later reads (e.g., readFile) to throw unrelated errors;
    remove the try/catch so the promise can reject and fail the test, or replace the
    catch with an explicit assertion such as await
    expect(createPluginTemplate("foo","Foo","", destDir)).resolves.not.toThrow();
    apply the same change to the other occurrence around the second
    createPluginTemplate call so failures surface clearly.

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: defaults

**Review profile**: CHILL

**Plan**: Pro

**Run ID**: `971d75d5-f051-404f-a7e4-b8af13e3e9b5`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 04a8c7b46aa134fae5ef75e5a9e1b67c9195042b and 0cedb62c6d00b3fbaa225ed70ba484e5de1f62d5.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `pnpm-lock.yaml` is excluded by `!**/pnpm-lock.yaml`

</details>

<details>
<summary>📒 Files selected for processing (27)</summary>

* `.planning/codebase/ARCHITECTURE.md`
* `.planning/codebase/CONCERNS.md`
* `.planning/codebase/CONVENTIONS.md`
* `.planning/codebase/INTEGRATIONS.md`
* `.planning/codebase/STACK.md`
* `.planning/codebase/STRUCTURE.md`
* `.planning/codebase/TESTING.md`
* `files/empty-project/package.json`
* `files/empty-project/webpack.config.js`
* `package.json`
* `src/build/build-distfiles.ts`
* `src/build/build-diststats.ts`
* `src/build/build-prettier.ts`
* `src/build/build-tsc.ts`
* `src/build/build.ts`
* `src/cli.ts`
* `src/create/plugin/create-plugin.ts`
* `src/create/preset/create-preset.ts`
* `src/create/shape/create-shape.ts`
* `src/utils/file-utils.ts`
* `src/utils/template-utils.ts`
* `tests/create-plugin.test.ts`
* `tests/create-preset.test.ts`
* `tests/create-shape.test.ts`
* `tests/file-utils.test.ts`
* `tests/tsconfig.json`
* `tsconfig.json`

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

@matteobruni matteobruni merged commit 608851f into main Mar 10, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants