Socket
Socket
Sign inDemoInstall

type-level-regexp

Package Overview
Dependencies
0
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    type-level-regexp

Type-Level RegExp parser, matcher and permutation resolver


Version published
Weekly downloads
26K
decreased by-0.95%
Maintainers
1
Install size
88.9 kB
Created
Weekly downloads
 

Readme

Source

🔤🔍 Type-Level RegExp (WIP)

npm version

TypeScript type-level RegExp parser and matcher implemented using template literals.

Demo

Open in Codeflow

👉 Try on TypeScript Playground or see examples in Playground and test folders.

🚧 Work In Progress, PRs and issues are welcome 🚧

Quick Setup

  1. Add type-level-regexp dependency to your project
# Using pnpm
pnpm i -D type-level-regexp

# Using npm
npm i -D type-level-regexp
  1. Import createRegExp function, pass in a RegExp string pattern to it creates a TypedRegExp, passing this TypedRegExp to String.match(), String.matchAll() or String.replace() functions to get fully typed match result.

Basic Usage

match result will be fully typed if match against a literal stirng, or shows emumerated results if match against a dynamic string.

import { createRegExp, spreadRegExpIterator } from 'type-level-regexp'

/** string.match() */
const regExp = createRegExp('foO(?<g1>b[a-g]r)(?:BAz|(?<g2>qux))', ['i'])
const matchResult = 'prefix foobarbaz suffix'.match(regExp) // matching literal string
matchResult[0] // 'foobarbaz'
matchResult[1] // 'bar'
matchResult[3] // show type error `type '3' can't be used to index type 'RegExpMatchResult<...>`
matchResult.length // 3
matchResult.index // 7
matchResult.groups // { g1: "bar"; g2: undefined; }

/** string.replace() */
const regExp2 = createRegExp('(\\d{4})[-.](?<month>\\w{3,4})[-.](\\d{1,2})')
const replaceResult = '1991-Sept-15'.replace(regExp2, '$<month> $3, $1')
replaceResult // 'Sept 15, 1991'

/** string.matchAll() */
const regExp3 = createRegExp('c[a-z]{2}', ['g'])
const matchALlIterator = 'cat car caw cay caw cay'.matchAll(regExp3)
const spreadedResult = spreadRegExpIterator(matchALlIterator)
spreadedResult[2][0] // 'caw'
spreadedResult[3].index // 12

const InvalidRegExp = createRegExp('foo(bar')
// TypeScript error: Argument of type 'string' is not assignable to parameter of type 'RegExpSyntaxError<"Invalid regular expression, missing closing \`)\`">'

For TypeScript library authors, you can also import individual generic types to parse and match RegExp string at type-level and combine with your library's type-level features.

import { ParseRegExp, MatchRegExp } from 'type-level-regexp'

type MatchResult = MatchRegExp<'fooBAR42', ParseRegExp<'Fo[a-z](Bar)\\d{2}'>, 'i'>

type Matched = MatchResult[0] // 'fooBAR42'
type First = MatchResult[1] // 'BAR'

type RegExpAST = ParseRegExp<'foo(?<g1>bar)'>
// [{
//     type: "string";
//     value: "foo";
// }, {
//     type: "namedCapture";
//     name: "g1";
//     value: [{
//         type: "string";
//         value: "bar";
//     }];
// }]

Origin & Notice

The main purpose of this project is to test and demonstrate the possibility and limitations of writing a RegExp parser/matcher in TypeScript's type-level. Note that this may not be practically useful, but rather an interesting showcase.

The idea for this project originated while I was working on improving the type hints of string.match and replace in magic-regexp (created by the most inspiring, resourceful, and kind Daniel Roe from Nuxt, definitely check it out if you are working with RegExp and TypeScript!).

As the complexity grows, I start working on this separated repo to increase development speed and try out different iterations. It will be incorporate and use in magic-regexp, and Gabriel Vergnaud's awesome hotscript very soon.

❤️ Testing, feedbacks and PRs are welcome!

Features

  • Export createRegExp function to create aTypedRegExp that replace your original /regex_pattern/ regex object, which can be pass to String.match(), String.matchAll() and String.replace() functions and gets fully typed result.
  • Shows RegExpSyntaxError if the provided RegExp pattern is invalid.
  • Enhance types of RegExp related String functions (.match, matchAll, .replace...) for literal or dynamic typed string.
  • Result of String functions matched exactly as runtime result.
  • Support all common RegExp tokens (incl. Lookarounds, Backreferences...etc), quantifiers (incl. greedy/lazy) and (g,i) flags.
  • Export helper functions spreadRegExpMatchArray and spreadRegExpIterator to get tuple type of match results and iterators.
  • Provide generic type ParseRegExp to parse and RegExp string to AST.
  • Provide generic type MatchRegExp to match giving string with a parsed RegExp.
  • Provide generic type ResolvePermutation to permutation all possible matching string of given RegExp if possible (due to TypeScript type-level limitation)
  • More details please try on TypeScript Playground, or see tests files in Tests and Stackblitz. (examples in index.test-d.ts)
Example - type-safe args in replacing function of string.replace()

replaceRegexp

Example - spreaded string.matchAll() with union of RegExp pattern remain as tuple

type-level-matchAll-with-union

RegExp Tokens & Flags

TokensDescriptionSupport
.Matches any single character.
*, *?Matches zero or more occurrences (Greedy/Lazy).
+, *?Matches one or more occurrences (Greedy/Lazy).
?, ??Matches zero or one occurrence (Greedy/Lazy).
^Matches the start of a line.
$Matches the end of a line.
\s, \SMatches any whitespace, non-whitespace character.
\d, \DMatches any digit, non-digit character.
\w, \WMatches any word, non-word character.
\b, \BMatches a word-boundary, non-word-boundary.
[abc]Matches any character in the set.
[^abc]Matches any character not in the set.
()Creates a capturing group.
(?:)Creates a non-capturing group.
(?<name>)Creates a named-capturing group.
|Matches either the expression before or after the vertical bar.
{n}Matches exactly n occurrences.
{n,}Matches at least n occurrences.
{n,m}Matches between n and m occurrences.
(?=), (?!)Positive/Negative lookahead.
(?<=), (?<!)Positive/Negative lookbehind.
FlagsDescriptionSupport
gGlobal matching (matches all occurrences).
iCase-insensitive matching.

💻 Development

  • Clone this repository
  • Enable Corepack using corepack enable (use npm i -g corepack for Node.js < 16.10)
  • Install dependencies using pnpm install
  • Run interactive tests using pnpm dev

License

Made with 🔥 and ❤️

Published under MIT License.

Keywords

FAQs

Last updated on 08 May 2023

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc