@ptolemy2002/rgx 4.2.0 → 4.3.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 CHANGED
@@ -20,21 +20,27 @@ const validVanillaRegexFlagsSymbol = Symbol('rgx.ValidVanillaRegexFlags');
20
20
  type ValidVanillaRegexFlagsBrandSymbol = typeof validVanillaRegexFlagsSymbol;
21
21
  type ValidVanillaRegexFlags = Branded<string, [ValidVanillaRegexFlagsBrandSymbol]>;
22
22
 
23
+ const validRegexFlagsSymbol = Symbol('rgx.ValidRegexFlags');
24
+ type ValidRegexFlagsBrandSymbol = typeof validRegexFlagsSymbol;
25
+ type ValidRegexFlags = Branded<string, [ValidRegexFlagsBrandSymbol]> | ValidVanillaRegexFlags;
26
+
27
+ type RegExpFlagTransformer = (exp: RegExp) => RegExp;
28
+
23
29
  const validIdentifierSymbol = Symbol('rgx.ValidIdentifier');
24
30
  type ValidIdentifierBrandSymbol = typeof validIdentifierSymbol;
25
31
  type ValidIdentifier = Branded<string, [ValidIdentifierBrandSymbol]>;
26
32
 
27
33
  type RGXTokenType = 'no-op' | 'literal' | 'native' | 'convertible' | 'class' | RGXTokenType[];
28
34
  type RGXTokenTypeFlat = Exclude<RGXTokenType, RGXTokenType[]> | "array";
29
- type RGXTokenTypeGuardInput = RGXTokenTypeFlat | null | RGXClassTokenConstructor | RGXTokenTypeGuardInput[];
35
+ type RGXTokenTypeGuardInput = RGXTokenTypeFlat | null | RGXClassTokenConstructor | typeof ExtRegExp | RGXTokenTypeGuardInput[];
30
36
  type RGXTokenFromType<T extends RGXTokenTypeGuardInput> =
31
37
  // Maps token type strings to their corresponding types, e.g.:
32
38
  // 'no-op' -> RGXNoOpToken, 'literal' -> RGXLiteralToken, etc.
33
- // Also maps RGXClassTokenConstructor to InstanceType<T>.
39
+ // Also maps RGXClassTokenConstructor to InstanceType<T> and typeof ExtRegExp to ExtRegExp.
34
40
  // ... see source for full definition
35
41
  ;
36
42
 
37
- type RGXErrorCode = 'UNKNOWN' | 'INVALID_RGX_TOKEN' | 'INVALID_REGEX_STRING' | 'INVALID_VANILLA_REGEX_FLAGS' | 'NOT_IMPLEMENTED' | 'INVALID_IDENTIFIER' | 'OUT_OF_BOUNDS';
43
+ type RGXErrorCode = 'UNKNOWN' | 'INVALID_RGX_TOKEN' | 'INVALID_REGEX_STRING' | 'INVALID_REGEX_FLAGS' | 'INVALID_VANILLA_REGEX_FLAGS' | 'NOT_IMPLEMENTED' | 'INVALID_IDENTIFIER' | 'OUT_OF_BOUNDS' | 'INVALID_FLAG_TRANSFORMER_KEY' | 'FLAG_TRANSFORMER_CONFLICT';
38
44
 
