Skip to content

Add regex and IPv4 CIDR range functions#13

Merged
Sander-Toonen merged 1 commit into
mainfrom
feat/regex-and-ip-range-functions
Jun 22, 2026
Merged

Add regex and IPv4 CIDR range functions#13
Sander-Toonen merged 1 commit into
mainfrom
feat/regex-and-ip-range-functions

Conversation

@Sander-Toonen

Copy link
Copy Markdown
Contributor

Summary

Adds four dependency-free built-in functions to @pro-fa/expreszo and bumps the package to 0.6.6.

Function Category Description
regexMatches(str, pattern, flags?) string true/false if the string matches the regex
regexExtract(str, pattern, flags?) string first match — full match, or capture-group array when the pattern has groups; undefined if no match
regexReplace(str, pattern, replacement, flags?) string regex replace (defaults to a global replace)
ipInRange(ip, cidr) utility true if the IPv4 address is inside the CIDR block; native 32-bit math, IPv4 only

All four are pure: true, safe: true, sync, and add no new dependencies.

Implementation notes

  • New impls: functions/string/regex.ts, functions/utility/network.ts.
  • Registered in the builtin catalog (registry/builtin/functions.ts + function-docs.ts) and the legacy runtime Parser.functions map (parsing/parser.ts) — a parity test enforces the two stay in lock-step.
  • The language service (completions/hover/signature help) and the MCP server source functions dynamically from the registry, so they pick these up automatically — no code changes needed there.

Caveats

  • Escaping: the string lexer rejects unknown escape sequences, so backslash classes must be written "\d" in expression source; character classes like "[0-9]" need no escaping. Documented in docs/syntax.md and the sample.
  • ReDoS: a caller-supplied regex in an untrusted expression can trigger catastrophic backtracking. Documented in code and docs; not mitigated (no dep added).

Docs & samples

  • docs/syntax.md: new Regular Expressions subsection + ipInRange in the Utility table + examples.
  • docs/quick-reference.md: regex rows and a Network Functions section.
  • samples/language-service-sample/examples.js: a "Regex & IP Range Functions" example.

Testing

  • New tests: test/functions/functions-regex.ts, test/functions/functions-network.ts.
  • Full suite: 2244 passing; coverage 86%+ (above the 80% gate), regex.ts 100% lines.
  • mcp-server tests: 12/12 pass.
  • Type-check and lint clean.

🤖 Generated with Claude Code

Add four dependency-free built-ins to @pro-fa/expreszo:

- regexMatches(str, pattern, flags?) — boolean match test
- regexExtract(str, pattern, flags?) — first match or capture groups
- regexReplace(str, pattern, replacement, flags?) — regex replace (defaults to global)
- ipInRange(ip, cidr) — IPv4 CIDR membership via native 32-bit math

Wired into the registry, runtime parser functions map, and builtin docs;
the language service and MCP server pick them up automatically. Updates the
docs (syntax + quick reference) and adds a language-service sample entry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 22, 2026 13:04
@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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

This PR adds four new dependency-free built-in functions to @pro-fa/expreszo—three regex helpers and an IPv4 CIDR membership check—then wires them into the built-in function registry, legacy Parser.functions map, docs, samples, and tests, along with a package version bump.

Changes:

  • Add regexMatches, regexExtract, regexReplace (string) and ipInRange (utility) implementations and export them through the functions barrels.
  • Register the new built-ins in the descriptor registry and legacy parser function map; add language-service sample usage.
  • Add documentation and introduce new TypeScript tests for regex and network functionality; bump package version to 0.6.6.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
samples/language-service-sample/examples.js Adds a sample showcasing the new regex and CIDR functions in the language-service demo.
packages/expreszo/test/functions/functions-regex.ts Adds test coverage for the new regex built-in functions.
packages/expreszo/test/functions/functions-network.ts Adds test coverage for the new ipInRange built-in function.
packages/expreszo/src/registry/builtin/functions.ts Registers the new built-ins in the function descriptor catalog.
packages/expreszo/src/registry/builtin/function-docs.ts Adds language-service docs metadata for the new functions.
packages/expreszo/src/parsing/parser.ts Adds the new functions to the legacy Parser.functions registry for parity.
packages/expreszo/src/functions/utility/network.ts Implements ipInRange and IPv4 parsing logic.
packages/expreszo/src/functions/utility/index.ts Re-exports the new utility/network functions.
packages/expreszo/src/functions/string/regex.ts Implements regex match/extract/replace built-ins.
packages/expreszo/src/functions/string/index.ts Re-exports the new string/regex functions.
packages/expreszo/package.json Bumps @pro-fa/expreszo version to 0.6.6.
docs/syntax.md Documents regex functions and ipInRange, plus adds examples and caveats.
docs/quick-reference.md Adds quick-reference entries for regex functions and a network section for ipInRange.

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

Comment on lines +70 to +73
const match = str.match(compile('regexExtract', pattern, flags));
if (match === null) {
return undefined;
}
Comment thread docs/syntax.md
| if(c, a, b) | Function form of c ? a : b. Uses lazy evaluation: only the matching branch is evaluated. |
| coalesce(a, b, ...) | Returns the first non-null and non-empty string value from the arguments. Numbers and booleans (including 0 and false) are considered valid values. |
| json(value) | Converts a value to a JSON string representation. |
| ipInRange(ip, cidr) | Returns `true` if the IPv4 address `ip` falls within the CIDR block `cidr` (e.g. `"10.0.0.0/8"`), `false` otherwise. IPv4 only. |
Comment on lines +19 to +20
// Reject empty, signs, whitespace, and non-numeric octets; require a plain
// decimal integer 0–255 with no leading-zero ambiguity beyond "0".
Comment on lines +52 to +70
describe('regexExtract(str, pattern, flags?)', function () {
it('should return the full match when there are no capture groups', function () {
const parser = new Parser();
assert.strictEqual(parser.evaluate('regexExtract("abc123def", "[0-9]+")'), '123');
});

it('should return capture groups as an array when present', function () {
const parser = new Parser();
assert.deepStrictEqual(parser.evaluate('regexExtract("user-42", "user-([0-9]+)")'), ['42']);
assert.deepStrictEqual(
parser.evaluate('regexExtract("2026-06-22", "([0-9]+)-([0-9]+)-([0-9]+)")'),
['2026', '06', '22']
);
});

it('should return undefined when there is no match', function () {
const parser = new Parser();
assert.strictEqual(parser.evaluate('regexExtract("abc", "[0-9]+")'), undefined);
});
@Sander-Toonen Sander-Toonen merged commit bd072de into main Jun 22, 2026
10 checks passed
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