Skip to content

Commit 61237f5

Browse files
committed
feat: initial commit
0 parents  commit 61237f5

19 files changed

+8991
-0
lines changed

.eslintignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
coverage/
2+
dist/

.eslintrc

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": [
3+
"@readme/eslint-config",
4+
"@readme/eslint-config/typescript",
5+
"@readme/eslint-config/esm"
6+
],
7+
"root": true
8+
}

.github/dependabot.yml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: github-actions
4+
directory: "/"
5+
schedule:
6+
interval: monthly
7+
reviewers:
8+
- erunion
9+
labels:
10+
- dependencies
11+
commit-message:
12+
prefix: chore(deps)
13+
prefix-development: chore(deps-dev)
14+
15+
- package-ecosystem: npm
16+
directory: "/"
17+
schedule:
18+
interval: monthly
19+
open-pull-requests-limit: 10
20+
reviewers:
21+
- erunion
22+
labels:
23+
- dependencies
24+
groups:
25+
minor-development-deps:
26+
dependency-type: 'development'
27+
update-types:
28+
- minor
29+
- patch

.github/workflows/ci.yml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
node-version:
16+
- lts/-1
17+
- lts/*
18+
- latest
19+
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- name: Use Node.js ${{ matrix.node-version }}
24+
uses: actions/setup-node@v4
25+
with:
26+
node-version: ${{ matrix.node-version }}
27+
28+
- run: npm ci

.github/workflows/codeql-analysis.yml

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: "CodeQL"
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
schedule:
9+
- cron: '0 12 * * 1'
10+
11+
jobs:
12+
analyze:
13+
name: Analyze
14+
runs-on: ubuntu-latest
15+
permissions:
16+
actions: read
17+
contents: read
18+
security-events: write
19+
20+
strategy:
21+
fail-fast: false
22+
matrix:
23+
language: [ 'javascript' ]
24+
25+
steps:
26+
- name: Checkout repository
27+
uses: actions/checkout@v4
28+
29+
- name: Initialize CodeQL
30+
uses: github/codeql-action/init@v3
31+
with:
32+
languages: ${{ matrix.language }}
33+
34+
- name: Perform CodeQL Analysis
35+
uses: github/codeql-action/analyze@v3

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
coverage/
2+
dist/
3+
node_modules/

.npmignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.github/
2+
coverage/
3+
test/
4+
.eslint*
5+
.prettier*

.prettierignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
coverage/
2+
dist/

.vscode/settings.json

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"editor.defaultFormatter": "esbenp.prettier-vscode",
3+
"editor.codeActionsOnSave": {
4+
"source.fixAll": "explicit"
5+
},
6+
"editor.formatOnSave": true,
7+
"search.exclude": {
8+
"coverage": true
9+
}
10+
}

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 ReadMe
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# structured-regex
2+
3+
[![Build](https://github.com/readmeio/structured-regex/workflows/CI/badge.svg)](https://github.com/readmeio/structured-regex/) [![](https://img.shields.io/npm/v/structured-regex)](https://npm.im/structured-regex)
4+
5+
[![](https://raw.githubusercontent.com/readmeio/.github/main/oss-header.png)](https://readme.io)
6+
7+
`structured-regex` is a wrapper for [RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) that allows you to do named group parsing without having to use actually [named capture groups](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Named_capturing_group).
8+
9+
Why not use named capture groups? If you're composing a complicated regex by interpolating other regex patterns into it if any of those patterns contain a named capture that group may either only partially match the pattern they're inserted into, or if their name is reused then the regex will throw an error.
10+
11+
For example on a `/projects/me` URI with a regex to match it of `/projects/(me|${PROJECT_SUBDOMAIN.regex.source})` you can't have `?<subdomain>` inside of the `PROJECT_SUBDOMAIN` regex because `me` wouldn't be placed into our matched `subdomain` group.
12+
13+
`structured-regex` not only allows you to formally define the expected typings of our matches but you can supply it a mapping object to coorelate your named group with the index that it's captured against.
14+
15+
## 📦 Installation
16+
17+
```sh
18+
npm install --save structured-regex
19+
```
20+
21+
## 🧰 Usage
22+
23+
```ts
24+
import { StructuredRegEx } from 'structured-regex';
25+
26+
const SEMVER_REGEX = /([0-9]+)(?:\.([0-9]+))?(?:\.([0-9]+))?(-.*)?/;
27+
const SLUG_REGEX = /[a-z0-9-_ ]+/i;
28+
29+
const VERSION_REGEX = new RegExp(`stable|${SEMVER_REGEX.source}`, 'i');
30+
const API_FILENAME_REGEX = new RegExp(`(${SLUG_REGEX.source}.(json|yaml|yml))`, 'i');
31+
32+
const API_URI_REGEX = new StructuredRegEx<{ filename: string; version: string }>(
33+
new RegExp(`/versions/(${VERSION_REGEX.source})/apis/(${API_FILENAME_REGEX.source})`, 'i'),
34+
{
35+
version: 1,
36+
filename: 6, // `filename` is in the `matches[6]` spot of a valid match
37+
},
38+
);
39+
40+
console.log(API_URI_REGEX.parse('/versions/stable/apis/petstore.json'));
41+
// ➪ { version: 'stable', filename: 'petstore.json' }
42+
```
43+
44+
You can also supply it non-`RegExp` regexes as well.
45+
46+
```ts
47+
const API_URI_REGEX = new StructuredRegEx<{ filename: string; version: string }>(/\/versions\/(.*)\/apis\/(.*)/i, {
48+
version: 1,
49+
filename: 2,
50+
});
51+
52+
console.log(API_URI_REGEX.parse('/versions/stable/apis/petstore.json'));
53+
// ➪ { version: 'stable', filename: 'petstore.json' }
54+
```

0 commit comments

Comments
 (0)