@ptolemy2002/rgx 5.1.0 → 5.2.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
@@ -12,12 +12,18 @@ import { CloneDepth } from "@ptolemy2002/immutability-utils";
12
12
  type RGXNoOpToken = null | undefined;
13
13
  type RGXLiteralToken = RegExp;
14
14
  type RGXNativeToken = string | number | boolean | RGXNoOpToken;
15
- type RGXConvertibleToken = { toRgx: () => RGXToken, readonly rgxGroupWrap?: boolean, readonly rgxIsGroup?: boolean, readonly rgxIsRepeatable?: boolean };
15
+ type RGXConvertibleToken = {
16
+ toRgx: () => RGXToken,
17
+ rgxAcceptInsertion?: (tokens: RGXToken[], flags: ValidRegexFlags) => string | boolean,
18
+ readonly rgxGroupWrap?: boolean,
19
+ readonly rgxIsGroup?: boolean,
20
+ readonly rgxIsRepeatable?: boolean
21
+ };
16
22
  type RGXToken = RGXNativeToken | RGXLiteralToken | RGXConvertibleToken | RGXToken[];
17
23
 
18
24
  type RGXClassTokenConstructor = new (...args: unknown[]) => RGXClassToken;
19
25
  type RGXGroupedToken = RGXToken[] | RGXLiteralToken | RGXGroupedConvertibleToken;
20
- type RGXGroupedConvertibleToken = (RGXConvertibleToken & { readonly rgxIsGroup: true }) | (Omit<RGXConvertibleToken, "toRGX"> & { toRgx: () => RGXGroupedToken, readonly rgxGroupWrap: true });
26
+ type RGXGroupedConvertibleToken = (RGXConvertibleToken & { readonly rgxIsGroup: true }) | (Omit<RGXConvertibleToken, "toRgx"> & { toRgx: () => RGXGroupedToken, readonly rgxGroupWrap: true });
21
27
 
22
28
  const validRegexSymbol = Symbol('rgx.ValidRegex');
23
29
  type ValidRegexBrandSymbol = typeof validRegexSymbol;
@@ -48,7 +54,7 @@ type RGXTokenFromType<T extends RGXTokenTypeGuardInput> =
48
54
  // ... see source for full definition
49
55
  ;
50
56
 
51
- type RGXErrorCode = 'UNKNOWN' | 'INVALID_RGX_TOKEN' | 'INVALID_REGEX_STRING' | 'INVALID_REGEX_FLAGS' | 'INVALID_VANILLA_REGEX_FLAGS' | 'NOT_IMPLEMENTED' | 'NOT_SUPPORTED' | 'INVALID_IDENTIFIER' | 'OUT_OF_BOUNDS' | 'INVALID_FLAG_TRANSFORMER_KEY' | 'FLAG_TRANSFORMER_CONFLICT';
57
+ type RGXErrorCode = 'UNKNOWN' | 'INVALID_RGX_TOKEN' | 'INVALID_REGEX_STRING' | 'INVALID_REGEX_FLAGS' | 'INVALID_VANILLA_REGEX_FLAGS' | 'NOT_IMPLEMENTED' | 'NOT_SUPPORTED' | 'INVALID_IDENTIFIER' | 'OUT_OF_BOUNDS' | 'INVALID_FLAG_TRANSFORMER_KEY' | 'FLAG_TRANSFORMER_CONFLICT' | 'INSERTION_REJECTED';
52
58
 
53
59
  type RangeObject = {
54
60
  min?: number | null;
@@ -212,6 +218,19 @@ constructor(message: string, got: string)
212
218
  #### Properties
213
219
  - `got` (`string`): The conflicting key string.
214
220
 
221
+ ### RGXInsertionRejectedError extends RGXError
222
+ A specific error class for token insertion rejection. This error is thrown when a convertible token's `rgxAcceptInsertion` method returns `false` or a string (rejection reason) during pattern construction via `rgx`, `rgxa`, or `rgxConcat`. The error code is set to `INSERTION_REJECTED` on instantiation.
223
+
224
+ #### Constructor
225
+ ```typescript
226
+ constructor(reason?: string | null, message?: string | null)
227
+ ```
228
+ - `reason` (`string | null`, optional): The reason the insertion was rejected. Defaults to `null`.
229
+ - `message` (`string | null`, optional): An optional additional message providing more context. Defaults to `null`.
230
+
231
+ #### Properties
232
+ - `reason` (`string | null`): The reason the insertion was rejected, or `null` if no reason was provided.
233
+
215
234
  ### RGXOutOfBoundsError extends RGXError
216
235
  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.
217
236
 
@@ -284,6 +303,7 @@ An abstract base class for creating custom RGX token classes. Subclasses must im
284
303
  - `rgxGroupWrap` (`boolean`): Returns `true` by default. Controls whether the resolver wraps this token's resolved output in a non-capturing group. Subclasses can override this to prevent double-wrapping (e.g., when the token already wraps itself in a group).
285
304
 
286
305
  #### Methods
306
+ - `rgxAcceptInsertion(tokens: RGXToken[], flags: ValidRegexFlags) => string | boolean`: Called during pattern construction (via `rgx`, `rgxa`, or `rgxConcat`) to allow the token to reject its own insertion based on the surrounding tokens and the pattern's flags. Returns `true` to accept insertion (the default), `false` to reject with no reason, or a string to reject with a reason message. When a token rejects insertion, an `RGXInsertionRejectedError` is thrown. Subclasses can override this to enforce constraints such as requiring certain flags to be present.
287
307
  - `or(...others: RGXTokenCollectionInput[]) => RGXClassUnionToken`: Creates an `RGXClassUnionToken` that represents a union (alternation) of this token with the provided others. If any of the `others` are `RGXClassUnionToken` instances, their tokens are flattened into the union rather than nested. If `this` is already an `RGXClassUnionToken`, its existing tokens are preserved and the others are appended.
288
308
  - `group(args?: RGXGroupTokenArgs) => RGXGroupToken`: Wraps this token in an `RGXGroupToken` with the provided arguments. The `args` parameter defaults to `{}`, which creates a capturing group with no name. This is a convenience method that creates a new `RGXGroupToken` with `this` as the sole token.
289
309
  - `repeat(min?: number, max?: number | null, lazy?: boolean) => RGXRepeatToken`: Wraps this token in an `RGXRepeatToken` with the given repetition bounds. `min` defaults to `1`, `max` defaults to `min`, `lazy` defaults to `false`. Pass `null` for `max` to allow unlimited repetitions. When `lazy` is `true`, the resulting quantifier will be non-greedy. This is a convenience method that creates a new `RGXRepeatToken` with `this` as the token. Throws `RGXNotSupportedError` if called on a token with `rgxIsRepeatable` set to `false` (e.g., `RGXLookaroundToken`).
@@ -576,11 +596,11 @@ Asserts that the given value is a native token (string, number, boolean, or no-o
576
596
  function isRGXConvertibleToken(value: unknown, returnCheck?: boolean): value is RGXConvertibleToken
577
597
  ```
578
598
 
579
- Checks if the given value is a convertible token (an object with a `toRgx` method). If the `rgxGroupWrap`, `rgxIsRepeatable`, or `rgxIsGroup` properties are present, they must be booleans; otherwise, the check fails. When `returnCheck` is `true` (the default), also validates that `toRgx` is callable and returns a valid `RGXToken` (which can be any RGX token type, including other convertible tokens, allowing for recursive structures).
599
+ Checks if the given value is a convertible token (an object with a `toRgx` method). If the `rgxGroupWrap`, `rgxIsRepeatable`, or `rgxIsGroup` properties are present, they must be booleans; otherwise, the check fails. If the `rgxAcceptInsertion` property is present, it must be a callable that returns a `string` or `boolean`; otherwise, the check fails. Validates that `toRgx` is callable and returns a valid `RGXToken` (which can be any RGX token type, including other convertible tokens, allowing for recursive structures). When `returnCheck` is `false`, only checks for the presence and callability of function properties instead of also checking their return values.
580
600
 
581
601
  #### Parameters
582
602
  - `value` (`unknown`): The value to check.
583
- - `returnCheck` (`boolean`, optional): Whether to validate the return value of the `toRgx` method. Defaults to `true`. When `false`, only checks that `toRgx` exists and is callable. **Note**: Setting this to `false` makes the type guard assertion strictly unsafe, as it doesn't verify that the `toRgx` method actually returns a valid `RGXToken`. However, depending on the type of the value you're checking, you might not need that safety (e.g., when checking values that you know are valid based on other context).
603
+ - `returnCheck` (`boolean`, optional): Whether to validate the return value of the `toRgx` method. Defaults to `true`. When `false`, only checks that `toRgx` exists and is callable. **Note**: Setting this to `false` makes the type guard assertion strictly unsafe, as it doesn't verify that the methods actually return valid values. However, depending on the type of the value you're checking, you might not need that safety (e.g., when checking values that you know are valid based on other context).
584
604
 
585
605
  #### Returns
586
606
  - `boolean`: `true` if the value is a convertible token, otherwise `false`.
@@ -589,7 +609,7 @@ Checks if the given value is a convertible token (an object with a `toRgx` metho
589
609
  ```typescript
590
610
  function assertRGXConvertibleToken(value: unknown, returnCheck?: boolean): asserts value is RGXConvertibleToken
591
611
  ```
592
- Asserts that the given value is a convertible token (an object with a `toRgx` method). If the `rgxGroupWrap`, `rgxIsRepeatable`, or `rgxIsGroup` properties are present, they must be booleans; otherwise, the assertion fails. When `returnCheck` is `true` (the default), also validates that `toRgx` is callable and returns a valid `RGXToken` (which can be any RGX token type, including other convertible tokens, allowing for recursive structures). If the assertion fails, an `RGXInvalidTokenError` will be thrown.
612
+ Asserts that the given value is a convertible token (an object with a `toRgx` method). If the `rgxGroupWrap`, `rgxIsRepeatable`, or `rgxIsGroup` properties are present, they must be booleans; otherwise, the assertion fails. If the `rgxAcceptInsertion` property is present, it must be a callable that returns a `string` or `boolean`; otherwise, the assertion fails. When `returnCheck` is `true` (the default), also validates that `toRgx` is callable and returns a valid `RGXToken` (which can be any RGX token type, including other convertible tokens, allowing for recursive structures). If the assertion fails, an `RGXInvalidTokenError` will be thrown.
593
613
 
594
614
  #### Parameters
595
615
  - `value` (`unknown`): The value to assert.
@@ -892,7 +912,7 @@ For convertible tokens, if the token has an `rgxGroupWrap` property, that value
892
912
  function rgxConcat(tokens: RGXToken[], groupWrap?: boolean, currentFlags?: string): ValidRegexString
893
913
  ```
894
914
 
895
- A helper function that resolves an array of RGX tokens and concatenates their resolved string representations together. This is useful for cases where you want to concatenate multiple tokens without creating a union between them.
915
+ A helper function that resolves an array of RGX tokens and concatenates their resolved string representations together. This is useful for cases where you want to concatenate multiple tokens without creating a union between them. Before returning, any convertible token in the array that defines `rgxAcceptInsertion` is checked; if it returns `false` or a string, an `RGXInsertionRejectedError` is thrown.
896
916
 
897
917
  #### Parameters
898
918
  - `tokens` (`RGXToken[]`): The array of RGX tokens to resolve and concatenate.
@@ -907,7 +927,7 @@ A helper function that resolves an array of RGX tokens and concatenates their re
907
927
  function rgx(flags?: string): (strings: TemplateStringsArray, ...tokens: RGXToken[]) => ExtRegExp
908
928
  ```
909
929
 
910
- 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.
930
+ 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. Before constructing the pattern, any convertible token that defines `rgxAcceptInsertion` is checked; if it returns `false` or a string, an `RGXInsertionRejectedError` is thrown.
911
931
 
912
932
  The provided `flags` are passed as `currentFlags` to the resolver, enabling inline modifier groups for any `RegExp` literal tokens whose localizable flags (`i`, `m`, `s`) differ from the parent flags. For example, embedding `/foo/i` in a no-flag context produces `(?i:foo)`, while embedding `/bar/` in an `i`-flag context produces `(?-i:bar)`.
913
933
 
@@ -942,7 +962,7 @@ const pattern4 = rgx()`${beginning}${caseInsensitiveWord} world${end}`; // /^(?i
942
962
  ```typescript
943
963
  function rgxa(tokens: RGXToken[], flags?: string): ExtRegExp
944
964
  ```
945
- 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. Like `rgx`, the provided `flags` are passed as `currentFlags` to the resolver, enabling inline modifier groups for `RegExp` literal tokens whose localizable flags differ.
965
+ 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. Like `rgx`, the provided `flags` are passed as `currentFlags` to the resolver, enabling inline modifier groups for `RegExp` literal tokens whose localizable flags differ. Before constructing the pattern, any convertible token in the array that defines `rgxAcceptInsertion` is checked; if it returns `false` or a string, an `RGXInsertionRejectedError` is thrown.
946
966
 
947
967
  #### Parameters
948
968
  - `tokens` (`RGXToken[]`): The RGX tokens to be resolved and concatenated to form the regex pattern.
@@ -1,4 +1,4 @@
1
- import { RGXConvertibleToken, RGXToken, ValidRegexString } from "../types";
1
+ import { RGXConvertibleToken, RGXToken, ValidRegexFlags, ValidRegexString } from "../types";
2
2
  import { RGXTokenCollectionInput } from "../collection";
3
3
  import { CloneDepth } from "@ptolemy2002/immutability-utils";
4
4
  import type { RGXClassUnionToken } from "./union";
@@ -9,6 +9,7 @@ import type { RGXLookbehindToken } from "./lookbehind";
9
9
  export declare abstract class RGXClassToken implements RGXConvertibleToken {
10
10
  abstract toRgx(): RGXToken;
11
11
  abstract clone(depth?: CloneDepth): ThisType<this>;
12
+ rgxAcceptInsertion(tokens: RGXToken[], flags: ValidRegexFlags): string | boolean;
12
13
  static check: (value: unknown) => value is RGXClassToken;
13
14
  static assert: (value: unknown) => asserts value is RGXClassToken;
14
15
  get rgxIsGroup(): boolean;
@@ -4,6 +4,9 @@ exports.RGXClassToken = void 0;
4
4
  const errors_1 = require("../errors");
5
5
  const resolve_1 = require("../resolve");
6
6
  class RGXClassToken {
7
+ rgxAcceptInsertion(tokens, flags) {
8
+ return true;
9
+ }
7
10
  get rgxIsGroup() {
8
11
  return false;
9
12
  }
package/dist/concat.js CHANGED
@@ -1,8 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.rgxConcat = rgxConcat;
4
+ const internal_1 = require("./internal");
4
5
  const resolve_1 = require("./resolve");
5
6
  // Wrapper for letting an array of tokens be resolved as a concatenation instead of a union.
6
7
  function rgxConcat(tokens, groupWrap = true, currentFlags = '') {
7
- return tokens.map(t => (0, resolve_1.resolveRGXToken)(t, groupWrap, true, currentFlags)).join('');
8
+ const result = tokens.map(t => (0, resolve_1.resolveRGXToken)(t, groupWrap, true, currentFlags)).join('');
9
+ (0, internal_1.assureAcceptance)(tokens, currentFlags);
10
+ return result;
8
11
  }
@@ -1,4 +1,4 @@
1
- export type RGXErrorCode = 'UNKNOWN' | 'INVALID_RGX_TOKEN' | 'INVALID_REGEX_STRING' | 'INVALID_REGEX_FLAGS' | 'INVALID_VANILLA_REGEX_FLAGS' | 'NOT_IMPLEMENTED' | 'NOT_SUPPORTED' | 'INVALID_IDENTIFIER' | 'OUT_OF_BOUNDS' | 'INVALID_FLAG_TRANSFORMER_KEY' | 'FLAG_TRANSFORMER_CONFLICT';
1
+ export type RGXErrorCode = 'UNKNOWN' | 'INVALID_RGX_TOKEN' | 'INVALID_REGEX_STRING' | 'INVALID_REGEX_FLAGS' | 'INVALID_VANILLA_REGEX_FLAGS' | 'NOT_IMPLEMENTED' | 'NOT_SUPPORTED' | 'INVALID_IDENTIFIER' | 'OUT_OF_BOUNDS' | 'INVALID_FLAG_TRANSFORMER_KEY' | 'FLAG_TRANSFORMER_CONFLICT' | 'INSERTION_REJECTED';
2
2
  export declare class RGXError extends Error {
3
3
  _message: string;
4
4
  code: RGXErrorCode;
@@ -9,3 +9,4 @@ export * from './outOfBounds';
9
9
  export * from './invalidFlagTransformerKey';
10
10
  export * from './flagTransformerConflict';
11
11
  export * from './notSupported';
12
+ export * from './insertionRejected';
@@ -25,3 +25,4 @@ __exportStar(require("./outOfBounds"), exports);
25
25
  __exportStar(require("./invalidFlagTransformerKey"), exports);
26
26
  __exportStar(require("./flagTransformerConflict"), exports);
27
27
  __exportStar(require("./notSupported"), exports);
28
+ __exportStar(require("./insertionRejected"), exports);
@@ -0,0 +1,6 @@
1
+ import { RGXError } from "./base";
2
+ export declare class RGXInsertionRejectedError extends RGXError {
3
+ reason: string | null;
4
+ constructor(reason?: string | null, message?: string | null);
5
+ calcMessage(message: string): string;
6
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RGXInsertionRejectedError = void 0;
4
+ const base_1 = require("./base");
5
+ class RGXInsertionRejectedError extends base_1.RGXError {
6
+ constructor(reason = null, message = null) {
7
+ super(message || "", "INSERTION_REJECTED");
8
+ this.reason = null;
9
+ this.reason = reason;
10
+ this.name = "RGXInsertionRejectedError";
11
+ }
12
+ calcMessage(message) {
13
+ let result = `Insertion rejected`;
14
+ if (this.reason)
15
+ result += `; Reason: ${this.reason}`;
16
+ if (message)
17
+ result += `; Additional info: ${message}`;
18
+ return result;
19
+ }
20
+ }
21
+ exports.RGXInsertionRejectedError = RGXInsertionRejectedError;
package/dist/index.js CHANGED
@@ -38,6 +38,7 @@ __exportStar(require("./clone"), exports);
38
38
  (0, flag_transformer_1.registerCustomFlagTransformers)();
39
39
  function rgxa(tokens, flags = '') {
40
40
  (0, ExtRegExp_1.assertValidRegexFlags)(flags);
41
+ (0, internal_1.assureAcceptance)(tokens, flags);
41
42
  const pattern = (0, concat_1.rgxConcat)(tokens, true, flags);
42
43
  return (0, ExtRegExp_1.extRegExp)(pattern, flags);
43
44
  }
@@ -0,0 +1,2 @@
1
+ import { RGXToken, ValidRegexFlags } from "../types";
2
+ export declare function assureAcceptance(tokens: RGXToken[], flags: ValidRegexFlags): void;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assureAcceptance = assureAcceptance;
4
+ const errors_1 = require("../errors");
5
+ const typeGuards_1 = require("../typeGuards");
6
+ function assureAcceptance(tokens, flags) {
7
+ for (const token of tokens) {
8
+ if ((0, typeGuards_1.isRGXConvertibleToken)(token) && token.rgxAcceptInsertion) {
9
+ const messageOrAccepted = token.rgxAcceptInsertion(tokens, flags);
10
+ if (messageOrAccepted === true)
11
+ continue;
12
+ if (messageOrAccepted === false)
13
+ throw new errors_1.RGXInsertionRejectedError();
14
+ throw new errors_1.RGXInsertionRejectedError(messageOrAccepted);
15
+ }
16
+ }
17
+ }
@@ -3,3 +3,4 @@ export * from "./createClassGuardFunction";
3
3
  export * from "./taggedTemplateToArray";
4
4
  export * from "./isConstructor";
5
5
  export * from "./getProxy";
6
+ export * from "./assureAcceptance";
@@ -19,3 +19,4 @@ __exportStar(require("./createClassGuardFunction"), exports);
19
19
  __exportStar(require("./taggedTemplateToArray"), exports);
20
20
  __exportStar(require("./isConstructor"), exports);
21
21
  __exportStar(require("./getProxy"), exports);
22
+ __exportStar(require("./assureAcceptance"), exports);
@@ -98,6 +98,16 @@ function isRGXConvertibleToken(value, returnCheck = true) {
98
98
  return false;
99
99
  if ('rgxIsGroup' in value && typeof value.rgxIsGroup !== 'boolean')
100
100
  return false;
101
+ // If the rgxAcceptInsertion property exists, it must be a function that returns a string or boolean.
102
+ if ('rgxAcceptInsertion' in value) {
103
+ if (!(0, is_callable_1.default)(value.rgxAcceptInsertion))
104
+ return false;
105
+ if (returnCheck) {
106
+ const acceptResult = value.rgxAcceptInsertion([], '');
107
+ if (typeof acceptResult !== 'string' && typeof acceptResult !== 'boolean')
108
+ return false;
109
+ }
110
+ }
101
111
  if ((0, is_callable_1.default)(value.toRgx)) {
102
112
  if (!returnCheck)
103
113
  return true;
package/dist/types.d.ts CHANGED
@@ -7,6 +7,7 @@ export type RGXLiteralToken = RegExp;
7
7
  export type RGXNativeToken = string | number | boolean | RGXNoOpToken;
8
8
  export type RGXConvertibleToken = {
9
9
  toRgx: () => RGXToken;
10
+ rgxAcceptInsertion?: (tokens: RGXToken[], flags: ValidRegexFlags) => string | boolean;
10
11
  readonly rgxGroupWrap?: boolean;
11
12
  readonly rgxIsGroup?: boolean;
12
13
  readonly rgxIsRepeatable?: boolean;
@@ -16,7 +17,7 @@ export type RGXClassTokenConstructor = new (...args: unknown[]) => RGXClassToken
16
17
  export type RGXGroupedToken = RGXToken[] | RGXLiteralToken | RGXGroupedConvertibleToken;
17
18
  export type RGXGroupedConvertibleToken = (RGXConvertibleToken & {
18
19
  readonly rgxIsGroup: true;
19
- }) | (Omit<RGXConvertibleToken, "toRGX"> & {
20
+ }) | (Omit<RGXConvertibleToken, "toRgx"> & {
20
21
  toRgx: () => RGXGroupedToken;
21
22
  readonly rgxGroupWrap: true;
22
23
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ptolemy2002/rgx",
3
- "version": "5.1.0",
3
+ "version": "5.2.0",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",