Overview of magic-regexp
mainRegExp objects.repository·main·Indexed 26 days ago
https://github.com/unjs/magic-regexpA type-safe, readable alternative to standard Regular Expressions that uses a natural language API. It features a build-time transform to compile patterns into pure RegExp objects for zero runtime overhead, automatic typing for capture groups, and a zero-dependency runtime. Supports integration with Nuxt, Vite, Webpack, and Rollup.
RegExp objects.RegExp at build time.RegExp is displayed on hover in supported editors.You can optionally enable the included transform to allow for zero-runtime usage. This is done by adding the appropriate plugin to your build tool configuration.
// Nuxt 3
import { defineNuxtConfig } from 'nuxt'
export default defineNuxtConfig({
// This will also enable auto-imports of magic-regexp helpers
modules: ['magic-regexp/nuxt'],
})import { MagicRegExpTransformPlugin } from 'magic-regexp/transform'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [MagicRegExpTransformPlugin.vite()],
})// or, if using next.config.js
// const { MagicRegExpTransformPlugin } = require('magic-regexp/transform')
import { MagicRegExpTransformPlugin } from 'magic-regexp/transform'
export default {
webpack(config) {
config.plugins = config.plugins || []
config.plugins.push(MagicRegExpTransformPlugin.webpack())
return config
},
}import { MagicRegExpTransformPlugin } from 'magic-regexp/transform'
// unbuild
import { defineBuildConfig } from 'unbuild'
export default defineBuildConfig({
hooks: {
'rollup:options': (options, config) => {
config.plugins.push(MagicRegExpTransformPlugin.rollup())
},
},
})You can use the convert function from magic-regexp/converter to transform standard JavaScript regular expressions into magic-regexp syntax. This is useful for migrating existing regex patterns to the more readable magic-regexp API.
Note: This feature is currently marked as experimental.
import { convert } from 'magic-regexp/converter'
convert(/[abc]/)
// createRegExp(exactly('a').or('b').or('c'))
convert(/(foo)bar\d+/)
// createRegExp(exactly('foo').grouped(), 'bar', oneOrMore(digit))If you use external variables inside a createRegExp call, the expression will not be statically compiled into a RegExp. While the code will still function using a minimal runtime, you will lose the performance benefits of the build-time transform.
Example of non-compilable code:
const someString = 'test'
const regExp = createRegExp(exactly(someString))You can obtain type-level results of a RegExp match or replace in string literals using an experimental feature. This allows you to know the exact types of matched groups, the index, and the length at compile time.
To use this feature, you must import helpers from the magic-regexp/further-magic subpath instead of the standard magic-regexp entry point.
Key Behaviors:
'foo'), the result type will reflect the exact content and structure (e.g., ['foo', 'foo']).null (e.g., ["bar", "bar"] | ["foo", "foo"] | null).To contribute to magic-regexp, follow these steps to set up your local development environment:
corepack enable.pnpm install.pnpm dev.corepack enable
pnpm install
pnpm devYou can inspect the RegExp being constructed in two ways:
.toString() on any Input object to see the generated pattern string at runtime.magic-regexp, first install the package using your preferred package manager:The most efficient way to use magic-regexp is through its build-time transform. By using createRegExp with helpers, the library can statically compile your expression into a standard RegExp at build time, avoiding runtime overhead.
Important Constraint: To enable static compilation, you must include all magic-regexp helpers directly within the createRegExp block. You cannot rely on external variables inside the block if you want the expression to be statically compiled.
const beforeTransform = createRegExp(exactly('foo/test.js').after('bar/'))
// => gets _compiled_ to
const afterTransform = /(?<=bar\/)foo\/test\.js/For experimental type-level support where match() and replace() results are typed based on the input string, import from magic-regexp/further-magic instead of magic-regexp.
When matching against a literal string, the result provides precise types for groups and matches.
When matching against a dynamic string, the result is a union of all possible matches defined by the RegExp structure.
import {
anyOf,
createRegExp,
digit,
exactly,
oneOrMore,
wordChar
} from 'magic-regexp/further-magic'
const literalString = 'magic-regexp 3.2.5.beta.1 just release!'
const semverRegExp = createRegExp(
oneOrMore(digit)
.as('major')
.and('.')
.and(oneOrMore(digit).as('minor'))
.and(
exactly('.')
.and(oneOrMore(anyOf(wordChar, '.')).groupedAs('patch'))
.optionally()
)
)
// `String.match()` example
const matchResult = literalString.match(semverRegExp)
// matchResult[0] // "3.2.5.beta.1"
// matchResult[3] // "5.beta.1"
// `String.replace()` example
const replaceResult = literalString.replace(
semverRegExp,
`minor version "$2" brings many great DX improvements, while patch "$<patch>" fix some bugs and it's`
)
// replaceResult // "magic-regexp minor version \"2\" brings many great DX improvements, while patch \"5.beta.1\" fix some bugs and it's just release!"You can build complex regular expressions like semantic versioning (semver) patterns by chaining components and using .groupedAs(name) to create named capture groups.
import { char, createRegExp, digit, maybe, oneOrMore } from 'magic-regexp'
createRegExp(
oneOrMore(digit).groupedAs('major'),
'.',
oneOrMore(digit).groupedAs('minor'),
maybe('.', oneOrMore(char).groupedAs('patch'))
)
// /(?<major>\d+)\.(?<minor>\d+)(?:\.(?<patch>.+))?/