Skip to content

feat: serialize RegExp objects over RPC#225

Open
dimitropoulos wants to merge 1 commit into
mainfrom
feat/serialize-regexp
Open

feat: serialize RegExp objects over RPC#225
dimitropoulos wants to merge 1 commit into
mainfrom
feat/serialize-regexp

Conversation

@dimitropoulos

@dimitropoulos dimitropoulos commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Adds by-value serialization for RegExp, aligning with Cloudflare Workers RPC structured-clonable type support.

Wire format: ["regexp", source, flags] (flags is always present, empty string when none).

From what I can tell, capnweb-validate already supports RegExp.

Based on the RegExp portion of the prior work in #99 (credit to @lmaccherone).

Closes #222.

Copilot AI review requested due to automatic review settings July 27, 2026 01:29
@changeset-bot

changeset-bot Bot commented Jul 27, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4ec4f99

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

This PR includes changesets to release 1 package
Name Type
capnweb 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

pkg-pr-new Bot commented Jul 27, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/capnweb@225

commit: 4ec4f99

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I'm Bonk, and I've done a quick review of your PR.

Adds by-value ["regexp", source, flags] serialization for RegExp, mirroring the existing Date handling.

Issue (high severity): RegExp round-trip is broken at the structuredClonable encoding level.

The Devaluator passes a native RegExp through unencoded when encodingLevel === "structuredClonable" (src/serialize.ts:340-341), exactly like Date (src/serialize.ts:331-332). But the Evaluator's structuredClonable passthrough (src/serialize.ts:818-822) only accepts raw Date and bigint values:

if (this.encodingLevel === "structuredClonable") {
  if (value instanceof Date || typeof value === "bigint") {
    return value;
  }
}

A raw RegExp is not an Array, so it never reaches the case "regexp" tuple decoder you added. Instead it falls through to the generic value instanceof Object branch (src/serialize.ts:1248), which iterates enumerable own properties and returns a plain object. Since RegExp has no enumerable own properties, an incoming RegExp at this level is silently corrupted into {} — the value is lost, not round-tripped.

This is exactly the path the PR targets ("aligning with Cloudflare Workers RPC structured-clonable type support"), and it isn't covered by tests: SERIALIZE_TEST_CASES only exercises the default serialize/deserialize (tuple) path, never structuredClonable.

Fix: mirror Date in the Evaluator passthrough at src/serialize.ts:819 (that unchanged line is outside this diff, so I can't attach the suggestion directly there):

if (value instanceof Date || value instanceof RegExp || typeof value === "bigint") {
  return value;
}

Also please add a structuredClonable-level round-trip test for RegExp so this path is covered.

Minor note: flags normalizes flag order (re.flags is sorted), so /x/mi round-trips as "im". That's harmless (equivalent semantics) and worth a mention only if strict flag-string preservation matters.

Comment thread src/serialize.ts
case "regexp":
if (value.length === 3 && typeof value[1] === "string" &&
typeof value[2] === "string") {
return new RegExp(value[1], value[2]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This tuple decoder is only reached at non-structuredClonable levels. At structuredClonable level the value arrives as a raw RegExp (emitted by the Devaluator at line 340-341) and never becomes an Array, so it bypasses this case and is mangled into {} by the generic object path (line 1248). The corresponding fix is in the passthrough block at line 819:

if (value instanceof Date || value instanceof RegExp || typeof value === "bigint") {
  return value;
}

@ask-bonk

ask-bonk Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review posted successfully to PR #225.

I reviewed PR #225 (feat: serialize RegExp objects over RPC) and found one high-severity issue: the RegExp round-trip is broken at the structuredClonable encoding level. The Devaluator emits a raw RegExp there (mirroring Date), but the Evaluator's passthrough only whitelists Date and bigint, so an incoming RegExp gets mangled into an empty plain object {}. This is the exact path the PR aims to support (Cloudflare Workers RPC alignment) and is untested. I posted the review with a concrete fix and a request to add a structuredClonable-level round-trip test.

github run

Closes #222. Adds by-value serialization for RegExp, aligning with
Cloudflare Workers RPC structured-clonable type support.

Based on the RegExp portion of the prior work in #99.

Co-authored-by: Larry Maccherone <927864+lmaccherone@users.noreply.github.com>
@dimitropoulos
dimitropoulos force-pushed the feat/serialize-regexp branch from b4d9912 to 4ec4f99 Compare July 27, 2026 01:33

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds first-class RPC support for RegExp values, matching Cloudflare Workers’ structured-clonable type support and documenting the new wire encoding.

Changes:

  • Introduces a new regexp RPC kind and corresponding (de)serialization logic using ["regexp", source, flags].
  • Extends core payload handling to treat RegExp as an immutable/pass-by-value type in relevant traversal/copy/dispose paths.
  • Updates docs (README + protocol) and adds round-trip tests for RegExp.

Reviewed changes

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

Show a summary per file
File Description
src/serialize.ts Adds RegExp tuple encoding/decoding and structured-clonable passthrough handling.
src/core.ts Adds regexp to RPC type classification and payload traversal/copy/dispose switch cases.
README.md Moves RegExp into the supported pass-by-value types list.
protocol.md Documents the ["regexp", source, flags] wire format with an example.
.changeset/serialize-regexp.md Declares a minor release for the new serialization capability.
tests/index.test.ts Adds serialize/deserialize round-trip cases for RegExp.

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

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.

support RegExp serialization type

2 participants