Skip to content

Commit 403e7e9

Browse files
refactor: split code into multiple files (#2)
1 parent dfd5d2f commit 403e7e9

10 files changed

+123
-83
lines changed

Diff for: README.md

+3-4
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ npm install ts-regex
1111
## Usage
1212

1313
```js
14-
import { multiply } from 'ts-regex';
14+
import { buildRegex, oneOrMore } from 'ts-regex';
1515

16-
// ...
17-
18-
const result = await multiply(3, 7);
16+
// /(Hello)+ World/
17+
const regex = buildRegex(oneOrMore('Hello '), 'World');
1918
```
2019

2120
## Contributing

Diff for: src/__tests__/compiler.test.tsx

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { buildPattern, buildRegex, oneOrMore, optionally } from '..';
2+
3+
test('basic quantifies', () => {
4+
expect(buildPattern('a')).toEqual('a');
5+
expect(buildPattern('a', 'b')).toEqual('ab');
6+
7+
expect(buildPattern(oneOrMore('a'))).toEqual('a+');
8+
expect(buildPattern(optionally('a'))).toEqual('a?');
9+
10+
expect(buildPattern('a', oneOrMore('b'))).toEqual('ab+');
11+
expect(buildPattern('a', oneOrMore('bc'))).toEqual('a(bc)+');
12+
expect(buildPattern('a', oneOrMore('bc'))).toEqual('a(bc)+');
13+
14+
expect(buildPattern(optionally('a'), 'b')).toEqual('a?b');
15+
});
16+
17+
test('regex constructor', () => {
18+
expect(buildRegex('a').test('a')).toBeTruthy();
19+
expect(buildRegex('a').test('b')).toBeFalsy();
20+
});

Diff for: src/__tests__/index.test.tsx

-76
This file was deleted.

Diff for: src/__tests__/quantifier.test.tsx

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { oneOrMore, optionally } from '../quantifiers';
2+
import { buildPattern } from '../compiler';
3+
4+
test('"oneOrMore" quantifier', () => {
5+
expect(buildPattern(oneOrMore('a'))).toEqual('a+');
6+
expect(buildPattern(oneOrMore('ab'))).toEqual('(ab)+');
7+
});
8+
9+
test('"optionally" quantifier', () => {
10+
expect(buildPattern(optionally('a'))).toEqual('a?');
11+
expect(buildPattern(optionally('ab'))).toEqual('(ab)?');
12+
});

Diff for: src/compiler.ts

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import type { RegexComponent } from './types';
2+
import { compilers as quantifiers } from './quantifiers';
3+
4+
/**
5+
* Generate RegExp object from components.
6+
*
7+
* @param components
8+
* @returns
9+
*/
10+
export function buildRegex(...components: RegexComponent[]): RegExp {
11+
const pattern = compileList(components);
12+
return new RegExp(pattern);
13+
}
14+
15+
/**
16+
* Generate regex pattern from components.
17+
* @param components
18+
* @returns
19+
*/
20+
export function buildPattern(...components: RegexComponent[]): string {
21+
return compileList(components);
22+
}
23+
24+
// Recursive compilation
25+
26+
function compileList(components: RegexComponent[]): string {
27+
return components.map((c) => compileSingle(c)).join('');
28+
}
29+
30+
function compileSingle(component: RegexComponent): string {
31+
if (typeof component === 'string') {
32+
return component;
33+
}
34+
35+
const componentCompiler = quantifiers[component.type];
36+
if (!componentCompiler) {
37+
throw new Error(`Unknown component type ${component.type}`);
38+
}
39+
40+
const children = compileList(component.children);
41+
return componentCompiler(children);
42+
}

Diff for: src/index.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
export function multiply(a: number, b: number): Promise<number> {
2-
return Promise.resolve(a * b);
3-
}
1+
export type * from './types';
2+
3+
export { buildRegex, buildPattern } from './compiler';
4+
export { oneOrMore, optionally } from './quantifiers';

Diff for: src/quantifiers.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { OneOrMore, Optionally, RegexComponent } from './types';
2+
import type { CompilerMap } from './types-internal';
3+
import { wrapGroup } from './utils';
4+
5+
export function oneOrMore(...children: RegexComponent[]): OneOrMore {
6+
return {
7+
type: 'oneOrMore',
8+
children,
9+
};
10+
}
11+
12+
export function optionally(...children: RegexComponent[]): Optionally {
13+
return {
14+
type: 'optionally',
15+
children,
16+
};
17+
}
18+
19+
export const compilers = {
20+
oneOrMore: (compiledChildren) => `${wrapGroup(compiledChildren)}+`,
21+
optionally: (compiledChildren: string) => `${wrapGroup(compiledChildren)}?`,
22+
} satisfies CompilerMap;

Diff for: src/types-internal.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Compilation
2+
export type ComponentCompiler = (compiledChildren: string) => string;
3+
export type CompilerMap = Record<string, ComponentCompiler>;

Diff for: src/types.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export type RegexComponent = string | RegexQuantifier;
2+
3+
export type RegexQuantifier = OneOrMore | Optionally;
4+
5+
// Quantifiers
6+
export type OneOrMore = {
7+
type: 'oneOrMore';
8+
children: RegexComponent[];
9+
};
10+
11+
export type Optionally = {
12+
type: 'optionally';
13+
children: RegexComponent[];
14+
};

Diff for: src/utils.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function wrapGroup(input: string): string {
2+
return input.length === 1 ? input : `(${input})`;
3+
}

0 commit comments

Comments
 (0)