Feature/update eslint type aware implementation#270
Conversation
🦋 Changeset detectedLatest commit: 206a502 The changes in this PR will be included in the next version bump. This PR includes changesets to release 28 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughRepo adds a shared TS base and composite builds, modernizes ESLint (ordering, ignore, options), migrates builds to tsdown with schema generation, updates catalogs/manifests, refactors several packages (single-file, svelte-social-share-links, catppuccin-xsl, astro-iconify), and removes Catppuccin XSL example apps. ChangesTypeScript configuration modernization
ESLint configuration modernization
Build tooling migration to tsdown and schema generation
Dependency catalog and workspace/manifests updates
Feature-level refactors and module updates
catppuccin-xsl example apps removal
Targeted test and assertion updates
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive refactor of the monorepo's TypeScript architecture, establishing a centralized tsconfig.base.json and implementing project references with composite mode across all packages. The @stephansama/eslint-config package has been significantly enhanced with a deterministic configuration application order, improved TypeScript project service support, and a new unified ignore system. Other notable changes include the migration of dependencies to pnpm catalogs, file renaming for consistency in svelte-social-share-links, and logic extraction in single-file. Review feedback highlights several opportunities to improve robustness, such as providing default values for configuration parameters to avoid runtime errors, using global flags in regex replacements, avoiding direct mutation of input options, and ensuring type safety during module export iteration.
| modules: Array<string>; | ||
| }>; | ||
|
|
||
| export function config(options: Options): Config[] { |
There was a problem hiding this comment.
The options parameter is missing a default value. Since the builder can call this function with undefined (when the config is enabled via a boolean true), this will cause a runtime error when accessing properties of options.
| export function config(options: Options): Config[] { | |
| export function config(options: Options = {}): Config[] { |
| const urlRegexes = { | ||
| hash: /\[h\]/i, | ||
| image: /\[i\]/i, | ||
| title: /\[t\]/i, | ||
| url: /\[u\]/i, | ||
| user: /\[uid\]/i, | ||
| }; |
There was a problem hiding this comment.
The regexes used for placeholder replacement should include the global flag (g) to ensure that all occurrences of a placeholder within a URL template are replaced. Without it, only the first match will be substituted, which could lead to broken URLs if a template uses the same placeholder multiple times.
const urlRegexes = {
hash: /\[h\]/gi,
image: /\[i\]/gi,
title: /\[t\]/gi,
url: /\[u\]/gi,
user: /\[uid\]/gi,
};| }); | ||
|
|
||
| for (const [config, input] of sortedEntries) { | ||
| if (!input || excludeOptions.has(config as BuilderKey)) continue; |
| options.parserOptions ??= {}; | ||
|
|
||
| options.parser ??= tsparser; | ||
|
|
||
| options.parserOptions.tsconfigRootDir ??= process.cwd(); | ||
|
|
||
| if (!options.parserOptions.project) { | ||
| options.parserOptions.projectService ??= true; |
| for (const inlineCallback of Object.values(inline)) { | ||
| await inlineCallback($, url); | ||
| } |
There was a problem hiding this comment.
Iterating over all exported values from the inline module and calling them as functions is fragile. If any non-function value (such as a constant or a default export) is added to ./inline, this loop will throw a runtime error. It is recommended to verify that inlineCallback is a function before execution.
| for (const inlineCallback of Object.values(inline)) { | |
| await inlineCallback($, url); | |
| } | |
| for (const inlineCallback of Object.values(inline)) { | |
| if (typeof inlineCallback === "function") { | |
| await inlineCallback($, url); | |
| } | |
| } |
| return Object.fromEntries( | ||
| Object.entries(colors).map(([key, value]) => [key, value.hex]), | ||
| ); |
There was a problem hiding this comment.
The refactor to Object.fromEntries loses the explicit return type information that was present in the previous reduce implementation. Adding a return type annotation or a type cast would help maintain type safety for consumers of this utility.
| return Object.fromEntries( | |
| Object.entries(colors).map(([key, value]) => [key, value.hex]), | |
| ); | |
| return Object.fromEntries( | |
| Object.entries(colors).map(([key, value]) => [key, value.hex]), | |
| ) as Record<keyof CatppuccinColors, string>; |
|
|
||
| export type Options = Array<string>; | ||
|
|
||
| export function config(ignoreList: Options): Config[] { |
There was a problem hiding this comment.
The ignoreList parameter should be optional or have a default value to handle cases where the configuration is enabled without specific extended ignores (e.g., when ignore: true is used in the builder).
| export function config(ignoreList: Options): Config[] { | |
| export function config(ignoreList: Options = []): Config[] { |
There was a problem hiding this comment.
Actionable comments posted: 22
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.config/www/tsconfig.json:
- Line 2: Update the "extends" entry in .config/www/tsconfig.json from a string
to an array to match the other configs: change the "extends" property so it uses
the array form (i.e., "extends": ["../../tsconfig.base.json"]) to keep
consistency with the project's tsconfig files.
In `@core/ai-commit-msg/test/config.test.ts`:
- Around line 1-2: Replace the blanket ESLint disable with a targeted rule:
remove "/* eslint-disable */" and instead use "/* eslint-disable
`@typescript-eslint/no-explicit-any` */" at the top of
core/ai-commit-msg/test/config.test.ts, or alternatively remove the file-wide
disable and add inline rule-specific disables immediately where the cosmiconfig
mocks use "as any" (the mocks at the locations corresponding to the current
lines 26 and 39) so only the explicit-any rule is suppressed.
In `@core/ai-commit-msg/tsconfig.json`:
- Around line 4-6: The tsconfig.json for core/ai-commit-msg is missing
compilerOptions.composite: true which prevents this package from participating
in the monorepo composite build; update the tsconfig.json by adding "composite":
true under "compilerOptions" so this package supports
incremental/project-references builds (match other packages that set composite),
and ensure the file still includes "types": ["node"] alongside the new composite
flag.
In `@core/catppuccin-xsl/src/utilities.ts`:
- Around line 7-10: The convertColors function currently returns a widened
Record<string,string>; change its signature to explicitly return a mapped type
like { [K in keyof CatppuccinColors]: string } (or Record<keyof
CatppuccinColors, string>) and adjust the Object.fromEntries usage by casting
the result (e.g., via unknown) to that mapped return type so callers retain
key-level typing; update the export function convertColors(colors:
CatppuccinColors) declaration accordingly and keep the same entries->map
transformation inside.
In `@core/eslint-config/package.json`:
- Line 146: The change removed the publishConfig.provenance setting which
weakens supply-chain attestations; restore publishConfig.provenance (e.g., add
or set "publishConfig": { "provenance": true, "access": "public" }) in
package.json so npm will generate provenance attestations when publishing and
preserve the repository-to-package linkage.
In `@core/eslint-config/src/configs/ignore.ts`:
- Around line 22-27: The current truthiness check on ignoreList can still push
an empty config when ignoreList is [] — update the conditional that adds to
configs to ensure ignoreList has length > 0 (e.g., check ignoreList &&
ignoreList.length > 0) before pushing the object with name
"stephansama/ignore/extended" so you only add a config when there are actual
ignore patterns to apply; reference the ignoreList variable and the configs.push
block to locate the change.
- Line 9: The config function currently declares a required parameter
ignoreList: Options but the body treats it as optional (checks its truthiness);
update the signature of function config to accept an optional parameter
(ignoreList?: Options) and ensure any internal usage handles undefined (e.g.,
use default empty value or guard checks used already). Refer to the function
name config and the parameter ignoreList so the change is applied consistently
across overloads/exports and any callers are adjusted if necessary; keep the
return type Config[] unchanged.
In `@core/eslint-config/src/configs/typescript.ts`:
- Around line 46-48: The current truthiness check on
options.parserOptions.project incorrectly treats an explicit false as unset and
enables projectService; change the condition to test for undefined specifically
(i.e., only when options.parserOptions.project === undefined) before applying
the fallback options.parserOptions.projectService ??= true so that an explicit
project: false preserves the user's intent while still enabling projectService
by default when project is truly unset.
In `@core/eslint-config/src/order.ts`:
- Around line 9-13: The map construction uses an explicit return inside the
list.map callback; replace the function body in the list.map call used to build
the exported map (the current anonymous callback that returns [current, index])
with a concise arrow implicit return (e.g., remove the block and return keywords
so the callback directly returns [current, index]) to simplify the code in the
map definition.
In `@core/github-env/package.json`:
- Around line 17-20: Bump the package.json "version" from 1.0.2 to a
breaking-change major like 2.0.0, add a top-level "deprecated" string e.g. "This
package is deprecated. See MIGRATION.md for migration instructions.", and add a
migration document (MIGRATION.md or CHANGELOG.md) to the package and include its
filename in the "files" array so it’s published; update the "description" if
needed to reference the migration doc. Ensure the new "deprecated" field and
version change are committed alongside the created MIGRATION.md/CHANGELOG.md.
In `@core/single-file/src/cli.ts`:
- Line 4: Replace the direct deep import of convertPageToSingleFile with an
import from the package public entrypoint; update the import statement in the
CLI to import convertPageToSingleFile from the module root (e.g., "." or
"./index") so the CLI uses the public API surface and is decoupled from the
internal file ./convert.
In `@core/single-file/src/convert.ts`:
- Around line 21-23: The loop that invokes inline callbacks (for (const
inlineCallback of Object.values(inline)) { await inlineCallback($, url); })
lacks error handling and will crash the whole conversion if any callback throws;
update this by wrapping each call in a try/catch to log the error (include
callback identity if available) and continue (resilient mode), or if you want
fail-fast, wrap the entire loop in a try/catch and rethrow a descriptive Error
that includes context (e.g., which url and that an inline callback failed) so
the behavior is explicit; reference the inline variable and the inlineCallback
invocation in convert.ts when making the change.
- Line 13: The Content-Type check in convert.ts uses
pageResponse?.headers?.get("Content-Type")?.includes("text/html"), which can
miss case/whitespace/MIME-parameter edge cases; update the check around
pageResponse.headers (in the same function/block) to fetch the header
case-insensitively (e.g., normalize header keys or iterate headers) and
normalize the header value (trim and toLowerCase) then compare the media type
portion (split on ';' and compare === 'text/html' or use startsWith 'text/html')
so values like "text/html; charset=utf-8" or with extra whitespace still pass
and other types do not.
- Line 8: The convertPageToSingleFile function currently accepts any string for
the url parameter without validation; add a defensive URL validation at the
start of convertPageToSingleFile to check that url is a well-formed HTTP/HTTPS
URL (e.g., using the URL constructor or a simple regex) and throw a clear,
descriptive error if invalid before calling ky.get so callers get an informative
message rather than letting ky.get throw; reference the convertPageToSingleFile
function and the subsequent ky.get usage when adding this check.
- Line 9: Wrap the network call to ky.get(url) in a try/catch (surround the
await ky.get(url) that assigns to pageResponse) and handle errors by either
rethrowing a descriptive Error or returning a failure result that the caller
(cli.ts:29) can present gracefully; ensure you log or include the original error
message and status (from the caught error) so the CLI doesn't crash on unhandled
promise rejections.
In `@core/svelte-social-share-links/src/lib/social-share-link.svelte`:
- Line 22: The namespace JSON import stores data under a `default` key so
`networks[props.network]` is undefined at runtime; change the import to a
default import (replace `import * as networks from "./networks.json" with {
type: "json" }` with a default import) and update usages to access the JSON
object directly via `networks` (so `networks[props.network]` resolves
correctly), ensuring any references in this file to `networks` or
`props.network` remain unchanged otherwise.
In `@examples/astro-iconify-svgmap/tsconfig.json`:
- Around line 4-7: The tsconfig currently enables composite and allows emit
("composite": true, "noEmit": false) but lacks an output path; add an explicit
outDir under "compilerOptions" (for example "outDir": "dist" or "build") so
emitted artifacts are placed outside source directories and avoid polluting the
repo; update the tsconfig's "compilerOptions" to include the outDir property
alongside "noEmit" and "composite".
In `@examples/svelte-social-share-links/astro/tsconfig.json`:
- Line 5: The tsconfig overrides "compilerOptions" with "noEmit": false which
contradicts Astro's standard (type-check-only) config; update the
"compilerOptions" entry in this tsconfig to either remove the explicit noEmit
setting so it inherits the upstream "noEmit": true, or change "noEmit": false to
"noEmit": true so the "noEmit" compilerOption aligns with
astro/tsconfigs/strict.
In `@examples/typed-events/vanilla/src/counter.js`:
- Around line 41-44: The setCounter function currently assigns a string to
element.innerHTML which can introduce XSS risks; change this to assign to
element.textContent instead so the displayed value is treated as plain text (in
function setCounter, replace the use of element.innerHTML with
element.textContent while keeping the same template/string interpolation using
the counter variable).
In `@monoman.config.ts`:
- Around line 17-21: The contents function currently types its parameter as
Record<string, unknown>, which is too loose; define a specific interface (e.g.,
TsConfig or similar) that includes at least extends?: string | string[] and
compilerOptions?: { composite?: boolean; [key: string]: unknown } and update the
contents(data: Record<string, unknown>) signature to contents(data: TsConfig) so
you get proper completion and safety when setting data.extends and
data.compilerOptions.composite; adjust any other references to data within the
file to respect the new TsConfig shape.
In `@pnpm-workspace.yaml`:
- Line 61: Add a short comment or documentation entry explaining why the
mdast-zone dependency is pinned to a GitHub commit (the line "mdast-zone:
github:stephansama/mdast-zone#1c5b08cd97240debeed4c9c6afad49df5877a132"), e.g.,
note that it contains an unreleased bugfix or a forked change required by the
project, include the reason, the PR/issue or fork reference, and the plan for
when/if to switch back to a published version; place this comment near the
dependency entry or in the repo's dependency/third-party-docs so dependency
auditors can find the rationale.
In `@tsconfig.json`:
- Around line 2-33: The root tsconfig references a non-parseable JSON and two
referenced projects missing composite builds; fix the invalid JSON in
examples/svelte-social-share-links/svelte-kit/tsconfig.json so it is valid JSON
(repair trailing commas, unclosed strings/braces, etc.), and add
"compilerOptions": { "composite": true } to the project configs
core/ai-commit-msg/tsconfig.json and
core/catppuccin-jsonresume-theme/tsconfig.json so they can be used as project
references by the root tsconfig.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: c0853e38-4c98-4fe6-8554-25e5210e3389
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (116)
.config/www/.vitepress/theme/index.ts.config/www/package.json.config/www/tsconfig.jsoncore/ai-commit-msg/build.tscore/ai-commit-msg/package.jsoncore/ai-commit-msg/src/config.tscore/ai-commit-msg/src/index.tscore/ai-commit-msg/test/ai.test.tscore/ai-commit-msg/test/config.test.tscore/ai-commit-msg/test/index.test.tscore/ai-commit-msg/test/schema.test.tscore/ai-commit-msg/tsconfig.jsoncore/alfred-kaomoji/jsconfig.jsoncore/astro-iconify-svgmap/src/index.tscore/astro-iconify-svgmap/tsconfig.jsoncore/auto-readme/build.tscore/auto-readme/package.jsoncore/auto-readme/src/config.tscore/auto-readme/src/plugin.tscore/auto-readme/tsconfig.jsoncore/catppuccin-jsonresume-theme/tsconfig.jsoncore/catppuccin-typedoc/tsconfig.jsoncore/catppuccin-xsl/src/opml.tscore/catppuccin-xsl/src/rss.tscore/catppuccin-xsl/src/run.test.tscore/catppuccin-xsl/src/sitemap.tscore/catppuccin-xsl/src/utilities.tscore/catppuccin-xsl/templates/schema.tscore/catppuccin-xsl/tsconfig.jsoncore/eslint-config/package.jsoncore/eslint-config/src/builder.tscore/eslint-config/src/configs/baseline.tscore/eslint-config/src/configs/e18e.tscore/eslint-config/src/configs/gitignore.tscore/eslint-config/src/configs/ignore.tscore/eslint-config/src/configs/index.tscore/eslint-config/src/configs/perfectionist.tscore/eslint-config/src/configs/regexp.tscore/eslint-config/src/configs/typescript.tscore/eslint-config/src/configs/unicorn.tscore/eslint-config/src/order.tscore/eslint-config/src/presets.tscore/eslint-config/tsconfig.jsoncore/example/tsconfig.jsoncore/find-makefile-targets/tsconfig.jsoncore/github-env/package.jsoncore/multipublish/build.tscore/multipublish/cli.mjscore/multipublish/package.jsoncore/multipublish/src/config.tscore/multipublish/tsconfig.jsoncore/multipublish/vitest.config.tscore/prettier-plugin-handlebars/tests/plugin.test.tscore/prettier-plugin-handlebars/tsconfig.jsoncore/remark-asciinema/tsconfig.jsoncore/single-file/README.mdcore/single-file/example/index.jscore/single-file/src/cli.tscore/single-file/src/convert.tscore/single-file/src/index.tscore/single-file/tsconfig.jsoncore/svelte-social-share-links/.storybook/main.tscore/svelte-social-share-links/src/lib/index.tscore/svelte-social-share-links/src/lib/networks.tscore/svelte-social-share-links/src/lib/social-share-link.stories.sveltecore/svelte-social-share-links/src/lib/social-share-link.sveltecore/svelte-social-share-links/tsconfig.app.jsoncore/svelte-social-share-links/tsconfig.jsoncore/svelte-social-share-links/tsconfig.node.jsoncore/svelte-social-share-links/vite.webcomponent.config.tscore/typed-env/src/index.tscore/typed-env/tsconfig.jsoncore/typed-events/example/index.jscore/typed-events/tsconfig.jsoncore/typed-nocodb-api/tsconfig.jsoncore/typed-templates/tsconfig.jsoncore/types-github-action-env/tsconfig.jsoncore/types-lhci/tsconfig.jsoneslint.config.tsexamples/astro-iconify-svgmap/tsconfig.jsonexamples/catppuccin-xsl/astro/CHANGELOG.mdexamples/catppuccin-xsl/astro/README.mdexamples/catppuccin-xsl/astro/astro.config.mjsexamples/catppuccin-xsl/astro/package.jsonexamples/catppuccin-xsl/astro/src/pages/index.astroexamples/catppuccin-xsl/astro/src/pages/opml.xml.tsexamples/catppuccin-xsl/astro/src/pages/opml.xsl.tsexamples/catppuccin-xsl/astro/src/pages/rss.xml.tsexamples/catppuccin-xsl/astro/src/pages/rss.xsl.tsexamples/catppuccin-xsl/astro/src/pages/sitemap.xsl.tsexamples/catppuccin-xsl/astro/tsconfig.jsonexamples/catppuccin-xsl/vanilla/CHANGELOG.mdexamples/catppuccin-xsl/vanilla/index.htmlexamples/catppuccin-xsl/vanilla/package.jsonexamples/catppuccin-xsl/vanilla/src/generate.jsexamples/catppuccin-xsl/vanilla/turbo.jsonexamples/remark-asciinema/tsconfig.jsonexamples/svelte-social-share-links/astro/astro.config.tsexamples/svelte-social-share-links/astro/src/component/bluesky.svelteexamples/svelte-social-share-links/astro/src/pages/index.astroexamples/svelte-social-share-links/astro/tsconfig.jsonexamples/svelte-social-share-links/svelte-kit/tsconfig.jsonexamples/typed-events/react/app/routes/home.tsxexamples/typed-events/react/package.jsonexamples/typed-events/react/tsconfig.jsonexamples/typed-events/vanilla/package.jsonexamples/typed-events/vanilla/src/counter.jsmonoman.config.tspackage.jsonpnpm-workspace.yamlscripts/tsconfig.jsontsconfig.base.jsontsconfig.jsontsconfig.root.jsonturbo/generators/config.tsturbo/generators/templates/common/tsconfig.json
💤 Files with no reviewable changes (23)
- examples/svelte-social-share-links/astro/astro.config.ts
- core/ai-commit-msg/src/config.ts
- core/auto-readme/src/config.ts
- examples/catppuccin-xsl/astro/src/pages/rss.xsl.ts
- examples/catppuccin-xsl/vanilla/CHANGELOG.md
- core/multipublish/src/config.ts
- turbo/generators/config.ts
- examples/catppuccin-xsl/vanilla/package.json
- examples/catppuccin-xsl/astro/src/pages/opml.xsl.ts
- examples/catppuccin-xsl/astro/CHANGELOG.md
- examples/catppuccin-xsl/astro/astro.config.mjs
- examples/catppuccin-xsl/astro/tsconfig.json
- examples/catppuccin-xsl/astro/README.md
- examples/catppuccin-xsl/vanilla/turbo.json
- examples/catppuccin-xsl/astro/package.json
- examples/catppuccin-xsl/astro/src/pages/opml.xml.ts
- core/auto-readme/src/plugin.ts
- examples/catppuccin-xsl/vanilla/index.html
- core/eslint-config/src/configs/gitignore.ts
- examples/catppuccin-xsl/vanilla/src/generate.js
- examples/catppuccin-xsl/astro/src/pages/sitemap.xsl.ts
- examples/catppuccin-xsl/astro/src/pages/index.astro
- examples/catppuccin-xsl/astro/src/pages/rss.xml.ts
| @@ -0,0 +1,8 @@ | |||
| { | |||
| "extends": "../../tsconfig.base.json", | |||
There was a problem hiding this comment.
Use array format for extends to maintain consistency.
While TypeScript accepts both string and array formats for extends, all other tsconfig.json files in this PR use the array format: "extends": ["../../tsconfig.base.json"]. This inconsistency may cause confusion.
📝 Proposed fix
- "extends": "../../tsconfig.base.json",
+ "extends": ["../../tsconfig.base.json"],📝 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.
| "extends": "../../tsconfig.base.json", | |
| "extends": ["../../tsconfig.base.json"], |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.config/www/tsconfig.json at line 2, Update the "extends" entry in
.config/www/tsconfig.json from a string to an array to match the other configs:
change the "extends" property so it uses the array form (i.e., "extends":
["../../tsconfig.base.json"]) to keep consistency with the project's tsconfig
files.
| /* eslint-disable unicorn/no-abusive-eslint-disable */ | ||
| /* eslint-disable */ |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check which ESLint rules are violated in config.test.ts
# Remove the eslint-disable comments temporarily and run ESLint
rg -n "eslint-disable" core/ai-commit-msg/test/config.test.tsRepository: stephansama/packages
Length of output: 144
🏁 Script executed:
cat -n core/ai-commit-msg/test/config.test.ts | head -50Repository: stephansama/packages
Length of output: 1826
🏁 Script executed:
wc -l core/ai-commit-msg/test/config.test.tsRepository: stephansama/packages
Length of output: 106
🏁 Script executed:
git -C core/ai-commit-msg log --oneline -n 20 -- test/config.test.tsRepository: stephansama/packages
Length of output: 119
Replace blanket ESLint disable with a targeted rule instead.
The file disables unicorn/no-abusive-eslint-disable and then immediately uses /* eslint-disable */ to suppress all linting rules, which is exactly the anti-pattern the unicorn rule is designed to prevent. The problematic code uses as any type assertions on lines 26 and 39 when mocking cosmiconfig. Replace the blanket disable with:
/* eslint-disable `@typescript-eslint/no-explicit-any` */Alternatively, add a rule-specific disable only at the lines that need it.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/ai-commit-msg/test/config.test.ts` around lines 1 - 2, Replace the
blanket ESLint disable with a targeted rule: remove "/* eslint-disable */" and
instead use "/* eslint-disable `@typescript-eslint/no-explicit-any` */" at the top
of core/ai-commit-msg/test/config.test.ts, or alternatively remove the file-wide
disable and add inline rule-specific disables immediately where the cosmiconfig
mocks use "as any" (the mocks at the locations corresponding to the current
lines 26 and 39) so only the explicit-any rule is suppressed.
| "compilerOptions": { | ||
| "types": ["node"] | ||
| } |
There was a problem hiding this comment.
Missing composite: true breaks the monorepo composite build setup.
All other packages in this PR enable compilerOptions.composite: true for incremental/project-references builds, but this file is missing that setting. This inconsistency will prevent this package from participating in the composite build graph.
🔧 Proposed fix to enable composite mode
"compilerOptions": {
- "types": ["node"]
+ "types": ["node"],
+ "composite": true
}📝 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.
| "compilerOptions": { | |
| "types": ["node"] | |
| } | |
| "compilerOptions": { | |
| "types": ["node"], | |
| "composite": true | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/ai-commit-msg/tsconfig.json` around lines 4 - 6, The tsconfig.json for
core/ai-commit-msg is missing compilerOptions.composite: true which prevents
this package from participating in the monorepo composite build; update the
tsconfig.json by adding "composite": true under "compilerOptions" so this
package supports incremental/project-references builds (match other packages
that set composite), and ensure the file still includes "types": ["node"]
alongside the new composite flag.
| export function convertColors(colors: CatppuccinColors) { | ||
| return Object.entries(colors).reduce( | ||
| (acc, [key, val]) => { | ||
| acc[key as keyof typeof acc] = val.hex; | ||
| return acc; | ||
| }, | ||
| {} as Record<ColorName, string>, | ||
| return Object.fromEntries( | ||
| Object.entries(colors).map(([key, value]) => [key, value.hex]), | ||
| ); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
# First, locate and examine the utilities.ts file
find . -type f -name "utilities.ts" | head -20Repository: stephansama/packages
Length of output: 376
🏁 Script executed:
# Check the current implementation of convertColors and surrounding context
grep -r "convertColors" --include="*.ts" -B 2 -A 5Repository: stephansama/packages
Length of output: 3263
🏁 Script executed:
# Look for CatppuccinColors type definition
grep -r "CatppuccinColors" --include="*.ts" -B 2 -A 5Repository: stephansama/packages
Length of output: 834
🏁 Script executed:
# Check git history for the convertColors function
cd ./core/catppuccin-xsl && git log -p --follow -S "convertColors" -- src/utilities.ts | head -100Repository: stephansama/packages
Length of output: 46
🏁 Script executed:
# Check if CatppuccinColors is from an external package or local type
find . -type f -name "*.ts" -o -name "*.d.ts" | xargs grep -l "CatppuccinColors" | grep -E "(palette|types)" | head -10Repository: stephansama/packages
Length of output: 46
🏁 Script executed:
# Look at the actual package.json to understand the dependency
cat ./core/catppuccin-xsl/package.json | grep -A 5 -B 5 "catppuccin"Repository: stephansama/packages
Length of output: 934
🏁 Script executed:
cat -n ./core/catppuccin-xsl/src/utilities.tsRepository: stephansama/packages
Length of output: 848
🏁 Script executed:
# Check what the schema.compile method expects as parameter types
grep -r "schema.compile" ./core/catppuccin-xsl/src --include="*.ts" -B 2 -A 2 | head -40Repository: stephansama/packages
Length of output: 46
🏁 Script executed:
# Check the actual type definition of CatppuccinColors from the external package
# First find if it's available locally or if we need to inspect node_modules
fd "palette" --type d | head -10Repository: stephansama/packages
Length of output: 46
🏁 Script executed:
# Find schema definitions
find ./core/catppuccin-xsl/src -type f -name "*.ts" -exec grep -l "schema" {} \;Repository: stephansama/packages
Length of output: 168
🏁 Script executed:
# Look for the typed-templates package to understand what compile expects
find . -path "*/typed-templates/src/*" -type f -name "*.ts" | head -10Repository: stephansama/packages
Length of output: 254
🏁 Script executed:
# Check if there's any type checking that depends on exact keys
grep -r "compile" ./core/catppuccin-xsl/src --include="*.ts" -B 5 -A 5 | head -60Repository: stephansama/packages
Length of output: 3915
🏁 Script executed:
# Look at one of the schema files to understand the types
cat ./core/catppuccin-xsl/src/opml.ts | head -50Repository: stephansama/packages
Length of output: 613
🏁 Script executed:
# Check typed-templates to understand what compile expects
cat ./core/typed-templates/src/index.tsRepository: stephansama/packages
Length of output: 257
🏁 Script executed:
# Check the schema map to see how it handles the compile method and its parameters
cat ./core/typed-templates/src/map.ts | head -100Repository: stephansama/packages
Length of output: 1702
🏁 Script executed:
# Search for schema definitions in catppuccin-xsl
grep -r "Schema\|schema" ./core/catppuccin-xsl/src --include="*.ts" | grep -v "compile" | head -20Repository: stephansama/packages
Length of output: 314
🏁 Script executed:
# Check the templates directory
find ./core -type d -name "templates" | head -5Repository: stephansama/packages
Length of output: 96
🏁 Script executed:
# Find the `@templates/schema` file
find ./core -type f -name "schema*" | head -20Repository: stephansama/packages
Length of output: 288
🏁 Script executed:
# Look for the templates package path definitions
find ./core -type f -name "tsconfig.json" -o -name "vite.config.ts" | xargs grep -l "templates" 2>/dev/nullRepository: stephansama/packages
Length of output: 100
🏁 Script executed:
# Check the catppuccin-xsl package imports
grep -r "@templates/schema" ./core/catppuccin-xsl --include="*.ts" -B 5 -A 5Repository: stephansama/packages
Length of output: 1767
🏁 Script executed:
# Check the tsconfig to verify the `@templates` alias
cat ./core/catppuccin-xsl/tsconfig.jsonRepository: stephansama/packages
Length of output: 303
🏁 Script executed:
# Now examine the schema.ts file which defines the schemas
cat ./core/catppuccin-xsl/templates/schema.tsRepository: stephansama/packages
Length of output: 2011
Preserve key-level typing in convertColors.
The current implementation loses compile-time type guarantees for expected palette keys. Object.fromEntries infers the return type as Record<string, string>, widening the constrained key structure from CatppuccinColors. While runtime validation via the schema handles this, adding an explicit return type preserves type-aware IDE hints and build-time safety.
Suggested diff
-export function convertColors(colors: CatppuccinColors) {
- return Object.fromEntries(
- Object.entries(colors).map(([key, value]) => [key, value.hex]),
- );
-}
+export function convertColors(
+ colors: CatppuccinColors,
+): Record<keyof CatppuccinColors, string> {
+ return Object.fromEntries(
+ Object.entries(colors).map(([key, value]) => [key, value.hex]),
+ ) as Record<keyof CatppuccinColors, string>;
+}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/catppuccin-xsl/src/utilities.ts` around lines 7 - 10, The convertColors
function currently returns a widened Record<string,string>; change its signature
to explicitly return a mapped type like { [K in keyof CatppuccinColors]: string
} (or Record<keyof CatppuccinColors, string>) and adjust the Object.fromEntries
usage by casting the result (e.g., via unknown) to that mapped return type so
callers retain key-level typing; update the export function
convertColors(colors: CatppuccinColors) declaration accordingly and keep the
same entries->map transformation inside.
| "publishConfig": { | ||
| "access": "public", | ||
| "provenance": true | ||
| "access": "public" |
There was a problem hiding this comment.
Removal of publishConfig.provenance reduces supply chain security.
The provenance field enables npm to generate attestations linking published packages to their source repository, improving supply chain transparency and security. Removing this field degrades the package's security posture.
Consider keeping provenance enabled unless there are specific compatibility or CI/CD issues that require its removal.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/eslint-config/package.json` at line 146, The change removed the
publishConfig.provenance setting which weakens supply-chain attestations;
restore publishConfig.provenance (e.g., add or set "publishConfig": {
"provenance": true, "access": "public" }) in package.json so npm will generate
provenance attestations when publishing and preserve the repository-to-package
linkage.
| "exclude": ["dist"], | ||
| "include": [".astro/types.d.ts", "**/*"], | ||
| "exclude": ["dist"] | ||
| "compilerOptions": { "composite": true, "noEmit": false } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check noEmit settings in other Astro tsconfig files
# Find all Astro-related tsconfig files and check their noEmit setting
fd -e json "tsconfig" -x sh -c 'grep -q "astro" {} && echo "File: {}" && cat {}' | grep -A2 -B2 "noEmit"
# Check if there are any .d.ts files being generated in this directory
fd -e ts -d 1 "\.d\.ts$" examples/svelte-social-share-links/astro/Repository: stephansama/packages
Length of output: 481
🏁 Script executed:
# Check all tsconfig files in the repository to understand the pattern better
fd -name "tsconfig.json" -type f | head -20Repository: stephansama/packages
Length of output: 295
🏁 Script executed:
# Look for any Astro configuration files that might explain this setup
fd -name "astro.config" -type fRepository: stephansama/packages
Length of output: 295
🏁 Script executed:
# Check if there are multiple projects using composite mode
rg '"composite":\s*true' -A2 -B2 --type json | head -50Repository: stephansama/packages
Length of output: 2309
🏁 Script executed:
cat examples/svelte-social-share-links/astro/tsconfig.jsonRepository: stephansama/packages
Length of output: 234
🏁 Script executed:
# Also check the parent tsconfig to understand the inheritance
cat examples/svelte-social-share-links/tsconfig.jsonRepository: stephansama/packages
Length of output: 145
🏁 Script executed:
# Look at what .astro/types.d.ts contains
find examples/svelte-social-share-links/astro -name "*.d.ts" -type fRepository: stephansama/packages
Length of output: 46
🌐 Web query:
Astro tsconfigs/strict noEmit setting official documentation
💡 Result:
Astro provides official TypeScript configuration templates in its repository at packages/astro/tsconfigs/, including base.json, strict.json, and strictest.json[1][2]. The strict.json extends base.json and sets "strict": true[1]. The base.json explicitly includes "noEmit": true with the comment "Astro directly run TypeScript code, noEmit: true" to prevent TypeScript compilation output since Astro uses esbuild for transpilation and type-checking is separate[2]. Official documentation recommends extending "astro/tsconfigs/strict" for strict mode in tsconfig.json[3][4][5]. This setup enables editor type-checking without emitting JS files, and type checking uses astro check or tsc (where --noEmit is redundant due to the config)[3][6][5].
Citations:
- 1: https://github.com/withastro/astro/blob/main/packages/astro/tsconfigs/strict.json
- 2: https://github.com/withastro/astro/blob/main/packages/astro/tsconfigs/base.json
- 3: https://docs.astro.build/en/guides/typescript/
- 4: https://www.mintlify.com/withastro/astro/config/typescript
- 5: https://docs.astro.build/en/guides/typescript
- 6: Minor: Type checking: --noEmit likely redundant withastro/docs#1566
🌐 Web query:
Astro TypeScript composite mode noEmit false purpose
💡 Result:
In Astro projects, standard TypeScript configurations (extending "astro/tsconfigs/base", "strict", or "strictest") use "noEmit": true because Astro handles compilation and bundling via Vite, so TypeScript is only for type-checking [1][2][3]. The combination of TypeScript's "composite": true (enabling project references for monorepos) with "noEmit": false serves a specific purpose in build-focused tsconfigs: it allows emitting declaration (.d.ts) files and build information (.tsbuildinfo) for incremental compilation and cross-project type sharing [4][5][6]. TypeScript requires "noEmit": false (or explicit "declaration": true) with "composite": true, as "noEmit": true is incompatible [5]. This setup is used in Astro's own monorepo for package builds (e.g., tsconfig.build.json), where TypeScript emits.d.ts to dist/ for other packages to reference via "references" [4]. For user Astro projects wanting project references (e.g., monorepo with shared TS packages), set "composite": true and "noEmit": false in referenced projects' tsconfigs to generate declarations, while the root/app tsconfig can reference them and use "noEmit": true [4][7][8].
Citations:
- 1: Minor: Type checking: --noEmit likely redundant withastro/docs#1566
- 2: https://docs.astro.build/en/guides/typescript
- 3: withastro/astro@96beb88
- 4: refactor: update tsconfig to use TypeScript project references withastro/astro#16505
- 5: tsc: TS5053: Option 'noEmit' cannot be specified with option 'composite' microsoft/TypeScript#36917
- 6: https://kindatechnical.com/typescript/project-references-composite-builds.html
- 7: refactor: migrate react tests to typescript withastro/astro#16318
- 8: https://stackoverflow.com/questions/78907727/typescript-composite-project-with-nextjs
Change noEmit: false to noEmit: true to follow Astro's standard configuration.
The example extends astro/tsconfigs/strict, which explicitly uses noEmit: true for Astro's type-checking-only approach. The "noEmit": false override contradicts Astro's official recommendation and is only appropriate for monorepo builds emitting declaration files for project references—a pattern not used here. Remove the noEmit override to inherit the standard noEmit: true setting, or explicitly set it to true.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/svelte-social-share-links/astro/tsconfig.json` at line 5, The
tsconfig overrides "compilerOptions" with "noEmit": false which contradicts
Astro's standard (type-check-only) config; update the "compilerOptions" entry in
this tsconfig to either remove the explicit noEmit setting so it inherits the
upstream "noEmit": true, or change "noEmit": false to "noEmit": true so the
"noEmit" compilerOption aligns with astro/tsconfigs/strict.
| function setCounter(count) { | ||
| counter = count; | ||
| element.innerHTML = `count is ${counter}`; | ||
| } |
There was a problem hiding this comment.
Use textContent instead of innerHTML for safety.
While the counter variable is validated as a number via Zod schemas, using textContent instead of innerHTML is a safer practice that eliminates any XSS risk, even if the validation were to change or be bypassed in the future.
🛡️ Proposed fix
function setCounter(count) {
counter = count;
- element.innerHTML = `count is ${counter}`;
+ element.textContent = `count is ${counter}`;
}📝 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.
| function setCounter(count) { | |
| counter = count; | |
| element.innerHTML = `count is ${counter}`; | |
| } | |
| function setCounter(count) { | |
| counter = count; | |
| element.textContent = `count is ${counter}`; | |
| } |
🧰 Tools
🪛 OpenGrep (1.20.0)
[WARNING] 43-43: Setting innerHTML with dynamic content can lead to XSS. Use textContent or createElement with proper escaping instead.
(coderabbit.xss.innerhtml-assignment)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/typed-events/vanilla/src/counter.js` around lines 41 - 44, The
setCounter function currently assigns a string to element.innerHTML which can
introduce XSS risks; change this to assign to element.textContent instead so the
displayed value is treated as plain text (in function setCounter, replace the
use of element.innerHTML with element.textContent while keeping the same
template/string interpolation using the counter variable).
| mdast: 3.0.0 | ||
| mdast-comment-marker: ^3.0.0 | ||
| mdast-util-from-markdown: ^2.0.2 | ||
| mdast-zone: github:stephansama/mdast-zone#1c5b08cd97240debeed4c9c6afad49df5877a132 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check if there's documentation about the mdast-zone fork
rg -i "mdast-zone" --type=md -C 3Repository: stephansama/packages
Length of output: 46
🏁 Script executed:
#!/bin/bash
# Check the context around line 61 in pnpm-workspace.yaml
cat -n pnpm-workspace.yaml | sed -n '55,65p'Repository: stephansama/packages
Length of output: 445
🏁 Script executed:
#!/bin/bash
# Search for any documentation about mdast-zone in all file types (not just markdown)
rg -i "mdast-zone" -C 3Repository: stephansama/packages
Length of output: 3041
🏁 Script executed:
#!/bin/bash
# Check if there are any comments or documentation in workspace root that might explain dependencies
ls -la | grep -E "(README|CHANGELOG|docs|\.md$)"
cat -n pnpm-workspace.yaml | head -20Repository: stephansama/packages
Length of output: 558
Document the rationale for the GitHub commit reference.
The mdast-zone dependency uses a direct GitHub commit hash instead of a published version. Explain why this custom reference is necessary (e.g., unreleased fixes, forked modifications) in a comment or documentation, as it impacts dependency audits and future updates.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@pnpm-workspace.yaml` at line 61, Add a short comment or documentation entry
explaining why the mdast-zone dependency is pinned to a GitHub commit (the line
"mdast-zone:
github:stephansama/mdast-zone#1c5b08cd97240debeed4c9c6afad49df5877a132"), e.g.,
note that it contains an unreleased bugfix or a forked change required by the
project, include the reason, the PR/issue or fork reference, and the plan for
when/if to switch back to a published version; place this comment near the
dependency entry or in the repo's dependency/third-party-docs so dependency
auditors can find the rationale.
| "references": [ | ||
| { "path": "./tsconfig.root.json" }, | ||
| { "path": "./.config/www/tsconfig.json" }, | ||
| { "path": "./scripts/tsconfig.json" }, | ||
| { "path": "./core/ai-commit-msg/tsconfig.json" }, | ||
| { "path": "./core/alfred-kaomoji/jsconfig.json" }, | ||
| { "path": "./core/astro-iconify-svgmap/tsconfig.json" }, | ||
| { "path": "./core/auto-readme/tsconfig.json" }, | ||
| { "path": "./core/catppuccin-jsonresume-theme/tsconfig.json" }, | ||
| { "path": "./core/catppuccin-typedoc/tsconfig.json" }, | ||
| { "path": "./core/catppuccin-xsl/tsconfig.json" }, | ||
| { "path": "./core/eslint-config/tsconfig.json" }, | ||
| { "path": "./core/example/tsconfig.json" }, | ||
| { "path": "./core/find-makefile-targets/tsconfig.json" }, | ||
| { "path": "./core/multipublish/tsconfig.json" }, | ||
| { "path": "./core/prettier-plugin-handlebars/tsconfig.json" }, | ||
| { "path": "./core/remark-asciinema/tsconfig.json" }, | ||
| { "path": "./core/single-file/tsconfig.json" }, | ||
| { "path": "./core/svelte-social-share-links/tsconfig.json" }, | ||
| { "path": "./core/typed-env/tsconfig.json" }, | ||
| { "path": "./core/typed-events/tsconfig.json" }, | ||
| { "path": "./core/typed-nocodb-api/tsconfig.json" }, | ||
| { "path": "./core/typed-templates/tsconfig.json" }, | ||
| { "path": "./core/types-github-action-env/tsconfig.json" }, | ||
| { "path": "./core/types-lhci/tsconfig.json" }, | ||
| { "path": "./examples/astro-iconify-svgmap/tsconfig.json" }, | ||
| { "path": "./examples/remark-asciinema/tsconfig.json" }, | ||
| { "path": "./examples/svelte-social-share-links/astro/tsconfig.json" }, | ||
| { | ||
| "path": "./examples/svelte-social-share-links/svelte-kit/tsconfig.json" | ||
| } | ||
| ] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python - <<'PY'
import json
from pathlib import Path
root = Path(".")
root_cfg = json.loads((root / "tsconfig.json").read_text())
refs = root_cfg.get("references", [])
missing = []
non_composite = []
invalid_json = []
for r in refs:
p = root / r["path"]
if not p.exists():
missing.append(r["path"])
continue
try:
cfg = json.loads(p.read_text())
except Exception:
invalid_json.append(r["path"])
continue
composite = cfg.get("compilerOptions", {}).get("composite", False)
if not composite:
non_composite.append(r["path"])
print("Missing references:")
for x in missing: print(" -", x)
print("\nInvalid JSON configs:")
for x in invalid_json: print(" -", x)
print("\nReferences without compilerOptions.composite=true:")
for x in non_composite: print(" -", x)
PYRepository: stephansama/packages
Length of output: 314
Fix invalid JSON and missing composite settings in referenced configs.
The root tsconfig.json references 28 config files, but verification found:
- Invalid JSON:
./examples/svelte-social-share-links/svelte-kit/tsconfig.jsoncannot be parsed and will cause build failures. - Missing
compilerOptions.composite: true:./core/ai-commit-msg/tsconfig.json./core/catppuccin-jsonresume-theme/tsconfig.json
These configs are referenced from the root and should be marked as composite to enable project references.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tsconfig.json` around lines 2 - 33, The root tsconfig references a
non-parseable JSON and two referenced projects missing composite builds; fix the
invalid JSON in examples/svelte-social-share-links/svelte-kit/tsconfig.json so
it is valid JSON (repair trailing commas, unclosed strings/braces, etc.), and
add "compilerOptions": { "composite": true } to the project configs
core/ai-commit-msg/tsconfig.json and
core/catppuccin-jsonresume-theme/tsconfig.json so they can be used as project
references by the root tsconfig.
| { | ||
| "name": "@stephansama/eslint-config", | ||
| "version": "0.1.3", | ||
| "version": "0.1.5", |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@core/example/tsconfig.json`:
- Line 4: tsconfig.json's "files" array incorrectly lists the build artifact
"../../scripts/dist/examples.js", which creates a fragile build-order
dependency; remove that entry from the "files" array in
core/example/tsconfig.json so only source files are listed and let
core/example/src/index.ts continue to resolve the fallback import at runtime (if
you need compile-time safety, instead enable skipLibCheck or add an explicit
build step that generates the artifact before TypeScript runs).
In `@core/typed-events/vitest.config.ts`:
- Around line 5-6: Update the catalog's pinned vite version to a compatible
release (e.g., vite 7.3.1) in the pnpm-workspace.yaml so it matches the version
used by vite-tsconfig-paths@5.1.4, then remove the suppressing cast on the
plugin import (replace plugins: [tsconfigPaths() as any] with plugins:
[tsconfigPaths()] ) in the files that used the cast (look for tsconfigPaths()
usages in core/typed-events/vitest.config.ts, core/typed-templates/... and
core/catppuccin-xsl/...), rebuild types and ensure no type errors remain.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: a87b967f-90ea-4be2-91f8-626209b48cbd
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (20)
core/ai-commit-msg/package.jsoncore/astro-iconify-svgmap/src/get.tscore/astro-iconify-svgmap/src/index.tscore/auto-readme/package.jsoncore/catppuccin-xsl/vitest.config.tscore/eslint-config/src/configs/e18e.tscore/eslint-config/src/configs/imports.tscore/example/src/index.test.tscore/example/tsconfig.jsoncore/multipublish/package.jsoncore/multipublish/src/detect.tscore/remark-asciinema/package.jsoncore/typed-events/vitest.config.tscore/typed-templates/vitest.config.tscore/types-github-action-env/tsconfig.jsoncore/types-lhci/tsconfig.jsoneslint.config.tspackage.jsonpnpm-workspace.yamlscripts/package.json
| "include": ["./src/**/*"] | ||
| "extends": ["../../tsconfig.base.json"], | ||
| "include": ["./src/**/*", "tsdown.config.ts"], | ||
| "files": ["../../scripts/dist/examples.js"], |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify the examples.js build artifact and its usage
# Check if the file exists
echo "=== Checking if examples.js exists ==="
if [ -f "scripts/dist/examples.js" ]; then
echo "✓ File exists"
ls -lh scripts/dist/examples.js
else
echo "✗ File does not exist"
fi
# Find build scripts that might generate this file
echo -e "\n=== Searching for scripts that build examples.js ==="
rg -n "examples\.js" --type=json -g 'package.json' -C2
# Check for TypeScript source that generates this file
echo -e "\n=== Looking for source files that might generate examples.js ==="
fd -e ts -e js . scripts/ --exec echo {} \; | head -20
# Check if this file is imported/referenced elsewhere in core/example
echo -e "\n=== Checking references to examples.js in core/example ==="
rg -n "examples" core/example/ -g '!node_modules' -g '!dist' -C2Repository: stephansama/packages
Length of output: 5164
🏁 Script executed:
# Check what the generate-examples script produces
cat scripts/src/generate-examples.ts | head -50Repository: stephansama/packages
Length of output: 1410
🏁 Script executed:
# Check the scripts package.json to see the generate-examples script
cat scripts/package.json | grep -A 5 "generate-examples"Repository: stephansama/packages
Length of output: 328
🏁 Script executed:
# Look for any build configuration or scripts that orchestrate the build order
fd -e json -e js -e ts . -path "*/root*" -o -path "*/build*" | head -20
cat package.json | grep -A 20 "scripts"Repository: stephansama/packages
Length of output: 1729
🏁 Script executed:
# Check if there's a prebuild step or any documentation about build order
cat package.json | grep -B 5 -A 5 "build"Repository: stephansama/packages
Length of output: 595
🏁 Script executed:
# Verify when examples.js is supposed to be generated relative to TypeScript compilation
# Check turbo config for build order
cat turbo.json 2>/dev/null || cat turbo.config.ts 2>/dev/null || echo "No turbo config found"Repository: stephansama/packages
Length of output: 982
🏁 Script executed:
# Check if there are any scripts that run generate-examples before core/example builds
grep -r "generate-examples" --include="*.json" --include="*.ts" --include="*.js" . 2>/dev/null | grep -v node_modules | grep -v ".git"Repository: stephansama/packages
Length of output: 474
Remove the build artifact from the TypeScript configuration to avoid build order failures.
The files array includes ../../scripts/dist/examples.js, a build artifact that doesn't exist until the generate-examples script runs. While core/example/src/index.ts does import this file at runtime as a fallback, including it in the files array forces TypeScript to process it during compilation, creating a fragile implicit build order dependency. This will cause TypeScript compilation failures if the file hasn't been generated yet.
The files array should contain only source files, not build outputs. Since this is a runtime fallback import, remove it from files and let the import resolve naturally at runtime. If TypeScript compilation needs to validate the import path exists, consider using skipLibCheck or ensuring the build artifact is generated before compilation through explicit task dependencies in your build orchestration.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/example/tsconfig.json` at line 4, tsconfig.json's "files" array
incorrectly lists the build artifact "../../scripts/dist/examples.js", which
creates a fragile build-order dependency; remove that entry from the "files"
array in core/example/tsconfig.json so only source files are listed and let
core/example/src/index.ts continue to resolve the fallback import at runtime (if
you need compile-time safety, instead enable skipLibCheck or add an explicit
build step that generates the artifact before TypeScript runs).
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| plugins: [tsconfigPaths() as any], |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Package manifests with vite/vitest/vite-tsconfig-paths/typescript =="
fd -HI '^package\.json$' | while read -r f; do
python - "$f" <<'PY'
import json, sys
p=sys.argv[1]
with open(p, 'r', encoding='utf-8') as fh:
data=json.load(fh)
deps={}
for k in ("dependencies","devDependencies","peerDependencies","optionalDependencies"):
for name,val in data.get(k,{}).items():
if name in ("vite","vitest","vite-tsconfig-paths","typescript"):
deps.setdefault(k,{})[name]=val
if deps:
print(f"\n{p}")
for sect,vals in deps.items():
print(f" {sect}: {vals}")
PY
done
echo
echo "== Workspace/catalog hints =="
fd -HI 'pnpm-workspace.yaml|pnpm-lock.yaml|package.json|turbo.json' | sed 's#^#- #'
echo
echo "== Lockfile occurrences (if present) =="
if [ -f pnpm-lock.yaml ]; then
rg -n "^(\\s{2})?/(vite|vitest|vite-tsconfig-paths|typescript)@" pnpm-lock.yaml -C1 || true
fi
echo
echo "== Any existing typed workaround patterns in vitest configs =="
rg -n --type=ts -C2 "tsconfigPaths\\(\\)\\s+as\\s+any|PluginOption|defineProject\\("Repository: stephansama/packages
Length of output: 50377
🏁 Script executed:
# Find and read pnpm-workspace.yaml to see catalog definitions
cat pnpm-workspace.yamlRepository: stephansama/packages
Length of output: 5485
🏁 Script executed:
# Read the actual vitest.config.ts file
cat -n core/typed-events/vitest.config.tsRepository: stephansama/packages
Length of output: 448
🏁 Script executed:
# Check vite-tsconfig-paths package info and its type signatures
if [ -d "node_modules/.pnpm" ]; then
# Find vite-tsconfig-paths entry and check package.json
find node_modules/.pnpm -name "vite-tsconfig-paths*" -type d -maxdepth 1 | head -1 | xargs -I {} sh -c 'cat {}/node_modules/vite-tsconfig-paths/package.json | grep -A5 "version\|exports"'
fiRepository: stephansama/packages
Length of output: 46
🏁 Script executed:
# Check if there are type definitions/errors with PluginOption
rg -n "PluginOption|defineProject" core/typed-events/vitest.config.ts -A3 -B3 || echo "No matches"Repository: stephansama/packages
Length of output: 315
🏁 Script executed:
# Check vite-tsconfig-paths actual types and what it exports
cd core/typed-events && npx -y tsc --noEmit 2>&1 | head -40 || echo "No immediate errors"Repository: stephansama/packages
Length of output: 229
🏁 Script executed:
# Check vite version in examples vs core to see the divergence
grep -A2 '"vite"' examples/typed-events/react/package.json core/typed-events/package.jsonRepository: stephansama/packages
Length of output: 263
🏁 Script executed:
# Verify the type incompatibility: what does tsconfigPaths actually return?
rg "export.*function tsconfigPaths|declare.*tsconfigPaths" node_modules/.pnpm/vite-tsconfig-paths*/node_modules/vite-tsconfig-paths -A5 | head -30Repository: stephansama/packages
Length of output: 177
🏁 Script executed:
# Find where vite-tsconfig-paths is actually installed
find node_modules -name "vite-tsconfig-paths" -type d | head -5Repository: stephansama/packages
Length of output: 46
🏁 Script executed:
# Look for the installed vite-tsconfig-paths package and check its types
find node_modules -path "*/vite-tsconfig-paths/package.json" | head -1 | xargs cat | grep -A10 '"main"\|"types"\|"exports"'Repository: stephansama/packages
Length of output: 46
🏁 Script executed:
# Check what tsconfigPaths() actually returns by looking at its implementation/types
find node_modules -path "*/vite-tsconfig-paths/dist/*.d.ts" | head -1 | xargs cat 2>/dev/null | head -50Repository: stephansama/packages
Length of output: 46
🏁 Script executed:
# Search for other vitest configs in the workspace to see if they also use 'any' cast
rg -l "vitest.config\.(ts|js)" core/ examples/Repository: stephansama/packages
Length of output: 269
🏁 Script executed:
# Check those files for the same pattern
rg -n "as any|PluginOption" --type=ts core/*/vitest.config.ts examples/*/vitest.config.ts 2>/dev/null || echo "No matches or files"Repository: stephansama/packages
Length of output: 308
🏁 Script executed:
# Look at pnpm-lock to understand actual resolved versions for vite
rg "vite@6\.|vite@7\." pnpm-lock.yaml | head -5Repository: stephansama/packages
Length of output: 1636
🏁 Script executed:
# Check if there's any documentation or issue about vite + vitest compatibility
rg "vitest.*vite.*compat|vite.*version.*6\.|vite.*version.*7\." core/typed-events/ examples/typed-events/ 2>/dev/null || echo "No matches"Repository: stephansama/packages
Length of output: 75
Update catalog vite version to align with vite-tsconfig-paths@5.1.4.
The any cast suppresses a real type incompatibility. The catalog locks vite@6.3.5, but vite-tsconfig-paths@5.1.4 is tested and works with vite@7.3.1 (as shown in examples). This version mismatch cascades across three packages—core/typed-events, core/typed-templates, and core/catppuccin-xsl—all using the same cast.
Update pnpm-workspace.yaml catalog to set vite: 7.3.1 (or compatible higher version) to resolve the type alignment and remove the need for as any.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/typed-events/vitest.config.ts` around lines 5 - 6, Update the catalog's
pinned vite version to a compatible release (e.g., vite 7.3.1) in the
pnpm-workspace.yaml so it matches the version used by vite-tsconfig-paths@5.1.4,
then remove the suppressing cast on the plugin import (replace plugins:
[tsconfigPaths() as any] with plugins: [tsconfigPaths()] ) in the files that
used the cast (look for tsconfigPaths() usages in
core/typed-events/vitest.config.ts, core/typed-templates/... and
core/catppuccin-xsl/...), rebuild types and ensure no type errors remain.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.config/www/package.json:
- Around line 17-18: The two npm scripts setup:healthcheck and setup:meta can
fail if the public/ directory is missing; update those script entries so they
ensure the directory exists before redirecting output (e.g., run a mkdir -p
public step or use a Node write call) so writing to public/healthcheck.json and
public/meta.json never errors; change the commands for "setup:healthcheck" and
"setup:meta" accordingly to create public/ first then produce the JSON files.
In `@eslint.config.ts`:
- Line 11: Update the ignores array in eslint.config.ts to remove the leading
"./" from the glob patterns; specifically change the entries using
`./turbo/generators/**` and `./.config/www/api/**` to `turbo/generators/**` and
`.config/www/api/**` (or use `**/turbo/generators/**` style), by editing the
ignores property so it follows the ESLint flat config glob conventions.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: f9df6cfc-e271-4dce-8f15-fc896dfb2d8b
📒 Files selected for processing (3)
.config/www/package.jsoneslint.config.tsscripts/package.json
| "setup:healthcheck": "node -e \"console.log(JSON.stringify({message: Date.now()}))\" >public/healthcheck.json", | ||
| "setup:meta": "pnpm --filter=scripts meta >public/meta.json", |
There was a problem hiding this comment.
Ensure public/ exists before redirecting output
Line 17 and Line 18 can fail on clean environments when public/ is missing, because shell redirection (>public/...) does not create parent directories. This can break setup/predev.
Proposed fix
- "setup:healthcheck": "node -e \"console.log(JSON.stringify({message: Date.now()}))\" >public/healthcheck.json",
- "setup:meta": "pnpm --filter=scripts meta >public/meta.json",
+ "setup:healthcheck": "node -e \"const fs=require('node:fs'); fs.mkdirSync('public',{recursive:true}); console.log(JSON.stringify({message: Date.now()}))\" >public/healthcheck.json",
+ "setup:meta": "node -e \"require('node:fs').mkdirSync('public',{recursive:true})\" && pnpm --filter=scripts meta >public/meta.json",📝 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.
| "setup:healthcheck": "node -e \"console.log(JSON.stringify({message: Date.now()}))\" >public/healthcheck.json", | |
| "setup:meta": "pnpm --filter=scripts meta >public/meta.json", | |
| "setup:healthcheck": "node -e \"const fs=require('node:fs'); fs.mkdirSync('public',{recursive:true}); console.log(JSON.stringify({message: Date.now()}))\" >public/healthcheck.json", | |
| "setup:meta": "node -e \"require('node:fs').mkdirSync('public',{recursive:true})\" && pnpm --filter=scripts meta >public/meta.json", |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.config/www/package.json around lines 17 - 18, The two npm scripts
setup:healthcheck and setup:meta can fail if the public/ directory is missing;
update those script entries so they ensure the directory exists before
redirecting output (e.g., run a mkdir -p public step or use a Node write call)
so writing to public/healthcheck.json and public/meta.json never errors; change
the commands for "setup:healthcheck" and "setup:meta" accordingly to create
public/ first then produce the JSON files.
| e18e: { | ||
| banDependenciesAllowList: ["cosmiconfig"], | ||
| }, | ||
| ignore: [`./turbo/generators/**`, `./.config/www/api/**`], |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Verify the ignore paths exist and check ESLint flat config ignore pattern expectations
# Check if the paths exist
echo "Checking if paths exist:"
[ -d "turbo/generators" ] && echo "✓ turbo/generators exists" || echo "✗ turbo/generators not found"
[ -d ".config/www/api" ] && echo "✓ .config/www/api exists" || echo "✗ .config/www/api not found"
# Search for any ESLint ignore pattern documentation or examples in the codebase
echo -e "\nSearching for ignore pattern usage in eslint-config:"
rg -n -C2 'ignore.*:\s*\[' core/eslint-config/src/ --type tsRepository: stephansama/packages
Length of output: 591
🏁 Script executed:
#!/bin/bash
# Read the eslint.config.ts file to see the full context
echo "=== eslint.config.ts file ==="
cat -n eslint.config.ts | head -40
# Check if .config/www/api directory exists or if it appears anywhere in the codebase
echo -e "\n=== Searching for .config/www/api references ==="
rg -r '\.config/www/api' --max-count 5
# Check if .config directory structure exists
echo -e "\n=== Checking .config directory structure ==="
[ -d ".config" ] && find .config -type d | head -20 || echo "No .config directory found"Repository: stephansama/packages
Length of output: 1965
🏁 Script executed:
#!/bin/bash
# Search for any references to www/api or history of this path
echo "=== Searching for www/api in codebase ==="
rg 'www/api' --max-count 10
# Check git history for this file if available
echo -e "\n=== Git history for eslint.config.ts ==="
git log --oneline eslint.config.ts | head -10
# Search for ESLint ignore pattern documentation/comments in the config file
echo -e "\n=== Full eslint.config.ts content (up to line 15) ==="
head -15 eslint.config.ts
# Check if there's any documentation about ignore patterns
echo -e "\n=== Searching for ignore pattern documentation ==="
rg 'ignore.*pattern|ignore.*glob' . --type md --max-count 5Repository: stephansama/packages
Length of output: 1587
🏁 Script executed:
#!/bin/bash
# Check the git commit that added www package linting
echo "=== Git show for www package linting commit ==="
git show bc36958 --stat
# Check if there's actually a www package and what directories it has
echo -e "\n=== www package structure ==="
find . -path "./.git" -prune -o -type d -name "www" -print | head -5
ls -la .config/www/ 2>/dev/null || echo "No .config/www"
# Check ESLint flat config documentation for ignore pattern syntax
echo -e "\n=== Looking for ESLint config documentation or comments ==="
rg '@stephansama/eslint-config' . --type ts -B2 -A2 | head -30Repository: stephansama/packages
Length of output: 1626
🏁 Script executed:
#!/bin/bash
# Check the actual change in that commit to understand what happened
echo "=== Git show diff for eslint.config.ts ==="
git show bc36958 eslint.config.ts
# Check if api directory is supposed to exist elsewhere
echo -e "\n=== Searching for 'api' in .config/www ==="
find .config/www -type f -name "*api*" 2>/dev/null || echo "No api files found"
find .config/www -type d -name "*api*" 2>/dev/null || echo "No api directories found"
# Check if there's a generated or build artifact that creates this directory
echo -e "\n=== Checking build/dist output or generated folders ==="
ls -la .config/www/.vitepress/ 2>/dev/null | head -10Repository: stephansama/packages
Length of output: 1062
🏁 Script executed:
#!/bin/bash
# Check the ESLint config package to see how ignore patterns are documented
echo "=== ESLint config package ignore handling ==="
cat core/eslint-config/src/index.ts | head -50
# Search for how ignore patterns are processed
echo -e "\n=== Searching for ignore pattern processing in eslint-config ==="
rg -n 'ignore' core/eslint-config/src/index.ts -A3 -B3 | head -40
# Check if there's any README or documentation for the eslint-config package
echo -e "\n=== Checking eslint-config documentation ==="
ls -la core/eslint-config/Repository: stephansama/packages
Length of output: 1135
🏁 Script executed:
#!/bin/bash
# Check the builder to understand how ignore patterns are processed
echo "=== ESLint config builder source ==="
cat core/eslint-config/src/builder.ts | head -100
# Look for the types to understand the ignore option
echo -e "\n=== Searching for ignore type definition ==="
rg -n 'ignore.*:' core/eslint-config/src/types.ts -B2 -A2Repository: stephansama/packages
Length of output: 1930
🏁 Script executed:
#!/bin/bash
# Find the types file and check its full content
echo "=== Finding type definitions ==="
find core/eslint-config/src -name "types.ts" -o -name "types.d.ts"
# Read the types file
echo -e "\n=== Type definitions file ==="
cat core/eslint-config/src/types.ts
# Also check the configs directory for ignore handling
echo -e "\n=== Looking for ignore config ==="
ls -la core/eslint-config/src/configs/Repository: stephansama/packages
Length of output: 2824
🏁 Script executed:
#!/bin/bash
# Check the ignore.ts config file
echo "=== ignore.ts config ==="
cat core/eslint-config/src/configs/ignore.ts
# Also check the index.ts to see how ignore is exported
echo -e "\n=== index.ts config export ==="
cat core/eslint-config/src/configs/index.tsRepository: stephansama/packages
Length of output: 2367
🏁 Script executed:
#!/bin/bash
# Check if there's any .gitignore or documentation about what .config/www/api should contain
echo "=== Checking for .gitignore entries ==="
cat .gitignore | grep -E "api|www" || echo "No matching entries"
# Check if there are any similar patterns for www in git history
echo -e "\n=== Git log for changes related to www/api ==="
git log --all --grep="api" --oneline | head -10
# Check ESLint documentation or examples in the codebase
echo -e "\n=== Checking glob patterns used elsewhere ==="
rg 'ignores|glob\.EXCLUDES' core/eslint-config/src/glob.ts -A5Repository: stephansama/packages
Length of output: 603
🏁 Script executed:
#!/bin/bash
# Check the glob patterns module to understand how ESLint ignores work
echo "=== glob.ts file ==="
cat core/eslint-config/src/glob.ts
# Verify if .config/www/api appears in .gitignore
echo -e "\n=== Checking .gitignore for the api directory ==="
grep -n "api" .gitignore
# Search for ESLint flat config documentation about ignore patterns
echo -e "\n=== Checking ESLint config examples in project ==="
rg -n 'ignores.*:\s*\[' . --type ts -A2 | head -30Repository: stephansama/packages
Length of output: 1705
🏁 Script executed:
#!/bin/bash
# Check ESLint flat config documentation or comments
echo "=== Searching for ESLint flat config ignore pattern documentation ==="
rg -n 'ignores' core/eslint-config --type ts -B2 -A2 | head -50
# Check if there are any tests or examples showing correct ignore patterns
echo -e "\n=== Looking for test files related to ignore ==="
find . -name "*.test.ts" -o -name "*.spec.ts" | xargs grep -l "ignore" 2>/dev/null | head -5
# Verify the pattern format by checking if glob.EXCLUDES patterns work
echo -e "\n=== Sample EXCLUDES patterns from glob.ts ==="
grep -E "node_modules|dist" core/eslint-config/src/glob.tsRepository: stephansama/packages
Length of output: 1166
Remove the ./ prefix from ignore patterns for consistency with ESLint flat config conventions.
The ignore patterns use ./ prefix (./turbo/generators/**, ./.config/www/api/**), but throughout the codebase ESLint flat config patterns are defined without this prefix (e.g., **/node_modules, **/dist, node_modules). ESLint flat config ignores expects glob patterns in standard format. Update to: turbo/generators/** and .config/www/api/** (or use explicit glob syntax like **/turbo/generators/**).
Note: .config/www/api is currently listed in .gitignore and doesn't exist on the filesystem, which is intentional. The pattern itself is valid for pre-emptively ignoring future or build-generated content.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@eslint.config.ts` at line 11, Update the ignores array in eslint.config.ts to
remove the leading "./" from the glob patterns; specifically change the entries
using `./turbo/generators/**` and `./.config/www/api/**` to
`turbo/generators/**` and `.config/www/api/**` (or use `**/turbo/generators/**`
style), by editing the ignores property so it follows the ESLint flat config
glob conventions.
@stephansama/ai-commit-msg
@stephansama/alfred-kaomoji
@stephansama/astro-iconify-svgmap
@stephansama/auto-readme
@stephansama/catppuccin-jsonresume-theme
@stephansama/catppuccin-opml
@stephansama/catppuccin-rss
@stephansama/catppuccin-typedoc
@stephansama/catppuccin-xsl
@stephansama/eslint-config
create-stephansama-example
@stephansama/find-makefile-targets
@stephansama/github-env
@stephansama/multipublish
@stephansama/prettier-plugin-handlebars
@stephansama/remark-asciinema
@stephansama/single-file
@stephansama/svelte-social-share-links
@stephansama/typed-env
@stephansama/typed-events
@stephansama/typed-nocodb-api
@stephansama/typed-templates
@stephansama/types-github-action-env
@stephansama/types-lhci
commit: |
There was a problem hiding this comment.
Actionable comments posted: 10
♻️ Duplicate comments (2)
.config/www/package.json (1)
18-19:⚠️ Potential issue | 🟠 Major | ⚡ Quick winEnsure
public/exists before writing redirected files.On Line 18 and Line 19, shell redirection to
public/*.jsoncan fail in clean environments wherepublic/is absent. This is still a release-impacting setup break.Proposed fix
- "setup:healthcheck": "node -e \"console.log(JSON.stringify({message: Date.now()}))\" >public/healthcheck.json", - "setup:meta": "pnpm --filter=scripts meta >public/meta.json", + "setup:healthcheck": "node -e \"require('node:fs').mkdirSync('public',{recursive:true}); console.log(JSON.stringify({message: Date.now()}))\" >public/healthcheck.json", + "setup:meta": "node -e \"require('node:fs').mkdirSync('public',{recursive:true})\" && pnpm --filter=scripts meta >public/meta.json",🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.config/www/package.json around lines 18 - 19, The package.json scripts "setup:healthcheck" and "setup:meta" currently redirect output into public/*.json which will fail if the public directory is missing; update both scripts so they ensure the public directory exists first (e.g., create the directory if absent) before writing the files, keeping the existing output behavior and exit codes intact. Locate the "setup:healthcheck" and "setup:meta" entries and prepend a step that guarantees creation of public/ (or switch to a small Node one-liner that creates the directory then writes the JSON) so redirection never fails in clean environments.core/ai-commit-msg/tsconfig.json (1)
9-11:⚠️ Potential issue | 🟠 Major | ⚡ Quick winMissing
composite: truefor monorepo project references.This package's tsconfig is missing
compilerOptions.composite: true, which other packages in this PR include. This prevents the package from participating in the monorepo's composite build graph and incremental compilation.🔧 Proposed fix
"compilerOptions": { - "types": ["node"] + "types": ["node"], + "composite": true }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/ai-commit-msg/tsconfig.json` around lines 9 - 11, Add "compilerOptions.composite": true to this package's tsconfig so it can participate in the monorepo's project references and incremental build; update the "compilerOptions" object in core/ai-commit-msg/tsconfig.json to include composite: true (alongside existing "types": ["node"]) so the project becomes a composite project.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@core/ai-commit-msg/tsdown.config.ts`:
- Line 26: The JSON schema is being serialized as a single-line string via
JSON.stringify(jsonSchema); update the serialization to produce pretty-printed
output (e.g., use JSON.stringify(jsonSchema, null, 2) or an equivalent spacing
argument) so the file written from jsonString is human-readable; locate the
JSON.stringify call for the jsonSchema (variable jsonString) in tsdown.config.ts
and replace it with the formatted stringify form.
In `@core/auto-readme/package.json`:
- Around line 94-95: The package.json has duplicate or misplaced "main" and
"module" fields at the end; move the "main" and "module" entries so they sit
with the other entry-point metadata (near "exports", "types", and
"bin")—specifically add "main": "./dist/index.cjs" and "module":
"./dist/index.mjs" after the "types" entry (with the other exports/bin fields)
and remove the duplicate definitions at the file bottom so there is a single
canonical definition.
- Line 40: The package.json currently sets "types": "./dist/index.d.cts" and
lacks types conditions in the conditional "exports", causing ESM consumers to
resolve CJS declarations; update the conditional exports for the root export
(the "." export) to include "types" under both "import" and "require" conditions
so the ESM path points to "./dist/index.d.mts" and the CJS path points to
"./dist/index.d.cts" while keeping the existing default module file paths (e.g.,
"./dist/index.mjs" and "./dist/index.cjs"); modify the "exports" object to
include these "types" entries alongside "default" for "import" and "require".
In `@core/auto-readme/tsdown.config.ts`:
- Line 12: The format property in tsdown.config.ts uses single-quoted values
('esm', 'cjs'); change both occurrences of those array entries to use double
quotes ("esm", "cjs") to match the project's tsdown config style and other
files, updating the format = ['esm','cjs'] arrays accordingly.
- Line 26: The JSON schema is being serialized to a single-line string; change
the JSON.stringify call that assigns jsonSchemaFile to produce pretty-printed
output by passing spacing (e.g., JSON.stringify(jsonSchema, null, 2)) so the
written schema file is human-readable—update the assignment to jsonSchemaFile
accordingly (look for the const jsonSchemaFile = JSON.stringify(jsonSchema)
expression).
In `@core/multipublish/tsdown.config.ts`:
- Line 2: The file incorrectly uses a default import from 'node:path' which
yields undefined; change the import to a valid ESM import (e.g., use a namespace
import or named import) and update usages accordingly — for example replace the
default import of path with a namespace import and ensure the call at
path.join(...) (line referencing path.join) still references the correct symbol
(or import join and replace path.join(...) with join(...)) so runtime calls
succeed.
- Around line 28-31: The writeFile call using fs.promises.writeFile (the code
that writes "./config/schema.json") lacks error handling; wrap the await
fs.promises.writeFile(...) in a try/catch, log the caught error with details
(e.g., using console.error or the existing logger if available), and rethrow or
exit with a non-zero status so the build hook fails fast when writing the file
fails; ensure you reference the existing write operation (fs.promises.writeFile
and path.join("./config/", "schema.json")) when applying the change.
In `@core/svelte-social-share-links/tsconfig.tsbuildinfo`:
- Line 1: Remove the generated tsbuildinfo artifact from version control and
ignore future ones: delete or git rm --cached the committed
core/svelte-social-share-links/tsconfig.tsbuildinfo file, add a rule to the
repository/package .gitignore to include *.tsbuildinfo (or specifically
tsconfig.tsbuildinfo), and commit that change so subsequent incremental build
metadata is not tracked; if CI or other branches already contain it, ensure you
remove it from those branches or create a follow-up commit to clean the tracked
file.
In `@core/types-lhci/package.json`:
- Line 31: The package.json currently points the top-level "types" to
"./dist/index.d.cts", which serves only CommonJS declarations; update
package.json to either add conditional "types" under "exports" so ESM imports
use "./dist/index.d.mts" and CJS require uses "./dist/index.d.cts" (mirroring
"import"/"require" defaults), or change the top-level "types" to
"./dist/index.d.mts" if you prefer a simpler single-file approach; ensure you
adjust the "exports" object for "." to include "types" alongside the existing
"import" and "require" keys so TypeScript consumers get matching .d.mts/.d.cts
files.
In `@core/types-lhci/tsdown.config.ts`:
- Line 17: The JSON schema is being serialized into a single-line string via
JSON.stringify(jsonSchema) which hurts readability; update the serialization
used where jsonString is assigned to call JSON.stringify(jsonSchema, null, 2)
(or another suitable indent) so the output file is pretty-printed, and ensure
any downstream writer that consumes jsonString still writes the formatted
string.
---
Duplicate comments:
In @.config/www/package.json:
- Around line 18-19: The package.json scripts "setup:healthcheck" and
"setup:meta" currently redirect output into public/*.json which will fail if the
public directory is missing; update both scripts so they ensure the public
directory exists first (e.g., create the directory if absent) before writing the
files, keeping the existing output behavior and exit codes intact. Locate the
"setup:healthcheck" and "setup:meta" entries and prepend a step that guarantees
creation of public/ (or switch to a small Node one-liner that creates the
directory then writes the JSON) so redirection never fails in clean
environments.
In `@core/ai-commit-msg/tsconfig.json`:
- Around line 9-11: Add "compilerOptions.composite": true to this package's
tsconfig so it can participate in the monorepo's project references and
incremental build; update the "compilerOptions" object in
core/ai-commit-msg/tsconfig.json to include composite: true (alongside existing
"types": ["node"]) so the project becomes a composite project.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: fa91e625-8861-44c8-a958-78fc4761d2f3
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (18)
.config/www/package.jsoncore/ai-commit-msg/package.jsoncore/ai-commit-msg/test/index.test.tscore/ai-commit-msg/tsconfig.jsoncore/ai-commit-msg/tsdown.config.tscore/auto-readme/package.jsoncore/auto-readme/tsconfig.jsoncore/auto-readme/tsdown.config.tscore/eslint-config/package.jsoncore/example/package.jsoncore/multipublish/package.jsoncore/multipublish/tsconfig.jsoncore/multipublish/tsdown.config.tscore/svelte-social-share-links/tsconfig.tsbuildinfocore/types-lhci/build.tscore/types-lhci/package.jsoncore/types-lhci/tsconfig.jsoncore/types-lhci/tsdown.config.ts
💤 Files with no reviewable changes (1)
- core/types-lhci/build.ts
|
|
||
| const jsonSchema = z.toJSONSchema(configSchema); | ||
|
|
||
| const jsonString = JSON.stringify(jsonSchema); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Consider formatting the JSON output for readability.
The JSON schema is written as a single-line string. Adding formatting would improve readability for developers inspecting the schema file.
📝 Suggested improvement
- const jsonString = JSON.stringify(jsonSchema);
+ const jsonString = JSON.stringify(jsonSchema, null, 2);📝 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.
| const jsonString = JSON.stringify(jsonSchema); | |
| const jsonString = JSON.stringify(jsonSchema, null, 2); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/ai-commit-msg/tsdown.config.ts` at line 26, The JSON schema is being
serialized as a single-line string via JSON.stringify(jsonSchema); update the
serialization to produce pretty-printed output (e.g., use
JSON.stringify(jsonSchema, null, 2) or an equivalent spacing argument) so the
file written from jsonString is human-readable; locate the JSON.stringify call
for the jsonSchema (variable jsonString) in tsdown.config.ts and replace it with
the formatted stringify form.
| "main": "./config/schema.cjs", | ||
| "module": "./config/schema.mjs", | ||
| "types": "./config/schema.d.cts", | ||
| "types": "./dist/index.d.cts", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check tsdown config for declaration file generation
# Look for tsdown configuration
fd -t f 'tsdown.config' core/auto-readme
# Check declaration settings
rg -n "dts|declaration" core/auto-readme/tsdown.config.ts -A2 -B2Repository: stephansama/packages
Length of output: 291
🏁 Script executed:
# Read the package.json to see the types and module fields
cat -n core/auto-readme/package.json | sed -n '35,50p'Repository: stephansama/packages
Length of output: 585
🏁 Script executed:
# Get more context on the module field mentioned at line 95
cat -n core/auto-readme/package.json | sed -n '90,100p'Repository: stephansama/packages
Length of output: 249
🏁 Script executed:
# View the complete tsdown config to understand declaration file generation
cat -n core/auto-readme/tsdown.config.tsRepository: stephansama/packages
Length of output: 1104
🏁 Script executed:
# Check what files exist in dist/
fd -t f . core/auto-readme/dist 2>/dev/null | head -20Repository: stephansama/packages
Length of output: 46
🏁 Script executed:
# Also check the exports field in package.json for context on how types are declared
cat -n core/auto-readme/package.json | sed -n '1,45p'Repository: stephansama/packages
Length of output: 1460
🏁 Script executed:
# Search for tsdown documentation or examples in the repo
rg -i "tsdown" core/auto-readme --type mdRepository: stephansama/packages
Length of output: 124
🏁 Script executed:
# Check if there's any TypeScript configuration that might affect declaration generation
cat -n core/auto-readme/tsconfig.json 2>/dev/null || echo "No tsconfig.json"Repository: stephansama/packages
Length of output: 323
🏁 Script executed:
# Search for any comments or documentation about the types field
rg -n "types.*d\." core/auto-readme/package.json -B2 -A2Repository: stephansama/packages
Length of output: 191
🏁 Script executed:
# Look at other packages to see their pattern
fd -t f 'package.json' core --max-depth 2 | head -5Repository: stephansama/packages
Length of output: 244
🏁 Script executed:
# Check one other package's structure for comparison
cat core/button/package.json | rg -n "types|module|main|exports" -A1 -B1Repository: stephansama/packages
Length of output: 121
🏁 Script executed:
# Search for any .d.cts or .d.mts files in the repository to understand the pattern
fd -t f '\.d\.(cts|mts|ts)' coreRepository: stephansama/packages
Length of output: 334
🏁 Script executed:
# Check if there's a build output or dist directory in git
git ls-files core/auto-readme/dist | head -10Repository: stephansama/packages
Length of output: 46
🏁 Script executed:
# Look for any issues or notes about types in the repository
rg -n "\.d\.cts|\.d\.mts" core --type md --type tsRepository: stephansama/packages
Length of output: 149
🏁 Script executed:
# Search for tsdown in the root to understand the tool better
fd -t f 'package.json' . --max-depth 1 | xargs rg "tsdown" 2>/dev/nullRepository: stephansama/packages
Length of output: 48
🌐 Web query:
tsdown TypeScript declaration file generation strategy dual format esm cjs
💡 Result:
For tsdown, the recommended dual ESM+CJS declaration-file strategy is: 1) Build ESM + CJS in one tsdown config (dual-format), and enable dts generation (either via package.json “types/typings” or dts: true / --dts). - tsdown lets you request multiple output formats in one build via format: ["esm", "cjs"] [1]. - dts generation is enabled automatically when package.json has a types/typings field, or explicitly via the --dts option / dts: true config [2]. - tsdown’s dts system is implemented with rolldown-plugin-dts (and it may use a fast oxc-transform path when tsconfig has isolatedDeclarations) [2]. Example tsdown.config.ts: import { defineConfig } from "tsdown"; export default defineConfig([ { entry: "src/index.ts", format: ["esm", "cjs"], dts: true, }, ]); (Using format as an array for dual-format is explicitly documented) [1]. 2) In dual-format builds, tsdown generates ESM declarations as.d.mts and CJS declarations as.d.cts (rather than reusing the same.d.ts file for both). This is reflected in tsdown’s documented dual-package behavior and the existence of CJS/ESM-specific declaration extensions used in dual ESM+CJS setups [3][4][5]. 3) Prefer tsdown’s “single source of truth” option for declarations: dts.cjsReexport. - tsdown has a dts.cjsReexport option that, when building both esm and cjs simultaneously, generates a.d.cts “re-export stub” instead of doing a second independent TypeScript compilation pass [5]. - The goal is to eliminate the TypeScript “dual module hazard” where separate.d.cts and.d.mts files can trigger TS2352 errors in some consumer/casting scenarios; tsdown achieves this by re-exporting everything from the corresponding.d.mts [5]. So, your dual declaration strategy should look like: export default defineConfig([ { entry: "src/index.ts", format: ["esm", "cjs"], dts: { cjsReexport: true, }, }, ]); (“cjsReexport generates a.d.cts re-export stub” and “eliminates the dual module hazard” are explicitly stated) [5]. 4) Package.json wiring: ensure conditional exports point TypeScript at the right declaration file(s). - For dual publish, you typically use package.json “exports” with import/require conditions and include a “types” condition for each; multiple guides stress that the types condition is important for resolution [6][7]. Putting it all together, the practical strategy is: - Use tsdown dual format (format: ["esm", "cjs"]) [1]. - Enable dts generation (dts: true or via types/typings field) [2]. - Set dts.cjsReexport: true to avoid the second declaration compilation pass and instead emit a CJS declaration re-export stub from the ESM declaration [5]. - Configure package.json exports so TypeScript picks the correct declaration under both import (ESM) and require (CJS) paths [6][7].
Citations:
- 1: https://tsdown.dev/guide/how-it-works
- 2: https://tsdown.dev/options/dts
- 3: https://dev.to/hacksore/dual-publish-esm-and-cjs-with-tsdown-2l75
- 4: feat(dts): add
cjsReexportoption to eliminate dual module type hazard rolldown/tsdown#856 - 5: https://tsdown.dev/reference/api/Interface.DtsOptions
- 6: https://esmodules.com/publishing/
- 7: https://blog.johnnyreilly.com/dual-publishing-esm-cjs-modules-with-tsup-and-are-the-types-wrong
Add types conditions to the conditional exports for proper TypeScript resolution.
The types field points to ./dist/index.d.cts (CommonJS declaration), but the ESM module (./dist/index.mjs) needs corresponding .d.mts type declarations. With tsdown's dual-format build generating both .d.mts (ESM) and .d.cts (CJS) declarations, TypeScript consumers will incorrectly resolve CommonJS types when importing the ESM module due to the top-level types fallback. Add types conditions to the conditional exports:
"exports": {
".": {
"import": { "types": "./dist/index.d.mts", "default": "./dist/index.mjs" },
"require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" }
}
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/auto-readme/package.json` at line 40, The package.json currently sets
"types": "./dist/index.d.cts" and lacks types conditions in the conditional
"exports", causing ESM consumers to resolve CJS declarations; update the
conditional exports for the root export (the "." export) to include "types"
under both "import" and "require" conditions so the ESM path points to
"./dist/index.d.mts" and the CJS path points to "./dist/index.d.cts" while
keeping the existing default module file paths (e.g., "./dist/index.mjs" and
"./dist/index.cjs"); modify the "exports" object to include these "types"
entries alongside "default" for "import" and "require".
| async "build:done"() { | ||
| const { configSchema } = await import("./config/schema.mjs"); | ||
| const jsonSchema = z.toJSONSchema(configSchema); | ||
| const jsonSchemaFile = JSON.stringify(jsonSchema); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Consider formatting the JSON output for readability.
The JSON schema is written as a single-line string. Adding formatting would improve readability for developers inspecting the schema file.
📝 Suggested improvement
- const jsonSchemaFile = JSON.stringify(jsonSchema);
+ const jsonSchemaFile = JSON.stringify(jsonSchema, null, 2);📝 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.
| const jsonSchemaFile = JSON.stringify(jsonSchema); | |
| const jsonSchemaFile = JSON.stringify(jsonSchema, null, 2); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/auto-readme/tsdown.config.ts` at line 26, The JSON schema is being
serialized to a single-line string; change the JSON.stringify call that assigns
jsonSchemaFile to produce pretty-printed output by passing spacing (e.g.,
JSON.stringify(jsonSchema, null, 2)) so the written schema file is
human-readable—update the assignment to jsonSchemaFile accordingly (look for the
const jsonSchemaFile = JSON.stringify(jsonSchema) expression).
| @@ -0,0 +1,38 @@ | |||
| import * as fs from "node:fs"; | |||
| import path from "node:path"; | |||
There was a problem hiding this comment.
Fix incorrect default import of node:path.
Node.js built-in modules like node:path do not export a default export in ESM. Line 29 uses path.join(), which will fail at runtime because path will be undefined.
🔧 Proposed fix
-import path from "node:path";
+import * as path from "node:path";Alternatively, use named imports:
-import path from "node:path";
+import { join } from "node:path";And update line 29:
- path.join("./config/", "schema.json"),
+ join("./config/", "schema.json"),📝 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.
| import path from "node:path"; | |
| import * as path from "node:path"; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/multipublish/tsdown.config.ts` at line 2, The file incorrectly uses a
default import from 'node:path' which yields undefined; change the import to a
valid ESM import (e.g., use a namespace import or named import) and update
usages accordingly — for example replace the default import of path with a
namespace import and ensure the call at path.join(...) (line referencing
path.join) still references the correct symbol (or import join and replace
path.join(...) with join(...)) so runtime calls succeed.
| await fs.promises.writeFile( | ||
| path.join("./config/", "schema.json"), | ||
| jsonString, | ||
| ); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Consider adding error handling for file write operation.
The writeFile operation can fail due to permissions, disk space, or other I/O errors. Since this runs in a build hook, a failed write would silently complete the build without the expected schema.json artifact.
🛡️ Proposed fix to add error handling
async "build:done"() {
const { configSchema } = await import("./config/schema.mjs");
const jsonSchema = z.toJSONSchema(configSchema);
const jsonString = JSON.stringify(jsonSchema);
- await fs.promises.writeFile(
- path.join("./config/", "schema.json"),
- jsonString,
- );
+ try {
+ await fs.promises.writeFile(
+ path.join("./config/", "schema.json"),
+ jsonString,
+ );
+ } catch (error) {
+ console.error("Failed to write schema.json:", error);
+ throw error;
+ }
},📝 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.
| await fs.promises.writeFile( | |
| path.join("./config/", "schema.json"), | |
| jsonString, | |
| ); | |
| async "build:done"() { | |
| const { configSchema } = await import("./config/schema.mjs"); | |
| const jsonSchema = z.toJSONSchema(configSchema); | |
| const jsonString = JSON.stringify(jsonSchema); | |
| try { | |
| await fs.promises.writeFile( | |
| path.join("./config/", "schema.json"), | |
| jsonString, | |
| ); | |
| } catch (error) { | |
| console.error("Failed to write schema.json:", error); | |
| throw error; | |
| } | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/multipublish/tsdown.config.ts` around lines 28 - 31, The writeFile call
using fs.promises.writeFile (the code that writes "./config/schema.json") lacks
error handling; wrap the await fs.promises.writeFile(...) in a try/catch, log
the caught error with details (e.g., using console.error or the existing logger
if available), and rethrow or exit with a non-zero status so the build hook
fails fast when writing the file fails; ensure you reference the existing write
operation (fs.promises.writeFile and path.join("./config/", "schema.json")) when
applying the change.
| "main": "./dist/index.cjs", | ||
| "module": "./dist/index.js", | ||
| "module": "./dist/index.mjs", | ||
| "types": "./dist/index.d.cts", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check tsdown config and verify declaration file generation
# Look for tsdown configuration
fd -t f 'tsdown.config' core/types-lhci
# Check what declaration files are expected to be generated
rg -n "dts|declaration" core/types-lhci/tsdown.config.ts -A2 -B2Repository: stephansama/packages
Length of output: 192
🏁 Script executed:
# Read the full tsdown config
cat core/types-lhci/tsdown.config.tsRepository: stephansama/packages
Length of output: 705
🏁 Script executed:
# Read the full package.json to see the complete exports and types configuration
cat core/types-lhci/package.jsonRepository: stephansama/packages
Length of output: 1430
🌐 Web query:
tsdown declaration files esm cjs .d.ts .d.mts .d.cts generation
💡 Result:
Summary: tsdown/rolldown-plugin-dts primarily generates/bundles .d.ts (and supports .d.cts stubs when building both ESM+CJS). Generating fully separate, extension-matched declaration files like .d.mts and .d.cts is tied to TypeScript/exports semantics and is not something tsdown automatically documents as producing by default; you typically wire type paths per exports conditions in package.json. 1) What the tools generate (tsdown) - tsdown can generate declaration files when package.json has types/typings, or when you enable --dts / dts: true in config [1][2]. - tsdown uses rolldown-plugin-dts internally for .d.ts generation/bundling [1][2]. - Build behavior note: for ESM, .js and .d.ts are generated in the same build process; for CJS, tsdown uses a separate build process exclusively for .d.ts generation “to ensure compatibility” [1][2]. - When building both esm and cjs formats simultaneously, tsdown’s DTS options mention generating a .d.cts re-export stub “instead of running a full second TypeScript compilation pass”; the stub re-exports everything from the corresponding .d.mts file [3]. - So tsdown’s documented dual-module approach is: one “real” declaration set for ESM (as .d.mts), and a CJS stub layer (as .d.cts) that points back to the ESM .d.mts declarations [3]. 2) What TypeScript expects for .d.mts / .d.cts - TypeScript supports separate declaration files for ESM vs CJS via the .d.mts and .d.cts extensions (introduced alongside TypeScript’s module resolution/exports enhancements; discussed in tsup’s feature request context) [4]. - In practice, consumers need the package’s exports map to route types to the appropriate declaration file per condition (e.g., import vs require), otherwise TypeScript may not pick the extension-appropriate .d.mts/.d.cts [5][6]. 3) How generation ties to rollup-plugin-dts (rolldown-plugin-dts) - rolldown-plugin-dts is the plugin tsdown uses for .d.ts bundling [1][2]. - The plugin documents that it can produce .d.ts in a “single build” for ESM, but that CommonJS requires “two distinct build processes” for .cjs and its corresponding type definition files (notably .d.cts) [7][8]. - emitDtsOnly exists specifically to help with a separate DTS generation pass for CJS [7][8]. 4) Practical packaging: use exports with per-condition types - With conditional exports, you should specify types under the import and require branches so TypeScript resolves to the correct declaration extension for each runtime format [5][6]. - Example shape (illustrative): - exports['.'].import.types → ./dist/index.d.mts - exports['.'].require.types → ./dist/index.d.cts [5] What you asked (directly): “tsdown declaration files esm cjs.d.ts.d.mts.d.cts generation” - tsdown generation is documented for .d.ts via dts: true/--dts and via rolldown-plugin-dts [1][2]. - For dual ESM+CJS, tsdown’s DTS API documents a .d.cts stub re-export strategy (so you effectively get ESM-specific .d.mts declarations plus CJS .d.cts stubs) [3]. If you tell me your desired format array (e.g., ['esm','cjs']), your tsconfig module settings, and your intended package.json exports shape, I can propose an exact tsdown config + exports snippet that matches .d.mts/.d.cts correctly for your setup.
Citations:
- 1: https://tsdown.dev/options/dts
- 2: https://github.com/antfu/skills/blob/c35a5588a5158b5b404a14fb10469b2b6dc1952b/skills/tsdown/references/option-dts.md
- 3: https://tsdown.dev/reference/api/Interface.DtsOptions
- 4: [feature] Generate esm-specific declaration files egoist/tsup#760
- 5: https://stackoverflow.com/questions/79264950/how-to-bundle-types-field-in-package-json-when-using-export-rather-than-mai
- 6: https://stackoverflow.com/questions/72457791/typescript-packages-that-ship-with-mjs-and-d-ts-but-without-d-mts-how-to-i
- 7: https://github.com/sxzz/rolldown-plugin-dts/
- 8: https://github.com/sxzz/rolldown-plugin-dts/blob/main/README.md
Add conditional types in exports to align TypeScript definitions with each module format.
The types field points to ./dist/index.d.cts (CommonJS declarations) as a fallback, but ESM consumers importing via ./dist/index.mjs will receive incorrect CommonJS type definitions. With dual ESM/CJS builds, conditional types should route to the correct declaration file per import type:
"exports": {
".": {
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
},
"./package.json": "./package.json"
}Alternatively, change the top-level types field to ./dist/index.d.mts if conditional exports are not preferred.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/types-lhci/package.json` at line 31, The package.json currently points
the top-level "types" to "./dist/index.d.cts", which serves only CommonJS
declarations; update package.json to either add conditional "types" under
"exports" so ESM imports use "./dist/index.d.mts" and CJS require uses
"./dist/index.d.cts" (mirroring "import"/"require" defaults), or change the
top-level "types" to "./dist/index.d.mts" if you prefer a simpler single-file
approach; ensure you adjust the "exports" object for "." to include "types"
alongside the existing "import" and "require" keys so TypeScript consumers get
matching .d.mts/.d.cts files.
| async "build:done"() { | ||
| const schema = await import("./dist/index.mjs"); | ||
| const jsonSchema = z.toJSONSchema(schema.lhciSchema); | ||
| const jsonString = JSON.stringify(jsonSchema); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Consider formatting the JSON output for readability.
The JSON schema is written as a single-line string. Adding formatting would improve readability for developers inspecting the schema file.
📝 Suggested improvement
- const jsonString = JSON.stringify(jsonSchema);
+ const jsonString = JSON.stringify(jsonSchema, null, 2);📝 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.
| const jsonString = JSON.stringify(jsonSchema); | |
| const jsonString = JSON.stringify(jsonSchema, null, 2); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/types-lhci/tsdown.config.ts` at line 17, The JSON schema is being
serialized into a single-line string via JSON.stringify(jsonSchema) which hurts
readability; update the serialization used where jsonString is assigned to call
JSON.stringify(jsonSchema, null, 2) (or another suitable indent) so the output
file is pretty-printed, and ensure any downstream writer that consumes
jsonString still writes the formatted string.
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
core/auto-readme/package.json (1)
31-33:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAdd
typesconditions to the main export for proper TypeScript resolution.The main export lacks
typesconditions, causing TypeScript to fall back to the roottypesfield (./dist/index.d.cts), which points to CommonJS declarations. ESM consumers will incorrectly resolve CJS types. This issue was flagged in a previous review and remains unaddressed.📝 Recommended fix
"exports": { ".": { + "import": { + "types": "./dist/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } - "import": "./dist/index.mjs", - "require": "./dist/index.cjs" },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/auto-readme/package.json` around lines 31 - 33, The package export map currently only provides "import" and "require" entries and lacks conditional "types", so TS resolves the root "types" (./dist/index.d.cts) for ESM consumers; update the export entry that contains "import" and "require" to include "types" condition mappings so ESM resolves to the ESM declaration file and CJS to the CJS declaration file (e.g., add a "types" pointing to the ESM .d.mts alongside the "import" key and a "types" pointing to ./dist/index.d.cts alongside the "require" key), keeping the existing root "types" as necessary; target the export object that contains the "import" and "require" keys referenced in package.json.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@core/auto-readme/package.json`:
- Around line 34-37: The ./schema export in package.json is missing explicit
types conditions, so add a "types" conditional mapping alongside "import" and
"require" for the "./schema" export (pointing to the generated declaration files
from tsdown, e.g. the .d.mts path for the ES module variant and the .d.cts path
for the CJS variant) so TypeScript consumers resolve the correct declaration
format; update the "./schema" export object to include "types":
"./config/schema.d.mts" for the import/ESM case and the corresponding
"./config/schema.d.cts" for the require/CJS case (or the appropriate generated
filenames) while keeping the existing "import" and "require" entries.
In `@core/types-lhci/tsdown.config.ts`:
- Around line 20-23: The ESM module import in the async "build:done" hook is
being cached (import("./dist/index.mjs")), causing stale schema output in watch
mode; modify the import to force a fresh load each run by appending a unique
cache-busting query (e.g., timestamp or increment) to the module specifier
before importing, then continue to call z.toJSONSchema(schema.lhciSchema) and
JSON.stringify(jsonSchema) as before so the generated schema is always
up-to-date.
In `@turbo/generators/package.json`:
- Line 2: The package.json for the turbo/generators package is missing the
monorepo-standard engines.node constraint; add an "engines" entry with "node":
">=24" in turbo/generators/package.json (alongside the existing "type":
"commonjs") to restore consistency with other packages and prevent installs on
unsupported Node versions; update any associated validation or CI checks if they
read engines (refer to the package.json "type" key to locate the file and add
the "engines" object).
---
Duplicate comments:
In `@core/auto-readme/package.json`:
- Around line 31-33: The package export map currently only provides "import" and
"require" entries and lacks conditional "types", so TS resolves the root "types"
(./dist/index.d.cts) for ESM consumers; update the export entry that contains
"import" and "require" to include "types" condition mappings so ESM resolves to
the ESM declaration file and CJS to the CJS declaration file (e.g., add a
"types" pointing to the ESM .d.mts alongside the "import" key and a "types"
pointing to ./dist/index.d.cts alongside the "require" key), keeping the
existing root "types" as necessary; target the export object that contains the
"import" and "require" keys referenced in package.json.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: fce046c8-d445-4438-87f9-5c0725aec557
⛔ Files ignored due to path filters (1)
core/alfred-kaomoji/icon.pngis excluded by!**/*.png
📒 Files selected for processing (43)
.config/www/package.json.config/www/setup.sh.config/www/typedoc.jsoncore/ai-commit-msg/package.jsoncore/ai-commit-msg/tsdown.config.tscore/ai-commit-msg/typedoc.jsoncore/alfred-kaomoji/README.mdcore/alfred-kaomoji/package.jsoncore/alfred-kaomoji/typedoc.jsoncore/astro-iconify-svgmap/typedoc.jsoncore/auto-readme/package.jsoncore/auto-readme/tsdown.config.tscore/auto-readme/typedoc.jsoncore/catppuccin-jsonresume-theme/package.jsoncore/catppuccin-jsonresume-theme/typedoc.jsoncore/catppuccin-typedoc/typedoc.jsoncore/eslint-config/typedoc.jsoncore/example/typedoc.jsoncore/find-makefile-targets/typedoc.jsoncore/multipublish/package.jsoncore/multipublish/tsdown.config.tscore/multipublish/typedoc.jsoncore/prettier-plugin-handlebars/typedoc.jsoncore/remark-asciinema/typedoc.jsoncore/single-file/typedoc.jsoncore/typed-env/package.jsoncore/typed-env/typedoc.jsoncore/typed-events/typedoc.jsoncore/typed-nocodb-api/package.jsoncore/typed-nocodb-api/typedoc.jsoncore/typed-templates/typedoc.jsoncore/types-lhci/package.jsoncore/types-lhci/tsdown.config.tscore/types-lhci/typedoc.jsonexamples/astro-iconify-svgmap/package.jsonexamples/remark-asciinema/package.jsonexamples/svelte-social-share-links/astro/package.jsonexamples/svelte-social-share-links/svelte-kit/package.jsonexamples/typed-events/react/package.jsonexamples/typed-events/vanilla/package.jsonmonoman.config.tsturbo/generators/package.jsonturbo/generators/templates/common/typedoc.json
💤 Files with no reviewable changes (20)
- .config/www/setup.sh
- core/catppuccin-jsonresume-theme/typedoc.json
- core/astro-iconify-svgmap/typedoc.json
- core/typed-nocodb-api/typedoc.json
- core/typed-env/typedoc.json
- core/auto-readme/typedoc.json
- core/types-lhci/typedoc.json
- core/alfred-kaomoji/typedoc.json
- core/eslint-config/typedoc.json
- core/typed-templates/typedoc.json
- core/single-file/typedoc.json
- turbo/generators/templates/common/typedoc.json
- core/typed-events/typedoc.json
- core/multipublish/typedoc.json
- core/ai-commit-msg/typedoc.json
- core/remark-asciinema/typedoc.json
- core/find-makefile-targets/typedoc.json
- core/example/typedoc.json
- core/catppuccin-typedoc/typedoc.json
- core/prettier-plugin-handlebars/typedoc.json
| "./schema": { | ||
| "import": "./config/schema.mjs", | ||
| "require": "./config/schema.cjs" | ||
| }, |
There was a problem hiding this comment.
Add types conditions to the ./schema export.
The ./schema export uses conditional import/require paths but omits types conditions. When tsdown builds with dual format and dts: true, it generates both .d.mts and .d.cts declaration files. Without explicit types conditions, TypeScript consumers will rely on ambient resolution or the root types field, potentially resolving the wrong declaration format.
📝 Proposed fix
"./schema": {
- "import": "./config/schema.mjs",
- "require": "./config/schema.cjs"
+ "import": {
+ "types": "./config/schema.d.mts",
+ "default": "./config/schema.mjs"
+ },
+ "require": {
+ "types": "./config/schema.d.cts",
+ "default": "./config/schema.cjs"
+ }
},🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/auto-readme/package.json` around lines 34 - 37, The ./schema export in
package.json is missing explicit types conditions, so add a "types" conditional
mapping alongside "import" and "require" for the "./schema" export (pointing to
the generated declaration files from tsdown, e.g. the .d.mts path for the ES
module variant and the .d.cts path for the CJS variant) so TypeScript consumers
resolve the correct declaration format; update the "./schema" export object to
include "types": "./config/schema.d.mts" for the import/ESM case and the
corresponding "./config/schema.d.cts" for the require/CJS case (or the
appropriate generated filenames) while keeping the existing "import" and
"require" entries.
| async "build:done"() { | ||
| const schema = await import("./dist/index.mjs"); | ||
| const jsonSchema = z.toJSONSchema(schema.lhciSchema); | ||
| const jsonFile = JSON.stringify(jsonSchema); |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Node.js ESM, does dynamic import("./dist/index.mjs") return a cached module on repeated calls in the same process, and is adding a query string to a file URL (file:///.../index.mjs?t=...) a supported cache-busting approach?
💡 Result:
Yes: in Node.js ESM, repeated dynamic imports in the same process return the cached module when the resolved module URL is the same. Node’s ESM loader maintains its own separate module cache (not require.cache), and ES modules are resolved and cached as URLs [1]. Dynamic import uses the ES module loader’s cache, so calling import('./dist/index.mjs') again resolves to the same URL and returns the already-loaded module instance rather than re-evaluating it. Is cache-busting via a query string on a file URL supported? - Generally yes for practical cache-busting: Node treats the cache key as the resolved URL, and ES module specifiers containing query parameters produce distinct cache entries because the query is part of the URL used for caching [2]. So changing file:///.../index.mjs?t=... yields a different URL, which results in a different cache entry (i.e., a fresh evaluation). - Caveat: this effectively creates new module instances and cached entries that can accumulate for the lifetime of the process, because there’s no public API to evict/clear the internal ESM module cache [3][1]. Therefore, import( "./dist/index.mjs") will be cached on repeated calls in the same process (same URL), while import("file:///.../index.mjs?t=" + Date.now) is a supported/working way to bust the ESM cache by changing the URL (query string), with the trade-off of growing in-memory cached modules over time.
Citations:
- 1: https://nodejs.org/api/esm.html
- 2: https://www.thenodebook.com/modules/import-meta-caching
- 3: Important feature: Allow busting ESM cache nodejs/node#38322
🏁 Script executed:
# Check if the file exists and read the relevant section
fd -t f "tsdown.config.ts" | head -5Repository: stephansama/packages
Length of output: 263
🏁 Script executed:
# Once we locate the file, read it to verify the code snippet
if [ -f "core/types-lhci/tsdown.config.ts" ]; then
echo "=== File found, reading lines 1-30 to see context ==="
head -30 "core/types-lhci/tsdown.config.ts" | cat -n
fiRepository: stephansama/packages
Length of output: 1084
🏁 Script executed:
# Also check the actual import statement and build:done hook
if [ -f "core/types-lhci/tsdown.config.ts" ]; then
echo "=== Searching for 'build:done' and related code ==="
rg -n "build:done|import.*dist/index.mjs" "core/types-lhci/tsdown.config.ts" -A 5 -B 2
fiRepository: stephansama/packages
Length of output: 482
Bust ESM module cache in watch mode to prevent stale schema generation.
import("./dist/index.mjs") is cached by URL in Node.js ESM. In repeated build:done hooks (watch mode), this returns the already-loaded module instance instead of re-evaluating it, causing the generated schema to become stale.
💡 Suggested fix
import * as fs from "node:fs";
import path from "node:path";
+import { pathToFileURL } from "node:url";
import { defineConfig } from "tsdown";
import * as z from "zod";
@@
hooks: {
async "build:done"() {
- const schema = await import("./dist/index.mjs");
+ const moduleUrl = pathToFileURL(path.resolve("./dist/index.mjs")).href;
+ const schema = await import(`${moduleUrl}?t=${Date.now()}`);
const jsonSchema = z.toJSONSchema(schema.lhciSchema);
const jsonFile = JSON.stringify(jsonSchema);
const jsonPath = path.join("./dist", "schema.json");
await fs.promises.writeFile(jsonPath, jsonFile);
},
},📝 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.
| async "build:done"() { | |
| const schema = await import("./dist/index.mjs"); | |
| const jsonSchema = z.toJSONSchema(schema.lhciSchema); | |
| const jsonFile = JSON.stringify(jsonSchema); | |
| import * as fs from "node:fs"; | |
| import path from "node:path"; | |
| import { pathToFileURL } from "node:url"; | |
| import { defineConfig } from "tsdown"; | |
| import * as z from "zod"; | |
| // ... (other config) | |
| hooks: { | |
| async "build:done"() { | |
| const moduleUrl = pathToFileURL(path.resolve("./dist/index.mjs")).href; | |
| const schema = await import(`${moduleUrl}?t=${Date.now()}`); | |
| const jsonSchema = z.toJSONSchema(schema.lhciSchema); | |
| const jsonFile = JSON.stringify(jsonSchema); | |
| const jsonPath = path.join("./dist", "schema.json"); | |
| await fs.promises.writeFile(jsonPath, jsonFile); | |
| }, | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/types-lhci/tsdown.config.ts` around lines 20 - 23, The ESM module import
in the async "build:done" hook is being cached (import("./dist/index.mjs")),
causing stale schema output in watch mode; modify the import to force a fresh
load each run by appending a unique cache-busting query (e.g., timestamp or
increment) to the module specifier before importing, then continue to call
z.toJSONSchema(schema.lhciSchema) and JSON.stringify(jsonSchema) as before so
the generated schema is always up-to-date.
| "engines": { | ||
| "node": ">=24" | ||
| } | ||
| "type": "commonjs" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify engine-policy consistency and whether this package is now an outlier.
# Read-only reconnaissance only.
echo "== package files with engines.node =="
rg -n --glob '**/package.json' '"engines"\s*:\s*\{[^}]*"node"\s*:' -U
echo
echo "== turbo/generators/package.json =="
cat turbo/generators/package.json
echo
echo "== CI/workflow Node versions (if present) =="
rg -n --glob '.github/workflows/*.yml' 'node-version|setup-node|matrix'Repository: stephansama/packages
Length of output: 4325
Restore engines.node constraint to maintain monorepo-wide consistency.
This package is now the only one in the repository without an engines.node constraint. All 40+ other packages consistently declare "node": ">=24". Removing this constraint allows installations on unsupported Node versions without explicit awareness. Either restore the constraint or document and validate that broader Node version support is intentional.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@turbo/generators/package.json` at line 2, The package.json for the
turbo/generators package is missing the monorepo-standard engines.node
constraint; add an "engines" entry with "node": ">=24" in
turbo/generators/package.json (alongside the existing "type": "commonjs") to
restore consistency with other packages and prevent installs on unsupported Node
versions; update any associated validation or CI checks if they read engines
(refer to the package.json "type" key to locate the file and add the "engines"
object).
Checklist
mainhave been mergedmain