Conversation
…e circular dependency check to use dependency-cruiser
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughThis PR introduces Dependency Cruiser as a replacement for Madge for circular dependency detection, updates Node.js module specifiers to use the Changes
Sequence DiagramsequenceDiagram
participant BuildSystem as Build System
participant DepCruiser as Dependency Cruiser
participant FileSystem as File System
participant Logger as Logger
BuildSystem->>FileSystem: Read .dependency-cruiser.js/cjs
FileSystem-->>BuildSystem: Config (or none)
BuildSystem->>BuildSystem: Build cruise options<br/>(merge config + defaults)
BuildSystem->>DepCruiser: cruise(src, cruiseOptions)
DepCruiser->>DepCruiser: Analyze dependencies<br/>& detect violations
DepCruiser-->>BuildSystem: Violation results
BuildSystem->>BuildSystem: Filter for no-circular
alt No circular deps found
BuildSystem->>Logger: Log success
BuildSystem-->>BuildSystem: Return true
else Circular deps found
BuildSystem->>Logger: Log cycle paths
BuildSystem-->>BuildSystem: Return false
end
Logger-->>BuildSystem: Output complete
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR updates the package version from 3.0.14 to 3.1.1 and includes several modernization improvements to the build toolchain and code formatting.
Changes:
- Replaced madge with dependency-cruiser for circular dependency detection
- Migrated from Babel to SWC for faster builds (added @swc/core and swc-loader, removed babel-loader and @babel/core)
- Standardized Node.js module imports to use
node:protocol (e.g.,node:path,node:child_process) - Reformatted code from 4-space to 2-space indentation throughout the codebase
- Updated various dependency versions and adjusted browserslist target from 2019 to 2021
Reviewed changes
Copilot reviewed 25 out of 31 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| package.json | Updated version to 3.1.1, replaced madge with dependency-cruiser, added SWC support, removed Babel dependencies, updated circular-deps script |
| tsconfig.json | Removed "madge" from types array as it's no longer a dependency |
| src/build/build-circular-deps.ts | Complete rewrite to use dependency-cruiser instead of madge with improved error reporting and configuration support |
| src/build/build-prettier.ts | Changed tabWidth from 4 to 2 and reformatted all code with 2-space indentation |
| src/**/*.ts | Standardized imports to use node: protocol for built-in modules and reformatted with 2-space indentation |
| tests/**/*.test.ts | Updated path imports to use node:path and reformatted with 2-space indentation |
| .dependency-cruiser.cjs | Added comprehensive dependency-cruiser configuration file with various rule definitions |
| pnpm-workspace.yaml | Added @swc/core to onlyBuiltDependencies for build optimization |
| files/empty-project/.browserslistrc | Updated browser support target from 2019 to 2021 |
| files/empty-project/package.json | Updated CLI and dependency versions, removed Babel dependencies |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In `@package.json`:
- Line 47: The package.json currently lists "dependency-cruiser" in dependencies
but it is a build-time tool used only by the "circular-deps" script; move the
"dependency-cruiser" entry from the top-level "dependencies" section into the
"devDependencies" section so it is treated as a dev-only dependency and not
installed for runtime consumers; update package.json by removing the
"dependency-cruiser" line from dependencies and adding the same entry (same
version string "^17.3.7") under "devDependencies".
In `@src/build/build-circular-deps.ts`:
- Around line 64-77: The default circular-check rule in the else branch that
sets cruiseOptions.ruleSet currently uses severity: "error" but the
.dependency-cruiser.cjs uses severity: "warn"; update the fallback in
build-circular-deps.ts (the else block that assigns cruiseOptions.ruleSet / the
"no-circular" rule) to use severity: "warn" (or otherwise match the config's
severity) so behavior is consistent whether or not a config file exists.
In `@src/build/build-prettier.ts`:
- Around line 115-125: Re-enable the CI formatting check by removing the
surrounding TODO/commented-out block and restoring the if (ci) branch: use
prettier.check(contents, options) when the ci flag is true and throw an Error if
it returns false (e.g., `package.dist.json is not formatted correctly`);
otherwise format via prettier.format(contents, options) and write the result
with fs.writeFile("package.dist.json", formatted, "utf8"). Make sure to keep the
existing variables/identifiers (ci, contents, options, prettier.check,
prettier.format, formatted, fs.writeFile) so CI will enforce formatting while
local runs still overwrite the file.
In `@src/create/plugin/create-plugin.ts`:
- Around line 96-139: The repoPath extraction in updateReadmeFile incorrectly
assumes repoUrl contains ".git"; update the logic in updateReadmeFile to
normalize repoUrl by stripping the protocol/host prefix (e.g., remove
"https://github.com/" or "http://github.com/" and optional "www.") and then
remove an optional trailing ".git" suffix before using it as repoPath; replace
the current substring/indexOf(".git") logic (references: repoUrl, stringSearch,
trailingSlashSearch, repoPath) with this normalized value and keep the existing
fallback ("tsparticles/plugin-template") if normalization yields an empty
string.
In `@src/create/preset/create-preset.ts`:
- Around line 148-151: The replacement string for the RegExp in create-preset.ts
is missing the closing brace/quote/backtick; update the `to` value so the
template interpolation is closed and the string is valid — e.g. change `to:
\`preset: "${camelizedName}\`` to `to: \`preset: "${camelizedName}"\`` (ensure
`${camelizedName}` is closed and the surrounding backtick/string quote is
present).
In `@src/create/shape/create-shape.ts`:
- Around line 135-138: The replacement string in the mapping object for
shape.type is missing the closing brace/quote around the template variable;
update the `to` value used alongside the `from: /shape\.type: "template"/g`
entry so the template variable `camelizedName` is properly closed (i.e., ensure
`${camelizedName}` is fully terminated inside the string literal) in the mapping
near create-shape.ts so the replacement produces a valid string `shape.type:
"..."`.
🧹 Nitpick comments (8)
src/cli.ts (1)
4-6: Inconsistent module specifier forurl.Line 4 imports
fileURLToPathfrom"url"without thenode:prefix, while line 6 uses"node:path". For consistency with the PR's goal of standardizing onnode:prefixed imports for built-ins, consider updating theurlimport as well.Suggested fix
-import { fileURLToPath } from "url"; +import { fileURLToPath } from "node:url";src/build/build-bundle.ts (1)
38-48: Pre-existing: Missingreturnafterreject.Note that after
reject(new Error(...))on line 41, there's noreturnstatement, soresolve(true)on line 48 will also be called. While JavaScript Promises ignore subsequent settlements, this pattern can cause confusion. This is a pre-existing issue, not introduced by this PR's formatting changes.Optional fix
if (stats.hasErrors()) { console.error(info.errors); reject(new Error(info.errors?.map(error => error.message).join("\n"))); + + return; }src/utils/file-utils.ts (1)
20-33: Preserve RegExp flags and validate pattern sources.
new RegExp(token.from, "g")drops any non‑gflags from RegExp inputs and treats string inputs as raw regex patterns. If callers depend on flags (e.g., case‑insensitive) or if strings can include metacharacters, behavior changes and safety risks increase. Please confirmtoken.fromis always trusted/static; otherwise consider preserving flags and escaping string inputs.💡 Suggested safer construction
+const escapeRegExp = (value: string): string => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + export async function replaceTokensInFiles(options: ReplaceTokensOptions[]): Promise<void> { for (const item of options) { const filePath = item.path; let data = await fs.readFile(filePath, "utf-8"); for (const token of item.tokens) { - const regex = new RegExp(token.from, "g"); + const regex = + token.from instanceof RegExp + ? new RegExp( + token.from.source, + token.from.flags.includes("g") ? token.from.flags : `${token.from.flags}g`, + ) + : new RegExp(escapeRegExp(token.from), "g"); data = data.replace(regex, token.to); } await fs.writeFile(filePath, data); } }src/build/build-circular-deps.ts (2)
31-77: Consider refactoring duplicated config loading logic.The config loading for
.dependency-cruiser.js(lines 32-47) and.dependency-cruiser.cjs(lines 48-63) are nearly identical. This could be extracted into a helper function.♻️ Proposed refactor
+async function loadConfig(configPath: string, cruiseOptions: ICruiseOptions): Promise<ICruiseOptions> { + const configModule = (await import(configPath)) as { + default: { + forbidden?: IForbiddenRuleType[]; + options?: ICruiseOptions; + }; + }, + extendedConfig = configModule.default; + + return { + ...cruiseOptions, + ...extendedConfig.options, + ruleSet: { + forbidden: extendedConfig.forbidden ?? [], + }, + }; +} // Then in buildCircularDeps: try { if (await fs.pathExists(configPath)) { - const configModule = (await import(configPath)) as { - default: { - forbidden?: IForbiddenRuleType[]; - options?: ICruiseOptions; - }; - }, - extendedConfig = configModule.default; - - cruiseOptions = { - ...cruiseOptions, - ...extendedConfig.options, - ruleSet: { - forbidden: extendedConfig.forbidden ?? [], - }, - }; + cruiseOptions = await loadConfig(configPath, cruiseOptions); } else if (await fs.pathExists(configPathCjs)) { - const configModule = (await import(configPathCjs)) as { - default: { - forbidden?: IForbiddenRuleType[]; - options?: ICruiseOptions; - }; - }, - extendedConfig = configModule.default; - - cruiseOptions = { - ...cruiseOptions, - ...extendedConfig.options, - ruleSet: { - forbidden: extendedConfig.forbidden ?? [], - }, - }; + cruiseOptions = await loadConfig(configPathCjs, cruiseOptions); } else {
87-93: Remove unnecessary type assertion on cycle step.Since
violation.cycleis already typed asIMiniDependency[]from dependency-cruiser (which has anameproperty), the inline type assertion is unnecessary.♻️ Proposed improvement
for (const violation of circularViolations) { - const cyclePath = (violation.cycle ?? []).map(step => { - return (step as { name: string }).name; - }); + const cyclePath = (violation.cycle ?? []).map(step => step.name); console.error(`Cycle detected: ${cyclePath.join(" -> ")}`); }src/build/build-distfiles.ts (1)
29-33: Clarify the dependency copying logic.The
else ifmeans only one ofdependenciesorpeerDependenciesgets copied to the dist package. If a package has both,peerDependencieswill be ignored. If this is intentional, a comment would help clarify the design decision.📝 Suggested comment
+ // Copy dependencies first; if none exist, fall back to peerDependencies + // Note: If both exist, only dependencies is used (peerDependencies are typically + // expected to be provided by the consuming project) if (pkgInfo.dependencies) { libObj["dependencies"] = JSON.parse(JSON.stringify(pkgInfo.dependencies).replaceAll("workspace:", "")); } else if (pkgInfo.peerDependencies) { libObj["peerDependencies"] = JSON.parse(JSON.stringify(pkgInfo.peerDependencies).replaceAll("workspace:", "")); }src/build/build-prettier.ts (1)
193-222: Simplify the early return flow.The pattern of setting
res = truewhen folder doesn't exist, then checkingif (!res)is a bit convoluted. Consider using early return for clarity.♻️ Suggested simplification
try { const folder = "traduction", folderPath = path.join(basePath, folder); - if (!fs.existsSync(folderPath)) { - res = true; - } - - if (!res) { + if (!fs.existsSync(folderPath)) { + console.log("Prettier - done on traductions (folder not found)"); + return true; + } + for await (const file of klaw(folderPath)) { // ... loop body } res = true; - } } catch (e) {src/build/build.ts (1)
49-51: Inconsistent path module import.Line 49 uses
await import("path")while other files in this PR have migrated tonode:path. For consistency, consider updating this dynamic import as well.♻️ Proposed fix
- const path = await import("path"), + const path = await import("node:path"), srcPath = path.join(basePath, argPath), fs = await import("fs-extra");
| "klaw": "^4.1.0", | ||
| "lookpath": "^1.2.3", | ||
| "madge": "^8.0.0", | ||
| "dependency-cruiser": "^17.3.7", |
There was a problem hiding this comment.
Move dependency-cruiser to devDependencies.
dependency-cruiser is used only in the circular-deps script for validating the CLI's own codebase during development/build. It's not a runtime dependency needed by CLI users. It should be in devDependencies like other build-time tools.
Proposed fix
Move line 47 to the devDependencies section:
"dependencies": {
...
- "dependency-cruiser": "^17.3.7",
...
},
"devDependencies": {
+ "dependency-cruiser": "^17.3.7",
...
}🤖 Prompt for AI Agents
In `@package.json` at line 47, The package.json currently lists
"dependency-cruiser" in dependencies but it is a build-time tool used only by
the "circular-deps" script; move the "dependency-cruiser" entry from the
top-level "dependencies" section into the "devDependencies" section so it is
treated as a dev-only dependency and not installed for runtime consumers; update
package.json by removing the "dependency-cruiser" line from dependencies and
adding the same entry (same version string "^17.3.7") under "devDependencies".
| } else { | ||
| console.log("No .dependency-cruiser.js found, applying default circular check."); | ||
|
|
||
| cruiseOptions.ruleSet = { | ||
| forbidden: [ | ||
| { | ||
| name: "no-circular", | ||
| severity: "error", | ||
| from: {}, | ||
| to: { circular: true }, | ||
| }, | ||
| ], | ||
| }; | ||
| } |
There was a problem hiding this comment.
Severity inconsistency between default and config file.
The default fallback uses severity: "error" (line 71), but the .dependency-cruiser.cjs config file uses severity: "warn". This could lead to different behavior depending on whether a config file exists. Consider aligning these for consistent behavior.
🤖 Prompt for AI Agents
In `@src/build/build-circular-deps.ts` around lines 64 - 77, The default
circular-check rule in the else branch that sets cruiseOptions.ruleSet currently
uses severity: "error" but the .dependency-cruiser.cjs uses severity: "warn";
update the fallback in build-circular-deps.ts (the else block that assigns
cruiseOptions.ruleSet / the "no-circular" rule) to use severity: "warn" (or
otherwise match the config's severity) so behavior is consistent whether or not
a config file exists.
| // TODO: disabled this check until "prettier-plugin-multiline-arrays" package is compatible with Prettier 3.0.0 | ||
|
|
||
| /* if (ci) { | ||
| /* if (ci) { | ||
| if (!(await prettier.check(contents, options))) { | ||
| throw new Error(`package.dist.json is not formatted correctly`); | ||
| } | ||
| } else { */ | ||
| const formatted = await prettier.format(contents, options); | ||
| const formatted = await prettier.format(contents, options); | ||
|
|
||
| await fs.writeFile("package.dist.json", formatted, "utf8"); | ||
| // } | ||
| await fs.writeFile("package.dist.json", formatted, "utf8"); | ||
| // } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
prettier-plugin-multiline-arrays Prettier 3 support compatibility
💡 Result:
prettier-plugin-multiline-arrays does support Prettier 3, as long as you use a recent version of the plugin:
- Latest (v4.1.3) declares
peerDependenciesofprettier: ">=3.0.0 <4.0.0", so it’s intended to work with all Prettier 3.x releases. It’s also ESM-only ("type": "module") and requires Node >= 20. [1] - This aligns with Prettier 3’s plugin API changes (including ESM plugin support), which is why older Prettier-2-era plugins often needed updates. [2]
If you’re on Prettier 3 and hit install warnings/errors, ensure you’re on plugin v4.x (preferably latest) and running Node 20+. [1]
Sources: [1], [2]
Re-enable the CI format check—the plugin now supports Prettier 3.
The prettier-plugin-multiline-arrays package (v4.1.3+) now explicitly supports Prettier 3 with peerDependencies of prettier: ">=3.0.0 <4.0.0". The TODO blocking the CI check is outdated. Remove the comment and restore the check to ensure package.dist.json is properly formatted on CI.
🤖 Prompt for AI Agents
In `@src/build/build-prettier.ts` around lines 115 - 125, Re-enable the CI
formatting check by removing the surrounding TODO/commented-out block and
restoring the if (ci) branch: use prettier.check(contents, options) when the ci
flag is true and throw an Error if it returns false (e.g., `package.dist.json is
not formatted correctly`); otherwise format via prettier.format(contents,
options) and write the result with fs.writeFile("package.dist.json", formatted,
"utf8"). Make sure to keep the existing variables/identifiers (ci, contents,
options, prettier.check, prettier.format, formatted, fs.writeFile) so CI will
enforce formatting while local runs still overwrite the file.
| async function updateReadmeFile(destPath: string, name: string, description: string, repoUrl: string): Promise<void> { | ||
| const readmePath = path.join(destPath, "README.md"), | ||
| capitalizedName = capitalize(name, "-", " "), | ||
| camelizedName = camelize(capitalizedName), | ||
| dashedName = dash(camelizedName), | ||
| stringSearch = "github.com", | ||
| trailingSlashSearch = "github.com/", | ||
| repoPath = repoUrl.includes(stringSearch) | ||
| ? repoUrl.substring( | ||
| repoUrl.indexOf(trailingSlashSearch) + trailingSlashSearch.length, | ||
| repoUrl.indexOf(".git"), | ||
| ) | ||
| : "tsparticles/plugin-template"; | ||
| const readmePath = path.join(destPath, "README.md"), | ||
| capitalizedName = capitalize(name, "-", " "), | ||
| camelizedName = camelize(capitalizedName), | ||
| dashedName = dash(camelizedName), | ||
| stringSearch = "github.com", | ||
| trailingSlashSearch = "github.com/", | ||
| repoPath = repoUrl.includes(stringSearch) | ||
| ? repoUrl.substring(repoUrl.indexOf(trailingSlashSearch) + trailingSlashSearch.length, repoUrl.indexOf(".git")) | ||
| : "tsparticles/plugin-template"; | ||
|
|
||
| await replaceTokensInFile({ | ||
| path: readmePath, | ||
| tokens: [ | ||
| { | ||
| from: /tsParticles Template Plugin/g, | ||
| to: `tsParticles ${description} Plugin`, | ||
| }, | ||
| { | ||
| from: /tsparticles-plugin-template/g, | ||
| to: `tsparticles-plugin-${dashedName}`, | ||
| }, | ||
| { | ||
| from: /tsparticles\.plugin\.template(\.bundle)?\.min\.js/g, | ||
| to: `tsparticles.plugin.${camelizedName}$1.min.js`, | ||
| }, | ||
| { | ||
| from: /loadTemplatePlugin/g, | ||
| to: `load${capitalizedName}Plugin`, | ||
| }, | ||
| { | ||
| from: /\[tsParticles]\(https:\/\/github.com\/matteobruni\/tsparticles\) additional template plugin\./g, | ||
| to: `[tsParticles](https://github.com/matteobruni/tsparticles) additional ${name} plugin.`, | ||
| }, | ||
| { | ||
| from: /plugin\.type: "template"/g, | ||
| to: `plugin.type: "${camelizedName}"`, | ||
| }, | ||
| { | ||
| from: /!\[demo]\(https:\/\/raw.githubusercontent.com\/tsparticles\/plugin-template\/main\/images\/sample.png\)/g, | ||
| to: ``, | ||
| }, | ||
| ], | ||
| }); | ||
| await replaceTokensInFile({ | ||
| path: readmePath, | ||
| tokens: [ | ||
| { | ||
| from: /tsParticles Template Plugin/g, | ||
| to: `tsParticles ${description} Plugin`, | ||
| }, | ||
| { | ||
| from: /tsparticles-plugin-template/g, | ||
| to: `tsparticles-plugin-${dashedName}`, | ||
| }, | ||
| { | ||
| from: /tsparticles\.plugin\.template(\.bundle)?\.min\.js/g, | ||
| to: `tsparticles.plugin.${camelizedName}$1.min.js`, | ||
| }, | ||
| { | ||
| from: /loadTemplatePlugin/g, | ||
| to: `load${capitalizedName}Plugin`, | ||
| }, | ||
| { | ||
| from: /\[tsParticles]\(https:\/\/github.com\/matteobruni\/tsparticles\) additional template plugin\./g, | ||
| to: `[tsParticles](https://github.com/matteobruni/tsparticles) additional ${name} plugin.`, | ||
| }, | ||
| { | ||
| from: /plugin\.type: "template"/g, | ||
| to: `plugin.type: "${camelizedName}"`, | ||
| }, | ||
| { | ||
| from: /!\[demo]\(https:\/\/raw.githubusercontent.com\/tsparticles\/plugin-template\/main\/images\/sample.png\)/g, | ||
| to: ``, | ||
| }, | ||
| ], | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's examine the file to understand the full context
cat -n src/create/plugin/create-plugin.ts | sed -n '90,145p'Repository: tsparticles/cli
Length of output: 2524
🏁 Script executed:
# Search for any tests related to updateReadmeFile
fd -type f -name "*.test.ts" -o -name "*.spec.ts" | xargs rg -l "updateReadmeFile|create-plugin" 2>/dev/null || echo "No test files found"Repository: tsparticles/cli
Length of output: 405
🏁 Script executed:
# Let's verify JavaScript substring behavior with -1
node << 'EOF'
// Test substring behavior with indexOf returning -1
const url = "https://github.com/user/repo";
const withGit = "https://github.com/user/repo.git";
const trailingSlashSearch = "github.com/";
const startIdx = url.indexOf(trailingSlashSearch) + trailingSlashSearch.length;
const endIdx = url.indexOf(".git");
console.log("URL without .git:", url);
console.log("startIdx:", startIdx);
console.log("endIdx:", endIdx);
console.log("substring result:", url.substring(startIdx, endIdx));
console.log("substring result is empty:", url.substring(startIdx, endIdx) === "");
console.log("\nURL with .git:", withGit);
console.log("startIdx:", withGit.indexOf(trailingSlashSearch) + trailingSlashSearch.length);
console.log("endIdx:", withGit.indexOf(".git"));
console.log("substring result:", withGit.substring(withGit.indexOf(trailingSlashSearch) + trailingSlashSearch.length, withGit.indexOf(".git")));
EOFRepository: tsparticles/cli
Length of output: 301
🏁 Script executed:
# Check if there are any actual calls to this function to understand if URLs without .git are realistic
rg "updateReadmeFile|repoUrl" src/create/plugin/create-plugin.ts -B 3 -A 3Repository: tsparticles/cli
Length of output: 2851
🏁 Script executed:
# Check the test file for coverage of updateReadmeFile and URL handling
cat -n tests/create-plugin.test.ts | head -100Repository: tsparticles/cli
Length of output: 1603
🏁 Script executed:
# Search for test cases that might test URLs with and without .git
rg "updateReadmeFile|repoUrl|\.git" tests/create-plugin.test.ts -B 2 -A 2Repository: tsparticles/cli
Length of output: 41
🏁 Script executed:
# Verify the proposed fix handles various URL formats correctly
node << 'EOF'
const testUrls = [
"https://github.com/user/repo",
"https://github.com/user/repo.git",
"git@github.com:user/repo",
"git@github.com:user/repo.git",
"https://github.com/matteobruni/tsparticles",
];
console.log("Testing proposed fix:");
testUrls.forEach(url => {
const repoPath = url
.replace(/^git@github\.com:/, "")
.replace(/^https?:\/\/github\.com\//, "")
.replace(/\.git$/, "");
console.log(`Input: ${url}`);
console.log(`Output: ${repoPath}\n`);
});
EOFRepository: tsparticles/cli
Length of output: 383
Handle repository URLs that omit the .git suffix.
The test at tests/create-plugin.test.ts:28 passes "https://github.com/matteobruni/tsparticles" without a .git suffix. When indexOf(".git") returns -1, the current substring() call produces an incorrect repoPath ("https://github.com/" instead of "matteobruni/tsparticles"), breaking the README demo image link. Normalize the URL by stripping the protocol/host and removing an optional .git suffix:
- repoPath = repoUrl.includes(stringSearch)
- ? repoUrl.substring(repoUrl.indexOf(trailingSlashSearch) + trailingSlashSearch.length, repoUrl.indexOf(".git"))
- : "tsparticles/plugin-template";
+ repoPath = repoUrl.includes(stringSearch)
+ ? repoUrl
+ .replace(/^git@github\.com:/, "")
+ .replace(/^https?:\/\/github\.com\//, "")
+ .replace(/\.git$/, "")
+ : "tsparticles/plugin-template";🤖 Prompt for AI Agents
In `@src/create/plugin/create-plugin.ts` around lines 96 - 139, The repoPath
extraction in updateReadmeFile incorrectly assumes repoUrl contains ".git";
update the logic in updateReadmeFile to normalize repoUrl by stripping the
protocol/host prefix (e.g., remove "https://github.com/" or "http://github.com/"
and optional "www.") and then remove an optional trailing ".git" suffix before
using it as repoPath; replace the current substring/indexOf(".git") logic
(references: repoUrl, stringSearch, trailingSlashSearch, repoPath) with this
normalized value and keep the existing fallback ("tsparticles/plugin-template")
if normalization yields an empty string.
| { | ||
| from: /preset: "template"/g, | ||
| to: `preset: "${camelizedName}`, | ||
| }, |
There was a problem hiding this comment.
Missing closing quote in the replacement string.
Line 150 has an incomplete string template - the closing quote is missing after ${camelizedName}.
🐛 Proposed fix
{
from: /preset: "template"/g,
- to: `preset: "${camelizedName}`,
+ to: `preset: "${camelizedName}"`,
},📝 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.
| { | |
| from: /preset: "template"/g, | |
| to: `preset: "${camelizedName}`, | |
| }, | |
| { | |
| from: /preset: "template"/g, | |
| to: `preset: "${camelizedName}"`, | |
| }, |
🤖 Prompt for AI Agents
In `@src/create/preset/create-preset.ts` around lines 148 - 151, The replacement
string for the RegExp in create-preset.ts is missing the closing
brace/quote/backtick; update the `to` value so the template interpolation is
closed and the string is valid — e.g. change `to: \`preset: "${camelizedName}\``
to `to: \`preset: "${camelizedName}"\`` (ensure `${camelizedName}` is closed and
the surrounding backtick/string quote is present).
| { | ||
| from: /shape\.type: "template"/g, | ||
| to: `shape.type: "${camelizedName}`, | ||
| }, |
There was a problem hiding this comment.
Missing closing quote in the replacement string.
Line 137 has an incomplete string template - the closing quote is missing after ${camelizedName}.
🐛 Proposed fix
{
from: /shape\.type: "template"/g,
- to: `shape.type: "${camelizedName}`,
+ to: `shape.type: "${camelizedName}"`,
},📝 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.
| { | |
| from: /shape\.type: "template"/g, | |
| to: `shape.type: "${camelizedName}`, | |
| }, | |
| { | |
| from: /shape\.type: "template"/g, | |
| to: `shape.type: "${camelizedName}"`, | |
| }, |
🤖 Prompt for AI Agents
In `@src/create/shape/create-shape.ts` around lines 135 - 138, The replacement
string in the mapping object for shape.type is missing the closing brace/quote
around the template variable; update the `to` value used alongside the `from:
/shape\.type: "template"/g` entry so the template variable `camelizedName` is
properly closed (i.e., ensure `${camelizedName}` is fully terminated inside the
string literal) in the mapping near create-shape.ts so the replacement produces
a valid string `shape.type: "..."`.
Summary by CodeRabbit
Release Notes
New Features
Chores