@ptolemy2002/rgx 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +187 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +98 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# RGX
|
|
2
|
+
A library for easy construction and validation of regular expressions in TypeScript. You can use `rgx` to concatenate various types of tokens into a valid regular expression string, with type safety and validation.
|
|
3
|
+
|
|
4
|
+
## Type Reference
|
|
5
|
+
```typescript
|
|
6
|
+
import { Branded } from "@ptolemy2002/ts-brand-utils";
|
|
7
|
+
|
|
8
|
+
type RGXNoOpToken = null | undefined;
|
|
9
|
+
type RGXNativeToken = string | number | boolean | RGXNoOpToken;
|
|
10
|
+
type RGXConvertibleToken = { toRgx: () => RGXNativeToken | RGXNativeToken[] };
|
|
11
|
+
type RGXToken = RGXNativeToken | RGXConvertibleToken | RGXToken[];
|
|
12
|
+
|
|
13
|
+
const validRegexSymbol = Symbol('ValidRegex');
|
|
14
|
+
type ValidRegexBrandSymbol = typeof validRegexSymbol;
|
|
15
|
+
type ValidRegexString = Branded<string, [ValidRegexBrandSymbol]>;
|
|
16
|
+
|
|
17
|
+
type RGXTokenType = 'no-op' | 'native' | 'convertible' | RGXTokenType[];
|
|
18
|
+
type RGXTokenFromType<T extends RGXTokenType> =
|
|
19
|
+
// ... see source for full definition
|
|
20
|
+
;
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Functions
|
|
24
|
+
The following functions are exported by the library:
|
|
25
|
+
|
|
26
|
+
### isRGXNoOpToken
|
|
27
|
+
```typescript
|
|
28
|
+
function isRGXNoOpToken(value: unknown): value is RGXNoOpToken
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Checks if the given value is a no-op token (`null` or `undefined`).
|
|
32
|
+
|
|
33
|
+
#### Parameters
|
|
34
|
+
- `value` (`unknown`): The value to check.
|
|
35
|
+
|
|
36
|
+
#### Returns
|
|
37
|
+
- `boolean`: `true` if the value is a no-op token, otherwise `false`.
|
|
38
|
+
|
|
39
|
+
### isRGXNativeToken
|
|
40
|
+
```typescript
|
|
41
|
+
function isRGXNativeToken(value: unknown): value is RGXNativeToken
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Checks if the given value is a native token (string, number, boolean, or no-op).
|
|
45
|
+
|
|
46
|
+
#### Parameters
|
|
47
|
+
- `value` (`unknown`): The value to check.
|
|
48
|
+
|
|
49
|
+
#### Returns
|
|
50
|
+
- `boolean`: `true` if the value is a native token, otherwise `false`.
|
|
51
|
+
|
|
52
|
+
### isRGXConvertibleToken
|
|
53
|
+
```typescript
|
|
54
|
+
function isRGXConvertibleToken(value: unknown): value is RGXConvertibleToken
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Checks if the given value is a convertible token (an object with a `toRgx` method). Validates that `toRgx` is callable and returns a valid RGX native token or array of native tokens.
|
|
58
|
+
|
|
59
|
+
#### Parameters
|
|
60
|
+
- `value` (`unknown`): The value to check.
|
|
61
|
+
|
|
62
|
+
#### Returns
|
|
63
|
+
- `boolean`: `true` if the value is a convertible token, otherwise `false`.
|
|
64
|
+
|
|
65
|
+
### rgxTokenType
|
|
66
|
+
```typescript
|
|
67
|
+
function rgxTokenType(value: RGXToken): RGXTokenType
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Determines the type of a given RGX token (`no-op`, `native`, `convertible`, or an array of the former).
|
|
71
|
+
|
|
72
|
+
If you narrow the result of this function to something more specific, you can then convert these string or array literals into their corresponding token types using the `RGXTokenFromType` utility type or `rgxTokenFromType` function.
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
const token: RGXToken = ...;
|
|
76
|
+
const type = rgxTokenType(token);
|
|
77
|
+
|
|
78
|
+
if (type === 'native') {
|
|
79
|
+
const narrowedToken1 = token as RGXTokenFromType<typeof type>; // narrowedToken is RGXNativeToken
|
|
80
|
+
const narrowedToken2 = rgxTokenFromType(type, token); // same as above
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### Parameters
|
|
85
|
+
- `value` (`RGXToken`): The RGX token to check.
|
|
86
|
+
|
|
87
|
+
#### Returns
|
|
88
|
+
- `RGXTokenType`: The type of the RGX token.
|
|
89
|
+
|
|
90
|
+
### rgxTokenFromType
|
|
91
|
+
```typescript
|
|
92
|
+
function rgxTokenFromType<T extends RGXTokenType>(type: T, value: RGXToken): RGXTokenFromType<T>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Does nothing at runtime, but performs a type assertion to the correct subset of `RGXToken` based on the provided `RGXTokenType`.
|
|
96
|
+
|
|
97
|
+
#### Parameters
|
|
98
|
+
- `type` (`T`): The RGX token type to assert to.
|
|
99
|
+
- `value` (`RGXToken`): The RGX token to assert.
|
|
100
|
+
|
|
101
|
+
#### Returns
|
|
102
|
+
- `RGXTokenFromType<T>`: The input value, but with its type asserted to the corresponding token type based on the provided `RGXTokenType`.
|
|
103
|
+
|
|
104
|
+
### isValidRegex
|
|
105
|
+
```typescript
|
|
106
|
+
function isValidRegex(value: string): value is ValidRegexString
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Checks if the given string is a valid regular expression by attempting to create a new `RegExp` object with it. If it succeeds, the string is branded as a `ValidRegexString`.
|
|
110
|
+
|
|
111
|
+
#### Parameters
|
|
112
|
+
- `value` (`string`): The string to check.
|
|
113
|
+
|
|
114
|
+
#### Returns
|
|
115
|
+
- `boolean`: `true` if the string is a valid regular expression, otherwise `false`.
|
|
116
|
+
|
|
117
|
+
### escapeRegex
|
|
118
|
+
```typescript
|
|
119
|
+
function escapeRegex(value: string): ValidRegexString
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Escapes special regex characters in the given string and brands the result as a `ValidRegexString`.
|
|
123
|
+
|
|
124
|
+
#### Parameters
|
|
125
|
+
- `value` (`string`): The string to escape.
|
|
126
|
+
|
|
127
|
+
#### Returns
|
|
128
|
+
- `ValidRegexString`: The escaped string, branded as a valid regex string.
|
|
129
|
+
|
|
130
|
+
### resolveRGXToken
|
|
131
|
+
```typescript
|
|
132
|
+
function resolveRGXToken(token: RGXToken): string
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Resolves an RGX token to a string. No-op tokens resolve to an empty string, native tokens are converted to strings and escaped, convertible tokens are converted using their `toRgx` method and then resolved recursively, and arrays of tokens are resolved as unions of their resolved elements (placed in a non-capturing group).
|
|
136
|
+
|
|
137
|
+
#### Parameters
|
|
138
|
+
- `token` (`RGXToken`): The RGX token to resolve.
|
|
139
|
+
|
|
140
|
+
#### Returns
|
|
141
|
+
- `string`: The resolved string representation of the RGX token.
|
|
142
|
+
|
|
143
|
+
### rgx
|
|
144
|
+
```typescript
|
|
145
|
+
function rgx(strings: TemplateStringsArray, ...tokens: RGXToken[]): RegExp
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
A template tag function that constructs a `RegExp` object from the provided template literal. The template literal can contain RGX tokens, which will be resolved and concatenated with the literal parts to form the final regex pattern.
|
|
149
|
+
|
|
150
|
+
Example usages:
|
|
151
|
+
```typescript
|
|
152
|
+
const beginning = /^/;
|
|
153
|
+
const end = /$/;
|
|
154
|
+
const word = /\w+/;
|
|
155
|
+
const pattern = rgx`${beginning}testing ${word}${end}`; // /^testing \w+$/ - matches the string "testing " followed by a word, anchored to the start and end of the string
|
|
156
|
+
|
|
157
|
+
const optionalDigit = /\d?/;
|
|
158
|
+
const pattern2 = rgx`${beginning}optional digit: ${optionalDigit}${end}`; // /^optional digit: \d?$/ - matches the string "optional digit: " followed by an optional digit, anchored to the start and end of the string
|
|
159
|
+
|
|
160
|
+
const pattern3 = rgx`${beginning}value: ${[word, optionalDigit]}${end}`; // /^value: (?:\w+|\d?)$/ - matches the string "value: " followed by either a word or an optional digit, anchored to the start and end of the string
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
#### Parameters
|
|
164
|
+
- `strings` (`TemplateStringsArray`): The literal parts of the template string.
|
|
165
|
+
- `tokens` (`RGXToken[]`): The RGX tokens to be resolved and concatenated with the literal parts.
|
|
166
|
+
|
|
167
|
+
#### Returns
|
|
168
|
+
- `RegExp`: The resulting regular expression object constructed from the template literal.
|
|
169
|
+
|
|
170
|
+
## Peer Dependencies
|
|
171
|
+
- `@ptolemy2002/ts-brand-utils` ^1.0.0
|
|
172
|
+
- `@ptolemy2002/ts-utils` ^3.4.0
|
|
173
|
+
- `is-callable` ^1.2.7
|
|
174
|
+
|
|
175
|
+
## Commands
|
|
176
|
+
The following commands exist in the project:
|
|
177
|
+
|
|
178
|
+
- `npm run uninstall` - Uninstalls all dependencies for the library
|
|
179
|
+
- `npm run reinstall` - Uninstalls and then Reinstalls all dependencies for the library
|
|
180
|
+
- `npm run build` - Builds the library
|
|
181
|
+
- `npm run release` - Publishes the library to npm without changing the version
|
|
182
|
+
- `npm run release-patch` - Publishes the library to npm with a patch version bump
|
|
183
|
+
- `npm run release-minor` - Publishes the library to npm with a minor version bump
|
|
184
|
+
- `npm run release-major` - Publishes the library to npm with a major version bump
|
|
185
|
+
- `npm run test` - Runs the tests for the library
|
|
186
|
+
- `npm run test:watch` - Runs the tests for the library in watch mode
|
|
187
|
+
- `npm run test:coverage` - Runs the tests for the library and generates a coverage report
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Branded } from "@ptolemy2002/ts-brand-utils";
|
|
2
|
+
export type RGXNoOpToken = null | undefined;
|
|
3
|
+
export type RGXNativeToken = string | number | boolean | RGXNoOpToken;
|
|
4
|
+
export type RGXConvertibleToken = {
|
|
5
|
+
toRgx: () => RGXNativeToken | RGXNativeToken[];
|
|
6
|
+
};
|
|
7
|
+
export type RGXToken = RGXNativeToken | RGXConvertibleToken | RGXToken[];
|
|
8
|
+
export type RGXTokenType = 'no-op' | 'native' | 'convertible' | RGXTokenType[];
|
|
9
|
+
export type RGXTokenFromType<T extends RGXTokenType> = T extends 'no-op' ? RGXNoOpToken : T extends 'native' ? RGXNativeToken : T extends 'convertible' ? RGXConvertibleToken : T extends RGXTokenType[] ? {
|
|
10
|
+
[K in keyof T]: T[K] extends RGXTokenType ? RGXTokenFromType<T[K]> : never;
|
|
11
|
+
} : never;
|
|
12
|
+
export declare const validRegexSymbol: unique symbol;
|
|
13
|
+
export type ValidRegexBrandSymbol = typeof validRegexSymbol;
|
|
14
|
+
export type ValidRegexString = Branded<string, [ValidRegexBrandSymbol]>;
|
|
15
|
+
export declare function isRGXNoOpToken(value: unknown): value is RGXNoOpToken;
|
|
16
|
+
export declare function isRGXNativeToken(value: unknown): value is RGXNativeToken;
|
|
17
|
+
export declare function isRGXConvertibleToken(value: unknown): value is RGXConvertibleToken;
|
|
18
|
+
export declare function rgxTokenType(value: RGXToken): RGXTokenType;
|
|
19
|
+
export declare function rgxTokenFromType<T extends RGXTokenType>(type: T, value: RGXToken): RGXTokenFromType<T>;
|
|
20
|
+
export declare function isValidRegex(value: string): value is ValidRegexString;
|
|
21
|
+
export declare function escapeRegex(value: string): ValidRegexString;
|
|
22
|
+
export declare function resolveRGXToken(token: RGXToken): string;
|
|
23
|
+
export default function rgx(strings: TemplateStringsArray, ...tokens: RGXToken[]): RegExp;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.validRegexSymbol = void 0;
|
|
7
|
+
exports.isRGXNoOpToken = isRGXNoOpToken;
|
|
8
|
+
exports.isRGXNativeToken = isRGXNativeToken;
|
|
9
|
+
exports.isRGXConvertibleToken = isRGXConvertibleToken;
|
|
10
|
+
exports.rgxTokenType = rgxTokenType;
|
|
11
|
+
exports.rgxTokenFromType = rgxTokenFromType;
|
|
12
|
+
exports.isValidRegex = isValidRegex;
|
|
13
|
+
exports.escapeRegex = escapeRegex;
|
|
14
|
+
exports.resolveRGXToken = resolveRGXToken;
|
|
15
|
+
exports.default = rgx;
|
|
16
|
+
const is_callable_1 = __importDefault(require("is-callable"));
|
|
17
|
+
exports.validRegexSymbol = Symbol('ValidRegex');
|
|
18
|
+
function isRGXNoOpToken(value) {
|
|
19
|
+
return value === null || value === undefined;
|
|
20
|
+
}
|
|
21
|
+
function isRGXNativeToken(value) {
|
|
22
|
+
return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || isRGXNoOpToken(value);
|
|
23
|
+
}
|
|
24
|
+
function isRGXConvertibleToken(value) {
|
|
25
|
+
if (typeof value === 'object' && value !== null && 'toRgx' in value) {
|
|
26
|
+
if ((0, is_callable_1.default)(value.toRgx)) {
|
|
27
|
+
const returnValue = value.toRgx();
|
|
28
|
+
if (Array.isArray(returnValue)) {
|
|
29
|
+
return returnValue.every(isRGXNativeToken);
|
|
30
|
+
}
|
|
31
|
+
return isRGXNativeToken(returnValue);
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
function rgxTokenType(value) {
|
|
38
|
+
if (isRGXNoOpToken(value))
|
|
39
|
+
return 'no-op';
|
|
40
|
+
if (isRGXNativeToken(value))
|
|
41
|
+
return 'native';
|
|
42
|
+
if (isRGXConvertibleToken(value))
|
|
43
|
+
return 'convertible';
|
|
44
|
+
if (Array.isArray(value))
|
|
45
|
+
return value.map(rgxTokenType);
|
|
46
|
+
// Ignoring this line since it should be impossible to reach if the types are correct, but we need it to satisfy the return type
|
|
47
|
+
/* istanbul ignore next */
|
|
48
|
+
throw new TypeError(`Invalid RGX token: ${value}`);
|
|
49
|
+
}
|
|
50
|
+
function rgxTokenFromType(type, value) {
|
|
51
|
+
// Ignoring this line because the function is entirely a TypeScript utility that doesn't need to be tested at runtime.
|
|
52
|
+
/* istanbul ignore next */
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
function isValidRegex(value) {
|
|
56
|
+
try {
|
|
57
|
+
new RegExp(value);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function escapeRegex(value) {
|
|
65
|
+
return value.replaceAll(/[\-\^\$.*+?^${}()|[\]\\]/g, '\\$&');
|
|
66
|
+
}
|
|
67
|
+
function resolveRGXToken(token) {
|
|
68
|
+
if (isRGXNoOpToken(token))
|
|
69
|
+
return '';
|
|
70
|
+
if (isRGXNativeToken(token))
|
|
71
|
+
return escapeRegex(String(token));
|
|
72
|
+
if (isRGXConvertibleToken(token)) {
|
|
73
|
+
return resolveRGXToken(token.toRgx());
|
|
74
|
+
}
|
|
75
|
+
// Interpret arrays as unions
|
|
76
|
+
if (Array.isArray(token)) {
|
|
77
|
+
if (token.length === 0)
|
|
78
|
+
return '';
|
|
79
|
+
if (token.length > 1) {
|
|
80
|
+
return '(?:' + token.map(resolveRGXToken).join('|') + ')';
|
|
81
|
+
}
|
|
82
|
+
return resolveRGXToken(token[0]);
|
|
83
|
+
}
|
|
84
|
+
// Ignoring this line since it should be impossible to reach if the types are correct, but we need it to satisfy the return type
|
|
85
|
+
/* istanbul ignore next */
|
|
86
|
+
throw new TypeError(`Invalid RGX token: ${token}`);
|
|
87
|
+
}
|
|
88
|
+
function rgx(strings, ...tokens) {
|
|
89
|
+
let pattern = '';
|
|
90
|
+
const resolvedTokens = tokens.map(resolveRGXToken);
|
|
91
|
+
for (let i = 0; i < strings.length; i++) {
|
|
92
|
+
pattern += strings[i];
|
|
93
|
+
if (i < resolvedTokens.length) {
|
|
94
|
+
pattern += resolvedTokens[i];
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return new RegExp(pattern);
|
|
98
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ptolemy2002/rgx",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"/dist"
|
|
9
|
+
],
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/Ptolemy2002/rgx",
|
|
13
|
+
"directory": "lib"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"prepare": "npx ts-patch install -s",
|
|
17
|
+
"build": "bash ./scripts/build.sh",
|
|
18
|
+
"_build": "tsc --project ./tsconfig.build.json",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"test": "jest",
|
|
21
|
+
"test:watch": "jest --watch",
|
|
22
|
+
"test:coverage": "jest --coverage",
|
|
23
|
+
"postinstall": "npx typesync",
|
|
24
|
+
"uninstall": "bash ./scripts/uninstall.sh",
|
|
25
|
+
"reinstall": "bash ./scripts/reinstall.sh",
|
|
26
|
+
"release": "bash ./scripts/release.sh",
|
|
27
|
+
"release-patch": "bash ./scripts/release.sh patch",
|
|
28
|
+
"release-minor": "bash ./scripts/release.sh minor",
|
|
29
|
+
"release-major": "bash ./scripts/release.sh major"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@ptolemy2002/ts-brand-utils": "^1.0.0",
|
|
33
|
+
"@ptolemy2002/ts-utils": "^3.4.0",
|
|
34
|
+
"@types/is-callable": "^1.1.2",
|
|
35
|
+
"@types/jest": "^29.5.0",
|
|
36
|
+
"is-callable": "^1.2.7",
|
|
37
|
+
"jest": "^29.5.0",
|
|
38
|
+
"ts-jest": "^29.1.0",
|
|
39
|
+
"ts-patch": "^3.3.0",
|
|
40
|
+
"tsconfig-paths": "^4.2.0",
|
|
41
|
+
"typescript-transform-paths": "^3.5.3"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@ptolemy2002/ts-brand-utils": "^1.0.0",
|
|
45
|
+
"@ptolemy2002/ts-utils": "^3.4.0",
|
|
46
|
+
"is-callable": "^1.2.7"
|
|
47
|
+
}
|
|
48
|
+
}
|