Skip to content

feat: set pattern constraint for regular expressions#1188

Open
transparent-citizen wants to merge 3 commits intoedmundhung:mainfrom
transparent-citizen:main
Open

feat: set pattern constraint for regular expressions#1188
transparent-citizen wants to merge 3 commits intoedmundhung:mainfrom
transparent-citizen:main

Conversation

@transparent-citizen
Copy link
Copy Markdown
Contributor

@transparent-citizen transparent-citizen commented Apr 16, 2026

This PR lets Conform construct an HTML pattern attribute based on regular expressions from zod v3, v4, and valibot schemas.

It's worth noting that these validators allow multiple regexes for string schemas. For example in zod,

z.string().regex(/a/).regex(/b/)

matches strings containing at least one "a" and one "b" in any order. But because <input> accepts only one pattern attribute, multiple regexes need to be combined into one, using positive lookahead assertions:

 in: [A-Z], [0-9]
out: ^(?=.*(?:[A-Z]))(?=.*(?:[0-9])).*$

The correctness of out is supported by this jsfiddle featuring an input whose text turns green if and only if it matches both in patterns.

Regular expressions in the HTML pattern attribute run with the v flag by default (used to be u). These supported flags are stripped, while unsupported flags will not be mapped to a pattern.

Generated Summary
  • Added combinePatterns(patterns: RegExp[]): string | undefined in packages/conform-dom/util.ts and re-exported it from packages/conform-dom/future. It returns undefined for empty input or when any regex has unsupported flags (allowed flags u/v are stripped). For valid inputs it builds a single anchored pattern that conjuncts multiple regexes with positive lookaheads (e.g. ^(?=.(?:[A-Z]))(?=.(?:[0-9])).*$). HTML pattern generation assumes browser behavior using the v flag by default; supported flags are stripped and unsupported flags are not mapped.
  • Zod (default): getZodConstraint now collects ZodString regex checks (def.checks kind === 'regex') and sets constraint.pattern via combinePatterns.
  • Zod v4: getZodConstraint now reads _schema._zod.bag.patterns and sets constraint.pattern via combinePatterns.
  • Valibot: getValibotConstraint now inspects schema.pipe for regex validators and sets constraint.pattern via combinePatterns.
  • Tests: Added unit tests for combinePatterns and Vitest cases verifying single and chained regex → combined pattern behavior for zod/default, zod/v4, and valibot; tests cover empty-input and unsupported/supported flags.
  • Changeset: Adds documentation and example showing mapping of schema regex validators to the HTML pattern attribute and how to expose it via inputProps.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 16, 2026

🦋 Changeset detected

Latest commit: b59535e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@conform-to/dom Minor
@conform-to/react Minor
@conform-to/valibot Minor
@conform-to/zod Minor
@conform-to/yup Minor

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

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 16, 2026

More templates

@conform-to/dom

npm i https://pkg.pr.new/@conform-to/dom@1188

@conform-to/react

npm i https://pkg.pr.new/@conform-to/react@1188

@conform-to/valibot

npm i https://pkg.pr.new/@conform-to/valibot@1188

@conform-to/validitystate

npm i https://pkg.pr.new/@conform-to/validitystate@1188

@conform-to/yup

npm i https://pkg.pr.new/@conform-to/yup@1188

@conform-to/zod

npm i https://pkg.pr.new/@conform-to/zod@1188

commit: b59535e

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 16, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Added a new exported utility combinePatterns that builds anchored lookahead-based HTML pattern strings (or returns undefined for empty/unsupported-flag inputs), re-exported it from the DOM future API, and used it in Zod and Valibot adapters to populate constraint.pattern. Tests and a changeset were added.

Changes

Cohort / File(s) Summary
Core Pattern Utility
packages/conform-dom/util.ts, packages/conform-dom/future/index.ts
Add `combinePatterns(patterns: RegExp[]): string
Valibot Integration
packages/conform-valibot/constraint.ts, packages/conform-valibot/tests/constraint.test.ts
Import and use combinePatterns to derive constraint.pattern from schema.pipe regex validators for string schemas; add tests for single and multiple regex pipeline cases with runtime RegExp assertions.
Zod (default) Integration
packages/conform-zod/default/constraint.ts, packages/conform-zod/default/tests/constraint.test.ts
Collect ZodString regex checks, combine their sources via combinePatterns, and set constraint.pattern when produced; add unit tests for single and chained .regex() cases.
Zod (v4) Integration
packages/conform-zod/v4/constraint.ts, packages/conform-zod/v4/tests/constraint.test.ts
Read _schema._zod.bag.patterns for string schemas, combine with combinePatterns, and assign constraint.pattern when truthy; add tests validating combined pattern output.
Tests (DOM util)
packages/conform-dom/tests/util.test.ts
Add tests for combinePatterns: empty input yields undefined; single/multiple regexes produce expected lookahead-anchored strings; unsupported flags produce undefined; /u is accepted.
Release Notes
.changeset/pattern-constraint-regex.md
New changeset documenting mapping of regex-based validators to HTML pattern attributes and bumping affected packages as minor releases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I stitched the patterns, stitch by stitch,

Lookaheads hum where anchors pitch.
Empty lists I skip with care,
Flags that balk I leave elsewhere.
Together they hop — a matched affair.

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary change: adding support for mapping regex schema constraints to the HTML pattern attribute across zod and valibot validators.

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


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.

Actionable comments posted: 1

🤖 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/conform-dom/util.ts`:
- Around line 129-134: The single-pattern branch returns first.source which
changes semantics to full-string match; instead make the single-pattern case use
the same lookahead construction as the multi-pattern branch so unanchored
regexes remain substring-style (use patterns and first variables and return the
`(?=.*...)` based string instead of first.source) — update the logic in util.ts
around the patterns/first handling so both single and multiple patterns generate
`^` + lookaheads + `.*$`, ensuring downstream generators in
conform-valibot/constraint.ts and conform-zod/* preserve original regex
semantics.
🪄 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: 9d4cafac-e70c-43f0-8c68-fd14f058eea7

📥 Commits

Reviewing files that changed from the base of the PR and between a9481c5 and 7dcb74c.

📒 Files selected for processing (8)
  • packages/conform-dom/future/index.ts
  • packages/conform-dom/util.ts
  • packages/conform-valibot/constraint.ts
  • packages/conform-valibot/tests/constraint.test.ts
  • packages/conform-zod/default/constraint.ts
  • packages/conform-zod/default/tests/constraint.test.ts
  • packages/conform-zod/v4/constraint.ts
  • packages/conform-zod/v4/tests/constraint.test.ts

Comment thread packages/conform-dom/util.ts Outdated
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

♻️ Duplicate comments (1)
packages/conform-dom/util.ts (1)

129-134: ⚠️ Potential issue | 🟠 Major

Single-regex branch changes regex semantics and can over-reject valid inputs.

This issue was flagged in a previous review. The single-pattern case returns first.source directly, which makes unanchored regexes behave as full-string matches in HTML (the pattern attribute has implicit ^...$ anchors). However, Zod/Valibot's .regex() uses RegExp.test() which matches substrings.

Example: A string "abcD" passes .regex(/[A-Z]/) in Zod, but pattern="[A-Z]" fails in browser validation because HTML requires the entire value to match.

The single-pattern case should use the same lookahead strategy as multi-pattern for consistent semantics:

💡 Proposed fix
 export function combinePatterns(patterns: RegExp[]): string {
 	if (patterns.length === 0) {
 		return '';
 	}

-	const first = patterns[0];
-	if (first && patterns.length === 1) {
-		return first.source;
-	}
-
-	return `^${patterns.map((p) => `(?=.*${p.source})`).join('')}.*$`;
+	return `^${patterns.map((p) => `(?=.*(?:${p.source}))`).join('')}.*$`;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/conform-dom/util.ts` around lines 129 - 134, The single-pattern
branch currently returns first.source directly which changes semantics; instead
always build the anchored lookahead pattern used for multi-patterns so HTML
pattern semantics match RegExp.test() behavior. Replace the special-case return
of first.source (the code referencing first and patterns) with the same
construction used below: return an anchored string using patterns.map(p =>
`(?=.*${p.source})`).join('') wrapped with ^ and .*$ so both single and multiple
patterns use the lookahead strategy.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/pattern-constraint-regex.md:
- Around line 10-22: The example is missing the zod import used by schema
(symbols: z and schema); add the zod import at the top of the snippet so
z.object and z.string() resolve (e.g., import the named export that provides z
from the 'zod' package) and ensure the import sits alongside the existing
imports (configureForms, getConstraints, InputHTMLAttributes).

---

Duplicate comments:
In `@packages/conform-dom/util.ts`:
- Around line 129-134: The single-pattern branch currently returns first.source
directly which changes semantics; instead always build the anchored lookahead
pattern used for multi-patterns so HTML pattern semantics match RegExp.test()
behavior. Replace the special-case return of first.source (the code referencing
first and patterns) with the same construction used below: return an anchored
string using patterns.map(p => `(?=.*${p.source})`).join('') wrapped with ^ and
.*$ so both single and multiple patterns use the lookahead strategy.
🪄 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: 0f283ca0-ddcf-401a-9ba7-4d55b0359757

📥 Commits

Reviewing files that changed from the base of the PR and between 7dcb74c and 18ff2e4.

📒 Files selected for processing (9)
  • .changeset/pattern-constraint-regex.md
  • packages/conform-dom/future/index.ts
  • packages/conform-dom/util.ts
  • packages/conform-valibot/constraint.ts
  • packages/conform-valibot/tests/constraint.test.ts
  • packages/conform-zod/default/constraint.ts
  • packages/conform-zod/default/tests/constraint.test.ts
  • packages/conform-zod/v4/constraint.ts
  • packages/conform-zod/v4/tests/constraint.test.ts

Comment thread .changeset/pattern-constraint-regex.md
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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/pattern-constraint-regex.md:
- Around line 30-31: Update the inline comment that shows the expected combined
pattern to match the actual output from combinePatterns: change the example from
'^(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*]).*$' to include the non-capturing groups
produced by combinePatterns, i.e.
'^(?=.*(?:[A-Z]))(?=.*(?:[0-9]))(?=.*(?:[!@#$%^&*])).*$'; ensure the comment
near where metadata.pattern is assigned reflects this exact format and
references combinePatterns behavior.

In `@packages/conform-dom/util.ts`:
- Around line 117-130: The JSDoc example for combinePatterns is inaccurate: the
function takes a RegExp[] (not string[]) and the implementation wraps each
pattern in a non-capturing group, so update the documentation for the
combinePatterns function to show RegExp[] input and the actual output (e.g.,
['[A-Z]', '[0-9]'] -> '^(?=.*(?:[A-Z]))(?=.*(?:[0-9])).*$'); ensure the example
uses RegExp-style patterns (or refactor the function if you prefer string
inputs) and adjust the comment text to match the implemented return value
exactly.

In `@packages/conform-zod/v4/tests/constraint.test.ts`:
- Around line 461-484: The combinePatterns implementation is wrapping each regex
source in an unnecessary non-capturing group which yields incorrect lookahead
patterns; update the combinePatterns function in util.ts to build lookaheads
using the raw pattern source (use `(?=.*${p.source})` for each RegExp p) instead
of `(?=.*(?:${p.source}))`, so the returned string becomes
`^${patterns.map(...).join('')}.*$` with direct p.source insertion and no extra
`(?:...)` wrapping.
🪄 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: 1f7618c3-8d72-4b08-9593-c1106bd84f8c

📥 Commits

Reviewing files that changed from the base of the PR and between 18ff2e4 and 2b0c670.

📒 Files selected for processing (9)
  • .changeset/pattern-constraint-regex.md
  • packages/conform-dom/future/index.ts
  • packages/conform-dom/util.ts
  • packages/conform-valibot/constraint.ts
  • packages/conform-valibot/tests/constraint.test.ts
  • packages/conform-zod/default/constraint.ts
  • packages/conform-zod/default/tests/constraint.test.ts
  • packages/conform-zod/v4/constraint.ts
  • packages/conform-zod/v4/tests/constraint.test.ts

Comment thread .changeset/pattern-constraint-regex.md Outdated
Comment thread packages/conform-dom/util.ts
@transparent-citizen transparent-citizen force-pushed the main branch 2 times, most recently from f028ada to 512dc23 Compare April 16, 2026 15:23
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

♻️ Duplicate comments (1)
packages/conform-dom/util.ts (1)

117-123: 🧹 Nitpick | 🔵 Trivial

JSDoc has minor inconsistencies with the implementation.

  1. Line 119 states "For a single pattern, returns the pattern source as-is" but the implementation always wraps patterns in the lookahead format regardless of count.

  2. Line 122's example shows ['[A-Z]', '[0-9]'] (string array notation) but the function signature takes RegExp[].

📝 Suggested documentation fix
 /**
  * Combines multiple regex patterns into a single HTML pattern attribute string.
- * For a single pattern, returns the pattern source as-is.
  * For multiple patterns, combines them using lookahead assertions that must ALL match.
  *
- * Example: ['[A-Z]', '[0-9]'] -> '^(?=.*(?:[A-Z]))(?=.*(?:[0-9])).*$'
+ * Example: [/[A-Z]/, /[0-9]/] -> '^(?=.*(?:[A-Z]))(?=.*(?:[0-9])).*$'
  */
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/conform-dom/util.ts` around lines 117 - 123, The JSDoc is out of
sync with the implementation: update the comment for the function that combines
multiple RegExp patterns into an HTML pattern attribute (the function that
accepts RegExp[]) to reflect that it always wraps patterns in lookahead
assertions (it does not return a single pattern source as-is), and change the
example to show RegExp values (e.g. [/ [A-Z]/, /[0-9]/] or the literal /[A-Z]/,
/[0-9]/) instead of string array notation so the signature RegExp[] matches the
example.
🤖 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/conform-valibot/tests/constraint.test.ts`:
- Around line 390-402: The assertion in the test for getValibotConstraint
currently requires exact pattern string equality which makes the test brittle;
update the test in constraint.test.ts to assert the structural parts (e.g.,
empty.required, singlePattern.required, multiplePatterns.required) remain true
but replace exact pattern string equality with semantic checks: extract the
pattern value returned by getValibotConstraint(schema), construct RegExp objects
from those pattern strings, and assert they accept known good inputs and reject
known bad inputs for singlePattern and multiplePatterns (e.g., uppercase-only vs
lowercase, and combinations with digits) so logically equivalent regex rewrites
won't break the test.

---

Duplicate comments:
In `@packages/conform-dom/util.ts`:
- Around line 117-123: The JSDoc is out of sync with the implementation: update
the comment for the function that combines multiple RegExp patterns into an HTML
pattern attribute (the function that accepts RegExp[]) to reflect that it always
wraps patterns in lookahead assertions (it does not return a single pattern
source as-is), and change the example to show RegExp values (e.g. [/ [A-Z]/,
/[0-9]/] or the literal /[A-Z]/, /[0-9]/) instead of string array notation so
the signature RegExp[] matches the example.
🪄 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: 8a7566df-2a95-4f89-b768-e078763d95c0

📥 Commits

Reviewing files that changed from the base of the PR and between 2b0c670 and f028ada.

📒 Files selected for processing (9)
  • .changeset/pattern-constraint-regex.md
  • packages/conform-dom/future/index.ts
  • packages/conform-dom/util.ts
  • packages/conform-valibot/constraint.ts
  • packages/conform-valibot/tests/constraint.test.ts
  • packages/conform-zod/default/constraint.ts
  • packages/conform-zod/default/tests/constraint.test.ts
  • packages/conform-zod/v4/constraint.ts
  • packages/conform-zod/v4/tests/constraint.test.ts

Comment thread packages/conform-valibot/tests/constraint.test.ts
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

♻️ Duplicate comments (1)
packages/conform-valibot/tests/constraint.test.ts (1)

390-402: 🧹 Nitpick | 🔵 Trivial

Use semantic regex assertions to avoid brittle serialization coupling.

Line 390-Line 402 currently lock the test to one exact pattern string form; logically equivalent rewrites of combinePatterns would cause noisy failures.

♻️ Suggested test hardening
-		expect(getValibotConstraint(schema)).toEqual({
+		const constraint = getValibotConstraint(schema);
+		expect(constraint).toEqual({
 			empty: {
 				required: true,
 			},
 			singlePattern: {
 				required: true,
 				pattern: '^(?=.*(?:^[A-Z]+$)).*$',
 			},
 			multiplePatterns: {
 				required: true,
 				pattern: '^(?=.*(?:[A-Z]))(?=.*(?:[0-9])).*$',
 			},
 		});
+
+		const singlePattern = new RegExp(constraint.singlePattern.pattern!);
+		expect(singlePattern.test('ABC')).toBe(true);
+		expect(singlePattern.test('AbC')).toBe(false);
+
+		const multiplePatterns = new RegExp(constraint.multiplePatterns.pattern!);
+		expect(multiplePatterns.test('A1')).toBe(true);
+		expect(multiplePatterns.test('ABC')).toBe(false);
+		expect(multiplePatterns.test('123')).toBe(false);
 	});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/conform-valibot/tests/constraint.test.ts` around lines 390 - 402,
The test currently asserts exact serialized pattern strings from
getValibotConstraint which is brittle; instead assert semantics: keep checking
that getValibotConstraint(schema).empty.required and
.singlePattern.required/.multiplePatterns.required are true, and for the pattern
fields verify their semantics by (a) treating the returned pattern string as a
RegExp (e.g., new RegExp(pattern)) and asserting it matches positive example
strings and rejects negative examples, or (b) assert the pattern string contains
the expected lookahead fragments like '(?=.*[A-Z])' and '(?=.*[0-9])' using
string matching—refer to getValibotConstraint and the
schema/singlePattern/multiplePatterns keys to locate where to change the
assertions.
🤖 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/conform-dom/util.ts`:
- Around line 124-129: The combinePatterns function currently drops RegExp flags
by using p.source which can produce incorrect HTML pattern attributes for
flagged regexes; modify combinePatterns (and its return type) to detect any
flagged RegExp (e.g., check p.flags or p.constructor.name) and return undefined
immediately when any pattern has flags instead of producing a string, otherwise
keep the existing combined `^...$` behavior using p.source; update any callers
expecting a string to handle the new undefined case so flagged regexes are not
emitted to the HTML pattern attribute.

---

Duplicate comments:
In `@packages/conform-valibot/tests/constraint.test.ts`:
- Around line 390-402: The test currently asserts exact serialized pattern
strings from getValibotConstraint which is brittle; instead assert semantics:
keep checking that getValibotConstraint(schema).empty.required and
.singlePattern.required/.multiplePatterns.required are true, and for the pattern
fields verify their semantics by (a) treating the returned pattern string as a
RegExp (e.g., new RegExp(pattern)) and asserting it matches positive example
strings and rejects negative examples, or (b) assert the pattern string contains
the expected lookahead fragments like '(?=.*[A-Z])' and '(?=.*[0-9])' using
string matching—refer to getValibotConstraint and the
schema/singlePattern/multiplePatterns keys to locate where to change the
assertions.
🪄 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: d478dc02-fd45-4074-9bdb-0efa0dc747b8

📥 Commits

Reviewing files that changed from the base of the PR and between f028ada and 512dc23.

📒 Files selected for processing (9)
  • .changeset/pattern-constraint-regex.md
  • packages/conform-dom/future/index.ts
  • packages/conform-dom/util.ts
  • packages/conform-valibot/constraint.ts
  • packages/conform-valibot/tests/constraint.test.ts
  • packages/conform-zod/default/constraint.ts
  • packages/conform-zod/default/tests/constraint.test.ts
  • packages/conform-zod/v4/constraint.ts
  • packages/conform-zod/v4/tests/constraint.test.ts

Comment thread packages/conform-dom/util.ts Outdated
@transparent-citizen transparent-citizen force-pushed the main branch 4 times, most recently from 9103975 to 2e0da81 Compare April 16, 2026 17:32
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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/pattern-constraint-regex.md:
- Line 8: The markdown file starts prose immediately after frontmatter and
triggers markdownlint MD041; add a top-level H1 heading (e.g., "# Pattern
constraint regex") at the top of the document immediately after the existing
frontmatter so the file has an H1 before any prose; ensure the heading text
describes the change (references to "pattern-constraint-regex" or similar) and
leave the rest of the content unchanged.

In `@packages/conform-dom/tests/util.test.ts`:
- Around line 39-42: Tests only cover 'g' flag rejection; add cases to ensure
allowed flags ('u' and 'v') and other unsupported flags are enforced by
combinePatterns. In util.test.ts add an assertion that combinePatterns([/a/u,
/b/u]) (or similar) returns a combined RegExp (not undefined) and an assertion
that combinePatterns([/A/i]) (or mix with other flags) returns undefined;
reference combinePatterns and the whitelist logic in util.ts (flags 'u' and 'v')
to guide expectations.

In `@packages/conform-dom/util.ts`:
- Around line 127-137: The exported function combinePatterns should declare an
explicit return type of string | undefined to make its public contract clear;
update the function signature for combinePatterns (the exported function in
util.ts) to return string | undefined instead of relying on inference, leaving
the implementation unchanged so callers see the precise return type.
🪄 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: 02279444-904a-45f4-91eb-eaed7d1cbae4

📥 Commits

Reviewing files that changed from the base of the PR and between f028ada and 9103975.

📒 Files selected for processing (10)
  • .changeset/pattern-constraint-regex.md
  • packages/conform-dom/future/index.ts
  • packages/conform-dom/tests/util.test.ts
  • packages/conform-dom/util.ts
  • packages/conform-valibot/constraint.ts
  • packages/conform-valibot/tests/constraint.test.ts
  • packages/conform-zod/default/constraint.ts
  • packages/conform-zod/default/tests/constraint.test.ts
  • packages/conform-zod/v4/constraint.ts
  • packages/conform-zod/v4/tests/constraint.test.ts

Comment thread .changeset/pattern-constraint-regex.md Outdated
Comment thread packages/conform-dom/tests/util.test.ts Outdated
Comment thread packages/conform-dom/util.ts Outdated
@transparent-citizen transparent-citizen force-pushed the main branch 2 times, most recently from ce76ea1 to fe25719 Compare April 16, 2026 17:36
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.

♻️ Duplicate comments (2)
packages/conform-dom/tests/util.test.ts (1)

39-42: 🧹 Nitpick | 🔵 Trivial

Consider adding test cases for allowed flags (u/v).

The tests cover unsupported flags (g, i) returning undefined, but don't verify that patterns with u or v flags (which are stripped) still produce valid output.

📝 Suggested test additions
 	// Patterns with unsupported flags
 	expect(combinePatterns([/[A-Z]/g])).toBeUndefined();
 	expect(combinePatterns([/[A-Z]/, /[0-9]/i])).toBeUndefined();
+
+	// Patterns with allowed flags (u/v are stripped, should still work)
+	expect(combinePatterns([/[A-Z]/u])).toBe('^(?=.*(?:[A-Z])).*$');
+	expect(combinePatterns([/[A-Z]/v, /[0-9]/u])).toBe(
+		'^(?=.*(?:[A-Z]))(?=.*(?:[0-9])).*$',
+	);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/conform-dom/tests/util.test.ts` around lines 39 - 42, The test suite
for combinePatterns currently checks that unsupported flags (g, i) yield
undefined but lacks coverage for allowed flags; add tests invoking
combinePatterns with patterns using the u and v flags (e.g. /.../u and /.../v)
and assert the result is not undefined and correctly combines the pattern bodies
(i.e., flags are stripped and the resulting RegExp or pattern string reflects
the combined content); update util.test.ts near the other combinePatterns tests
and reference the combinePatterns function in your assertions.
.changeset/pattern-constraint-regex.md (1)

8-8: ⚠️ Potential issue | 🟡 Minor

Add an H1 after frontmatter to satisfy markdownlint MD041.

The first content line is prose; this should start with a top-level heading.

Suggested fix
+# Map regex constraints to `pattern`
+
 Mapped regex constraints to `pattern`, enabling advanced client-side validation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/pattern-constraint-regex.md at line 8, Add a top-level heading
immediately after the YAML frontmatter in .changeset/pattern-constraint-regex.md
so the first content line is not plain prose; insert an H1 (for example
referencing the change like "# Pattern constraint regex" or a generic "#
Changelog") directly after the closing frontmatter delimiter (---) and before
the existing line "Mapped regex constraints to `pattern`, enabling advanced
client-side validation." to satisfy markdownlint MD041.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In @.changeset/pattern-constraint-regex.md:
- Line 8: Add a top-level heading immediately after the YAML frontmatter in
.changeset/pattern-constraint-regex.md so the first content line is not plain
prose; insert an H1 (for example referencing the change like "# Pattern
constraint regex" or a generic "# Changelog") directly after the closing
frontmatter delimiter (---) and before the existing line "Mapped regex
constraints to `pattern`, enabling advanced client-side validation." to satisfy
markdownlint MD041.

In `@packages/conform-dom/tests/util.test.ts`:
- Around line 39-42: The test suite for combinePatterns currently checks that
unsupported flags (g, i) yield undefined but lacks coverage for allowed flags;
add tests invoking combinePatterns with patterns using the u and v flags (e.g.
/.../u and /.../v) and assert the result is not undefined and correctly combines
the pattern bodies (i.e., flags are stripped and the resulting RegExp or pattern
string reflects the combined content); update util.test.ts near the other
combinePatterns tests and reference the combinePatterns function in your
assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: fefe9485-13b4-4cf5-bc04-6fa8d26e9633

📥 Commits

Reviewing files that changed from the base of the PR and between 9103975 and ce76ea1.

📒 Files selected for processing (10)
  • .changeset/pattern-constraint-regex.md
  • packages/conform-dom/future/index.ts
  • packages/conform-dom/tests/util.test.ts
  • packages/conform-dom/util.ts
  • packages/conform-valibot/constraint.ts
  • packages/conform-valibot/tests/constraint.test.ts
  • packages/conform-zod/default/constraint.ts
  • packages/conform-zod/default/tests/constraint.test.ts
  • packages/conform-zod/v4/constraint.ts
  • packages/conform-zod/v4/tests/constraint.test.ts

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

🤖 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/conform-dom/tests/util.test.ts`:
- Around line 39-42: Add tests asserting that combinePatterns accepts allowed
flags 'u' and 'v': call combinePatterns with arrays containing patterns that
include the 'u' flag and the 'v' flag (e.g., /.../u and /.../v) and assert the
result is not undefined and is a RegExp (or matches expected combined behavior).
Update packages/conform-dom/tests/util.test.ts near the existing flag tests to
include these assertions referencing combinePatterns so we confirm allowed flags
produce a valid combined pattern.

In `@packages/conform-zod/v4/tests/constraint.test.ts`:
- Around line 461-484: The test "regex patterns" currently only asserts the
exact pattern strings returned by getZodConstraint but should also include
semantic runtime checks to ensure those pattern strings actually match the
intended inputs; update the test that builds the schema (variable schema with
fields empty, singlePattern, multiplePatterns) to, after calling
getZodConstraint, construct RegExp instances from the returned pattern values
for singlePattern and multiplePatterns and assert RegExp.test(...) against
representative matching and non-matching sample strings (e.g., uppercase-only
and numeric-containing samples) so the patterns are validated semantically in
addition to string equality.
🪄 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: 60decdd8-3ca8-4b8a-9868-6d7050e23f96

📥 Commits

Reviewing files that changed from the base of the PR and between ce76ea1 and fe25719.

📒 Files selected for processing (10)
  • .changeset/pattern-constraint-regex.md
  • packages/conform-dom/future/index.ts
  • packages/conform-dom/tests/util.test.ts
  • packages/conform-dom/util.ts
  • packages/conform-valibot/constraint.ts
  • packages/conform-valibot/tests/constraint.test.ts
  • packages/conform-zod/default/constraint.ts
  • packages/conform-zod/default/tests/constraint.test.ts
  • packages/conform-zod/v4/constraint.ts
  • packages/conform-zod/v4/tests/constraint.test.ts

Comment thread packages/conform-dom/tests/util.test.ts Outdated
Comment on lines +39 to +42
// Patterns with unsupported flags
expect(combinePatterns([/[A-Z]/g])).toBeUndefined();
expect(combinePatterns([/[A-Z]/, /[0-9]/i])).toBeUndefined();
});
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Apr 16, 2026

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Add test coverage for allowed u and v flags.

