Skip to content

chore(ts): fix build:tsc pipeline in pnpm monorepo#1208

Merged
danieliser merged 17 commits into
developfrom
fix/tsconfig-build-tsc-compliance
Apr 22, 2026
Merged

chore(ts): fix build:tsc pipeline in pnpm monorepo#1208
danieliser merged 17 commits into
developfrom
fix/tsconfig-build-tsc-compliance

Conversation

@danieliser
Copy link
Copy Markdown
Member

@danieliser danieliser commented Apr 22, 2026

Summary

Fixes the build:tsc step of the JS/TS Code Quality CI job that's been failing since the CI Summary rollup was added for branch protection (#1207 was the PR that surfaced it). The rollup promoted previously-masked continue-on-error: true failures to blocker status, exposing three pre-existing TypeScript config issues.

None of these are caused by #1207 — they're pre-existing on develop and were only hidden because the old CI setup let tsc failures silently pass.

What CI was seeing

From the last failed run on PR #1207 before it was admin-merged:

  • TS5107 × multiple — "esModuleInterop=false" and "moduleResolution=node10" are deprecated in TS 5.x, will be removed in TS 7.
  • TS2688 × multiple — "Cannot find type definition file for 'node'/'react'/'jest'" across 10 packages. pnpm-hoisted monorepo layout meant the ambient types: [...] array in the base tsconfig referenced type libs not reachable from each package's resolution root.
  • TS2883 — test files being compiled as part of build:tsc but expected jest globals the source packages didn't declare.

Changes

tsconfig.base.json

  1. Empty out types: [...]. The hardcoded ["node", "react", "jest", "@testing-library/jest-dom"] array forced every package to resolve type libs it didn't have as direct deps. Packages that need globals (jquery, etc.) already declare them in their own tsconfig. Empty array disables TS's auto-inclusion of every hoisted @types/*, which is the correct monorepo behavior.
  2. Widen test-file exclude pattern to match actual naming (__tests__/ and *.test.{ts,tsx}) instead of the unused test/. Test files shouldn't participate in type-build.
  3. Silence TS5107 with "ignoreDeprecations": "5.0". Migrating to moduleResolution: "bundler" is the long-term fix but breaks type-root resolution under pnpm hoisting in this monorepo; defer that to a dedicated task before TS 7.0 removes the escape hatch.

packages/icons/src/lib/*.tsx (18 files)

Annotate each exported icon const with : JSX.Element. Once TS5107 stops blocking, tsc proceeds to emit .d.ts files and hits TS2742 because pnpm hoists @types/react into a versioned .pnpm/ path that can't be named portably. Explicit annotations let tsc emit the type name without a reference to the hoisted path.

packages/core-data/src/types/notices.ts + actions.ts

The local Notice type had drifted from @wordpress/notices::NoticeOptions in three ways that tsc surfaced once the mask was lifted:

  1. Notice.status was widened with | string, erasing the narrow 'error' | 'warning' | 'success' | 'info' union.
  2. Notice extended WPNotice, so spreading it into createNotice(status, content, options) as the third arg passed extras (status, content, spokenMessage, __unstableHTML) not part of the options contract.
  3. NoticeAction.url / .onClick typed as string | null / Function | null didn't match WP's string | undefined / () => void.

Action handlers that referenced Notice['status'] / Notice['content'] for their input param types now reference WPNotice directly, which carries those fields since they're function arguments rather than options.

Note: this is a type-only change to the emitted public types of @popup-maker/core-data. NoticeAction.url going from string | null to string | undefined is a technical breaking change for TS consumers, but runtime semantics are unchanged.

pnpm-lock.yaml

Post-install pnpm switched a few internal workspace refs from file: to link: protocol. No version changes.

What's NOT in this PR

Not all build:tsc errors are fixed. Local runs surface additional TS2742 errors in packages/components, packages/cta-admin, etc. — but CI doesn't hit those because CI's install layout differs from local, and the cascade only reaches them after TS5107 is silenced. If CI surfaces them after merge, a follow-up PR can annotate those packages the same way icons was annotated.

Test plan

  • CI js-quality job reaches green (or reveals a new, distinct class of error)
  • CI Summary rollup no longer blocks future PRs on the pre-existing TS5107 deprecation

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor

    • Improved notice validation and handling for more reliable in-app notices
    • Added explicit type annotations across UI components and icons for greater stability
  • Chores

    • Updated TypeScript config and dev dependencies to align tooling and reduce compiler noise

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 22, 2026

Warning

Rate limit exceeded

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

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 50 minutes and 14 seconds.

⌛ How to resolve this issue?

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

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

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

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

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 387eac16-fb27-4d62-9390-c2cc8f27fc21

📥 Commits

Reviewing files that changed from the base of the PR and between da51323 and 025812c.

📒 Files selected for processing (3)
  • packages/core-data/src/types/notices.ts
  • packages/cta-editor/src/registries/tabs/general.tsx
  • packages/fields/src/lib/html.tsx

Walkthrough

Tightened and separated TypeScript typings (notably WPNotice vs Notice), updated many component and icon declarations with explicit JSX/React types, adjusted notice-related selectors/actions to validate statuses, and modified TypeScript config and package dependencies. All changes are type/signature-only except a few runtime casts; no functional behavior was added.

Changes

Cohort / File(s) Summary
Notice types & usage
packages/core-data/src/types/notices.ts, packages/core-data/src/call-to-actions/actions.ts, packages/core-data/src/call-to-actions/selectors.ts, packages/core-data/src/popups/actions.ts, packages/core-data/src/popups/selectors.ts
Introduced/reshaped WPNotice and Notice types (narrowed status), added isValidNoticeStatus helper, switched selectors/actions to use WPNotice and runtime status validation, and adjusted createNotice parameter typings.
Icon component typings
packages/icons/src/lib/*.(tsx) (e.g., block-manager.tsx, block.tsx, check-all.tsx, custom-redirect.tsx, filter-lines.tsx, gears.tsx, incognito.tsx, license-key.tsx, locked-user.tsx, mark-*.tsx, monitor.tsx, permissions.tsx, protected-message.tsx, upgrade.tsx)
Added explicit : JSX.Element annotations to numerous icon constant exports; no markup or runtime changes.
Component return/type annotations
multiple UI packages (e.g., packages/block-editor/src/..., packages/components/src/lib/..., packages/cta-admin/src/..., packages/cta-editor/src/..., packages/fields/src/lib/..., packages/layout/src/components/..., packages/cta-admin/src/registries/..., etc.)
Added or tightened component/HOC return types (e.g., : JSX.Element, `: JSX.Element
Slots export typing
packages/layout/src/slots/index.ts
Replaced destructured Slot/Fill exports with intermediate constants and explicit exported Slot/Fill type aliases derived from ReturnType<typeof createSlotFill>.
TypeScript config & deps
tsconfig.base.json, package.json, packages/cta-editor/tsconfig.json, packages/cta-editor/package.json
Added ignoreDeprecations: "5.0" and types: [] at root tsconfig, expanded exclude globs; added typescript devDependency and @wordpress/notices/runtime plus @types/node devDependency and package.json pins.
Misc. typing/casts
packages/block-editor/src/plugins/popup-title-panel.tsx, packages/cta-admin/src/index.tsx, various files
Added a few double-casts/explicit parameter casts when interacting with external stores/providers and tightened some registry/provider callsite typings; no behavioral changes.
Lint config
.eslintrc.js
Updated import/no-unresolved ignore patterns to include ^@popup-maker/ scoped imports.

Sequence Diagram(s)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly describes the main objective: fixing the build:tsc pipeline in the pnpm monorepo by addressing TypeScript configuration and type issues.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/tsconfig-build-tsc-compliance

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

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
packages/icons/src/lib/mark-white.tsx (1)

6-6: Type annotation correctly fixes TS2742 build error.

The explicit JSX.Element annotation resolves the inferred-type naming issue caused by pnpm hoisting of @types/react. This change is correct and aligns with the PR's objective to fix the failing build:tsc step.


Consider converting to function components for better React patterns.

While the current constant-based pattern works, converting these icons to function components would enable:

  • Accepting dynamic props (e.g., custom className, aria labels, size)
  • Better alignment with modern React patterns
  • Improved reusability across different contexts
♻️ Example refactor to function component
-const MarkWhite: JSX.Element = (
+const MarkWhite = () => (
 	<SVG
 		viewBox="0 0 179 179"

This is not required for the current build fix but could be considered in a future refactor.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/icons/src/lib/mark-white.tsx` at line 6, Keep the explicit type
annotation on the MarkWhite constant to preserve the TS2742 build fix (leave
const MarkWhite: JSX.Element = (...) as-is); if you want the suggested refactor,
replace the const with a function component named MarkWhite that accepts
standard SVG/React props (e.g., props: React.SVGProps<SVGSVGElement> & {
className?: string, ariaLabel?: string }), return the same SVG JSX from that
function, and export it – ensure the function signature and return type align
with React.FC or explicit JSX.Element to avoid reintroducing the type inference
issue.
packages/core-data/src/call-to-actions/actions.ts (1)

55-65: Type annotation n: Notice is now semantically wrong after the Notice vs WPNotice split.

getNotices() returns WP-shaped notice records (matching WPNotice), not the NoticeOptions-shaped Notice type introduced in this PR. It still compiles because the fields you touch (id) overlap structurally, but the intent is confusing — and the n.id?.startsWith(...) optional chain only makes sense under Notice (where id is optional); on WPNotice.id (required string) the ?. is dead code.

♻️ Suggested tightening
-import type { EditorId, Notice, WPNotice } from '../types';
+import type { EditorId, Notice, WPNotice } from '../types';
@@
-		const fieldErrors = notices.filter(
-			( n: Notice ) => n.id?.startsWith( `field-error-${ ctaId }-` )
-		);
-		fieldErrors.forEach( ( n: Notice ) =>
+		const fieldErrors = notices.filter( ( n: WPNotice ) =>
+			n.id.startsWith( `field-error-${ ctaId }-` )
+		);
+		fieldErrors.forEach( ( n: WPNotice ) =>
			registry
				.dispatch( noticesStore )
				.removeNotice( n.id, NOTICE_CONTEXT )
		);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core-data/src/call-to-actions/actions.ts` around lines 55 - 65, The
filter is typed as (n: Notice) but getNotices() returns WP-shaped notices
(WPNotice); change the annotation in the fieldErrors filter to use WPNotice (or
let inference pick it up) and remove the unnecessary optional chaining on id
(use n.id.startsWith(...)); update the predicate in the fieldErrors declaration
that references getNotices(), registry, noticesStore, NOTICE_CONTEXT and ensure
the dispatch.removeNotice call still uses n.id (typed as string) so TypeScript
reflects the WPNotice shape.
packages/core-data/src/types/notices.ts (1)

101-117: Local NoticeAction type is incomplete compared to upstream @wordpress/notices.

The type omits several properties supported by @wordpress/notices v5.29.0:

  • className?: string
  • noDefaultClasses?: boolean
  • disabled?: boolean
  • variant?: 'primary' | 'secondary' | 'link'

If any consumer attempts to pass these valid upstream properties, TypeScript will reject them. Consider aligning the type with upstream or re-exporting the WordPress type directly.

The url: string | nullurl?: string narrowing mentioned in PR objectives has no current callsites explicitly passing url: null, so runtime impact is minimal.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core-data/src/types/notices.ts` around lines 101 - 117, The local
NoticeAction type is missing fields from upstream `@wordpress/notices`; update the
NoticeAction type declaration to include optional properties className?: string,
noDefaultClasses?: boolean, disabled?: boolean, and variant?: 'primary' |
'secondary' | 'link' (or re-export the upstream NoticeAction type from
`@wordpress/notices` to keep parity) so consumers passing those upstream-supported
props won't be rejected; adjust the export in
packages/core-data/src/types/notices.ts accordingly, keeping url as optional if
you prefer the narrowed type.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/core-data/src/call-to-actions/actions.ts`:
- Around line 55-65: The filter is typed as (n: Notice) but getNotices() returns
WP-shaped notices (WPNotice); change the annotation in the fieldErrors filter to
use WPNotice (or let inference pick it up) and remove the unnecessary optional
chaining on id (use n.id.startsWith(...)); update the predicate in the
fieldErrors declaration that references getNotices(), registry, noticesStore,
NOTICE_CONTEXT and ensure the dispatch.removeNotice call still uses n.id (typed
as string) so TypeScript reflects the WPNotice shape.

In `@packages/core-data/src/types/notices.ts`:
- Around line 101-117: The local NoticeAction type is missing fields from
upstream `@wordpress/notices`; update the NoticeAction type declaration to include
optional properties className?: string, noDefaultClasses?: boolean, disabled?:
boolean, and variant?: 'primary' | 'secondary' | 'link' (or re-export the
upstream NoticeAction type from `@wordpress/notices` to keep parity) so consumers
passing those upstream-supported props won't be rejected; adjust the export in
packages/core-data/src/types/notices.ts accordingly, keeping url as optional if
you prefer the narrowed type.

In `@packages/icons/src/lib/mark-white.tsx`:
- Line 6: Keep the explicit type annotation on the MarkWhite constant to
preserve the TS2742 build fix (leave const MarkWhite: JSX.Element = (...)
as-is); if you want the suggested refactor, replace the const with a function
component named MarkWhite that accepts standard SVG/React props (e.g., props:
React.SVGProps<SVGSVGElement> & { className?: string, ariaLabel?: string }),
return the same SVG JSX from that function, and export it – ensure the function
signature and return type align with React.FC or explicit JSX.Element to avoid
reintroducing the type inference issue.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 34c85ec9-d51f-4c49-9f17-94dc54fc64aa

📥 Commits

Reviewing files that changed from the base of the PR and between e45fdd7 and c1ab008.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (22)
  • packages/core-data/src/call-to-actions/actions.ts
  • packages/core-data/src/popups/actions.ts
  • packages/core-data/src/types/notices.ts
  • packages/icons/src/lib/block-manager.tsx
  • packages/icons/src/lib/block.tsx
  • packages/icons/src/lib/check-all.tsx
  • packages/icons/src/lib/custom-redirect.tsx
  • packages/icons/src/lib/filter-lines.tsx
  • packages/icons/src/lib/gears.tsx
  • packages/icons/src/lib/incognito.tsx
  • packages/icons/src/lib/license-key.tsx
  • packages/icons/src/lib/locked-user.tsx
  • packages/icons/src/lib/mark-colored.tsx
  • packages/icons/src/lib/mark-light.tsx
  • packages/icons/src/lib/mark-retro.tsx
  • packages/icons/src/lib/mark-white.tsx
  • packages/icons/src/lib/mark.tsx
  • packages/icons/src/lib/monitor.tsx
  • packages/icons/src/lib/permissions.tsx
  • packages/icons/src/lib/protected-message.tsx
  • packages/icons/src/lib/upgrade.tsx
  • tsconfig.base.json

Three related fixes so build:tsc stops failing on pre-existing config
drift:

- Empty out the ambient 'types: [node, react, jest, @testing-library/
  jest-dom]' array. In a pnpm-hoisted monorepo this forces every
  package to resolve type libs it doesn't have as direct deps, which
  fails. Packages that need globals (jquery, etc) already declare
  them in their own tsconfig. TS auto-includes every @types/*
  reachable via node_modules when 'types' is absent or empty, which
  is the correct monorepo behavior.
- Widen the test-file exclude pattern to match actual conventions
  (__tests__/ and *.test.{ts,tsx}) instead of the unused 'test/'.
  Test files shouldn't participate in type-build; they're compiled
  by jest.
- Silence the TS 5.x deprecation warning for 'moduleResolution: node'
  with 'ignoreDeprecations: 5.0'. Migrating to 'bundler' breaks
  type-root resolution under pnpm hoisting; defer that to its own
  dedicated task before TS 7.0 removes the escape hatch entirely.
tsc TS2742: inferred types couldn't be named portably because pnpm
hoists @types/react into a versioned .pnpm path that's not reachable
from the emitted .d.ts. Explicit annotations let tsc emit the type
name without a reference to the hoisted path.
Several call sites spread a local Notice object into WP's
createNotice(status, content, options) as the options arg — but the
local Notice type had drifted from upstream NoticeOptions in three
ways that tsc flagged once the test-file mask was lifted:

1. Notice.status was widened with '| string', erasing the narrow
   union WP expects ('error' | 'warning' | 'success' | 'info').
   Drop the widening.
2. Notice extended WPNotice, so spreading it into createNotice
   options passed extras (status, content, spokenMessage, __unstableHTML)
   that aren't part of the options contract. Redefine Notice to
   match NoticeOptions exactly — distinct shape, not a superset of
   WPNotice.
3. NoticeAction.url/onClick typed as 'string | null' / 'Function |
   null' didn't match WP's 'string | undefined' / '() => void'.
   Realign.

Action handlers that used Notice['status']/Notice['content'] for
their input param types now reference WPNotice directly — Notice no
longer carries those fields since they're function arguments rather
than options.

Note: this is a type-only refactor of the emitted public types for
consumers of @popup-maker/core-data. NoticeAction.url going from
'string | null' to 'string | undefined' is a technical breaking
change for TS consumers, but runtime semantics are unchanged (null
was already effectively optional).
Previously typescript was only pulled in transitively via storybook
and stylelint peer deps. Makes tsc reliably resolvable from root
node_modules/.bin, which helps workspace-level invocations and gives
pnpm a stable hoist target for the TS compiler itself.
getNotices() returns WPNotice[] (the shape with required id: string),
not Notice (which is the NoticeOptions shape). Correcting the type
annotation removes the unnecessary optional chain on n.id.
Previous commit added typescript@5.7.3 as root devDep but the lock
regeneration missed resolving the webpack-cli variant of webpack,
causing frozen-lockfile install to fail in CI. Full lockfile refresh
produces a consistent tree.
@danieliser danieliser force-pushed the fix/tsconfig-build-tsc-compliance branch from bb3c673 to 0fb3e9f Compare April 22, 2026 10:04
Earlier WPNotice rename broke column alignment of the @param block
for createNotice() in both call-to-actions/actions.ts and popups/
actions.ts. jsdoc/check-line-alignment caught it in CI.
Once Phase 1 fixed the TS5107 deprecation errors, tsc got far enough
to emit .d.ts files and hit TS2742 'cannot be named without a
reference to .pnpm/@types+react@18.3.28/...' across 17 exported
components. Explicit return-type annotations let tsc emit portable
type names instead of trying to follow the pnpm-hoisted path.

Special cases:
- controlled-tab-panel/index.tsx: extract withInstanceId(TabPanel) to
  a named const with React.ComponentType annotation.
- url-control/suggestion.tsx: annotate outer const with
  React.ForwardRefExoticComponent so the forwardRef return type is
  nameable.
- confirm-dialogue/index.tsx: annotation is JSX.Element | null since
  the component returns null when no callback is provided.
…742)

Same pnpm-hoisted @types/react pattern as the components package.
use-fields.tsx: FieldsContext annotated with React.Context<FieldsContextType>
so the createContext return is nameable.
AppContent, AppHeader, AppLayout: standard JSX.Element return-type.

slots/index.ts: the four createSlotFill() destructures couldn't emit
portable types for their Fill/Slot properties. Broke each destructure
into an intermediate const and annotated the re-exports with shared
SlotFillFill / SlotFillSlot type aliases derived from
ReturnType<typeof createSlotFill>.
…-editor, cta-admin (TS2742)

Continuing Phase 2 after components/fields/layout: annotate every
remaining TS2742 hit in the monorepo with explicit JSX.Element
(or JSX.Element | null where the component can return null).

Also:

- block-editor: add missing @wordpress/{i18n,edit-post,plugins,
  api-fetch} deps for popup-title-panel.tsx, fix two pre-existing
  type issues in that file (double-cast to unknown, drop invalid
  icon: null, add null return type).
- cta-editor: add missing @wordpress/notices + @types/node deps,
  widen withDataStore/withModal/withQueryParams HOC signatures to
  their emitted ComponentType form, annotate Editor, fix Context
  destructure.
- cta-admin: annotate 33 exported components. context.tsx splits
  the generic Context destructure into explicit Provider/Consumer
  consts. index.tsx casts registry to RegistryProvider's expected
  value type (pre-existing mismatch). list-view/notices.tsx now
  compiles thanks to core-data selector fix below.
- core-data: correct getNotices() / getNoticeById() selectors to
  return WPNotice (full shape with id/status/content) instead of
  Notice (NoticeOptions shape). The prior cast to Notice was a
  hold-over from the Phase 1 type realignment and broke every
  downstream consumer that read notice.id / .status / .content.
Prettier reformatting of 12 files whose manual annotations didn't
match the repo's prettier config (line wrapping, indentation).
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
packages/core-data/src/popups/selectors.ts (1)

339-353: Type cast narrows status unsafely.

noticesStore.getNotices() returns notices whose status is typed as string upstream. Casting to the narrower WPNotice[] (with a 4-literal status union) is a one-way assertion: if any third-party plugin creates a notice in NOTICE_CONTEXT with a non-standard status, downstream consumers will assume an invalid literal. Either keep status optional/string on WPNotice, or filter by known statuses before casting.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core-data/src/popups/selectors.ts` around lines 339 - 353, The code
unsafely casts noticesStore.getNotices( NOTICE_CONTEXT ) to WPNotice[] in
getNotices and getNoticeById which narrows status to a 4-literal union; instead
either (A) widen the WPNotice.status type to accept string (update the WPNotice
definition) so the cast is safe, or (B) validate and filter the returned notices
before casting: call noticesStore.getNotices( NOTICE_CONTEXT ), filter entries
by an isValidStatus(status) predicate that only keeps known statuses, then
cast/map to WPNotice for return; apply the same pattern in both getNotices and
getNoticeById.
packages/core-data/src/types/notices.ts (1)

4-47: Minor: WPNotice.status is looser than @wordpress/notices.

@wordpress/notices types status as required on a notice record returned from the store, but here it is status?:. Since getNotices() always returns a notice with a status set, consider making it required to catch accidental undefined reads at call sites (and tighten the cast in selectors.ts).

Proposed tightening
-	status?: 'warning' | 'success' | 'error' | 'info';
+	status: 'warning' | 'success' | 'error' | 'info';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core-data/src/types/notices.ts` around lines 4 - 47, The
WPNotice.status field is currently optional but should be required to match
`@wordpress/notices` and the guarantees from getNotices(); change the WPNotice
interface so status is non-optional (status: 'warning' | 'success' | 'error' |
'info') and then update any code that creates WPNotice instances to always
supply a status; also tighten the casts/usages in selectors.ts (remove the
permissive undefined casts and assume status exists) so callers no longer rely
on an optional status and any places that previously omitted status are updated
to provide a default/explicit value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/cta-editor/src/editor/index.ts`:
- Line 1: The import in editor/index.ts currently pulls ComponentType from
'@wordpress/element' but should import ComponentType from 'react' to match the
other HOC files; update the import statement that references ComponentType so it
imports from 'react' (change the import source for ComponentType) to maintain
consistency with with-query-params.tsx, with-modal.tsx, and with-data-store.tsx.

In `@packages/fields/src/lib/html.tsx`:
- Line 4: The HtmlField component currently renders raw HTML via
dangerouslySetInnerHTML using the content prop; add an explicit note or enforce
sanitization: either add a clear comment above the HtmlField export stating that
content must be pre-sanitized server-side (e.g., via wp_kses in the REST
controller) and must never contain unsanitized user input, or (preferred) call a
client-side sanitizer utility on content before passing it to
dangerouslySetInnerHTML (reference the HtmlField component and its content prop)
so the component always outputs safe HTML regardless of upstream handling.

---

Nitpick comments:
In `@packages/core-data/src/popups/selectors.ts`:
- Around line 339-353: The code unsafely casts noticesStore.getNotices(
NOTICE_CONTEXT ) to WPNotice[] in getNotices and getNoticeById which narrows
status to a 4-literal union; instead either (A) widen the WPNotice.status type
to accept string (update the WPNotice definition) so the cast is safe, or (B)
validate and filter the returned notices before casting: call
noticesStore.getNotices( NOTICE_CONTEXT ), filter entries by an
isValidStatus(status) predicate that only keeps known statuses, then cast/map to
WPNotice for return; apply the same pattern in both getNotices and
getNoticeById.

In `@packages/core-data/src/types/notices.ts`:
- Around line 4-47: The WPNotice.status field is currently optional but should
be required to match `@wordpress/notices` and the guarantees from getNotices();
change the WPNotice interface so status is non-optional (status: 'warning' |
'success' | 'error' | 'info') and then update any code that creates WPNotice
instances to always supply a status; also tighten the casts/usages in
selectors.ts (remove the permissive undefined casts and assume status exists) so
callers no longer rely on an optional status and any places that previously
omitted status are updated to provide a default/explicit value.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6caf5aa2-b9b1-4d6d-83d7-9cced691a226

📥 Commits

Reviewing files that changed from the base of the PR and between c1ab008 and 41ecd8a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (108)
  • package.json
  • packages/block-editor/package.json
  • packages/block-editor/src/formats/popup-trigger/index.tsx
  • packages/block-editor/src/formats/popup-trigger/inline.tsx
  • packages/block-editor/src/formats/popup-trigger/trigger-popover/popup-trigger-editor.tsx
  • packages/block-editor/src/formats/popup-trigger/trigger-popover/popup-trigger-viewer.tsx
  • packages/block-editor/src/plugins/popup-title-panel.tsx
  • packages/components/src/lib/confirm-dialogue/index.tsx
  • packages/components/src/lib/controlled-tab-panel/index.tsx
  • packages/components/src/lib/controlled-tab-panel/tab-button.tsx
  • packages/components/src/lib/cta-select-control/index.tsx
  • packages/components/src/lib/device-toggle/index.tsx
  • packages/components/src/lib/entity-select-control/index.tsx
  • packages/components/src/lib/field-panel/index.tsx
  • packages/components/src/lib/field-row/index.tsx
  • packages/components/src/lib/freeform-control/index.tsx
  • packages/components/src/lib/full-screen-panel/index.tsx
  • packages/components/src/lib/list-table/index.tsx
  • packages/components/src/lib/popup-select-control/index.tsx
  • packages/components/src/lib/radio-buttons-control/index.tsx
  • packages/components/src/lib/searchable-multicheck-control/index.tsx
  • packages/components/src/lib/text-highlight/index.tsx
  • packages/components/src/lib/url-control/index.tsx
  • packages/components/src/lib/url-control/suggestion.tsx
  • packages/core-data/src/call-to-actions/actions.ts
  • packages/core-data/src/call-to-actions/selectors.ts
  • packages/core-data/src/popups/actions.ts
  • packages/core-data/src/popups/selectors.ts
  • packages/core-data/src/types/notices.ts
  • packages/cta-admin/src/App.tsx
  • packages/cta-admin/src/components/app-header/index.tsx
  • packages/cta-admin/src/components/list-view/header.tsx
  • packages/cta-admin/src/components/list-view/index.tsx
  • packages/cta-admin/src/components/list-view/notices.tsx
  • packages/cta-admin/src/components/list/bulk-actions/index.tsx
  • packages/cta-admin/src/components/list/filters/index.tsx
  • packages/cta-admin/src/components/list/index.tsx
  • packages/cta-admin/src/components/list/options/index.tsx
  • packages/cta-admin/src/components/list/quick-actions/index.tsx
  • packages/cta-admin/src/context.tsx
  • packages/cta-admin/src/index.tsx
  • packages/cta-admin/src/registries/list-bulk-actions/delete.tsx
  • packages/cta-admin/src/registries/list-bulk-actions/disable.tsx
  • packages/cta-admin/src/registries/list-bulk-actions/enable.tsx
  • packages/cta-admin/src/registries/list-bulk-actions/export.tsx
  • packages/cta-admin/src/registries/list-bulk-actions/trash.tsx
  • packages/cta-admin/src/registries/list-filters/status.tsx
  • packages/cta-admin/src/registries/list-filters/type.tsx
  • packages/cta-admin/src/registries/list-options/export.tsx
  • packages/cta-admin/src/registries/list-options/import.tsx
  • packages/cta-admin/src/registries/list-quick-actions/delete.tsx
  • packages/cta-admin/src/registries/list-quick-actions/edit.tsx
  • packages/cta-admin/src/registries/list-quick-actions/export.tsx
  • packages/cta-admin/src/registries/list-quick-actions/trash.tsx
  • packages/cta-editor/package.json
  • packages/cta-editor/src/components/debug-notices.tsx
  • packages/cta-editor/src/editor/components/header-actions.tsx
  • packages/cta-editor/src/editor/components/header-options.tsx
  • packages/cta-editor/src/editor/hocs/with-data-store.tsx
  • packages/cta-editor/src/editor/hocs/with-modal.tsx
  • packages/cta-editor/src/editor/hocs/with-query-params.tsx
  • packages/cta-editor/src/editor/index.ts
  • packages/cta-editor/src/registries/header-actions/history.tsx
  • packages/cta-editor/src/registries/header-actions/status.tsx
  • packages/cta-editor/src/registries/header-options/delete.tsx
  • packages/cta-editor/src/registries/tabs/general.tsx
  • packages/cta-editor/tsconfig.json
  • packages/fields/src/hooks/use-fields.tsx
  • packages/fields/src/lib/checkbox.tsx
  • packages/fields/src/lib/color.tsx
  • packages/fields/src/lib/custom-select.tsx
  • packages/fields/src/lib/date.tsx
  • packages/fields/src/lib/field.tsx
  • packages/fields/src/lib/fields.tsx
  • packages/fields/src/lib/html.tsx
  • packages/fields/src/lib/measure.tsx
  • packages/fields/src/lib/multicheck.tsx
  • packages/fields/src/lib/number.tsx
  • packages/fields/src/lib/object-select.tsx
  • packages/fields/src/lib/radio.tsx
  • packages/fields/src/lib/rangeslider.tsx
  • packages/fields/src/lib/select.tsx
  • packages/fields/src/lib/text.tsx
  • packages/fields/src/lib/textarea.tsx
  • packages/fields/src/lib/token-select.tsx
  • packages/icons/src/lib/block-manager.tsx
  • packages/icons/src/lib/block.tsx
  • packages/icons/src/lib/check-all.tsx
  • packages/icons/src/lib/custom-redirect.tsx
  • packages/icons/src/lib/filter-lines.tsx
  • packages/icons/src/lib/gears.tsx
  • packages/icons/src/lib/incognito.tsx
  • packages/icons/src/lib/license-key.tsx
  • packages/icons/src/lib/locked-user.tsx
  • packages/icons/src/lib/mark-colored.tsx
  • packages/icons/src/lib/mark-light.tsx
  • packages/icons/src/lib/mark-retro.tsx
  • packages/icons/src/lib/mark-white.tsx
  • packages/icons/src/lib/mark.tsx
  • packages/icons/src/lib/monitor.tsx
  • packages/icons/src/lib/permissions.tsx
  • packages/icons/src/lib/protected-message.tsx
  • packages/icons/src/lib/upgrade.tsx
  • packages/layout/src/components/app-content/index.tsx
  • packages/layout/src/components/app-header/index.tsx
  • packages/layout/src/components/app-layout/index.tsx
  • packages/layout/src/slots/index.ts
  • tsconfig.base.json
✅ Files skipped from review due to trivial changes (89)
  • package.json
  • packages/components/src/lib/cta-select-control/index.tsx
  • packages/components/src/lib/field-panel/index.tsx
  • packages/cta-admin/src/components/app-header/index.tsx
  • packages/cta-admin/src/components/list-view/header.tsx
  • packages/cta-admin/src/components/list/bulk-actions/index.tsx
  • packages/cta-admin/src/components/list/options/index.tsx
  • packages/cta-admin/src/components/list/quick-actions/index.tsx
  • packages/cta-admin/src/registries/list-options/export.tsx
  • packages/fields/src/lib/measure.tsx
  • packages/cta-editor/src/editor/components/header-actions.tsx
  • packages/cta-editor/tsconfig.json
  • packages/cta-admin/src/registries/list-bulk-actions/delete.tsx
  • packages/cta-admin/src/registries/list-bulk-actions/trash.tsx
  • packages/block-editor/package.json
  • packages/block-editor/src/formats/popup-trigger/index.tsx
  • packages/block-editor/src/formats/popup-trigger/inline.tsx
  • packages/block-editor/src/formats/popup-trigger/trigger-popover/popup-trigger-editor.tsx
  • packages/components/src/lib/confirm-dialogue/index.tsx
  • packages/components/src/lib/controlled-tab-panel/tab-button.tsx
  • packages/components/src/lib/device-toggle/index.tsx
  • packages/components/src/lib/entity-select-control/index.tsx
  • packages/components/src/lib/field-row/index.tsx
  • packages/components/src/lib/freeform-control/index.tsx
  • packages/components/src/lib/popup-select-control/index.tsx
  • packages/components/src/lib/radio-buttons-control/index.tsx
  • packages/components/src/lib/text-highlight/index.tsx
  • packages/fields/src/lib/textarea.tsx
  • packages/fields/src/lib/text.tsx
  • packages/fields/src/lib/fields.tsx
  • packages/components/src/lib/searchable-multicheck-control/index.tsx
  • packages/icons/src/lib/gears.tsx
  • packages/components/src/lib/full-screen-panel/index.tsx
  • packages/icons/src/lib/mark.tsx
  • packages/components/src/lib/url-control/index.tsx
  • packages/cta-admin/src/components/list-view/index.tsx
  • packages/cta-admin/src/components/list-view/notices.tsx
  • packages/cta-admin/src/components/list/filters/index.tsx
  • packages/cta-admin/src/components/list/index.tsx
  • packages/cta-admin/src/App.tsx
  • packages/cta-admin/src/registries/list-bulk-actions/disable.tsx
  • packages/cta-admin/src/registries/list-bulk-actions/export.tsx
  • packages/cta-admin/src/registries/list-filters/status.tsx
  • packages/cta-admin/src/registries/list-filters/type.tsx
  • packages/fields/src/lib/checkbox.tsx
  • packages/fields/src/lib/date.tsx
  • packages/fields/src/lib/multicheck.tsx
  • packages/fields/src/lib/radio.tsx
  • packages/fields/src/lib/number.tsx
  • packages/cta-admin/src/registries/list-options/import.tsx
  • packages/fields/src/lib/custom-select.tsx
  • packages/cta-editor/src/components/debug-notices.tsx
  • packages/fields/src/lib/field.tsx
  • packages/cta-editor/package.json
  • packages/fields/src/lib/object-select.tsx
  • packages/icons/src/lib/check-all.tsx
  • packages/core-data/src/call-to-actions/selectors.ts
  • packages/cta-admin/src/registries/list-quick-actions/export.tsx
  • packages/cta-editor/src/registries/header-actions/status.tsx
  • packages/cta-editor/src/editor/components/header-options.tsx
  • packages/cta-admin/src/registries/list-quick-actions/edit.tsx
  • packages/cta-editor/src/registries/tabs/general.tsx
  • packages/cta-editor/src/registries/header-actions/history.tsx
  • packages/fields/src/lib/color.tsx
  • packages/cta-editor/src/registries/header-options/delete.tsx
  • packages/icons/src/lib/block.tsx
  • packages/icons/src/lib/block-manager.tsx
  • packages/fields/src/lib/token-select.tsx
  • packages/fields/src/lib/rangeslider.tsx
  • packages/icons/src/lib/locked-user.tsx
  • packages/icons/src/lib/mark-colored.tsx
  • packages/icons/src/lib/filter-lines.tsx
  • packages/icons/src/lib/mark-white.tsx
  • packages/icons/src/lib/monitor.tsx
  • packages/icons/src/lib/permissions.tsx
  • packages/icons/src/lib/custom-redirect.tsx
  • packages/icons/src/lib/mark-light.tsx
  • packages/icons/src/lib/mark-retro.tsx
  • packages/layout/src/components/app-content/index.tsx
  • packages/icons/src/lib/upgrade.tsx
  • packages/icons/src/lib/protected-message.tsx
  • packages/layout/src/components/app-layout/index.tsx
  • packages/icons/src/lib/license-key.tsx
  • packages/icons/src/lib/incognito.tsx
  • packages/block-editor/src/formats/popup-trigger/trigger-popover/popup-trigger-viewer.tsx
  • packages/fields/src/lib/select.tsx
  • packages/cta-editor/src/editor/hocs/with-modal.tsx
  • packages/fields/src/hooks/use-fields.tsx
  • packages/cta-admin/src/registries/list-quick-actions/trash.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • tsconfig.base.json
  • packages/core-data/src/call-to-actions/actions.ts

Comment thread packages/cta-editor/src/editor/index.ts Outdated
Comment thread packages/fields/src/lib/html.tsx
- Add @popup-maker/* to import/no-unresolved ignore. These are pnpm
  workspace packages that resolve at runtime via tsconfig paths and
  webpack aliases; eslint-plugin-import can't follow the symlinks in
  CI even though the code works.
- Fix translator comment format on pre-existing sprintf calls so
  @wordpress/i18n-translator-comments is satisfied. The rule expects
  '%d: description' / '%s: description' form; several call sites
  used '1. description' which fails validation.
- Rewrite ternary in popup-trigger-viewer.tsx so the translator
  comment directly precedes sprintf (rule doesn't recognize comments
  between ? and sprintf as 'preceding').
The @wordpress/i18n-translator-comments rule wants the comment to
precede __() specifically, not the outer sprintf() call.
- cta-editor/editor/index.ts: import ComponentType from 'react' to
  match the other HOC files (with-data-store, with-modal, with-
  query-params all import from 'react', not @wordpress/element).
- fields/lib/html.tsx: document the dangerouslySetInnerHTML contract
  — content must be sanitized server-side by the REST controller
  before reaching this component.
- core-data: replace unsafe 'as WPNotice[]' casts in getNotices /
  getNoticeById with a shared isValidNoticeStatus() predicate that
  filters to known-status notices before casting. Honest narrowing
  instead of a lying cast; keeps WPNotice's literal status union
  accurate.
jsdoc/require-param rule requires @param for each function parameter
when a JSDoc block exists. Added missing @param tags on the new
comments for isValidNoticeStatus and HtmlField.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/cta-editor/src/registries/tabs/general.tsx (1)

131-132: Redundant as string cast.

SelectControl's onChange already provides type as string, so type as string is a no-op. Safe to drop for clarity, but not blocking.

♻️ Proposed tweak
-						const ctaType = registeredCtaTypes[ type as string ];
+						const ctaType = registeredCtaTypes[ type ];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cta-editor/src/registries/tabs/general.tsx` around lines 131 - 132,
The code uses an unnecessary TypeScript cast in the onChange handler—remove the
redundant "as string" so the onChange parameter `type` is used directly when
indexing `registeredCtaTypes` (i.e., change the arrow function passed to
SelectControl/onChange to use `registeredCtaTypes[type]` instead of
`registeredCtaTypes[type as string]`), keeping the rest of the handler logic
intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core-data/src/types/notices.ts`:
- Around line 57-98: The Notice interface is missing the optional __unstableHTML
property which causes TypeScript excess-property errors when callers spread WP
notice options into createNotice; add "__unstableHTML?: boolean" to the Notice
interface definition (the exported Notice type in the notices.ts type
declarations) so the shape matches `@wordpress/notices`' NoticeOptions and callers
can pass that flag without type errors.

---

Nitpick comments:
In `@packages/cta-editor/src/registries/tabs/general.tsx`:
- Around line 131-132: The code uses an unnecessary TypeScript cast in the
onChange handler—remove the redundant "as string" so the onChange parameter
`type` is used directly when indexing `registeredCtaTypes` (i.e., change the
arrow function passed to SelectControl/onChange to use
`registeredCtaTypes[type]` instead of `registeredCtaTypes[type as string]`),
keeping the rest of the handler logic intact.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f68cda61-0e71-44ff-829c-13ed72f183fd

📥 Commits

Reviewing files that changed from the base of the PR and between 41ecd8a and da51323.

📒 Files selected for processing (25)
  • .eslintrc.js
  • packages/block-editor/src/formats/popup-trigger/trigger-popover/popup-trigger-viewer.tsx
  • packages/components/src/lib/field-panel/index.tsx
  • packages/components/src/lib/popup-select-control/index.tsx
  • packages/components/src/lib/text-highlight/index.tsx
  • packages/core-data/src/call-to-actions/selectors.ts
  • packages/core-data/src/popups/selectors.ts
  • packages/core-data/src/types/notices.ts
  • packages/cta-admin/src/components/list-view/header.tsx
  • packages/cta-admin/src/components/list/bulk-actions/index.tsx
  • packages/cta-admin/src/context.tsx
  • packages/cta-admin/src/index.tsx
  • packages/cta-admin/src/registries/list-bulk-actions/delete.tsx
  • packages/cta-admin/src/registries/list-bulk-actions/disable.tsx
  • packages/cta-admin/src/registries/list-bulk-actions/enable.tsx
  • packages/cta-admin/src/registries/list-bulk-actions/trash.tsx
  • packages/cta-admin/src/registries/list-quick-actions/delete.tsx
  • packages/cta-admin/src/registries/list-quick-actions/edit.tsx
  • packages/cta-admin/src/registries/list-quick-actions/trash.tsx
  • packages/cta-editor/src/editor/index.ts
  • packages/cta-editor/src/registries/tabs/general.tsx
  • packages/fields/src/hooks/use-fields.tsx
  • packages/fields/src/lib/field.tsx
  • packages/fields/src/lib/html.tsx
  • packages/fields/src/lib/text.tsx
✅ Files skipped from review due to trivial changes (13)
  • .eslintrc.js
  • packages/cta-admin/src/registries/list-quick-actions/trash.tsx
  • packages/cta-admin/src/index.tsx
  • packages/cta-admin/src/registries/list-quick-actions/edit.tsx
  • packages/cta-admin/src/components/list/bulk-actions/index.tsx
  • packages/cta-admin/src/registries/list-bulk-actions/delete.tsx
  • packages/components/src/lib/field-panel/index.tsx
  • packages/components/src/lib/popup-select-control/index.tsx
  • packages/cta-admin/src/registries/list-bulk-actions/trash.tsx
  • packages/cta-admin/src/registries/list-quick-actions/delete.tsx
  • packages/fields/src/lib/field.tsx
  • packages/components/src/lib/text-highlight/index.tsx
  • packages/fields/src/hooks/use-fields.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/cta-editor/src/editor/index.ts
  • packages/fields/src/lib/text.tsx
  • packages/cta-admin/src/context.tsx
  • packages/core-data/src/call-to-actions/selectors.ts
  • packages/cta-admin/src/registries/list-bulk-actions/disable.tsx
  • packages/block-editor/src/formats/popup-trigger/trigger-popover/popup-trigger-viewer.tsx
  • packages/core-data/src/popups/selectors.ts

Comment thread packages/core-data/src/types/notices.ts
- notices.ts: add __unstableHTML?: boolean to the Notice (NoticeOptions)
  interface to match @wordpress/notices upstream. Callers spreading
  this flag previously got excess-property errors.
- general.tsx: drop redundant 'as string' cast on SelectControl's
  onChange parameter — it's already typed as string by WP's
  SelectControl.
@danieliser danieliser merged commit 213e88e into develop Apr 22, 2026
15 checks passed
@danieliser danieliser deleted the fix/tsconfig-build-tsc-compliance branch April 22, 2026 19:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant