@ptolemy2002/rgx 4.1.0 → 4.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
@@ -34,7 +34,14 @@ type RGXTokenFromType<T extends RGXTokenTypeGuardInput> =
34
34
  // ... see source for full definition
35
35
  ;
36
36
 
37
- type RGXErrorCode = 'UNKNOWN' | 'INVALID_RGX_TOKEN' | 'INVALID_REGEX_STRING' | 'INVALID_VANILLA_REGEX_FLAGS' | 'NOT_IMPLEMENTED' | 'INVALID_IDENTIFIER';
37
+ type RGXErrorCode = 'UNKNOWN' | 'INVALID_RGX_TOKEN' | 'INVALID_REGEX_STRING' | 'INVALID_VANILLA_REGEX_FLAGS' | 'NOT_IMPLEMENTED' | 'INVALID_IDENTIFIER' | 'OUT_OF_BOUNDS';
38
+
39
+ type RangeObject = {
40
+ min?: number | null;
41
+ max?: number | null;
42
+ inclusiveLeft?: boolean;
43
+ inclusiveRight?: boolean;
44
+ };
38
45
  type ExpectedTokenType = {
39
46
  type: "tokenType";
40
47
  values: RGXTokenTypeFlat[];
@@ -142,6 +149,33 @@ constructor(message: string, got: string)
142
149
  #### Methods
143
150
  - `toString() => string`: Returns a formatted string indicating the invalid identifier and the reason for failure.
144
151
 
152
+ ### RGXOutOfBoundsError extends RGXError
153
+ 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
+
155
+ #### Constructor
156
+ ```typescript
157
+ constructor(message: string, got: number, { min, max, inclusiveLeft, inclusiveRight }?: RangeObject)
158
+ ```
159
+ - `message` (`string`): The error message.
160
+ - `got` (`number`): The actual numeric value that was received, which fell outside the expected range.
161
+ - `min` (`number | null`, optional): The minimum bound of the range. Defaults to `null` (no minimum).
162
+ - `max` (`number | null`, optional): The maximum bound of the range. Defaults to `null` (no maximum). Setting `min` to a value greater than `max` will adjust `max` to equal `min`, and vice versa.
163
+ - `inclusiveLeft` (`boolean`, optional): Whether the minimum bound is inclusive. Defaults to `true`.
164
+ - `inclusiveRight` (`boolean`, optional): Whether the maximum bound is inclusive. Defaults to `true`.
165
+
166
+ #### Properties
167
+ - `got` (`number`): The actual numeric value that was received.
168
+ - `min` (`number | null`): The minimum bound of the range. Setting this to a value greater than `max` will adjust `max` to equal `min`.
169
+ - `max` (`number | null`): The maximum bound of the range. Setting this to a value less than `min` will adjust `min` to equal `max`.
170
+ - `inclusiveLeft` (`boolean`): Whether the minimum bound is inclusive.
171
+ - `inclusiveRight` (`boolean`): Whether the maximum bound is inclusive.
172
+
173
+ #### Methods
174
+ - `failedAtMin() => boolean`: Returns `true` if the `got` value is below the minimum bound (respecting `inclusiveLeft`), otherwise `false`. Returns `false` if `min` is `null`.
175
+ - `failedAtMax() => boolean`: Returns `true` if the `got` value is above the maximum bound (respecting `inclusiveRight`), otherwise `false`. Returns `false` if `max` is `null`.
176
+ - `failedAtAny() => boolean`: Returns `true` if the value failed at either the minimum or maximum bound.
177
+ - `toString() => string`: Returns a formatted string indicating the out-of-bounds value, the expected range, and which bound was violated.
178
+
145
179
  ### RGXTokenCollection
146
180
  A class representing a collection of RGX tokens. This class manages collections of RGX tokens like an array, but with additional metadata about the collection mode (union or concat). Since `toRgx()` returns a `RegExp`, instances of this class satisfy the `RGXConvertibleToken` interface and can be used directly as tokens in `rgx`, `rgxa`, and other token-accepting functions.
147
181
 
@@ -700,6 +734,81 @@ function rgxClassInit(): void
700
734
 
701
735
  Initializes internal method patches required for `RGXClassToken` subclass methods (such as `or` and `group`) to work correctly. This function is called automatically when importing from the main module entry point, so you typically do not need to call it yourself. It only needs to be called manually if you import directly from sub-modules.
702
736
 
737
+ ### isInRange
738
+ ```typescript
739
+ function isInRange(value: number, { min, max, inclusiveLeft, inclusiveRight }?: RangeObject): boolean
740
+ ```
741
+
742
+ Checks if the given numeric value falls within the specified range.
743
+
744
+ #### Parameters
745
+ - `value` (`number`): The value to check.
746
+ - `min` (`number | null`, optional): The minimum bound of the range. Defaults to `null` (no minimum).
747
+ - `max` (`number | null`, optional): The maximum bound of the range. Defaults to `null` (no maximum).
748
+ - `inclusiveLeft` (`boolean`, optional): Whether the minimum bound is inclusive. Defaults to `true`.
749
+ - `inclusiveRight` (`boolean`, optional): Whether the maximum bound is inclusive. Defaults to `true`.
750
+
751
+ #### Returns
752
+ - `boolean`: `true` if the value is within the specified range, otherwise `false`.
753
+
754
+ ### assertInRange
755
+ ```typescript
756
+ function assertInRange(value: number, range: RangeObject, message?: string): void
757
+ ```
758
+
759
+ Asserts that the given numeric value falls within the specified range. If the assertion fails, an `RGXOutOfBoundsError` will be thrown.
760
+
761
+ #### Parameters
762
+ - `value` (`number`): The value to assert.
763
+ - `range` (`RangeObject`): The range to check against.
764
+ - `message` (`string`, optional): A custom error message. Defaults to `"Value out of bounds"`.
765
+
766
+ #### Returns
767
+ - `void`: This function does not return a value, but will throw an error if the assertion fails.
768
+
769
+ ### normalizeVanillaRegexFlags
770
+ ```typescript
771
+ function normalizeVanillaRegexFlags(flags: string): string
772
+ ```
773
+
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.
775
+
776
+ #### Parameters
777
+ - `flags` (`string`): The flags string to normalize.
778
+
779
+ #### Returns
780
+ - `string`: The normalized flags string with duplicates removed.
781
+
782
+ ### regexWithFlags
783
+ ```typescript
784
+ function regexWithFlags(exp: RegExp, flags: string, replace?: boolean): RegExp
785
+ ```
786
+
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`.
788
+
789
+ #### Parameters
790
+ - `exp` (`RegExp`): The source regular expression.
791
+ - `flags` (`string`): The flags to add or replace with. Must be valid vanilla regex flags, or an `RGXInvalidVanillaRegexFlagsError` will be thrown.
792
+ - `replace` (`boolean`, optional): Whether to replace the existing flags entirely instead of merging. Defaults to `false`.
793
+
794
+ #### Returns
795
+ - `RegExp`: A new `RegExp` with the same source pattern and the resulting flags.
796
+
797
+ ### regexMatchAtPosition
798
+ ```typescript
799
+ function regexMatchAtPosition(regex: RegExp, str: string, position: number): boolean
800
+ ```
801
+
802
+ Tests whether the given regular expression matches at a specific position in the string. This is done by creating a sticky (`y` flag) copy of the regex and setting its `lastIndex` to the desired position. The position must be within the bounds of the string (>= 0 and < string length), or an `RGXOutOfBoundsError` will be thrown.
803
+
804
+ #### Parameters
805
+ - `regex` (`RegExp`): The regular expression to test.
806
+ - `str` (`string`): The string to test against.
807
+ - `position` (`number`): The zero-based index in the string at which to test the match. Must be >= 0 and < `str.length`.
808
+
809
+ #### Returns
810
+ - `boolean`: `true` if the regex matches at the specified position, otherwise `false`.
811
+
703
812
  ## Peer Dependencies
704
813
  - `@ptolemy2002/immutability-utils` ^2.0.0
705
814
  - `@ptolemy2002/js-utils` ^3.2.2
@@ -1,4 +1,4 @@
1
- export type RGXErrorCode = 'UNKNOWN' | 'INVALID_RGX_TOKEN' | 'INVALID_REGEX_STRING' | 'INVALID_VANILLA_REGEX_FLAGS' | 'NOT_IMPLEMENTED' | 'INVALID_IDENTIFIER';
1
+ export type RGXErrorCode = 'UNKNOWN' | 'INVALID_RGX_TOKEN' | 'INVALID_REGEX_STRING' | 'INVALID_VANILLA_REGEX_FLAGS' | 'NOT_IMPLEMENTED' | 'INVALID_IDENTIFIER' | 'OUT_OF_BOUNDS';
2
2
  export declare class RGXError extends Error {
3
3
  code: RGXErrorCode;
4
4
  constructor(message: string, code?: RGXErrorCode);
@@ -4,3 +4,4 @@ export * from './invalidRegexString';
4
4
  export * from './invalidVanillaRegexFlags';
5
5
  export * from './notImplemented';
6
6
  export * from './invalidIdentifier';
7
+ export * from './outOfBounds';
@@ -20,3 +20,4 @@ __exportStar(require("./invalidRegexString"), exports);
20
20
  __exportStar(require("./invalidVanillaRegexFlags"), exports);
21
21
  __exportStar(require("./notImplemented"), exports);
22
22
  __exportStar(require("./invalidIdentifier"), exports);
23
+ __exportStar(require("./outOfBounds"), exports);
@@ -0,0 +1,20 @@
1
+ import { RGXError } from "./base";
2
+ import { RangeObject } from "../types";
3
+ export declare class RGXOutOfBoundsError extends RGXError {
4
+ got: number;
5
+ _min: number | null;
6
+ _max: number | null;
7
+ inclusiveLeft: boolean;
8
+ inclusiveRight: boolean;
9
+ get min(): number | null;
10
+ set min(value: number | null);
11
+ get max(): number | null;
12
+ set max(value: number | null);
13
+ constructor(message: string, got: number, { min, max, inclusiveLeft, inclusiveRight }?: RangeObject);
14
+ failedAtMin(): boolean;
15
+ failedAtMax(): boolean;
16
+ failedAtAny(): boolean;
17
+ toString(): string;
18
+ }
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;
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RGXOutOfBoundsError = void 0;
4
+ exports.isInRange = isInRange;
5
+ exports.assertInRange = assertInRange;
6
+ const base_1 = require("./base");
7
+ class RGXOutOfBoundsError extends base_1.RGXError {
8
+ get min() {
9
+ return this._min;
10
+ }
11
+ set min(value) {
12
+ this._min = value;
13
+ if (this._max !== null && value !== null && value > this._max) {
14
+ this._max = value;
15
+ }
16
+ }
17
+ get max() {
18
+ return this._max;
19
+ }
20
+ set max(value) {
21
+ this._max = value;
22
+ if (this._min !== null && value !== null && value < this._min) {
23
+ this._min = value;
24
+ }
25
+ }
26
+ constructor(message, got, { min = null, max = null, inclusiveLeft = true, inclusiveRight = true } = {}) {
27
+ super(message, 'OUT_OF_BOUNDS');
28
+ this.name = 'RGXOutOfBoundsError';
29
+ this.got = got;
30
+ this.min = min;
31
+ this.max = max;
32
+ this.inclusiveLeft = inclusiveLeft;
33
+ this.inclusiveRight = inclusiveRight;
34
+ }
35
+ failedAtMin() {
36
+ return this.min !== null && (this.inclusiveLeft ? this.got < this.min : this.got <= this.min);
37
+ }
38
+ failedAtMax() {
39
+ return this.max !== null && (this.inclusiveRight ? this.got > this.max : this.got >= this.max);
40
+ }
41
+ failedAtAny() {
42
+ return this.failedAtMin() || this.failedAtMax();
43
+ }
44
+ toString() {
45
+ const rangeParts = [];
46
+ if (this.min !== null) {
47
+ if (this.inclusiveLeft)
48
+ rangeParts.push(`>= ${this.min}`);
49
+ else
50
+ rangeParts.push(`> ${this.min}`);
51
+ }
52
+ if (this.max !== null) {
53
+ if (this.inclusiveRight)
54
+ rangeParts.push(`<= ${this.max}`);
55
+ else
56
+ rangeParts.push(`< ${this.max}`);
57
+ }
58
+ const rangeStr = rangeParts.join(" and ");
59
+ // Determine which one was failed
60
+ if (!this.failedAtAny()) {
61
+ return `${this.name}: ${this.message}; Got: [${this.got}]; Expected: [${rangeStr}]`;
62
+ }
63
+ else if (this.failedAtMin()) {
64
+ let thirdPart;
65
+ if (!this.inclusiveLeft && this.got === this.min)
66
+ thirdPart = `${this.got} == ${this.min}`;
67
+ else
68
+ thirdPart = `${this.got} < ${this.min}`;
69
+ return `${this.name}: ${this.message}; Got: [${this.got}]; Expected: [${rangeStr}]; ${thirdPart}`;
70
+ }
71
+ else {
72
+ let thirdPart;
73
+ if (!this.inclusiveRight && this.got === this.max)
74
+ thirdPart = `${this.got} == ${this.max}`;
75
+ else
76
+ thirdPart = `${this.got} > ${this.max}`;
77
+ return `${this.name}: ${this.message}; Got: [${this.got}]; Expected: [${rangeStr}]; ${thirdPart}`;
78
+ }
79
+ }
80
+ }
81
+ exports.RGXOutOfBoundsError = RGXOutOfBoundsError;
82
+ function isInRange(value, { min = null, max = null, inclusiveLeft = true, inclusiveRight = true } = {}) {
83
+ if (min !== null) {
84
+ if (inclusiveLeft) {
85
+ if (value < min)
86
+ return false;
87
+ }
88
+ else {
89
+ if (value <= min)
90
+ return false;
91
+ }
92
+ }
93
+ if (max !== null) {
94
+ if (inclusiveRight) {
95
+ if (value > max)
96
+ return false;
97
+ }
98
+ else {
99
+ if (value >= max)
100
+ return false;
101
+ }
102
+ }
103
+ return true;
104
+ }
105
+ function assertInRange(value, range, message = "Value out of bounds") {
106
+ if (!isInRange(value, range)) {
107
+ throw new RGXOutOfBoundsError(message, value, range);
108
+ }
109
+ }
package/dist/index.d.ts CHANGED
@@ -6,5 +6,6 @@ export * from "./collection";
6
6
  export * from "./class";
7
7
  export * from "./resolve";
8
8
  export * from "./concat";
9
+ export * from "./utils";
9
10
  export declare function rgxa(tokens: t.RGXToken[], flags?: string): RegExp;
10
11
  export default function rgx(flags?: string): (strings: TemplateStringsArray, ...tokens: t.RGXToken[]) => RegExp;
package/dist/index.js CHANGED
@@ -49,6 +49,7 @@ __exportStar(require("./collection"), exports);
49
49
  __exportStar(require("./class"), exports);
50
50
  __exportStar(require("./resolve"), exports);
51
51
  __exportStar(require("./concat"), exports);
52
+ __exportStar(require("./utils"), exports);
52
53
  // Call this for certain class methods to work correctly
53
54
  (0, class_1.rgxClassInit)();
54
55
  function rgxa(tokens, flags = '') {
package/dist/types.d.ts CHANGED
@@ -15,6 +15,12 @@ export type RGXTokenTypeGuardInput = RGXTokenTypeFlat | null | RGXClassTokenCons
15
15
  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
16
  [K in keyof T]: T[K] extends RGXTokenTypeGuardInput ? RGXTokenFromType<T[K]> : never;
17
17
  } : T extends RGXClassTokenConstructor ? InstanceType<T> : never;
18
+ export type RangeObject = {
19
+ min?: number | null;
20
+ max?: number | null;
21
+ inclusiveLeft?: boolean;
22
+ inclusiveRight?: boolean;
23
+ };
18
24
  export declare const validRegexSymbol: unique symbol;
19
25
  export type ValidRegexBrandSymbol = typeof validRegexSymbol;
20
26
  export type ValidRegexString = Branded<string, [ValidRegexBrandSymbol]>;
@@ -0,0 +1,3 @@
1
+ export * from "./regexMatchAtPosition";
2
+ export * from "./regexWithFlags";
3
+ export * from "./normalizeRegexFlags";
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./regexMatchAtPosition"), exports);
18
+ __exportStar(require("./regexWithFlags"), exports);
19
+ __exportStar(require("./normalizeRegexFlags"), exports);
@@ -0,0 +1 @@
1
+ export declare function normalizeVanillaRegexFlags(flags: string): string;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeVanillaRegexFlags = normalizeVanillaRegexFlags;
4
+ const errors_1 = require("../errors");
5
+ function normalizeVanillaRegexFlags(flags) {
6
+ const validFlags = ['g', 'i', 'm', 's', 'u', 'y'];
7
+ const seenFlags = new Set();
8
+ let normalizedFlags = '';
9
+ for (const flag of flags) {
10
+ if (!validFlags.includes(flag)) {
11
+ throw new errors_1.RGXInvalidVanillaRegexFlagsError(`[${flag}] is not valid.`, flags);
12
+ }
13
+ if (!seenFlags.has(flag)) {
14
+ seenFlags.add(flag);
15
+ normalizedFlags += flag;
16
+ }
17
+ }
18
+ return normalizedFlags;
19
+ }
@@ -0,0 +1 @@
1
+ export declare function regexMatchAtPosition(regex: RegExp, str: string, position: number): boolean;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.regexMatchAtPosition = regexMatchAtPosition;
4
+ const outOfBounds_1 = require("../errors/outOfBounds");
5
+ const regexWithFlags_1 = require("./regexWithFlags");
6
+ function regexMatchAtPosition(regex, str, position) {
7
+ /*
8
+ The y flag means sticky mode, which means the next match must start at
9
+ lastIndex. By setting lastIndex to the position we want to check, we can test
10
+ if the regex matches at that position.
11
+ */
12
+ (0, outOfBounds_1.assertInRange)(position, { min: 0, max: str.length, inclusiveRight: false }, 'String index out of bounds');
13
+ const stickyRegex = (0, regexWithFlags_1.regexWithFlags)(regex, "y");
14
+ stickyRegex.lastIndex = position;
15
+ return stickyRegex.test(str);
16
+ }
@@ -0,0 +1 @@
1
+ export declare function regexWithFlags(exp: RegExp, flags: string, replace?: boolean): RegExp;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.regexWithFlags = regexWithFlags;
4
+ const typeGuards_1 = require("../typeGuards");
5
+ const normalizeRegexFlags_1 = require("./normalizeRegexFlags");
6
+ function regexWithFlags(exp, flags, replace = false) {
7
+ (0, typeGuards_1.assertValidVanillaRegexFlags)(flags);
8
+ if (replace)
9
+ return new RegExp(exp.source, flags);
10
+ const existingFlags = exp.flags;
11
+ const newFlags = existingFlags + flags;
12
+ return new RegExp(exp.source, (0, normalizeRegexFlags_1.normalizeVanillaRegexFlags)(newFlags));
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ptolemy2002/rgx",
3
- "version": "4.1.0",
3
+ "version": "4.2.0",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",