Skip to content

Commit

Permalink
feat: inverted character class (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
mdjastrzebski authored Dec 21, 2023
1 parent 1b4e445 commit f45e8a5
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 9 deletions.
20 changes: 19 additions & 1 deletion src/components/__tests__/character-class.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import {
anyOf,
digit,
encodeCharacterClass,
inverted,
whitespace,
word,
} from '../character-class';
import { execRegex } from '../../test-utils';

test('"whitespace" character class', () => {
expect(buildPattern(whitespace)).toEqual(`\\s`);
Expand Down Expand Up @@ -60,17 +62,33 @@ test('"anyOf" moves hyphen to the first position', () => {
expect(buildPattern(anyOf('a-bc'))).toBe('[-abc]');
});

test('`anyOf` throws on empty text', () => {
test('"anyOf" throws on empty text', () => {
expect(() => anyOf('')).toThrowErrorMatchingInlineSnapshot(
`"\`anyOf\` should received at least one character"`
);
});

test('"inverted" character class', () => {
expect(buildPattern(inverted(anyOf('a')))).toBe('[^a]');
expect(buildPattern(inverted(anyOf('abc')))).toBe('[^abc]');
});

test('"inverted" character class double inversion', () => {
expect(buildPattern(inverted(inverted(anyOf('a'))))).toBe('a');
expect(buildPattern(inverted(inverted(anyOf('abc'))))).toBe('[abc]');
});

test('"inverted" character class execution', () => {
expect(execRegex('aa', [inverted(anyOf('a'))])).toBeNull();
expect(execRegex('aba', [inverted(anyOf('a'))])).toEqual(['b']);
});

test('buildPattern throws on empty text', () => {
expect(() =>
encodeCharacterClass({
type: 'characterClass',
characters: [],
inverted: false,
})
).toThrowErrorMatchingInlineSnapshot(
`"Character class should contain at least one character"`
Expand Down
28 changes: 21 additions & 7 deletions src/components/character-class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,25 @@ import type { CharacterClass } from './types';
export const any: CharacterClass = {
type: 'characterClass',
characters: ['.'],
inverted: false,
};

export const whitespace: CharacterClass = {
type: 'characterClass',
characters: ['\\s'],
inverted: false,
};

export const digit: CharacterClass = {
type: 'characterClass',
characters: ['\\d'],
inverted: false,
};

export const word: CharacterClass = {
type: 'characterClass',
characters: ['\\w'],
inverted: false,
};

export function anyOf(characters: string): CharacterClass {
Expand All @@ -31,26 +35,36 @@ export function anyOf(characters: string): CharacterClass {
return {
type: 'characterClass',
characters: charactersArray,
inverted: false,
};
}

export function encodeCharacterClass({
characters,
}: CharacterClass): EncoderNode {
if (characters.length === 0) {
export function inverted(characterClass: CharacterClass): CharacterClass {
return {
type: 'characterClass',
characters: characterClass.characters,
inverted: !characterClass.inverted,
};
}

export function encodeCharacterClass(
characterClass: CharacterClass
): EncoderNode {
if (characterClass.characters.length === 0) {
throw new Error('Character class should contain at least one character');
}

if (characters.length === 1) {
if (characterClass.characters.length === 1 && !characterClass.inverted) {
return {
precedence: EncoderPrecedence.Atom,
pattern: characters[0]!,
pattern: characterClass.characters[0]!,
};
}

const characterString = reorderHyphen(characterClass.characters).join('');
return {
precedence: EncoderPrecedence.Atom,
pattern: `[${reorderHyphen(characters).join('')}]`,
pattern: `[${characterClass.inverted ? '^' : ''}${characterString}]`,
};
}

Expand Down
1 change: 1 addition & 0 deletions src/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type Quantifier = One | OneOrMore | Optionally | ZeroOrMore | Repeat;
export type CharacterClass = {
type: 'characterClass';
characters: string[];
inverted: boolean;
};

// Components
Expand Down
3 changes: 2 additions & 1 deletion src/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ export function execRegex(
elements: Array<RegexElement | string>
) {
const regex = buildRegex(...elements);
return [...regex.exec(text)!];
const result = regex.exec(text);
return result ? [...result] : null;
}

0 comments on commit f45e8a5

Please sign in to comment.