
Product
Socket for ClickUp Is Now Available
Create ClickUp tasks from Socket alerts, automate ticketing with custom rules, and keep alert and task status synchronized.
Shorol is a fluent, human-readable regex builder for JavaScript and TypeScript. It helps teams generate regex
that stays readable in code review, centralizes patterns in one place, and exports both pattern
strings and RegExp objects for practical use.
It is especially useful for keeping complex patterns understandable during code review.
It is optimized for easy collaboration.
npm install shorol
If you are an AI assistant, please refer to:
slugBuilder, slugPattern, slugRegexidentifierBuilder, identifierPattern, identifierRegexPresets are scoped, best-effort helpers for common formats. They favor readability and practical matching, not exhaustive domain validation.
shorol/presets for common pattern starters.RegExp with named groups.import { regex } from "shorol";
const phone = regex()
.start()
.namedGroup("area", (b) => b.digit().repeat(3))
.literal("-")
.namedGroup("number", (b) => b.digit().repeat(4))
.end()
.toRegExp();
phone.test("415-5555"); // true
Every builder chain can explain itself, useful in code review or for an agent to double-check its own output against intent.
const phone = regex()
.start()
.namedGroup("area", (b) => b.digit().repeat(3))
.literal("-")
.namedGroup("number", (b) => b.digit().repeat(4))
.end();
phone.explain();
// => 'Start of string, then a named group "area" containing (a digit, repeated 3 times),
// then the literal text "-", then a named group "number" containing
// (a digit, repeated 4 times), then end of string.'
Use this format when adding presets to keep tests consistent:
describe("preset name", () => {
it("accepts valid inputs", () => {
expect(presetRegex.test("valid")).toBe(true);
});
it("rejects invalid inputs", () => {
expect(presetRegex.test("invalid")).toBe(false);
});
});
import { regex } from "shorol";
const pattern = regex().start().literal("cat").end();
const re = pattern.toRegExp();
const re = regex()
.group((b) => b.literal("cat").orLiteral("dog"))
.whitespace()
.word()
.oneOrMore()
.toRegExp("i");
const pattern = regex().literal("yes").orLiteral("no").toString();
const slug = regex()
.anyOf("abcdefghijklmnopqrstuvwxyz0123456789")
.oneOrMore()
.toRegExp("i");
const noSpaces = regex()
.start()
.noneOf(" \t\n\r")
.oneOrMore()
.end()
.toRegExp();
const lowerAZ = regex().range("a", "z").oneOrMore().toRegExp();
const password = regex()
.lookahead((b) => b.any().oneOrMore().digit())
.lookahead((b) => b.any().oneOrMore().anyOf("!@#$"))
.any()
.oneOrMore()
.toRegExp();
const quoted = regex()
.namedGroup("value", (b) => b.noneOf("\"").oneOrMore())
.toRegExp();
const uuidV4 = regex()
.start()
.anyOf("0123456789abcdef").repeat(8)
.literal("-")
.anyOf("0123456789abcdef").repeat(4)
.literal("-")
.literal("4")
.anyOf("0123456789abcdef").repeat(3)
.literal("-")
.anyOf("89ab")
.anyOf("0123456789abcdef").repeat(3)
.literal("-")
.anyOf("0123456789abcdef").repeat(12)
.end()
.toRegExp("i");
const username = regex()
.start()
.anyOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_")
.repeat(3, 30)
.end()
.toRegExp();
YYYY-MM-DD shape)const isoDate = regex()
.start()
.digit().repeat(4)
.literal("-")
.digit().repeat(2)
.literal("-")
.digit().repeat(2)
.end()
.toRegExp();
const re = regex()
.namedGroup("area", (b) => b.digit().repeat(3))
.literal("-")
.namedGroup("number", (b) => b.digit().repeat(4))
.toRegExp();
import { slugRegex, identifierPattern } from "shorol";
slugRegex.test("my-post-slug"); // true
const identifier = new RegExp(identifierPattern);
regex(): Builderstart() / end()literal(text: string)anyOf(chars: string | string[]) / noneOf(chars: string | string[]) / range(from: string, to: string)any() / digit() / word() / whitespace()wordBoundary() / nonWordBoundary()space() / lineBreak() / tab()group(fn) / namedGroup(name, fn) / nonCapture(fn)lookahead(fn) / negativeLookahead(fn) / lookbehind(fn) / negativeLookbehind(fn)or(fn) / orLiteral(text)optional() / zeroOrMore() / oneOrMore() / repeat(min, max?)global() / ignoreCase() / multiline() / dotAll() / unicode()flags(flags: string) / toString() / toRegExp(flags?)matches(input: string, flags?: string)clone()explain()Shorol is designed to keep regex readable for humans. To make AI- and human-generated regex easy to review:
src/regexes.ts.src/presets.ts.RegExp.*Basic when intentionally non-exhaustive).src/regexes.ts.src/index.ts if it should be public.src/regexes.test.ts.Example registry entry:
export const slugBuilder = () =>
regex()
.start()
.word()
.oneOrMore()
.nonCapture((b) => b.literal("-").word().oneOrMore())
.zeroOrMore()
.end();
export const slugPattern = slugBuilder().toString();
export const slugRegex = slugBuilder().toRegExp();
Releases are automated via GitHub Actions and semantic-release on merges to main.
This project follows Conventional Commits to automate releases.
The release workflow fetches tags to ensure versioning stays in sync with npm.
MIT. See LICENSE.
FAQs
Fluent, human-readable regex builder for JavaScript/TypeScript.
We found that shorol demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Product
Create ClickUp tasks from Socket alerts, automate ticketing with custom rules, and keep alert and task status synchronized.

Product
Create and manage Asana tasks directly from Socket alerts, with manual task creation, automated ticketing rules, and two-way sync.

Security News
Open VSX has removed three extension IDs from its malicious-extension list as the legitimate publishers they impersonated move to claim the names for themselves.