Skip to content

feat: allow custom regexp engine via RegexpCompiler option #72

@satisataka

Description

@satisataka

Is your feature request related to a problem? Please describe.

The doc.go already acknowledges that Go's regexp package differs from ECMA 262 (no back-references, no lookahead/lookbehind). This is documented under "Deviations from the specification" with a link to the regexp2 comparison table.

Currently, there is no way to plug in an alternative regexp engine. Users working with schemas that use PCRE-specific features (e.g., (?=...) lookahead in pattern or patternProperties) cannot validate them correctly.

Describe the solution you'd like

Add a RegexpCompiler option to ResolveOptions that allows users to provide a custom regexp compiler. The default behavior remains unchanged (Go's regexp.Compile).

The proposed API:

// A Regexp is a compiled regular expression.
type Regexp interface {
    MatchString(s string) bool
}

// A RegexpCompiler compiles a regular expression pattern string into a Regexp.
type RegexpCompiler func(pattern string) (Regexp, error)

type ResolveOptions struct {
    // ... existing fields ...
    
    // RegexpCompiler compiles regular expression patterns used in "pattern" and
    // "patternProperties" keywords. If nil, Go's regexp.Compile is used.
    RegexpCompiler RegexpCompiler
}

Usage with regexp2 (note: regexp2.MatchString returns (bool, error), so an adapter is needed):

import "github.com/dlclark/regexp2"

type regexp2Adapter struct {
    re *regexp2.Regexp
}

func (r regexp2Adapter) MatchString(s string) bool {
    ok, err := r.re.MatchString(s)
    return err == nil && ok
}

compiler := func(pattern string) (jsonschema.Regexp, error) {
    re, err := regexp2.Compile(pattern, regexp2.ECMAScript)
    if err != nil {
        return nil, err
    }
    return regexp2Adapter{re: re}, nil
}

resolved, err := schema.Resolve(&jsonschema.ResolveOptions{
    RegexpCompiler: compiler,
})

Implementation details

  • Minimal interface: Regexp requires only MatchString(string) bool, matching the existing validation path and avoiding changes to runtime validation semantics
  • Internal resolvedInfo stores Regexp interface instead of *regexp.Regexp
  • validate.go should require little or no change, since validation already only needs MatchString semantics
  • doc.go "Deviations" section updated to mention the escape hatch
  • Full test coverage: custom compiler for pattern, patternProperties, and error propagation
  • Fully backwards-compatible — nil RegexpCompiler defaults to regexp.Compile

PR: #73

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions