NX Plugin + Bundle Webpack/Rollup plugins#209
Conversation
Bumps [eslint](https://github.com/eslint/eslint) from 10.2.1 to 10.3.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](eslint/eslint@v10.2.1...v10.3.0) --- updated-dependencies: - dependency-name: eslint dependency-version: 10.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
|
Important Review skippedToo many files! This PR contains 197 files, which is 47 over the limit of 150. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (197)
You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThis PR introduces Nx monorepo support to the tsParticles CLI build system. It splits the bundler into webpack/rollup variants, extracts build steps into standalone commands (eslint, prettier, tsc), creates an Nx plugin to recognize these commands as canonical targets, refactors the build orchestrator to try Nx execution first then fall back to legacy ChangesCore Build System & Nx Integration
Sequence DiagramsequenceDiagram
participant User
participant Build as build<br/>(main cmd)
participant NxDetect as Nx Detection
participant NxExec as Nx Executor
participant LegacyExec as Legacy<br/>Executor
User->>Build: pnpm tsparticles-cli build [--nx]
alt --nx flag or auto-detection
Build->>NxDetect: resolveNxContext(basePath)
NxDetect-->>Build: NxContext or undefined
rect rgba(100, 200, 100, 0.5)
Build->>Build: createNxTargetPlan(targets, options)
Build-->>Build: NxTargetPlan { targets, missingSteps }
end
alt Nx context found & plan valid
Build->>NxExec: tryRunNxBuild(options)
NxExec->>NxExec: runNxTarget() for each target
NxExec-->>Build: true
Build-->>User: ✓ Build completed via Nx
else No Nx or missing targets
Build->>LegacyExec: runLegacyBuild(options)
rect rgba(100, 100, 200, 0.5)
LegacyExec->>LegacyExec: Parse package.json scripts
LegacyExec->>LegacyExec: Run selected scripts sequentially
end
LegacyExec-->>Build: success/failure
Build-->>User: ✓ Build completed (legacy)
end
else --legacy flag
Build->>LegacyExec: runLegacyBuild(options)
LegacyExec-->>Build: result
Build-->>User: ✓ Build completed (legacy)
end
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly Related PRs
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
|
View your CI Pipeline Execution ↗ for commit 7883212
☁️ Nx Cloud last updated this comment at |
There was a problem hiding this comment.
Pull request overview
This PR introduces an internal Nx plugin for the tsParticles CLI monorepo and updates the build tooling to expose/consume canonical Nx targets (including separate Webpack vs Rollup bundle targets). It also adds new build subcommand packages and Vitest coverage around the new Nx-target planning.
Changes:
- Add
@tsparticles/cli-nx-pluginto infer canonical Nx target aliases from existingpackage.jsonscripts forcommands/*andpackages/*. - Refactor
commands/buildto plan and run build steps as Nx targets (with new target convention mapping and tests). - Add/build-split packages for Rollup bundling and for build steps like ESLint / Prettier / TSC, plus workspace script updates.
Reviewed changes
Copilot reviewed 59 out of 64 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Adds a root TypeScript configuration for the workspace. |
| pnpm-lock.yaml | Updates lockfile for new workspace packages and dependencies (Nx plugin + rollup tooling). |
| packages/nx-plugin/vitest.config.ts | Adds Vitest config for the Nx plugin package tests. |
| packages/nx-plugin/tsconfig.json | Adds TS project config for the Nx plugin package. |
| packages/nx-plugin/tests/create-nodes.test.ts | Adds tests for canonical alias generation and workspace package detection. |
| packages/nx-plugin/src/tsconfig.json | Adds src-level TS config for building plugin sources. |
| packages/nx-plugin/src/index.ts | Adds Nx plugin entrypoint/default export and re-export(s). |
| packages/nx-plugin/src/create-nodes.ts | Implements createNodesV2 to augment Nx projects with canonical alias targets. |
| packages/nx-plugin/src/canonical-targets.ts | Defines canonical alias mapping and helpers for generating Nx targets. |
| packages/nx-plugin/project.json | Adds an Nx project config for the plugin package. |
| packages/nx-plugin/package.json | Adds package metadata/scripts/deps for the Nx plugin package. |
| packages/nx-plugin/eslint.config.js | Adds ESLint config for the Nx plugin package. |
| packages/nx-plugin/README.md | Documents plugin behavior and canonical aliases. |
| package.json | Updates root scripts to invoke Nx via pnpm nx ... and adds common workspace commands. |
| nx.json | Registers @tsparticles/cli-nx-plugin in Nx plugins configuration. |
| commands/build/vitest.config.ts | Adds Vitest config for commands/build tests. |
| commands/build/tests/nx-plan.test.ts | Adds tests verifying canonical target selection and fallbacks. |
| commands/build/src/nx-types.ts | Adds shared types for Nx detection/target planning. |
| commands/build/src/nx-targets.ts | Defines canonical target conventions and target picking helper. |
| commands/build/src/nx-runner.ts | Adds execution layer for running resolved Nx targets. |
| commands/build/src/nx-plan.ts | Adds logic to build a target execution plan from CLI flags + available Nx targets. |
| commands/build/src/nx-context.ts | Adds logic to detect Nx workspace/project context and run nx show .../targets. |
| commands/build/src/build.ts | Refactors build command to construct Nx plan and execute targets; adds Rollup + new subcommands. |
| commands/build/src/build-options.ts | Adds a typed options object for Nx planning/execution. |
| commands/build/package.json | Adds vitest scripts and new build-step command dependencies (rollup, eslint, prettier, tsc). |
| commands/build/README.md | Documents Nx-aware build mode and canonical target conventions. |
| commands/build-tsc/tsconfig.json | Adds TS config for the new build-tsc package. |
| commands/build-tsc/src/utils.ts | Implements TypeScript build utility for multiple compile targets. |
| commands/build-tsc/src/tsconfig.json | Adds src-level TS config for build-tsc. |
| commands/build-tsc/src/tsc.ts | Adds the CLI subcommand wrapper for the TSC build step. |
| commands/build-tsc/renovate.json | Adds Renovate config for the build-tsc package. |
| commands/build-tsc/package.json | Adds new @tsparticles/cli-command-build-tsc package metadata and deps. |
| commands/build-tsc/eslint.config.js | Adds ESLint config for the build-tsc package. |
| commands/build-tsc/README.md | Adds README for the build-tsc package. |
| commands/build-tsc/.dependency-cruiser.cjs | Adds dependency-cruiser config for the build-tsc package. |
| commands/build-prettier/tsconfig.json | Adds TS config for the new build-prettier package. |
| commands/build-prettier/src/utils.ts | Implements Prettier formatting/check helpers. |
| commands/build-prettier/src/tsconfig.json | Adds src-level TS config for build-prettier. |
| commands/build-prettier/src/prettier.ts | Adds the CLI subcommand wrapper for the Prettier step. |
| commands/build-prettier/renovate.json | Adds Renovate config for the build-prettier package. |
| commands/build-prettier/package.json | Adds new @tsparticles/cli-command-build-prettier package metadata and deps. |
| commands/build-prettier/eslint.config.js | Adds ESLint config for the build-prettier package. |
| commands/build-prettier/README.md | Adds README for the build-prettier package. |
| commands/build-prettier/.dependency-cruiser.cjs | Adds dependency-cruiser config for the build-prettier package. |
| commands/build-eslint/tsconfig.json | Adds TS config for the new build-eslint package. |
| commands/build-eslint/src/utils.ts | Implements ESLint runner helper. |
| commands/build-eslint/src/tsconfig.json | Adds src-level TS config for build-eslint. |
| commands/build-eslint/src/eslint.ts | Adds the CLI subcommand wrapper for the ESLint step. |
| commands/build-eslint/renovate.json | Adds Renovate config for the build-eslint package. |
| commands/build-eslint/package.json | Adds new @tsparticles/cli-command-build-eslint package metadata and deps. |
| commands/build-eslint/eslint.config.js | Adds ESLint config for the build-eslint package. |
| commands/build-eslint/README.md | Adds README for the build-eslint package. |
| commands/build-eslint/.dependency-cruiser.cjs | Adds dependency-cruiser config for the build-eslint package. |
| commands/build-bundle/src/bundle.ts | Renames bundle subcommand to bundle:webpack and updates messages. |
| commands/build-bundle-rollup/tsconfig.json | Adds TS config for the new build-bundle-rollup package. |
| commands/build-bundle-rollup/src/utils.ts | Implements Rollup config discovery + bundling via @tsparticles/rollup-plugin. |
| commands/build-bundle-rollup/src/tsconfig.json | Adds src-level TS config for build-bundle-rollup. |
| commands/build-bundle-rollup/src/bundle-rollup.ts | Adds the CLI subcommand wrapper for Rollup bundling. |
| commands/build-bundle-rollup/renovate.json | Adds Renovate config for build-bundle-rollup. |
| commands/build-bundle-rollup/package.json | Adds new @tsparticles/cli-command-build-bundle-rollup package metadata and deps. |
| commands/build-bundle-rollup/eslint.config.js | Adds ESLint config for build-bundle-rollup. |
| commands/build-bundle-rollup/README.md | Adds README for the Rollup bundle command package. |
| commands/build-bundle-rollup/.dependency-cruiser.cjs | Reuses dependency-cruiser config from build-bundle. |
| README.md | Updates root documentation for Nx workspace usage and developer commands. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "targets": { | ||
| "build": { | ||
| "options": { | ||
| "main": "packages/nx-plugin/src/index.ts" | ||
| } | ||
| }, | ||
| "build:ci": { | ||
| "options": { | ||
| "main": "packages/nx-plugin/src/index.ts" | ||
| } | ||
| } |
| prettierCommand.action(async (argPath: string) => { | ||
| const opts = prettierCommand.opts(), | ||
| ci = !!opts["ci"], | ||
| silentOpt = opts["silent"] as string | boolean, | ||
| silent = silentOpt === "false" ? false : !!silentOpt || ci, | ||
| basePath = process.cwd(); | ||
|
|
||
| if (!existsSync(basePath)) { | ||
| throw new Error("Provided path does not exist"); | ||
| } | ||
|
|
||
| const srcPath = path.join(basePath, argPath); | ||
|
|
||
| if (!existsSync(srcPath)) { | ||
| throw new Error("Provided path does not exist"); | ||
| } |
| throw new Error("Dist files build failed"); | ||
| } | ||
|
|
||
| console.log("Bundle finished successfully!"); |
| ### Build in an Nx workspace | ||
|
|
||
| The `build` command can delegate to Nx targets when it detects an Nx workspace. | ||
|
|
||
| ```bash | ||
| tsparticles-cli build --nx | ||
| tsparticles-cli build --nx --clean --lint --tsc | ||
| tsparticles-cli build --legacy | ||
| pnpm nx run @tsparticles/cli-command-build:tsc | ||
| ``` | ||
|
|
||
| - `--nx`: forces Nx-target execution when required targets exist | ||
| - `--legacy`: disables Nx-aware mode and runs the original in-process pipeline | ||
| - default behavior in this workspace: with no granular flags, `build`/`build:ci` Nx aggregate targets are preferred when available | ||
|
|
| - `--legacy`: disables Nx-aware mode and runs the original in-process pipeline | ||
| - default behavior in this workspace: with no granular flags, `build`/`build:ci` Nx aggregate targets are preferred when available | ||
|
|
||
| Inside this repository, the local plugin `@tsparticles/cli-nx-plugin` augments package projects under `commands/*` and `packages/*` with canonical aliases like `clean`, `prettify`, `prettify:ci`, `tsc`, `bundle`, and `distfiles`. |
| const tscCommand = new Command("distfiles"); | ||
|
|
||
| tscCommand.description("Build the TypeScript files for tsParticles library"); |
| if (!(await buildTS(basePath, silent))) { | ||
| throw new Error("Dist files build failed"); | ||
| } | ||
|
|
||
| console.log("Bundle finished successfully!"); | ||
| }); |
| buildCommand.option("-t, --tsc", "Build the library using TypeScript", false); | ||
| buildCommand.option("--nx", "Prefer running Nx targets when available", false); | ||
|
|
||
| buildCommand.argument("[path]", `Path to the project root folder, default is "src"`, "src"); | ||
|
|
||
| buildCommand.action(async (argPath: string) => { | ||
| buildCommand.action((argPath: string) => { | ||
| const opts = buildCommand.opts(), | ||
| ci = !!opts["ci"], | ||
| all = | ||
| !!opts["all"] || | ||
| (!opts["bundle"] && | ||
| (!opts["bundleWebpack"] && | ||
| !opts["bundleRollup"] && | ||
| !opts["clean"] && | ||
| !opts["circularDeps"] && | ||
| !opts["dist"] && | ||
| !opts["lint"] && | ||
| !opts["prettify"] && | ||
| !opts["tsc"]), | ||
| doBundle = all || !!opts["bundle"], | ||
| circularDeps = all || !!opts["circularDeps"], | ||
| clean = all || !!opts["clean"], | ||
| distfiles = all || !!opts["dist"], | ||
| doLint = all || !!opts["lint"], | ||
| prettier = all || !!opts["prettify"], | ||
| tsc = all || !!opts["tsc"], | ||
| silentOpt = opts["silent"] as string | boolean, | ||
| silent = silentOpt === "false" ? false : !!silentOpt || ci, | ||
| basePath = process.cwd(), | ||
| { getDistStats } = await import("@tsparticles/cli-command-build-diststats"), | ||
| oldStats = await getDistStats(basePath); | ||
|
|
||
| if (clean) { | ||
| const { clearDist } = await import("@tsparticles/cli-command-build-clear"); | ||
|
|
||
| await clearDist(basePath, silent); | ||
| } | ||
|
|
||
| const srcPath = path.join(basePath, argPath); | ||
|
|
||
| if (!existsSync(srcPath)) { | ||
| throw new Error("Provided path does not exist"); | ||
| } | ||
|
|
||
| let canContinue = true; | ||
|
|
||
| if (prettier) { | ||
| const { prettifySrc } = await import("./build-prettier.js"); | ||
|
|
||
| canContinue = await prettifySrc(basePath, srcPath, ci, silent); | ||
| } | ||
|
|
||
| if (canContinue && doLint) { | ||
| const { lint } = await import("./build-eslint.js"); | ||
|
|
||
| canContinue = await lint(ci, silent); | ||
| } | ||
|
|
||
| if (canContinue && (tsc || circularDeps)) { | ||
| const checks: Promise<boolean>[] = []; | ||
|
|
||
| if (tsc) { | ||
| checks.push(import("./build-tsc.js").then(({ buildTS }) => buildTS(basePath, silent))); | ||
| } | ||
|
|
||
| if (circularDeps) { | ||
| checks.push( | ||
| import("@tsparticles/cli-command-build-circular-deps").then(({ circularDeps }) => | ||
| circularDeps(basePath, silent), | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| canContinue = (await Promise.all(checks)).every(result => result); | ||
| } | ||
|
|
||
| if (canContinue && doBundle) { | ||
| const { bundle } = await import("@tsparticles/cli-command-build-bundle"); | ||
|
|
||
| canContinue = await bundle(basePath, silent); | ||
| } | ||
|
|
||
| if (canContinue && prettier) { | ||
| const { prettifyReadme, prettifyPackageJson, prettifyPackageDistJson } = await import("./build-prettier.js"); | ||
|
|
||
| canContinue = | ||
| (await prettifyReadme(basePath, ci, silent)) && | ||
| (await prettifyPackageJson(basePath, ci, silent)) && | ||
| (await prettifyPackageDistJson(basePath, ci, silent)); | ||
| } | ||
|
|
||
| if (canContinue && distfiles) { | ||
| const { buildDistFiles } = await import("@tsparticles/cli-command-build-distfiles"); | ||
|
|
||
| canContinue = await buildDistFiles(basePath, silent); | ||
| } | ||
|
|
||
| if (!canContinue) { | ||
| throw new Error("Build failed"); | ||
| } | ||
|
|
||
| let texts: string[] = [], | ||
| outputFunc = console.info; | ||
|
|
||
| if (!silent) { | ||
| const newStats = await getDistStats(basePath), | ||
| diffSize = newStats.totalSize - oldStats.totalSize, | ||
| bundleDiffSize = newStats.bundleSize - oldStats.bundleSize, | ||
| minSize = 0, | ||
| bundleSizeIncreased = bundleDiffSize > minSize, | ||
| bundleSizeIncreasedText = bundleSizeIncreased ? "increased" : "decreased", | ||
| diffSizeIncreasedText = diffSize > minSize ? "increased" : "decreased"; | ||
|
|
||
| outputFunc = bundleSizeIncreased ? console.warn : console.info; | ||
|
|
||
| texts = [ | ||
| bundleDiffSize | ||
| ? `Bundle size ${bundleSizeIncreasedText} from ${oldStats.bundleSize.toString()} to ${newStats.bundleSize.toString()} (${Math.abs(bundleDiffSize).toString()}B)` | ||
| : "Bundle size unchanged", | ||
| diffSize | ||
| ? `Size ${diffSizeIncreasedText} from ${oldStats.totalSize.toString()} to ${newStats.totalSize.toString()} (${Math.abs(diffSize).toString()}B)` | ||
| : "Size unchanged", | ||
| `Files count changed from ${oldStats.totalFiles.toString()} to ${newStats.totalFiles.toString()} (${( | ||
| newStats.totalFiles - oldStats.totalFiles | ||
| ).toString()})`, | ||
| `Folders count changed from ${oldStats.totalFolders.toString()} to ${newStats.totalFolders.toString()} (${( | ||
| newStats.totalFolders - oldStats.totalFolders | ||
| ).toString()})`, | ||
| ]; | ||
| } | ||
|
|
||
| console.log("Build finished successfully!"); | ||
|
|
||
| if (!silent) { | ||
| for (const text of texts) { | ||
| outputFunc(text); | ||
| } | ||
| commandOptions: BuildExecutionOptions = { | ||
| all, | ||
| argPath, | ||
| basePath: process.cwd(), | ||
| ci: !!opts["ci"], | ||
| circularDeps: all || !!opts["circularDeps"], | ||
| clean: all || !!opts["clean"], | ||
| distfiles: all || !!opts["dist"], | ||
| doBundleRollup: !!opts["bundleRollup"], | ||
| doBundleWebpack: all || !!opts["bundleWebpack"], | ||
| doLint: all || !!opts["lint"], | ||
| prettier: all || !!opts["prettify"], | ||
| silent: silentOpt === "false" ? false : !!silentOpt || !!opts["ci"], | ||
| tsc: all || !!opts["tsc"], | ||
| useNx: !!opts["nx"], | ||
| }; | ||
|
|
||
| if (!tryRunNxBuild(commandOptions)) { | ||
| throw new Error("Nx build execution is required, but it cannot run inside an active Nx task context."); |
| @@ -2,9 +2,9 @@ import { Command } from "commander"; | |||
| import { bundle } from "./utils.js"; | |||
| import { existsSync } from "node:fs"; | |||
|
|
|||
| const bundleCommand = new Command("bundle"); | |||
| const bundleCommand = new Command("bundle:webpack"); | |||
|
|
|||
| throw new Error("Dist files build failed"); | ||
| } | ||
|
|
||
| console.log("Bundle finished successfully!"); |
…eslint-10.3.0 build(deps): bump eslint from 10.2.1 to 10.3.0
There was a problem hiding this comment.
Actionable comments posted: 13
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🟡 Minor comments (14)
commands/build-tsc/README.md-10-23 (1)
10-23:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winSame wrong package name as
commands/build-eslint/README.md.All install examples use
@particlesjs/cliinstead of@tsparticles/cli. The same fix described in thebuild-eslintREADME comment applies here.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-tsc/README.md` around lines 10 - 23, Replace the incorrect package name '@particlesjs/cli' with the correct '@tsparticles/cli' in this README's install examples (the npm, Yarn, and PNPM sections); search for the literal string '@particlesjs/cli' and update each occurrence to '@tsparticles/cli' so all three install command examples reflect the correct package.commands/build-eslint/README.md-10-23 (1)
10-23:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winWrong package name in install commands.
All install examples reference
@particlesjs/cli, but the package is published as@tsparticles/cli(perpackages/cli/package.jsonline 2). Runningnpm install -g@particlesjs/cli`` would install a different or non-existent package.Additionally, the content is an exact copy of the top-level CLI README — it shows only generic
buildandcreate presetcommands, with nothing specific to thebuild-eslintsubcommand this package implements.📝 Proposed fix for package name
### NPM ```bash -npm install -g `@particlesjs/cli` +npm install -g `@tsparticles/cli`Yarn
-yarn global add `@particlesjs/cli` +yarn global add `@tsparticles/cli`PNPM
-pnpm global add `@particlesjs/cli` +pnpm global add `@tsparticles/cli`</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@commands/build-eslint/README.mdaround lines 10 - 23, The README for the
build-eslint command incorrectly references the published CLI package name and
contains generic top-level CLI docs; update the install examples to use the
correct package name "@tsparticles/cli" (replace all occurrences of
"@particlesjs/cli" in the npm/yarn/pnpm install lines) and replace the copied
top-level CLI content with focused documentation for this package's subcommand
(describe usage of the build-eslint command, example invocations like
"tsparticles build-eslint [--fix] [--config ]", brief explanation
of options and expected outputs, and any package-specific notes) so the README
documents the actual build-eslint behavior rather than generic CLI commands.</details> </blockquote></details> <details> <summary>commands/build-bundle-rollup/tsconfig.json-46-46 (1)</summary><blockquote> `46-46`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_ **`skipLibCheck: true` is absent in `commands/build-eslint/tsconfig.json` but present here** This inconsistency means library declaration files are type-checked in `build-eslint` but skipped for `build-bundle-rollup`. If added to work around type incompatibilities in rollup's declaration files, add a comment explaining the reason. If added unintentionally, consider removing it to keep strict type checking uniform across packages. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@commands/build-bundle-rollup/tsconfig.jsonat line 46, The tsconfig key
"skipLibCheck" is present in the build-bundle-rollup tsconfig but absent in the
build-eslint tsconfig, causing inconsistent library declaration checking; either
remove "skipLibCheck": true from the build-bundle-rollup tsconfig to keep strict
checks consistent, or if it was added intentionally to work around incompatible
third-party declaration files, add an inline comment next to the "skipLibCheck"
entry explaining the specific issue and why the exception is required so
maintainers understand the rationale; update the corresponding tsconfig so both
packages follow the chosen approach.</details> </blockquote></details> <details> <summary>commands/build-eslint/tsconfig.json-3-4 (1)</summary><blockquote> `3-4`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_ **`outDir` and `rootDir` both set to `"."` with `composite: true`** With `include: ["src/**/*"]` and `outDir: "."`, running `tsc -p tsconfig.json` directly (or `tsc --build` on this project) emits `.js`/`.d.ts` files alongside the `.ts` sources under `src/`. This is the established pattern in this codebase where the parent config is a template and actual compilation flows through `src/tsconfig.json`; however, the parent's `composite: true` makes it a legitimate build target in `--build` mode, so its own `outDir` should point somewhere clean (e.g., `"dist"` or at minimum a separate directory from the sources). This pattern is repeated identically in `packages/nx-plugin/tsconfig.json` and `commands/build-bundle-rollup/tsconfig.json`. The same-directory `outDir`/`rootDir` also means TypeScript won't be able to distinguish emitted declarations from source files. <details> <summary>🔧 Proposed fix</summary> ```diff - "rootDir": ".", - "outDir": ".", + "rootDir": ".", + "outDir": "dist",Or alternatively, since this tsconfig is only a base template and never a direct build target, suppress its compilation entirely:
+ "files": [], "include": [ "src/**/*" ]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-eslint/tsconfig.json` around lines 3 - 4, The tsconfig has composite: true with rootDir and outDir both set to ".", causing emitted .js/.d.ts to land next to sources; update the tsconfig to point outDir to a separate directory (e.g., change "outDir" from "." to "dist") so emitted files are isolated (apply the same change to packages/nx-plugin/tsconfig.json and commands/build-bundle-rollup/tsconfig.json), or if this file is only a template, remove/switch off composite or add a noEmit flag to prevent it being a build target—adjust the "composite", "outDir", or "noEmit" keys accordingly to resolve the conflict.commands/build-bundle-rollup/package.json-3-3 (1)
3-3:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winPackage version
3.4.7is behind its own workspace sibling dependency floor of3.4.14.All
@tsparticles/*siblings require^3.4.14, yet this package declares version3.4.7. In a pnpm workspace the lockfile resolves correctly, but publishing this package with a lower version than its required sibling minima is confusing and may break consumers who install it outside the workspace. Bump to at least3.4.14to align with the rest of the monorepo.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-bundle-rollup/package.json` at line 3, The package.json "version" field is lower than the monorepo sibling floor; update the "version" value from 3.4.7 to at least 3.4.14 (matching the `@tsparticles/`* siblings' ^3.4.14 requirement), commit the change, and ensure any published metadata or release scripts that read the package.json "version" are consistent with this bump.commands/build-bundle/src/utils.ts-41-51 (1)
41-51:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winMissing
returnafterreject()lets execution fall through toresolve(true).When
stats.hasErrors()is true,reject()is called but control continues into the warnings check and then unconditionally callsresolve(true). JavaScript Promise semantics ensure the first settlement wins (so the Promise is correctly rejected), but the fallthrough is misleading: warnings are still logged for error builds and the deadresolve(true)call is confusing. Add areturnafter thereject()call.🐛 Proposed fix
if (stats.hasErrors()) { console.error(statsInfo.errors); - reject(new Error(statsInfo.errors?.map(error => error.message).join("\n"))); + reject(new Error(statsInfo.errors?.map(error => error.message).join("\n"))); + return; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-bundle/src/utils.ts` around lines 41 - 51, The error-handling branch inside the stats handling (the block checking stats.hasErrors()) currently calls reject(new Error(...)) but falls through to the warnings check and the final resolve(true); add a return immediately after the reject(...) in that stats.hasErrors() branch (the same block that logs console.error(statsInfo.errors) and calls reject(new Error(statsInfo.errors?.map(...).join("\n")))) so execution stops there and doesn't log warnings or call resolve(true) for errored builds.commands/build-tsc/src/tsc.ts-34-34 (1)
34-34:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winStale "Bundle" success message in a TypeScript compilation command.
console.info("Bundle finished successfully!")is a copy-over from the originalbundleCommand. Replace it with a message appropriate to TypeScript compilation.🐛 Proposed fix
- console.info("Bundle finished successfully!"); + console.info("TypeScript compilation finished successfully!");🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-tsc/src/tsc.ts` at line 34, Update the stale console.info message in the TypeScript compilation command: replace the current console.info("Bundle finished successfully!") call with a message that reflects TypeScript compilation (for example use "TypeScript compilation completed successfully" or similar) so the log no longer references "Bundle"; locate the console.info call in the tsc command implementation and change only the string content.commands/build-eslint/src/eslint.ts-24-29 (1)
24-29:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winCopy-paste error: wrong error message, wrong success message, and
console.loginstead ofconsole.infoThree issues in the action handler:
- Line 25:
"Dist files build failed"was copied from a distfiles command — should reflect an ESLint failure (e.g."ESLint check failed").- Line 28:
"Bundle finished successfully!"describes a bundle step, not an ESLint run.- Line 28:
console.logshould beconsole.infoto match the PR's unified logging convention across all commands.🐛 Proposed fix
if (!(await lint(ci, silent))) { - throw new Error("Dist files build failed"); + throw new Error("ESLint check failed"); } - console.log("Bundle finished successfully!"); + console.info("ESLint completed successfully!");🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-eslint/src/eslint.ts` around lines 24 - 29, Replace the incorrect messages and logger in the ESLint action handler: when lint(ci, silent) returns false, throw a new Error with a correct message like "ESLint check failed" instead of "Dist files build failed"; on success, replace the misleading "Bundle finished successfully!" text with an ESLint-appropriate message such as "ESLint check passed"; and use console.info instead of console.log for the success message to follow the project's unified logging convention (locate these changes around the lint(ci, silent) check and the subsequent success log in commands/build-eslint/src/eslint.ts).commands/build-bundle-rollup/src/utils.ts-63-73 (1)
63-73:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win
bundleResult.generate()result is silently discardedWhen
output.fileandoutput.dirare both absent,generate()computes the full in-memory bundle but the returnedRollupOutputis thrown away — making the call a pure waste of CPU and memory. Likely a misconfiguration; consider throwing to surface it rather than silently no-op'ing.💡 Proposed fix
async function writeRollupOutput( bundleResult: Awaited<ReturnType<typeof rollup>>, output: OutputOptions, ): Promise<void> { if (output.file || output.dir) { await bundleResult.write(output); return; } - await bundleResult.generate(output); + throw new Error("Rollup output is missing both 'file' and 'dir'; cannot write bundle"); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-bundle-rollup/src/utils.ts` around lines 63 - 73, The writeRollupOutput function currently calls bundleResult.generate(output) and discards the result when neither output.file nor output.dir is set; change it to surface this misconfiguration by validating the output options in writeRollupOutput: if output.file or output.dir is present, call bundleResult.write(output) and return as now; otherwise do NOT call bundleResult.generate — instead throw a clear Error (from writeRollupOutput) that includes context (e.g., stringify the output options) so callers see the invalid configuration rather than wasting CPU/memory; reference bundleResult.generate and the output parameter so the throw replaces the discarded generate call.commands/build-bundle/src/bundle-webpack.ts-26-28 (1)
26-28:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winSame
existsSync(process.cwd())dead code as inbundle-rollup.ts
process.cwd()always points to an existing directory; this guard is unreachable and should be removed (same fix as inbundle-rollup.tslines 26-28).🧹 Proposed fix
const opts = bundleWebpackCommand.opts(), ci = !!opts["ci"], silentOpt = opts["silent"] as string | boolean, silent = silentOpt === "false" ? false : !!silentOpt || ci, basePath = process.cwd(); - if (!existsSync(basePath)) { - throw new Error("Provided path does not exist"); - } - if (!(await bundleWebpack(basePath, silent))) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-bundle/src/bundle-webpack.ts` around lines 26 - 28, Remove the unreachable guard that checks filesystem existence for the current working directory: delete the if (!existsSync(basePath)) throw new Error("Provided path does not exist"); check (the one using existsSync/process.cwd()-derived basePath) in bundle-webpack.ts; if you still need to validate a user-supplied path, validate a real input path variable instead of process.cwd(), otherwise simply remove the dead check referencing basePath/existsSync.commands/build-prettier/src/prettier.ts-27-29 (1)
27-29:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win
existsSync(process.cwd())is alwaystrue— same dead code as in the bundle commandsIdentical to the unreachable guard noted in
bundle-rollup.ts. Remove to keep the logic clean.🧹 Proposed fix
const opts = prettierCommand.opts(), ci = !!opts["ci"], silentOpt = opts["silent"] as string | boolean, silent = silentOpt === "false" ? false : !!silentOpt || ci, basePath = process.cwd(); - if (!existsSync(basePath)) { - throw new Error("Provided path does not exist"); - } - const srcPath = path.join(basePath, argPath);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-prettier/src/prettier.ts` around lines 27 - 29, Remove the redundant reachability check that uses existsSync with the current working directory pattern: delete the if-block that checks existsSync(basePath) and throws new Error("Provided path does not exist"); instead rely on upstream validation or let downstream fs calls surface errors—locate the conditional using existsSync and the variable basePath in the module (e.g., the if (!existsSync(basePath)) { throw new Error(...) } block) and remove it to match the bundle-rollup.ts cleanup.commands/build-bundle-rollup/src/bundle-rollup.ts-26-28 (1)
26-28:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win
existsSync(process.cwd())is alwaystrue— dead code
process.cwd()returns the directory the current process is running in, which is guaranteed to exist. This guard can never trigger and should be removed to avoid misleading future readers. The same unreachable check is also present incommands/build-bundle/src/bundle-webpack.ts(line 26) andcommands/build-prettier/src/prettier.ts(line 27).🧹 Proposed fix
const opts = bundleRollupCommand.opts(), ci = !!opts["ci"], silentOpt = opts["silent"] as string | boolean, silent = silentOpt === "false" ? false : !!silentOpt || ci, basePath = process.cwd(); - if (!existsSync(basePath)) { - throw new Error("Provided path does not exist"); - } - if (!(await bundleRollup(basePath, silent))) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-bundle-rollup/src/bundle-rollup.ts` around lines 26 - 28, Remove the unreachable filesystem existence guard that calls existsSync(process.cwd()) (and similar checks) — locate the early check in bundle-rollup.ts (the if (!existsSync(basePath)) / existsSync(process.cwd()) pattern) and delete it from bundle-rollup.ts, bundle-webpack.ts, and prettier.ts; if you intended to validate a user-provided path, replace the check with a real validation against the user input variable (e.g., validate `basePath` or the CLI path arg) and throw a clear error only when that user-supplied path does not exist.README.md-66-66 (1)
66-66:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win
bundlealias is incorrect — the actual targets arebundle:rollupandbundle:webpack.The test file at
packages/nx-plugin/tests/create-nodes.test.ts(line 19-20) confirms the canonical aliases generated arebundle:rollupandbundle:webpack, not a singlebundletarget. Runningpnpm nx run <pkg>:bundlewill fail with "target not found".📝 Proposed fix
-Inside this repository, the local plugin `@tsparticles/cli-nx-plugin` augments package projects under `commands/*` and `packages/*` with canonical aliases like `clean`, `prettify`, `prettify:ci`, `tsc`, `bundle`, and `distfiles`. +Inside this repository, the local plugin `@tsparticles/cli-nx-plugin` augments package projects under `commands/*` and `packages/*` with canonical aliases like `clean`, `prettify`, `prettify:ci`, `tsc`, `bundle:webpack`, `bundle:rollup`, and `distfiles`.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` at line 66, The README incorrectly lists a single `bundle` alias; update the description to list the actual canonical targets `bundle:rollup` and `bundle:webpack` (as asserted by the test `create-nodes.test.ts`), replacing "bundle" with "bundle:rollup" and "bundle:webpack" so references to running `pnpm nx run <pkg>:bundle` are not misleading and reflect the real targets.commands/build/README.md-62-63 (1)
62-63:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winContradictory
--nxflag descriptionLine 62 says
--nxis "preserved for compatibility" and "the build flow is Nx-only," but line 63 says the "default behavior" is to resolve Nx targets. If--nxis merely a compatibility alias and the default already delegates to Nx, it's unclear when or why you would pass--nxat all. Additionally, the code block above (lines 58–59) shows--bundle-webpackand--bundle-rollupwithout--nx, which further muddies the distinction.Consider clarifying whether
--nxis a no-op (backward-compatible alias), an opt-in flag, or truly redundant given the new default behavior.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build/README.md` around lines 62 - 63, Clarify the README's description of the --nx flag: state explicitly whether --nx is a no-op backward-compatibility alias, an opt-in override, or redundant with the current default behavior that resolves Nx targets; update the sentence mentioning `--nx` to indicate its exact behavior (e.g., "preserved for compatibility (no-op alias)" or "force Nx mode when other bundlers might be chosen") and adjust the following "default behavior" line to remove ambiguity by saying "default: resolves and runs Nx targets (so passing `--nx` is optional/for-compatibility)" and add a short note explaining how `--bundle-webpack` and `--bundle-rollup` interact with `--nx` (whether they override it or can be used concurrently).
🧹 Nitpick comments (13)
tsconfig.json (1)
1-10: ⚡ Quick winConsider adding
strict: trueas a safe root default.The three-level hierarchy (root → intermediate → src) means strict settings live at the intermediate level, which is fine. However, if a new command package ever extends this root directly and skips the intermediate config, it will silently compile without strict mode. Adding
strict: truehere is a no-op for correctly structured packages (they re-declare strict options at the intermediate level) but prevents the silent regression for any future package that skips the intermediate level.🔒 Proposed addition
{ "compilerOptions": { "target": "ESNext", "module": "NodeNext", "moduleResolution": "NodeNext", "esModuleInterop": true, "allowSyntheticDefaultImports": true, - "types": ["node"] + "types": ["node"], + "strict": true } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tsconfig.json` around lines 1 - 10, Add "strict": true to the root tsconfig's compilerOptions to enforce strict type checking by default; update the tsconfig.json compilerOptions block (where "target", "module", "moduleResolution", "esModuleInterop", "allowSyntheticDefaultImports", and "types" are declared) to include strict: true so any package that extends the root but skips the intermediate config still compiles with strict checks.commands/build-bundle-rollup/renovate.json (1)
6-8: ⚡ Quick win
config:baseis deprecated — useconfig:recommendedinstead.
config:basewas renamed toconfig:recommendedin Renovate v36.config:recommendedis now Renovate's canonical default configuration. Renovate will raise its own config migration PR for this, but fixing it proactively avoids the noise. The same pattern appears in the siblingrenovate.jsonfiles added in this PR (commands/build-eslint,commands/build-prettier,commands/build-tsc) — they should all be updated together.⚙️ Proposed fix
{ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "baseBranches": [ "dev" ], "extends": [ - "config:base" + "config:recommended" ] }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-bundle-rollup/renovate.json` around lines 6 - 8, Update the Renovate preset from the deprecated "config:base" to "config:recommended": in commands/build-bundle-rollup/renovate.json replace the extends entry "config:base" with "config:recommended", and make the same change in the sibling files commands/build-eslint/renovate.json, commands/build-prettier/renovate.json, and commands/build-tsc/renovate.json so all Renovate configs use the current canonical default.commands/build-tsc/renovate.json (1)
6-8: ⚡ Quick win
config:baseis deprecated — useconfig:recommended.Same issue as
commands/build-eslint/renovate.json: the Renovate config validator flags this as"Config migration necessary"and outputs the corrected config with"config:recommended".♻️ Proposed fix
"extends": [ - "config:base" + "config:recommended" ]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-tsc/renovate.json` around lines 6 - 8, Replace the deprecated Renovate preset by updating the "extends" entry that currently contains "config:base" to use "config:recommended" instead; locate the "extends" array in the renovate.json (the element with value "config:base") and change that string to "config:recommended" so the config validator stops reporting "Config migration necessary".commands/build-eslint/renovate.json (1)
6-8: ⚡ Quick win
config:baseis deprecated — useconfig:recommendedinstead.The Renovate config validator explicitly warns
"Config migration necessary"whenconfig:baseis present, showing that"config:base"should be replaced with"config:recommended". Renovate renamedconfig:basetoconfig:recommendedin v36.♻️ Proposed fix
"extends": [ - "config:base" + "config:recommended" ]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-eslint/renovate.json` around lines 6 - 8, Replace the deprecated Renovate preset by updating the "extends" entry that currently contains "config:base" to "config:recommended"; locate the renovat e config's "extends" array (the string "config:base") and substitute it with "config:recommended" so the Renovate config validator no longer reports "Config migration necessary".commands/build-bundle-rollup/package.json (2)
36-59: ⚡ Quick winBuild/lint toolchain entries belong in
devDependencies, notdependencies.
eslint,prettier,typescript,dependency-cruiser,eslint-config-prettier,eslint-plugin-jsdoc,eslint-plugin-prettier,eslint-plugin-tsdoc,typescript-eslint, andrimrafare development-time tools used to build and validate this package's own source. Placing them independenciescauses every consumer that installs@tsparticles/cli-command-build-bundle-rollupto unnecessarily pull in the entire lint/compiler stack as transitive runtime dependencies.♻️ Proposed reorganization
"dependencies": { "@swc/core": "^1.15.32", - "@tsparticles/depcruise-config": "^3.4.14", - "@tsparticles/eslint-config": "^3.4.14", - "@tsparticles/prettier-config": "^3.4.14", "@tsparticles/rollup-plugin": "^3.4.14", - "@tsparticles/tsconfig": "^3.4.14", - "eslint": "^10.3.0", - "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^62.9.0", - "eslint-plugin-prettier": "^5.5.5", - "eslint-plugin-tsdoc": "^0.5.2", "klaw": "^4.1.0", "lookpath": "^1.2.3", - "dependency-cruiser": "^17.3.10", "path-scurry": "^2.0.2", - "prettier": "^3.8.3", - "prettier-plugin-multiline-arrays": "^4.1.7", "prompts": "^2.4.2", - "rimraf": "^6.1.3", "rollup": "^4.52.5", - "typescript": "^6.0.3", - "typescript-eslint": "^8.59.1" }, "devDependencies": { + "@tsparticles/depcruise-config": "^3.4.14", + "@tsparticles/eslint-config": "^3.4.14", + "@tsparticles/prettier-config": "^3.4.14", + "@tsparticles/tsconfig": "^3.4.14", "@types/estree": "^1.0.8", "@types/klaw": "^3.0.7", "@types/node": "^25.6.0", "@types/prompts": "^2.4.9", "browserslist": "^4.28.2", "commander": "^14.0.3", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", + "dependency-cruiser": "^17.3.10", + "eslint": "^10.3.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-jsdoc": "^62.9.0", + "eslint-plugin-prettier": "^5.5.5", + "eslint-plugin-tsdoc": "^0.5.2", + "prettier": "^3.8.3", + "prettier-plugin-multiline-arrays": "^4.1.7", + "rimraf": "^6.1.3", "ts-node": "^10.9.2", + "typescript": "^6.0.3", + "typescript-eslint": "^8.59.1", "vitest": "^4.1.5" },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-bundle-rollup/package.json` around lines 36 - 59, The package.json currently lists build and lint tools under "dependencies" which makes them runtime transitive deps; move the build/lint tool entries (eslint, prettier, typescript, dependency-cruiser, eslint-config-prettier, eslint-plugin-jsdoc, eslint-plugin-prettier, eslint-plugin-tsdoc, typescript-eslint, rimraf, swc-loader, `@swc/core`, prettier-plugin-multiline-arrays, and any other non-runtime tooling) from the "dependencies" object into "devDependencies" so only true runtime libs (e.g., rollup, prompts, klaw, lookpath, path-scurry) remain in "dependencies"; update package.json accordingly and run npm/yarn install to validate the lockfile changes.
26-27: 💤 Low value
build:ts:cjsnaming is misleading for an ESM package.With
"type": "module"set, TypeScript output is treated as ESM, not CJS. The:cjssuffix is confusing (it matches the pattern in the analogous webpack package but is semantically wrong here unless thetsconfigexplicitly emits.cjsextensions).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-bundle-rollup/package.json` around lines 26 - 27, The npm script name build:ts:cjs is misleading for an ESM package; rename the script to reflect ESM output (for example build:ts:esm) and update the dependent script build:ts to call the new name, or alternatively remove the :cjs suffix and keep a single build:ts script; adjust only the "build:ts" and "build:ts:cjs" script entries in package.json so names match the actual ESM output from tsc.commands/build-eslint/.dependency-cruiser.cjs (1)
1-382: ⚡ Quick winConsider re-exporting the shared config rather than duplicating it.
This file is a verbatim copy of
commands/build-prettier/.dependency-cruiser.cjs. The AI summary notes thatcommands/build-bundle-rollup/.dependency-cruiser.cjsalready re-exports@tsparticles/depcruise-configinstead of inlining the full template. Any future rule changes (e.g., adding a new forbidden pattern, adjusting severity) will need to be applied in both files manually.♻️ Proposed refactor — re-export the shared config
-/** `@type` {import('dependency-cruiser').IConfiguration} */ -module.exports = { - forbidden: [ - // ... (382 lines of duplicated config) - ], - options: { ... } -}; -// generated: dependency-cruiser@17.3.7 on 2026-01-28T14:30:16.611Z +const { default: baseConfig } = require("@tsparticles/depcruise-config"); + +/** `@type` {import('dependency-cruiser').IConfiguration} */ +module.exports = { + ...baseConfig, + options: { + ...baseConfig.options, + tsConfig: { fileName: "src/tsconfig.json" }, + }, +};🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-eslint/.dependency-cruiser.cjs` around lines 1 - 382, This file duplicates the full dependency-cruiser configuration inline instead of re-exporting the shared config; replace the large module.exports object with a single re-export of the shared config (i.e., set module.exports = require('@tsparticles/depcruise-config') or import and export it) so future rule changes live in one place; look for the top-level module.exports object in this file and swap it to re-export the package named '@tsparticles/depcruise-config'.commands/build-eslint/package.json (1)
5-5:build:ts:cjsscript name is misleading — outputs ESM, not CommonJS.The package is correctly configured for ESM:
tsconfig.jsonuses"module": "NodeNext", which emits ESM modules. The"type": "module"declaration (line 5) and"main": "dist/eslint.js"(line 71) are compatible with this output and will work correctly at runtime.However, the script name
build:ts:cjs(line 26) is misleading. It suggests CommonJS output but actually compiles to ESM. Consider renaming it tobuild:tsorbuild:ts:esmfor clarity.Additionally, for modern ESM packages, consider using the
"exports"field instead of"main"to provide explicit entry points and better tooling support.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build-eslint/package.json` at line 5, The npm script name "build:ts:cjs" is misleading because the package is ESM ("type": "module" and "main": "dist/eslint.js") and tsconfig emits ESM; rename the script "build:ts:cjs" to a clearer name such as "build:ts" or "build:ts:esm" in package.json and update any references (CI, docs, other npm scripts) to the old name; optionally add an "exports" field alongside or in place of "main" to explicitly declare entry points for modern ESM tooling.packages/nx-plugin/package.json (1)
27-44: ⚡ Quick winDev-only tools belong in
devDependencies, notdependenciesOnly
@nx/devkitis a genuine runtime dependency for this Nx plugin. Everything else (vitest,eslint,prettier,rimraf,typescript,typescript-eslint, alleslint-plugin-*,prettier-plugin-multiline-arrays, evennxitself) is only needed for linting, testing, and building. Although the package is"private": trueand won't be published to npm, placing these independenciesis semantically misleading and can lead to unintended installation overhead in workspace dependency hoisting.🔧 Proposed reorganization
"dependencies": { "@nx/devkit": "^22.7.1" }, "devDependencies": { "@tsparticles/eslint-config": "^3.4.14", "@tsparticles/prettier-config": "^3.4.14", "@tsparticles/tsconfig": "^3.4.14", + "@types/node": "^25.6.0", "eslint": "^10.3.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-jsdoc": "^62.9.0", "eslint-plugin-prettier": "^5.5.5", "eslint-plugin-tsdoc": "^0.5.2", "nx": "22.7.1", "prettier": "^3.8.3", "prettier-plugin-multiline-arrays": "^4.1.7", "rimraf": "^6.1.3", "typescript": "^6.0.3", "typescript-eslint": "^8.59.1", "vitest": "^4.1.5" - }, - "devDependencies": { - "@types/node": "^25.6.0" }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/nx-plugin/package.json` around lines 27 - 44, The package.json currently lists many dev-only tools under "dependencies"; move all non-runtime packages into "devDependencies" and keep only true runtime deps (e.g., "@nx/devkit") in "dependencies". Specifically, remove "vitest", "eslint", "eslint-config-prettier", "eslint-plugin-jsdoc", "eslint-plugin-prettier", "eslint-plugin-tsdoc", "prettier", "prettier-plugin-multiline-arrays", "rimraf", "typescript", "typescript-eslint", and "nx" from "dependencies" and add them under "devDependencies" instead, ensuring package.json reflects that only `@nx/devkit` remains as a runtime dependency.commands/build/src/nx-context.ts (1)
186-208: 💤 Low valueFallback project resolution may be slow for large workspaces.
This loop queries every remaining project via
nx show projectto find a match byroot. In large Nx workspaces, this could result in many subprocess invocations. However, this is a reasonable fallback for edge cases where the project name differs from both the directory name andpackage.jsonname.If performance becomes an issue, consider caching the full project list with roots in a single query using
nx show projects --json --with-targetor similar.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build/src/nx-context.ts` around lines 186 - 208, The fallback loop that calls runNxJsonCommand for each project (iterating remainingProjectNames and using toNxProjectDetails with "show project") is expensive for large workspaces; replace it by making a single query that returns all projects/roots (e.g., call runNxJsonCommand once with "show projects --json" or similar) and build a map of projectName -> root/targets, then find the matching project by comparing roots to absoluteBasePath; update the code that currently uses remainingProjectNames/toNxProjectDetails to consult this cached map and return the matched workspaceRoot/packageManager/projectName/targets instead of invoking runNxJsonCommand per project.commands/build/src/build.ts (1)
76-77: 💤 Low valueAsymmetric bundler behavior in
--allmode.When
--allis set,doBundleWebpackbecomestruebutdoBundleRollupremainsfalse. This means--alltriggers webpack bundling but not rollup bundling.If this is intentional (webpack is the primary bundler), consider documenting this in the
--alloption description. If both bundlers should be included,doBundleRollupshould also checkall.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@commands/build/src/build.ts` around lines 76 - 77, The current logic sets doBundleWebpack to all || !!opts["bundleWebpack"] but leaves doBundleRollup as !!opts["bundleRollup"], causing asymmetric behavior when all is true; update the doBundleRollup assignment to also respect the all flag (i.e., change doBundleRollup to all || !!opts["bundleRollup"]) so both bundlers run under --all, or if asymmetric behavior is intended, add a clear note to the --all option documentation explaining that --all triggers only webpack (reference the doBundleRollup and doBundleWebpack variables and the opts/all flags when making the change).packages/nx-plugin/src/canonical-targets.ts (2)
10-10: 💤 Low value
pnpmRunPrefixis hardcoded in target metadata.
metadata.runCommandis purely informational (shown in Nx Console), so this doesn't affect execution correctness. However, in a workspace that might ever be switched to npm or yarn, the hint would be misleading. Since the entire repo is pnpm-first and execution goes throughnx:run-scriptregardless of what the metadata says, this is cosmetic only.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/nx-plugin/src/canonical-targets.ts` at line 10, The metadata currently hardcodes pnpmRunPrefix ("pnpm run") which makes metadata.runCommand misleading for non-pnpm workspaces; update canonical-targets.ts to avoid the hardcoded pnpm hint by either deriving the prefix from the detected package manager or by using a generic hint (e.g., "npm run / yarn run / pnpm run" or simply "run") and replace usages of pnpmRunPrefix in the code that sets metadata.runCommand so the displayed hint is accurate regardless of package manager; look for the pnpmRunPrefix constant and where metadata.runCommand is built and change that logic accordingly.
101-109: 💤 Low value
isTsParticlesWorkspacePackage: logic is correct but hardcodes workspace topology.The path matching implicitly encodes the two allowed top-level directories (
commands/,packages/). If the monorepo ever gains a new top-level source directory, this function needs a matching update. Worth noting as a future maintenance touch-point; no change required now.Also,
normalizedPath.includes("/files/")requires a leading slash so it won't match a hypothetical root-levelfiles/…/package.jsonpath — but since such a path would also fail thestartsWithcheck, there is no logical gap.♻️ Optional: drive the allowlist from a constant to ease future extension
+const workspacePrefixes = ["commands/", "packages/"] as const; + export function isTsParticlesWorkspacePackage(packageJsonPath: string): boolean { const normalizedPath = packageJsonPath.replaceAll("\\", "/"); if (normalizedPath.includes("/files/")) { return false; } - return normalizedPath.startsWith("commands/") || normalizedPath.startsWith("packages/"); + return workspacePrefixes.some(prefix => normalizedPath.startsWith(prefix)); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/nx-plugin/src/canonical-targets.ts` around lines 101 - 109, The function isTsParticlesWorkspacePackage hardcodes allowed top-level dirs; define a constant array (e.g., CANONICAL_TOP_LEVEL_DIRS = ["commands/", "packages/"]) and replace the explicit startsWith checks with CANONICAL_TOP_LEVEL_DIRS.some(dir => normalizedPath.startsWith(dir)); keep the existing normalizedPath.includes("/files/") early-exit logic but move it above the array check so the behavior stays identical; update the function isTsParticlesWorkspacePackage to reference the new constant.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c4899e12-add2-4a6f-9e34-e6212ecf1499
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (76)
README.mdcommands/build-bundle-rollup/.dependency-cruiser.cjscommands/build-bundle-rollup/README.mdcommands/build-bundle-rollup/eslint.config.jscommands/build-bundle-rollup/package.jsoncommands/build-bundle-rollup/renovate.jsoncommands/build-bundle-rollup/src/bundle-rollup.tscommands/build-bundle-rollup/src/tsconfig.jsoncommands/build-bundle-rollup/src/utils.tscommands/build-bundle-rollup/tsconfig.jsoncommands/build-bundle/package.jsoncommands/build-bundle/src/bundle-webpack.tscommands/build-bundle/src/utils.tscommands/build-circular-deps/package.jsoncommands/build-circular-deps/src/circular-deps.tscommands/build-circular-deps/src/utils.tscommands/build-clear/package.jsoncommands/build-distfiles/package.jsoncommands/build-distfiles/src/distfiles.tscommands/build-distfiles/src/utils.tscommands/build-diststats/package.jsoncommands/build-eslint/.dependency-cruiser.cjscommands/build-eslint/README.mdcommands/build-eslint/eslint.config.jscommands/build-eslint/package.jsoncommands/build-eslint/renovate.jsoncommands/build-eslint/src/eslint.tscommands/build-eslint/src/tsconfig.jsoncommands/build-eslint/src/utils.tscommands/build-eslint/tsconfig.jsoncommands/build-prettier/.dependency-cruiser.cjscommands/build-prettier/README.mdcommands/build-prettier/eslint.config.jscommands/build-prettier/package.jsoncommands/build-prettier/renovate.jsoncommands/build-prettier/src/prettier.tscommands/build-prettier/src/tsconfig.jsoncommands/build-prettier/src/utils.tscommands/build-prettier/tsconfig.jsoncommands/build-tsc/.dependency-cruiser.cjscommands/build-tsc/README.mdcommands/build-tsc/eslint.config.jscommands/build-tsc/package.jsoncommands/build-tsc/renovate.jsoncommands/build-tsc/src/tsc.tscommands/build-tsc/src/tsconfig.jsoncommands/build-tsc/src/utils.tscommands/build-tsc/tsconfig.jsoncommands/build/README.mdcommands/build/package.jsoncommands/build/src/build-options.tscommands/build/src/build.tscommands/build/src/nx-context.tscommands/build/src/nx-plan.tscommands/build/src/nx-runner.tscommands/build/src/nx-targets.tscommands/build/src/nx-types.tscommands/build/tests/nx-plan.test.tscommands/build/vitest.config.tscommands/create-utils/package.jsoncommands/create/package.jsonnx.jsonpackage.jsonpackages/cli/package.jsonpackages/nx-plugin/README.mdpackages/nx-plugin/eslint.config.jspackages/nx-plugin/package.jsonpackages/nx-plugin/project.jsonpackages/nx-plugin/src/canonical-targets.tspackages/nx-plugin/src/create-nodes.tspackages/nx-plugin/src/index.tspackages/nx-plugin/src/tsconfig.jsonpackages/nx-plugin/tests/create-nodes.test.tspackages/nx-plugin/tsconfig.jsonpackages/nx-plugin/vitest.config.tstsconfig.json
| "prompts": "^2.4.2", | ||
| "rimraf": "^6.1.3", | ||
| "rollup": "^4.52.5", | ||
| "swc-loader": "^0.2.7", |
There was a problem hiding this comment.
swc-loader is a webpack loader and has no place in the rollup-bundle package.
swc-loader is webpack-specific — it integrates SWC into webpack's loader pipeline and cannot be used by rollup. The rollup package already has @swc/core as a direct runtime dependency; for SWC in rollup you would need a rollup plugin (e.g. rollup-plugin-swc3), not a webpack loader. Remove swc-loader from this package.
🐛 Proposed fix
- "swc-loader": "^0.2.7",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "swc-loader": "^0.2.7", |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@commands/build-bundle-rollup/package.json` at line 57, Remove the
webpack-specific dependency "swc-loader" from the package.json of the rollup
bundle package because it's not usable with Rollup; instead ensure the package
uses `@swc/core` (already present) or a Rollup plugin such as rollup-plugin-swc3
when SWC transforms are needed in the Rollup build. Locate the "swc-loader"
entry in package.json and delete that dependency, and if build tooling requires
SWC during bundling, add or document the appropriate Rollup plugin (e.g.,
rollup-plugin-swc3) rather than a webpack loader.
| try { | ||
| const configs = await loadRollupConfig(basePath); | ||
|
|
||
| for (const config of configs) { | ||
| const bundleResult = await rollup(config); | ||
| let outputs: OutputOptions[] = []; | ||
|
|
||
| if (config.output) { | ||
| outputs = Array.isArray(config.output) ? config.output : [config.output]; | ||
| } | ||
|
|
||
| if (outputs.length === emptyCount) { | ||
| throw new Error("Rollup config is missing output settings"); | ||
| } | ||
|
|
||
| for (const output of outputs) { | ||
| await writeRollupOutput(bundleResult, output); | ||
| } | ||
|
|
||
| await bundleResult.close(); | ||
| } | ||
| } catch (e) { | ||
| console.error(e); | ||
|
|
||
| return false; | ||
| } |
There was a problem hiding this comment.
bundleResult leaks when an error is thrown before close()
If the outputs.length === 0 guard at line 98 throws, or if writeRollupOutput (line 102) rejects, execution jumps directly to the outer catch block, which only logs and returns false — bundleResult.close() is never called. Rollup's RollupBuild can hold open file handles/watchers, so this is a real resource leak for any error path.
🛡️ Proposed fix – wrap output processing in try/finally
for (const config of configs) {
const bundleResult = await rollup(config);
let outputs: OutputOptions[] = [];
+ try {
if (config.output) {
outputs = Array.isArray(config.output) ? config.output : [config.output];
}
- if (outputs.length === emptyCount) {
+ if (outputs.length === 0) {
throw new Error("Rollup config is missing output settings");
}
for (const output of outputs) {
await writeRollupOutput(bundleResult, output);
}
-
- await bundleResult.close();
+ } finally {
+ await bundleResult.close();
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| try { | |
| const configs = await loadRollupConfig(basePath); | |
| for (const config of configs) { | |
| const bundleResult = await rollup(config); | |
| let outputs: OutputOptions[] = []; | |
| if (config.output) { | |
| outputs = Array.isArray(config.output) ? config.output : [config.output]; | |
| } | |
| if (outputs.length === emptyCount) { | |
| throw new Error("Rollup config is missing output settings"); | |
| } | |
| for (const output of outputs) { | |
| await writeRollupOutput(bundleResult, output); | |
| } | |
| await bundleResult.close(); | |
| } | |
| } catch (e) { | |
| console.error(e); | |
| return false; | |
| } | |
| try { | |
| const configs = await loadRollupConfig(basePath); | |
| for (const config of configs) { | |
| const bundleResult = await rollup(config); | |
| let outputs: OutputOptions[] = []; | |
| try { | |
| if (config.output) { | |
| outputs = Array.isArray(config.output) ? config.output : [config.output]; | |
| } | |
| if (outputs.length === 0) { | |
| throw new Error("Rollup config is missing output settings"); | |
| } | |
| for (const output of outputs) { | |
| await writeRollupOutput(bundleResult, output); | |
| } | |
| } finally { | |
| await bundleResult.close(); | |
| } | |
| } | |
| } catch (e) { | |
| console.error(e); | |
| return false; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@commands/build-bundle-rollup/src/utils.ts` around lines 86 - 111, When
iterating configs after loadRollupConfig, ensure RollupBuild resources aren't
leaked by wrapping the per-config processing (the call to rollup(config), the
outputs handling, and writeRollupOutput calls) in a try/finally so that
bundleResult.close() is always invoked; specifically, inside the loop where you
create const bundleResult = await rollup(config) (and before you inspect
outputs/ call writeRollupOutput), add a try { ... } finally { if (bundleResult
&& typeof bundleResult.close === "function") await bundleResult.close(); } to
guarantee close runs on both normal and error paths, and keep the existing outer
catch to log and return false.
| "rootDir": ".", | ||
| "outDir": "../dist" | ||
| }, | ||
| "references": [{ "path": "../" }], |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Find src/tsconfig.json files that reference their own parent directory.
# Expected result: Zero or only the files from this PR – indicating this is a systematic
# pattern to evaluate, not an isolated typo.
fd -g 'tsconfig.json' --full-path --search-path commands -E '*/node_modules/*' |
xargs -I{} sh -c '
dir=$(dirname {})
parent=$(dirname "$dir")
name=$(basename "$dir")
if [ "$name" = "src" ]; then
refs=$(python3 -c "
import json, sys
try:
d = json.load(open(sys.argv[1]))
print(json.dumps(d.get(\"references\", [])))
except: print(\"[]\")
" "{}")
echo "=== {} ==="
echo " references: $refs"
fi
'Repository: tsparticles/cli
Length of output: 41
🏁 Script executed:
# First, let's examine the file structure and actual tsconfig content
find commands/build-eslint -name 'tsconfig.json' -type f | sort
echo "=== Child tsconfig (src/tsconfig.json) ==="
cat commands/build-eslint/src/tsconfig.json
echo ""
echo "=== Parent tsconfig (commands/build-eslint/tsconfig.json) ==="
cat commands/build-eslint/tsconfig.jsonRepository: tsparticles/cli
Length of output: 1615
references: [{ "path": "../" }] creates a backwards project-reference that causes double compilation.
src/tsconfig.json extends ../tsconfig.json (which already includes src/**/* and has composite: true), then also declares a project reference back to that same parent. When tsc -p src or tsc --build is invoked, TypeScript must build the parent first (compiling all src/**/* files to the parent's outDir: "."), then build src/tsconfig.json (compiling the exact same files again to ../dist). TypeScript's own documentation warns about this pattern: "have a 'solution' tsconfig.json file that simply has references to all of your leaf-node projects and sets files to an empty array (otherwise the solution file will cause double compilation of files)." The reference here is inverted – the leaf pointing at the solution/parent – producing the exact double-compilation scenario the docs caution against.
The extends is sufficient to inherit all compiler options from the parent. The references entry should be removed unless there is a deliberate intent to produce two separate build outputs for the same files.
🔧 Proposed fix
{
"extends": "../tsconfig.json",
"compilerOptions": {
"rootDir": ".",
"outDir": "../dist"
},
- "references": [{ "path": "../" }],
"include": ["**/*"]
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@commands/build-eslint/src/tsconfig.json` at line 7, The "references": [{
"path": "../" }] entry in src/tsconfig.json creates a backwards
project-reference causing duplicate compilation; remove the references property
from src/tsconfig.json so it only relies on "extends": "../tsconfig.json" to
inherit compilerOptions and avoid double-building the same files, then run the
build (e.g., tsc -p src or tsc --build) to verify that files are no longer
compiled twice.
| "@tsparticles/eslint-config": "^3.4.14", | ||
| "@tsparticles/prettier-config": "^3.4.14", | ||
| "@tsparticles/tsconfig": "^3.4.14", | ||
| "eslint": "^10.3.0", |
There was a problem hiding this comment.
eslint belongs in devDependencies, not dependencies.
eslint is only invoked by the lint and lint:ci dev scripts. Placing it in dependencies ships ESLint as a mandatory transitive install for every downstream consumer of @tsparticles/cli-command-build-prettier, which is incorrect. Compare with commands/build-eslint/package.json, which correctly places eslint in peerDependencies/devDependencies only.
🐛 Proposed fix
"dependencies": {
"@swc/core": "^1.15.32",
- "eslint": "^10.3.0",
"eslint-config-prettier": "^10.1.8", "devDependencies": {
+ "eslint": "^10.3.0",
"@types/estree": "^1.0.8",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@commands/build-prettier/package.json` at line 42, Move the "eslint" entry out
of dependencies in package.json and add it to devDependencies instead: remove
the existing "eslint": "^10.3.0" line from the dependencies block and add the
same version under devDependencies so the lint and lint:ci dev scripts still
work but ESLint is not shipped as a runtime dependency of the package.
| } | ||
| } | ||
|
|
||
| console.info("Build completed successfully!"); |
There was a problem hiding this comment.
console.info on completion bypasses options.silent
All other informational logging (Line 31) is guarded by options.silent, but the completion message on Line 42 always prints, leaking output in silent mode (e.g., during programmatic/pipe usage or CI capturing).
🔧 Proposed fix
- console.info("Build completed successfully!");
+ if (!options.silent) {
+ console.info("Build completed successfully!");
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| console.info("Build completed successfully!"); | |
| if (!options.silent) { | |
| console.info("Build completed successfully!"); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@commands/build/src/nx-runner.ts` at line 42, The unconditional
console.info("Build completed successfully!") should be guarded by the existing
options.silent flag so it doesn't print in silent mode; update the console.info
call in nx-runner.ts to only log when options.silent is false (e.g., wrap it in
if (!options.silent) { ... } or use the same guarded logging path used for the
earlier info message), referencing the console.info call and the options.silent
variable to locate and change the code.
| "plugins": [ | ||
| "@tsparticles/cli-nx-plugin" | ||
| ], |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if the plugin is declared in the root package.json
echo "=== Root package.json deps ==="
cat package.json | python3 -c "
import json, sys
pkg = json.load(sys.stdin)
deps = {**pkg.get('dependencies', {}), **pkg.get('devDependencies', {})}
key = '@tsparticles/cli-nx-plugin'
print(f'{key}: {deps.get(key, \"NOT FOUND\")}')
"
# Also verify packages/nx-plugin has a matching package name
echo "=== nx-plugin package name ==="
fd "package.json" packages/nx-plugin --max-depth 1 --exec python3 -c "
import json, sys
with open('{}') as f:
pkg = json.load(f)
print(pkg.get('name', 'N/A'))
"Repository: tsparticles/cli
Length of output: 186
Add @tsparticles/cli-nx-plugin to root package.json devDependencies.
The plugin is referenced in nx.json but missing from the root package.json. Nx requires plugins to be resolvable from the workspace root's node_modules. Without adding "@tsparticles/cli-nx-plugin": "workspace:*" to root devDependencies, Nx will silently fail to load the plugin at workspace startup, and no canonical target aliases will be inferred.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@nx.json` around lines 34 - 36, Add the referenced plugin
"@tsparticles/cli-nx-plugin" to the root package.json devDependencies so Nx can
resolve it from the workspace root; open the root package.json and add an entry
like "@tsparticles/cli-nx-plugin": "workspace:*" under devDependencies, then run
npm/yarn install to ensure the plugin is present in node_modules and Nx can load
the plugin referenced in nx.json's "plugins" array.
| "build": "pnpm run prettify:src && pnpm run lint && pnpm run test && pnpm run prettify:readme", | ||
| "build:ci": "pnpm run prettify:ci:src && pnpm run lint:ci && pnpm run test:ci && pnpm run prettify:ci:readme", | ||
| "clear:dist": "rimraf ./dist", | ||
| "test": "vitest run", | ||
| "test:ci": "vitest run", | ||
| "prepack": "pnpm run build" |
There was a problem hiding this comment.
Build script has no TypeScript compilation step and "main" points to raw source
The build (and build:ci) scripts run prettify, lint, and test, but never invoke tsc. Combined with "main": "src/index.ts", this means the plugin's TypeScript is never compiled to JavaScript, and the Nx workspace plugin loader hits the .js-import resolution failure seen in CI. Either:
- Compile on build: add a
tscstep to both scripts and change"main"to point atdist/index.js, or - Source-only: configure the Nx workspace's module loader (e.g.,
tsx) to handle.ts→.jsremapping when loading plugins.
🔧 Proposed fix (compile-on-build approach)
- "build": "pnpm run prettify:src && pnpm run lint && pnpm run test && pnpm run prettify:readme",
- "build:ci": "pnpm run prettify:ci:src && pnpm run lint:ci && pnpm run test:ci && pnpm run prettify:ci:readme",
+ "build": "pnpm run prettify:src && pnpm run lint && pnpm run tsc && pnpm run test && pnpm run prettify:readme",
+ "build:ci": "pnpm run prettify:ci:src && pnpm run lint:ci && pnpm run tsc && pnpm run test:ci && pnpm run prettify:ci:readme",
+ "tsc": "tsc -p src/tsconfig.json",And update "main":
- "main": "src/index.ts",
+ "main": "dist/index.js",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "build": "pnpm run prettify:src && pnpm run lint && pnpm run test && pnpm run prettify:readme", | |
| "build:ci": "pnpm run prettify:ci:src && pnpm run lint:ci && pnpm run test:ci && pnpm run prettify:ci:readme", | |
| "clear:dist": "rimraf ./dist", | |
| "test": "vitest run", | |
| "test:ci": "vitest run", | |
| "prepack": "pnpm run build" | |
| "build": "pnpm run prettify:src && pnpm run lint && pnpm run tsc && pnpm run test && pnpm run prettify:readme", | |
| "build:ci": "pnpm run prettify:ci:src && pnpm run lint:ci && pnpm run tsc && pnpm run test:ci && pnpm run prettify:ci:readme", | |
| "tsc": "tsc -p src/tsconfig.json", | |
| "clear:dist": "rimraf ./dist", | |
| "test": "vitest run", | |
| "test:ci": "vitest run", | |
| "prepack": "pnpm run build" |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/nx-plugin/package.json` around lines 20 - 25, The build currently
runs prettify/lint/test but does not compile TypeScript and "main" points to
"src/index.ts"; update package.json so the build and build:ci scripts run tsc
(e.g., add a TypeScript compile step such as "pnpm run tsc:build" or directly
"tsc -p tsconfig.build.json") before prettify/ lint/tests (or place compilation
at the start), ensure the compiled output goes to dist, and change "main" from
"src/index.ts" to "dist/index.js"; also keep prepack invoking the build and
optionally run "clear:dist" before compiling to avoid stale artifacts
(referencing the build, build:ci, prepack, clear:dist and main entries).
| "build": { | ||
| "options": { | ||
| "main": "packages/nx-plugin/src/index.ts" | ||
| } | ||
| }, | ||
| "build:ci": { | ||
| "options": { | ||
| "main": "packages/nx-plugin/src/index.ts" | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm no executor is inherited from nx.json targetDefaults for the "build" target name
rg -n '"build"' nx.json -A 5 | head -40Repository: tsparticles/cli
Length of output: 187
🏁 Script executed:
#!/bin/bash
# Get full nx.json build target configuration
rg -n '"build"' nx.json -A 20 | head -80Repository: tsparticles/cli
Length of output: 476
🏁 Script executed:
#!/bin/bash
# Get the packages/nx-plugin/project.json file contents
cat packages/nx-plugin/project.jsonRepository: tsparticles/cli
Length of output: 437
Both build and build:ci targets are missing the executor field — TypeScript is never compiled
The main option alone is meaningless without an executor telling Nx how to use it. With no executor defined in either the project configuration or inherited from nx.json targetDefaults, Nx has no way to compile the TypeScript source to dist/, which is the root cause of the pipeline failure. The @nx/js:tsc executor (or equivalent) is required, along with outputPath and tsConfig.
🔧 Proposed fix
"build": {
+ "executor": "@nx/js:tsc",
"options": {
+ "outputPath": "packages/nx-plugin/dist",
+ "tsConfig": "packages/nx-plugin/src/tsconfig.json",
"main": "packages/nx-plugin/src/index.ts"
}
},
"build:ci": {
+ "executor": "@nx/js:tsc",
"options": {
+ "outputPath": "packages/nx-plugin/dist",
+ "tsConfig": "packages/nx-plugin/src/tsconfig.json",
"main": "packages/nx-plugin/src/index.ts"
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "build": { | |
| "options": { | |
| "main": "packages/nx-plugin/src/index.ts" | |
| } | |
| }, | |
| "build:ci": { | |
| "options": { | |
| "main": "packages/nx-plugin/src/index.ts" | |
| } | |
| } | |
| "build": { | |
| "executor": "@nx/js:tsc", | |
| "options": { | |
| "outputPath": "packages/nx-plugin/dist", | |
| "tsConfig": "packages/nx-plugin/src/tsconfig.json", | |
| "main": "packages/nx-plugin/src/index.ts" | |
| } | |
| }, | |
| "build:ci": { | |
| "executor": "@nx/js:tsc", | |
| "options": { | |
| "outputPath": "packages/nx-plugin/dist", | |
| "tsConfig": "packages/nx-plugin/src/tsconfig.json", | |
| "main": "packages/nx-plugin/src/index.ts" | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/nx-plugin/project.json` around lines 6 - 15, The build and build:ci
targets only define "main" and lack an "executor", so TypeScript is never
compiled; update both targets ("build" and "build:ci") to use the `@nx/js`:tsc
executor (or another appropriate Nx executor) and add the required options
"outputPath" (e.g., dist/<project>) and "tsConfig" (path to your
tsconfig.app.json) alongside the existing "main" so Nx can produce compiled
output; ensure the same changes apply to both target blocks.
| @@ -0,0 +1,9 @@ | |||
| import { createNodesV2 } from "./create-nodes.js"; | |||
There was a problem hiding this comment.
Pipeline failure: create-nodes.js not resolvable from TypeScript source — fix is in project.json and package.json
The CI error is:
Nx failed to load plugin(s):
@tsparticles/cli-nx-plugin. Cannot find module.../packages/nx-plugin/src/create-nodes.js
The .js extension in the import is correct TypeScript ESM convention, but Nx is loading src/index.ts directly (via "main": "src/index.ts" in package.json) without a TypeScript loader that remaps .js → .ts. Since no compiled .js file exists (there is no tsc step anywhere), resolution fails. The fixes are in project.json and package.json — see comments on those files.
🧰 Tools
🪛 GitHub Actions: Node.js CI
[error] 1-1: Nx failed to load plugin(s): @tsparticles/cli-nx-plugin. Cannot find module '/home/runner/work/cli/cli/packages/nx-plugin/src/create-nodes.js' imported from /home/runner/work/cli/cli/packages/nx-plugin/src/index.ts.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/nx-plugin/src/index.ts` at line 1, The import of createNodesV2 from
"./create-nodes.js" fails at runtime because Nx is loading the TypeScript source
(src/index.ts) directly and cannot resolve the .js extension to a .ts module;
update the package build/config so Nx loads the compiled output instead: change
the package.json "main" to point to a built JS entry (or remove pointing to
src), and update project.json targets (or outputs) to run a build step that
emits compiled .js files before Nx loads the plugin; ensure createNodesV2 still
imports the compiled create-nodes.js in the built package so runtime resolution
succeeds.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@commands/build-tsc/src/tsc.ts`:
- Around line 30-34: The success message currently always prints via
console.info after calling buildTS; change it to respect the silent flag by only
printing when silent is falsy (e.g., wrap the console.info call in if (!silent)
or use an existing logger that honors silent). Update the post-build block in
tsc.ts (after buildTS(basePath, silent)) so the "TypeScript build finished
successfully!" message is emitted only when silent is not set.
In `@commands/build/src/build.ts`:
- Around line 89-115: The default "all" build path currently omits Rollup
because doBundleRollup is set to !!opts["bundleRollup"] (only true for an
explicit flag); change the Rollup behavior so Rollup runs when the overall "all"
plan is active by updating commandOptions to set doBundleRollup: all ||
!!opts["bundleRollup"] (leave the existing all calculation and other option
mappings as-is); reference variables: all, doBundleRollup, opts, commandOptions.
- Around line 87-104: The buildCommand.action handler currently ignores the
argPath and sets commandOptions.basePath to process.cwd(); change this to derive
basePath from the provided argPath (falling back to the documented default) e.g.
use path.resolve(process.cwd(), argPath || "src") so the BuildExecutionOptions
passed from buildCommand.action uses the intended target directory; update any
downstream uses (dist-stat collection) that rely on commandOptions.basePath to
ensure they operate on the resolved basePath.
In `@commands/build/src/legacy-runner.ts`:
- Around line 128-135: The success messages are printed unconditionally causing
noise when silent mode is requested; wrap the success log in the
aggregate-script branch and the per-step branch with a check for options.silent
(i.e., only call console.info("Build completed successfully!") when
!options.silent). Locate the aggregate branch that calls runScript(...) with
aggregateScript and the per-step loop/branch around lines handling individual
step scripts and apply the same !options.silent guard so both paths respect
silent mode.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 570c5ac6-dd58-4d2c-afcd-20d547d28d3a
📒 Files selected for processing (9)
commands/build-tsc/src/tsc.tscommands/build/README.mdcommands/build/src/build.tscommands/build/src/legacy-runner.tscommands/build/src/nx-runner.tspackages/nx-plugin/src/create-nodes.tspackages/nx-plugin/src/index.tspackages/nx-plugin/src/tsconfig.jsonpackages/nx-plugin/tsconfig.json
✅ Files skipped from review due to trivial changes (1)
- packages/nx-plugin/src/tsconfig.json
| if (!(await buildTS(basePath, silent))) { | ||
| throw new Error("TypeScript build failed"); | ||
| } | ||
|
|
||
| console.log("Bundle finished successfully!"); | ||
| console.info("TypeScript build finished successfully!"); |
There was a problem hiding this comment.
Honor silent for the success message.
console.info still emits even when --silent is set, so quiet invocations leak output at the end of a successful build.
♻️ Proposed fix
- console.info("TypeScript build finished successfully!");
+ if (!silent) {
+ console.info("TypeScript build finished successfully!");
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (!(await buildTS(basePath, silent))) { | |
| throw new Error("TypeScript build failed"); | |
| } | |
| console.log("Bundle finished successfully!"); | |
| console.info("TypeScript build finished successfully!"); | |
| if (!(await buildTS(basePath, silent))) { | |
| throw new Error("TypeScript build failed"); | |
| } | |
| if (!silent) { | |
| console.info("TypeScript build finished successfully!"); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@commands/build-tsc/src/tsc.ts` around lines 30 - 34, The success message
currently always prints via console.info after calling buildTS; change it to
respect the silent flag by only printing when silent is falsy (e.g., wrap the
console.info call in if (!silent) or use an existing logger that honors silent).
Update the post-build block in tsc.ts (after buildTS(basePath, silent)) so the
"TypeScript build finished successfully!" message is emitted only when silent is
not set.
| buildCommand.action(async (argPath: string) => { | ||
| const opts = buildCommand.opts(), | ||
| ci = !!opts["ci"], | ||
| all = | ||
| !!opts["all"] || | ||
| (!opts["bundle"] && | ||
| (!opts["bundleWebpack"] && | ||
| !opts["bundleRollup"] && | ||
| !opts["clean"] && | ||
| !opts["circularDeps"] && | ||
| !opts["dist"] && | ||
| !opts["lint"] && | ||
| !opts["prettify"] && | ||
| !opts["tsc"]), | ||
| doBundle = all || !!opts["bundle"], | ||
| circularDeps = all || !!opts["circularDeps"], | ||
| clean = all || !!opts["clean"], | ||
| distfiles = all || !!opts["dist"], | ||
| doLint = all || !!opts["lint"], | ||
| prettier = all || !!opts["prettify"], | ||
| tsc = all || !!opts["tsc"], | ||
| silentOpt = opts["silent"] as string | boolean, | ||
| silent = silentOpt === "false" ? false : !!silentOpt || ci, | ||
| basePath = process.cwd(), | ||
| { getDistStats } = await import("@tsparticles/cli-command-build-diststats"), | ||
| oldStats = await getDistStats(basePath); | ||
|
|
||
| if (clean) { | ||
| const { clearDist } = await import("@tsparticles/cli-command-build-clear"); | ||
|
|
||
| await clearDist(basePath, silent); | ||
| } | ||
|
|
||
| const srcPath = path.join(basePath, argPath); | ||
|
|
||
| if (!existsSync(srcPath)) { | ||
| throw new Error("Provided path does not exist"); | ||
| } | ||
|
|
||
| let canContinue = true; | ||
|
|
||
| if (prettier) { | ||
| const { prettifySrc } = await import("./build-prettier.js"); | ||
|
|
||
| canContinue = await prettifySrc(basePath, srcPath, ci, silent); | ||
| } | ||
|
|
||
| if (canContinue && doLint) { | ||
| const { lint } = await import("./build-eslint.js"); | ||
|
|
||
| canContinue = await lint(ci, silent); | ||
| } | ||
|
|
||
| if (canContinue && (tsc || circularDeps)) { | ||
| const checks: Promise<boolean>[] = []; | ||
|
|
||
| if (tsc) { | ||
| checks.push(import("./build-tsc.js").then(({ buildTS }) => buildTS(basePath, silent))); | ||
| commandOptions: BuildExecutionOptions = { | ||
| all, | ||
| argPath, | ||
| basePath: process.cwd(), | ||
| ci: !!opts["ci"], |
There was a problem hiding this comment.
Use the path argument when deriving basePath.
build <path> currently ignores the argument and always targets process.cwd(), so both execution and dist-stat collection run against the wrong directory. The documented default of "src" never takes effect.
♻️ Proposed fix
+import path from "node:path";
...
- basePath: process.cwd(),
+ basePath: path.resolve(process.cwd(), argPath),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| buildCommand.action(async (argPath: string) => { | |
| const opts = buildCommand.opts(), | |
| ci = !!opts["ci"], | |
| all = | |
| !!opts["all"] || | |
| (!opts["bundle"] && | |
| (!opts["bundleWebpack"] && | |
| !opts["bundleRollup"] && | |
| !opts["clean"] && | |
| !opts["circularDeps"] && | |
| !opts["dist"] && | |
| !opts["lint"] && | |
| !opts["prettify"] && | |
| !opts["tsc"]), | |
| doBundle = all || !!opts["bundle"], | |
| circularDeps = all || !!opts["circularDeps"], | |
| clean = all || !!opts["clean"], | |
| distfiles = all || !!opts["dist"], | |
| doLint = all || !!opts["lint"], | |
| prettier = all || !!opts["prettify"], | |
| tsc = all || !!opts["tsc"], | |
| silentOpt = opts["silent"] as string | boolean, | |
| silent = silentOpt === "false" ? false : !!silentOpt || ci, | |
| basePath = process.cwd(), | |
| { getDistStats } = await import("@tsparticles/cli-command-build-diststats"), | |
| oldStats = await getDistStats(basePath); | |
| if (clean) { | |
| const { clearDist } = await import("@tsparticles/cli-command-build-clear"); | |
| await clearDist(basePath, silent); | |
| } | |
| const srcPath = path.join(basePath, argPath); | |
| if (!existsSync(srcPath)) { | |
| throw new Error("Provided path does not exist"); | |
| } | |
| let canContinue = true; | |
| if (prettier) { | |
| const { prettifySrc } = await import("./build-prettier.js"); | |
| canContinue = await prettifySrc(basePath, srcPath, ci, silent); | |
| } | |
| if (canContinue && doLint) { | |
| const { lint } = await import("./build-eslint.js"); | |
| canContinue = await lint(ci, silent); | |
| } | |
| if (canContinue && (tsc || circularDeps)) { | |
| const checks: Promise<boolean>[] = []; | |
| if (tsc) { | |
| checks.push(import("./build-tsc.js").then(({ buildTS }) => buildTS(basePath, silent))); | |
| commandOptions: BuildExecutionOptions = { | |
| all, | |
| argPath, | |
| basePath: process.cwd(), | |
| ci: !!opts["ci"], | |
| import path from "node:path"; | |
| buildCommand.action(async (argPath: string) => { | |
| const opts = buildCommand.opts(), | |
| all = | |
| !!opts["all"] || | |
| (!opts["bundleWebpack"] && | |
| !opts["bundleRollup"] && | |
| !opts["clean"] && | |
| !opts["circularDeps"] && | |
| !opts["dist"] && | |
| !opts["lint"] && | |
| !opts["prettify"] && | |
| !opts["tsc"]), | |
| silentOpt = opts["silent"] as string | boolean, | |
| commandOptions: BuildExecutionOptions = { | |
| all, | |
| argPath, | |
| basePath: path.resolve(process.cwd(), argPath), | |
| ci: !!opts["ci"], |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@commands/build/src/build.ts` around lines 87 - 104, The buildCommand.action
handler currently ignores the argPath and sets commandOptions.basePath to
process.cwd(); change this to derive basePath from the provided argPath (falling
back to the documented default) e.g. use path.resolve(process.cwd(), argPath ||
"src") so the BuildExecutionOptions passed from buildCommand.action uses the
intended target directory; update any downstream uses (dist-stat collection)
that rely on commandOptions.basePath to ensure they operate on the resolved
basePath.
| all = | ||
| !!opts["all"] || | ||
| (!opts["bundle"] && | ||
| (!opts["bundleWebpack"] && | ||
| !opts["bundleRollup"] && | ||
| !opts["clean"] && | ||
| !opts["circularDeps"] && | ||
| !opts["dist"] && | ||
| !opts["lint"] && | ||
| !opts["prettify"] && | ||
| !opts["tsc"]), | ||
| doBundle = all || !!opts["bundle"], | ||
| circularDeps = all || !!opts["circularDeps"], | ||
| clean = all || !!opts["clean"], | ||
| distfiles = all || !!opts["dist"], | ||
| doLint = all || !!opts["lint"], | ||
| prettier = all || !!opts["prettify"], | ||
| tsc = all || !!opts["tsc"], | ||
| silentOpt = opts["silent"] as string | boolean, | ||
| silent = silentOpt === "false" ? false : !!silentOpt || ci, | ||
| basePath = process.cwd(), | ||
| { getDistStats } = await import("@tsparticles/cli-command-build-diststats"), | ||
| oldStats = await getDistStats(basePath); | ||
|
|
||
| if (clean) { | ||
| const { clearDist } = await import("@tsparticles/cli-command-build-clear"); | ||
|
|
||
| await clearDist(basePath, silent); | ||
| } | ||
|
|
||
| const srcPath = path.join(basePath, argPath); | ||
|
|
||
| if (!existsSync(srcPath)) { | ||
| throw new Error("Provided path does not exist"); | ||
| } | ||
|
|
||
| let canContinue = true; | ||
|
|
||
| if (prettier) { | ||
| const { prettifySrc } = await import("./build-prettier.js"); | ||
|
|
||
| canContinue = await prettifySrc(basePath, srcPath, ci, silent); | ||
| } | ||
|
|
||
| if (canContinue && doLint) { | ||
| const { lint } = await import("./build-eslint.js"); | ||
|
|
||
| canContinue = await lint(ci, silent); | ||
| } | ||
|
|
||
| if (canContinue && (tsc || circularDeps)) { | ||
| const checks: Promise<boolean>[] = []; | ||
|
|
||
| if (tsc) { | ||
| checks.push(import("./build-tsc.js").then(({ buildTS }) => buildTS(basePath, silent))); | ||
| commandOptions: BuildExecutionOptions = { | ||
| all, | ||
| argPath, | ||
| basePath: process.cwd(), | ||
| ci: !!opts["ci"], | ||
| circularDeps: all || !!opts["circularDeps"], | ||
| clean: all || !!opts["clean"], | ||
| distfiles: all || !!opts["dist"], | ||
| doBundleRollup: !!opts["bundleRollup"], | ||
| doBundleWebpack: all || !!opts["bundleWebpack"], | ||
| doLint: all || !!opts["lint"], | ||
| prettier: all || !!opts["prettify"], | ||
| silent: silentOpt === "false" ? false : !!silentOpt || !!opts["ci"], | ||
| tsc: all || !!opts["tsc"], | ||
| useNx: !!opts["nx"], | ||
| }, |
There was a problem hiding this comment.
Include rollup in the default all build plan.
doBundleRollup is only enabled when the explicit flag is passed, so the no-flag/default build path skips the rollup bundle step.
♻️ Proposed fix
- doBundleRollup: !!opts["bundleRollup"],
+ doBundleRollup: all || !!opts["bundleRollup"],📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| all = | |
| !!opts["all"] || | |
| (!opts["bundle"] && | |
| (!opts["bundleWebpack"] && | |
| !opts["bundleRollup"] && | |
| !opts["clean"] && | |
| !opts["circularDeps"] && | |
| !opts["dist"] && | |
| !opts["lint"] && | |
| !opts["prettify"] && | |
| !opts["tsc"]), | |
| doBundle = all || !!opts["bundle"], | |
| circularDeps = all || !!opts["circularDeps"], | |
| clean = all || !!opts["clean"], | |
| distfiles = all || !!opts["dist"], | |
| doLint = all || !!opts["lint"], | |
| prettier = all || !!opts["prettify"], | |
| tsc = all || !!opts["tsc"], | |
| silentOpt = opts["silent"] as string | boolean, | |
| silent = silentOpt === "false" ? false : !!silentOpt || ci, | |
| basePath = process.cwd(), | |
| { getDistStats } = await import("@tsparticles/cli-command-build-diststats"), | |
| oldStats = await getDistStats(basePath); | |
| if (clean) { | |
| const { clearDist } = await import("@tsparticles/cli-command-build-clear"); | |
| await clearDist(basePath, silent); | |
| } | |
| const srcPath = path.join(basePath, argPath); | |
| if (!existsSync(srcPath)) { | |
| throw new Error("Provided path does not exist"); | |
| } | |
| let canContinue = true; | |
| if (prettier) { | |
| const { prettifySrc } = await import("./build-prettier.js"); | |
| canContinue = await prettifySrc(basePath, srcPath, ci, silent); | |
| } | |
| if (canContinue && doLint) { | |
| const { lint } = await import("./build-eslint.js"); | |
| canContinue = await lint(ci, silent); | |
| } | |
| if (canContinue && (tsc || circularDeps)) { | |
| const checks: Promise<boolean>[] = []; | |
| if (tsc) { | |
| checks.push(import("./build-tsc.js").then(({ buildTS }) => buildTS(basePath, silent))); | |
| commandOptions: BuildExecutionOptions = { | |
| all, | |
| argPath, | |
| basePath: process.cwd(), | |
| ci: !!opts["ci"], | |
| circularDeps: all || !!opts["circularDeps"], | |
| clean: all || !!opts["clean"], | |
| distfiles: all || !!opts["dist"], | |
| doBundleRollup: !!opts["bundleRollup"], | |
| doBundleWebpack: all || !!opts["bundleWebpack"], | |
| doLint: all || !!opts["lint"], | |
| prettier: all || !!opts["prettify"], | |
| silent: silentOpt === "false" ? false : !!silentOpt || !!opts["ci"], | |
| tsc: all || !!opts["tsc"], | |
| useNx: !!opts["nx"], | |
| }, | |
| all = | |
| !!opts["all"] || | |
| (!opts["bundleWebpack"] && | |
| !opts["bundleRollup"] && | |
| !opts["clean"] && | |
| !opts["circularDeps"] && | |
| !opts["dist"] && | |
| !opts["lint"] && | |
| !opts["prettify"] && | |
| !opts["tsc"]), | |
| silentOpt = opts["silent"] as string | boolean, | |
| commandOptions: BuildExecutionOptions = { | |
| all, | |
| argPath, | |
| basePath: process.cwd(), | |
| ci: !!opts["ci"], | |
| circularDeps: all || !!opts["circularDeps"], | |
| clean: all || !!opts["clean"], | |
| distfiles: all || !!opts["dist"], | |
| doBundleRollup: all || !!opts["bundleRollup"], | |
| doBundleWebpack: all || !!opts["bundleWebpack"], | |
| doLint: all || !!opts["lint"], | |
| prettier: all || !!opts["prettify"], | |
| silent: silentOpt === "false" ? false : !!silentOpt || !!opts["ci"], | |
| tsc: all || !!opts["tsc"], | |
| useNx: !!opts["nx"], | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@commands/build/src/build.ts` around lines 89 - 115, The default "all" build
path currently omits Rollup because doBundleRollup is set to
!!opts["bundleRollup"] (only true for an explicit flag); change the Rollup
behavior so Rollup runs when the overall "all" plan is active by updating
commandOptions to set doBundleRollup: all || !!opts["bundleRollup"] (leave the
existing all calculation and other option mappings as-is); reference variables:
all, doBundleRollup, opts, commandOptions.
| if (aggregateScript) { | ||
| if ( | ||
| !runScript(options.basePath, resolvePackageManager(packageJson.packageManager), aggregateScript, options.silent) | ||
| ) { | ||
| throw new Error(`Legacy build script failed: ${aggregateScript}`); | ||
| } | ||
|
|
||
| console.info("Build completed successfully!"); |
There was a problem hiding this comment.
Guard both success logs when silent is enabled.
Both the aggregate-script path and the per-step path print Build completed successfully! unconditionally, so quiet builds still emit stdout.
🔧 Proposed fix
- console.info("Build completed successfully!");
+ if (!options.silent) {
+ console.info("Build completed successfully!");
+ }
@@
- console.info("Build completed successfully!");
+ if (!options.silent) {
+ console.info("Build completed successfully!");
+ }Also applies to: 217-223
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@commands/build/src/legacy-runner.ts` around lines 128 - 135, The success
messages are printed unconditionally causing noise when silent mode is
requested; wrap the success log in the aggregate-script branch and the per-step
branch with a check for options.silent (i.e., only call console.info("Build
completed successfully!") when !options.silent). Locate the aggregate branch
that calls runScript(...) with aggregateScript and the per-step loop/branch
around lines handling individual step scripts and apply the same !options.silent
guard so both paths respect silent mode.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@commands/build-bundle-webpack/package.json`:
- Around line 10-14: Update the package.json repository metadata so the
repository.directory field points to the renamed package folder; specifically
change the "repository.directory" value from "commands/build-bundle" to
"commands/build-bundle-webpack" so published source links resolve to the correct
subdirectory.
In `@commands/build-bundle-webpack/src/bundle-webpack.ts`:
- Around line 19-35: The final success message is always printed even when
--silent or CI mode is requested; update the bundleWebpackCommand.action handler
to check the computed silent boolean (derived from opts, ci, and silentOpt)
before calling console.info so the success log is skipped when silent is true;
locate the silent calculation and the console.info("Webpack bundling completed
successfully!") call in bundleWebpackCommand.action and wrap or gate that
console.info behind an if (!silent) check (or equivalent) so the message
respects --silent/CI.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b926246f-e755-4a11-97f6-51e842088078
📒 Files selected for processing (9)
commands/build-bundle-webpack/.dependency-cruiser.cjscommands/build-bundle-webpack/README.mdcommands/build-bundle-webpack/eslint.config.jscommands/build-bundle-webpack/package.jsoncommands/build-bundle-webpack/renovate.jsoncommands/build-bundle-webpack/src/bundle-webpack.tscommands/build-bundle-webpack/src/tsconfig.jsoncommands/build-bundle-webpack/src/utils.tscommands/build-bundle-webpack/tsconfig.json
✅ Files skipped from review due to trivial changes (1)
- commands/build-bundle-webpack/src/tsconfig.json
| bundleWebpackCommand.action(async () => { | ||
| const opts = bundleWebpackCommand.opts(), | ||
| ci = !!opts["ci"], | ||
| silentOpt = opts["silent"] as string | boolean, | ||
| silent = silentOpt === "false" ? false : !!silentOpt || ci, | ||
| basePath = process.cwd(); | ||
|
|
||
| if (!existsSync(basePath)) { | ||
| throw new Error("Provided path does not exist"); | ||
| } | ||
|
|
||
| if (!(await bundleWebpack(basePath, silent))) { | ||
| throw new Error("Webpack bundling failed"); | ||
| } | ||
|
|
||
| console.info("Webpack bundling completed successfully!"); | ||
| }); |
There was a problem hiding this comment.
Respect --silent on the final success log.
This console.info still runs during --ci / --silent executions, so the command prints output even when the caller explicitly asked to suppress it.
♻️ Suggested fix
if (!(await bundleWebpack(basePath, silent))) {
throw new Error("Webpack bundling failed");
}
- console.info("Webpack bundling completed successfully!");
+ if (!silent) {
+ console.info("Webpack bundling completed successfully!");
+ }
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| bundleWebpackCommand.action(async () => { | |
| const opts = bundleWebpackCommand.opts(), | |
| ci = !!opts["ci"], | |
| silentOpt = opts["silent"] as string | boolean, | |
| silent = silentOpt === "false" ? false : !!silentOpt || ci, | |
| basePath = process.cwd(); | |
| if (!existsSync(basePath)) { | |
| throw new Error("Provided path does not exist"); | |
| } | |
| if (!(await bundleWebpack(basePath, silent))) { | |
| throw new Error("Webpack bundling failed"); | |
| } | |
| console.info("Webpack bundling completed successfully!"); | |
| }); | |
| bundleWebpackCommand.action(async () => { | |
| const opts = bundleWebpackCommand.opts(), | |
| ci = !!opts["ci"], | |
| silentOpt = opts["silent"] as string | boolean, | |
| silent = silentOpt === "false" ? false : !!silentOpt || ci, | |
| basePath = process.cwd(); | |
| if (!existsSync(basePath)) { | |
| throw new Error("Provided path does not exist"); | |
| } | |
| if (!(await bundleWebpack(basePath, silent))) { | |
| throw new Error("Webpack bundling failed"); | |
| } | |
| if (!silent) { | |
| console.info("Webpack bundling completed successfully!"); | |
| } | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@commands/build-bundle-webpack/src/bundle-webpack.ts` around lines 19 - 35,
The final success message is always printed even when --silent or CI mode is
requested; update the bundleWebpackCommand.action handler to check the computed
silent boolean (derived from opts, ci, and silentOpt) before calling
console.info so the success log is skipped when silent is true; locate the
silent calculation and the console.info("Webpack bundling completed
successfully!") call in bundleWebpackCommand.action and wrap or gate that
console.info behind an if (!silent) check (or equivalent) so the message
respects --silent/CI.
git-subtree-dir: utils git-subtree-split: 844ce3acd230539805aec182f78e4bc8b1126dd5
…mported into the main repo too
There was a problem hiding this comment.
Nx Cloud is proposing a fix for your failed CI:
We added a paths entry to commands/build-bundle-rollup/tsconfig.json to fix the ESLint no-unsafe-call and no-unsafe-return errors caused by TypeScript being unable to resolve @tsparticles/rollup-plugin types (its dist/ hasn't been built yet). By mapping the package directly to its workspace source at ../../utils/rollup-plugin/src/index.ts, TypeScript can now correctly type loadParticlesBundle as (p: ParticlesBuildParams) => RollupOptions[], satisfying both unsafe-call and unsafe-return rules without touching business logic.
Warning
❌ We could not verify this fix.
diff --git a/commands/build-bundle-rollup/tsconfig.json b/commands/build-bundle-rollup/tsconfig.json
index e0ed61e..d50d1be 100644
--- a/commands/build-bundle-rollup/tsconfig.json
+++ b/commands/build-bundle-rollup/tsconfig.json
@@ -2,6 +2,9 @@
"compilerOptions": {
"rootDir": ".",
"outDir": ".",
+ "paths": {
+ "@tsparticles/rollup-plugin": ["../../utils/rollup-plugin/src/index.ts"]
+ },
"resolveJsonModule": true,
"composite": true,
"target": "ESNext",
Or Apply changes locally with:
npx nx-cloud apply-locally rb16-uUdz
Apply fix locally with your editor ↗ View interactive diff ↗
🎓 Learn more about Self-Healing CI on nx.dev
Summary by CodeRabbit
New Features
Chores