Skip to content

Commit f058426

Browse files
authored
docs: add initial documentation site (#14)
1 parent b898740 commit f058426

21 files changed

+6920
-155
lines changed

README.md

Lines changed: 2 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
> A compiled-away, type-safe, readable RegExp alternative
1010
1111
- [ Changelog](https://github.com/danielroe/magic-regexp/blob/main/CHANGELOG.md)
12+
- [📖  Documentation](https://magic-regexp.roe.dev)
1213
- [▶️  Online playground](https://stackblitz.com/github/danielroe/magic-regexp/tree/main/playground)
1314

1415
## Features
@@ -21,159 +22,7 @@
2122
- Packed with useful utilities: `charIn`, `charNotIn`, `anyOf`, `char`, `word`, `digit`, `whitespace`, `letter`, `tab`, `linefeed`, `carriageReturn`, `not`, `maybe`, `exactly`, `oneOrMore`
2223
- All chainable with `and`, `or`, `after`, `before`, `notAfter`, `notBefore`, `times`, `as`, `at`, `optionally`
2324

24-
**Future ideas**
25-
26-
- [ ] More TypeScript guard-rails
27-
- [ ] More complex RegExp features/syntax
28-
- [ ] Instrumentation for accurately getting coverage on RegExps
29-
- [ ] Hybrid/partially-compiled RegExps for better dynamic support
30-
31-
## Setup
32-
33-
Install package:
34-
35-
```sh
36-
# npm
37-
npm install magic-regexp
38-
39-
# yarn
40-
yarn add magic-regexp
41-
42-
# pnpm
43-
pnpm install magic-regexp
44-
```
45-
46-
```js
47-
import { createRegExp, exactly } from 'magic-regexp'
48-
49-
const regExp = createRegExp(exactly('foo/test.js').after('bar/'))
50-
console.log(regExp)
51-
52-
// /(?<=bar\/)foo\/test\.js/
53-
```
54-
55-
## Usage
56-
57-
Every pattern you create with the library should be wrapped in `createRegExp`. It also takes a second argument, which is an array of flags.
58-
59-
```js
60-
import { createRegExp, global, multiline } from 'magic-regexp'
61-
createRegExp('string-to-match', [global, multiline])
62-
// you can also pass flags directly as strings
63-
createRegExp('string-to-match', ['g', 'm'])
64-
```
65-
66-
> **Note**
67-
> By default, all helpers from `magic-regexp` assume that input that is passed should be escaped - so no special RegExp characters apply. So `createRegExp('foo?\d')` will not match `food3` but only `foo?\d` exactly.
68-
69-
There are a range of helpers that can be used to activate pattern matching, and they can be chained.
70-
71-
They are:
72-
73-
- `charIn`, `charNotIn` - this matches or doesn't match any character in the string provided.
74-
- `anyOf` - this takes an array of inputs and matches any of them.
75-
- `char`, `word`, `digit`, `whitespace`, `letter`, `tab`, `linefeed` and `carriageReturn` - these are helpers for specific RegExp characters.
76-
- `not` - this can prefix `word`, `digit`, `whitespace`, `letter`, `tab`, `linefeed` or `carriageReturn`. For example `createRegExp(not.letter)`.
77-
- `maybe` - equivalent to `?` - this marks the input as optional.
78-
- `oneOrMore` - equivalent to `+` - this marks the input as repeatable, any number of times but at least once.
79-
- `exactly` - this escapes a string input to match it exactly.
80-
81-
All of these helpers return an object of type `Input` that can be chained with the following helpers:
82-
83-
- `and` - this adds a new pattern to the current input.
84-
- `or` - this provides an alternative to the current input.
85-
- `after`, `before`, `notAfter` and `notBefore` - these activate positive/negative lookahead/lookbehinds. Make sure to check [browser support](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#browser_compatibility) as not all browsers support lookbehinds (notably Safari).
86-
- `times` - this is a function you can call directly to repeat the previous pattern an exact number of times, or you can use `times.between(min, max)` to specify a range, `times.atLeast(num)` to indicate it must repeat x times or `times.any()` to indicate it can repeat any number of times, _including none_.
87-
- `optionally` - this is a function you can call to mark the current input as optional.
88-
- `as` - this defines the entire input so far as a named capture group. You will get type safety when using the resulting RegExp with `String.match()`.
89-
- `at` - this allows you to match beginning/ends of lines with `at.lineStart()` and `at.lineEnd()`.
90-
91-
## Compilation at build
92-
93-
The best way to use `magic-regexp` is by making use of the included transform.
94-
95-
```js
96-
const regExp = createRegExp(exactly('foo/test.js').after('bar/'))
97-
// => gets _compiled_ to
98-
const regExp = /(?<=bar\/)foo\/test\.js/
99-
```
100-
101-
Of course, this only works with non-dynamic regexps. Within the `createRegExp` block you have to include all the helpers you are using from `magic-regexp` - and not rely on any external variables. This, for example, will not statically compile into a RegExp, although it will still continue to work with a minimal runtime:
102-
103-
```js
104-
const someString = 'test'
105-
const regExp = createRegExp(exactly(someString))
106-
```
107-
108-
### Nuxt
109-
110-
```js
111-
import { defineNuxtConfig } from 'nuxt'
112-
113-
// https://v3.nuxtjs.org/api/configuration/nuxt.config
114-
export default defineNuxtConfig({
115-
// This will also enable auto-imports of magic-regexp helpers
116-
modules: ['magic-regexp/nuxt'],
117-
})
118-
```
119-
120-
### Vite
121-
122-
```js
123-
import { defineConfig } from 'vite'
124-
import { MagicRegExpTransformPlugin } from 'magic-regexp/transform'
125-
126-
export default defineConfig({
127-
plugins: [MagicRegExpTransformPlugin.vite()],
128-
})
129-
```
130-
131-
### Next.js
132-
133-
For Next, you will need to ensure you are using `next.config.mjs` or have set `"type": "module"` in your `package.json.
134-
135-
```js
136-
import { MagicRegExpTransformPlugin } from 'magic-regexp/transform'
137-
138-
export default {
139-
webpack(config) {
140-
config.plugins = config.plugins || []
141-
config.plugins.push(MagicRegExpTransformPlugin.webpack())
142-
return config
143-
},
144-
}
145-
```
146-
147-
### unbuild
148-
149-
```js
150-
import { defineBuildConfig } from 'unbuild'
151-
import { MagicRegExpTransformPlugin } from 'magic-regexp/transform'
152-
153-
export default defineBuildConfig({
154-
hooks: {
155-
'rollup:options': (options, config) => {
156-
config.plugins.push(MagicRegExpTransformPlugin.rollup())
157-
},
158-
},
159-
})
160-
```
161-
162-
## Examples
163-
164-
```js
165-
import { createRegExp, exactly, oneOrMore, digit } from 'magic-regexp'
166-
167-
// Quick-and-dirty semver
168-
createRegExp(
169-
oneOrMore(digit)
170-
.as('major')
171-
.and('.')
172-
.and(oneOrMore(digit).as('minor'))
173-
.and(exactly('.').and(oneOrMore(char).as('patch')).optionally())
174-
)
175-
// /(?<major>(\d)+)\.(?<minor>(\d)+)(\.(?<patch>(.)+))?/
176-
```
25+
[📖 &nbsp;Read more](https://magic-regexp.roe.dev)
17726

17827
## 💻 Development
17928

docs/.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Create one with no scope selected on https://github.com/settings/tokens/new
2+
# This token is used for fetching the repository releases.
3+
GITHUB_TOKEN=

docs/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.env
2+
.nuxt
3+
.output

docs/.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
shamefully-hoist=true

docs/components/content/Logo.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<template>
2+
<div class="font-bold flex flex-row items-center gap-2">🦄 magic-regexp</div>
3+
</template>

docs/content/1.index.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
title: 'Welcome'
3+
description: 'A compiled-away, type-safe, readable RegExp alternative'
4+
layout: fluid
5+
navigation: false
6+
---
7+
8+
::block-hero
9+
---
10+
cta:
11+
- Get Started
12+
- /getting-started/setup
13+
secondary:
14+
- Star on GitHub
15+
- https://github.com/danielroe/magic-regexp
16+
snippet: npm install magic-regexp
17+
---
18+
19+
20+
#title
21+
🦄 magic-regexp
22+
23+
#description
24+
A compiled-away, type-safe, readable RegExp alternative.
25+
26+
#extra
27+
28+
::list
29+
30+
- Runtime is zero-dependency and ultra-minimal
31+
- Ships with transform to compile to pure RegExp
32+
- Automatically typed capture groups
33+
- Natural language syntax
34+
- Generated RegExp displays on hover
35+
36+
::
37+
::
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
---
2+
title: Setup
3+
description: Install magic-regexp from npm and (optionally) enable the build-time transform via a plugin.
4+
---
5+
6+
First, install `magic-regexp`:
7+
8+
::code-group
9+
10+
```sh [npm]
11+
npm install magic-regexp
12+
```
13+
14+
```sh [yarn]
15+
yarn add magic-regexp
16+
```
17+
18+
```sh [pnpm]
19+
pnpm install magic-regexp
20+
```
21+
22+
::
23+
24+
---
25+
26+
Second, optionally, you can enable the included transform, [which enables zero-runtime usage](/getting-started/usage#build-time-transform).
27+
28+
::code-group
29+
30+
```js [nuxt.config.ts]
31+
// Nuxt 3
32+
import { defineNuxtConfig } from 'nuxt'
33+
34+
export default defineNuxtConfig({
35+
// This will also enable auto-imports of magic-regexp helpers
36+
modules: ['magic-regexp/nuxt'],
37+
})
38+
```
39+
40+
```js [vite.config.ts]
41+
// For Vite, you will need to ensure you are using `vite.config.mjs`
42+
// or have set `"type": "module"` in your `package.json.
43+
import { defineConfig } from 'vite'
44+
import { MagicRegExpTransformPlugin } from 'magic-regexp/transform'
45+
46+
export default defineConfig({
47+
plugins: [MagicRegExpTransformPlugin.vite()],
48+
})
49+
```
50+
51+
```js [next.config.mjs]
52+
// For Next, you will need to ensure you are using `next.config.mjs`
53+
// or have set `"type": "module"` in your `package.json.
54+
import { MagicRegExpTransformPlugin } from 'magic-regexp/transform'
55+
56+
export default {
57+
webpack(config) {
58+
config.plugins = config.plugins || []
59+
config.plugins.push(MagicRegExpTransformPlugin.webpack())
60+
return config
61+
},
62+
}
63+
```
64+
65+
::
66+
67+
<!--
68+
TODO: https://github.com/unjs/unbuild/issues/92
69+
```js [build.config.ts ]
70+
// unbuild
71+
import { defineBuildConfig } from 'unbuild'
72+
import { MagicRegExpTransformPlugin } from 'magic-regexp/transform'
73+
74+
export default defineBuildConfig({
75+
hooks: {
76+
'rollup:options': (options, config) => {
77+
config.plugins.push(MagicRegExpTransformPlugin.rollup())
78+
},
79+
},
80+
})
81+
``` -->
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
title: Usage
3+
---
4+
5+
```js
6+
import { createRegExp, exactly } from 'magic-regexp'
7+
8+
const regExp = createRegExp(exactly('foo/test.js').after('bar/'))
9+
console.log(regExp)
10+
11+
// /(?<=bar\/)foo\/test\.js/
12+
```
13+
14+
## createRegExp
15+
16+
Every pattern you create with the library should be wrapped in `createRegExp`, which enables the build-time transform.
17+
18+
The first argument is either a string to match exactly, or an input pattern built up using helpers from `magic-regexp`. It also takes a second argument, which is an array of flags or flags string.
19+
20+
```js
21+
import { createRegExp, global, multiline, exactly } from 'magic-regexp'
22+
23+
createRegExp(exactly('foo').or('bar'))
24+
25+
createRegExp('string-to-match', [global, multiline])
26+
// you can also pass flags directly as strings or Sets
27+
createRegExp('string-to-match', ['g', 'm'])
28+
```
29+
30+
::alert
31+
By default, all helpers from `magic-regexp` assume that input that is passed should be escaped - so no special RegExp characters apply. So `createRegExp('foo?\d')` will not match `food3` but only `foo?\d` exactly.
32+
::
33+
34+
## Creating inputs
35+
36+
There are a range of helpers that can be used to activate pattern matching, and they can be chained. Each one of these returns an object of type `Input` that can be passed directly to `new RegExp`, `createRegExp`, to another helper or chained to produce more complex patterns.
37+
38+
| | |
39+
| --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
40+
| `charIn`, `charNotIn` | this matches or doesn't match any character in the string provided. |
41+
| `anyOf` | this takes an array of inputs and matches any of them. |
42+
| `char`, `word`, `digit`, `whitespace`, `letter`, `tab`, `linefeed` and `carriageReturn` | these are helpers for specific RegExp characters. |
43+
| `not` | this can prefix `word`, `digit`, `whitespace`, `letter`, `tab`, `linefeed` or `carriageReturn`. For example `createRegExp(not.letter)`. |
44+
| `maybe` | equivalent to `?` - this marks the input as optional. |
45+
| `oneOrMore` | Equivalent to `+` - this marks the input as repeatable, any number of times but at least once. |
46+
| `exactly` | This escapes a string input to match it exactly. |
47+
48+
## Chaining inputs
49+
50+
All of the helpers above return an object of type `Input` that can be chained with the following helpers:
51+
52+
| | |
53+
| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
54+
| `and` | this adds a new pattern to the current input. |
55+
| `or` | this provides an alternative to the current input. |
56+
| `after`, `before`, `notAfter` and `notBefore` | these activate positive/negative lookahead/lookbehinds. Make sure to check [browser support](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#browser_compatibility) as not all browsers support lookbehinds (notably Safari). |
57+
| `times` | this is a function you can call directly to repeat the previous pattern an exact number of times, or you can use `times.between(min, max)` to specify a range, `times.atLeast(num)` to indicate it must repeat x times or `times.any()` to indicate it can repeat any number of times, _including none_. |
58+
| `optionally` | this is a function you can call to mark the current input as optional. |
59+
| `as` | this defines the entire input so far as a named capture group. You will get type safety when using the resulting RegExp with `String.match()`. |
60+
| `at` | this allows you to match beginning/ends of lines with `at.lineStart()` and `at.lineEnd()`. |
61+
62+
## Debugging
63+
64+
When using `magic-regexp`, a TypeScript generic is generated for you that should show the RegExp that you are constructing, as you go.
65+
66+
This is true not just for the final RegExp, but also for the pieces you create along the way.
67+
68+
So, for example:
69+
70+
```ts
71+
import { exactly } from 'magic-regexp'
72+
73+
exactly('test.mjs')
74+
// (alias) exactly<"test.mjs">(input: "test.mjs"): Input<"test\\.mjs", never>
75+
76+
exactly('test.mjs').or('something.else')
77+
// (property) Input<"test\\.mjs", never>.or: <"something.else">(input: "something.else") => Input<"(test\\.mjs|something\\.else)", never>
78+
```
79+
80+
Each function, if you hover over it, shows what's going in, and what's coming out by way of regular expression
81+
82+
You can also call `.toString()` on any input to see the same information at runtime.

0 commit comments

Comments
 (0)