Skip to content

Conversation

@almeidx
Copy link
Member

@almeidx almeidx commented Nov 26, 2025

Supersedes #11303

Closes #11308

Made the chatInputCommandPredicate validate the full structure, including options, so users that may be using this predicate can actually validate Chat Input Commands

@vercel
Copy link

vercel bot commented Nov 26, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
discord-js Skipped Skipped Dec 8, 2025 11:06pm
discord-js-guide Skipped Skipped Dec 8, 2025 11:06pm

@codecov
Copy link

codecov bot commented Nov 26, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 32.48%. Comparing base (d0745af) to head (273547b).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #11304      +/-   ##
==========================================
+ Coverage   32.45%   32.48%   +0.03%     
==========================================
  Files         369      369              
  Lines       13611    13618       +7     
  Branches     1069     1069              
==========================================
+ Hits         4417     4424       +7     
  Misses       9059     9059              
  Partials      135      135              
Flag Coverage Δ
builders 68.09% <100.00%> (+0.14%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@vercel vercel bot temporarily deployed to Preview – discord-js-guide November 26, 2025 16:07 Inactive
@vercel vercel bot temporarily deployed to Preview – discord-js November 26, 2025 16:07 Inactive
@almeidx almeidx force-pushed the refactor/validation-on-chatinputcommand branch from 2f710d4 to 18c8ae9 Compare November 26, 2025 16:09
@vercel vercel bot temporarily deployed to Preview – discord-js-guide November 26, 2025 16:09 Inactive
@vercel vercel bot temporarily deployed to Preview – discord-js November 26, 2025 16:09 Inactive
@almeidx almeidx force-pushed the refactor/validation-on-chatinputcommand branch from 18c8ae9 to 4772957 Compare November 26, 2025 16:10
@vercel vercel bot temporarily deployed to Preview – discord-js November 26, 2025 16:10 Inactive
@vercel vercel bot temporarily deployed to Preview – discord-js-guide November 26, 2025 16:10 Inactive
Comment on lines +51 to +52
const choiceStringPredicate = z.object({
...choiceBasePredicate.shape,
Copy link
Member

Choose a reason for hiding this comment

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

what's the reason for not using extend() here and in the following predicates?

Copy link
Member Author

@almeidx almeidx Dec 8, 2025

Choose a reason for hiding this comment

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

From https://zod.dev/api?id=extend

This approach has a few advantages:

  • It uses language-level features (spread syntax) instead of library-specific APIs
  • The same syntax works in Zod and Zod Mini
  • It's more tsc-efficient — the .extend() method can be expensive on large schemas, and due to a TypeScript limitation it gets quadratically more expensive when calls are chained
  • If you wish, you can change the strictness level of the resulting schema by using z.strictObject() or z.looseObject()

I'm not strictly committed to this approach. Down to revert the change if it's unwanted

Copy link
Member

Choose a reason for hiding this comment

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

I like it better honestly, probably makes sense to use it in some other places too

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors validation logic for chat input commands by moving full structural validation (including options) to the ChatInputCommandBuilder level rather than validating each option independently.

Key Changes

  • Modified chatInputCommandPredicate to validate the complete command structure including nested options, subcommands, and subcommand groups
  • Updated all basic option classes (user, role, mentionable, boolean, attachment) to define type-specific predicates
  • Changed option serialization to skip individual validation (toJSON(false)), delegating full validation to the command builder level

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/builders/src/interactions/commands/chatInput/options/user.ts Added userOptionPredicate to ChatInputCommandUserOption class
packages/builders/src/interactions/commands/chatInput/options/role.ts Added roleOptionPredicate to ChatInputCommandRoleOption class
packages/builders/src/interactions/commands/chatInput/options/mentionable.ts Added mentionableOptionPredicate to ChatInputCommandMentionableOption class
packages/builders/src/interactions/commands/chatInput/options/boolean.ts Added booleanOptionPredicate to ChatInputCommandBooleanOption class
packages/builders/src/interactions/commands/chatInput/options/attachment.ts Added attachmentOptionPredicate to ChatInputCommandAttachmentOption class
packages/builders/src/interactions/commands/chatInput/options/ApplicationCommandOptionBase.ts Removed default predicate assignment, requiring subclasses to provide type-specific predicates
packages/builders/src/interactions/commands/chatInput/ChatInputCommand.ts Changed option validation to always be disabled during serialization, deferring to command-level validation
packages/builders/src/interactions/commands/chatInput/Assertions.ts Refactored validation predicates: created specific predicates for each option type, enhanced chatInputCommandPredicate to validate full structure including options and subcommands
packages/builders/__tests__/interactions/ChatInputCommands/ChatInputCommands.test.ts Added test case validating commands with both subcommands and subcommand groups

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

@almeidx almeidx force-pushed the refactor/validation-on-chatinputcommand branch from 4772957 to 3f449bc Compare December 8, 2025 21:09
@vercel vercel bot temporarily deployed to Preview – discord-js December 8, 2025 21:09 Inactive
@vercel vercel bot temporarily deployed to Preview – discord-js-guide December 8, 2025 21:09 Inactive
@almeidx almeidx removed the in review label Dec 8, 2025
@almeidx almeidx force-pushed the refactor/validation-on-chatinputcommand branch from 3f449bc to 273547b Compare December 8, 2025 23:06
@vercel vercel bot temporarily deployed to Preview – discord-js December 8, 2025 23:06 Inactive
@vercel vercel bot temporarily deployed to Preview – discord-js-guide December 8, 2025 23:06 Inactive
@coderabbitai
Copy link

coderabbitai bot commented Dec 8, 2025

📝 Walkthrough

Walkthrough

The changes refactor chat input command validation by introducing specific option-type predicates in place of a generic base predicate, updating assertion schemas to validate subcommands and subcommand groups, and altering option serialization to always disable validation overrides during JSON conversion.

Changes

Cohort / File(s) Change Summary
Assertion schema refactoring
packages/builders/src/interactions/commands/chatInput/Assertions.ts
Replaces generic basicOptionPredicate with baseBasicOptionPredicate and introduces specific option type predicates (attachmentOptionPredicate, booleanOptionPredicate, mentionableOptionPredicate, roleOptionPredicate, userOptionPredicate). Adds chatInputCommandSubcommandPredicate and updates chatInputCommandSubcommandGroupPredicate and chatInputCommandPredicate to include comprehensive validation for contexts, permissions, integration types, and structured options.
Option class predicate assignments
packages/builders/src/interactions/commands/chatInput/options/ApplicationCommandOptionBase.ts, packages/builders/src/interactions/commands/chatInput/options/{attachment,boolean,mentionable,role,user}.ts
Removes concrete basicOptionPredicate from base class, converting it to a type-only declaration. Individual option classes now declare protected static override readonly predicate properties assigned to their respective option-type predicates.
Chat input command serialization
packages/builders/src/interactions/commands/chatInput/ChatInputCommand.ts
Changes option serialization to always pass false to option.toJSON() instead of forwarding the external validationOverride parameter.
Test refactoring
packages/builders/__tests__/interactions/ChatInputCommands/ChatInputCommands.test.ts
Updates test builder assembly sequence to use modular helper builders (getNamedBuilder(), getSubcommand(), getSubcommandGroup()) instead of inline configuration on a chained base builder.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Assertions.ts refactoring: Dense schema changes with new type predicates and modified validation structures affecting multiple validation paths; requires tracing how each predicate is used across option types and command structures.
  • Predicate assignment pattern: While repetitive across option files, each assignment must be verified to use the correct corresponding predicate and is coupled to the schema changes in Assertions.ts.
  • ChatInputCommand.ts behavioral change: The shift from forwarding validationOverride to always passing false alters validation behavior; requires careful assessment of whether this change is safe across all use cases and doesn't introduce validation regressions.
  • Base class modification: Removing the default predicate from ApplicationCommandOptionBase and delegating to subclasses is a structural change that must be verified across all option subclasses.
  • Cross-file consistency: The coherence between imports, predicate definitions, and class assignments across multiple files needs thorough verification.

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main refactoring effort to move full validation responsibility to ChatInputCommandBuilder and the underlying predicates.
Description check ✅ Passed The description relates to the changeset by explaining the validation structure changes and linking to the specific issue being addressed.
Linked Issues check ✅ Passed The PR successfully addresses issue #11308 by restructuring validation to enable full chat input command validation through the predicate.
Out of Scope Changes check ✅ Passed All changes directly support the validation refactoring objective; test updates reflect the new modular builder approach without introducing unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/validation-on-chatinputcommand

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d0745af and 273547b.

📒 Files selected for processing (9)
  • packages/builders/__tests__/interactions/ChatInputCommands/ChatInputCommands.test.ts (1 hunks)
  • packages/builders/src/interactions/commands/chatInput/Assertions.ts (3 hunks)
  • packages/builders/src/interactions/commands/chatInput/ChatInputCommand.ts (1 hunks)
  • packages/builders/src/interactions/commands/chatInput/options/ApplicationCommandOptionBase.ts (1 hunks)
  • packages/builders/src/interactions/commands/chatInput/options/attachment.ts (1 hunks)
  • packages/builders/src/interactions/commands/chatInput/options/boolean.ts (1 hunks)
  • packages/builders/src/interactions/commands/chatInput/options/mentionable.ts (1 hunks)
  • packages/builders/src/interactions/commands/chatInput/options/role.ts (1 hunks)
  • packages/builders/src/interactions/commands/chatInput/options/user.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
packages/builders/src/interactions/commands/chatInput/options/user.ts (1)
packages/builders/src/interactions/commands/chatInput/Assertions.ts (1)
  • userOptionPredicate (97-100)
packages/builders/src/interactions/commands/chatInput/options/attachment.ts (1)
packages/builders/src/interactions/commands/chatInput/Assertions.ts (1)
  • attachmentOptionPredicate (77-80)
packages/builders/src/interactions/commands/chatInput/ChatInputCommand.ts (3)
packages/builders/src/components/selectMenu/StringSelectMenu.ts (1)
  • options (24-26)
packages/builders/src/interactions/commands/chatInput/ChatInputCommandSubcommands.ts (1)
  • options (39-41)
packages/builders/src/interactions/commands/chatInput/mixins/SharedChatInputCommandOptions.ts (1)
  • options (30-32)
packages/builders/src/interactions/commands/chatInput/options/mentionable.ts (1)
packages/builders/src/interactions/commands/chatInput/Assertions.ts (1)
  • mentionableOptionPredicate (87-90)
packages/builders/src/interactions/commands/chatInput/options/boolean.ts (1)
packages/builders/src/interactions/commands/chatInput/Assertions.ts (1)
  • booleanOptionPredicate (82-85)
packages/builders/src/interactions/commands/chatInput/options/role.ts (1)
packages/builders/src/interactions/commands/chatInput/Assertions.ts (1)
  • roleOptionPredicate (92-95)
packages/builders/src/interactions/commands/chatInput/Assertions.ts (1)
packages/builders/src/Assertions.ts (1)
  • memberPermissionsPredicate (8-8)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tests
  • GitHub Check: Tests
🔇 Additional comments (11)
packages/builders/src/interactions/commands/chatInput/options/boolean.ts (1)

2-2: LGTM! Predicate wiring follows the established pattern.

The addition of the class-level predicate binding using booleanOptionPredicate correctly implements the new validation architecture where each option type declares its own predicate.

Also applies to: 9-12

packages/builders/src/interactions/commands/chatInput/ChatInputCommand.ts (1)

33-33: Validation architecture correctly centralized.

The change from option.toJSON(validationOverride) to option.toJSON(false) is the core of this refactoring. Individual options now skip self-validation, and comprehensive validation occurs at line 36 via chatInputCommandPredicate. This ensures the entire command structure, including all nested options, is validated as a single unit.

packages/builders/src/interactions/commands/chatInput/options/role.ts (1)

2-2: LGTM! Consistent predicate wiring.

The role option correctly adopts the same predicate binding pattern as other option types.

Also applies to: 9-12

packages/builders/__tests__/interactions/ChatInputCommands/ChatInputCommands.test.ts (1)

382-384: Test refactoring improves maintainability.

The change to use helper functions (getNamedBuilder(), getSubcommand(), getSubcommandGroup()) makes the test more consistent with the modular builder pattern used throughout the test suite while preserving the same test coverage.

packages/builders/src/interactions/commands/chatInput/options/user.ts (1)

2-2: LGTM! Predicate wiring implemented correctly.

The user option follows the established predicate binding pattern consistently.

Also applies to: 9-12

packages/builders/src/interactions/commands/chatInput/options/mentionable.ts (1)

2-2: LGTM! Consistent predicate implementation.

The mentionable option correctly implements the predicate binding pattern.

Also applies to: 9-12

packages/builders/src/interactions/commands/chatInput/options/attachment.ts (1)

2-2: LGTM! Predicate binding follows the pattern.

The attachment option correctly adopts the predicate binding approach.

Also applies to: 9-12

packages/builders/src/interactions/commands/chatInput/options/ApplicationCommandOptionBase.ts (1)

26-26: Base class correctly delegates predicate to subclasses.

Changing the predicate field from a concrete value to a type-only declaration (protected static readonly predicate: z.ZodType) is the foundational change that enables the per-option-type predicate wiring pattern. Subclasses now must provide their own predicates via override, and the runtime access at line 62 ((this.constructor as typeof ApplicationCommandOptionBase).predicate) correctly uses the subclass-provided value.

packages/builders/src/interactions/commands/chatInput/Assertions.ts (3)

72-100: Well-structured option predicate hierarchy.

The introduction of baseBasicOptionPredicate and individual type-specific predicates is a clean approach. Each simple option type correctly extends the base and adds its specific type literal.


155-165: Subcommand structure is correct.

The subcommand predicate correctly allows optional basic options (max 25), and the subcommand group correctly requires at least one subcommand with .min(1). This aligns with Discord's API requirements for command nesting.


167-180: Full command predicate correctly enforces option structure and validates with Zod 4.

The options union correctly implements Discord's constraint that commands can have either basic options OR subcommands/subcommand groups, but not a mix. Zod 4's z.enum() successfully validates the numeric enums (InteractionContextType, ApplicationIntegrationType) from discord-api-types/v10. While Zod discourages numeric enums as error-prone, they function correctly here and the predicate is actively used in ChatInputCommand validation without issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

Refactor chat input command validation overrides

4 participants