The tests verify that unsupported flags (g, i) cause undefined to be returned, but there's no assertion confirming that patterns with the allowed u or v flags still produce a valid combined pattern.

♻️ Proposed test additions
 	// Patterns with unsupported flags
 	expect(combinePatterns([/[A-Z]/g])).toBeUndefined();
 	expect(combinePatterns([/[A-Z]/, /[0-9]/i])).toBeUndefined();
+
+	// Patterns with allowed flags (u and v)
+	expect(combinePatterns([/[A-Z]/u])).toBe('^(?=.*(?:[A-Z])).*$');
+	expect(combinePatterns([/[A-Z]/v, /[0-9]/])).toBe(
+		'^(?=.*(?:[A-Z]))(?=.*(?:[0-9])).*$',
+	);
 });
📝 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.

Suggested change
// Patterns with unsupported flags
expect(combinePatterns([/[A-Z]/g])).toBeUndefined();
expect(combinePatterns([/[A-Z]/, /[0-9]/i])).toBeUndefined();
});
// Patterns with unsupported flags
expect(combinePatterns([/[A-Z]/g])).toBeUndefined();
expect(combinePatterns([/[A-Z]/, /[0-9]/i])).toBeUndefined();
// Patterns with allowed flags (u and v)
expect(combinePatterns([/[A-Z]/u])).toBe('^(?=.*(?:[A-Z])).*$');
expect(combinePatterns([/[A-Z]/v, /[0-9]/])).toBe(
'^(?=.*(?:[0-9]))(?=.*(?:[A-Z])).*$',
);
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/conform-dom/tests/util.test.ts` around lines 39 - 42, Add tests
asserting that combinePatterns accepts allowed flags 'u' and 'v': call
combinePatterns with arrays containing patterns that include the 'u' flag and
the 'v' flag (e.g., /.../u and /.../v) and assert the result is not undefined
and is a RegExp (or matches expected combined behavior). Update
packages/conform-dom/tests/util.test.ts near the existing flag tests to include
these assertions referencing combinePatterns so we confirm allowed flags produce
a valid combined pattern.

Copy link
Copy Markdown
Contributor Author

@transparent-citizen transparent-citizen Apr 16, 2026

Choose a reason for hiding this comment

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

I added a test for the u flag, but chose to pass on the v flag. The syntax is relatively new, and requiring newer syntax might limit environment support.

@edmundhung: Willing to change this if you prefer.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment thread packages/conform-zod/v4/tests/constraint.test.ts
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

♻️ Duplicate comments (1)
packages/conform-dom/tests/util.test.ts (1)

39-45: ⚠️ Potential issue | 🟡 Minor

Add explicit v-flag coverage in combinePatterns tests.

Line [43] only verifies u as supported. Add a v case too, so the supported-flag contract is fully locked and regressions are caught.

♻️ Suggested test update
 test('combinePatterns', () => {
@@
 	// Supported flags
 	expect(combinePatterns([/[A-Z]/u])).toBe('^(?=.*(?:[A-Z])).*$');
+
+	// `v` may not be available in all JS runtimes; gate to avoid parser/runtime issues
+	let supportsV = false;
+	try {
+		new RegExp('', 'v');
+		supportsV = true;
+	} catch {
+		supportsV = false;
+	}
+
+	if (supportsV) {
+		expect(combinePatterns([new RegExp('[A-Z]', 'v')])).toBe(
+			'^(?=.*(?:[A-Z])).*$',
+		);
+	}
 });
#!/bin/bash
# Read-only verification: confirm util whitelist behavior and current test coverage.
rg -n -C3 "combinePatterns|flags|u|v" packages/conform-dom/util.ts
rg -n -C3 "Supported flags|Unsupported flags|combinePatterns\\(" packages/conform-dom/tests/util.test.ts
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/conform-dom/tests/util.test.ts` around lines 39 - 45, The test
currently asserts that combinePatterns supports the 'u' flag but omits verifying
support for the 'v' flag; update the tests around combinePatterns in
util.test.ts to add an explicit case asserting that combinePatterns([/[A-Z]/v])
returns the expected combined string (matching the same format as the 'u' case),
and also add a mixed supported-case if desired (e.g., a pattern with 'v'
combined alone or with other supported flags) so the supported-flag contract for
combinePatterns is locked and will fail on regressions.
🤖 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/conform-dom/util.ts`:
- Around line 122-123: Update the JSDoc to match the implementation: state that
the function strips the `u` and `v` flags (because HTML pattern attributes
implicitly run with `v`) and only returns undefined when any other flags are
present; mention that `u`/`v` are silently removed rather than treated as an
error. Apply this change to the JSDoc for the pattern-handling function in
packages/conform-dom/util.ts so the comment aligns with the code that strips
`u`/`v` and rejects other flags.

---

Duplicate comments:
In `@packages/conform-dom/tests/util.test.ts`:
- Around line 39-45: The test currently asserts that combinePatterns supports
the 'u' flag but omits verifying support for the 'v' flag; update the tests
around combinePatterns in util.test.ts to add an explicit case asserting that
combinePatterns([/[A-Z]/v]) returns the expected combined string (matching the
same format as the 'u' case), and also add a mixed supported-case if desired
(e.g., a pattern with 'v' combined alone or with other supported flags) so the
supported-flag contract for combinePatterns is locked and will fail on
regressions.
🪄 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: 4eaa0336-70e5-42c5-8e41-abbd4fcf6afa

📥 Commits

Reviewing files that changed from the base of the PR and between fe25719 and decc258.

📒 Files selected for processing (10)
  • .changeset/pattern-constraint-regex.md
  • packages/conform-dom/future/index.ts
  • packages/conform-dom/tests/util.test.ts
  • packages/conform-dom/util.ts
  • packages/conform-valibot/constraint.ts
  • packages/conform-valibot/tests/constraint.test.ts
  • packages/conform-zod/default/constraint.ts
  • packages/conform-zod/default/tests/constraint.test.ts
  • packages/conform-zod/v4/constraint.ts
  • packages/conform-zod/v4/tests/constraint.test.ts

Comment thread packages/conform-dom/util.ts Outdated
@transparent-citizen transparent-citizen force-pushed the main branch 2 times, most recently from 5ebb455 to 4898385 Compare April 16, 2026 18:00
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.

♻️ Duplicate comments (1)
packages/conform-dom/util.ts (1)

122-123: ⚠️ Potential issue | 🟡 Minor

JSDoc still overstates flag rejection behavior.

The wording says “any pattern has flags,” but the implementation allows u/v and only rejects other flags. Please align wording with code behavior.

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

In `@packages/conform-dom/util.ts` around lines 122 - 123, Update the JSDoc in
packages/conform-dom/util.ts that describes HTML pattern flag handling to match
the code: state that the function only rejects patterns with disallowed flags
(i.e., flags other than `u` and `v`), and that it strips `u` and `v` because
HTML pattern attributes don't support flags; remove the phrase “any pattern has
flags” and explicitly mention that `u`/`v` are allowed/stripped while other
flags cause undefined to be returned.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/conform-dom/util.ts`:
- Around line 122-123: Update the JSDoc in packages/conform-dom/util.ts that
describes HTML pattern flag handling to match the code: state that the function
only rejects patterns with disallowed flags (i.e., flags other than `u` and
`v`), and that it strips `u` and `v` because HTML pattern attributes don't
support flags; remove the phrase “any pattern has flags” and explicitly mention
that `u`/`v` are allowed/stripped while other flags cause undefined to be
returned.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 96c51260-d6ac-4a7a-adf8-0476a0bc53e7

📥 Commits

Reviewing files that changed from the base of the PR and between decc258 and 5ebb455.

📒 Files selected for processing (10)
  • .changeset/pattern-constraint-regex.md
  • packages/conform-dom/future/index.ts
  • packages/conform-dom/tests/util.test.ts
  • packages/conform-dom/util.ts
  • packages/conform-valibot/constraint.ts
  • packages/conform-valibot/tests/constraint.test.ts
  • packages/conform-zod/default/constraint.ts
  • packages/conform-zod/default/tests/constraint.test.ts
  • packages/conform-zod/v4/constraint.ts
  • packages/conform-zod/v4/tests/constraint.test.ts

@transparent-citizen
Copy link
Copy Markdown
Contributor Author

@edmundhung Thanks for setting up CodeRabbit! A lot of its suggestions were quite helpful. Looking forward to hearing from you! 🙂

@transparent-citizen transparent-citizen force-pushed the main branch 2 times, most recently from 162d634 to c6760a0 Compare April 17, 2026 08:20
@transparent-citizen transparent-citizen force-pushed the main branch 3 times, most recently from a4bd405 to 64b2d10 Compare April 17, 2026 11:22
Copy link
Copy Markdown
Owner

@edmundhung edmundhung left a comment

Choose a reason for hiding this comment

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

Love it! Thanks for working on this 👍🏼

Comment thread packages/conform-dom/util.ts Outdated
Comment on lines +132 to +134
if (patterns.some((p) => p.flags.replace(/[uv]/g, ''))) {
return undefined;
}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I would suggest making it best-effort, so remaining valid regex should still be used to generate a HTML pattern string.

I also wonder if we should validate the regex manually using the v flag, like this:

try {
  new RegExp(pattern, 'v');
  return true;
} catch {
  return false;
}

What do you think?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I looked into the unsupported flags a bit more. From what I can tell, we can safely drop all of them without reducing the validity of the pattern, the only exception being i.

However, /a/i and /[aA]/ describe the same grammar, and similarly we can map /[a-z]/i to /[a-zA-Z]/ to make the regex flagless. It looks feasible to map all i-flagged regexes to flagless regexes.

I think validity checks like the one you showed are reasonable to do, but I think tests are a more suitable environment for this code. Runtime verification makes Conform pay a runtime cost, as it would load a new RegExp object into memory and compile the pattern to a finite-state machine, when all it needed to do was to combine the input patterns.

Is it at all possible to enter the catch case? Given that the inputs to combinePatterns are RegExp objects with valid patterns, and we're placing them in isolated slots using (?:...), it couldn't possibly yield an unparseable regex, can it?

Comment thread packages/conform-valibot/constraint.ts Outdated
Comment thread packages/conform-zod/default/constraint.ts
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.

2 participants