39
45
  type RangeObject = {
40
46
  min?: number | null;
@@ -149,6 +155,54 @@ constructor(message: string, got: string)
149
155
  #### Methods
150
156
  - `toString() => string`: Returns a formatted string indicating the invalid identifier and the reason for failure.
151
157
 
158
+ ### RGXInvalidRegexFlagsError extends RGXError
159
+ A specific error class for invalid regex flags (including both vanilla and custom registered flags). This error is thrown when a string fails validation as valid regex flags. The error code is set to `INVALID_REGEX_FLAGS` on instantiation.
160
+
161
+ #### Constructor
162
+ ```typescript
163
+ constructor(message: string, got: string)
164
+ ```
165
+ - `message` (`string`): The error message.
166
+ - `got` (`string`): The actual string that was received, which failed validation.
167
+
168
+ #### Properties
169
+ - `got` (`string`): The actual string that was received, which failed validation.
170
+
171
+ #### Methods
172
+ - `toString() => string`: Returns a formatted string indicating the invalid flags and the reason for failure.
173
+
174
+ ### RGXInvalidFlagTransformerKeyError extends RGXError
175
+ A specific error class for invalid flag transformer keys. This error is thrown when an invalid key is provided to `registerFlagTransformer` (e.g., a key that is not a single character). The error code is set to `INVALID_FLAG_TRANSFORMER_KEY` on instantiation.
176
+
177
+ #### Constructor
178
+ ```typescript
179
+ constructor(message: string, got: string)
180
+ ```
181
+ - `message` (`string`): The error message.
182
+ - `got` (`string`): The actual key string that was received, which failed validation.
183
+
184
+ #### Properties
185
+ - `got` (`string`): The actual key string that was received, which failed validation.
186
+
187
+ #### Methods
188
+ - `toString() => string`: Returns a formatted string indicating the invalid key and the reason for failure.
189
+
190
+ ### RGXFlagTransformerConflictError extends RGXError
191
+ A specific error class for flag transformer conflicts. This error is thrown when attempting to register a flag transformer with a key that conflicts with an existing vanilla regex flag or an already-registered transformer. The error code is set to `FLAG_TRANSFORMER_CONFLICT` on instantiation.
192
+
193
+ #### Constructor
194
+ ```typescript
195
+ constructor(message: string, got: string)
196
+ ```
197
+ - `message` (`string`): The error message.
198
+ - `got` (`string`): The conflicting key string.
199
+
200
+ #### Properties
201
+ - `got` (`string`): The conflicting key string.
202
+
203
+ #### Methods
204
+ - `toString() => string`: Returns a formatted string indicating the conflict and the reason for failure.
205
+
152
206
  ### RGXOutOfBoundsError extends RGXError
153
207
  A specific error class for out-of-bounds values. This error is thrown when a numeric value falls outside an expected range. The error code is set to `OUT_OF_BOUNDS` on instantiation.
154
208
 
@@ -277,6 +331,24 @@ constructor(args?: RGXGroupTokenArgs, tokens?: RGXTokenCollectionInput)
277
331
  #### Methods
278
332
  - `toRgx() => RegExp`: Resolves the group by concatenating the internal tokens and wrapping the result in the appropriate group syntax: `(?<name>...)` for named groups, `(?:...)` for non-capturing groups, or `(...)` for capturing groups.
279
333
 
334
+ ### ExtRegExp extends RegExp
335
+ A subclass of `RegExp` that supports custom flag transformers in addition to the standard vanilla regex flags (g, i, m, s, u, y). When constructed, custom flags are extracted, their corresponding transformers are applied to the pattern and vanilla flags, and the resulting transformed `RegExp` is created. The `flags` getter returns both the vanilla flags and any custom flags.
336
+
337
+ A function `extRegExp` is provided with the same parameters as this class' constructor, for easier instantiation without needing to use the `new` keyword.
338
+
339
+ #### Constructor
340
+ ```typescript
341
+ constructor(pattern: string | RegExp, flags?: string)
342
+ ```
343
+ - `pattern` (`string | RegExp`): The regex pattern. If a `RegExp` is provided, its `source` is used and its existing `flags` are tracked as already-applied flags to avoid re-applying transformers.
344
+ - `flags` (`string`, optional): The flags string, which may include both vanilla regex flags and custom registered flag keys. Validated via `assertValidRegexFlags`. Defaults to `''`.
345
+
346
+ #### Properties
347
+ - `flags` (`string`): Returns the combination of the vanilla flags (from the underlying `RegExp`) and any custom flags that were applied during construction.
348
+
349
+ #### Static Properties
350
+ - `[Symbol.species]` (`RegExpConstructor`): Returns `ExtRegExp`, ensuring that derived `RegExp` methods (like those returning new regex instances) produce `ExtRegExp` instances rather than plain `RegExp`.
351
+
280
352
  ## Functions
281
353
  The following functions are exported by the library:
282
354
 
@@ -659,10 +731,10 @@ A helper function that resolves an array of RGX tokens and concatenates their re
659
731
 
660
732
  ### rgx
661
733
  ```typescript
662
- function rgx(flags?: string): (strings: TemplateStringsArray, ...tokens: RGXToken[]) => RegExp
734
+ function rgx(flags?: string): (strings: TemplateStringsArray, ...tokens: RGXToken[]) => ExtRegExp
663
735
  ```
664
736
 
665
- Creates and returns a template tag function that constructs a `RegExp` object from the provided template literal with the provided flags. The template literal can contain RGX tokens, which will be resolved and concatenated with the literal parts to form the final regex pattern.
737
+ Creates and returns a template tag function that constructs an `ExtRegExp` object from the provided template literal with the provided flags. The template literal can contain RGX tokens, which will be resolved and concatenated with the literal parts to form the final regex pattern.
666
738
 
667
739
  Example usages:
668
740
  ```typescript
@@ -679,27 +751,27 @@ const pattern3 = rgx()`${beginning}value: ${[word, optionalDigit]}${end}`; // /^
679
751
 
680
752
  #### Parameters
681
753
  **Direct**
682
- - `flags` (`string`, optional): The regex flags to apply to the resulting `RegExp` object (e.g., 'g', 'i', 'm', etc.). If not provided, no flags will be applied. If provided and not valid vanilla regex flags, an `RGXInvalidVanillaRegexFlagsError` will be thrown.
754
+ - `flags` (`string`, optional): The regex flags to apply to the resulting `ExtRegExp` object (e.g., 'g', 'i', 'm', or custom registered flags). If not provided, no flags will be applied. If provided and not valid regex flags (vanilla or registered custom), an `RGXInvalidRegexFlagsError` will be thrown.
683
755
 
684
756
  **Template Tag**
685
757
  - `strings` (`TemplateStringsArray`): The literal parts of the template string.
686
758
  - `tokens` (`RGXToken[]`): The RGX tokens to be resolved and concatenated with the literal parts.
687
759
 
688
760
  #### Returns
689
- - `(strings: TemplateStringsArray, ...tokens: RGXToken[]) => RegExp`: A template tag function that takes a template literal and returns a `RegExp` object constructed from the resolved tokens, literal parts, and the provided flags.
761
+ - `(strings: TemplateStringsArray, ...tokens: RGXToken[]) => ExtRegExp`: A template tag function that takes a template literal and returns an `ExtRegExp` object constructed from the resolved tokens, literal parts, and the provided flags.
690
762
 
691
763
  ### rgxa
692
764
  ```typescript
693
- function rgxa(tokens: RGXToken[], flags?: string): RegExp
765
+ function rgxa(tokens: RGXToken[], flags?: string): ExtRegExp
694
766
  ```
695
- As an alternative to using the `rgx` template tag, you can directly call `rgxa` with an array of RGX tokens and optional flags to get a `RegExp` object. This is useful in cases where you don't want to use a template literal.
767
+ As an alternative to using the `rgx` template tag, you can directly call `rgxa` with an array of RGX tokens and optional flags to get an `ExtRegExp` object. This is useful in cases where you don't want to use a template literal.
696
768
 
697
769
  #### Parameters
698
770
  - `tokens` (`RGXToken[]`): The RGX tokens to be resolved and concatenated to form the regex pattern.
699
- - `flags` (`string`, optional): The regex flags to apply to the resulting `RegExp` object (e.g., 'g', 'i', 'm', etc.). If not provided, no flags will be applied. If provided and not valid vanilla regex flags, an `RGXInvalidVanillaRegexFlagsError` will be thrown.
771
+ - `flags` (`string`, optional): The regex flags to apply to the resulting `ExtRegExp` object (e.g., 'g', 'i', 'm', or custom registered flags). If not provided, no flags will be applied. If provided and not valid regex flags (vanilla or registered custom), an `RGXInvalidRegexFlagsError` will be thrown.
700
772
 
701
773
  #### Returns
702
- - `RegExp`: A `RegExp` object constructed from the resolved tokens and the provided flags.
774
+ - `ExtRegExp`: An `ExtRegExp` object constructed from the resolved tokens and the provided flags.
703
775
 
704
776
  ### expandRgxUnionTokens
705
777
  ```typescript
@@ -766,12 +838,132 @@ Asserts that the given numeric value falls within the specified range. If the as
766
838
  #### Returns
767
839
  - `void`: This function does not return a value, but will throw an error if the assertion fails.
768
840
 
841
+ ### isValidRegexFlags
842
+ ```typescript
843
+ function isValidRegexFlags(flags: string): flags is ValidRegexFlags
844
+ ```
845
+
846
+ Checks if the given string is a valid combination of regex flags, including both vanilla flags (g, i, m, s, u, y) and any custom flags registered via `registerFlagTransformer`. Custom flag characters are stripped before validating the remaining characters as vanilla flags.
847
+
848
+ #### Parameters
849
+ - `flags` (`string`): The string to check.
850
+
851
+ #### Returns
852
+ - `boolean`: `true` if the string is a valid combination of regex flags, otherwise `false`.
853
+
854
+ ### assertValidRegexFlags
855
+ ```typescript
856
+ function assertValidRegexFlags(flags: string): asserts flags is ValidRegexFlags
857
+ ```
858
+
859
+ Asserts that the given string is a valid combination of regex flags, including both vanilla flags and any custom registered flags. If the assertion fails, an `RGXInvalidRegexFlagsError` will be thrown.
860
+
861
+ #### Parameters
862
+ - `flags` (`string`): The string to assert.
863
+
864
+ #### Returns
865
+ - `void`: This function does not return a value, but will throw an error if the assertion fails.
866
+
867
+ ### isFlagKeyAvailable
868
+ ```typescript
869
+ function isFlagKeyAvailable(flags: string): boolean
870
+ ```
871
+
872
+ Checks if the given string is available for use as a custom flag transformer key. Returns `false` if the string is a vanilla regex flag or if any character in the string is already registered as a custom flag transformer.
873
+
874
+ #### Parameters
875
+ - `flags` (`string`): The string to check.
876
+
877
+ #### Returns
878
+ - `boolean`: `true` if the string is available for use as a custom flag key, otherwise `false`.
879
+
880
+ ### registerFlagTransformer
881
+ ```typescript
882
+ function registerFlagTransformer(key: string, transformer: RegExpFlagTransformer): void
883
+ ```
884
+
885
+ Registers a custom flag transformer under the given single-character key. The key must be exactly one character, must not be a vanilla regex flag, and must not already be registered. When an `ExtRegExp` is constructed with this flag character in its flags string, the transformer function will be called with the `RegExp` to transform it.
886
+
887
+ #### Parameters
888
+ - `key` (`string`): A single-character string to use as the flag key. Must not be a vanilla regex flag or an already-registered key.
889
+ - `transformer` (`RegExpFlagTransformer`): A function that takes a `RegExp` and returns a transformed `RegExp`.
890
+
891
+ #### Returns
892
+ - `void`: This function does not return a value, but will throw an `RGXInvalidFlagTransformerKeyError` if the key is not a single character, or an `RGXFlagTransformerConflictError` if the key conflicts with a vanilla flag or an existing transformer.
893
+
894
+ ### unregisterFlagTransformer
895
+ ```typescript
896
+ function unregisterFlagTransformer(key: string): void
897
+ ```
898
+
899
+ Unregisters a previously registered custom flag transformer by its key. If the key was not registered, this is a no-op.
900
+
901
+ #### Parameters
902
+ - `key` (`string`): The flag key to unregister.
903
+
904
+ #### Returns
905
+ - `void`: This function does not return a value.
906
+
907
+ ### applyFlagTransformers
908
+ ```typescript
909
+ function applyFlagTransformers(regex: RegExp, flags: string, alreadyAppliedFlags?: string): RegExp
910
+ ```
911
+
912
+ Applies all registered flag transformers whose keys appear in the given flags string to the provided `RegExp`, returning the resulting transformed `RegExp`. Flags present in `alreadyAppliedFlags` are skipped to avoid re-applying transformers.
913
+
914
+ #### Parameters
915
+ - `regex` (`RegExp`): The regular expression to transform.
916
+ - `flags` (`string`): The flags string containing custom flag characters to apply.
917
+ - `alreadyAppliedFlags` (`string`, optional): A string of flag characters that have already been applied and should be skipped. Defaults to `''`.
918
+
919
+ #### Returns
920
+ - `RegExp`: The transformed `RegExp` after applying all matching flag transformers.
921
+
922
+ ### extractCustomRegexFlags
923
+ ```typescript
924
+ function extractCustomRegexFlags(flags: string): string
925
+ ```
926
+
927
+ Extracts the custom (non-vanilla) flag characters from the given flags string by returning only the characters that correspond to registered flag transformers.
928
+
929
+ #### Parameters
930
+ - `flags` (`string`): The flags string to extract custom flags from.
931
+
932
+ #### Returns
933
+ - `string`: A string containing only the custom flag characters found in the input.
934
+
935
+ ### extractVanillaRegexFlags
936
+ ```typescript
937
+ function extractVanillaRegexFlags(flags: string): string
938
+ ```
939
+
940
+ Extracts the vanilla regex flag characters from the given flags string by removing all characters that correspond to registered flag transformers.
941
+
942
+ #### Parameters
943
+ - `flags` (`string`): The flags string to extract vanilla flags from.
944
+
945
+ #### Returns
946
+ - `string`: A string with all registered custom flag characters removed, leaving only vanilla flags.
947
+
948
+ ### normalizeRegexFlags
949
+ ```typescript
950
+ function normalizeRegexFlags(flags: string): string
951
+ ```
952
+
953
+ Normalizes a string of regex flags (including both vanilla and custom registered flags) by removing duplicate flags while preserving order. If any character in the string is not a valid regex flag (vanilla or registered custom), an `RGXInvalidRegexFlagsError` will be thrown.
954
+
955
+ #### Parameters
956
+ - `flags` (`string`): The flags string to normalize.
957
+
958
+ #### Returns
959
+ - `string`: The normalized flags string with duplicates removed.
960
+
769
961
  ### normalizeVanillaRegexFlags
770
962
  ```typescript
771
963
  function normalizeVanillaRegexFlags(flags: string): string
772
964
  ```
773
965
 
774
- Normalizes a string of vanilla regex flags by removing duplicate flags while preserving order. If any character in the string is not a valid vanilla regex flag (g, i, m, s, u, y), an `RGXInvalidVanillaRegexFlagsError` will be thrown.
966
+ Normalizes a string of vanilla regex flags by removing duplicate flags while preserving order. First validates that all characters are valid vanilla regex flags (g, i, m, s, u, y), throwing an `RGXInvalidVanillaRegexFlagsError` if any are not, then delegates to `normalizeRegexFlags` for deduplication.
775
967
 
776
968
  #### Parameters
777
969
  - `flags` (`string`): The flags string to normalize.
@@ -781,18 +973,18 @@ Normalizes a string of vanilla regex flags by removing duplicate flags while pre
781
973
 
782
974
  ### regexWithFlags
783
975
  ```typescript
784
- function regexWithFlags(exp: RegExp, flags: string, replace?: boolean): RegExp
976
+ function regexWithFlags(exp: RegExp | ExtRegExp, flags: string, replace?: boolean): ExtRegExp
785
977
  ```
786
978
 
787
- Creates a new `RegExp` from an existing one with additional or replaced flags. When `replace` is `false` (the default), the provided flags are merged with the existing flags and normalized (duplicates removed). When `replace` is `true`, the existing flags are discarded and only the provided flags are used. The provided flags are validated as valid vanilla regex flags via `assertValidVanillaRegexFlags`.
979
+ Creates a new `ExtRegExp` from an existing one with additional or replaced flags. When `replace` is `false` (the default), the provided flags are merged with the existing flags and normalized (duplicates removed). When `replace` is `true`, the existing flags are discarded and only the provided flags are used. The provided flags are validated as valid vanilla regex flags via `assertValidVanillaRegexFlags`.
788
980
 
789
981
  #### Parameters
790
- - `exp` (`RegExp`): The source regular expression.
982
+ - `exp` (`RegExp | ExtRegExp`): The source regular expression.
791
983
  - `flags` (`string`): The flags to add or replace with. Must be valid vanilla regex flags, or an `RGXInvalidVanillaRegexFlagsError` will be thrown.
792
984
  - `replace` (`boolean`, optional): Whether to replace the existing flags entirely instead of merging. Defaults to `false`.
793
985
 
794
986
  #### Returns
795
- - `RegExp`: A new `RegExp` with the same source pattern and the resulting flags.
987
+ - `ExtRegExp`: A new `ExtRegExp` with the same source pattern and the resulting flags.
796
988
 
797
989
  ### regexMatchAtPosition
798
990
  ```typescript
@@ -829,4 +1021,4 @@ The following commands exist in the project:
829
1021
  - `npm run release-major` - Publishes the library to npm with a major version bump
830
1022
  - `npm run test` - Runs the tests for the library
831
1023
  - `npm run test:watch` - Runs the tests for the library in watch mode
832
- - `npm run test:coverage` - Runs the tests for the library and generates a coverage report
1024
+ - `npm run test:coverage` - Runs the tests for the library and generates a coverage report
@@ -0,0 +1,17 @@
1
+ import { ValidRegexFlags } from "./types";
2
+ export type RegExpFlagTransformer = (exp: RegExp) => RegExp;
3
+ export declare class ExtRegExp extends RegExp {
4
+ private extFlags;
5
+ constructor(pattern: string | RegExp, flags?: string);
6
+ get flags(): string;
7
+ static get [Symbol.species](): RegExpConstructor;
8
+ }
9
+ export declare function isFlagKeyAvailable(flags: string): boolean;
10
+ export declare function registerFlagTransformer(key: string, transformer: RegExpFlagTransformer): void;
11
+ export declare function unregisterFlagTransformer(key: string): void;
12
+ export declare function applyFlagTransformers(regex: RegExp, flags: string, alreadyAppliedFlags?: string): RegExp;
13
+ export declare function extractCustomRegexFlags(flags: string): string;
14
+ export declare function extractVanillaRegexFlags(flags: string): string;
15
+ export declare function isValidRegexFlags(flags: string): flags is ValidRegexFlags;
16
+ export declare function assertValidRegexFlags(flags: string): asserts flags is ValidRegexFlags;
17
+ export declare const extRegExp: (pattern: string | RegExp, flags?: string | undefined) => ExtRegExp;
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extRegExp = exports.ExtRegExp = void 0;
4
+ exports.isFlagKeyAvailable = isFlagKeyAvailable;
5
+ exports.registerFlagTransformer = registerFlagTransformer;
6
+ exports.unregisterFlagTransformer = unregisterFlagTransformer;
7
+ exports.applyFlagTransformers = applyFlagTransformers;
8
+ exports.extractCustomRegexFlags = extractCustomRegexFlags;
9
+ exports.extractVanillaRegexFlags = extractVanillaRegexFlags;
10
+ exports.isValidRegexFlags = isValidRegexFlags;
11
+ exports.assertValidRegexFlags = assertValidRegexFlags;
12
+ const errors_1 = require("./errors");
13
+ const internal_1 = require("./internal");
14
+ const typeGuards_1 = require("./typeGuards");
15
+ const flagTransformers = {};
16
+ class ExtRegExp extends RegExp {
17
+ constructor(pattern, flags = '') {
18
+ assertValidRegexFlags(flags);
19
+ const vanillaFlags = extractVanillaRegexFlags(flags);
20
+ const customFlags = extractCustomRegexFlags(flags);
21
+ const source = pattern instanceof RegExp ? pattern.source : pattern;
22
+ const alreadyAppliedFlags = pattern instanceof RegExp ? pattern.flags : '';
23
+ const { source: transformedSource, flags: transformedFlags } = applyFlagTransformers(new RegExp(source, vanillaFlags), customFlags, alreadyAppliedFlags);
24
+ super(transformedSource, transformedFlags);
25
+ this.extFlags = customFlags;
26
+ }
27
+ get flags() {
28
+ return super.flags + this.extFlags;
29
+ }
30
+ // Ensure that methods like .exec(), split(), etc. return instances
31
+ // of ExtRegExp rather than plain RegExp (preserves custom flags)
32
+ static get [Symbol.species]() {
33
+ return ExtRegExp;
34
+ }
35
+ }
36
+ exports.ExtRegExp = ExtRegExp;
37
+ function isFlagKeyAvailable(flags) {
38
+ if ((0, typeGuards_1.isValidVanillaRegexFlags)(flags))
39
+ return false;
40
+ for (const flag in flagTransformers) {
41
+ if (flags.includes(flag))
42
+ return false;
43
+ }
44
+ return true;
45
+ }
46
+ function registerFlagTransformer(key, transformer) {
47
+ if (key.length !== 1)
48
+ throw new errors_1.RGXInvalidFlagTransformerKeyError("Flag key must be a single character.", key);
49
+ if ((0, typeGuards_1.isValidVanillaRegexFlags)(key))
50
+ throw new errors_1.RGXFlagTransformerConflictError("Transformer key conflicts with a vanilla regex flag.", key);
51
+ if (!isFlagKeyAvailable(key))
52
+ throw new errors_1.RGXFlagTransformerConflictError("Transformer already exists under this key.", key);
53
+ flagTransformers[key] = transformer;
54
+ }
55
+ function unregisterFlagTransformer(key) {
56
+ delete flagTransformers[key];
57
+ }
58
+ function applyFlagTransformers(regex, flags, alreadyAppliedFlags = '') {
59
+ for (const flag in flagTransformers) {
60
+ if (flags.includes(flag) && !alreadyAppliedFlags.includes(flag)) {
61
+ regex = flagTransformers[flag](regex);
62
+ alreadyAppliedFlags += flag;
63
+ }
64
+ }
65
+ return regex;
66
+ }
67
+ function extractCustomRegexFlags(flags) {
68
+ let customFlags = '';
69
+ for (const flag in flagTransformers) {
70
+ if (flags.includes(flag)) {
71
+ customFlags += flag;
72
+ }
73
+ }
74
+ return customFlags;
75
+ }
76
+ function extractVanillaRegexFlags(flags) {
77
+ for (const flag in flagTransformers) {
78
+ flags = flags.replaceAll(flag, '');
79
+ }
80
+ return flags;
81
+ }
82
+ function isValidRegexFlags(flags) {
83
+ // Remove all instances of registered flag transformers from the flags string, then
84
+ // check if the remaining flags are valid vanilla regex flags.
85
+ flags = extractVanillaRegexFlags(flags);
86
+ return (0, typeGuards_1.isValidVanillaRegexFlags)(flags);
87
+ }
88
+ function assertValidRegexFlags(flags) {
89
+ if (!isValidRegexFlags(flags)) {
90
+ throw new errors_1.RGXInvalidRegexFlagsError("Invalid regex flags", flags);
91
+ }
92
+ }
93
+ exports.extRegExp = (0, internal_1.createConstructFunction)(ExtRegExp);
@@ -1,4 +1,4 @@
1
- export type RGXErrorCode = 'UNKNOWN' | 'INVALID_RGX_TOKEN' | 'INVALID_REGEX_STRING' | 'INVALID_VANILLA_REGEX_FLAGS' | 'NOT_IMPLEMENTED' | 'INVALID_IDENTIFIER' | 'OUT_OF_BOUNDS';
1
+ export type RGXErrorCode = 'UNKNOWN' | 'INVALID_RGX_TOKEN' | 'INVALID_REGEX_STRING' | 'INVALID_REGEX_FLAGS' | 'INVALID_VANILLA_REGEX_FLAGS' | 'NOT_IMPLEMENTED' | 'INVALID_IDENTIFIER' | 'OUT_OF_BOUNDS' | 'INVALID_FLAG_TRANSFORMER_KEY' | 'FLAG_TRANSFORMER_CONFLICT';
2
2
  export declare class RGXError extends Error {
3
3
  code: RGXErrorCode;
4
4
  constructor(message: string, code?: RGXErrorCode);
@@ -0,0 +1,6 @@
1
+ import { RGXError } from "./";
2
+ export declare class RGXFlagTransformerConflictError extends RGXError {
3
+ got: string;
4
+ constructor(message: string, got: string);
5
+ toString(): string;
6
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RGXFlagTransformerConflictError = void 0;
4
+ const errors_1 = require("./");
5
+ class RGXFlagTransformerConflictError extends errors_1.RGXError {
6
+ constructor(message, got) {
7
+ super(message, 'FLAG_TRANSFORMER_CONFLICT');
8
+ this.name = 'RGXFlagTransformerConflictError';
9
+ this.got = got;
10
+ }
11
+ toString() {
12
+ return `${this.name}: ${this.message}; Got: ${JSON.stringify(this.got)}`;
13
+ }
14
+ }
15
+ exports.RGXFlagTransformerConflictError = RGXFlagTransformerConflictError;
@@ -1,7 +1,10 @@
1
1
  export * from './base';
2
2
  export * from './invalidToken';
3
3
  export * from './invalidRegexString';
4
+ export * from './invalidRegexFlags';
4
5
  export * from './invalidVanillaRegexFlags';
5
6
  export * from './notImplemented';
6
7
  export * from './invalidIdentifier';
7
8
  export * from './outOfBounds';
9
+ export * from './invalidFlagTransformerKey';
10
+ export * from './flagTransformerConflict';
@@ -17,7 +17,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./base"), exports);
18
18
  __exportStar(require("./invalidToken"), exports);
19
19
  __exportStar(require("./invalidRegexString"), exports);
20
+ __exportStar(require("./invalidRegexFlags"), exports);
20
21
  __exportStar(require("./invalidVanillaRegexFlags"), exports);
21
22
  __exportStar(require("./notImplemented"), exports);
22
23
  __exportStar(require("./invalidIdentifier"), exports);
23
24
  __exportStar(require("./outOfBounds"), exports);
25
+ __exportStar(require("./invalidFlagTransformerKey"), exports);
26
+ __exportStar(require("./flagTransformerConflict"), exports);
@@ -0,0 +1,6 @@
1
+ import { RGXError } from "./";
2
+ export declare class RGXInvalidFlagTransformerKeyError extends RGXError {
3
+ got: string;
4
+ constructor(message: string, got: string);
5
+ toString(): string;
6
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RGXInvalidFlagTransformerKeyError = void 0;
4
+ const errors_1 = require("./");
5
+ class RGXInvalidFlagTransformerKeyError extends errors_1.RGXError {
6
+ constructor(message, got) {
7
+ super(message, 'INVALID_FLAG_TRANSFORMER_KEY');
8
+ this.name = 'RGXInvalidFlagTransformerKeyError';
9
+ this.got = got;
10
+ }
11
+ toString() {
12
+ return `${this.name}: ${this.message}; Got: ${JSON.stringify(this.got)}`;
13
+ }
14
+ }
15
+ exports.RGXInvalidFlagTransformerKeyError = RGXInvalidFlagTransformerKeyError;
@@ -0,0 +1,6 @@
1
+ import { RGXError } from "./";
2
+ export declare class RGXInvalidRegexFlagsError extends RGXError {
3
+ got: string;
4
+ constructor(message: string, got: string);
5
+ toString(): string;
6
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RGXInvalidRegexFlagsError = void 0;
4
+ const errors_1 = require("./");
5
+ class RGXInvalidRegexFlagsError extends errors_1.RGXError {
6
+ constructor(message, got) {
7
+ super(message, 'INVALID_REGEX_FLAGS');
8
+ this.name = 'RGXInvalidRegexFlagsError';
9
+ this.got = got;
10
+ }
11
+ toString() {
12
+ return `${this.name}: ${this.message}; Got: ${JSON.stringify(this.got)}`;
13
+ }
14
+ }
15
+ exports.RGXInvalidRegexFlagsError = RGXInvalidRegexFlagsError;
@@ -17,4 +17,4 @@ export declare class RGXOutOfBoundsError extends RGXError {
17
17
  toString(): string;
18
18
  }
19
19
  export declare function isInRange(value: number, { min, max, inclusiveLeft, inclusiveRight }?: RangeObject): boolean;
20
- export declare function assertInRange(value: number, range: RangeObject, message?: string): void;
20
+ export declare function assertInRange(value: number, range?: RangeObject, message?: string): void;
@@ -102,7 +102,7 @@ function isInRange(value, { min = null, max = null, inclusiveLeft = true, inclus
102
102
  }
103
103
  return true;
104
104
  }
105
- function assertInRange(value, range, message = "Value out of bounds") {
105
+ function assertInRange(value, range = {}, message = "Value out of bounds") {
106
106
  if (!isInRange(value, range)) {
107
107
  throw new RGXOutOfBoundsError(message, value, range);
108
108
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as t from "./types";
2
+ import { ExtRegExp } from "./ExtRegExp";
2
3
  export * from "./errors";
3
4
  export * from "./types";
4
5
  export * from "./typeGuards";
@@ -7,5 +8,6 @@ export * from "./class";
7
8
  export * from "./resolve";
8
9
  export * from "./concat";
9
10
  export * from "./utils";
10
- export declare function rgxa(tokens: t.RGXToken[], flags?: string): RegExp;
11
- export default function rgx(flags?: string): (strings: TemplateStringsArray, ...tokens: t.RGXToken[]) => RegExp;
11
+ export * from "./ExtRegExp";
12
+ export declare function rgxa(tokens: t.RGXToken[], flags?: string): ExtRegExp;
13
+ export default function rgx(flags?: string): (strings: TemplateStringsArray, ...tokens: t.RGXToken[]) => ExtRegExp;
package/dist/index.js CHANGED
@@ -10,38 +10,16 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
10
10
  if (k2 === undefined) k2 = k;
11
11
  o[k2] = m[k];
12
12
  }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
13
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
36
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
37
15
  };
38
16
  Object.defineProperty(exports, "__esModule", { value: true });
39
17
  exports.rgxa = rgxa;
40
18
  exports.default = rgx;
41
- const tg = __importStar(require("./typeGuards"));
42
19
  const class_1 = require("./class");
43
20
  const concat_1 = require("./concat");
44
21
  const internal_1 = require("./internal");
22
+ const ExtRegExp_1 = require("./ExtRegExp");
45
23
  __exportStar(require("./errors"), exports);
46
24
  __exportStar(require("./types"), exports);
47
25
  __exportStar(require("./typeGuards"), exports);
@@ -50,15 +28,16 @@ __exportStar(require("./class"), exports);
50
28
  __exportStar(require("./resolve"), exports);
51
29
  __exportStar(require("./concat"), exports);
52
30
  __exportStar(require("./utils"), exports);
31
+ __exportStar(require("./ExtRegExp"), exports);
53
32
  // Call this for certain class methods to work correctly
54
33
  (0, class_1.rgxClassInit)();
55
34
  function rgxa(tokens, flags = '') {
56
- tg.assertValidVanillaRegexFlags(flags);
35
+ (0, ExtRegExp_1.assertValidRegexFlags)(flags);
57
36
  const pattern = (0, concat_1.rgxConcat)(tokens);
58
- return new RegExp(pattern, flags);
37
+ return (0, ExtRegExp_1.extRegExp)(pattern, flags);
59
38
  }
60
39
  function rgx(flags = '') {
61
- tg.assertValidVanillaRegexFlags(flags);
40
+ (0, ExtRegExp_1.assertValidRegexFlags)(flags);
62
41
  return (strings, ...tokens) => {
63
42
  return rgxa((0, internal_1.taggedTemplateToArray)(strings, tokens), flags);
64
43
  };
package/dist/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Branded } from "@ptolemy2002/ts-brand-utils";
2
2
  import type { RGXClassToken } from "./class";
3
+ import { ExtRegExp } from "./ExtRegExp";
3
4
  export type RGXNoOpToken = null | undefined;
4
5
  export type RGXLiteralToken = RegExp;
5
6
  export type RGXNativeToken = string | number | boolean | RGXNoOpToken;
@@ -11,10 +12,10 @@ export type RGXToken = RGXNativeToken | RGXLiteralToken | RGXConvertibleToken |
11
12
  export type RGXClassTokenConstructor = new (...args: unknown[]) => RGXClassToken;
12
13
  export type RGXTokenType = 'no-op' | 'literal' | 'native' | 'convertible' | 'class' | RGXTokenType[];
13
14
  export type RGXTokenTypeFlat = Exclude<RGXTokenType, RGXTokenType[]> | "array";
14
- export type RGXTokenTypeGuardInput = RGXTokenTypeFlat | null | RGXClassTokenConstructor | RGXTokenTypeGuardInput[];
15
+ export type RGXTokenTypeGuardInput = RGXTokenTypeFlat | null | RGXClassTokenConstructor | typeof ExtRegExp | RGXTokenTypeGuardInput[];
15
16
  export type RGXTokenFromType<T extends RGXTokenTypeGuardInput> = T extends null ? RGXToken : T extends 'no-op' ? RGXNoOpToken : T extends 'literal' ? RGXLiteralToken : T extends 'native' ? RGXNativeToken : T extends 'convertible' ? RGXConvertibleToken : T extends 'class' ? RGXClassToken : T extends 'array' ? RGXToken[] : T extends RGXTokenTypeGuardInput[] ? {
16
17
  [K in keyof T]: T[K] extends RGXTokenTypeGuardInput ? RGXTokenFromType<T[K]> : never;
17
- } : T extends RGXClassTokenConstructor ? InstanceType<T> : never;
18
+ } : T extends RGXClassTokenConstructor ? InstanceType<T> : T extends typeof ExtRegExp ? ExtRegExp : never;
18
19
  export type RangeObject = {
19
20
  min?: number | null;
20
21
  max?: number | null;
@@ -27,6 +28,9 @@ export type ValidRegexString = Branded<string, [ValidRegexBrandSymbol]>;
27
28
  export declare const validVanillaRegexFlagsSymbol: unique symbol;
28
29
  export type ValidVanillaRegexFlagsBrandSymbol = typeof validVanillaRegexFlagsSymbol;
29
30
  export type ValidVanillaRegexFlags = Branded<string, [ValidVanillaRegexFlagsBrandSymbol]>;
31
+ export declare const validRegexFlagsSymbol: unique symbol;
32
+ export type ValidRegexFlagsBrandSymbol = typeof validRegexFlagsSymbol;
33
+ export type ValidRegexFlags = Branded<string, [ValidRegexFlagsBrandSymbol]> | ValidVanillaRegexFlags;
30
34
  export declare const validIdentifierSymbol: unique symbol;
31
35
  export type ValidIdentifierBrandSymbol = typeof validIdentifierSymbol;
32
36
  export type ValidIdentifier = Branded<string, [ValidIdentifierBrandSymbol]>;
package/dist/types.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validIdentifierSymbol = exports.validVanillaRegexFlagsSymbol = exports.validRegexSymbol = void 0;
3
+ exports.validIdentifierSymbol = exports.validRegexFlagsSymbol = exports.validVanillaRegexFlagsSymbol = exports.validRegexSymbol = void 0;
4
4
  exports.validRegexSymbol = Symbol('rgx.ValidRegex');
5
5
  exports.validVanillaRegexFlagsSymbol = Symbol('rgx.ValidVanillaRegexFlags');
6
+ exports.validRegexFlagsSymbol = Symbol('rgx.ValidRegexFlags');
6
7
  exports.validIdentifierSymbol = Symbol('rgx.ValidIdentifier');
@@ -1 +1,2 @@
1
+ export declare function normalizeRegexFlags(flags: string): string;
1
2
  export declare function normalizeVanillaRegexFlags(flags: string): string;
@@ -1,14 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeRegexFlags = normalizeRegexFlags;
3
4
  exports.normalizeVanillaRegexFlags = normalizeVanillaRegexFlags;
4
5
  const errors_1 = require("../errors");
5
- function normalizeVanillaRegexFlags(flags) {
6
- const validFlags = ['g', 'i', 'm', 's', 'u', 'y'];
6
+ const ExtRegExp_1 = require("../ExtRegExp");
7
+ const typeGuards_1 = require("../typeGuards");
8
+ function normalizeRegexFlags(flags) {
7
9
  const seenFlags = new Set();
8
10
  let normalizedFlags = '';
9
11
  for (const flag of flags) {
10
- if (!validFlags.includes(flag)) {
11
- throw new errors_1.RGXInvalidVanillaRegexFlagsError(`[${flag}] is not valid.`, flags);
12
+ if (!(0, ExtRegExp_1.isValidRegexFlags)(flag)) {
13
+ throw new errors_1.RGXInvalidRegexFlagsError(`[${flag}] is not valid.`, flags);
12
14
  }
13
15
  if (!seenFlags.has(flag)) {
14
16
  seenFlags.add(flag);
@@ -17,3 +19,12 @@ function normalizeVanillaRegexFlags(flags) {
17
19
  }
18
20
  return normalizedFlags;
19
21
  }
22
+ function normalizeVanillaRegexFlags(flags) {
23
+ for (const flag of flags) {
24
+ if (!(0, typeGuards_1.isValidVanillaRegexFlags)(flag)) {
25
+ throw new errors_1.RGXInvalidVanillaRegexFlagsError(`[${flag}] is not a valid vanilla regex flag.`, flags);
26
+ }
27
+ }
28
+ // This will not throw, as all vanilla flags are valid regex flags.
29
+ return normalizeRegexFlags(flags);
30
+ }
@@ -1 +1,2 @@
1
- export declare function regexWithFlags(exp: RegExp, flags: string, replace?: boolean): RegExp;
1
+ import { ExtRegExp } from "../ExtRegExp";
2
+ export declare function regexWithFlags(exp: RegExp | ExtRegExp, flags: string, replace?: boolean): ExtRegExp;
@@ -3,11 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.regexWithFlags = regexWithFlags;
4
4
  const typeGuards_1 = require("../typeGuards");
5
5
  const normalizeRegexFlags_1 = require("./normalizeRegexFlags");
6
+ const ExtRegExp_1 = require("../ExtRegExp");
6
7
  function regexWithFlags(exp, flags, replace = false) {
7
8
  (0, typeGuards_1.assertValidVanillaRegexFlags)(flags);
8
9
  if (replace)
9
- return new RegExp(exp.source, flags);
10
+ return new ExtRegExp_1.ExtRegExp(exp.source, flags);
10
11
  const existingFlags = exp.flags;
11
12
  const newFlags = existingFlags + flags;
12
- return new RegExp(exp.source, (0, normalizeRegexFlags_1.normalizeVanillaRegexFlags)(newFlags));
13
+ return new ExtRegExp_1.ExtRegExp(exp.source, (0, normalizeRegexFlags_1.normalizeVanillaRegexFlags)(newFlags));
13
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ptolemy2002/rgx",
3
- "version": "4.2.0",
3
+ "version": "4.3.0",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",