npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

type-level-regexp

v0.1.17

Published

Type-Level RegExp parser, matcher and permutation resolver

Downloads

115,378

Readme

🔤🔍 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

| Tokens | Description | Support | | --- | --- | --- | | . | 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, \S | Matches any whitespace, non-whitespace character. | ✅ | | \d, \D | Matches any digit, non-digit character. | ✅ | | \w, \W | Matches any word, non-word character. | ✅ | | \b, \B | Matches 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. | ✅ |

| Flags | Description | Support | | --- | --- | --- | | g | Global matching (matches all occurrences). | ✅ | | i | Case-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.