diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..55712c1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib" +} \ No newline at end of file diff --git a/docs/guide/matchers.md b/docs/guide/matchers.md index 4835e44..5baa9a6 100644 --- a/docs/guide/matchers.md +++ b/docs/guide/matchers.md @@ -4,28 +4,20 @@ We've previously discussed patterns and transformers. It's time to learn about how to use Obscenity to search for blacklisted terms in text, while respecting whitelisted terms. -Obscenity provides two matchers which implement this behavior, which are quite similar: the `RegExpMatcher` and the `NfaMatcher`. Both have their pros and cons, which we'll discuss briefly here. +To facilitate this, Obscenity provides the `RegExpMatcher`, which -- as the name suggests -- implements matching using regular expressions and string searching methods. At a high level, all it does is: -- The `RegExpMatcher` implements matching using regular expressions and string searching methods. At a high level, all it does is: - - ``` - apply transformations to text before matching whitelisted terms - find whitelisted terms in text - - apply transformations to text before matching blacklisted terms - for each blacklisted term - for all matches of the blacklisted term in the text - if a whitelisted term did not match this part of the text - emit match - ``` - - The `RegExpMatcher` is the implementation we recommend for most applications, as it performs better than the `NfaMatcher` on small - medium numbers of patterns and consumes less memory as well. - -- The `NfaMatcher` implements matching using finite automata (more specifically, it builds a heavily modified [Aho-Corasick automaton](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm) from the patterns and runs through the text once, walking the trie as it does so). - - It is, in theory, more efficient than the `RegExpMatcher` as it uses a single pass to match all the patterns, but the performance difference is only noticeable when you have a high number of patterns (> 100). Furthermore, as it has to build a trie from the patterns, it consumes more memory than the `RegExpMatcher` as well. +``` +apply transformations to text before matching whitelisted terms +find whitelisted terms in text + +apply transformations to text before matching blacklisted terms +for each blacklisted term + for all matches of the blacklisted term in the text + if a whitelisted term did not match this part of the text + emit match +``` -> **Note:** For the rest of this article, we will be using the `RegExpMatcher`, but it applies equally to the `NfaMatcher`. +For now, the `RegExpMatcher` is the only matcher implementation offered by Obscenity, though this may change in future versions. ## Providing matcher options diff --git a/docs/reference/README.md b/docs/reference/README.md index 80c7f5d..3e58498 100644 --- a/docs/reference/README.md +++ b/docs/reference/README.md @@ -11,7 +11,6 @@ obscenity ### Classes - [DataSet](classes/DataSet.md) -- [NfaMatcher](classes/NfaMatcher.md) - [ParserError](classes/ParserError.md) - [PhraseBuilder](classes/PhraseBuilder.md) - [RegExpMatcher](classes/RegExpMatcher.md) @@ -25,7 +24,6 @@ obscenity - [LiteralNode](interfaces/LiteralNode.md) - [MatchPayload](interfaces/MatchPayload.md) - [Matcher](interfaces/Matcher.md) -- [NfaMatcherOptions](interfaces/NfaMatcherOptions.md) - [OptionalNode](interfaces/OptionalNode.md) - [ParsedPattern](interfaces/ParsedPattern.md) - [PhraseContainer](interfaces/PhraseContainer.md) @@ -80,7 +78,7 @@ Context passed to [[TextCensorStrategy | text censoring strategies]]. #### Defined in -[src/censor/TextCensor.ts:104](https://github.com/jo3-l/obscenity/blob/563159b/src/censor/TextCensor.ts#L104) +[src/censor/TextCensor.ts:104](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/censor/TextCensor.ts#L104) ___ @@ -94,7 +92,7 @@ should be a set of characters that map to the transformed character. #### Defined in -[src/transformer/remap-characters/index.ts:60](https://github.com/jo3-l/obscenity/blob/563159b/src/transformer/remap-characters/index.ts#L60) +[src/transformer/remap-characters/index.ts:60](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/transformer/remap-characters/index.ts#L60) ___ @@ -106,7 +104,7 @@ All the profane words that are included in the [[englishDataset | english datase #### Defined in -[src/preset/english.ts:377](https://github.com/jo3-l/obscenity/blob/563159b/src/preset/english.ts#L377) +[src/preset/english.ts:377](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/preset/english.ts#L377) ___ @@ -124,7 +122,7 @@ Extends the default match payload by adding phrase metadata. #### Defined in -[src/dataset/DataSet.ts:199](https://github.com/jo3-l/obscenity/blob/563159b/src/dataset/DataSet.ts#L199) +[src/dataset/DataSet.ts:190](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/dataset/DataSet.ts#L190) ___ @@ -136,7 +134,7 @@ All the possible kinds of nodes. #### Defined in -[src/pattern/Nodes.ts:24](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Nodes.ts#L24) +[src/pattern/Nodes.ts:24](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Nodes.ts#L24) ___ @@ -163,7 +161,7 @@ replacement string. #### Defined in -[src/censor/TextCensor.ts:99](https://github.com/jo3-l/obscenity/blob/563159b/src/censor/TextCensor.ts#L99) +[src/censor/TextCensor.ts:99](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/censor/TextCensor.ts#L99) ## Variables @@ -224,7 +222,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #### Defined in -[src/preset/english.ts:103](https://github.com/jo3-l/obscenity/blob/563159b/src/preset/english.ts#L103) +[src/preset/english.ts:103](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/preset/english.ts#L103) ___ @@ -237,20 +235,20 @@ A set of transformers to be used when matching blacklisted patterns with the #### Defined in -[src/preset/english.ts:14](https://github.com/jo3-l/obscenity/blob/563159b/src/preset/english.ts#L14) +[src/preset/english.ts:14](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/preset/english.ts#L14) ___ ### englishRecommendedTransformers -• `Const` **englishRecommendedTransformers**: `Pick`<[`NfaMatcherOptions`](interfaces/NfaMatcherOptions.md), ``"blacklistMatcherTransformers"`` \| ``"whitelistMatcherTransformers"``\> +• `Const` **englishRecommendedTransformers**: `Pick`<[`RegExpMatcherOptions`](interfaces/RegExpMatcherOptions.md), ``"blacklistMatcherTransformers"`` \| ``"whitelistMatcherTransformers"``\> Recommended transformers to be used with the [[englishDataset | english word -dataset]] and the [[RegExpMatcher]] or the [[NfaMatcher]]. +dataset]] and the [[RegExpMatcher]]. #### Defined in -[src/preset/english.ts:48](https://github.com/jo3-l/obscenity/blob/563159b/src/preset/english.ts#L48) +[src/preset/english.ts:48](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/preset/english.ts#L48) ___ @@ -263,7 +261,7 @@ A set of transformers to be used when matching whitelisted terms with the #### Defined in -[src/preset/english.ts:36](https://github.com/jo3-l/obscenity/blob/563159b/src/preset/english.ts#L36) +[src/preset/english.ts:36](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/preset/english.ts#L36) ___ @@ -275,7 +273,7 @@ The current version of the library, formatted as `MAJOR.MINOR.PATCH`. #### Defined in -[src/index.ts:28](https://github.com/jo3-l/obscenity/blob/563159b/src/index.ts#L28) +[src/index.ts:27](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/index.ts#L27) ## Functions @@ -310,11 +308,11 @@ const matcher = new RegExpMatcher({ [`BlacklistedTerm`](interfaces/BlacklistedTerm.md)[] A list of blacklisted terms with valid IDs which can then be passed -to the [[RegExpMatcher]] or [[NfaMatcher]]. +to the [[RegExpMatcher]]. #### Defined in -[src/matcher/BlacklistedTerm.ts:37](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/BlacklistedTerm.ts#L37) +[src/matcher/BlacklistedTerm.ts:37](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/BlacklistedTerm.ts#L37) ___ @@ -341,7 +339,7 @@ A [[TextCensorStrategy]] for use with the [[TextCensor]]. #### Defined in -[src/censor/BuiltinStrategies.ts:71](https://github.com/jo3-l/obscenity/blob/563159b/src/censor/BuiltinStrategies.ts#L71) +[src/censor/BuiltinStrategies.ts:71](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/censor/BuiltinStrategies.ts#L71) ___ @@ -400,11 +398,11 @@ const matcher = new RegExpMatcher({ ..., blacklistMatcherTransformers: [transfor `StatefulTransformerContainer` A container holding the transformer, which can then be passed to the -[[RegExpMatcher]] or the [[NfaMatcher]]. +[[RegExpMatcher]]. #### Defined in -[src/transformer/collapse-duplicates/index.ts:46](https://github.com/jo3-l/obscenity/blob/563159b/src/transformer/collapse-duplicates/index.ts#L46) +[src/transformer/collapse-duplicates/index.ts:46](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/transformer/collapse-duplicates/index.ts#L46) ___ @@ -445,7 +443,7 @@ than the first. #### Defined in -[src/matcher/MatchPayload.ts:57](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/MatchPayload.ts#L57) +[src/matcher/MatchPayload.ts:57](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/MatchPayload.ts#L57) ___ @@ -479,7 +477,7 @@ A [[TextCensorStrategy]] for use with the [[TextCensor]]. #### Defined in -[src/censor/BuiltinStrategies.ts:134](https://github.com/jo3-l/obscenity/blob/563159b/src/censor/BuiltinStrategies.ts#L134) +[src/censor/BuiltinStrategies.ts:134](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/censor/BuiltinStrategies.ts#L134) ___ @@ -523,7 +521,7 @@ A [[TextCensorStrategy]] for use with the [[TextCensor]]. #### Defined in -[src/censor/BuiltinStrategies.ts:115](https://github.com/jo3-l/obscenity/blob/563159b/src/censor/BuiltinStrategies.ts#L115) +[src/censor/BuiltinStrategies.ts:115](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/censor/BuiltinStrategies.ts#L115) ___ @@ -552,7 +550,7 @@ A [[TextCensorStrategy]] for use with the [[TextCensor]]. #### Defined in -[src/censor/BuiltinStrategies.ts:89](https://github.com/jo3-l/obscenity/blob/563159b/src/censor/BuiltinStrategies.ts#L89) +[src/censor/BuiltinStrategies.ts:89](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/censor/BuiltinStrategies.ts#L89) ___ @@ -586,7 +584,7 @@ A [[TextCensorStrategy]] for use with the [[TextCensor]]. #### Defined in -[src/censor/BuiltinStrategies.ts:51](https://github.com/jo3-l/obscenity/blob/563159b/src/censor/BuiltinStrategies.ts#L51) +[src/censor/BuiltinStrategies.ts:51](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/censor/BuiltinStrategies.ts#L51) ___ @@ -631,7 +629,7 @@ A [[TextCensorStrategy]] for use with the [[TextCensor]]. #### Defined in -[src/censor/BuiltinStrategies.ts:28](https://github.com/jo3-l/obscenity/blob/563159b/src/censor/BuiltinStrategies.ts#L28) +[src/censor/BuiltinStrategies.ts:28](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/censor/BuiltinStrategies.ts#L28) ___ @@ -662,11 +660,11 @@ pattern. [`ParsedPattern`](interfaces/ParsedPattern.md) The parsed pattern, which can then be used with the -[[RegExpMatcher]] or the [[NfaMatcher]]. +[[RegExpMatcher]]. #### Defined in -[src/pattern/Pattern.ts:130](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Pattern.ts#L130) +[src/pattern/Pattern.ts:130](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Pattern.ts#L130) ___ @@ -795,11 +793,11 @@ using a template tag. [`ParsedPattern`](interfaces/ParsedPattern.md) The parsed pattern, which can then be used with the -[[RegExpMatcher]] or the [[NfaMatcher]]. +[[RegExpMatcher]]. #### Defined in -[src/pattern/Pattern.ts:106](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Pattern.ts#L106) +[src/pattern/Pattern.ts:106](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Pattern.ts#L106) ___ @@ -833,7 +831,7 @@ A [[TextCensorStrategy]] for use with the [[TextCensor]]. #### Defined in -[src/censor/BuiltinStrategies.ts:155](https://github.com/jo3-l/obscenity/blob/563159b/src/censor/BuiltinStrategies.ts#L155) +[src/censor/BuiltinStrategies.ts:155](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/censor/BuiltinStrategies.ts#L155) ___ @@ -889,11 +887,11 @@ const matcher = new RegExpMatcher({ ..., blacklistMatcherTransformers: [transfor `SimpleTransformerContainer` A container holding the transformer, which can then be passed to the -[[RegExpMatcher]] or the [[NfaMatcher]]. +[[RegExpMatcher]]. #### Defined in -[src/transformer/remap-characters/index.ts:38](https://github.com/jo3-l/obscenity/blob/563159b/src/transformer/remap-characters/index.ts#L38) +[src/transformer/remap-characters/index.ts:38](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/transformer/remap-characters/index.ts#L38) ___ @@ -922,11 +920,11 @@ const matcher = new RegExpMatcher({ ..., blacklistMatcherTransformers: [transfor `SimpleTransformerContainer` A container holding the transformer, which can then be passed to the -[[RegExpMatcher]] or the [[NfaMatcher]]. +[[RegExpMatcher]]. #### Defined in -[src/transformer/resolve-confusables/index.ts:22](https://github.com/jo3-l/obscenity/blob/563159b/src/transformer/resolve-confusables/index.ts#L22) +[src/transformer/resolve-confusables/index.ts:22](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/transformer/resolve-confusables/index.ts#L22) ___ @@ -956,11 +954,11 @@ const matcher = new RegExpMatcher({ ..., blacklistMatcherTransformers: [transfor `SimpleTransformerContainer` A container holding the transformer, which can then be passed to the -[[RegExpMatcher]] or the [[NfaMatcher]]. +[[RegExpMatcher]]. #### Defined in -[src/transformer/resolve-leetspeak/index.ts:23](https://github.com/jo3-l/obscenity/blob/563159b/src/transformer/resolve-leetspeak/index.ts#L23) +[src/transformer/resolve-leetspeak/index.ts:23](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/transformer/resolve-leetspeak/index.ts#L23) ___ @@ -990,11 +988,11 @@ const matcher = new RegExpMatcher({ ..., blacklistMatcherTransformers: [transfor `SimpleTransformerContainer` A container holding the transformer, which can then be passed to the -[[RegExpMatcher]] or the [[NfaMatcher]]. +[[RegExpMatcher]]. #### Defined in -[src/transformer/skip-non-alphabetic/index.ts:23](https://github.com/jo3-l/obscenity/blob/563159b/src/transformer/skip-non-alphabetic/index.ts#L23) +[src/transformer/skip-non-alphabetic/index.ts:23](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/transformer/skip-non-alphabetic/index.ts#L23) ___ @@ -1017,8 +1015,8 @@ of varying cases. `SimpleTransformerContainer` A container holding the transformer, which can then be passed to the -[[RegExpMatcher]] or the [[NfaMatcher]]. +[[RegExpMatcher]]. #### Defined in -[src/transformer/to-ascii-lowercase/index.ts:18](https://github.com/jo3-l/obscenity/blob/563159b/src/transformer/to-ascii-lowercase/index.ts#L18) +[src/transformer/to-ascii-lowercase/index.ts:18](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/transformer/to-ascii-lowercase/index.ts#L18) diff --git a/docs/reference/classes/DataSet.md b/docs/reference/classes/DataSet.md index b757069..1d8203a 100644 --- a/docs/reference/classes/DataSet.md +++ b/docs/reference/classes/DataSet.md @@ -63,7 +63,7 @@ const customDataset = new DataSet().addAll(englishDataset); #### Defined in -[src/dataset/DataSet.ts:29](https://github.com/jo3-l/obscenity/blob/563159b/src/dataset/DataSet.ts#L29) +[src/dataset/DataSet.ts:29](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/dataset/DataSet.ts#L29) ___ @@ -96,16 +96,15 @@ const data = new DataSet<{ originalWord: string }>() #### Defined in -[src/dataset/DataSet.ts:75](https://github.com/jo3-l/obscenity/blob/563159b/src/dataset/DataSet.ts#L75) +[src/dataset/DataSet.ts:75](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/dataset/DataSet.ts#L75) ___ ### build -▸ **build**(): `Pick`<[`NfaMatcherOptions`](../interfaces/NfaMatcherOptions.md), ``"blacklistedTerms"`` \| ``"whitelistedTerms"``\> +▸ **build**(): `Pick`<[`RegExpMatcherOptions`](../interfaces/RegExpMatcherOptions.md), ``"blacklistedTerms"`` \| ``"whitelistedTerms"``\> -Returns the dataset in a format suitable for usage with the [[RegExpMatcher]] -or the [[NfaMatcher]]. +Returns the dataset in a format suitable for usage with the [[RegExpMatcher]]. **`Example`** @@ -117,23 +116,13 @@ const matcher = new RegExpMatcher({ }); ``` -**`Example`** - -```typescript -// With the NfaMatcher: -const matcher = new NfaMatcher({ - ...dataset.build(), - // additional options here -}); -``` - #### Returns -`Pick`<[`NfaMatcherOptions`](../interfaces/NfaMatcherOptions.md), ``"blacklistedTerms"`` \| ``"whitelistedTerms"``\> +`Pick`<[`RegExpMatcherOptions`](../interfaces/RegExpMatcherOptions.md), ``"blacklistedTerms"`` \| ``"whitelistedTerms"``\> #### Defined in -[src/dataset/DataSet.ts:127](https://github.com/jo3-l/obscenity/blob/563159b/src/dataset/DataSet.ts#L127) +[src/dataset/DataSet.ts:118](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/dataset/DataSet.ts#L118) ___ @@ -165,7 +154,7 @@ const phraseMetadata = matchesWithPhraseMetadata[0].phraseMetadata; #### Defined in -[src/dataset/DataSet.ts:94](https://github.com/jo3-l/obscenity/blob/563159b/src/dataset/DataSet.ts#L94) +[src/dataset/DataSet.ts:94](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/dataset/DataSet.ts#L94) ___ @@ -195,4 +184,4 @@ const customDataset = new DataSet<{ originalWord: string }>() #### Defined in -[src/dataset/DataSet.ts:46](https://github.com/jo3-l/obscenity/blob/563159b/src/dataset/DataSet.ts#L46) +[src/dataset/DataSet.ts:46](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/dataset/DataSet.ts#L46) diff --git a/docs/reference/classes/NfaMatcher.md b/docs/reference/classes/NfaMatcher.md deleted file mode 100644 index cb2e452..0000000 --- a/docs/reference/classes/NfaMatcher.md +++ /dev/null @@ -1,176 +0,0 @@ -[obscenity](../README.md) / NfaMatcher - -# Class: NfaMatcher - -An implementation of the [[Matcher]] interface using finite automata -techniques. - -It is theoretically faster than the [[RegExpMatcher]]: the `hasMatch()` and -`getAllMatches()` execute in time proportional only to that of the length of -the input text and the number of matches. In other words, it _theoretically_ -should not degrade in performance as you add more terms - matching with 100 -and 1000 patterns should have the same performance. It achieves this by -building a heavily modified [Aho-Corasick -automaton](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm) from -the input patterns. - -In practice, its high constant factors make it slower than the -[[RegExpMatcher]] until about ~100 patterns, at which point both -implementations have approximately the same performance. - -The regular-expression matcher should be preferred to this one if at all -possible, as it uses more memory and is only marginally faster at the scale -most users of this package are expected to use it at. However, it may be -appropriate if: - -- You have a large number of patterns (> 100); -- You expect to be matching on long text; -- You have benchmarked the implementations and found the [[NfaMatcher]] to be - noticeably faster. - -## Implements - -- [`Matcher`](../interfaces/Matcher.md) - -## Table of contents - -### Constructors - -- [constructor](NfaMatcher.md#constructor) - -### Methods - -- [getAllMatches](NfaMatcher.md#getallmatches) -- [hasMatch](NfaMatcher.md#hasmatch) - -## Constructors - -### constructor - -• **new NfaMatcher**(`options`) - -Creates a new [[NfaMatcher]] with the options given. - -**`Example`** - -```typescript -// Use the options provided by the English preset. -const matcher = new NfaMatcher({ - ...englishDataset.build(), - ...englishRecommendedTransformers, -}); -``` - -**`Example`** - -```typescript -// Simple matcher that only has blacklisted patterns. -const matcher = new NfaMatcher({ - blacklistedTerms: assignIncrementingIds([ - pattern`fuck`, - pattern`f?uck`, // wildcards (?) - pattern`bitch`, - pattern`b[i]tch` // optionals ([i] matches either "i" or "") - ]), -}); - -// Check whether some string matches any of the patterns. -const doesMatch = matcher.hasMatch('fuck you bitch'); -``` - -**`Example`** - -```typescript -// A more advanced example, with transformers and whitelisted terms. -const matcher = new NfaMatcher({ - blacklistedTerms: [ - { id: 1, pattern: pattern`penis` }, - { id: 2, pattern: pattern`fuck` }, - ], - whitelistedTerms: ['pen is'], - blacklistMatcherTransformers: [ - resolveConfusablesTransformer(), // '🅰' => 'a' - resolveLeetSpeakTransformer(), // '$' => 's' - foldAsciiCharCaseTransformer(), // case insensitive matching - skipNonAlphabeticTransformer(), // 'f.u...c.k' => 'fuck' - collapseDuplicatesTransformer(), // 'aaaa' => 'a' - ], -}); - -// Output all matches. -console.log(matcher.getAllMatches('fu.....uuuuCK the pen is mightier than the sword!')); -``` - -#### Parameters - -| Name | Type | Description | -| :------ | :------ | :------ | -| `options` | [`NfaMatcherOptions`](../interfaces/NfaMatcherOptions.md) | Options to use. | - -#### Defined in - -[src/matcher/nfa/NfaMatcher.ts:170](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/nfa/NfaMatcher.ts#L170) - -## Methods - -### getAllMatches - -▸ **getAllMatches**(`input`, `sorted?`): [`MatchPayload`](../interfaces/MatchPayload.md)[] - -Returns all matches of blacklisted terms in the text. - -If you only need to check for the presence of a match, and do not need -more specific information about the matches, use the `hasMatch()` method, -which is typically more efficient. - -#### Parameters - -| Name | Type | Default value | Description | -| :------ | :------ | :------ | :------ | -| `input` | `string` | `undefined` | Text to find profanities in. | -| `sorted` | `boolean` | `false` | Whether the resulting list of matches should be sorted using [[compareMatchByPositionAndId]]. Defaults to `false`. | - -#### Returns - -[`MatchPayload`](../interfaces/MatchPayload.md)[] - -A list of matches of the matcher on the text. The matches are -guaranteed to be sorted if and only if the `sorted` parameter is `true`, -otherwise, their order is unspecified. - -#### Implementation of - -[Matcher](../interfaces/Matcher.md).[getAllMatches](../interfaces/Matcher.md#getallmatches) - -#### Defined in - -[src/matcher/nfa/NfaMatcher.ts:202](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/nfa/NfaMatcher.ts#L202) - -___ - -### hasMatch - -▸ **hasMatch**(`input`): `boolean` - -Checks whether there is a match for any blacklisted term in the text. - -This is typically more efficient than calling `getAllMatches` and -checking the result, though it depends on the implementation. - -#### Parameters - -| Name | Type | Description | -| :------ | :------ | :------ | -| `input` | `string` | Text to check. | - -#### Returns - -`boolean` - -#### Implementation of - -[Matcher](../interfaces/Matcher.md).[hasMatch](../interfaces/Matcher.md#hasmatch) - -#### Defined in - -[src/matcher/nfa/NfaMatcher.ts:197](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/nfa/NfaMatcher.ts#L197) diff --git a/docs/reference/classes/ParserError.md b/docs/reference/classes/ParserError.md index 3ad63b5..17b7337 100644 --- a/docs/reference/classes/ParserError.md +++ b/docs/reference/classes/ParserError.md @@ -44,7 +44,7 @@ Error.constructor #### Defined in -[src/pattern/ParserError.ts:18](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/ParserError.ts#L18) +[src/pattern/ParserError.ts:18](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/ParserError.ts#L18) ## Properties @@ -57,7 +57,7 @@ Note that surrogate pairs are counted as 1 column wide, not 2. #### Defined in -[src/pattern/ParserError.ts:16](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/ParserError.ts#L16) +[src/pattern/ParserError.ts:16](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/ParserError.ts#L16) ___ @@ -69,7 +69,7 @@ The line on which the error occurred (one-based). #### Defined in -[src/pattern/ParserError.ts:10](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/ParserError.ts#L10) +[src/pattern/ParserError.ts:10](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/ParserError.ts#L10) ___ @@ -83,7 +83,7 @@ Error.message #### Defined in -node_modules/.pnpm/typescript@5.1.3/node_modules/typescript/lib/lib.es5.d.ts:1068 +node_modules/.pnpm/typescript@5.2.2/node_modules/typescript/lib/lib.es5.d.ts:1068 ___ @@ -97,7 +97,7 @@ Error.name #### Defined in -[src/pattern/ParserError.ts:5](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/ParserError.ts#L5) +[src/pattern/ParserError.ts:5](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/ParserError.ts#L5) ___ @@ -111,4 +111,4 @@ Error.stack #### Defined in -node_modules/.pnpm/typescript@5.1.3/node_modules/typescript/lib/lib.es5.d.ts:1069 +node_modules/.pnpm/typescript@5.2.2/node_modules/typescript/lib/lib.es5.d.ts:1069 diff --git a/docs/reference/classes/PhraseBuilder.md b/docs/reference/classes/PhraseBuilder.md index 564ad98..1855623 100644 --- a/docs/reference/classes/PhraseBuilder.md +++ b/docs/reference/classes/PhraseBuilder.md @@ -55,7 +55,7 @@ Associates a pattern with this phrase. #### Defined in -[src/dataset/DataSet.ts:158](https://github.com/jo3-l/obscenity/blob/563159b/src/dataset/DataSet.ts#L158) +[src/dataset/DataSet.ts:149](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/dataset/DataSet.ts#L149) ___ @@ -77,7 +77,7 @@ Associates a whitelisted pattern with this phrase. #### Defined in -[src/dataset/DataSet.ts:168](https://github.com/jo3-l/obscenity/blob/563159b/src/dataset/DataSet.ts#L168) +[src/dataset/DataSet.ts:159](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/dataset/DataSet.ts#L159) ___ @@ -94,7 +94,7 @@ Builds the phrase, returning a [[PhraseContainer]] for use with the #### Defined in -[src/dataset/DataSet.ts:187](https://github.com/jo3-l/obscenity/blob/563159b/src/dataset/DataSet.ts#L187) +[src/dataset/DataSet.ts:178](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/dataset/DataSet.ts#L178) ___ @@ -116,4 +116,4 @@ Associates some metadata with this phrase. #### Defined in -[src/dataset/DataSet.ts:178](https://github.com/jo3-l/obscenity/blob/563159b/src/dataset/DataSet.ts#L178) +[src/dataset/DataSet.ts:169](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/dataset/DataSet.ts#L169) diff --git a/docs/reference/classes/RegExpMatcher.md b/docs/reference/classes/RegExpMatcher.md index 99226d3..61d650b 100644 --- a/docs/reference/classes/RegExpMatcher.md +++ b/docs/reference/classes/RegExpMatcher.md @@ -5,13 +5,6 @@ An implementation of the [[Matcher]] interface using regular expressions and string searching methods. -It should be the default choice for users of this package, as though it is -theoretically slower than the more complex [[NfaMatcher]], it uses much less -memory and is more efficient for low/medium numbers of patterns. - -Refer to the documentation of the [[NfaMatcher]] class for further discussion -on when to choose that implementation over this one. - ## Implements - [`Matcher`](../interfaces/Matcher.md) @@ -93,7 +86,7 @@ console.log(matcher.getAllMatches('fu.....uuuuCK the pen is mightier than the sw #### Defined in -[src/matcher/regexp/RegExpMatcher.ts:81](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/regexp/RegExpMatcher.ts#L81) +[src/matcher/regexp/RegExpMatcher.ts:74](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/regexp/RegExpMatcher.ts#L74) ## Methods @@ -128,7 +121,7 @@ otherwise, their order is unspecified. #### Defined in -[src/matcher/regexp/RegExpMatcher.ts:93](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/regexp/RegExpMatcher.ts#L93) +[src/matcher/regexp/RegExpMatcher.ts:86](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/regexp/RegExpMatcher.ts#L86) ___ @@ -157,4 +150,4 @@ checking the result, though it depends on the implementation. #### Defined in -[src/matcher/regexp/RegExpMatcher.ts:123](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/regexp/RegExpMatcher.ts#L123) +[src/matcher/regexp/RegExpMatcher.ts:116](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/regexp/RegExpMatcher.ts#L116) diff --git a/docs/reference/classes/TextCensor.md b/docs/reference/classes/TextCensor.md index 85b8f57..e34e4b9 100644 --- a/docs/reference/classes/TextCensor.md +++ b/docs/reference/classes/TextCensor.md @@ -58,7 +58,7 @@ The censored text. #### Defined in -[src/censor/TextCensor.ts:66](https://github.com/jo3-l/obscenity/blob/563159b/src/censor/TextCensor.ts#L66) +[src/censor/TextCensor.ts:66](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/censor/TextCensor.ts#L66) ___ @@ -104,4 +104,4 @@ utility functions: #### Defined in -[src/censor/TextCensor.ts:41](https://github.com/jo3-l/obscenity/blob/563159b/src/censor/TextCensor.ts#L41) +[src/censor/TextCensor.ts:41](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/censor/TextCensor.ts#L41) diff --git a/docs/reference/enums/SyntaxKind.md b/docs/reference/enums/SyntaxKind.md index 539bb8e..af91d2e 100644 --- a/docs/reference/enums/SyntaxKind.md +++ b/docs/reference/enums/SyntaxKind.md @@ -21,7 +21,7 @@ An enumeration of the kinds of nodes there are. #### Defined in -[src/pattern/Nodes.ts:33](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Nodes.ts#L33) +[src/pattern/Nodes.ts:33](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Nodes.ts#L33) ___ @@ -31,7 +31,7 @@ ___ #### Defined in -[src/pattern/Nodes.ts:32](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Nodes.ts#L32) +[src/pattern/Nodes.ts:32](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Nodes.ts#L32) ___ @@ -41,7 +41,7 @@ ___ #### Defined in -[src/pattern/Nodes.ts:30](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Nodes.ts#L30) +[src/pattern/Nodes.ts:30](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Nodes.ts#L30) ___ @@ -51,4 +51,4 @@ ___ #### Defined in -[src/pattern/Nodes.ts:31](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Nodes.ts#L31) +[src/pattern/Nodes.ts:31](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Nodes.ts#L31) diff --git a/docs/reference/interfaces/BlacklistedTerm.md b/docs/reference/interfaces/BlacklistedTerm.md index dd6edf5..52ac446 100644 --- a/docs/reference/interfaces/BlacklistedTerm.md +++ b/docs/reference/interfaces/BlacklistedTerm.md @@ -21,7 +21,7 @@ The identifier of the pattern; should be unique across all patterns. #### Defined in -[src/matcher/BlacklistedTerm.ts:10](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/BlacklistedTerm.ts#L10) +[src/matcher/BlacklistedTerm.ts:10](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/BlacklistedTerm.ts#L10) ___ @@ -33,4 +33,4 @@ The parsed pattern. #### Defined in -[src/matcher/BlacklistedTerm.ts:15](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/BlacklistedTerm.ts#L15) +[src/matcher/BlacklistedTerm.ts:15](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/BlacklistedTerm.ts#L15) diff --git a/docs/reference/interfaces/BoundaryAssertionNode.md b/docs/reference/interfaces/BoundaryAssertionNode.md index 01c4262..0032616 100644 --- a/docs/reference/interfaces/BoundaryAssertionNode.md +++ b/docs/reference/interfaces/BoundaryAssertionNode.md @@ -18,4 +18,4 @@ A boundary assertion node. #### Defined in -[src/pattern/Nodes.ts:72](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Nodes.ts#L72) +[src/pattern/Nodes.ts:72](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Nodes.ts#L72) diff --git a/docs/reference/interfaces/CollapseDuplicatesTransformerOptions.md b/docs/reference/interfaces/CollapseDuplicatesTransformerOptions.md index f010251..4fb2198 100644 --- a/docs/reference/interfaces/CollapseDuplicatesTransformerOptions.md +++ b/docs/reference/interfaces/CollapseDuplicatesTransformerOptions.md @@ -37,7 +37,7 @@ new Map() #### Defined in -[src/transformer/collapse-duplicates/index.ts:91](https://github.com/jo3-l/obscenity/blob/563159b/src/transformer/collapse-duplicates/index.ts#L91) +[src/transformer/collapse-duplicates/index.ts:91](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/transformer/collapse-duplicates/index.ts#L91) ___ @@ -59,4 +59,4 @@ would be transformed to `aa`. #### Defined in -[src/transformer/collapse-duplicates/index.ts:102](https://github.com/jo3-l/obscenity/blob/563159b/src/transformer/collapse-duplicates/index.ts#L102) +[src/transformer/collapse-duplicates/index.ts:102](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/transformer/collapse-duplicates/index.ts#L102) diff --git a/docs/reference/interfaces/LiteralNode.md b/docs/reference/interfaces/LiteralNode.md index 4498d6c..25b9465 100644 --- a/docs/reference/interfaces/LiteralNode.md +++ b/docs/reference/interfaces/LiteralNode.md @@ -21,7 +21,7 @@ The code points that this literal matches. #### Defined in -[src/pattern/Nodes.ts:63](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Nodes.ts#L63) +[src/pattern/Nodes.ts:63](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Nodes.ts#L63) ___ @@ -31,4 +31,4 @@ ___ #### Defined in -[src/pattern/Nodes.ts:65](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Nodes.ts#L65) +[src/pattern/Nodes.ts:65](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Nodes.ts#L65) diff --git a/docs/reference/interfaces/MatchPayload.md b/docs/reference/interfaces/MatchPayload.md index d012c86..7d6b533 100644 --- a/docs/reference/interfaces/MatchPayload.md +++ b/docs/reference/interfaces/MatchPayload.md @@ -29,7 +29,7 @@ then this points to the index of the low surrogate. #### Defined in -[src/matcher/MatchPayload.ts:16](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/MatchPayload.ts#L16) +[src/matcher/MatchPayload.ts:16](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/MatchPayload.ts#L16) ___ @@ -41,7 +41,7 @@ Total number of of code points that matched. #### Defined in -[src/matcher/MatchPayload.ts:21](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/MatchPayload.ts#L21) +[src/matcher/MatchPayload.ts:21](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/MatchPayload.ts#L21) ___ @@ -53,7 +53,7 @@ Start index of the match, inclusive. #### Defined in -[src/matcher/MatchPayload.ts:26](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/MatchPayload.ts#L26) +[src/matcher/MatchPayload.ts:26](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/MatchPayload.ts#L26) ___ @@ -65,4 +65,4 @@ ID of the blacklisted term that matched. #### Defined in -[src/matcher/MatchPayload.ts:31](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/MatchPayload.ts#L31) +[src/matcher/MatchPayload.ts:31](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/MatchPayload.ts#L31) diff --git a/docs/reference/interfaces/Matcher.md b/docs/reference/interfaces/Matcher.md index 7a3a523..dd3da8e 100644 --- a/docs/reference/interfaces/Matcher.md +++ b/docs/reference/interfaces/Matcher.md @@ -6,15 +6,10 @@ Searches for blacklisted terms in text, ignoring parts matched by whitelisted terms. See: -- [[NfaMatcher]] for an implementation using finite automata; - [[RegExpMatcher]] for an implementation using regular expressions. -Refer to the documentation of the classes mentioned above for discussion of -which circumstances one should prefer one over the other. - ## Implemented by -- [`NfaMatcher`](../classes/NfaMatcher.md) - [`RegExpMatcher`](../classes/RegExpMatcher.md) ## Table of contents @@ -53,7 +48,7 @@ otherwise, their order is unspecified. #### Defined in -[src/matcher/Matcher.ts:29](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/Matcher.ts#L29) +[src/matcher/Matcher.ts:25](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/Matcher.ts#L25) ___ @@ -78,4 +73,4 @@ checking the result, though it depends on the implementation. #### Defined in -[src/matcher/Matcher.ts:39](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/Matcher.ts#L39) +[src/matcher/Matcher.ts:35](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/Matcher.ts#L35) diff --git a/docs/reference/interfaces/NfaMatcherOptions.md b/docs/reference/interfaces/NfaMatcherOptions.md deleted file mode 100644 index b149c98..0000000 --- a/docs/reference/interfaces/NfaMatcherOptions.md +++ /dev/null @@ -1,94 +0,0 @@ -[obscenity](../README.md) / NfaMatcherOptions - -# Interface: NfaMatcherOptions - -Options for the [[NfaMatcher]]. - -## Table of contents - -### Properties - -- [blacklistMatcherTransformers](NfaMatcherOptions.md#blacklistmatchertransformers) -- [blacklistedTerms](NfaMatcherOptions.md#blacklistedterms) -- [whitelistMatcherTransformers](NfaMatcherOptions.md#whitelistmatchertransformers) -- [whitelistedTerms](NfaMatcherOptions.md#whitelistedterms) - -## Properties - -### blacklistMatcherTransformers - -• `Optional` **blacklistMatcherTransformers**: `TransformerContainer`[] - -A set of transformers that should be applied to the input text before -blacklisted patterns are matched. This does not affect the matching of -whitelisted terms. - -Transformers will be applied in the order they appear. - -**`Default`** - -```ts -[] -``` - -#### Defined in - -[src/matcher/nfa/NfaMatcher.ts:622](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/nfa/NfaMatcher.ts#L622) - -___ - -### blacklistedTerms - -• **blacklistedTerms**: [`BlacklistedTerm`](BlacklistedTerm.md)[] - -A list of blacklisted terms. - -#### Defined in - -[src/matcher/nfa/NfaMatcher.ts:627](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/nfa/NfaMatcher.ts#L627) - -___ - -### whitelistMatcherTransformers - -• `Optional` **whitelistMatcherTransformers**: `TransformerContainer`[] - -A set of transformers that should be applied to the input text before -whitelisted terms are matched. This does not affect the matching of -blacklisted terms. - -Transformers will be applied in the order they appear. - -**`Default`** - -```ts -[] -``` - -#### Defined in - -[src/matcher/nfa/NfaMatcher.ts:638](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/nfa/NfaMatcher.ts#L638) - -___ - -### whitelistedTerms - -• `Optional` **whitelistedTerms**: `string`[] - -A list of whitelisted terms. If a whitelisted term matches some part of -the text, a match of a blacklisted pattern within that part of the text -will not be emitted. - -For example, if we had a pattern `penis` and a whitelisted term `pen is`, -only no matches would be reported for the input text `the pen is mightier -than the sword.` - -**`Default`** - -```ts -[] -``` - -#### Defined in - -[src/matcher/nfa/NfaMatcher.ts:651](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/nfa/NfaMatcher.ts#L651) diff --git a/docs/reference/interfaces/OptionalNode.md b/docs/reference/interfaces/OptionalNode.md index 6990a2b..43c0a33 100644 --- a/docs/reference/interfaces/OptionalNode.md +++ b/docs/reference/interfaces/OptionalNode.md @@ -22,7 +22,7 @@ would be a literal node with the value `abc`. #### Defined in -[src/pattern/Nodes.ts:44](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Nodes.ts#L44) +[src/pattern/Nodes.ts:44](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Nodes.ts#L44) ___ @@ -32,4 +32,4 @@ ___ #### Defined in -[src/pattern/Nodes.ts:46](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Nodes.ts#L46) +[src/pattern/Nodes.ts:46](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Nodes.ts#L46) diff --git a/docs/reference/interfaces/ParsedPattern.md b/docs/reference/interfaces/ParsedPattern.md index 3addb8a..ce1ac2a 100644 --- a/docs/reference/interfaces/ParsedPattern.md +++ b/docs/reference/interfaces/ParsedPattern.md @@ -22,7 +22,7 @@ A list of nodes which make up the pattern. #### Defined in -[src/pattern/Nodes.ts:8](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Nodes.ts#L8) +[src/pattern/Nodes.ts:8](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Nodes.ts#L8) ___ @@ -34,7 +34,7 @@ Whether the pattern requires a word boundary at the end. #### Defined in -[src/pattern/Nodes.ts:13](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Nodes.ts#L13) +[src/pattern/Nodes.ts:13](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Nodes.ts#L13) ___ @@ -46,4 +46,4 @@ Whether the pattern requires a word boundary at the start. #### Defined in -[src/pattern/Nodes.ts:18](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Nodes.ts#L18) +[src/pattern/Nodes.ts:18](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Nodes.ts#L18) diff --git a/docs/reference/interfaces/PhraseContainer.md b/docs/reference/interfaces/PhraseContainer.md index 813098f..9da7496 100644 --- a/docs/reference/interfaces/PhraseContainer.md +++ b/docs/reference/interfaces/PhraseContainer.md @@ -28,7 +28,7 @@ Metadata associated with this phrase. #### Defined in -[src/dataset/DataSet.ts:213](https://github.com/jo3-l/obscenity/blob/563159b/src/dataset/DataSet.ts#L213) +[src/dataset/DataSet.ts:204](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/dataset/DataSet.ts#L204) ___ @@ -40,7 +40,7 @@ Patterns associated with this phrase. #### Defined in -[src/dataset/DataSet.ts:218](https://github.com/jo3-l/obscenity/blob/563159b/src/dataset/DataSet.ts#L218) +[src/dataset/DataSet.ts:209](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/dataset/DataSet.ts#L209) ___ @@ -52,4 +52,4 @@ Whitelisted terms associated with this phrase. #### Defined in -[src/dataset/DataSet.ts:223](https://github.com/jo3-l/obscenity/blob/563159b/src/dataset/DataSet.ts#L223) +[src/dataset/DataSet.ts:214](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/dataset/DataSet.ts#L214) diff --git a/docs/reference/interfaces/ProcessedCollapseDuplicatesTransformerOptions.md b/docs/reference/interfaces/ProcessedCollapseDuplicatesTransformerOptions.md index 6748364..2ed1bca 100644 --- a/docs/reference/interfaces/ProcessedCollapseDuplicatesTransformerOptions.md +++ b/docs/reference/interfaces/ProcessedCollapseDuplicatesTransformerOptions.md @@ -17,7 +17,7 @@ #### Defined in -[src/transformer/collapse-duplicates/index.ts:68](https://github.com/jo3-l/obscenity/blob/563159b/src/transformer/collapse-duplicates/index.ts#L68) +[src/transformer/collapse-duplicates/index.ts:68](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/transformer/collapse-duplicates/index.ts#L68) ___ @@ -27,4 +27,4 @@ ___ #### Defined in -[src/transformer/collapse-duplicates/index.ts:69](https://github.com/jo3-l/obscenity/blob/563159b/src/transformer/collapse-duplicates/index.ts#L69) +[src/transformer/collapse-duplicates/index.ts:69](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/transformer/collapse-duplicates/index.ts#L69) diff --git a/docs/reference/interfaces/RegExpMatcherOptions.md b/docs/reference/interfaces/RegExpMatcherOptions.md index c7cfb18..790b1a0 100644 --- a/docs/reference/interfaces/RegExpMatcherOptions.md +++ b/docs/reference/interfaces/RegExpMatcherOptions.md @@ -33,7 +33,7 @@ Transformers will be applied in the order they appear. #### Defined in -[src/matcher/regexp/RegExpMatcher.ts:227](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/regexp/RegExpMatcher.ts#L227) +[src/matcher/regexp/RegExpMatcher.ts:220](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/regexp/RegExpMatcher.ts#L220) ___ @@ -45,7 +45,7 @@ A list of blacklisted terms. #### Defined in -[src/matcher/regexp/RegExpMatcher.ts:232](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/regexp/RegExpMatcher.ts#L232) +[src/matcher/regexp/RegExpMatcher.ts:225](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/regexp/RegExpMatcher.ts#L225) ___ @@ -67,7 +67,7 @@ Transformers will be applied in the order they appear. #### Defined in -[src/matcher/regexp/RegExpMatcher.ts:243](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/regexp/RegExpMatcher.ts#L243) +[src/matcher/regexp/RegExpMatcher.ts:236](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/regexp/RegExpMatcher.ts#L236) ___ @@ -91,4 +91,4 @@ than the sword.` #### Defined in -[src/matcher/regexp/RegExpMatcher.ts:256](https://github.com/jo3-l/obscenity/blob/563159b/src/matcher/regexp/RegExpMatcher.ts#L256) +[src/matcher/regexp/RegExpMatcher.ts:249](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/matcher/regexp/RegExpMatcher.ts#L249) diff --git a/docs/reference/interfaces/WildcardNode.md b/docs/reference/interfaces/WildcardNode.md index 627da69..71b81f6 100644 --- a/docs/reference/interfaces/WildcardNode.md +++ b/docs/reference/interfaces/WildcardNode.md @@ -18,4 +18,4 @@ A wildcard node. #### Defined in -[src/pattern/Nodes.ts:53](https://github.com/jo3-l/obscenity/blob/563159b/src/pattern/Nodes.ts#L53) +[src/pattern/Nodes.ts:53](https://github.com/jo3-l/obscenity/blob/ae4df1a/src/pattern/Nodes.ts#L53) diff --git a/jest.config.ts b/jest.config.ts index 8526a3f..2f7acb4 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -5,8 +5,14 @@ const config: Config.InitialOptions = { testEnvironment: 'node', testRunner: 'jest-circus/runner', testMatch: ['/test/**/*.test.ts'], - globals: { - 'ts-jest': { tsconfig: '/test/tsconfig.json' }, + transform: { + // eslint-disable-next-line @typescript-eslint/naming-convention + '^.+\\.ts$': [ + 'ts-jest', + { + tsconfig: '/test/tsconfig.json', + }, + ], }, collectCoverage: true, collectCoverageFrom: ['/src/**/*.ts'], diff --git a/package.json b/package.json index fb77444..b119622 100644 --- a/package.json +++ b/package.json @@ -68,16 +68,16 @@ "fast-check": "^2.25.0", "gen-esm-wrapper": "^1.1.3", "is-ci": "^3.0.1", - "jest": "^29.5.0", + "jest": "^29.7.0", "jest-circus": "^29.5.0", "prettier": "^2.8.8", "rimraf": "^5.0.0", "standard-version": "^9.5.0", - "ts-jest": "^29.1.0", + "ts-jest": "^29.1.1", "ts-node": "^10.9.1", "typedoc": "^0.25.0", "typedoc-plugin-markdown": "^3.15.3", - "typescript": "^5.1.3" + "typescript": "^5.2.2" }, "engines": { "node": ">=14.0.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5685fd1..cf5420c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,10 +19,10 @@ devDependencies: version: 29.5.2 '@typescript-eslint/eslint-plugin': specifier: ^5.59.9 - version: 5.59.9(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.1.3) + version: 5.59.9(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.2.2) '@typescript-eslint/parser': specifier: ^5.59.9 - version: 5.59.9(eslint@8.42.0)(typescript@5.1.3) + version: 5.59.9(eslint@8.42.0)(typescript@5.2.2) conventional-github-releaser: specifier: ^3.1.5 version: 3.1.5 @@ -31,13 +31,13 @@ devDependencies: version: 8.42.0 eslint-config-neon: specifier: ^0.1.47 - version: 0.1.47(eslint@8.42.0)(jest@29.5.0)(svelte@3.59.2)(typescript@5.1.3) + version: 0.1.47(eslint@8.42.0)(jest@29.7.0)(svelte@3.59.2)(typescript@5.2.2) eslint-config-prettier: specifier: ^9.0.0 version: 9.0.0(eslint@8.42.0) eslint-plugin-jest: specifier: ^27.2.1 - version: 27.2.1(@typescript-eslint/eslint-plugin@5.59.9)(eslint@8.42.0)(jest@29.5.0)(typescript@5.1.3) + version: 27.2.1(@typescript-eslint/eslint-plugin@5.59.9)(eslint@8.42.0)(jest@29.7.0)(typescript@5.2.2) eslint-plugin-prettier: specifier: ^4.2.1 version: 4.2.1(eslint-config-prettier@9.0.0)(eslint@8.42.0)(prettier@2.8.8) @@ -51,8 +51,8 @@ devDependencies: specifier: ^3.0.1 version: 3.0.1 jest: - specifier: ^29.5.0 - version: 29.5.0(@types/node@20.2.5)(ts-node@10.9.1) + specifier: ^29.7.0 + version: 29.7.0(@types/node@20.8.2)(ts-node@10.9.1) jest-circus: specifier: ^29.5.0 version: 29.5.0 @@ -66,20 +66,20 @@ devDependencies: specifier: ^9.5.0 version: 9.5.0 ts-jest: - specifier: ^29.1.0 - version: 29.1.0(@babel/core@7.22.1)(@jest/types@29.5.0)(jest@29.5.0)(typescript@5.1.3) + specifier: ^29.1.1 + version: 29.1.1(@babel/core@7.23.0)(@jest/types@29.5.0)(jest@29.7.0)(typescript@5.2.2) ts-node: specifier: ^10.9.1 - version: 10.9.1(@types/node@20.2.5)(typescript@5.1.3) + version: 10.9.1(@types/node@20.8.2)(typescript@5.2.2) typedoc: specifier: ^0.25.0 - version: 0.25.0(typescript@5.1.3) + version: 0.25.0(typescript@5.2.2) typedoc-plugin-markdown: specifier: ^3.15.3 version: 3.15.3(typedoc@0.25.0) typescript: - specifier: ^5.1.3 - version: 5.1.3 + specifier: ^5.2.2 + version: 5.2.2 packages: @@ -88,46 +88,46 @@ packages: engines: {node: '>=6.0.0'} dependencies: '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/trace-mapping': 0.3.19 dev: true /@angular-eslint/bundled-angular-compiler@16.0.3: resolution: {integrity: sha512-8zwY6ustiPXBEF3+jELKVwGk6j2HJn7GHbqAhDFR02YiE27iRMSGTHIAWGs6ZI7F1JgfrIsOHrUgzC1x95K6rg==} dev: true - /@angular-eslint/eslint-plugin-template@16.0.3(eslint@8.42.0)(typescript@5.1.3): + /@angular-eslint/eslint-plugin-template@16.0.3(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-OKTMWOjC7F5tdv7gm2tlmgyr/uVyS1RWJZn4X/6D6p0kOpiDXmajtbYHD5tzbshX2Ep62Nt+rg8+1XGHrU0ScA==} peerDependencies: eslint: ^7.20.0 || ^8.0.0 typescript: '*' dependencies: '@angular-eslint/bundled-angular-compiler': 16.0.3 - '@angular-eslint/utils': 16.0.3(eslint@8.42.0)(typescript@5.1.3) - '@typescript-eslint/type-utils': 5.59.7(eslint@8.42.0)(typescript@5.1.3) - '@typescript-eslint/utils': 5.59.7(eslint@8.42.0)(typescript@5.1.3) + '@angular-eslint/utils': 16.0.3(eslint@8.42.0)(typescript@5.2.2) + '@typescript-eslint/type-utils': 5.59.7(eslint@8.42.0)(typescript@5.2.2) + '@typescript-eslint/utils': 5.59.7(eslint@8.42.0)(typescript@5.2.2) aria-query: 5.1.3 axobject-query: 3.1.1 eslint: 8.42.0 - typescript: 5.1.3 + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /@angular-eslint/eslint-plugin@16.0.3(eslint@8.42.0)(typescript@5.1.3): + /@angular-eslint/eslint-plugin@16.0.3(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-1c+dFytcQDOA2wJ8/rtydMV6UYq1BgVfOcBXOr0WJxC9g8Cad9czcUOkW41WGrTp5kICMliV0ypH5eEaCM2WDQ==} peerDependencies: eslint: ^7.20.0 || ^8.0.0 typescript: '*' dependencies: - '@angular-eslint/utils': 16.0.3(eslint@8.42.0)(typescript@5.1.3) - '@typescript-eslint/utils': 5.59.7(eslint@8.42.0)(typescript@5.1.3) + '@angular-eslint/utils': 16.0.3(eslint@8.42.0)(typescript@5.2.2) + '@typescript-eslint/utils': 5.59.7(eslint@8.42.0)(typescript@5.2.2) eslint: 8.42.0 - typescript: 5.1.3 + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /@angular-eslint/template-parser@16.0.3(eslint@8.42.0)(typescript@5.1.3): + /@angular-eslint/template-parser@16.0.3(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-IAWdwp/S9QC3EMiVxSS0E3ABy9PSidN3PW0Ll2EtM3mzXMYlpZXmxqd+B1xV/xKWzhk1Mp04QX8hHfG6Vq+qaQ==} peerDependencies: eslint: ^7.20.0 || ^8.0.0 @@ -136,19 +136,19 @@ packages: '@angular-eslint/bundled-angular-compiler': 16.0.3 eslint: 8.42.0 eslint-scope: 7.2.0 - typescript: 5.1.3 + typescript: 5.2.2 dev: true - /@angular-eslint/utils@16.0.3(eslint@8.42.0)(typescript@5.1.3): + /@angular-eslint/utils@16.0.3(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-QsbUVHJLk+fE08/D4y3wOyGk1iX2LVSygw+uzilbaAXfjD5/c0Ei5FbVx2mMYPk+aOl4yrvGQW3dmetMiAR0MQ==} peerDependencies: eslint: ^7.20.0 || ^8.0.0 typescript: '*' dependencies: '@angular-eslint/bundled-angular-compiler': 16.0.3 - '@typescript-eslint/utils': 5.59.7(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/utils': 5.59.7(eslint@8.42.0)(typescript@5.2.2) eslint: 8.42.0 - typescript: 5.1.3 + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true @@ -157,129 +157,125 @@ packages: resolution: {integrity: sha512-EZ3d5UTqN71N2zE3VdzVJeM+dM+pu0wV/jOi6g2VDU21LQTWozafsFMpbcLE/ksmTmbQM90/Tnn19/IR9fWGUw==} dev: true - /@babel/code-frame@7.21.4: - resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==} + /@babel/code-frame@7.22.13: + resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/highlight': 7.18.6 + '@babel/highlight': 7.22.20 + chalk: 2.4.2 dev: true - /@babel/compat-data@7.22.3: - resolution: {integrity: sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ==} + /@babel/compat-data@7.22.20: + resolution: {integrity: sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==} engines: {node: '>=6.9.0'} dev: true - /@babel/core@7.22.1: - resolution: {integrity: sha512-Hkqu7J4ynysSXxmAahpN1jjRwVJ+NdpraFLIWflgjpVob3KNyK3/tIUc7Q7szed8WMp0JNa7Qtd1E9Oo22F9gA==} + /@babel/core@7.23.0: + resolution: {integrity: sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.21.4 - '@babel/generator': 7.22.3 - '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1) - '@babel/helper-module-transforms': 7.22.1 - '@babel/helpers': 7.22.3 - '@babel/parser': 7.22.4 - '@babel/template': 7.21.9 - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 - convert-source-map: 1.9.0 + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.23.0 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-module-transforms': 7.23.0(@babel/core@7.23.0) + '@babel/helpers': 7.23.1 + '@babel/parser': 7.23.0 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.0 + '@babel/types': 7.23.0 + convert-source-map: 2.0.0 debug: 4.3.4 gensync: 1.0.0-beta.2 json5: 2.2.3 - semver: 6.3.0 + semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /@babel/generator@7.22.3: - resolution: {integrity: sha512-C17MW4wlk//ES/CJDL51kPNwl+qiBQyN7b9SKyVp11BLGFeSPoVaHrv+MNt8jwQFhQWowW88z1eeBx3pFz9v8A==} + /@babel/generator@7.23.0: + resolution: {integrity: sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.0 '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/trace-mapping': 0.3.19 jsesc: 2.5.2 dev: true - /@babel/helper-compilation-targets@7.22.1(@babel/core@7.22.1): - resolution: {integrity: sha512-Rqx13UM3yVB5q0D/KwQ8+SPfX/+Rnsy1Lw1k/UwOC4KC6qrzIQoY3lYnBu5EHKBlEHHcj0M0W8ltPSkD8rqfsQ==} + /@babel/helper-compilation-targets@7.22.15: + resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.22.3 - '@babel/core': 7.22.1 - '@babel/helper-validator-option': 7.21.0 - browserslist: 4.21.7 + '@babel/compat-data': 7.22.20 + '@babel/helper-validator-option': 7.22.15 + browserslist: 4.22.1 lru-cache: 5.1.1 - semver: 6.3.0 + semver: 6.3.1 dev: true - /@babel/helper-environment-visitor@7.22.1: - resolution: {integrity: sha512-Z2tgopurB/kTbidvzeBrc2To3PUP/9i5MUe+fU6QJCQDyPwSH2oRapkLw3KGECDYSjhQZCNxEvNvZlLw8JjGwA==} + /@babel/helper-environment-visitor@7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-function-name@7.21.0: - resolution: {integrity: sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==} + /@babel/helper-function-name@7.23.0: + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.21.9 - '@babel/types': 7.22.4 + '@babel/template': 7.22.15 + '@babel/types': 7.23.0 dev: true - /@babel/helper-hoist-variables@7.18.6: - resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.0 dev: true - /@babel/helper-module-imports@7.21.4: - resolution: {integrity: sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==} + /@babel/helper-module-imports@7.22.15: + resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.0 dev: true - /@babel/helper-module-transforms@7.22.1: - resolution: {integrity: sha512-dxAe9E7ySDGbQdCVOY/4+UcD8M9ZFqZcZhSPsPacvCG4M+9lwtDDQfI2EoaSvmf7W/8yCBkGU0m7Pvt1ru3UZw==} + /@babel/helper-module-transforms@7.23.0(@babel/core@7.23.0): + resolution: {integrity: sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 dependencies: - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-module-imports': 7.21.4 - '@babel/helper-simple-access': 7.21.5 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/helper-validator-identifier': 7.19.1 - '@babel/template': 7.21.9 - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.0 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 dev: true - /@babel/helper-plugin-utils@7.21.5: - resolution: {integrity: sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg==} + /@babel/helper-plugin-utils@7.22.5: + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-simple-access@7.21.5: - resolution: {integrity: sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==} + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.0 dev: true - /@babel/helper-split-export-declaration@7.18.6: - resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.0 dev: true - /@babel/helper-string-parser@7.21.5: - resolution: {integrity: sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==} + /@babel/helper-string-parser@7.22.5: + resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} engines: {node: '>=6.9.0'} dev: true @@ -288,166 +284,171 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/helper-validator-option@7.21.0: - resolution: {integrity: sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==} + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-option@7.22.15: + resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==} engines: {node: '>=6.9.0'} dev: true - /@babel/helpers@7.22.3: - resolution: {integrity: sha512-jBJ7jWblbgr7r6wYZHMdIqKc73ycaTcCaWRq4/2LpuPHcx7xMlZvpGQkOYc9HeSjn6rcx15CPlgVcBtZ4WZJ2w==} + /@babel/helpers@7.23.1: + resolution: {integrity: sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.21.9 - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.0 + '@babel/types': 7.23.0 transitivePeerDependencies: - supports-color dev: true - /@babel/highlight@7.18.6: - resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} + /@babel/highlight@7.22.20: + resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-validator-identifier': 7.19.1 + '@babel/helper-validator-identifier': 7.22.20 chalk: 2.4.2 js-tokens: 4.0.0 dev: true - /@babel/parser@7.22.4: - resolution: {integrity: sha512-VLLsx06XkEYqBtE5YGPwfSGwfrjnyPP5oiGty3S8pQLFDFLaS8VwWSIxkTXpcvr5zeYLE6+MBNl2npl/YnfofA==} + /@babel/parser@7.23.0: + resolution: {integrity: sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.0 dev: true - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.22.1): + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.0): resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.22.1): + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.0): resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.22.1): + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.0): resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.22.1): + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.0): resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.22.1): + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.0): resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-jsx@7.21.4(@babel/core@7.22.1): - resolution: {integrity: sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==} + /@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.23.0): + resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.22.1): + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.0): resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.22.1): + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.0): resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.22.1): + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.0): resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.22.1): + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.0): resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.22.1): + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.0): resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.22.1): + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.0): resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.22.1): + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.0): resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-typescript@7.21.4(@babel/core@7.22.1): - resolution: {integrity: sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==} + /@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.23.0): + resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/runtime@7.22.5: @@ -457,39 +458,57 @@ packages: regenerator-runtime: 0.13.11 dev: true - /@babel/template@7.21.9: - resolution: {integrity: sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ==} + /@babel/template@7.22.15: + resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.21.4 - '@babel/parser': 7.22.4 - '@babel/types': 7.22.4 + '@babel/code-frame': 7.22.13 + '@babel/parser': 7.23.0 + '@babel/types': 7.23.0 dev: true /@babel/traverse@7.22.4: resolution: {integrity: sha512-Tn1pDsjIcI+JcLKq1AVlZEr4226gpuAQTsLMorsYg9tuS/kG7nuwwJ4AB8jfQuEgb/COBwR/DqJxmoiYFu5/rQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.21.4 - '@babel/generator': 7.22.3 - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-function-name': 7.21.0 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.22.4 - '@babel/types': 7.22.4 + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.23.0 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.0 + '@babel/types': 7.23.0 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: true - /@babel/types@7.22.4: - resolution: {integrity: sha512-Tx9x3UBHTTsMSW85WB2kphxYQVvrZ/t1FxD88IpSgIjiUJlCm9z+xWIDwyo1vffTwSqteqyznB8ZE9vYYk16zA==} + /@babel/traverse@7.23.0: + resolution: {integrity: sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.21.5 - '@babel/helper-validator-identifier': 7.19.1 + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.23.0 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.0 + '@babel/types': 7.23.0 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/types@7.23.0: + resolution: {integrity: sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 dev: true @@ -591,13 +610,13 @@ packages: '@types/node': 20.2.5 chalk: 4.1.2 cosmiconfig: 8.2.0 - cosmiconfig-typescript-loader: 4.3.0(@types/node@20.2.5)(cosmiconfig@8.2.0)(ts-node@10.9.1)(typescript@4.9.5) + cosmiconfig-typescript-loader: 4.3.0(@types/node@20.2.5)(cosmiconfig@8.2.0)(ts-node@10.9.1)(typescript@5.2.2) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 resolve-from: 5.0.0 - ts-node: 10.9.1(@types/node@20.2.5)(typescript@4.9.5) - typescript: 4.9.5 + ts-node: 10.9.1(@types/node@20.2.5)(typescript@5.2.2) + typescript: 5.2.2 transitivePeerDependencies: - '@swc/core' - '@swc/wasm' @@ -776,20 +795,20 @@ packages: engines: {node: '>=8'} dev: true - /@jest/console@29.5.0: - resolution: {integrity: sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==} + /@jest/console@29.7.0: + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.5.0 - '@types/node': 20.2.5 + '@jest/types': 29.6.3 + '@types/node': 20.8.2 chalk: 4.1.2 - jest-message-util: 29.5.0 - jest-util: 29.5.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 slash: 3.0.0 dev: true - /@jest/core@29.5.0(ts-node@10.9.1): - resolution: {integrity: sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==} + /@jest/core@29.7.0(ts-node@10.9.1): + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -797,35 +816,36 @@ packages: node-notifier: optional: true dependencies: - '@jest/console': 29.5.0 - '@jest/reporters': 29.5.0 - '@jest/test-result': 29.5.0 - '@jest/transform': 29.5.0 - '@jest/types': 29.5.0 - '@types/node': 20.2.5 + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.8.2 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.8.0 exit: 0.1.2 graceful-fs: 4.2.11 - jest-changed-files: 29.5.0 - jest-config: 29.5.0(@types/node@20.2.5)(ts-node@10.9.1) - jest-haste-map: 29.5.0 - jest-message-util: 29.5.0 - jest-regex-util: 29.4.3 - jest-resolve: 29.5.0 - jest-resolve-dependencies: 29.5.0 - jest-runner: 29.5.0 - jest-runtime: 29.5.0 - jest-snapshot: 29.5.0 - jest-util: 29.5.0 - jest-validate: 29.5.0 - jest-watcher: 29.5.0 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.8.2)(ts-node@10.9.1) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 micromatch: 4.0.5 - pretty-format: 29.5.0 + pretty-format: 29.7.0 slash: 3.0.0 strip-ansi: 6.0.1 transitivePeerDependencies: + - babel-plugin-macros - supports-color - ts-node dev: true @@ -834,10 +854,20 @@ packages: resolution: {integrity: sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/fake-timers': 29.5.0 + '@jest/fake-timers': 29.7.0 '@jest/types': 29.5.0 '@types/node': 20.2.5 - jest-mock: 29.5.0 + jest-mock: 29.7.0 + dev: true + + /@jest/environment@29.7.0: + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.8.2 + jest-mock: 29.7.0 dev: true /@jest/expect-utils@29.5.0: @@ -847,42 +877,59 @@ packages: jest-get-type: 29.4.3 dev: true + /@jest/expect-utils@29.7.0: + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-get-type: 29.6.3 + dev: true + /@jest/expect@29.5.0: resolution: {integrity: sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - expect: 29.5.0 + expect: 29.7.0 jest-snapshot: 29.5.0 transitivePeerDependencies: - supports-color dev: true - /@jest/fake-timers@29.5.0: - resolution: {integrity: sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==} + /@jest/expect@29.7.0: + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.5.0 - '@sinonjs/fake-timers': 10.2.0 - '@types/node': 20.2.5 - jest-message-util: 29.5.0 - jest-mock: 29.5.0 - jest-util: 29.5.0 + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color dev: true - /@jest/globals@29.5.0: - resolution: {integrity: sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==} + /@jest/fake-timers@29.7.0: + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/environment': 29.5.0 - '@jest/expect': 29.5.0 - '@jest/types': 29.5.0 - jest-mock: 29.5.0 + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 20.8.2 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + dev: true + + /@jest/globals@29.7.0: + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/types': 29.6.3 + jest-mock: 29.7.0 transitivePeerDependencies: - supports-color dev: true - /@jest/reporters@29.5.0: - resolution: {integrity: sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==} + /@jest/reporters@29.7.0: + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -891,25 +938,25 @@ packages: optional: true dependencies: '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 29.5.0 - '@jest/test-result': 29.5.0 - '@jest/transform': 29.5.0 - '@jest/types': 29.5.0 - '@jridgewell/trace-mapping': 0.3.18 - '@types/node': 20.2.5 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.19 + '@types/node': 20.8.2 chalk: 4.1.2 - collect-v8-coverage: 1.0.1 + collect-v8-coverage: 1.0.2 exit: 0.1.2 glob: 7.2.3 graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.0 - istanbul-lib-instrument: 5.2.1 - istanbul-lib-report: 3.0.0 + istanbul-lib-instrument: 6.0.0 + istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.5 - jest-message-util: 29.5.0 - jest-util: 29.5.0 - jest-worker: 29.5.0 + istanbul-reports: 3.1.6 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 slash: 3.0.0 string-length: 4.0.2 strip-ansi: 6.0.1 @@ -925,11 +972,18 @@ packages: '@sinclair/typebox': 0.25.24 dev: true - /@jest/source-map@29.4.3: - resolution: {integrity: sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==} + /@jest/schemas@29.6.3: + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jridgewell/trace-mapping': 0.3.18 + '@sinclair/typebox': 0.27.8 + dev: true + + /@jest/source-map@29.6.3: + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jridgewell/trace-mapping': 0.3.19 callsites: 3.1.0 graceful-fs: 4.2.11 dev: true @@ -938,39 +992,49 @@ packages: resolution: {integrity: sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/console': 29.5.0 + '@jest/console': 29.7.0 '@jest/types': 29.5.0 '@types/istanbul-lib-coverage': 2.0.4 - collect-v8-coverage: 1.0.1 + collect-v8-coverage: 1.0.2 dev: true - /@jest/test-sequencer@29.5.0: - resolution: {integrity: sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==} + /@jest/test-result@29.7.0: + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/test-result': 29.5.0 + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.4 + collect-v8-coverage: 1.0.2 + dev: true + + /@jest/test-sequencer@29.7.0: + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/test-result': 29.7.0 graceful-fs: 4.2.11 - jest-haste-map: 29.5.0 + jest-haste-map: 29.7.0 slash: 3.0.0 dev: true - /@jest/transform@29.5.0: - resolution: {integrity: sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==} + /@jest/transform@29.7.0: + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.22.1 - '@jest/types': 29.5.0 - '@jridgewell/trace-mapping': 0.3.18 + '@babel/core': 7.23.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.19 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 convert-source-map: 2.0.0 fast-json-stable-stringify: 2.1.0 graceful-fs: 4.2.11 - jest-haste-map: 29.5.0 - jest-regex-util: 29.4.3 - jest-util: 29.5.0 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 micromatch: 4.0.5 - pirates: 4.0.5 + pirates: 4.0.6 slash: 3.0.0 write-file-atomic: 4.0.2 transitivePeerDependencies: @@ -989,18 +1053,25 @@ packages: chalk: 4.1.2 dev: true + /@jest/types@29.6.3: + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.4 + '@types/istanbul-reports': 3.0.2 + '@types/node': 20.8.2 + '@types/yargs': 17.0.26 + chalk: 4.1.2 + dev: true + /@jridgewell/gen-mapping@0.3.3: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} engines: {node: '>=6.0.0'} dependencies: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.18 - dev: true - - /@jridgewell/resolve-uri@3.1.0: - resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} - engines: {node: '>=6.0.0'} + '@jridgewell/trace-mapping': 0.3.19 dev: true /@jridgewell/resolve-uri@3.1.1: @@ -1013,19 +1084,15 @@ packages: engines: {node: '>=6.0.0'} dev: true - /@jridgewell/sourcemap-codec@1.4.14: - resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} - dev: true - /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} dev: true - /@jridgewell/trace-mapping@0.3.18: - resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} + /@jridgewell/trace-mapping@0.3.19: + resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 dev: true /@jridgewell/trace-mapping@0.3.9: @@ -1085,7 +1152,7 @@ packages: nopt: 7.2.0 proc-log: 3.0.0 read-package-json-fast: 3.0.2 - semver: 7.5.2 + semver: 7.5.4 walk-up-path: 3.0.1 dev: true @@ -1094,8 +1161,8 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dependencies: '@npmcli/name-from-folder': 2.0.0 - glob: 10.2.6 - minimatch: 9.0.1 + glob: 10.3.10 + minimatch: 9.0.3 read-package-json-fast: 3.0.2 dev: true @@ -1131,6 +1198,10 @@ packages: resolution: {integrity: sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==} dev: true + /@sinclair/typebox@0.27.8: + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + dev: true + /@sindresorhus/is@0.7.0: resolution: {integrity: sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==} engines: {node: '>=4'} @@ -1142,8 +1213,8 @@ packages: type-detect: 4.0.8 dev: true - /@sinonjs/fake-timers@10.2.0: - resolution: {integrity: sha512-OPwQlEdg40HAj5KNF8WW6q2KG4Z+cBCZb3m4ninfTZKaBmbIJodviQsDBoYMPHkOyJJMHnOJo5j2+LKDOhOACg==} + /@sinonjs/fake-timers@10.3.0: + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} dependencies: '@sinonjs/commons': 3.0.0 dev: true @@ -1170,39 +1241,45 @@ packages: '@types/estree': 1.0.1 dev: true - /@types/babel__core@7.20.1: - resolution: {integrity: sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==} + /@types/babel__core@7.20.2: + resolution: {integrity: sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==} dependencies: - '@babel/parser': 7.22.4 - '@babel/types': 7.22.4 - '@types/babel__generator': 7.6.4 - '@types/babel__template': 7.4.1 - '@types/babel__traverse': 7.20.1 + '@babel/parser': 7.23.0 + '@babel/types': 7.23.0 + '@types/babel__generator': 7.6.5 + '@types/babel__template': 7.4.2 + '@types/babel__traverse': 7.20.2 dev: true - /@types/babel__generator@7.6.4: - resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} + /@types/babel__generator@7.6.5: + resolution: {integrity: sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w==} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.0 dev: true - /@types/babel__template@7.4.1: - resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} + /@types/babel__template@7.4.2: + resolution: {integrity: sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ==} dependencies: - '@babel/parser': 7.22.4 - '@babel/types': 7.22.4 + '@babel/parser': 7.23.0 + '@babel/types': 7.23.0 dev: true /@types/babel__traverse@7.20.1: resolution: {integrity: sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.0 + dev: true + + /@types/babel__traverse@7.20.2: + resolution: {integrity: sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw==} + dependencies: + '@babel/types': 7.23.0 dev: true /@types/concat-stream@2.0.0: resolution: {integrity: sha512-t3YCerNM7NTVjLuICZo5gYAXYoDvpuuTceCcFQWcDQz26kxUR5uIWolxbIR5jRNIXpMqhOpW/b8imCR1LEmuJw==} dependencies: - '@types/node': 20.2.5 + '@types/node': 18.18.3 dev: true /@types/debug@4.1.8: @@ -1221,10 +1298,10 @@ packages: resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} dev: true - /@types/graceful-fs@4.1.6: - resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} + /@types/graceful-fs@4.1.7: + resolution: {integrity: sha512-MhzcwU8aUygZroVwL2jeYk6JisJrPl/oov/gsgGCue9mkgl9wjGbzReYQClxiUgFDnib9FuHqTndccKeZKxTRw==} dependencies: - '@types/node': 20.2.5 + '@types/node': 20.8.2 dev: true /@types/hast@2.3.4: @@ -1247,12 +1324,24 @@ packages: '@types/istanbul-lib-coverage': 2.0.4 dev: true + /@types/istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-gPQuzaPR5h/djlAv2apEG1HVOyj1IUs7GpfMZixU0/0KXT3pm64ylHuMUI1/Akh+sq/iikxg6Z2j+fcMDXaaTQ==} + dependencies: + '@types/istanbul-lib-coverage': 2.0.4 + dev: true + /@types/istanbul-reports@3.0.1: resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==} dependencies: '@types/istanbul-lib-report': 3.0.0 dev: true + /@types/istanbul-reports@3.0.2: + resolution: {integrity: sha512-kv43F9eb3Lhj+lr/Hn6OcLCs/sSM8bt+fIaP11rCYngfV6NVjzWXJ17owQtDQTL9tQ8WSLUrGsSJ6rJz0F1w1A==} + dependencies: + '@types/istanbul-lib-report': 3.0.1 + dev: true + /@types/jest@29.5.2: resolution: {integrity: sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg==} dependencies: @@ -1267,7 +1356,7 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 20.2.5 + '@types/node': 20.8.2 dev: true /@types/mdast@3.0.11: @@ -1284,14 +1373,18 @@ packages: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} dev: true - /@types/node@18.16.18: - resolution: {integrity: sha512-/aNaQZD0+iSBAGnvvN2Cx92HqE5sZCPZtx2TsK+4nvV23fFe09jVDvpArXr2j9DnYlzuU9WuoykDDc6wqvpNcw==} + /@types/node@18.18.3: + resolution: {integrity: sha512-0OVfGupTl3NBFr8+iXpfZ8NR7jfFO+P1Q+IO/q0wbo02wYkP5gy36phojeYWpLQ6WAMjl+VfmqUk2YbUfp0irA==} dev: true /@types/node@20.2.5: resolution: {integrity: sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==} dev: true + /@types/node@20.8.2: + resolution: {integrity: sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==} + dev: true + /@types/normalize-package-data@2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} dev: true @@ -1303,7 +1396,7 @@ packages: /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 20.2.5 + '@types/node': 20.8.2 dev: true /@types/semver@7.5.0: @@ -1326,13 +1419,23 @@ packages: resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} dev: true + /@types/yargs-parser@21.0.1: + resolution: {integrity: sha512-axdPBuLuEJt0c4yI5OZssC19K2Mq1uKdrfZBzuxLvaztgqUtFYZUNw7lETExPYJR9jdEoIg4mb7RQKRQzOkeGQ==} + dev: true + /@types/yargs@17.0.24: resolution: {integrity: sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==} dependencies: '@types/yargs-parser': 21.0.0 dev: true - /@typescript-eslint/eslint-plugin@5.59.9(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.1.3): + /@types/yargs@17.0.26: + resolution: {integrity: sha512-Y3vDy2X6zw/ZCumcwLpdhM5L7jmyGpmBCTYMHDLqT2IKVMYRRLdv6ZakA+wxhra6Z/3bwhNbNl9bDGXaFU+6rw==} + dependencies: + '@types/yargs-parser': 21.0.1 + dev: true + + /@typescript-eslint/eslint-plugin@5.59.9(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-4uQIBq1ffXd2YvF7MAvehWKW3zVv/w+mSfRAu+8cKbfj3nwzyqJLNcZJpQ/WZ1HLbJDiowwmQ6NO+63nCA+fqA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1344,36 +1447,36 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.5.1 - '@typescript-eslint/parser': 5.59.9(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/parser': 5.59.9(eslint@8.42.0)(typescript@5.2.2) '@typescript-eslint/scope-manager': 5.59.9 - '@typescript-eslint/type-utils': 5.59.9(eslint@8.42.0)(typescript@5.1.3) - '@typescript-eslint/utils': 5.59.9(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/type-utils': 5.59.9(eslint@8.42.0)(typescript@5.2.2) + '@typescript-eslint/utils': 5.59.9(eslint@8.42.0)(typescript@5.2.2) debug: 4.3.4 eslint: 8.42.0 grapheme-splitter: 1.0.4 ignore: 5.2.4 natural-compare-lite: 1.4.0 semver: 7.5.1 - tsutils: 3.21.0(typescript@5.1.3) - typescript: 5.1.3 + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/experimental-utils@5.60.1(eslint@8.42.0)(typescript@5.1.3): + /@typescript-eslint/experimental-utils@5.60.1(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-TXUdLxv2t8181nh5yLXl/Gr/zKj1ZofQ7m+ZdmG2+El0TYOHCvlZfc35D4nturemC3RUnf3KmLuFp3bVBjkG5w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/utils': 5.60.1(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/utils': 5.60.1(eslint@8.42.0)(typescript@5.2.2) eslint: 8.42.0 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/parser@5.59.9(eslint@8.42.0)(typescript@5.1.3): + /@typescript-eslint/parser@5.59.9(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-FsPkRvBtcLQ/eVK1ivDiNYBjn3TGJdXy2fhXX+rc7czWl4ARwnpArwbihSOHI2Peg9WbtGHrbThfBUkZZGTtvQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1385,10 +1488,10 @@ packages: dependencies: '@typescript-eslint/scope-manager': 5.59.9 '@typescript-eslint/types': 5.59.9 - '@typescript-eslint/typescript-estree': 5.59.9(typescript@5.1.3) + '@typescript-eslint/typescript-estree': 5.59.9(typescript@5.2.2) debug: 4.3.4 eslint: 8.42.0 - typescript: 5.1.3 + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true @@ -1417,7 +1520,7 @@ packages: '@typescript-eslint/visitor-keys': 5.60.1 dev: true - /@typescript-eslint/type-utils@5.59.7(eslint@8.42.0)(typescript@5.1.3): + /@typescript-eslint/type-utils@5.59.7(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-ozuz/GILuYG7osdY5O5yg0QxXUAEoI4Go3Do5xeu+ERH9PorHBPSdvD3Tjp2NN2bNLh1NJQSsQu2TPu/Ly+HaQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1427,17 +1530,17 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.59.7(typescript@5.1.3) - '@typescript-eslint/utils': 5.59.7(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/typescript-estree': 5.59.7(typescript@5.2.2) + '@typescript-eslint/utils': 5.59.7(eslint@8.42.0)(typescript@5.2.2) debug: 4.3.4 eslint: 8.42.0 - tsutils: 3.21.0(typescript@5.1.3) - typescript: 5.1.3 + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/type-utils@5.59.9(eslint@8.42.0)(typescript@5.1.3): + /@typescript-eslint/type-utils@5.59.9(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-ksEsT0/mEHg9e3qZu98AlSrONAQtrSTljL3ow9CGej8eRo7pe+yaC/mvTjptp23Xo/xIf2mLZKC6KPv4Sji26Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1447,12 +1550,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.59.9(typescript@5.1.3) - '@typescript-eslint/utils': 5.59.9(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/typescript-estree': 5.59.9(typescript@5.2.2) + '@typescript-eslint/utils': 5.59.9(eslint@8.42.0)(typescript@5.2.2) debug: 4.3.4 eslint: 8.42.0 - tsutils: 3.21.0(typescript@5.1.3) - typescript: 5.1.3 + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true @@ -1472,7 +1575,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree@5.59.7(typescript@5.1.3): + /@typescript-eslint/typescript-estree@5.59.7(typescript@5.2.2): resolution: {integrity: sha512-4A1NtZ1I3wMN2UGDkU9HMBL+TIQfbrh4uS0WDMMpf3xMRursDbqEf1ahh6vAAe3mObt8k3ZATnezwG4pdtWuUQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1486,14 +1589,14 @@ packages: debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.2 - tsutils: 3.21.0(typescript@5.1.3) - typescript: 5.1.3 + semver: 7.5.4 + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/typescript-estree@5.59.9(typescript@5.1.3): + /@typescript-eslint/typescript-estree@5.59.9(typescript@5.2.2): resolution: {integrity: sha512-pmM0/VQ7kUhd1QyIxgS+aRvMgw+ZljB3eDb+jYyp6d2bC0mQWLzUDF+DLwCTkQ3tlNyVsvZRXjFyV0LkU/aXjA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1507,14 +1610,14 @@ packages: debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.1 - tsutils: 3.21.0(typescript@5.1.3) - typescript: 5.1.3 + semver: 7.5.4 + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/typescript-estree@5.60.1(typescript@5.1.3): + /@typescript-eslint/typescript-estree@5.60.1(typescript@5.2.2): resolution: {integrity: sha512-hkX70J9+2M2ZT6fhti5Q2FoU9zb+GeZK2SLP1WZlvUDqdMbEKhexZODD1WodNRyO8eS+4nScvT0dts8IdaBzfw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1528,14 +1631,14 @@ packages: debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.2 - tsutils: 3.21.0(typescript@5.1.3) - typescript: 5.1.3 + semver: 7.5.4 + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@5.59.7(eslint@8.42.0)(typescript@5.1.3): + /@typescript-eslint/utils@5.59.7(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-yCX9WpdQKaLufz5luG4aJbOpdXf/fjwGMcLFXZVPUz3QqLirG5QcwwnIHNf8cjLjxK4qtzTO8udUtMQSAToQnQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1546,16 +1649,16 @@ packages: '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 5.59.7 '@typescript-eslint/types': 5.59.7 - '@typescript-eslint/typescript-estree': 5.59.7(typescript@5.1.3) + '@typescript-eslint/typescript-estree': 5.59.7(typescript@5.2.2) eslint: 8.42.0 eslint-scope: 5.1.1 - semver: 7.5.2 + semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/utils@5.59.9(eslint@8.42.0)(typescript@5.1.3): + /@typescript-eslint/utils@5.59.9(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-1PuMYsju/38I5Ggblaeb98TOoUvjhRvLpLa1DoTOFaLWqaXl/1iQ1eGurTXgBY58NUdtfTXKP5xBq7q9NDaLKg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1566,7 +1669,7 @@ packages: '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 5.59.9 '@typescript-eslint/types': 5.59.9 - '@typescript-eslint/typescript-estree': 5.59.9(typescript@5.1.3) + '@typescript-eslint/typescript-estree': 5.59.9(typescript@5.2.2) eslint: 8.42.0 eslint-scope: 5.1.1 semver: 7.5.1 @@ -1575,7 +1678,7 @@ packages: - typescript dev: true - /@typescript-eslint/utils@5.60.1(eslint@8.42.0)(typescript@5.1.3): + /@typescript-eslint/utils@5.60.1(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-tiJ7FFdFQOWssFa3gqb94Ilexyw0JVxj6vBzaSpfN/8IhoKkDuSAenUKvsSHw2A/TMpJb26izIszTXaqygkvpQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1586,10 +1689,10 @@ packages: '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 5.60.1 '@typescript-eslint/types': 5.60.1 - '@typescript-eslint/typescript-estree': 5.60.1(typescript@5.1.3) + '@typescript-eslint/typescript-estree': 5.60.1(typescript@5.2.2) eslint: 8.42.0 eslint-scope: 5.1.1 - semver: 7.5.2 + semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript @@ -1846,7 +1949,7 @@ packages: debug: 4.3.4 eslint-visitor-keys: 3.4.1 espree: 9.5.2 - semver: 7.5.2 + semver: 7.5.4 transitivePeerDependencies: - supports-color dev: true @@ -1883,17 +1986,17 @@ packages: dequal: 2.0.3 dev: true - /babel-jest@29.5.0(@babel/core@7.22.1): - resolution: {integrity: sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==} + /babel-jest@29.7.0(@babel/core@7.23.0): + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.8.0 dependencies: - '@babel/core': 7.22.1 - '@jest/transform': 29.5.0 - '@types/babel__core': 7.20.1 + '@babel/core': 7.23.0 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.2 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.5.0(@babel/core@7.22.1) + babel-preset-jest: 29.6.3(@babel/core@7.23.0) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 @@ -1905,7 +2008,7 @@ packages: resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} engines: {node: '>=8'} dependencies: - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-instrument: 5.2.1 @@ -1914,45 +2017,45 @@ packages: - supports-color dev: true - /babel-plugin-jest-hoist@29.5.0: - resolution: {integrity: sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==} + /babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/template': 7.21.9 - '@babel/types': 7.22.4 - '@types/babel__core': 7.20.1 - '@types/babel__traverse': 7.20.1 + '@babel/template': 7.22.15 + '@babel/types': 7.23.0 + '@types/babel__core': 7.20.2 + '@types/babel__traverse': 7.20.2 dev: true - /babel-preset-current-node-syntax@1.0.1(@babel/core@7.22.1): + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.0): resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.22.1 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.1) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.22.1) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.22.1) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.1) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.1) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.1) - dev: true - - /babel-preset-jest@29.5.0(@babel/core@7.22.1): - resolution: {integrity: sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==} + '@babel/core': 7.23.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.23.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.0) + dev: true + + /babel-preset-jest@29.6.3(@babel/core@7.23.0): + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.22.1 - babel-plugin-jest-hoist: 29.5.0 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.1) + '@babel/core': 7.23.0 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.0) dev: true /bail@2.0.2: @@ -2007,15 +2110,15 @@ packages: fill-range: 7.0.1 dev: true - /browserslist@4.21.7: - resolution: {integrity: sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==} + /browserslist@4.22.1: + resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001495 - electron-to-chromium: 1.4.421 - node-releases: 2.0.12 - update-browserslist-db: 1.0.11(browserslist@4.21.7) + caniuse-lite: 1.0.30001542 + electron-to-chromium: 1.4.539 + node-releases: 2.0.13 + update-browserslist-db: 1.0.13(browserslist@4.22.1) dev: true /bs-logger@0.2.6: @@ -2043,7 +2146,7 @@ packages: /builtins@5.0.1: resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==} dependencies: - semver: 7.5.2 + semver: 7.5.4 dev: true /bundle-name@3.0.0: @@ -2127,8 +2230,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite@1.0.30001495: - resolution: {integrity: sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==} + /caniuse-lite@1.0.30001542: + resolution: {integrity: sha512-UrtAXVcj1mvPBFQ4sKd38daP8dEcXXr5sQe6QNNinaPd0iA/cxg9/l3VrSdL73jgw5sKyuQ6jNgiKO12W3SsVA==} dev: true /caseless@0.12.0: @@ -2194,8 +2297,8 @@ packages: engines: {node: '>=8'} dev: true - /cjs-module-lexer@1.2.2: - resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} + /cjs-module-lexer@1.2.3: + resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} dev: true /clean-regexp@1.0.0: @@ -2233,8 +2336,8 @@ packages: engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} dev: true - /collect-v8-coverage@1.0.1: - resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==} + /collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} dev: true /color-convert@1.9.3: @@ -2442,7 +2545,7 @@ packages: json-stringify-safe: 5.0.1 lodash: 4.17.21 meow: 8.1.2 - semver: 6.3.0 + semver: 6.3.1 split: 1.0.1 through2: 4.0.2 dev: true @@ -2458,7 +2561,7 @@ packages: json-stringify-safe: 5.0.1 lodash: 4.17.21 meow: 8.1.2 - semver: 6.3.0 + semver: 6.3.1 split: 1.0.1 through2: 4.0.2 dev: true @@ -2566,7 +2669,7 @@ packages: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} dev: true - /cosmiconfig-typescript-loader@4.3.0(@types/node@20.2.5)(cosmiconfig@8.2.0)(ts-node@10.9.1)(typescript@4.9.5): + /cosmiconfig-typescript-loader@4.3.0(@types/node@20.2.5)(cosmiconfig@8.2.0)(ts-node@10.9.1)(typescript@5.2.2): resolution: {integrity: sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==} engines: {node: '>=12', npm: '>=6'} peerDependencies: @@ -2577,8 +2680,8 @@ packages: dependencies: '@types/node': 20.2.5 cosmiconfig: 8.2.0 - ts-node: 10.9.1(@types/node@20.2.5)(typescript@4.9.5) - typescript: 4.9.5 + ts-node: 10.9.1(@types/node@20.2.5)(typescript@5.2.2) + typescript: 5.2.2 dev: true /cosmiconfig@8.2.0: @@ -2591,6 +2694,25 @@ packages: path-type: 4.0.0 dev: true + /create-jest@29.7.0(@types/node@20.8.2)(ts-node@10.9.1): + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@20.8.2)(ts-node@10.9.1) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + /create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} dev: true @@ -2700,6 +2822,15 @@ packages: resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} dev: true + /dedent@1.5.1: + resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + dev: true + /deep-equal@2.2.1: resolution: {integrity: sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==} dependencies: @@ -2746,7 +2877,7 @@ packages: dependencies: bundle-name: 3.0.0 default-browser-id: 3.0.0 - execa: 7.1.1 + execa: 7.2.0 titleize: 3.0.0 dev: true @@ -2778,8 +2909,8 @@ packages: engines: {node: '>=8'} dev: true - /diff-sequences@29.4.3: - resolution: {integrity: sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==} + /diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true @@ -2844,8 +2975,8 @@ packages: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true - /electron-to-chromium@1.4.421: - resolution: {integrity: sha512-wZOyn3s/aQOtLGAwXMZfteQPN68kgls2wDAnYOA8kCjBvKVrW5RwmWVspxJYTqrcN7Y263XJVsC66VCIGzDO3g==} + /electron-to-chromium@1.4.539: + resolution: {integrity: sha512-wRmWJ8F7rgmINuI32S6r2SLrw/h/bJQsDSvBiq9GBfvc2Lh73qTOwn73r3Cf67mjVgFGJYcYtmERzySa5jIWlg==} dev: true /emittery@0.13.1: @@ -2973,24 +3104,24 @@ packages: engines: {node: '>=10'} dev: true - /eslint-config-neon@0.1.47(eslint@8.42.0)(jest@29.5.0)(svelte@3.59.2)(typescript@5.1.3): + /eslint-config-neon@0.1.47(eslint@8.42.0)(jest@29.7.0)(svelte@3.59.2)(typescript@5.2.2): resolution: {integrity: sha512-Ya9Q3u8DZufNwMDE3hRJ5+6VkZ+/OmJjyH1BLUotSBBEixiFZsOaouzWJer3edVkUf3VLjoZLUXrTlWvGnb34A==} engines: {node: '>=16.0.0'} dependencies: - '@angular-eslint/eslint-plugin': 16.0.3(eslint@8.42.0)(typescript@5.1.3) - '@angular-eslint/eslint-plugin-template': 16.0.3(eslint@8.42.0)(typescript@5.1.3) - '@angular-eslint/template-parser': 16.0.3(eslint@8.42.0)(typescript@5.1.3) + '@angular-eslint/eslint-plugin': 16.0.3(eslint@8.42.0)(typescript@5.2.2) + '@angular-eslint/eslint-plugin-template': 16.0.3(eslint@8.42.0)(typescript@5.2.2) + '@angular-eslint/template-parser': 16.0.3(eslint@8.42.0)(typescript@5.2.2) '@next/eslint-plugin-next': 13.4.7 '@rushstack/eslint-patch': 1.3.2 - '@typescript-eslint/eslint-plugin': 5.59.9(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.1.3) - '@typescript-eslint/parser': 5.59.9(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/eslint-plugin': 5.59.9(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.2.2) + '@typescript-eslint/parser': 5.59.9(eslint@8.42.0)(typescript@5.2.2) astro-eslint-parser: 0.13.3 eslint-config-prettier: 8.8.0(eslint@8.42.0) - eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.59.9)(eslint-plugin-i@2.28.0-2)(eslint@8.42.0) + eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.59.9)(eslint-plugin-i@2.28.1)(eslint@8.42.0) eslint-plugin-astro: 0.26.2(eslint@8.42.0) eslint-plugin-cypress: 2.13.3(eslint@8.42.0) - eslint-plugin-import: /eslint-plugin-i@2.28.0-2(@typescript-eslint/parser@5.59.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0) - eslint-plugin-jest: 27.2.1(@typescript-eslint/eslint-plugin@5.59.9)(eslint@8.42.0)(jest@29.5.0)(typescript@5.1.3) + eslint-plugin-import: /eslint-plugin-i@2.28.1(@typescript-eslint/parser@5.59.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0) + eslint-plugin-jest: 27.2.1(@typescript-eslint/eslint-plugin@5.59.9)(eslint@8.42.0)(jest@29.7.0)(typescript@5.2.2) eslint-plugin-jsdoc: 43.2.0(eslint@8.42.0) eslint-plugin-jsx-a11y: 6.7.1(eslint@8.42.0) eslint-plugin-lodash: 7.4.0(eslint@8.42.0) @@ -2999,12 +3130,12 @@ packages: eslint-plugin-promise: 6.1.1(eslint@8.42.0) eslint-plugin-react: 7.32.2(eslint@8.42.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.42.0) - eslint-plugin-rxjs: 5.0.3(eslint@8.42.0)(typescript@5.1.3) - eslint-plugin-rxjs-angular: 2.0.1(eslint@8.42.0)(typescript@5.1.3) + eslint-plugin-rxjs: 5.0.3(eslint@8.42.0)(typescript@5.2.2) + eslint-plugin-rxjs-angular: 2.0.1(eslint@8.42.0)(typescript@5.2.2) eslint-plugin-sonarjs: 0.19.0(eslint@8.42.0) eslint-plugin-svelte3: 4.0.0(eslint@8.42.0)(svelte@3.59.2) eslint-plugin-tsdoc: 0.2.17 - eslint-plugin-typescript-sort-keys: 2.3.0(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.1.3) + eslint-plugin-typescript-sort-keys: 2.3.0(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.2.2) eslint-plugin-unicorn: 47.0.0(eslint@8.42.0) eslint-plugin-vue: 9.15.1(eslint@8.42.0) vue-eslint-parser: 9.3.1(eslint@8.42.0) @@ -3036,32 +3167,32 @@ packages: eslint: 8.42.0 dev: true - /eslint-etc@5.2.1(eslint@8.42.0)(typescript@5.1.3): + /eslint-etc@5.2.1(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-lFJBSiIURdqQKq9xJhvSJFyPA+VeTh5xvk24e8pxVL7bwLBtGF60C/KRkLTMrvCZ6DA3kbPuYhLWY0TZMlqTsg==} peerDependencies: eslint: ^8.0.0 typescript: '>=4.0.0' dependencies: - '@typescript-eslint/experimental-utils': 5.60.1(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/experimental-utils': 5.60.1(eslint@8.42.0)(typescript@5.2.2) eslint: 8.42.0 - tsutils: 3.21.0(typescript@5.1.3) - tsutils-etc: 1.4.2(tsutils@3.21.0)(typescript@5.1.3) - typescript: 5.1.3 + tsutils: 3.21.0(typescript@5.2.2) + tsutils-etc: 1.4.2(tsutils@3.21.0)(typescript@5.2.2) + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /eslint-import-resolver-node@0.3.7: - resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: debug: 3.2.7 - is-core-module: 2.12.1 - resolve: 1.22.3 + is-core-module: 2.13.0 + resolve: 1.22.6 transitivePeerDependencies: - supports-color dev: true - /eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.59.9)(eslint-plugin-i@2.28.0-2)(eslint@8.42.0): + /eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.59.9)(eslint-plugin-i@2.28.1)(eslint@8.42.0): resolution: {integrity: sha512-TdJqPHs2lW5J9Zpe17DZNQuDnox4xo2o+0tE7Pggain9Rbc19ik8kFtXdxZ250FVx2kF4vlt2RSf4qlUpG7bhw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -3071,8 +3202,8 @@ packages: debug: 4.3.4 enhanced-resolve: 5.15.0 eslint: 8.42.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.9)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0) - eslint-plugin-import: /eslint-plugin-i@2.28.0-2(@typescript-eslint/parser@5.59.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.9)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0) + eslint-plugin-import: /eslint-plugin-i@2.28.1(@typescript-eslint/parser@5.59.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0) get-tsconfig: 4.6.2 globby: 13.2.0 is-core-module: 2.12.1 @@ -3110,7 +3241,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.59.9)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.59.9)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -3131,11 +3262,11 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.59.9(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/parser': 5.59.9(eslint@8.42.0)(typescript@5.2.2) debug: 3.2.7 eslint: 8.42.0 - eslint-import-resolver-node: 0.3.7 - eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.59.9)(eslint-plugin-i@2.28.0-2)(eslint@8.42.0) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.59.9)(eslint-plugin-i@2.28.1)(eslint@8.42.0) transitivePeerDependencies: - supports-color dev: true @@ -3177,8 +3308,8 @@ packages: regexpp: 3.2.0 dev: true - /eslint-plugin-i@2.28.0-2(@typescript-eslint/parser@5.59.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0): - resolution: {integrity: sha512-z48kG4qmE4TmiLcxbmvxMT5ycwvPkXaWW0XpU1L768uZaTbiDbxsHMEdV24JHlOR1xDsPpKW39BfP/pRdYIwFA==} + /eslint-plugin-i@2.28.1(@typescript-eslint/parser@5.59.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0): + resolution: {integrity: sha512-a4oVt0j3ixNhGhvV4XF6NS7OWRFK2rrJ0Q5C4S2dSRb8FxZi31J0uUd5WJLL58wnVJ/OiQ1BxiXnFA4dWQO1Cg==} engines: {node: '>=12'} peerDependencies: eslint: ^7.2.0 || ^8 @@ -3186,12 +3317,12 @@ packages: debug: 3.2.7 doctrine: 2.1.0 eslint: 8.42.0 - eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.9)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0) - get-tsconfig: 4.6.2 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.9)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.5.5)(eslint@8.42.0) + get-tsconfig: 4.7.2 is-glob: 4.0.3 minimatch: 3.1.2 - resolve: 1.22.3 + resolve: 1.22.6 semver: 7.5.4 transitivePeerDependencies: - '@typescript-eslint/parser' @@ -3200,7 +3331,7 @@ packages: - supports-color dev: true - /eslint-plugin-jest@27.2.1(@typescript-eslint/eslint-plugin@5.59.9)(eslint@8.42.0)(jest@29.5.0)(typescript@5.1.3): + /eslint-plugin-jest@27.2.1(@typescript-eslint/eslint-plugin@5.59.9)(eslint@8.42.0)(jest@29.7.0)(typescript@5.2.2): resolution: {integrity: sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -3213,10 +3344,10 @@ packages: jest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 5.59.9(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.1.3) - '@typescript-eslint/utils': 5.59.9(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/eslint-plugin': 5.59.9(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.2.2) + '@typescript-eslint/utils': 5.59.9(eslint@8.42.0)(typescript@5.2.2) eslint: 8.42.0 - jest: 29.5.0(@types/node@20.2.5)(ts-node@10.9.1) + jest: 29.7.0(@types/node@20.8.2)(ts-node@10.9.1) transitivePeerDependencies: - supports-color - typescript @@ -3235,7 +3366,7 @@ packages: escape-string-regexp: 4.0.0 eslint: 8.42.0 esquery: 1.5.0 - semver: 7.5.2 + semver: 7.5.4 spdx-expression-parse: 3.0.1 transitivePeerDependencies: - supports-color @@ -3263,7 +3394,7 @@ packages: minimatch: 3.1.2 object.entries: 1.1.6 object.fromentries: 2.0.6 - semver: 6.3.0 + semver: 6.3.1 dev: true /eslint-plugin-lodash@7.4.0(eslint@8.42.0): @@ -3320,8 +3451,8 @@ packages: ignore: 5.2.4 is-core-module: 2.12.1 minimatch: 3.1.2 - resolve: 1.22.2 - semver: 7.5.2 + resolve: 1.22.6 + semver: 7.5.4 dev: true /eslint-plugin-prettier@4.2.1(eslint-config-prettier@9.0.0)(eslint@8.42.0)(prettier@2.8.8): @@ -3379,44 +3510,44 @@ packages: object.values: 1.1.6 prop-types: 15.8.1 resolve: 2.0.0-next.4 - semver: 6.3.0 + semver: 6.3.1 string.prototype.matchall: 4.0.8 dev: true - /eslint-plugin-rxjs-angular@2.0.1(eslint@8.42.0)(typescript@5.1.3): + /eslint-plugin-rxjs-angular@2.0.1(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-HJ/JHhjDJKyFUmM8o7rS91WNkNv7W7Z/okR5X3hqG7tKVMLOJi4T63Aa74ECuCdowmdfW75p2RrW4R8WeoZIKQ==} peerDependencies: eslint: ^8.0.0 typescript: '>=4.0.0' dependencies: - '@typescript-eslint/experimental-utils': 5.60.1(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/experimental-utils': 5.60.1(eslint@8.42.0)(typescript@5.2.2) common-tags: 1.8.2 eslint: 8.42.0 - eslint-etc: 5.2.1(eslint@8.42.0)(typescript@5.1.3) + eslint-etc: 5.2.1(eslint@8.42.0)(typescript@5.2.2) requireindex: 1.2.0 tslib: 2.6.0 - typescript: 5.1.3 + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-rxjs@5.0.3(eslint@8.42.0)(typescript@5.1.3): + /eslint-plugin-rxjs@5.0.3(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-fcVkqLmYLRfRp+ShafjpUKuaZ+cw/sXAvM5dfSxiEr7M28QZ/NY7vaOr09FB4rSaZsQyLBnNPh5SL+4EgKjh8Q==} peerDependencies: eslint: ^8.0.0 typescript: '>=4.0.0' dependencies: - '@typescript-eslint/experimental-utils': 5.60.1(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/experimental-utils': 5.60.1(eslint@8.42.0)(typescript@5.2.2) common-tags: 1.8.2 decamelize: 5.0.1 eslint: 8.42.0 - eslint-etc: 5.2.1(eslint@8.42.0)(typescript@5.1.3) + eslint-etc: 5.2.1(eslint@8.42.0)(typescript@5.2.2) requireindex: 1.2.0 rxjs-report-usage: 1.0.6 tslib: 2.6.0 - tsutils: 3.21.0(typescript@5.1.3) - tsutils-etc: 1.4.2(tsutils@3.21.0)(typescript@5.1.3) - typescript: 5.1.3 + tsutils: 3.21.0(typescript@5.2.2) + tsutils-etc: 1.4.2(tsutils@3.21.0)(typescript@5.2.2) + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true @@ -3447,7 +3578,7 @@ packages: '@microsoft/tsdoc-config': 0.16.2 dev: true - /eslint-plugin-typescript-sort-keys@2.3.0(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.1.3): + /eslint-plugin-typescript-sort-keys@2.3.0(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.2.2): resolution: {integrity: sha512-3LAcYulo5gNYiPWee+TksITfvWeBuBjGgcSLTacPESFVKEoy8laOQuZvJlSCwTBHT2SCGIxr3bJ56zuux+3MCQ==} engines: {node: 12 || >= 13.9} peerDependencies: @@ -3455,12 +3586,12 @@ packages: eslint: ^5 || ^6 || ^7 || ^8 typescript: ^3 || ^4 || ^5 dependencies: - '@typescript-eslint/experimental-utils': 5.60.1(eslint@8.42.0)(typescript@5.1.3) - '@typescript-eslint/parser': 5.59.9(eslint@8.42.0)(typescript@5.1.3) + '@typescript-eslint/experimental-utils': 5.60.1(eslint@8.42.0)(typescript@5.2.2) + '@typescript-eslint/parser': 5.59.9(eslint@8.42.0)(typescript@5.2.2) eslint: 8.42.0 json-schema: 0.4.0 natural-compare-lite: 1.4.0 - typescript: 5.1.3 + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true @@ -3486,7 +3617,7 @@ packages: regexp-tree: 0.1.27 regjsparser: 0.10.0 safe-regex: 2.1.1 - semver: 7.5.2 + semver: 7.5.4 strip-indent: 3.0.0 dev: true @@ -3501,7 +3632,7 @@ packages: natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.0.13 - semver: 7.5.2 + semver: 7.5.4 vue-eslint-parser: 9.3.1(eslint@8.42.0) xml-name-validator: 4.0.0 transitivePeerDependencies: @@ -3674,8 +3805,8 @@ packages: strip-final-newline: 2.0.0 dev: true - /execa@7.1.1: - resolution: {integrity: sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==} + /execa@7.2.0: + resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==} engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} dependencies: cross-spawn: 7.0.3 @@ -3705,6 +3836,17 @@ packages: jest-util: 29.5.0 dev: true + /expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + dev: true + /extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} dev: true @@ -3843,7 +3985,7 @@ packages: engines: {node: '>=14'} dependencies: cross-spawn: 7.0.3 - signal-exit: 4.0.2 + signal-exit: 4.1.0 dev: true /format@0.2.2: @@ -3871,8 +4013,8 @@ packages: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true - /fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true @@ -3979,6 +4121,12 @@ packages: resolve-pkg-maps: 1.0.0 dev: true + /get-tsconfig@4.7.2: + resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: true + /gh-got@7.1.0: resolution: {integrity: sha512-KeWkkhresa7sbpzQLYzITMgez5rMigUsijhmSAHcLDORIMUbdlkdoZyaN1wQvIjmUZnyb/wkAPaXb4MQKX0mdQ==} engines: {node: '>=4'} @@ -4025,7 +4173,7 @@ packages: hasBin: true dependencies: meow: 4.0.1 - semver: 6.3.0 + semver: 6.3.1 dev: true /git-semver-tags@4.1.1: @@ -4034,7 +4182,7 @@ packages: hasBin: true dependencies: meow: 8.1.2 - semver: 6.3.0 + semver: 6.3.1 dev: true /gitconfiglocal@1.0.0: @@ -4064,11 +4212,23 @@ packages: dependencies: foreground-child: 3.1.1 jackspeak: 2.2.1 - minimatch: 9.0.1 + minimatch: 9.0.3 minipass: 6.0.2 path-scurry: 1.9.2 dev: true + /glob@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.3 + minipass: 6.0.2 + path-scurry: 1.10.1 + dev: true + /glob@7.1.7: resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} dependencies: @@ -4470,6 +4630,12 @@ packages: has: 1.0.3 dev: true + /is-core-module@2.13.0: + resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} + dependencies: + has: 1.0.3 + dev: true + /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} @@ -4714,21 +4880,34 @@ packages: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.22.1 - '@babel/parser': 7.22.4 + '@babel/core': 7.23.0 + '@babel/parser': 7.23.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 - semver: 6.3.0 + semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /istanbul-lib-report@3.0.0: - resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} - engines: {node: '>=8'} + /istanbul-lib-instrument@6.0.0: + resolution: {integrity: sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==} + engines: {node: '>=10'} + dependencies: + '@babel/core': 7.23.0 + '@babel/parser': 7.23.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} dependencies: istanbul-lib-coverage: 3.2.0 - make-dir: 3.1.0 + make-dir: 4.0.0 supports-color: 7.2.0 dev: true @@ -4743,12 +4922,12 @@ packages: - supports-color dev: true - /istanbul-reports@3.1.5: - resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} + /istanbul-reports@3.1.6: + resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} engines: {node: '>=8'} dependencies: html-escaper: 2.0.2 - istanbul-lib-report: 3.0.0 + istanbul-lib-report: 3.0.1 dev: true /isurl@1.0.0: @@ -4768,11 +4947,21 @@ packages: '@pkgjs/parseargs': 0.11.0 dev: true - /jest-changed-files@29.5.0: - resolution: {integrity: sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==} + /jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: true + + /jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: execa: 5.1.1 + jest-util: 29.7.0 p-limit: 3.1.0 dev: true @@ -4804,8 +4993,37 @@ packages: - supports-color dev: true - /jest-cli@29.5.0(@types/node@20.2.5)(ts-node@10.9.1): - resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==} + /jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.8.2 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.1 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.0.4 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + + /jest-cli@29.7.0(@types/node@20.8.2)(ts-node@10.9.1): + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true peerDependencies: @@ -4814,26 +5032,26 @@ packages: node-notifier: optional: true dependencies: - '@jest/core': 29.5.0(ts-node@10.9.1) - '@jest/test-result': 29.5.0 - '@jest/types': 29.5.0 + '@jest/core': 29.7.0(ts-node@10.9.1) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.8.2)(ts-node@10.9.1) exit: 0.1.2 - graceful-fs: 4.2.11 import-local: 3.1.0 - jest-config: 29.5.0(@types/node@20.2.5)(ts-node@10.9.1) - jest-util: 29.5.0 - jest-validate: 29.5.0 - prompts: 2.4.2 + jest-config: 29.7.0(@types/node@20.8.2)(ts-node@10.9.1) + jest-util: 29.7.0 + jest-validate: 29.7.0 yargs: 17.7.2 transitivePeerDependencies: - '@types/node' + - babel-plugin-macros - supports-color - ts-node dev: true - /jest-config@29.5.0(@types/node@20.2.5)(ts-node@10.9.1): - resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==} + /jest-config@29.7.0(@types/node@20.8.2)(ts-node@10.9.1): + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@types/node': '*' @@ -4844,46 +5062,47 @@ packages: ts-node: optional: true dependencies: - '@babel/core': 7.22.1 - '@jest/test-sequencer': 29.5.0 - '@jest/types': 29.5.0 - '@types/node': 20.2.5 - babel-jest: 29.5.0(@babel/core@7.22.1) + '@babel/core': 7.23.0 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.8.2 + babel-jest: 29.7.0(@babel/core@7.23.0) chalk: 4.1.2 ci-info: 3.8.0 deepmerge: 4.3.1 glob: 7.2.3 graceful-fs: 4.2.11 - jest-circus: 29.5.0 - jest-environment-node: 29.5.0 - jest-get-type: 29.4.3 - jest-regex-util: 29.4.3 - jest-resolve: 29.5.0 - jest-runner: 29.5.0 - jest-util: 29.5.0 - jest-validate: 29.5.0 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 micromatch: 4.0.5 parse-json: 5.2.0 - pretty-format: 29.5.0 + pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.1(@types/node@20.2.5)(typescript@5.1.3) + ts-node: 10.9.1(@types/node@20.8.2)(typescript@5.2.2) transitivePeerDependencies: + - babel-plugin-macros - supports-color dev: true - /jest-diff@29.5.0: - resolution: {integrity: sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==} + /jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: chalk: 4.1.2 - diff-sequences: 29.4.3 - jest-get-type: 29.4.3 - pretty-format: 29.5.0 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 dev: true - /jest-docblock@29.4.3: - resolution: {integrity: sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==} + /jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: detect-newline: 3.1.0 @@ -4895,21 +5114,32 @@ packages: dependencies: '@jest/types': 29.5.0 chalk: 4.1.2 - jest-get-type: 29.4.3 + jest-get-type: 29.6.3 jest-util: 29.5.0 pretty-format: 29.5.0 dev: true - /jest-environment-node@29.5.0: - resolution: {integrity: sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==} + /jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/environment': 29.5.0 - '@jest/fake-timers': 29.5.0 - '@jest/types': 29.5.0 - '@types/node': 20.2.5 - jest-mock: 29.5.0 - jest-util: 29.5.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + dev: true + + /jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.8.2 + jest-mock: 29.7.0 + jest-util: 29.7.0 dev: true /jest-get-type@29.4.3: @@ -4917,31 +5147,36 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true - /jest-haste-map@29.5.0: - resolution: {integrity: sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==} + /jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.5.0 - '@types/graceful-fs': 4.1.6 - '@types/node': 20.2.5 + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.7 + '@types/node': 20.8.2 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 - jest-regex-util: 29.4.3 - jest-util: 29.5.0 - jest-worker: 29.5.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 micromatch: 4.0.5 walker: 1.0.8 optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 dev: true - /jest-leak-detector@29.5.0: - resolution: {integrity: sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==} + /jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - jest-get-type: 29.4.3 - pretty-format: 29.5.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 dev: true /jest-matcher-utils@29.5.0: @@ -4949,16 +5184,26 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: chalk: 4.1.2 - jest-diff: 29.5.0 - jest-get-type: 29.4.3 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 pretty-format: 29.5.0 dev: true + /jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + /jest-message-util@29.5.0: resolution: {integrity: sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/code-frame': 7.21.4 + '@babel/code-frame': 7.22.13 '@jest/types': 29.5.0 '@types/stack-utils': 2.0.1 chalk: 4.1.2 @@ -4969,16 +5214,31 @@ packages: stack-utils: 2.0.6 dev: true - /jest-mock@29.5.0: - resolution: {integrity: sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==} + /jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.5.0 - '@types/node': 20.2.5 - jest-util: 29.5.0 + '@babel/code-frame': 7.22.13 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.1 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.5 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 dev: true - /jest-pnp-resolver@1.2.3(jest-resolve@29.5.0): + /jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.8.2 + jest-util: 29.7.0 + dev: true + + /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} engines: {node: '>=6'} peerDependencies: @@ -4987,62 +5247,62 @@ packages: jest-resolve: optional: true dependencies: - jest-resolve: 29.5.0 + jest-resolve: 29.7.0 dev: true - /jest-regex-util@29.4.3: - resolution: {integrity: sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==} + /jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true - /jest-resolve-dependencies@29.5.0: - resolution: {integrity: sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==} + /jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - jest-regex-util: 29.4.3 - jest-snapshot: 29.5.0 + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 transitivePeerDependencies: - supports-color dev: true - /jest-resolve@29.5.0: - resolution: {integrity: sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==} + /jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: chalk: 4.1.2 graceful-fs: 4.2.11 - jest-haste-map: 29.5.0 - jest-pnp-resolver: 1.2.3(jest-resolve@29.5.0) - jest-util: 29.5.0 - jest-validate: 29.5.0 - resolve: 1.22.3 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.6 resolve.exports: 2.0.2 slash: 3.0.0 dev: true - /jest-runner@29.5.0: - resolution: {integrity: sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==} + /jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/console': 29.5.0 - '@jest/environment': 29.5.0 - '@jest/test-result': 29.5.0 - '@jest/transform': 29.5.0 - '@jest/types': 29.5.0 - '@types/node': 20.2.5 + '@jest/console': 29.7.0 + '@jest/environment': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.8.2 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 - jest-docblock: 29.4.3 - jest-environment-node: 29.5.0 - jest-haste-map: 29.5.0 - jest-leak-detector: 29.5.0 - jest-message-util: 29.5.0 - jest-resolve: 29.5.0 - jest-runtime: 29.5.0 - jest-util: 29.5.0 - jest-watcher: 29.5.0 - jest-worker: 29.5.0 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 p-limit: 3.1.0 source-map-support: 0.5.13 transitivePeerDependencies: @@ -5054,23 +5314,23 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/environment': 29.5.0 - '@jest/fake-timers': 29.5.0 - '@jest/globals': 29.5.0 - '@jest/source-map': 29.4.3 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0 + '@jest/source-map': 29.6.3 '@jest/test-result': 29.5.0 - '@jest/transform': 29.5.0 + '@jest/transform': 29.7.0 '@jest/types': 29.5.0 '@types/node': 20.2.5 chalk: 4.1.2 - cjs-module-lexer: 1.2.2 - collect-v8-coverage: 1.0.1 + cjs-module-lexer: 1.2.3 + collect-v8-coverage: 1.0.2 glob: 7.2.3 graceful-fs: 4.2.11 - jest-haste-map: 29.5.0 + jest-haste-map: 29.7.0 jest-message-util: 29.5.0 - jest-mock: 29.5.0 - jest-regex-util: 29.4.3 - jest-resolve: 29.5.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 jest-snapshot: 29.5.0 jest-util: 29.5.0 slash: 3.0.0 @@ -5079,33 +5339,91 @@ packages: - supports-color dev: true + /jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0 + '@jest/source-map': 29.6.3 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.8.2 + chalk: 4.1.2 + cjs-module-lexer: 1.2.3 + collect-v8-coverage: 1.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + /jest-snapshot@29.5.0: resolution: {integrity: sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.22.1 - '@babel/generator': 7.22.3 - '@babel/plugin-syntax-jsx': 7.21.4(@babel/core@7.22.1) - '@babel/plugin-syntax-typescript': 7.21.4(@babel/core@7.22.1) + '@babel/core': 7.23.0 + '@babel/generator': 7.23.0 + '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.23.0) + '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.23.0) '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 - '@jest/expect-utils': 29.5.0 - '@jest/transform': 29.5.0 + '@babel/types': 7.23.0 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 '@jest/types': 29.5.0 '@types/babel__traverse': 7.20.1 '@types/prettier': 2.7.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.1) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.0) chalk: 4.1.2 - expect: 29.5.0 + expect: 29.7.0 graceful-fs: 4.2.11 - jest-diff: 29.5.0 - jest-get-type: 29.4.3 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 jest-matcher-utils: 29.5.0 jest-message-util: 29.5.0 jest-util: 29.5.0 natural-compare: 1.4.0 pretty-format: 29.5.0 - semver: 7.5.1 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/core': 7.23.0 + '@babel/generator': 7.23.0 + '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.23.0) + '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.23.0) + '@babel/types': 7.23.0 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.0) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.5.4 transitivePeerDependencies: - supports-color dev: true @@ -5122,44 +5440,56 @@ packages: picomatch: 2.3.1 dev: true - /jest-validate@29.5.0: - resolution: {integrity: sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==} + /jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.5.0 + '@jest/types': 29.6.3 + '@types/node': 20.8.2 + chalk: 4.1.2 + ci-info: 3.8.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + dev: true + + /jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 camelcase: 6.3.0 chalk: 4.1.2 - jest-get-type: 29.4.3 + jest-get-type: 29.6.3 leven: 3.1.0 - pretty-format: 29.5.0 + pretty-format: 29.7.0 dev: true - /jest-watcher@29.5.0: - resolution: {integrity: sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==} + /jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/test-result': 29.5.0 - '@jest/types': 29.5.0 - '@types/node': 20.2.5 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.8.2 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 - jest-util: 29.5.0 + jest-util: 29.7.0 string-length: 4.0.2 dev: true - /jest-worker@29.5.0: - resolution: {integrity: sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==} + /jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 20.2.5 - jest-util: 29.5.0 + '@types/node': 20.8.2 + jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true - /jest@29.5.0(@types/node@20.2.5)(ts-node@10.9.1): - resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==} + /jest@29.7.0(@types/node@20.8.2)(ts-node@10.9.1): + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true peerDependencies: @@ -5168,12 +5498,13 @@ packages: node-notifier: optional: true dependencies: - '@jest/core': 29.5.0(ts-node@10.9.1) - '@jest/types': 29.5.0 + '@jest/core': 29.7.0(ts-node@10.9.1) + '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.5.0(@types/node@20.2.5)(ts-node@10.9.1) + jest-cli: 29.7.0(@types/node@20.8.2)(ts-node@10.9.1) transitivePeerDependencies: - '@types/node' + - babel-plugin-macros - supports-color - ts-node dev: true @@ -5502,6 +5833,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /lru-cache@10.0.1: + resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==} + engines: {node: 14 || >=16.14} + dev: true + /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -5524,11 +5860,11 @@ packages: resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} dev: true - /make-dir@3.1.0: - resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} - engines: {node: '>=8'} + /make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} dependencies: - semver: 6.3.0 + semver: 7.5.4 dev: true /make-error@1.3.6: @@ -6064,13 +6400,6 @@ packages: brace-expansion: 2.0.1 dev: true - /minimatch@9.0.1: - resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} - engines: {node: '>=16 || 14 >=14.17'} - dependencies: - brace-expansion: 2.0.1 - dev: true - /minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} @@ -6144,8 +6473,8 @@ packages: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} dev: true - /node-releases@2.0.12: - resolution: {integrity: sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==} + /node-releases@2.0.13: + resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} dev: true /nopt@7.2.0: @@ -6160,7 +6489,7 @@ packages: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.3 + resolve: 1.22.6 semver: 5.7.1 validate-npm-package-license: 3.0.4 dev: true @@ -6170,8 +6499,8 @@ packages: engines: {node: '>=10'} dependencies: hosted-git-info: 4.1.0 - is-core-module: 2.12.1 - semver: 7.5.2 + is-core-module: 2.13.0 + semver: 7.5.1 validate-npm-package-license: 3.0.4 dev: true @@ -6462,7 +6791,7 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: - '@babel/code-frame': 7.21.4 + '@babel/code-frame': 7.22.13 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -6472,7 +6801,7 @@ packages: resolution: {integrity: sha512-SA5aMiaIjXkAiBrW/yPgLgQAQg42f7K3ACO+2l/zOvtQBwX58DMUsFJXelW2fx3yMBmWOVkR6j1MGsdSbCA4UA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: - '@babel/code-frame': 7.21.4 + '@babel/code-frame': 7.22.13 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 2.0.3 @@ -6514,6 +6843,14 @@ packages: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true + /path-scurry@1.10.1: + resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + lru-cache: 10.0.1 + minipass: 6.0.2 + dev: true + /path-scurry@1.9.2: resolution: {integrity: sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg==} engines: {node: '>=16 || 14 >=14.17'} @@ -6574,8 +6911,8 @@ packages: engines: {node: '>=0.10.0'} dev: true - /pirates@4.0.5: - resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} + /pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} dev: true @@ -6640,6 +6977,15 @@ packages: react-is: 18.2.0 dev: true + /pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.2.0 + dev: true + /proc-log@3.0.0: resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -6678,6 +7024,10 @@ packages: resolution: {integrity: sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==} dev: true + /pure-rand@6.0.4: + resolution: {integrity: sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==} + dev: true + /q@1.5.1: resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} engines: {node: '>=0.6.0', teleport: '>=0.2.0'} @@ -6935,24 +7285,15 @@ packages: /resolve@1.19.0: resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} dependencies: - is-core-module: 2.12.1 - path-parse: 1.0.7 - dev: true - - /resolve@1.22.2: - resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} - hasBin: true - dependencies: - is-core-module: 2.12.1 + is-core-module: 2.13.0 path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 dev: true - /resolve@1.22.3: - resolution: {integrity: sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==} + /resolve@1.22.6: + resolution: {integrity: sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==} hasBin: true dependencies: - is-core-module: 2.12.1 + is-core-module: 2.13.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 dev: true @@ -6961,7 +7302,7 @@ packages: resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} hasBin: true dependencies: - is-core-module: 2.12.1 + is-core-module: 2.13.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 dev: true @@ -7009,9 +7350,9 @@ packages: resolution: {integrity: sha512-omv1DIv5z1kV+zDAEjaDjWSkx8w5TbFp5NZoPwUipwzYVcor/4So9ZU3bUyQ1c8lxY5Q0Es/ztWW7PGjY7to0Q==} hasBin: true dependencies: - '@babel/parser': 7.22.4 - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 + '@babel/parser': 7.23.0 + '@babel/traverse': 7.23.0 + '@babel/types': 7.23.0 bent: 7.3.12 chalk: 4.1.2 glob: 7.2.3 @@ -7059,8 +7400,8 @@ packages: hasBin: true dev: true - /semver@6.3.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true dev: true @@ -7080,14 +7421,6 @@ packages: lru-cache: 6.0.0 dev: true - /semver@7.5.2: - resolution: {integrity: sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==} - engines: {node: '>=10'} - hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: true - /semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} engines: {node: '>=10'} @@ -7129,8 +7462,8 @@ packages: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true - /signal-exit@4.0.2: - resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==} + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} dev: true @@ -7553,8 +7886,8 @@ packages: resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==} dev: true - /ts-jest@29.1.0(@babel/core@7.22.1)(@jest/types@29.5.0)(jest@29.5.0)(typescript@5.1.3): - resolution: {integrity: sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==} + /ts-jest@29.1.1(@babel/core@7.23.0)(@jest/types@29.5.0)(jest@29.7.0)(typescript@5.2.2): + resolution: {integrity: sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true peerDependencies: @@ -7574,21 +7907,21 @@ packages: esbuild: optional: true dependencies: - '@babel/core': 7.22.1 + '@babel/core': 7.23.0 '@jest/types': 29.5.0 bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 29.5.0(@types/node@20.2.5)(ts-node@10.9.1) + jest: 29.7.0(@types/node@20.8.2)(ts-node@10.9.1) jest-util: 29.5.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.5.1 - typescript: 5.1.3 + semver: 7.5.4 + typescript: 5.2.2 yargs-parser: 21.1.1 dev: true - /ts-node@10.9.1(@types/node@20.2.5)(typescript@4.9.5): + /ts-node@10.9.1(@types/node@20.2.5)(typescript@5.2.2): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -7614,12 +7947,12 @@ packages: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.9.5 + typescript: 5.2.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 dev: true - /ts-node@10.9.1(@types/node@20.2.5)(typescript@5.1.3): + /ts-node@10.9.1(@types/node@20.8.2)(typescript@5.2.2): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -7638,14 +7971,14 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.2.5 + '@types/node': 20.8.2 acorn: 8.8.2 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.1.3 + typescript: 5.2.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 dev: true @@ -7658,27 +7991,27 @@ packages: resolution: {integrity: sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==} dev: true - /tsutils-etc@1.4.2(tsutils@3.21.0)(typescript@5.1.3): + /tsutils-etc@1.4.2(tsutils@3.21.0)(typescript@5.2.2): resolution: {integrity: sha512-2Dn5SxTDOu6YWDNKcx1xu2YUy6PUeKrWZB/x2cQ8vY2+iz3JRembKn/iZ0JLT1ZudGNwQQvtFX9AwvRHbXuPUg==} hasBin: true peerDependencies: tsutils: ^3.0.0 typescript: '>=4.0.0' dependencies: - '@types/yargs': 17.0.24 - tsutils: 3.21.0(typescript@5.1.3) - typescript: 5.1.3 + '@types/yargs': 17.0.26 + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2 yargs: 17.7.2 dev: true - /tsutils@3.21.0(typescript@5.1.3): + /tsutils@3.21.0(typescript@5.2.2): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 5.1.3 + typescript: 5.2.2 dev: true /type-check@0.4.0: @@ -7741,10 +8074,10 @@ packages: typedoc: '>=0.24.0' dependencies: handlebars: 4.7.7 - typedoc: 0.25.0(typescript@5.1.3) + typedoc: 0.25.0(typescript@5.2.2) dev: true - /typedoc@0.25.0(typescript@5.1.3): + /typedoc@0.25.0(typescript@5.2.2): resolution: {integrity: sha512-FvCYWhO1n5jACE0C32qg6b3dSfQ8f2VzExnnRboowHtqUD6ARzM2r8YJeZFYXhcm2hI4C2oCRDgNPk/yaQUN9g==} engines: {node: '>= 16'} hasBin: true @@ -7755,17 +8088,11 @@ packages: marked: 4.3.0 minimatch: 9.0.3 shiki: 0.14.2 - typescript: 5.1.3 + typescript: 5.2.2 dev: true - /typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} - hasBin: true - dev: true - - /typescript@5.1.3: - resolution: {integrity: sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==} + /typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} engines: {node: '>=14.17'} hasBin: true dev: true @@ -7793,7 +8120,7 @@ packages: '@types/concat-stream': 2.0.0 '@types/debug': 4.1.8 '@types/is-empty': 1.2.1 - '@types/node': 18.16.18 + '@types/node': 18.18.3 '@types/unist': 2.0.6 concat-stream: 2.0.0 debug: 4.3.4 @@ -7890,13 +8217,13 @@ packages: engines: {node: '>=8'} dev: true - /update-browserslist-db@1.0.11(browserslist@4.21.7): - resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==} + /update-browserslist-db@1.0.13(browserslist@4.22.1): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: - browserslist: 4.21.7 + browserslist: 4.22.1 escalade: 3.1.1 picocolors: 1.0.0 dev: true @@ -7948,7 +8275,7 @@ packages: resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==} engines: {node: '>=10.12.0'} dependencies: - '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/trace-mapping': 0.3.19 '@types/istanbul-lib-coverage': 2.0.4 convert-source-map: 1.9.0 dev: true @@ -8024,7 +8351,7 @@ packages: espree: 9.5.2 esquery: 1.5.0 lodash: 4.17.21 - semver: 7.5.2 + semver: 7.5.4 transitivePeerDependencies: - supports-color dev: true diff --git a/src/dataset/DataSet.ts b/src/dataset/DataSet.ts index e1474f7..dc91bb8 100644 --- a/src/dataset/DataSet.ts +++ b/src/dataset/DataSet.ts @@ -1,6 +1,6 @@ import { assignIncrementingIds } from '../matcher/BlacklistedTerm'; import type { MatchPayload } from '../matcher/MatchPayload'; -import type { NfaMatcherOptions } from '../matcher/nfa/NfaMatcher'; +import type { RegExpMatcherOptions } from '../matcher/regexp/RegExpMatcher'; import type { ParsedPattern } from '../pattern/Nodes'; /** @@ -104,8 +104,7 @@ export class DataSet { } /** - * Returns the dataset in a format suitable for usage with the [[RegExpMatcher]] - * or the [[NfaMatcher]]. + * Returns the dataset in a format suitable for usage with the [[RegExpMatcher]]. * * @example * ```typescript @@ -115,16 +114,8 @@ export class DataSet { * // additional options here * }); * ``` - * @example - * ```typescript - * // With the NfaMatcher: - * const matcher = new NfaMatcher({ - * ...dataset.build(), - * // additional options here - * }); - * ``` */ - public build(): Pick { + public build(): Pick { return { blacklistedTerms: assignIncrementingIds(this.containers.flatMap((p) => p.patterns)), whitelistedTerms: this.containers.flatMap((p) => p.whitelistedTerms), diff --git a/src/index.ts b/src/index.ts index fd93d09..5675ee3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,7 +4,6 @@ export * from './censor/TextCensor'; export * from './dataset/DataSet'; export * from './matcher/regexp/RegExpMatcher'; -export * from './matcher/nfa/NfaMatcher'; export * from './matcher/BlacklistedTerm'; export * from './matcher/MatchPayload'; export * from './matcher/Matcher'; diff --git a/src/matcher/BlacklistedTerm.ts b/src/matcher/BlacklistedTerm.ts index 3cb7f6e..1b2c383 100644 --- a/src/matcher/BlacklistedTerm.ts +++ b/src/matcher/BlacklistedTerm.ts @@ -32,7 +32,7 @@ export interface BlacklistedTerm { * ``` * @param patterns - List of parsed patterns. * @returns A list of blacklisted terms with valid IDs which can then be passed - * to the [[RegExpMatcher]] or [[NfaMatcher]]. + * to the [[RegExpMatcher]]. */ export function assignIncrementingIds(patterns: ParsedPattern[]) { let currentId = 0; diff --git a/src/matcher/Matcher.ts b/src/matcher/Matcher.ts index f2cda21..3962494 100644 --- a/src/matcher/Matcher.ts +++ b/src/matcher/Matcher.ts @@ -5,11 +5,7 @@ import type { MatchPayload } from './MatchPayload'; * terms. * * See: - * - [[NfaMatcher]] for an implementation using finite automata; * - [[RegExpMatcher]] for an implementation using regular expressions. - * - * Refer to the documentation of the classes mentioned above for discussion of - * which circumstances one should prefer one over the other. */ export interface Matcher { /** diff --git a/src/matcher/nfa/NfaMatcher.ts b/src/matcher/nfa/NfaMatcher.ts deleted file mode 100644 index 0decfab..0000000 --- a/src/matcher/nfa/NfaMatcher.ts +++ /dev/null @@ -1,663 +0,0 @@ -import type { LiteralNode } from '../../pattern/Nodes'; -import { SyntaxKind } from '../../pattern/Nodes'; -import type { SimpleNode } from '../../pattern/Simplifier'; -import { simplify } from '../../pattern/Simplifier'; -import type { LiteralGroup, WildcardGroup } from '../../pattern/Util'; -import { computePatternMatchLength, groupByNodeType, potentiallyMatchesEmptyString } from '../../pattern/Util'; -import { TransformerSet } from '../../transformer/TransformerSet'; -import type { TransformerContainer } from '../../transformer/Transformers'; -import { isHighSurrogate, isLowSurrogate, isWordChar } from '../../util/Char'; -import { CharacterIterator } from '../../util/CharacterIterator'; -import { CircularBuffer } from '../../util/CircularBuffer'; -import { Queue } from '../../util/Queue'; -import type { BlacklistedTerm } from '../BlacklistedTerm'; -import { IntervalCollection } from '../IntervalCollection'; -import type { MatchPayload } from '../MatchPayload'; -import { compareMatchByPositionAndId } from '../MatchPayload'; -import type { Matcher } from '../Matcher'; -import { WhitelistedTermMatcher } from './WhitelistedTermMatcher'; -import type { PartialMatchData } from './trie/BlacklistTrieNode'; -import { BlacklistTrieNode, NodeFlag, PartialMatchFlag, SharedFlag, hashPartialMatch } from './trie/BlacklistTrieNode'; -import type { ForwardingEdgeCollection } from './trie/edge/ForwardingEdgeCollection'; - -/** - * An implementation of the [[Matcher]] interface using finite automata - * techniques. - * - * It is theoretically faster than the [[RegExpMatcher]]: the `hasMatch()` and - * `getAllMatches()` execute in time proportional only to that of the length of - * the input text and the number of matches. In other words, it _theoretically_ - * should not degrade in performance as you add more terms - matching with 100 - * and 1000 patterns should have the same performance. It achieves this by - * building a heavily modified [Aho-Corasick - * automaton](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm) from - * the input patterns. - * - * In practice, its high constant factors make it slower than the - * [[RegExpMatcher]] until about ~100 patterns, at which point both - * implementations have approximately the same performance. - * - * The regular-expression matcher should be preferred to this one if at all - * possible, as it uses more memory and is only marginally faster at the scale - * most users of this package are expected to use it at. However, it may be - * appropriate if: - * - * - You have a large number of patterns (> 100); - * - You expect to be matching on long text; - * - You have benchmarked the implementations and found the [[NfaMatcher]] to be - * noticeably faster. - */ -export class NfaMatcher implements Matcher { - private readonly rootNode = new BlacklistTrieNode(); - - private readonly originalIds: number[] = []; // originalIds[i] is the term ID of the the pattern with ID i - - private readonly matchLengths: number[] = []; // matchLengths[i] is the match length of the pattern with ID i - - private readonly partialMatchStepCounts = new Map(); // partialMatchStepCounts[i] is the total number of steps of the pattern with ID i. Only applies to partial matches. - - private readonly wildcardOnlyPatterns: WildcardOnlyPatternData[] = []; - - // Maximum number of trailing wildcards. - // - // x x x ? y y ? ? ? ? - // ^^^^^^^ - // 4 trailing wildcards - private maxTrailingWildcardCount = 0; - - // Maximum distance between the start of a partial pattern and the end of the partial pattern following it. - // - // x x x ? ? ? y y y y - // 0 1 2 3 4 5 6 7 8 9 - // ^^^^^^^^^^^^^^^^^^^ - // distance of 10 - // - // This value is equal to how long we need to keep partial matches around. - private maxPartialPatternDistance = 0; - - private maxMatchLength = 0; // Maximum match length of any pattern, equal to how many indices to the left of the current position we need to track. - - private currentId = 0; // Current generated pattern ID. - - private readonly whitelistedTermMatcher: WhitelistedTermMatcher; - - private readonly slowTransformers: TransformerSet; - - private readonly fastTransformers: TransformerSet; - - // Use two iterators: one fast, and one slow. The fast iterator will - // constantly be |maxTrailingWildcardCount| positions head of the slow - // iterator. - private readonly slowIter = new CharacterIterator(); - - private readonly fastIter = new CharacterIterator(); - - // Sliding window of indices used for matching. - // - // current position - // | - // i0 i1 i2 i3 i4 i5 - // ^^^^^^^^^^^^^^^^^ - // maxMatchLength - private readonly usedIndices: CircularBuffer; - - // Sliding window of indices to the right of the current position. - // - // current position - // | - // i6 i7 i8 i9 i10 i11 i12 i13 - // ^^^^^^^^^^^^^^^^^^^^^^^^^^ - // maxTrailingWildcardCount - private readonly futureIndices: CircularBuffer; - - private matches: MatchPayload[] = []; - - private readonly partialMatches: CircularBuffer | undefined>; // partial matches found; value is a set of partial match hashes - - private currentNode = this.rootNode; - - private whitelistedIntervals = new IntervalCollection(); - - /** - * Creates a new [[NfaMatcher]] with the options given. - * - * @example - * ```typescript - * // Use the options provided by the English preset. - * const matcher = new NfaMatcher({ - * ...englishDataset.build(), - * ...englishRecommendedTransformers, - * }); - * ``` - * @example - * ```typescript - * // Simple matcher that only has blacklisted patterns. - * const matcher = new NfaMatcher({ - * blacklistedTerms: assignIncrementingIds([ - * pattern`fuck`, - * pattern`f?uck`, // wildcards (?) - * pattern`bitch`, - * pattern`b[i]tch` // optionals ([i] matches either "i" or "") - * ]), - * }); - * - * // Check whether some string matches any of the patterns. - * const doesMatch = matcher.hasMatch('fuck you bitch'); - * ``` - * @example - * ```typescript - * // A more advanced example, with transformers and whitelisted terms. - * const matcher = new NfaMatcher({ - * blacklistedTerms: [ - * { id: 1, pattern: pattern`penis` }, - * { id: 2, pattern: pattern`fuck` }, - * ], - * whitelistedTerms: ['pen is'], - * blacklistMatcherTransformers: [ - * resolveConfusablesTransformer(), // '🅰' => 'a' - * resolveLeetSpeakTransformer(), // '$' => 's' - * foldAsciiCharCaseTransformer(), // case insensitive matching - * skipNonAlphabeticTransformer(), // 'f.u...c.k' => 'fuck' - * collapseDuplicatesTransformer(), // 'aaaa' => 'a' - * ], - * }); - * - * // Output all matches. - * console.log(matcher.getAllMatches('fu.....uuuuCK the pen is mightier than the sword!')); - * ``` - * @param options - Options to use. - */ - public constructor({ - blacklistedTerms, - whitelistedTerms = [], - blacklistMatcherTransformers = [], - whitelistMatcherTransformers = [], - }: NfaMatcherOptions) { - this.whitelistedTermMatcher = new WhitelistedTermMatcher({ - terms: whitelistedTerms, - transformers: whitelistMatcherTransformers, - }); - this.slowTransformers = new TransformerSet(blacklistMatcherTransformers); - this.fastTransformers = new TransformerSet(blacklistMatcherTransformers); - this.ensureNoDuplicateIds(blacklistedTerms); - this.buildTrie(blacklistedTerms); - this.constructLinks(); - this.useUnderlyingEdgeCollectionImplementation(this.rootNode); - - // Sort wildcard-only patterns by the number of wildcards they have. - this.wildcardOnlyPatterns.sort((a, b) => - /* istanbul ignore next: not really possible to write a robust test for this */ - a.wildcardCount < b.wildcardCount ? -1 : b.wildcardCount < a.wildcardCount ? 1 : 0, - ); - this.usedIndices = new CircularBuffer(this.maxMatchLength); - this.futureIndices = new CircularBuffer(this.maxTrailingWildcardCount); - this.partialMatches = new CircularBuffer(this.maxPartialPatternDistance); - } - - public hasMatch(input: string) { - this.setInput(input); - return this.run(true); - } - - public getAllMatches(input: string, sorted = false) { - this.setInput(input); - this.run(); - if (sorted) this.matches.sort(compareMatchByPositionAndId); - return this.matches; - } - - private setInput(input: string) { - this.slowIter.setInput(input); - this.fastIter.setInput(input); - this.whitelistedIntervals = this.whitelistedTermMatcher.getMatches(input); - this.currentNode = this.rootNode; - this.slowTransformers.resetAll(); - this.fastTransformers.resetAll(); - this.usedIndices.clear(); - this.futureIndices.clear(); - this.partialMatches.clear(); - this.matches = []; - } - - private run(breakAfterFirstMatch = false) { - // Fill the future index buffer by advancing the fast iterator forward. - while (this.futureIndices.length < this.futureIndices.capacity) { - const char = this.fastIter.next().value; - if (char === undefined) { - // Iterator is done. - this.futureIndices.push(undefined); - } else { - const transformed = this.fastTransformers.applyTo(char); - // Only add the position if the character didn't become - // undefined after transformation. - if (transformed !== undefined) this.futureIndices.push(this.fastIter.position); - } - } - - for (const char of this.slowIter) { - const transformed = this.slowTransformers.applyTo(char); - if (transformed === undefined) continue; - - // Advance the index window forward. - // 1 3 4 5 7 8 9 - // becomes - // 3 4 5 7 8 9 10 (if 10 is the current position) - this.usedIndices.push(this.slowIter.position); - - // Advance the partial matches buffer forward. - this.partialMatches.push(undefined); - - // Find next usable character for the fast iterator. - if (this.maxTrailingWildcardCount > 0) { - let found = false; - while (!this.fastIter.done && !found) { - found = this.fastTransformers.applyTo(this.fastIter.next().value!) !== undefined; - if (found) this.futureIndices.push(this.fastIter.position); - } - - if (!found) this.futureIndices.push(undefined); - } - - // Follow failure links until we find a node that has a transition for the current character. - while (this.currentNode !== this.rootNode && !this.currentNode.edges.get(transformed)) { - this.currentNode = this.currentNode.failureLink; - } - - this.currentNode = this.currentNode.edges.get(transformed) ?? this.rootNode; - - // Emit matches for wildcard-only patterns. Patterns of the form - // ?^N ('?' repeated N times) always have a match ending at the - // current index if the number of characters seen is - // >= N. - for (const data of this.wildcardOnlyPatterns) { - if (data.wildcardCount > this.usedIndices.length) break; - const matchLength = this.matchLengths[data.id]; - const startIndex = this.usedIndices.get(this.usedIndices.length - matchLength)!; - const matched = this.emitMatch( - data.id, - data.flags, - startIndex, - this.slowIter.position + this.slowIter.lastWidth - 1, - matchLength, - ); - if (matched && breakAfterFirstMatch) return true; - } - - // Emit matches for the current node, then follow its output links. - if (this.currentNode.flags & NodeFlag.MatchLeaf) { - const matchLength = this.matchLengths[this.currentNode.termId]; - const startIndex = this.usedIndices.get(this.usedIndices.length - matchLength)!; - const matched = this.emitMatch( - this.currentNode.termId, - this.currentNode.flags, - startIndex, - this.slowIter.position + this.slowIter.lastWidth - 1, - matchLength, - ); - if (matched && breakAfterFirstMatch) return true; - } - - if (this.currentNode.flags & NodeFlag.PartialMatchLeaf) { - for (const partialMatch of this.currentNode.partialMatches!) { - if (this.emitPartialMatch(partialMatch) && breakAfterFirstMatch) return true; - } - } - - let outputLink = this.currentNode.outputLink; - while (outputLink) { - if (outputLink.flags & NodeFlag.PartialMatchLeaf) { - for (const partialMatch of outputLink.partialMatches!) { - if (this.emitPartialMatch(partialMatch) && breakAfterFirstMatch) return true; - } - } - - if (outputLink.flags & NodeFlag.MatchLeaf) { - const matchLength = this.matchLengths[outputLink.termId]; - const startIndex = this.usedIndices.get(this.usedIndices.length - matchLength)!; - const matched = this.emitMatch( - outputLink.termId, - outputLink.flags, - startIndex, - this.slowIter.position + this.slowIter.lastWidth - 1, - matchLength, - ); - if (matched && breakAfterFirstMatch) return true; - } - - outputLink = outputLink.outputLink; - } - } - - return this.matches.length > 0; - } - - private emitPartialMatch(data: PartialMatchData) { - // ??xxxxx - // If we have a match for 'xxxxx', the whole pattern matches if the - // number of characters seen is greater than the number of leading - // wildcards (in this case 2). - const hasSufficientCharactersBefore = data.leadingWildcardCount + data.matchLength <= this.usedIndices.length; - if (!hasSufficientCharactersBefore) return false; - - // x x ? ? y y y y y - // 0 1 2 3 4 5 5 6 7 - // - // If we have a match for 'yyyyy', the whole pattern matches if we have - // a match for 'xx' ending 7 characters before (length of 'yyyyy', plus - // two wildcards, plus one). - const hasMatchForPreviousStep = - // First step has no match before it. - data.step === 1 || - (this.partialMatches - .get(this.partialMatches.length - data.leadingWildcardCount - data.matchLength - 1) - ?.has(hashPartialMatch(data.step - 1, data.termId)) ?? - false); - if (!hasMatchForPreviousStep) return false; - if (data.step === this.partialMatchStepCounts.get(data.termId)) { - // Say the pattern is 'xx???yyyyy'. - // We're currently on 'yyyyy' and we know that the steps before - // match. We can safely emit a match if there are no trailing - // wildcards. - if (data.trailingWildcardCount === 0) { - const matchLength = this.matchLengths[data.termId]; - const startIndex = this.usedIndices.get(this.usedIndices.length - matchLength)!; - return this.emitMatch( - data.termId, - data.flags, - startIndex, - this.slowIter.position + this.slowIter.lastWidth - 1, - matchLength, - ); - } - - // Say the pattern is 'xx??yy??'. - // This pattern matches if there are at least two characters that are - // usable to the right of the current position. - let endIndex = this.futureIndices.get(data.trailingWildcardCount - 1); - if (endIndex === undefined) return false; - - // Adjust for surrogate pairs. - if ( - // not the last character - endIndex < this.slowIter.input.length - 1 && - // character is a high surrogate - isHighSurrogate(this.slowIter.input.charCodeAt(endIndex)) && - // next character is a low surrogate - isLowSurrogate(this.slowIter.input.charCodeAt(endIndex + 1)) - ) { - endIndex++; - } - - const matchLength = this.matchLengths[data.termId]; - const startIndex = this.usedIndices.get(this.usedIndices.length - matchLength + data.trailingWildcardCount)!; - return this.emitMatch(data.termId, data.flags, startIndex, endIndex, matchLength); - } - - // Otherwise, add a partial match. - let hashes = this.partialMatches.get(this.partialMatches.length - 1); - if (!hashes) this.partialMatches.set(this.partialMatches.length - 1, (hashes = new Set())); - hashes.add(hashPartialMatch(data.step, data.termId)); - return false; - } - - private emitMatch(id: number, flags: number, startIndex: number, endIndex: number, matchLength: number) { - const startBoundaryOk = - !(flags & SharedFlag.RequireWordBoundaryAtStart) || // doesn't require word boundary at the start - startIndex === 0 || // first character - !isWordChar(this.slowIter.input.charCodeAt(startIndex - 1)); // character before isn't a word char - const endBoundaryOk = - !(flags & SharedFlag.RequireWordBoundaryAtEnd) || // doesn't require word boundary at the end - endIndex === this.slowIter.input.length - 1 || // last character - !isWordChar(this.slowIter.input.charCodeAt(endIndex + 1)); // character after isn't a word char - if (!startBoundaryOk || !endBoundaryOk) return false; - - const termId = this.originalIds[id]; - if (this.whitelistedIntervals.query(startIndex, endIndex)) return false; - - this.matches.push({ termId, matchLength, startIndex, endIndex }); - return true; - } - - private ensureNoDuplicateIds(terms: BlacklistedTerm[]) { - const seen = new Set(); - for (const term of terms) { - if (seen.has(term.id)) throw new Error(`Found duplicate blacklisted term ID ${term.id}.`); - seen.add(term.id); - } - } - - private buildTrie(patterns: BlacklistedTerm[]) { - for (const pattern of patterns) this.registerTerm(pattern); - } - - private registerTerm(term: BlacklistedTerm) { - if (potentiallyMatchesEmptyString(term.pattern)) { - throw new Error(`Pattern with ID ${term.id} potentially matches empty string; this is unsupported.`); - } - - const simplifiedPatterns = simplify(term.pattern.nodes); - for (const pattern of simplifiedPatterns) { - // Each pattern may actually correspond to several simplified - // patterns, so use an incrementing numerical ID internally. - const id = this.currentId++; - this.originalIds.push(term.id); - - if (pattern.every((node): node is LiteralNode => node.kind === SyntaxKind.Literal)) { - this.registerPatternWithOnlyLiterals(id, pattern, term); - } else if (pattern.every((node) => node.kind === SyntaxKind.Wildcard)) { - this.registerPatternWithOnlyWildcards(id, pattern, term); - } else { - this.registerPatternWithWildcardsAndLiterals(id, pattern, term); - } - } - } - - private registerPatternWithOnlyLiterals(id: number, pattern: LiteralNode[], term: BlacklistedTerm) { - const matchLength = computePatternMatchLength(pattern); - this.matchLengths[id] = matchLength; - this.maxMatchLength = Math.max(this.maxMatchLength, matchLength); - - const endNode = this.extendTrie(pattern[0].chars); - endNode.flags |= NodeFlag.MatchLeaf; - endNode.termId = id; - if (term.pattern.requireWordBoundaryAtStart) endNode.flags |= NodeFlag.RequireWordBoundaryAtStart; - if (term.pattern.requireWordBoundaryAtEnd) endNode.flags |= NodeFlag.RequireWordBoundaryAtEnd; - } - - private registerPatternWithOnlyWildcards(id: number, pattern: SimpleNode[], term: BlacklistedTerm) { - const matchLength = computePatternMatchLength(pattern); - this.matchLengths[id] = matchLength; - this.maxMatchLength = Math.max(this.maxMatchLength, matchLength); - - const data: WildcardOnlyPatternData = { - id, - flags: 0, - wildcardCount: matchLength, - }; - if (term.pattern.requireWordBoundaryAtStart) data.flags |= WildcardOnlyPatternFlag.RequireWordBoundaryAtStart; - if (term.pattern.requireWordBoundaryAtEnd) data.flags |= WildcardOnlyPatternFlag.RequireWordBoundaryAtEnd; - this.wildcardOnlyPatterns.push(data); - } - - private registerPatternWithWildcardsAndLiterals(id: number, pattern: SimpleNode[], term: BlacklistedTerm) { - const matchLength = computePatternMatchLength(pattern); - this.matchLengths[id] = matchLength; - this.maxMatchLength = Math.max(this.maxMatchLength, matchLength); - - // If a pattern has a wildcard in addition to at least one literal, we - // will split the pattern at its wildcards, resulting in a number of - // partial patterns. For example, given 'l1 w1 l2 w2' where l1, l2 are - // literals and w1, w2 are wildcards, we would have 2 partial patterns: - // l1 and l2. - // - // We will then assign each partial pattern a step: l1 would be tep 1 - // and l2 step 2. Then, we will extend the trie with l1 and l2. After - // that is done, we will decorate the leaf nodes at the leaf nodes of - // each pattern with some additional metadata to indicate that they are - // the leaf node of a partial match. - // - // So how does this help us match wildcards? - // - // Let's say that we find the pattern l1 in the text. Since it is the - // first step, we will hash it and add it to the set of partial matches - // ending at that position. Now, let's say that we find pattern l2 in - // the text. We can combine the partial matches l1 and l2 iff l1 was - // found in the text 1 position before the start position of where l2 - // matched. (1 is the number of wildcards separating l1 and l2 in the - // original pattern). - // - // Since l2 is the last partial pattern, we add it to a stack of pending - // partial matches. (Note that if there was no wildcard after l2, we - // could emit it immediately. However, as there are wildcards after l2, - // we have to wait until we are sure that we have an adequate number of - // characters to satisfy the required number of wildcards). - const groups = groupByNodeType(pattern); - let step = 1; - - const startsWithLiteral = groups[0].isLiteralGroup; - for (let i = startsWithLiteral ? 0 : 1; i < groups.length; i += 2, step++) { - // Count the number of trailing and leading wildcards - // before/after the current literal segment. - const lastLiteralGroupLength = - i < 2 ? 0 : (groups[i - 2] as LiteralGroup).literals.reduce((a, b) => a + b.chars.length, 0); - const leadingWildcardCount = i === 0 ? 0 : (groups[i - 1] as WildcardGroup).wildcardCount; - const trailingWildcardCount = i === groups.length - 1 ? 0 : (groups[i + 1] as WildcardGroup).wildcardCount; - - // Extend the trie with the characters of the literal. - const chars = (groups[i] as LiteralGroup).literals.flatMap((node) => node.chars); - const endNode = this.extendTrie(chars); - - // Add some additional metadata to the leaf node. - const data: PartialMatchData = { - step, - termId: id, - flags: 0, - leadingWildcardCount, - trailingWildcardCount, - matchLength: chars.length, - }; - if (term.pattern.requireWordBoundaryAtStart) data.flags |= PartialMatchFlag.RequireWordBoundaryAtStart; - if (term.pattern.requireWordBoundaryAtEnd) data.flags |= PartialMatchFlag.RequireWordBoundaryAtEnd; - (endNode.partialMatches ??= []).push(data); - endNode.flags |= NodeFlag.PartialMatchLeaf; - - this.maxPartialPatternDistance = Math.max( - this.maxPartialPatternDistance, - lastLiteralGroupLength + leadingWildcardCount + chars.length, - ); - if (i >= groups.length - 2) { - // Last group of literals. - this.maxTrailingWildcardCount = Math.max(this.maxTrailingWildcardCount, trailingWildcardCount); - } - } - - this.partialMatchStepCounts.set(id, step - 1); - } - - private extendTrie(chars: number[]) { - let currentNode = this.rootNode; - for (const char of chars) { - const nextNode = currentNode.edges.get(char); - if (nextNode) { - currentNode = nextNode; - } else { - const newNode = new BlacklistTrieNode(); - currentNode.edges.set(char, newNode); - currentNode = newNode; - } - } - - return currentNode; - } - - private constructLinks() { - // Compute the failure and output functions for the trie. This - // implementation is fairly straightforward and is essentially the exact - // same as that detailed in Aho and Corasick's original paper. Refer to - // section 3 in said paper for more details. - this.rootNode.failureLink = this.rootNode; - const queue = new Queue(); - for (const node of this.rootNode.edges.values()) { - node.failureLink = this.rootNode; - queue.push(node); - } - - while (queue.length > 0) { - const node = queue.shift()!; - for (const [char, childNode] of node.edges) { - let cur = node.failureLink; - while (!cur.edges.get(char) && cur !== this.rootNode) cur = cur.failureLink; - - const failureLink = cur.edges.get(char) ?? this.rootNode; - childNode.failureLink = failureLink; - queue.push(childNode); - } - - node.outputLink = - node.failureLink.flags & NodeFlag.MatchLeaf || node.failureLink.flags & NodeFlag.PartialMatchLeaf - ? node.failureLink - : node.failureLink.outputLink; - } - } - - private useUnderlyingEdgeCollectionImplementation(node: BlacklistTrieNode) { - node.edges = (node.edges as ForwardingEdgeCollection).underlyingImplementation; - for (const childNode of node.edges.values()) this.useUnderlyingEdgeCollectionImplementation(childNode); - } -} - -/** - * Options for the [[NfaMatcher]]. - */ -export interface NfaMatcherOptions { - /** - * A set of transformers that should be applied to the input text before - * blacklisted patterns are matched. This does not affect the matching of - * whitelisted terms. - * - * Transformers will be applied in the order they appear. - * - * @default [] - */ - blacklistMatcherTransformers?: TransformerContainer[]; - - /** - * A list of blacklisted terms. - */ - blacklistedTerms: BlacklistedTerm[]; - - /** - * A set of transformers that should be applied to the input text before - * whitelisted terms are matched. This does not affect the matching of - * blacklisted terms. - * - * Transformers will be applied in the order they appear. - * - * @default [] - */ - whitelistMatcherTransformers?: TransformerContainer[]; - - /** - * A list of whitelisted terms. If a whitelisted term matches some part of - * the text, a match of a blacklisted pattern within that part of the text - * will not be emitted. - * - * For example, if we had a pattern `penis` and a whitelisted term `pen is`, - * only no matches would be reported for the input text `the pen is mightier - * than the sword.` - * - * @default [] - */ - whitelistedTerms?: string[]; -} - -interface WildcardOnlyPatternData { - flags: number; - id: number; - wildcardCount: number; -} - -const enum WildcardOnlyPatternFlag { - RequireWordBoundaryAtStart = 1, - RequireWordBoundaryAtEnd = 1 << 1, -} diff --git a/src/matcher/nfa/WhitelistedTermMatcher.ts b/src/matcher/nfa/WhitelistedTermMatcher.ts deleted file mode 100644 index 0b1e713..0000000 --- a/src/matcher/nfa/WhitelistedTermMatcher.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { TransformerSet } from '../../transformer/TransformerSet'; -import type { TransformerContainer } from '../../transformer/Transformers'; -import { CharacterIterator } from '../../util/CharacterIterator'; -import { CircularBuffer } from '../../util/CircularBuffer'; -import { Queue } from '../../util/Queue'; -import { IntervalCollection } from '../IntervalCollection'; -import { WhitelistTrieNode } from './trie/WhitelistTrieNode'; -import type { ForwardingEdgeCollection } from './trie/edge/ForwardingEdgeCollection'; - -export class WhitelistedTermMatcher { - private readonly rootNode = new WhitelistTrieNode(); - - private currentId = 0; - - private readonly matchLengths = new Map(); // term ID -> match length - - private maxMatchLength = 0; - - private readonly transformers: TransformerSet; - - public constructor({ terms, transformers = [] }: WhitelistedTermMatcherOptions) { - this.transformers = new TransformerSet(transformers); - for (const term of terms) this.registerTerm(term); - this.constructLinks(); - this.useUnderlyingEdgeCollectionImplementation(this.rootNode); - } - - public getMatches(text: string) { - if (this.rootNode.edges.size === 0) return new IntervalCollection(); - const usedIndices = new CircularBuffer(this.maxMatchLength); - const matches = new IntervalCollection(); - - let currentNode = this.rootNode; - const iter = new CharacterIterator(text); - for (const char of iter) { - const transformed = this.transformers.applyTo(char); - if (transformed === undefined) continue; // Returning undefined from a transformer skips that character. - - // Mark the current position as one used for matching. - usedIndices.push(iter.position); - - // Follow failure links until we find a node that has a transition for the current character. - while (currentNode !== this.rootNode && !currentNode.edges.get(transformed)) { - currentNode = currentNode.failureLink; - } - - currentNode = currentNode.edges.get(transformed) ?? this.rootNode; - - // Report matches as needed. - if (currentNode.isOutputNode) { - const matchLength = this.matchLengths.get(currentNode.termId)!; - const startIndex = usedIndices.get(usedIndices.length - matchLength)!; - // Adjust the end index by iter.lastWidth - 1 to account for surrogate pairs. - matches.insert(startIndex, iter.position + iter.lastWidth - 1); - } - - let linkedNode = currentNode.outputLink; - while (linkedNode) { - const matchLength = this.matchLengths.get(linkedNode.termId)!; - const startIndex = usedIndices.get(usedIndices.length - matchLength)!; - // Similar. - matches.insert(startIndex, iter.position + iter.lastWidth - 1); - linkedNode = linkedNode.outputLink; - } - } - - this.transformers.resetAll(); - return matches; - } - - private registerTerm(term: string) { - if (term.length === 0) throw new Error('Unexpected empty whitelisted term.'); - - const id = this.currentId++; - // Track the match length of this term. - const chars = [...new CharacterIterator(term)]; - const matchLength = chars.length; - this.matchLengths.set(id, matchLength); - if (matchLength > this.maxMatchLength) this.maxMatchLength = matchLength; - - let currentNode = this.rootNode; - for (const char of chars) { - const nextNode = currentNode.edges.get(char); - if (nextNode) { - currentNode = nextNode; - } else { - const newNode = new WhitelistTrieNode(); - currentNode.edges.set(char, newNode); - currentNode = newNode; - } - } - - currentNode.isOutputNode = true; - currentNode.termId = id; - } - - private constructLinks() { - // Compute the failure and output functions for the trie. This - // implementation is fairly straightforward and is essentially the exact - // same as that detailed in Aho and Corasick's original paper. Refer to - // section 3 in said paper for more details. - this.rootNode.failureLink = this.rootNode; - const queue = new Queue(); - for (const node of this.rootNode.edges.values()) { - node.failureLink = this.rootNode; - queue.push(node); - } - - while (queue.length > 0) { - const node = queue.shift()!; - for (const [char, childNode] of node.edges) { - let cur = node.failureLink; - while (!cur.edges.get(char) && cur !== this.rootNode) cur = cur.failureLink; - - childNode.failureLink = cur.edges.get(char) ?? this.rootNode; - queue.push(childNode); - } - - node.outputLink = node.failureLink.isOutputNode ? node.failureLink : node.failureLink.outputLink; - } - } - - private useUnderlyingEdgeCollectionImplementation(node: WhitelistTrieNode) { - node.edges = (node.edges as ForwardingEdgeCollection).underlyingImplementation; - for (const childNode of node.edges.values()) this.useUnderlyingEdgeCollectionImplementation(childNode); - } -} - -export interface WhitelistedTermMatcherOptions { - terms: string[]; - transformers?: TransformerContainer[]; -} diff --git a/src/matcher/nfa/trie/BlacklistTrieNode.ts b/src/matcher/nfa/trie/BlacklistTrieNode.ts deleted file mode 100644 index d398880..0000000 --- a/src/matcher/nfa/trie/BlacklistTrieNode.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { EdgeCollection } from './edge/EdgeCollection'; -import { ForwardingEdgeCollection } from './edge/ForwardingEdgeCollection'; - -export class BlacklistTrieNode { - public edges: EdgeCollection = new ForwardingEdgeCollection(); - - public termId = -1; - - public failureLink!: this; - - public outputLink?: this; - - public partialMatches?: PartialMatchData[]; // partial matches that end at this node - - public flags = 0; -} - -export const enum SharedFlag { - RequireWordBoundaryAtStart = 1, - RequireWordBoundaryAtEnd = 1 << 1, -} - -export const enum NodeFlag { - RequireWordBoundaryAtStart = 1, - RequireWordBoundaryAtEnd = 1 << 1, - MatchLeaf = 1 << 2, - PartialMatchLeaf = 1 << 3, -} - -export const enum PartialMatchFlag { - RequireWordBoundaryAtStart = 1, - RequireWordBoundaryAtEnd = 1 << 1, -} - -export interface PartialMatchData { - flags: number; - leadingWildcardCount: number; - matchLength: number; - step: number; - termId: number; - trailingWildcardCount: number; -} - -export function hashPartialMatch(step: number, termId: number) { - return `${step}-${termId}`; -} diff --git a/src/matcher/nfa/trie/WhitelistTrieNode.ts b/src/matcher/nfa/trie/WhitelistTrieNode.ts deleted file mode 100644 index 62215ec..0000000 --- a/src/matcher/nfa/trie/WhitelistTrieNode.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { EdgeCollection } from './edge/EdgeCollection'; -import { ForwardingEdgeCollection } from './edge/ForwardingEdgeCollection'; - -export class WhitelistTrieNode { - public edges: EdgeCollection = new ForwardingEdgeCollection(); - - public termId = -1; - - public failureLink!: WhitelistTrieNode; - - public outputLink?: WhitelistTrieNode; - - public isOutputNode = false; -} diff --git a/src/matcher/nfa/trie/edge/ArrayEdgeCollection.ts b/src/matcher/nfa/trie/edge/ArrayEdgeCollection.ts deleted file mode 100644 index e9302ab..0000000 --- a/src/matcher/nfa/trie/edge/ArrayEdgeCollection.ts +++ /dev/null @@ -1,70 +0,0 @@ -import type { Edge, EdgeCollection } from './EdgeCollection'; - -export class ArrayEdgeCollection implements EdgeCollection { - // Crossover point at which binary search becomes faster than a linear - // search. Somewhat arbitrary as benchmarking get() is hard (both linear - // search and binary search execute in less than one-tenth of a millisecond - // at the scale we're looking at) but micro-benchmarks seem to point to 8-12 - // being a crossover point. - private static readonly binarySearchThreshold = 10; - - private readonly edges: Edge[] = []; - - private dirty = false; - - public set(char: number, node: T) { - // Prefer overwriting an existing edge. - const index = this.edges.findIndex((edge) => edge[0] === char); - if (index === -1) { - this.edges.push([char, node]); - this.dirty = true; - } else { - this.edges[index][1] = node; - } - } - - public get(char: number) { - if (this.edges.length <= ArrayEdgeCollection.binarySearchThreshold) { - for (const edge of this.edges) { - if (edge[0] === char) return edge[1]; - } - - return; - } - - if (this.dirty) { - // Sort by character value. - this.edges.sort( - /* istanbul ignore next: not possible to write a robust test for this */ - (a, b) => (a[0] < b[0] ? -1 : b[0] < a[0] ? 1 : 0), - ); - this.dirty = false; - } - - let low = 0; - let high = this.edges.length - 1; - while (low <= high) { - const mid = (low + high) >>> 1; - const edge = this.edges[mid]; - if (edge[0] > char) high = mid - 1; - else if (edge[0] === char) return edge[1]; - else low = mid + 1; - } - } - - public get size() { - return this.edges.length; - } - - public keys() { - return this.edges.map((edge) => edge[0]).values(); - } - - public values() { - return this.edges.map((edge) => edge[1]).values(); - } - - public [Symbol.iterator]() { - return this.edges.values(); - } -} diff --git a/src/matcher/nfa/trie/edge/BucketEdgeCollection.ts b/src/matcher/nfa/trie/edge/BucketEdgeCollection.ts deleted file mode 100644 index 738dafd..0000000 --- a/src/matcher/nfa/trie/edge/BucketEdgeCollection.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { CharacterCode } from '../../../../util/Char'; -import type { Edge, EdgeCollection } from './EdgeCollection'; - -export class BucketEdgeCollection implements EdgeCollection { - private _size = 0; - - private buckets = Array.from({ length: 26 }); - - public set(char: number, node: T) { - const k = char - CharacterCode.LowerA; - // Only increment the size if we didn't already have a node corresponding to it. - if (!this.buckets[k]) this._size++; - this.buckets[k] = node; - } - - public get(char: number) { - const k = char - CharacterCode.LowerA; - if (k >= 0 && k < 26) return this.buckets[k]; - } - - public get size() { - return this._size; - } - - public *keys() { - for (let i = 0; i < 26; i++) { - if (this.buckets[i] !== undefined) yield i + CharacterCode.LowerA; - } - } - - public *values() { - for (let i = 0; i < 26; i++) { - if (this.buckets[i] !== undefined) yield this.buckets[i]!; - } - } - - public *[Symbol.iterator]() { - for (let i = 0; i < 26; i++) { - if (this.buckets[i] !== undefined) yield [i + CharacterCode.LowerA, this.buckets[i]] as Edge; - } - } -} diff --git a/src/matcher/nfa/trie/edge/EdgeCollection.ts b/src/matcher/nfa/trie/edge/EdgeCollection.ts deleted file mode 100644 index fdcb80c..0000000 --- a/src/matcher/nfa/trie/edge/EdgeCollection.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type EdgeCollection = Iterable> & { - get(char: number): T | undefined; - keys(): IterableIterator; - set(char: number, node: T): void; - get size(): number; - values(): IterableIterator; -}; - -export type Edge = [char: number, node: T]; diff --git a/src/matcher/nfa/trie/edge/ForwardingEdgeCollection.ts b/src/matcher/nfa/trie/edge/ForwardingEdgeCollection.ts deleted file mode 100644 index cc86ad2..0000000 --- a/src/matcher/nfa/trie/edge/ForwardingEdgeCollection.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { isLowerCase } from '../../../../util/Char'; -import { ArrayEdgeCollection } from './ArrayEdgeCollection'; -import { BucketEdgeCollection } from './BucketEdgeCollection'; -import type { EdgeCollection } from './EdgeCollection'; - -export class ForwardingEdgeCollection implements EdgeCollection { - private _underlyingImplementation: EdgeCollection = new ArrayEdgeCollection(); - - private implementation = Implementation.Array; - - private areKeysAllLowerCase = true; - - public set(char: number, node: T) { - this.areKeysAllLowerCase &&= isLowerCase(char); - if (!this.areKeysAllLowerCase && this.implementation === Implementation.Bucket) { - this.useImplementation(this.selectImplementation()); - } - - this._underlyingImplementation.set(char, node); - this.useImplementation(this.selectImplementation()); - } - - public get(char: number) { - return this._underlyingImplementation.get(char); - } - - public get size() { - return this._underlyingImplementation.size; - } - - public keys() { - return this._underlyingImplementation.keys(); - } - - public values() { - return this._underlyingImplementation.values(); - } - - public get underlyingImplementation() { - return this._underlyingImplementation; - } - - public [Symbol.iterator]() { - return this._underlyingImplementation[Symbol.iterator](); - } - - private selectImplementation() { - // These thresholds are all somewhat arbitrary as all implementations - // execute in less than one-tenth of a millisecond at the scale we're at - // here. However, micro-benchmarks point to the bucket implementation - // always being faster when it's applicable (lower-case ASCII - // characters). As it's not very memory-efficient for small numbers of - // edges, we use the array implementation if the size is less than 10 - // and the bucket implementation otherwise. - // - // When the bucket implementation is not available we choose between the - // array and map implementation. Both are fairly fast; though the map is - // fastest, the difference is not noticeable until ~50-60 edges are - // being stored. Thus, as the array implementation uses less memory, we - // choose it for medium sized collections and use the map implementation - // in all other cases. - if (this.size <= 10) return Implementation.Array; - if (this.areKeysAllLowerCase) return Implementation.Bucket; - if (this.size <= 35) return Implementation.Array; - return Implementation.Map; - } - - private useImplementation(newImplementation: Implementation) { - if (this.implementation === newImplementation) return; - const newCollection = this.instantiateImplementation(newImplementation); - for (const [k, v] of this._underlyingImplementation) newCollection.set(k, v); - this._underlyingImplementation = newCollection; - this.implementation = newImplementation; - } - - private instantiateImplementation(implementation: Implementation): EdgeCollection { - switch (implementation) { - case Implementation.Array: - /* istanbul ignore next: instantiateImplementation() should never be called with Array */ - return new ArrayEdgeCollection(); - case Implementation.Bucket: - return new BucketEdgeCollection(); - case Implementation.Map: - return new Map(); - } - } -} - -const enum Implementation { - Array, - Bucket, - Map, -} diff --git a/src/matcher/regexp/RegExpMatcher.ts b/src/matcher/regexp/RegExpMatcher.ts index 463c388..7f4fdb1 100644 --- a/src/matcher/regexp/RegExpMatcher.ts +++ b/src/matcher/regexp/RegExpMatcher.ts @@ -12,13 +12,6 @@ import type { Matcher } from '../Matcher'; /** * An implementation of the [[Matcher]] interface using regular expressions and * string searching methods. - * - * It should be the default choice for users of this package, as though it is - * theoretically slower than the more complex [[NfaMatcher]], it uses much less - * memory and is more efficient for low/medium numbers of patterns. - * - * Refer to the documentation of the [[NfaMatcher]] class for further discussion - * on when to choose that implementation over this one. */ export class RegExpMatcher implements Matcher { private readonly blacklistedTerms: CompiledBlacklistedTerm[]; diff --git a/src/pattern/Pattern.ts b/src/pattern/Pattern.ts index 4f3478c..5d26226 100644 --- a/src/pattern/Pattern.ts +++ b/src/pattern/Pattern.ts @@ -97,7 +97,7 @@ const parser = new Parser(); * const parsed = pattern`my initials are \[??\]`; // match "my initials are [", then any two characters, then a "]" * ``` * @returns The parsed pattern, which can then be used with the - * [[RegExpMatcher]] or the [[NfaMatcher]]. + * [[RegExpMatcher]]. * @throws [[ParserError]] if a syntactical error was detected while parsing the * pattern. * @see [[parseRawPattern]] if you want to parse a string into a pattern without @@ -125,7 +125,7 @@ export function pattern(strings: TemplateStringsArray, ...expressions: unknown[] * @throws [[ParserError]] if a syntactical error was detected while parsing the * pattern. * @returns The parsed pattern, which can then be used with the - * [[RegExpMatcher]] or the [[NfaMatcher]]. + * [[RegExpMatcher]]. */ export function parseRawPattern(pattern: string) { return parser.parse(pattern); diff --git a/src/preset/english.ts b/src/preset/english.ts index 55e72e9..dd739f9 100644 --- a/src/preset/english.ts +++ b/src/preset/english.ts @@ -1,5 +1,5 @@ import { DataSet } from '../dataset/DataSet'; -import type { NfaMatcherOptions } from '../matcher/nfa/NfaMatcher'; +import type { RegExpMatcherOptions } from '../matcher/regexp/RegExpMatcher'; import { pattern } from '../pattern/Pattern'; import { collapseDuplicatesTransformer } from '../transformer/collapse-duplicates'; import { resolveConfusablesTransformer } from '../transformer/resolve-confusables'; @@ -43,10 +43,10 @@ export const englishRecommendedWhitelistMatcherTransformers = [ /** * Recommended transformers to be used with the [[englishDataset | english word - * dataset]] and the [[RegExpMatcher]] or the [[NfaMatcher]]. + * dataset]] and the [[RegExpMatcher]]. */ export const englishRecommendedTransformers: Pick< - NfaMatcherOptions, + RegExpMatcherOptions, 'blacklistMatcherTransformers' | 'whitelistMatcherTransformers' > = { blacklistMatcherTransformers: englishRecommendedBlacklistMatcherTransformers, diff --git a/src/transformer/Transformers.ts b/src/transformer/Transformers.ts index 69c2aa7..a014c25 100644 --- a/src/transformer/Transformers.ts +++ b/src/transformer/Transformers.ts @@ -40,7 +40,7 @@ export type TransformerContainer = SimpleTransformerContainer | StatefulTransfor * character. A return value of `undefined` indicates that the character should * be ignored. * @returns A container holding the transformer, which can then be passed to the - * [[RegExpMatcher]] or the [[NfaMatcher]]. + * [[RegExpMatcher]]. */ export function createSimpleTransformer(transformer: TransformerFn): SimpleTransformerContainer { return { type: TransformerType.Simple, transform: transformer }; @@ -95,7 +95,7 @@ export interface SimpleTransformerContainer { * @param factory A function that returns an instance of the stateful * transformer. * @returns A container holding the stateful transformer, which can then be - * passed to the [[RegExpMatcher]] or the [[NfaMatcher]]. + * passed to the [[RegExpMatcher]]. */ export function createStatefulTransformer(factory: StatefulTransformerFactory): StatefulTransformerContainer { return { type: TransformerType.Stateful, factory }; diff --git a/src/transformer/collapse-duplicates/index.ts b/src/transformer/collapse-duplicates/index.ts index 45d591d..b196bcd 100644 --- a/src/transformer/collapse-duplicates/index.ts +++ b/src/transformer/collapse-duplicates/index.ts @@ -41,7 +41,7 @@ import { CollapseDuplicatesTransformer } from './transformer'; * ``` * @param options - Options for the transformer. * @returns A container holding the transformer, which can then be passed to the - * [[RegExpMatcher]] or the [[NfaMatcher]]. + * [[RegExpMatcher]]. */ export function collapseDuplicatesTransformer({ defaultThreshold = 1, diff --git a/src/transformer/remap-characters/index.ts b/src/transformer/remap-characters/index.ts index 3d5fc6f..a6a756d 100644 --- a/src/transformer/remap-characters/index.ts +++ b/src/transformer/remap-characters/index.ts @@ -31,7 +31,7 @@ import { createSimpleTransformer } from '../Transformers'; * ``` * @param mapping - A map/object mapping certain characters to others. * @returns A container holding the transformer, which can then be passed to the - * [[RegExpMatcher]] or the [[NfaMatcher]]. + * [[RegExpMatcher]]. * @see [[resolveConfusablesTransformer| Transformer that handles confusable Unicode characters]] * @see [[resolveLeetSpeakTransformer | Transformer that handles leet-speak]] */ diff --git a/src/transformer/resolve-confusables/index.ts b/src/transformer/resolve-confusables/index.ts index 543e720..c8f39cb 100644 --- a/src/transformer/resolve-confusables/index.ts +++ b/src/transformer/resolve-confusables/index.ts @@ -17,7 +17,7 @@ import { confusables } from './confusables'; * const matcher = new RegExpMatcher({ ..., blacklistMatcherTransformers: [transformer] }); * ``` * @returns A container holding the transformer, which can then be passed to the - * [[RegExpMatcher]] or the [[NfaMatcher]]. + * [[RegExpMatcher]]. */ export function resolveConfusablesTransformer() { return remapCharactersTransformer(confusables); diff --git a/src/transformer/resolve-leetspeak/index.ts b/src/transformer/resolve-leetspeak/index.ts index cca260e..0e19398 100644 --- a/src/transformer/resolve-leetspeak/index.ts +++ b/src/transformer/resolve-leetspeak/index.ts @@ -18,7 +18,7 @@ import { dictionary } from './dictionary'; * const matcher = new RegExpMatcher({ ..., blacklistMatcherTransformers: [transformer] }); * ``` * @returns A container holding the transformer, which can then be passed to the - * [[RegExpMatcher]] or the [[NfaMatcher]]. + * [[RegExpMatcher]]. */ export function resolveLeetSpeakTransformer() { return remapCharactersTransformer(dictionary); diff --git a/src/transformer/skip-non-alphabetic/index.ts b/src/transformer/skip-non-alphabetic/index.ts index 2a41f7a..e967588 100644 --- a/src/transformer/skip-non-alphabetic/index.ts +++ b/src/transformer/skip-non-alphabetic/index.ts @@ -18,7 +18,7 @@ import { createSimpleTransformer } from '../Transformers'; * const matcher = new RegExpMatcher({ ..., blacklistMatcherTransformers: [transformer] }); * ``` * @returns A container holding the transformer, which can then be passed to the - * [[RegExpMatcher]] or the [[NfaMatcher]]. + * [[RegExpMatcher]]. */ export function skipNonAlphabeticTransformer() { return createSimpleTransformer((c) => (isAlphabetic(c) ? c : undefined)); diff --git a/src/transformer/to-ascii-lowercase/index.ts b/src/transformer/to-ascii-lowercase/index.ts index 4202b9e..a8b16ff 100644 --- a/src/transformer/to-ascii-lowercase/index.ts +++ b/src/transformer/to-ascii-lowercase/index.ts @@ -13,7 +13,7 @@ import { createSimpleTransformer } from '../Transformers'; * of varying cases. * * @returns A container holding the transformer, which can then be passed to the - * [[RegExpMatcher]] or the [[NfaMatcher]]. + * [[RegExpMatcher]]. */ export function toAsciiLowerCaseTransformer() { return createSimpleTransformer((c) => (isUpperCase(c) ? invertCaseOfAlphabeticChar(c) : c)); diff --git a/test/matcher/nfa/NfaMatcher.fuzz.test.ts b/test/matcher/nfa/NfaMatcher.fuzz.test.ts deleted file mode 100644 index cd38437..0000000 --- a/test/matcher/nfa/NfaMatcher.fuzz.test.ts +++ /dev/null @@ -1,147 +0,0 @@ -import * as fc from 'fast-check'; -import { assignIncrementingIds } from '../../../src/matcher/BlacklistedTerm'; -import { NfaMatcher } from '../../../src/matcher/nfa/NfaMatcher'; -import type { LiteralNode, ParsedPattern } from '../../../src/pattern/Nodes'; -import { SyntaxKind } from '../../../src/pattern/Nodes'; -import { CharacterCode } from '../../../src/util/Char'; -import { CharacterIterator } from '../../../src/util/CharacterIterator'; -import type { Interval } from '../../../src/util/Interval'; -import { compareIntervals } from '../../../src/util/Interval'; - -test('running the pattern matcher on a set of patterns and input should have the same result as using a brute force approach with regexp', () => { - fc.assert( - fc.property( - fc.stringOf(fc.char()).chain((input) => { - // Generate patterns that are a substring of the input. - const arbitrarySubstringPatterns = - input.length < 2 - ? fc.constant([]) - : fc.array( - fc.tuple( - fc - .tuple(fc.integer({ min: 0, max: input.length - 1 }), fc.integer({ min: 0, max: input.length - 1 })) - .filter(([a, b]) => a !== b) - .chain(([a, b]) => { - // eslint-disable-next-line no-param-reassign - if (a > b) [a, b] = [b, a]; - return fc.tuple(fc.constant(input.slice(a, b)), fc.uniqueArray(fc.integer({ min: a, max: b }))); - }) - .map(([pattern, wildcardIndices]) => { - let patternWithWildcards = ''; - // eslint-disable-next-line unicorn/no-for-loop - for (let i = 0; i < pattern.length; i++) { - if (wildcardIndices.includes(i)) patternWithWildcards += '?'; - else patternWithWildcards += pattern[i]; - } - - return patternWithWildcards; - }), - fc.boolean(), - fc.boolean(), - ), - ); - // Completely random patterns. - const completelyArbitraryPatterns = fc.array( - fc.tuple( - fc - .stringOf(fc.oneof(fc.char16bits(), fc.char16bits(), fc.char16bits(), fc.constant('?'))) - .filter((p) => p.length > 0), - fc.boolean(), - fc.boolean(), - ), - ); - return fc.tuple(fc.constant(input), completelyArbitraryPatterns, arbitrarySubstringPatterns); - }), - ([input, randomPatterns, substrPatterns]) => { - const seen = new Set(); - const allPatterns: [string, boolean, boolean][] = []; - for (const pattern of randomPatterns) { - // Make sure we don't use the same pattern twice. - if (!seen.has(pattern[0])) { - allPatterns.push(pattern); - seen.add(pattern[0]); - } - } - - for (const pattern of substrPatterns) { - // Similar. - if (!seen.has(pattern[0])) { - allPatterns.push(pattern); - seen.add(pattern[0]); - } - } - - const matcher = new NfaMatcher({ - blacklistedTerms: assignIncrementingIds( - allPatterns.map(([pattern, requireWordBoundaryAtStart, requireWordBoundaryAtEnd]) => - toNodes(pattern, requireWordBoundaryAtStart, requireWordBoundaryAtEnd), - ), - ), - }); - - const matchedRegions = matcher.getAllMatches(input); - const transformedMatches: Record = {}; - for (const payload of matchedRegions) { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - (transformedMatches[payload.termId] ??= []).push([payload.startIndex, payload.endIndex]); - } - - for (const matches of Object.values(transformedMatches)) matches.sort((a, b) => compareIntervals(...a, ...b)); - expect(transformedMatches).toStrictEqual( - bruteForceMatch( - allPatterns.map(([pattern, requireWordBoundaryAtStart, requireWordBoundaryAtEnd]) => - toRegExp(pattern, requireWordBoundaryAtStart, requireWordBoundaryAtEnd), - ), - input, - ), - ); - }, - ), - ); -}); - -function bruteForceMatch(regExps: RegExp[], input: string) { - const result: Record = {}; - for (const [i, regExp] of regExps.entries()) { - let match: RegExpExecArray | null; - while ((match = regExp.exec(input))) { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - (result[i] ??= []).push([match.index, match.index + match[0].length - 1]); - regExp.lastIndex = match.index + 1; - } - } - - for (const matches of Object.values(result)) matches.sort((a, b) => compareIntervals(...a, ...b)); - return result; -} - -const regExpSpecialChars = ['.', '*', '+', '^', '$', '{', '}', '(', ')', '|', '[', '\\', ']']; - -function toRegExp(pattern: string, requireWordBoundaryAtStart: boolean, requireWordBoundaryAtEnd: boolean) { - let regexpStr = ''; - if (requireWordBoundaryAtStart) regexpStr += '(?<=[^\\dA-Za-z]|^)'; - for (const char of pattern) { - if (regExpSpecialChars.includes(char)) regexpStr += `\\${char}`; - else if (char === '?') regexpStr += '.'; - else regexpStr += char; - } - - if (requireWordBoundaryAtEnd) regexpStr += '(?=[^\\dA-Za-z]|$)'; - return new RegExp(regexpStr, 'gs'); -} - -function toNodes(pattern: string, requireWordBoundaryAtStart: boolean, requireWordBoundaryAtEnd: boolean) { - const parsed: ParsedPattern = { nodes: [], requireWordBoundaryAtStart, requireWordBoundaryAtEnd }; - for (const char of new CharacterIterator(pattern)) { - if (char === CharacterCode.QuestionMark) { - parsed.nodes.push({ kind: SyntaxKind.Wildcard }); - } else if (parsed.nodes.length === 0 || parsed.nodes[parsed.nodes.length - 1].kind !== SyntaxKind.Literal) { - parsed.nodes.push({ kind: SyntaxKind.Literal, chars: [char] }); - } else { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - (parsed.nodes[parsed.nodes.length - 1] as LiteralNode).chars.push(char); - } - } - - return parsed; -} diff --git a/test/matcher/nfa/NfaMatcher.test.ts b/test/matcher/nfa/NfaMatcher.test.ts deleted file mode 100644 index ed7d5c7..0000000 --- a/test/matcher/nfa/NfaMatcher.test.ts +++ /dev/null @@ -1,845 +0,0 @@ -import { assignIncrementingIds } from '../../../src/matcher/BlacklistedTerm'; -import type { MatchPayload } from '../../../src/matcher/MatchPayload'; -import { NfaMatcher } from '../../../src/matcher/nfa/NfaMatcher'; -import { WhitelistedTermMatcher } from '../../../src/matcher/nfa/WhitelistedTermMatcher'; -import { parseRawPattern, pattern } from '../../../src/pattern/Pattern'; -import { createSimpleTransformer } from '../../../src/transformer/Transformers'; -import { skipNonAlphabeticTransformer } from '../../../src/transformer/skip-non-alphabetic'; -import { CharacterCode } from '../../../src/util/Char'; - -describe('constructor', () => { - it('should not accept patterns with the same id', () => { - expect( - () => - new NfaMatcher({ - blacklistedTerms: [ - { id: 10, pattern: pattern`` }, - { id: 10, pattern: pattern`yo` }, - ], - }), - ).toThrow(new Error('Found duplicate blacklisted term ID 10.')); - }); - - it('should not accept empty patterns', () => { - expect( - () => - new NfaMatcher({ - blacklistedTerms: [{ id: 10, pattern: pattern`` }], - }), - ).toThrow('potentially matches empty string'); - }); - - it('should not accept patterns with optionals that have the empty string in their match set', () => { - expect( - () => - new NfaMatcher({ - blacklistedTerms: [{ id: 10, pattern: pattern`[abc]` }], - }), - ).toThrow('potentially matches empty string'); - }); -}); - -it('should match nothing if there are no patterns', () => { - const matcher = new NfaMatcher({ blacklistedTerms: [] }); - expect(matcher.getAllMatches('foo bar')).toHaveLength(0); -}); - -describe('simple matching; no wildcards/optionals', () => { - it.each([ - [ - 'should match a term at the start of the string', - ['hello'], - 'hello world', - { - 0: [[0, 4]], - }, - ], - [ - 'should match a term at the end of the string', - ['world'], - 'hello world', - { - 0: [[6, 10]], - }, - ], - ['should be case sensitive (no match)', ['WORLD'], 'hello world', []], - ['should be case sensitive (with match)', ['yO'], 'hello yO yo', { 0: [[6, 7]] }], - [ - 'should support spaces in terms', - ['hello W0rld'], - 'hello world! hello W0rld!', - { - 0: [[13, 23]], - }, - ], - [ - 'should support surrogate pairs', - ['cool 🌉'], - 'cool cool cool cool 🌉', - { - 0: [[15, 21]], - }, - ], - [ - 'should work with terms that are suffixes of other ones', - ['cool', 'cool beans'], - 'cool cool beans', - { - 0: [ - [0, 3], - [5, 8], - ], - 1: [[5, 14]], - }, - ], - [ - 'should work with terms that are suffixes of other ones, test 2', - ['he', 'she', 'his', 'her', 'here'], - 'he waited for she and her mom to go there', - { - 0: [ - [0, 1], - [15, 16], - [22, 23], - [37, 38], - ], - 1: [[14, 16]], - 3: [ - [37, 39], - [22, 24], - ], - 4: [[37, 40]], - }, - ], - ['should only match on the term exactly', ['her'], 'h he! her', { 0: [[6, 8]] }], - [ - 'should work with very long terms', - ['Pneumonoultramicroscopicsilicovolcanoconiosis', 'horrible'], - 'wow this word is quite long: Pneumonoultramicroscopicsilicovolcanoconiosie <- did you notice there was a typo there? horrible of me to do that... Pneumonoultramicroscopicsilicovolcanoconiosis', - { - 0: [[146, 190]], - 1: [[117, 124]], - }, - ], - [ - 'should match several similar terms', - ['thing', 'thang'], - 'im just doin my thign thing ok thang', - { - 0: [[22, 26]], - 1: [[31, 35]], - }, - ], - ['should work with terms that normalize to a different string', ['豈'], '豈', { 0: [[0, 0]] }], - ['should work with the null character', ['\u0000'], '\u0000', { 0: [[0, 0]] }], - ])('%s', (_, patterns, input, matches) => { - const expected: MatchPayload[] = []; - for (const [idStr, matchData] of Object.entries(matches)) { - const id = Number(idStr); - for (const match of matchData) { - expected.push({ - termId: id, - startIndex: match[0], - endIndex: match[1], - matchLength: [...patterns[id]].length, - }); - } - } - - const matcher = new NfaMatcher({ blacklistedTerms: assignIncrementingIds(patterns.map(parseRawPattern)) }); - expect(matcher.getAllMatches(input)).toBePermutationOf(expected); - }); -}); - -describe('matching with optionals', () => { - it('should emit matches with the correct ID', () => { - const matches = new NfaMatcher({ blacklistedTerms: [{ id: 10, pattern: pattern`w[o]rld` }] }).getAllMatches( - 'world wrld', - ); - expect(matches).toHaveLength(2); - expect(matches[0].termId).toBe(10); - expect(matches[1].termId).toBe(10); - }); - - it.each([ - [ - 'should match a single pattern with an optional at the start', - ['[a]bc'], - 'abc bc', - { - 0: [ - [0, 2, 3], - [1, 2, 2], - [4, 5, 2], - ], - }, - ], - [ - 'should match a single pattern with an optional at the end', - ['bc[d]'], - 'cant think of any good strings bc :(d', - { - 0: [[31, 32, 2]], - }, - ], - [ - 'should match a single pattern with an optional in the middle', - ['b[c]d'], - 'getting tired of writing tests, bcd bd :P', - { - 0: [ - [32, 34, 3], - [36, 37, 2], - ], - }, - ], - [ - 'should match a single pattern with an optional wildcard', - ['pi[?]kle'], - 'pickles are good and so are pikles, whatever those are', - { - 0: [ - [0, 5, 6], - [28, 32, 5], - ], - }, - ], - [ - 'should match several patterns with optionals', - ['s[?]m[e]th', 's[?]metimes'], - 'sometimes i like smth', - { - 0: [[17, 20, 4]], - 1: [[0, 8, 9]], - }, - ], - ])('%s', (_, patterns, input, matches) => { - const expected: MatchPayload[] = []; - for (const [idStr, matchData] of Object.entries(matches)) { - const id = Number(idStr); - for (const match of matchData) { - expected.push({ - termId: id, - startIndex: match[0], - endIndex: match[1], - matchLength: match[2], - }); - } - } - - const matcher = new NfaMatcher({ blacklistedTerms: assignIncrementingIds(patterns.map(parseRawPattern)) }); - expect(matcher.getAllMatches(input)).toBePermutationOf(expected); - }); -}); - -describe('matching with wildcards', () => { - it.each([ - [ - 'should match a pattern that only contains wildcards', - ['??', '?'], - 'abc', - { - 0: [ - [0, 1], - [1, 2], - ], - 1: [ - [0, 0], - [1, 1], - [2, 2], - ], - }, - ], - [ - 'should match a single pattern with an wildcard at the end correctly', - ['hello?'], - 'hellom world', - { - 0: [[0, 5]], - }, - ], - [ - 'should match a single pattern with a wildcard at the start correctly', - ['?world'], - 'my world', - { - 0: [[2, 7]], - }, - ], - [ - 'should match a single pattern with a wildcard in the middle correctly', - ['?world?'], - 'the world!', - { - 0: [[3, 9]], - }, - ], - [ - 'should match several patterns with wildcards in varying positions correctly', - ['?start', 'end?', 'mid?le?'], - 'look, wildcards can be at the start, the end, or the middle!', - { - 0: [[29, 34]], - 1: [[41, 44]], - 2: [[53, 59]], - }, - ], - [ - 'should match two patterns where the first is a proper suffix of the latter and has a wildcard correctly', - ['hello', 'ell?'], - 'hey, hello there!', - { - 0: [[5, 9]], - 1: [[6, 9]], - }, - ], - [ - 'should match four patterns where the first is a proper suffix of the second, similar with the second and so on', - ['l?', 'll?', 'ell?', 'hello'], - 'test test test hello??', - { - 0: [ - [17, 18], - [18, 19], - ], - 1: [[17, 19]], - 2: [[16, 19]], - 3: [[15, 19]], - }, - ], - [ - 'should match two patterns where one is a single wildcard and the second is a literal', - ['a!', '?'], - 'a! ', - { - 0: [[0, 1]], - 1: [ - [0, 0], - [1, 1], - [2, 2], - ], - }, - ], - [ - 'should treat surrogate pairs as a single character and thus match a wildcard', - ['night', 'cool ?'], - 'what a cool 🌉 night sky', - { - 0: [[15, 19]], - 1: [[7, 13]], - }, - ], - [ - 'should not match patterns with leading wildcards if there are insufficient characters at the start', - ['??bye'], - 'dbye', - {}, - ], - [ - 'should not match patterns with trailing wildcards if there are insufficient characters at the end', - ['hi????'], - 'hid', - {}, - ], - ])('%s', (_, patterns, input, matches) => { - const expected: MatchPayload[] = []; - for (const [idStr, matchData] of Object.entries(matches)) { - const id = Number(idStr); - for (const match of matchData) { - expected.push({ - termId: id, - startIndex: match[0], - endIndex: match[1], - matchLength: [...patterns[id]].length, - }); - } - } - - const matcher = new NfaMatcher({ blacklistedTerms: assignIncrementingIds(patterns.map(parseRawPattern)) }); - expect(matcher.getAllMatches(input)).toBePermutationOf(expected); - }); -}); - -describe('matching with word boundaries', () => { - it.each([ - // normal patterns - [ - 'should not emit matches for patterns which require a word boundary at the start if the matched segment has a word char before it', - ['|cool'], - 'something is quitecool', - {}, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment has a non-word char before it', - ['|beans'], - 'delicious beans', - { - 0: [[10, 14, 5]], - }, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment begins at the start of the string', - ['|things'], - 'things are cool', - { - 0: [[0, 5, 6]], - }, - ], - [ - 'should not emit matches for patterns which require a word boundary at the end if the matched segment does not have a non-word char after it', - ['cool|'], - 'something is quite coolbeans', - {}, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment has a non-word char after it', - ['beans|'], - 'delicious beans yes', - { - 0: [[10, 14, 5]], - }, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment ends at the eof', - ['things|'], - 'there are many things', - { - 0: [[15, 20, 6]], - }, - ], - - // normal patterns w/ non-word chars - [ - 'should not emit matches for patterns which require a word boundary at the start if the matched segment has a word char before it (pattern has non-word char near the start)', - ['|c!ol'], - 'something is quitec!ol', - {}, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment has a non-word char before it (pattern has non-word char near the start)', - ['|b*ans'], - 'delicious b*ans', - { - 0: [[10, 14, 5]], - }, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment begins at the start of the string (pattern has non-word char near the start)', - ['|t^ings'], - 't^ings are cool', - { - 0: [[0, 5, 6]], - }, - ], - [ - 'should not emit matches for patterns which require a word boundary at the end if the matched segment does not have a non-word char after it (pattern has non-word char near the end)', - ['co#l|'], - 'something is quite co#lbeans', - {}, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment has a non-word char after it (pattern has non-word char near the end)', - ['bea!s|'], - 'delicious bea!s yes', - { - 0: [[10, 14, 5]], - }, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment ends at the eof (pattern has non-word char near the end)', - ['thin$s|'], - 'there are many thin$s', - { - 0: [[15, 20, 6]], - }, - ], - - // patterns with wildcards - [ - 'should not emit matches for patterns which require a word boundary at the start if the matched segment does not have a non-word char after it (with wildcards)', - ['|c?ol'], - 'something is quitecool', - {}, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment has a non-word char after it (with wildcards)', - ['|be?ns'], - 'delicious beans', - { - 0: [[10, 14, 5]], - }, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment begins at the start of the string (with wildcards)', - ['|?hings'], - 'things are cool', - { - 0: [[0, 5, 6]], - }, - ], - [ - 'should not emit matches for patterns which require a word boundary at the end if the matched segment does not have a non-word char after it (with wildcards)', - ['?ool|'], - 'something is quite coolbeans', - {}, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment has a non-word char after it (with wildcards)', - ['be?ns|'], - 'delicious beans yes', - { - 0: [[10, 14, 5]], - }, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment ends at the eof (with wildcards)', - ['thing?|'], - 'there are many things', - { - 0: [[15, 20, 6]], - }, - ], - [ - 'should match a pattern with only wildcards and a word boundary at the start correctly', - ['|??'], - 'myby', - { - 0: [[0, 1, 2]], - }, - ], - [ - 'should match a pattern with only wildcards and a word boundary at the end correctly', - ['??|'], - 'myby', - { - 0: [[2, 3, 2]], - }, - ], - - // patterns with wildcards and non-word chars - [ - 'should not emit matches for patterns which require a word boundary at the start if the matched segment does not have a non-word char after it (with wildcards and a non-word char near the start)', - ['|c!?ol'], - 'something is quitec!ool', - {}, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment has a non-word char after it (with wildcards and a non-word char near the start)', - ['|b$e?ns'], - 'delicious b$eans', - { - 0: [[10, 15, 6]], - }, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment begins at the start of the string (with wildcards and a non-word char near the start)', - ['|?^ings'], - 't^ings are cool', - { - 0: [[0, 5, 6]], - }, - ], - [ - 'should not emit matches for patterns which require a word boundary at the end if the matched segment does not have a non-word char after it (with wildcards and a non-word char near the end)', - ['?o_l|'], - 'something is quite coolbeans', - {}, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment has a non-word char after it (with wildcards and a non-word char near the end)', - ['be?%s|'], - 'delicious bea%s yes', - { - 0: [[10, 14, 5]], - }, - ], - [ - 'should emit matches for patterns which require a word boundary at the start if the matched segment ends at the eof (with wildcards and a non-word char near the end)', - ['thin*?|'], - 'there are many thin*s', - { - 0: [[15, 20, 6]], - }, - ], - ])('%s', (_, patterns, input, matches) => { - const expected: MatchPayload[] = []; - for (const [idStr, matchData] of Object.entries(matches)) { - const id = Number(idStr); - for (const match of matchData) { - expected.push({ - termId: id, - startIndex: match[0], - endIndex: match[1], - matchLength: match[2], - }); - } - } - - const matcher = new NfaMatcher({ blacklistedTerms: assignIncrementingIds(patterns.map(parseRawPattern)) }); - expect(matcher.getAllMatches(input)).toBePermutationOf(expected); - }); -}); - -describe('matching with whitelisted terms', () => { - it('should call the getMatches() method of the WhitelistedTermMatcher with the input', () => { - const spy = jest.spyOn(WhitelistedTermMatcher.prototype, 'getMatches'); - const matcher = new NfaMatcher({ - blacklistedTerms: [{ id: 1, pattern: pattern`thing` }], - blacklistMatcherTransformers: [skipNonAlphabeticTransformer()], - whitelistedTerms: ['thi ing'], - }); - matcher.getAllMatches('the thi ing'); - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenLastCalledWith('the thi ing'); - }); - - it('should not match parts of the text which are completely matched by a whitelisted term', () => { - const matcher = new NfaMatcher({ - blacklistedTerms: [{ id: 1, pattern: pattern`penis` }], - blacklistMatcherTransformers: [skipNonAlphabeticTransformer()], - whitelistedTerms: ['pen is'], - }); - expect(matcher.getAllMatches('the pen is mightier than the penis')).toStrictEqual([ - { - termId: 1, - startIndex: 29, - endIndex: 33, - matchLength: 5, - }, - ]); - }); - - it('should match parts of the text that only overlap (and are not completely contained) by a whitelisted term', () => { - const matcher = new NfaMatcher({ - blacklistedTerms: [{ id: 1, pattern: pattern`bitch` }], - whitelistedTerms: ['bit', 'itch'], - }); - expect(matcher.getAllMatches('a bitch')).toStrictEqual([ - { - termId: 1, - startIndex: 2, - endIndex: 6, - matchLength: 5, - }, - ]); - }); -}); - -describe('matching with blacklist transformers', () => { - it('should skip characters which became undefined after transformation', () => { - const skipSpaces = createSimpleTransformer((c) => (c === 32 ? undefined : c)); - const matcher = new NfaMatcher({ - blacklistedTerms: [{ id: 1, pattern: pattern`something` }], - blacklistMatcherTransformers: [skipSpaces], - }); - expect(matcher.getAllMatches('s o m e t h i n g')).toStrictEqual([ - { - termId: 1, - startIndex: 0, - endIndex: 17, - matchLength: 9, - }, - ]); - }); - - it('should work with transformers that change chars (no match)', () => { - // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/restrict-plus-operands - const changeAToB = createSimpleTransformer((c) => (c === CharacterCode.LowerA ? c + 1 : c)); - const matcher = new NfaMatcher({ - blacklistedTerms: [{ id: 1, pattern: pattern`sa?e` }], - blacklistMatcherTransformers: [changeAToB], - }); - expect(matcher.getAllMatches('same')).toHaveLength(0); - }); - - it('should work with transformers that change chars (with match)', () => { - // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/restrict-plus-operands - const changeAToB = createSimpleTransformer((c) => (c === CharacterCode.LowerA ? c + 1 : c)); - const matcher = new NfaMatcher({ - blacklistedTerms: [{ id: 1, pattern: pattern`hbllo?` }], - blacklistMatcherTransformers: [changeAToB], - }); - expect(matcher.getAllMatches('sup hallothere')).toStrictEqual([ - { - termId: 1, - startIndex: 4, - endIndex: 9, - matchLength: 6, - }, - ]); - }); - - it('should not affect matching of whitelisted terms', () => { - // eslint-disable-next-line @typescript-eslint/restrict-plus-operands - const ignoreAllAs = createSimpleTransformer((c) => (c === CharacterCode.LowerA ? c + 1 : c)); - const matcher = new NfaMatcher({ - blacklistedTerms: [{ id: 1, pattern: pattern`bbb` }], - whitelistedTerms: ['aabbbaa'], - blacklistMatcherTransformers: [ignoreAllAs], - }); - expect(matcher.getAllMatches('!!!! $$aabbbaa## !!!')).toHaveLength(0); - }); - - it('should work with patterns that have trailing wildcards', () => { - const skipSpaces = createSimpleTransformer((c) => (c === 32 ? undefined : c)); - const matcher = new NfaMatcher({ - blacklistedTerms: [{ id: 1, pattern: pattern`trailing?` }], - whitelistedTerms: [], - blacklistMatcherTransformers: [skipSpaces], - }); - expect(matcher.getAllMatches(' !!!! $$ t r a i l i n g## !!!')).toStrictEqual([ - { - termId: 1, - startIndex: 9, - endIndex: 33, - matchLength: 9, - }, - ]); - }); -}); - -describe('matching with whitelist transformers', () => { - it('should work with transformers which become undefined after transformation', () => { - const skipSpaces = createSimpleTransformer((c) => (c === 32 ? undefined : c)); - const matcher = new NfaMatcher({ - blacklistedTerms: [{ id: 1, pattern: pattern`world` }], - whitelistedTerms: ['helloworld!'], - whitelistMatcherTransformers: [skipSpaces], - }); - expect(matcher.getAllMatches('h e l l o world!')).toHaveLength(0); - }); - - it('should work with transformers that change chars (no match)', () => { - // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/restrict-plus-operands - const changeAToB = createSimpleTransformer((c) => (c === CharacterCode.LowerA ? c + 1 : c)); - const matcher = new NfaMatcher({ - blacklistedTerms: [{ id: 1, pattern: pattern`biash` }], - whitelistedTerms: ['a biash'], - whitelistMatcherTransformers: [changeAToB], - }); - expect(matcher.getAllMatches('the a biash was')).toStrictEqual([ - { termId: 1, startIndex: 6, endIndex: 10, matchLength: 5 }, - ]); - }); - - it('should work with transformers that change chars (with match)', () => { - // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/restrict-plus-operands - const changeAToB = createSimpleTransformer((c) => (c === CharacterCode.LowerA ? c + 1 : c)); - const matcher = new NfaMatcher({ - blacklistedTerms: [{ id: 1, pattern: pattern`ass` }], - whitelistedTerms: ['bss'], - whitelistMatcherTransformers: [changeAToB], - }); - expect(matcher.getAllMatches('a big ass')).toHaveLength(0); - }); - - it('should not affect matching of blacklisted terms', () => { - // eslint-disable-next-line @typescript-eslint/restrict-plus-operands - const ignoreAllAs = createSimpleTransformer((c) => (c === CharacterCode.LowerA ? c + 1 : c)); - const matcher = new NfaMatcher({ - blacklistedTerms: [{ id: 1, pattern: pattern`dader` }], - whitelistedTerms: ['a dader'], - whitelistMatcherTransformers: [ignoreAllAs], - }); - expect(matcher.getAllMatches('there is a dader')).toStrictEqual([ - { termId: 1, startIndex: 11, endIndex: 15, matchLength: 5 }, - ]); - }); -}); - -describe('NfaMatcher#getAllMatches()', () => { - describe('result match order', () => { - it('should be sorted if the sorted parameter is set to true', () => { - const matcher = new NfaMatcher({ - blacklistedTerms: assignIncrementingIds([pattern`sup`, pattern`u?`, pattern`dude`]), - }); - expect(matcher.getAllMatches('sup guys there are some dudes here', true)).toStrictEqual([ - { termId: 0, startIndex: 0, endIndex: 2, matchLength: 3 }, - { termId: 1, startIndex: 1, endIndex: 2, matchLength: 2 }, - { termId: 1, startIndex: 5, endIndex: 6, matchLength: 2 }, - { termId: 2, startIndex: 24, endIndex: 27, matchLength: 4 }, - { termId: 1, startIndex: 25, endIndex: 26, matchLength: 2 }, - ]); - }); - }); - - it('should work when called several times in a row', () => { - const matcher = new NfaMatcher({ - blacklistedTerms: assignIncrementingIds([pattern`foobar`, pattern`hello`]), - whitelistedTerms: ['the foobar'], - }); - expect(matcher.getAllMatches('the foobar is quite foobar hello yo')).toBePermutationOf([ - { termId: 0, startIndex: 20, endIndex: 25, matchLength: 6 }, - { termId: 1, startIndex: 27, endIndex: 31, matchLength: 5 }, - ]); - expect(matcher.getAllMatches('the foobar is quite foobar hello yo')).toBePermutationOf([ - { termId: 0, startIndex: 20, endIndex: 25, matchLength: 6 }, - { termId: 1, startIndex: 27, endIndex: 31, matchLength: 5 }, - ]); - expect(matcher.getAllMatches('the foobar is quite foobar hello yo')).toBePermutationOf([ - { termId: 0, startIndex: 20, endIndex: 25, matchLength: 6 }, - { termId: 1, startIndex: 27, endIndex: 31, matchLength: 5 }, - ]); - }); -}); - -describe('NfaMatcher#hasMatch()', () => { - it('should be true if there is a match', () => { - const matcher = new NfaMatcher({ - blacklistedTerms: assignIncrementingIds([pattern`there`, pattern`yo there hi`]), - }); - expect(matcher.hasMatch('the yo there has a yo there')).toBeTruthy(); - }); - - it('should be falsy if there is no match', () => { - const matcher = new NfaMatcher({ - blacklistedTerms: assignIncrementingIds([pattern`yo`]), - }); - expect(matcher.hasMatch('no y-word here!')).toBeFalsy(); - }); - - it('should not return true if a match with incorrect word boundaries is found', () => { - const matcher = new NfaMatcher({ - blacklistedTerms: assignIncrementingIds([pattern`|xs`]), - }); - expect(matcher.hasMatch('yoxs')).toBeFalsy(); - }); - - it('should return true if there is a match for a pattern with a wildcard at the end', () => { - const matcher = new NfaMatcher({ - blacklistedTerms: assignIncrementingIds([pattern`x?`]), - }); - expect(matcher.hasMatch('my xo')).toBeTruthy(); - }); - - it('should return true if there is a match for a pattern that only contains wildcards', () => { - const matcher = new NfaMatcher({ - blacklistedTerms: assignIncrementingIds([pattern`??`]), - }); - expect(matcher.hasMatch('xy')).toBeTruthy(); - }); - - it('should return true if there a match for a pattern that contains wildcards at the start (only 1 pattern)', () => { - const matcher = new NfaMatcher({ - blacklistedTerms: assignIncrementingIds([pattern`?x`]), - }); - expect(matcher.hasMatch('foo bar quux')).toBeTruthy(); - }); - - it('should return true if there is a match for a pattern that contains wildcards at the start (two patterns)', () => { - const matcher = new NfaMatcher({ - blacklistedTerms: assignIncrementingIds([pattern`?a`, pattern`?ba|`]), - }); - expect(matcher.hasMatch('xbac')).toBeTruthy(); - }); - - it('should work when called several times in a row', () => { - const matcher = new NfaMatcher({ - blacklistedTerms: assignIncrementingIds([pattern`yo there`]), - whitelistedTerms: ['the yo there'], - }); - expect(matcher.hasMatch('the yo there has a yo there')).toBeTruthy(); - expect(matcher.hasMatch('the yo there has a yo there')).toBeTruthy(); - expect(matcher.hasMatch('the yo there has a yo there')).toBeTruthy(); - }); -}); diff --git a/test/matcher/nfa/WhitelistedTermMatcher.fuzz.test.ts b/test/matcher/nfa/WhitelistedTermMatcher.fuzz.test.ts deleted file mode 100644 index 011b746..0000000 --- a/test/matcher/nfa/WhitelistedTermMatcher.fuzz.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import * as fc from 'fast-check'; -import { WhitelistedTermMatcher } from '../../../src/matcher/nfa/WhitelistedTermMatcher'; -import type { Interval } from '../../../src/util/Interval'; - -test('running the whitelist matcher with a set of terms and input should have the same result as running the brute force string searching algorithm on it', () => { - fc.assert( - fc.property( - fc.unicodeString().chain((input) => { - // Generate patterns that are substrings of the input. - const arbitrarySubstringPatterns = - input.length < 2 - ? fc.constant([]) - : fc.array( - fc - .tuple(fc.integer({ min: 0, max: input.length - 1 }), fc.integer({ min: 0, max: input.length - 1 })) - .map(([a, b]) => { - if (a > b) return input.slice(b, a); - return input.slice(a, b); - }) - .filter((p) => p.length > 0), - ); - return fc.tuple( - fc.constant(input), - fc.array(fc.unicodeString().filter((p) => p.length > 0)), - arbitrarySubstringPatterns, - ); - }), - ([input, randomPatterns, substrPatterns]) => { - // Deduplicate the patterns. - const set = new Set(); - for (const pattern of randomPatterns) set.add(pattern); - for (const pattern of substrPatterns) set.add(pattern); - const allPatterns = [...set]; - const matcher = new WhitelistedTermMatcher({ terms: allPatterns }); - expect([...matcher.getMatches(input)]).toBePermutationOf(bruteForceMatch(allPatterns, input)); - }, - ), - ); -}); - -function bruteForceMatch(patterns: string[], input: string) { - const result: Interval[] = []; - for (let i = 0; i < input.length; i++) { - for (const pattern of patterns) { - if (input.startsWith(pattern, i)) { - result.push([i, i + pattern.length - 1]); - } - } - } - - return result; -} diff --git a/test/matcher/nfa/WhitelistedTermMatcher.test.ts b/test/matcher/nfa/WhitelistedTermMatcher.test.ts deleted file mode 100644 index 0453d4f..0000000 --- a/test/matcher/nfa/WhitelistedTermMatcher.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { WhitelistedTermMatcher } from '../../../src/matcher/nfa/WhitelistedTermMatcher'; -import { createSimpleTransformer } from '../../../src/transformer/Transformers'; -import { CharacterCode } from '../../../src/util/Char'; - -describe('constructor', () => { - it('should not allow empty terms', () => { - expect(() => new WhitelistedTermMatcher({ terms: [''] })).toThrow(new Error('Unexpected empty whitelisted term.')); - }); -}); - -describe('WhitelistedTermMatcher#getMatchedSpans', () => { - it('should return an empty interval collection if there are no terms', () => { - const matches = new WhitelistedTermMatcher({ terms: [] }).getMatches('hello world'); - expect([...matches]).toHaveLength(0); - }); - - it.each([ - ['should match a term at the start of the string', ['hello'], 'hello world', [[0, 4]]], - ['should match a term at the end of the string', ['world'], 'hello world', [[6, 10]]], - ['should be case sensitive (no match)', ['WORLD'], 'hello world', []], - ['should be case sensitive (with match)', ['yO'], 'hello yO yo', [[6, 7]]], - ['should support spaces in terms', ['hello W0rld'], 'hello world! hello W0rld!', [[13, 23]]], - ['should support surrogate pairs', ['cool 🌉'], 'cool cool cool cool 🌉', [[15, 21]]], - [ - 'should work with terms that are suffixes of other ones', - ['cool', 'cool beans'], - 'cool cool beans', - [ - [0, 3], - [5, 8], - [5, 14], - ], - ], - [ - 'should work with terms that are suffixes of other ones, test 2', - ['he', 'she', 'his', 'her', 'here'], - 'he waited for she and her mom to go there', - [ - [0, 1], - [14, 16], - [15, 16], - [22, 23], - [22, 24], - [37, 40], - [37, 38], - [37, 39], - ], - ], - ['should only match on the term exactly', ['her'], 'h he! her', [[6, 8]]], - [ - 'should work with very long terms', - ['Pneumonoultramicroscopicsilicovolcanoconiosis', 'horrible'], - 'wow this word is quite long: Pneumonoultramicroscopicsilicovolcanoconiosie <- did you notice there was a typo there? horrible of me to do that... Pneumonoultramicroscopicsilicovolcanoconiosis', - [ - [117, 124], - [146, 190], - ], - ], - [ - 'should match several similar terms', - ['thing', 'thang'], - 'im just doin my thign thing ok thang', - [ - [22, 26], - [31, 35], - ], - ], - ['should work with terms that normalize to a different string', ['豈'], '豈', [[0, 0]]], - ['should handle null characters correctly', ['\u0000'], '\u0000', [[0, 0]]], - ])('%s', (_, terms, input, expected) => { - const matches = new WhitelistedTermMatcher({ terms }).getMatches(input); - expect([...matches]).toBePermutationOf(expected); - }); - - describe('transformers', () => { - it('should work with transformers that skip chars', () => { - const skipA = createSimpleTransformer((c) => (c === CharacterCode.LowerA ? undefined : c)); - const matches = new WhitelistedTermMatcher({ terms: ['intriguing'], transformers: [skipA] }).getMatches( - 'hello world! inatrigauainagfoo bar.', - ); - expect([...matches]).toBePermutationOf([[13, 26]]); - }); - - it('should work with transformers that change chars (no match)', () => { - // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/restrict-plus-operands - const changeAToB = createSimpleTransformer((c) => (c === CharacterCode.LowerA ? CharacterCode.LowerA + 1 : c)); - const matches = new WhitelistedTermMatcher({ terms: ['hallo'], transformers: [changeAToB] }).getMatches('hallo'); - expect([...matches]).toHaveLength(0); - }); - - it('should work with transformers that change chars (with match)', () => { - // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/restrict-plus-operands - const changeAToB = createSimpleTransformer((c) => (c === CharacterCode.LowerA ? CharacterCode.LowerA + 1 : c)); - const matches = new WhitelistedTermMatcher({ terms: ['hbllo'], transformers: [changeAToB] }).getMatches('hallo'); - expect([...matches]).toBePermutationOf([[0, 4]]); - }); - }); -}); diff --git a/test/matcher/nfa/trie/BlacklistTrieNode.test.ts b/test/matcher/nfa/trie/BlacklistTrieNode.test.ts deleted file mode 100644 index 82e6a5d..0000000 --- a/test/matcher/nfa/trie/BlacklistTrieNode.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { BlacklistTrieNode, hashPartialMatch } from '../../../../src/matcher/nfa/trie/BlacklistTrieNode'; - -describe('constructor', () => { - it('should set edges to an empty edge list', () => { - expect(new BlacklistTrieNode().edges.size).toBe(0); - }); - - it('should set term id to -1', () => { - expect(new BlacklistTrieNode().termId).toBe(-1); - }); - - it('should set flags to 0', () => { - expect(new BlacklistTrieNode().flags).toBe(0); - }); -}); - -describe('hashPartialMatch()', () => { - it('should return a string in the format step-termId', () => { - expect(hashPartialMatch(0, 5)).toBe('0-5'); - }); -}); diff --git a/test/matcher/nfa/trie/WhitelistTrieNode.test.ts b/test/matcher/nfa/trie/WhitelistTrieNode.test.ts deleted file mode 100644 index e8617a7..0000000 --- a/test/matcher/nfa/trie/WhitelistTrieNode.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { WhitelistTrieNode } from '../../../../src/matcher/nfa/trie/WhitelistTrieNode'; - -describe('constructor', () => { - it('should set edges to an empty edge list', () => { - expect(new WhitelistTrieNode().edges.size).toBe(0); - }); - - it('should set termId to -1', () => { - expect(new WhitelistTrieNode().termId).toBe(-1); - }); - - it('should set isOutputNode to false', () => { - expect(new WhitelistTrieNode().isOutputNode).toBeFalsy(); - }); -}); diff --git a/test/matcher/nfa/trie/edge/ArrayEdgeCollection.test.ts b/test/matcher/nfa/trie/edge/ArrayEdgeCollection.test.ts deleted file mode 100644 index b7a51bf..0000000 --- a/test/matcher/nfa/trie/edge/ArrayEdgeCollection.test.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { ArrayEdgeCollection } from '../../../../../src/matcher/nfa/trie/edge/ArrayEdgeCollection'; -import type { Edge } from '../../../../../src/matcher/nfa/trie/edge/EdgeCollection'; - -let coll: ArrayEdgeCollection; - -beforeEach(() => { - coll = new ArrayEdgeCollection(); -}); - -describe('ArrayEdgeCollection#set()', () => { - it('should add the edge to the collection', () => { - coll.set(5, 'a'); - expect([...coll]).toBePermutationOf([[5, 'a']]); - }); - - it('should overwrite an existing edge if possible', () => { - coll.set(1, 'y'); - // eslint-disable-next-line sonarjs/no-element-overwrite - coll.set(1, 'z'); - expect([...coll]).toBePermutationOf([[1, 'z']]); - }); - - it('should increment the size only if no existing edge was found', () => { - coll.set(7, 'y'); - expect(coll.size).toBe(1); - coll.set(7, 'z'); - expect(coll.size).toBe(1); - }); -}); - -const edges: Edge[] = [ - [1, 'e'], - [4, 'o'], - [3, 'i'], - [7, 'z'], - [0, 'w'], - [10, 'b'], - [43, 'c'], - [57, 'v'], - [19, 'f'], -]; - -describe('ArrayEdgeCollection#get()', () => { - it('should return the node corresponding to the edge (<= 10 values in the collection)', () => { - coll.set(7, 'd'); - coll.set(9, 'z'); - coll.set(5, 'c'); - coll.set(10, 'e'); - expect(coll.get(5)).toBe('c'); - expect(coll.get(7)).toBe('d'); - expect(coll.get(9)).toBe('z'); - expect(coll.get(10)).toBe('e'); - }); - - it('should return the node corresponding to the edge (> 10 values in the collection)', () => { - for (const edge of edges) coll.set(...edge); - expect(coll.get(1)).toBe('e'); - expect(coll.get(57)).toBe('v'); - expect(coll.get(43)).toBe('c'); - expect(coll.get(0)).toBe('w'); - expect(coll.get(10)).toBe('b'); - }); - - it('should return undefined if there is no node corresponding to the edge (<= 3 values in the collection)', () => { - coll.set(5, 'x'); - coll.set(7, 'd'); - expect(coll.get(0)).toBeUndefined(); - expect(coll.get(6)).toBeUndefined(); - expect(coll.get(494)).toBeUndefined(); - }); - - it('should return undefined if there is no node corresponding to the edge (> 3 values in the collection)', () => { - for (const edge of edges) coll.set(...edge); - expect(coll.get(12)).toBeUndefined(); - expect(coll.get(15)).toBeUndefined(); - expect(coll.get(-1)).toBeUndefined(); - expect(coll.get(58)).toBeUndefined(); - expect(coll.get(554)).toBeUndefined(); - }); -}); - -describe('ArrayEdgeCollection#keys()', () => { - it('should return an iterator over the keys of the collection', () => { - coll.set(5, 'd'); - coll.set(8, 'e'); - coll.set(3, 'x'); - coll.set(10, 'e'); - expect([...coll.keys()]).toBePermutationOf([5, 8, 3, 10]); - }); -}); - -describe('ArrayEdgeCollection#values()', () => { - it('should return an iterator over the values of the collection', () => { - coll.set(19, 'd'); - coll.set(9, 'd'); - coll.set(15, 'e'); - coll.set(13, 'e'); - expect([...coll.values()]).toBePermutationOf(['d', 'd', 'e', 'e']); - }); -}); - -it('should be iterable', () => { - coll.set(12, 'j'); - coll.set(43, 'e'); - coll.set(17, 'p'); - coll.set(59, 'e'); - expect([...coll]).toBePermutationOf([ - [12, 'j'], - [43, 'e'], - [17, 'p'], - [59, 'e'], - ]); -}); diff --git a/test/matcher/nfa/trie/edge/BucketEdgeCollection.test.ts b/test/matcher/nfa/trie/edge/BucketEdgeCollection.test.ts deleted file mode 100644 index c159f4d..0000000 --- a/test/matcher/nfa/trie/edge/BucketEdgeCollection.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { BucketEdgeCollection } from '../../../../../src/matcher/nfa/trie/edge/BucketEdgeCollection'; - -const getCode = (c: string) => c.charCodeAt(0); - -let coll: BucketEdgeCollection; - -beforeEach(() => { - coll = new BucketEdgeCollection(); -}); - -describe('BucketEdgeCollection#set()', () => { - it('should add the edge to the collection', () => { - coll.set(getCode('a'), 'x'); - expect([...coll]).toBePermutationOf([[getCode('a'), 'x']]); - }); - - it('should increment the size only if no existing edge was found', () => { - coll.set(getCode('d'), 'a'); - expect(coll.size).toBe(1); - coll.set(getCode('d'), 'c'); - expect(coll.size).toBe(1); - }); -}); - -describe('BucketEdgeCollection#get()', () => { - it('should return the node corresponding to the character', () => { - coll.set(getCode('c'), 'd'); - coll.set(getCode('e'), 'y'); - coll.set(getCode('z'), 'e'); - expect(coll.get(getCode('c'))).toBe('d'); - expect(coll.get(getCode('e'))).toBe('y'); - expect(coll.get(getCode('z'))).toBe('e'); - }); - - it('should return undefined if no node exists', () => { - coll.set(getCode('e'), 'd'); - coll.set(getCode('z'), 'e'); - coll.set(getCode('y'), 'z'); - coll.set(getCode('p'), 'y'); - expect(coll.get(getCode('a'))).toBeUndefined(); - expect(coll.get(getCode('w'))).toBeUndefined(); - expect(coll.get(getCode('f'))).toBeUndefined(); - }); - - it('should return undefined if the key was not a lowercase letter', () => { - expect(coll.get(-1)).toBeUndefined(); - expect(coll.get(0)).toBeUndefined(); - expect(coll.get(getCode('z') + 1)).toBeUndefined(); - expect(coll.get(getCode('a') - 1)).toBeUndefined(); - expect(coll.get(594)).toBeUndefined(); - }); -}); - -describe('BucketEdgeCollection#keys()', () => { - it('should return an iterator over the keys', () => { - coll.set(getCode('z'), 'd'); - coll.set(getCode('u'), 'e'); - coll.set(getCode('n'), 'p'); - coll.set(getCode('m'), 'r'); - expect([...coll.keys()]).toBePermutationOf(['z', 'u', 'n', 'm'].map(getCode)); - }); -}); - -describe('BucketEdgeCollection#values()', () => { - it('should return an iterator over the values', () => { - coll.set(getCode('l'), 'e'); - coll.set(getCode('h'), 'e'); - coll.set(getCode('a'), 'p'); - coll.set(getCode('i'), 'v'); - expect([...coll.values()]).toBePermutationOf(['e', 'e', 'p', 'v']); - }); -}); - -it('should be iterable', () => { - coll.set(getCode('r'), 'j'); - coll.set(getCode('l'), 'e'); - coll.set(getCode('n'), 'p'); - coll.set(getCode('s'), 'e'); - expect([...coll]).toBePermutationOf([ - [getCode('r'), 'j'], - [getCode('l'), 'e'], - [getCode('n'), 'p'], - [getCode('s'), 'e'], - ]); -}); diff --git a/test/matcher/nfa/trie/edge/ForwardingEdgeCollection.test.ts b/test/matcher/nfa/trie/edge/ForwardingEdgeCollection.test.ts deleted file mode 100644 index 796465e..0000000 --- a/test/matcher/nfa/trie/edge/ForwardingEdgeCollection.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { ArrayEdgeCollection } from '../../../../../src/matcher/nfa/trie/edge/ArrayEdgeCollection'; -import { BucketEdgeCollection } from '../../../../../src/matcher/nfa/trie/edge/BucketEdgeCollection'; -import type { Edge } from '../../../../../src/matcher/nfa/trie/edge/EdgeCollection'; -import { ForwardingEdgeCollection } from '../../../../../src/matcher/nfa/trie/edge/ForwardingEdgeCollection'; -import { CharacterCode } from '../../../../../src/util/Char'; - -let coll: ForwardingEdgeCollection; - -beforeEach(() => { - coll = new ForwardingEdgeCollection(); -}); - -afterEach(() => { - jest.restoreAllMocks(); -}); - -describe('ForwardingEdgeCollection#set()', () => { - it('should use the array implementation by default', () => { - const spy = jest.spyOn(ArrayEdgeCollection.prototype, 'set'); - coll.set(5, 7); - expect(coll.underlyingImplementation).toBeInstanceOf(ArrayEdgeCollection); - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenLastCalledWith(5, 7); - }); - - it('should switch to the bucket implementation if the number of edges is > 10 and the keys are all lowercase', () => { - const spy = jest.spyOn(BucketEdgeCollection.prototype, 'set'); - const edges = [...Array.from({ length: 11 }).keys()].map>((i) => [i + CharacterCode.LowerA, i]); - for (const edge of edges) coll.set(...edge); - expect(coll.underlyingImplementation).toBeInstanceOf(BucketEdgeCollection); - expect(spy).toHaveBeenCalledTimes(11); - expect(spy.mock.calls).toBePermutationOf(edges); - }); - - it('should switch back to the array implementation if currently using the bucket implementation and an edge with a non-lowercase key is added', () => { - const bucketImplSpy = jest.spyOn(BucketEdgeCollection.prototype, 'set'); - const arrayImplSpy = jest.spyOn(ArrayEdgeCollection.prototype, 'set'); - const edges = [...Array.from({ length: 11 }).keys()].map>((i) => [i + CharacterCode.LowerA, i]); - for (const edge of edges) coll.set(...edge); - coll.set(5, 19); - expect(bucketImplSpy).toHaveBeenCalledTimes(11); - expect(bucketImplSpy).not.toHaveBeenCalledWith(5, 19); - expect(coll.underlyingImplementation).toBeInstanceOf(ArrayEdgeCollection); - expect(arrayImplSpy).toHaveBeenCalledTimes(23); - expect(arrayImplSpy.mock.calls).toBePermutationOf([...edges, ...edges, [5, 19]]); - }); - - it('should use the map implementation if the number of edges is > 35', () => { - const spy = jest.spyOn(Map.prototype, 'set'); - const edges = [...Array.from({ length: 36 }).keys()].map>((i) => [i, i + 5]); - for (const edge of edges) coll.set(...edge); - expect(coll.underlyingImplementation).toBeInstanceOf(Map); - expect(spy).toHaveBeenCalledTimes(36); - expect(spy.mock.calls).toBePermutationOf(edges); - }); -}); - -function getEdgeCollWithArrayImpl() { - const coll = new ForwardingEdgeCollection(); - coll.set(5, 19); - return coll; -} - -function getEdgeCollWithBucketImpl() { - const coll = new ForwardingEdgeCollection(); - for (let i = 0; i < 11; i++) coll.set(i + CharacterCode.LowerA, i); - return coll; -} - -function getEdgeCollWithMapImpl() { - const coll = new ForwardingEdgeCollection(); - for (let i = 0; i < 36; i++) coll.set(i, i + 5); - return coll; -} - -describe('ForwardingEdgeCollection#get()', () => { - it('should forward the call to the array implementation if that is the underlying implementation', () => { - const spy = jest.spyOn(ArrayEdgeCollection.prototype, 'get'); - getEdgeCollWithArrayImpl().get(5); - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenLastCalledWith(5); - }); - - it('should forward the call to the bucket implementation if that is the underlying implementation', () => { - const spy = jest.spyOn(BucketEdgeCollection.prototype, 'get'); - getEdgeCollWithBucketImpl().get(95); - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenLastCalledWith(95); - }); - - it('should forward the call to the map implementation if that is the underlying implementation', () => { - const spy = jest.spyOn(Map.prototype, 'get'); - getEdgeCollWithMapImpl().get(39); - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenLastCalledWith(39); - }); -}); - -describe.each<'keys' | 'values'>(['keys', 'values'])('ForwardingEdgeCollection#%s()', (method) => { - it('should forward the call to the array implementation if that is the underlying implementation', () => { - const spy = jest.spyOn(ArrayEdgeCollection.prototype, method); - getEdgeCollWithArrayImpl()[method](); - expect(spy).toHaveBeenCalledTimes(1); - }); - - it('should forward the call to the bucket implementation if that is the underlying implementation', () => { - const spy = jest.spyOn(BucketEdgeCollection.prototype, method); - getEdgeCollWithBucketImpl()[method](); - expect(spy).toHaveBeenCalledTimes(1); - }); - - it('should forward the call to the map implementation if that is the underlying implementation', () => { - const spy = jest.spyOn(Map.prototype, method); - getEdgeCollWithMapImpl()[method](); - expect(spy).toHaveBeenCalledTimes(1); - }); -});