diff --git a/README.md b/README.md index 658a891..b969f84 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ const hexDigit = charClass( const hexColor = buildRegExp( startOfString, - optionally('#'), + optional('#'), capture( choiceOf( repeat(hexDigit, 6), // #rrggbb @@ -85,7 +85,7 @@ const currencyAmount = buildRegExp([ ), capture( oneOrMore(digit), // Integer part - optionally(['.', repeat(digit, 2)]), // Fractional part + optional(['.', repeat(digit, 2)]), // Fractional part ), ]); ``` @@ -112,7 +112,7 @@ Comprehensive API document is available [here](./API.md). | -------------------------------- | ------------- | ------------------------------------------------- | | `zeroOrMore(x)` | `x*` | Zero or more occurence of a pattern | | `oneOrMore(x)` | `x+` | One or more occurence of a pattern | -| `optionally(x)` | `x?` | Zero or one occurence of a pattern | +| `optional(x)` | `x?` | Zero or one occurence of a pattern | | `repeat(x, n)` | `x{n}` | Pattern repeats exact number of times | | `repeat(x, { min: n, })` | `x{n,}` | Pattern repeats at least given number of times | | `repeat(x, { min: n, max: n2 })` | `x{n1,n2}` | Pattern repeats between n1 and n2 number of times | diff --git a/docs/API.md b/docs/API.md index 70e4e2a..88dbd8d 100644 --- a/docs/API.md +++ b/docs/API.md @@ -100,17 +100,17 @@ Regex syntax: `x+`; The `oneOrMore` quantifier matches one or more occurrences of given pattern, allowing a flexible number of repetitions of that element. -### `optionally()` +### `optional()` ```ts -function optionally( +function optional( sequence: RegexSequence, ): Optionally ``` Regex syntax: `x?`; -The `optionally` quantifier matches zero or one occurrence of given pattern, making it optional. +The `optional` quantifier matches zero or one occurrence of given pattern, making it optional. ### `repeat()` diff --git a/docs/Examples.md b/docs/Examples.md index 10c891a..bd96a87 100644 --- a/docs/Examples.md +++ b/docs/Examples.md @@ -3,16 +3,16 @@ ## JavaScript number ```ts -const optionalSign = optionally(anyOf('+-')); -const exponent = [anyOf('eE'), optionalSign, oneOrMore(digit)]; +const sign = anyOf('+-'); +const exponent = [anyOf('eE'), optional(sign), oneOrMore(digit)]; const regex = buildRegExp([ - optionalSign, + optional(sing), choiceOf( - [oneOrMore(digit), optionally(['.', zeroOrMore(digit)])], // leading digit + [oneOrMore(digit), optional(['.', zeroOrMore(digit)])], // leading digit ['.', oneOrMore(digit)], // leading dot ), - optionally(exponent), // exponent + optional(exponent), // exponent ]); ``` diff --git a/src/__tests__/examples.test.ts b/src/__tests__/examples.test.ts index 0155b4d..6455069 100644 --- a/src/__tests__/examples.test.ts +++ b/src/__tests__/examples.test.ts @@ -6,24 +6,24 @@ import { digit, endOfString, oneOrMore, - optionally, + optional, repeat, startOfString, zeroOrMore, } from '../index'; test('example: validate JavaScript number', () => { - const optionalSign = optionally(anyOf('+-')); - const exponent = [anyOf('eE'), optionalSign, oneOrMore(digit)]; + const sign = anyOf('+-'); + const exponent = [anyOf('eE'), optional(sign), oneOrMore(digit)]; const regex = buildRegExp([ startOfString, - optionalSign, + optional(sign), choiceOf( - [oneOrMore(digit), optionally(['.', zeroOrMore(digit)])], // leading digit + [oneOrMore(digit), optional(['.', zeroOrMore(digit)])], // leading digit ['.', oneOrMore(digit)], // leading dot ), - optionally(exponent), // exponent + optional(exponent), // exponent endOfString, ]); diff --git a/src/constructs/__tests__/character-class.test.ts b/src/constructs/__tests__/character-class.test.ts index 7a60c4d..bc8d703 100644 --- a/src/constructs/__tests__/character-class.test.ts +++ b/src/constructs/__tests__/character-class.test.ts @@ -1,4 +1,4 @@ -import { oneOrMore, optionally, zeroOrMore } from '../quantifiers'; +import { oneOrMore, optional, zeroOrMore } from '../quantifiers'; import { any, anyOf, @@ -76,7 +76,7 @@ test('`anyOf` base cases', () => { test('`anyOf` with quantifiers', () => { expect(['x', oneOrMore(anyOf('abc')), 'x']).toHavePattern(/x[abc]+x/); - expect(['x', optionally(anyOf('abc')), 'x']).toHavePattern(/x[abc]?x/); + expect(['x', optional(anyOf('abc')), 'x']).toHavePattern(/x[abc]?x/); expect(['x', zeroOrMore(anyOf('abc')), 'x']).toHavePattern(/x[abc]*x/); }); diff --git a/src/constructs/__tests__/quantifiers.test.tsx b/src/constructs/__tests__/quantifiers.test.tsx index 22a2584..cb882c0 100644 --- a/src/constructs/__tests__/quantifiers.test.tsx +++ b/src/constructs/__tests__/quantifiers.test.tsx @@ -1,14 +1,14 @@ import { digit } from '../character-class'; -import { oneOrMore, optionally, zeroOrMore } from '../quantifiers'; +import { oneOrMore, optional, zeroOrMore } from '../quantifiers'; test('`oneOrMore` quantifier', () => { expect(oneOrMore('a')).toHavePattern(/a+/); expect(oneOrMore('ab')).toHavePattern(/(?:ab)+/); }); -test('`optionally` quantifier', () => { - expect(optionally('a')).toHavePattern(/a?/); - expect(optionally('ab')).toHavePattern(/(?:ab)?/); +test('`optional` quantifier', () => { + expect(optional('a')).toHavePattern(/a?/); + expect(optional('ab')).toHavePattern(/(?:ab)?/); }); test('`zeroOrMore` quantifier', () => { @@ -20,8 +20,8 @@ test('`oneOrMore` does not generate capture when grouping', () => { expect(oneOrMore('aa')).toMatchGroups('aa', ['aa']); }); -test('`optionally` does not generate capture when grouping', () => { - expect(optionally('aa')).toMatchGroups('aa', ['aa']); +test('`optional` does not generate capture when grouping', () => { + expect(optional('aa')).toMatchGroups('aa', ['aa']); }); test('`zeroOrMore` does not generate capture when grouping', () => { @@ -30,10 +30,10 @@ test('`zeroOrMore` does not generate capture when grouping', () => { test('base quantifiers optimize grouping for atoms', () => { expect(oneOrMore(digit)).toHavePattern(/\d+/); - expect(optionally(digit)).toHavePattern(/\d?/); + expect(optional(digit)).toHavePattern(/\d?/); expect(zeroOrMore(digit)).toHavePattern(/\d*/); expect(oneOrMore('a')).toHavePattern(/a+/); - expect(optionally('a')).toHavePattern(/a?/); + expect(optional('a')).toHavePattern(/a?/); expect(zeroOrMore('a')).toHavePattern(/a*/); }); diff --git a/src/constructs/quantifiers.ts b/src/constructs/quantifiers.ts index c96a71d..77bb165 100644 --- a/src/constructs/quantifiers.ts +++ b/src/constructs/quantifiers.ts @@ -3,19 +3,27 @@ import type { EncodeResult } from '../encoder/types'; import { ensureArray } from '../utils/elements'; import type { RegexConstruct, RegexElement, RegexSequence } from '../types'; +export interface ZeroOrMore extends RegexConstruct { + type: 'zeroOrMore'; + children: RegexElement[]; +} + export interface OneOrMore extends RegexConstruct { type: 'oneOrMore'; children: RegexElement[]; } -export interface Optionally extends RegexConstruct { - type: 'optionally'; +export interface Optional extends RegexConstruct { + type: 'optional'; children: RegexElement[]; } -export interface ZeroOrMore extends RegexConstruct { - type: 'zeroOrMore'; - children: RegexElement[]; +export function zeroOrMore(sequence: RegexSequence): ZeroOrMore { + return { + type: 'zeroOrMore', + children: ensureArray(sequence), + encode: encodeZeroOrMore, + }; } export function oneOrMore(sequence: RegexSequence): OneOrMore { @@ -26,19 +34,18 @@ export function oneOrMore(sequence: RegexSequence): OneOrMore { }; } -export function optionally(sequence: RegexSequence): Optionally { +export function optional(sequence: RegexSequence): Optional { return { - type: 'optionally', + type: 'optional', children: ensureArray(sequence), - encode: encodeOptionally, + encode: encodeOptional, }; } -export function zeroOrMore(sequence: RegexSequence): ZeroOrMore { +function encodeZeroOrMore(this: ZeroOrMore): EncodeResult { return { - type: 'zeroOrMore', - children: ensureArray(sequence), - encode: encodeZeroOrMore, + precedence: 'sequence', + pattern: `${encodeAtom(this.children).pattern}*`, }; } @@ -49,16 +56,9 @@ function encodeOneOrMore(this: OneOrMore): EncodeResult { }; } -function encodeOptionally(this: Optionally): EncodeResult { +function encodeOptional(this: Optional): EncodeResult { return { precedence: 'sequence', pattern: `${encodeAtom(this.children).pattern}?`, }; } - -function encodeZeroOrMore(this: ZeroOrMore): EncodeResult { - return { - precedence: 'sequence', - pattern: `${encodeAtom(this.children).pattern}*`, - }; -} diff --git a/src/encoder/__tests__/encoder.test.tsx b/src/encoder/__tests__/encoder.test.tsx index d52dc3f..86f9ce2 100644 --- a/src/encoder/__tests__/encoder.test.tsx +++ b/src/encoder/__tests__/encoder.test.tsx @@ -1,5 +1,5 @@ import { buildPattern, buildRegExp } from '../../builders'; -import { oneOrMore, optionally, zeroOrMore } from '../../constructs/quantifiers'; +import { oneOrMore, optional, zeroOrMore } from '../../constructs/quantifiers'; import { repeat } from '../../constructs/repeat'; test('basic quantifies', () => { @@ -7,7 +7,7 @@ test('basic quantifies', () => { expect(['a', 'b']).toHavePattern(/ab/); expect(oneOrMore('a')).toHavePattern(/a+/); - expect(optionally('a')).toHavePattern(/a?/); + expect(optional('a')).toHavePattern(/a?/); expect(['a', oneOrMore('b')]).toHavePattern(/ab+/); expect(['a', oneOrMore('bc')]).toHavePattern(/a(?:bc)+/); @@ -19,9 +19,9 @@ test('basic quantifies', () => { expect(['a', zeroOrMore('bc')]).toHavePattern(/a(?:bc)*/); expect(['a', zeroOrMore('bc')]).toHavePattern(/a(?:bc)*/); - expect([optionally('a'), 'b']).toHavePattern(/a?b/); + expect([optional('a'), 'b']).toHavePattern(/a?b/); - expect([optionally('a'), 'b', oneOrMore('d')]).toHavePattern(/a?bd+/); + expect([optional('a'), 'b', oneOrMore('d')]).toHavePattern(/a?bd+/); }); test('`buildPattern` escapes special characters', () => { diff --git a/src/index.ts b/src/index.ts index 9bfb3d5..d7f7514 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,5 +15,5 @@ export { inverted, } from './constructs/character-class'; export { choiceOf } from './constructs/choice-of'; -export { oneOrMore, optionally, zeroOrMore } from './constructs/quantifiers'; +export { oneOrMore, optional, zeroOrMore } from './constructs/quantifiers'; export { repeat } from './constructs/repeat';