@zokugun/regexp 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ export { escape } from './escape.mjs';
2
+ export { parse } from './parse.mjs';
3
+ export { stringify } from './stringify.mjs';
4
+ export { visit } from './visit.mjs';
5
+ export { transform, type TransformContext } from './transform.mjs';
6
+ export { translate } from './translate.mjs';
7
+ export { TokenType, Flavor, type Token } from './types.mjs';
@@ -0,0 +1,7 @@
1
+ export { escape } from './escape.mjs';
2
+ export { parse } from './parse.mjs';
3
+ export { stringify } from './stringify.mjs';
4
+ export { visit } from './visit.mjs';
5
+ export { transform } from './transform.mjs';
6
+ export { translate } from './translate.mjs';
7
+ export { TokenType, Flavor } from './types.mjs';
@@ -0,0 +1,2 @@
1
+ import { type Token } from './types.mjs';
2
+ export declare function parse(value: string | RegExp): Token;
@@ -0,0 +1,13 @@
1
+ import { isRegExp } from '@zokugun/is-it-type';
2
+ import { pegParse } from './generated/parser.mjs';
3
+ export function parse(value) {
4
+ if (typeof value === 'string') {
5
+ return pegParse(value);
6
+ }
7
+ else if (isRegExp(value)) {
8
+ return pegParse(value.toString());
9
+ }
10
+ else {
11
+ throw new TypeError('The regexp to parse must be represented as a string.');
12
+ }
13
+ }
@@ -0,0 +1,2 @@
1
+ import { type Token } from './types.mjs';
2
+ export declare function stringify(tokens?: Token | Token[] | RegExp): string;
@@ -0,0 +1,225 @@
1
+ import { isRegExp } from '@zokugun/is-it-type';
2
+ import { TokenType } from './types.mjs';
3
+ export function stringify(tokens) {
4
+ if (Array.isArray(tokens)) {
5
+ let result = '';
6
+ for (const token of tokens) {
7
+ result += stringify(token);
8
+ }
9
+ return result;
10
+ }
11
+ else if (isRegExp(tokens)) {
12
+ return tokens.toString();
13
+ }
14
+ else if (tokens) {
15
+ return toString(tokens, '');
16
+ }
17
+ else {
18
+ return '';
19
+ }
20
+ }
21
+ function toString(value, result) {
22
+ if (value.type === TokenType.ALTERNATE) {
23
+ for (let i = 0, l = (value.body).length; i < l; i++) {
24
+ if (i !== 0) {
25
+ result += '|';
26
+ }
27
+ result = toString((value.body)[i], result);
28
+ }
29
+ }
30
+ else if (value.type === TokenType.ANY) {
31
+ result += '.';
32
+ }
33
+ else if (value.type === TokenType.BACK_REFERENCE) {
34
+ result += `\\${value.code}`;
35
+ }
36
+ else if (value.type === TokenType.BACKSPACE) {
37
+ result += '\\b';
38
+ }
39
+ else if (value.type === TokenType.BEGIN) {
40
+ result += '^';
41
+ }
42
+ else if (value.type === TokenType.CAPTURE_GROUP) {
43
+ result += '(';
44
+ result = toString(value.body, result);
45
+ result += ')';
46
+ }
47
+ else if (value.type === TokenType.CARRIAGE_RETURN) {
48
+ result += '\\r';
49
+ }
50
+ else if (value.type === TokenType.CHARSET) {
51
+ result += '[';
52
+ if (value.negated) {
53
+ result += '^';
54
+ }
55
+ for (const item of value.body) {
56
+ result = toString(item, result);
57
+ }
58
+ result += ']';
59
+ }
60
+ else if (value.type === TokenType.CONTROL) {
61
+ result += `\\c${value.code}`;
62
+ }
63
+ else if (value.type === TokenType.DIGIT) {
64
+ result += '\\d';
65
+ }
66
+ else if (value.type === TokenType.END) {
67
+ result += '$';
68
+ }
69
+ else if (value.type === TokenType.ESCAPE) {
70
+ result += `\\${value.code}`;
71
+ }
72
+ else if (value.type === TokenType.FORM_FEED) {
73
+ result += '\\f';
74
+ }
75
+ else if (value.type === TokenType.HEX) {
76
+ result += `\\x${value.code}`;
77
+ }
78
+ else if (value.type === TokenType.LINE_FEED) {
79
+ result += '\\n';
80
+ }
81
+ else if (value.type === TokenType.LITERAL) {
82
+ result += value.text;
83
+ }
84
+ else if (value.type === TokenType.MATCH) {
85
+ for (const item of value.body) {
86
+ result = toString(item, result);
87
+ }
88
+ }
89
+ else if (value.type === TokenType.MODIFIED_GROUP) {
90
+ result += '(?';
91
+ result += value.modifiers.positive.join('');
92
+ if (value.modifiers.negative.length > 0) {
93
+ result += `-${value.modifiers.negative.join('')}`;
94
+ }
95
+ result += ':';
96
+ result = toString(value.body, result);
97
+ result += ')';
98
+ }
99
+ else if (value.type === TokenType.MODIFIER) {
100
+ result += '(?';
101
+ result += value.positive.join('');
102
+ if (value.negative.length > 0) {
103
+ result += `-${value.negative.join('')}`;
104
+ }
105
+ result += ')';
106
+ }
107
+ else if (value.type === TokenType.NAMED_BACK_REFERENCE) {
108
+ result += `\\k<${value.name}>`;
109
+ }
110
+ else if (value.type === TokenType.NAMED_GROUP) {
111
+ result += `(?<${value.name}>`;
112
+ result = toString(value.body, result);
113
+ result += ')';
114
+ }
115
+ else if (value.type === TokenType.NEGATIVE_LOOKAHEAD) {
116
+ result += '(?!';
117
+ result = toString(value.body, result);
118
+ result += ')';
119
+ }
120
+ else if (value.type === TokenType.NEGATIVE_LOOKBEHIND) {
121
+ result += '(?<!';
122
+ result = toString(value.body, result);
123
+ result += ')';
124
+ }
125
+ else if (value.type === TokenType.NON_CAPTURE_GROUP) {
126
+ result += '(?:';
127
+ result = toString(value.body, result);
128
+ result += ')';
129
+ }
130
+ else if (value.type === TokenType.NON_DIGIT) {
131
+ result += '\\D';
132
+ }
133
+ else if (value.type === TokenType.NON_UNICODE_PROPERTY) {
134
+ result += `\\P{${value.property}}`;
135
+ }
136
+ else if (value.type === TokenType.NON_WHITE_SPACE) {
137
+ result += '\\S';
138
+ }
139
+ else if (value.type === TokenType.NON_WORD) {
140
+ result += '\\W';
141
+ }
142
+ else if (value.type === TokenType.NON_WORD_BOUNDARY) {
143
+ result += '\\B';
144
+ }
145
+ else if (value.type === TokenType.NUL) {
146
+ result += '\\0';
147
+ }
148
+ else if (value.type === TokenType.OCTAL) {
149
+ result += `\\0${value.code}`;
150
+ }
151
+ else if (value.type === TokenType.PATTERN) {
152
+ result += '/';
153
+ result = toString(value.body, result);
154
+ result += '/';
155
+ if (value.modifiers) {
156
+ result += value.modifiers.positive.join('');
157
+ }
158
+ }
159
+ else if (value.type === TokenType.POSITIVE_LOOKAHEAD) {
160
+ result += '(?=';
161
+ result = toString(value.body, result);
162
+ result += ')';
163
+ }
164
+ else if (value.type === TokenType.POSITIVE_LOOKBEHIND) {
165
+ result += '(?<=';
166
+ result = toString(value.body, result);
167
+ result += ')';
168
+ }
169
+ else if (value.type === TokenType.QUANTIFIED) {
170
+ result = toString(value.body, result);
171
+ result = toString(value.quantifier, result);
172
+ }
173
+ else if (value.type === TokenType.QUANTIFIER) {
174
+ if (value.max === Infinity) {
175
+ if (value.min === 0) {
176
+ result += '*';
177
+ }
178
+ else if (value.min === 1) {
179
+ result += '+';
180
+ }
181
+ else {
182
+ result += `{${value.min},}`;
183
+ }
184
+ }
185
+ else if (value.min === 0 && value.max === 1) {
186
+ result += '?';
187
+ }
188
+ else if (value.min === value.max) {
189
+ result += `{${value.min}}`;
190
+ }
191
+ else {
192
+ result += `{${value.min},${value.max}}`;
193
+ }
194
+ }
195
+ else if (value.type === TokenType.RANGE) {
196
+ result = toString(value.begin, result);
197
+ result += '-';
198
+ result = toString(value.end, result);
199
+ }
200
+ else if (value.type === TokenType.TAB) {
201
+ result += '\\t';
202
+ }
203
+ else if (value.type === TokenType.UNICODE) {
204
+ result += `\\u{${value.code}}`;
205
+ }
206
+ else if (value.type === TokenType.UNICODE_PROPERTY) {
207
+ result += `\\p{${value.property}}`;
208
+ }
209
+ else if (value.type === TokenType.UTF16) {
210
+ result += `\\u${value.code}`;
211
+ }
212
+ else if (value.type === TokenType.VERTICAL_TAB) {
213
+ result += '\\v';
214
+ }
215
+ else if (value.type === TokenType.WHITE_SPACE) {
216
+ result += '\\s';
217
+ }
218
+ else if (value.type === TokenType.WORD) {
219
+ result += '\\w';
220
+ }
221
+ else if (value.type === TokenType.WORD_BOUNDARY) {
222
+ result += '\\b';
223
+ }
224
+ return result;
225
+ }
@@ -0,0 +1,7 @@
1
+ import { type Token, type TokenType, type Transformer } from './types.mjs';
2
+ export type TransformContext = {
3
+ remove(): void;
4
+ replace(token: Token | string | Token[], transform?: boolean): void;
5
+ transform(tokensArg: Token | Token[] | undefined, parentArg: Token | null, keyArg: string | null): void;
6
+ };
7
+ export declare function transform(tokens: Token | Token[] | undefined, callback?: Transformer | Partial<Record<TokenType, Transformer>>): void;
@@ -0,0 +1,116 @@
1
+ import { parse } from './parse.mjs';
2
+ export function transform(tokens, callback) {
3
+ if (typeof callback === 'function') {
4
+ transformFunc(tokens, null, null, callback);
5
+ }
6
+ else if (callback) {
7
+ transformMap(tokens, callback);
8
+ }
9
+ }
10
+ function transformFunc(tokens, parent, key, callback) {
11
+ if (Array.isArray(tokens)) {
12
+ let i = -1;
13
+ let notSkipped = true;
14
+ const that = {
15
+ remove() {
16
+ tokens.splice(i, 1);
17
+ --i;
18
+ notSkipped = false;
19
+ },
20
+ replace(token, transform) {
21
+ let replacement;
22
+ if (typeof token === 'string') {
23
+ replacement = parse(token).body;
24
+ }
25
+ else {
26
+ replacement = token;
27
+ }
28
+ if (Array.isArray(replacement)) {
29
+ tokens.splice(i, 1, ...replacement);
30
+ }
31
+ else {
32
+ tokens.splice(i, 1, replacement);
33
+ }
34
+ if (transform) {
35
+ --i;
36
+ }
37
+ else if (Array.isArray(replacement)) {
38
+ i += replacement.length - 1;
39
+ }
40
+ notSkipped = false;
41
+ },
42
+ transform(tokensArg, parentArg, keyArg) {
43
+ transformFunc(tokensArg, parentArg, keyArg, callback);
44
+ notSkipped = false;
45
+ },
46
+ };
47
+ while (++i < tokens.length) {
48
+ const token = tokens[i];
49
+ callback.call(that, token, parent, key, i);
50
+ if (notSkipped) {
51
+ if ('body' in token && token.body) {
52
+ transformFunc(token.body, token, 'body', callback);
53
+ }
54
+ }
55
+ else {
56
+ notSkipped = true;
57
+ }
58
+ }
59
+ }
60
+ else if (parent) {
61
+ let notSkipped = true;
62
+ const that = {
63
+ remove() {
64
+ if (parent && key) {
65
+ delete parent[key];
66
+ }
67
+ notSkipped = false;
68
+ },
69
+ replace(token, transform) {
70
+ let replacement;
71
+ if (typeof token === 'string') {
72
+ replacement = parse(token).body;
73
+ }
74
+ else {
75
+ replacement = token;
76
+ }
77
+ if (parent && key) {
78
+ parent[key] = replacement;
79
+ }
80
+ if (transform && replacement) {
81
+ transformFunc(replacement, parent, key, callback);
82
+ }
83
+ notSkipped = false;
84
+ },
85
+ transform(tokensArg, parentArg, keyArg) {
86
+ transformFunc(tokensArg, parentArg, keyArg, callback);
87
+ notSkipped = false;
88
+ },
89
+ };
90
+ callback.call(that, tokens, parent, key, null);
91
+ if (notSkipped) {
92
+ const maybeBody = tokens.body;
93
+ if (maybeBody) {
94
+ transformFunc(maybeBody, tokens, 'body', callback);
95
+ }
96
+ }
97
+ else {
98
+ notSkipped = true;
99
+ }
100
+ }
101
+ else {
102
+ callback.call(null, tokens, null, null, null);
103
+ const maybeBody = tokens.body;
104
+ if (maybeBody) {
105
+ transformFunc(maybeBody, tokens, 'body', callback);
106
+ }
107
+ }
108
+ }
109
+ function transformMap(tokens, callbackMap) {
110
+ transformFunc(tokens, null, null, function (token, parent, key, index) {
111
+ const fn = callbackMap[token.type];
112
+ if (fn) {
113
+ fn.call(this, token, parent, key, index);
114
+ }
115
+ });
116
+ }
@@ -0,0 +1,4 @@
1
+ import { Flavor, type Token } from './types.mjs';
2
+ export declare function translate(value: string | RegExp | Token | Token[], target: Flavor, toString?: true): string;
3
+ export declare function translate(value: Token[], target: Flavor, toString: false): Token[];
4
+ export declare function translate(value: string | RegExp | Token, target: Flavor, toString: false): Token;
@@ -0,0 +1,136 @@
1
+ import { isRegExp, isString } from '@zokugun/is-it-type';
2
+ import { parse } from './parse.mjs';
3
+ import { stringify } from './stringify.mjs';
4
+ import { transform } from './transform.mjs';
5
+ import { TokenType, Flavor } from './types.mjs';
6
+ const TRANSLATORS = {
7
+ [Flavor.ES2018]: translateES2018,
8
+ };
9
+ export function translate(value, target, toString = true) {
10
+ const translator = TRANSLATORS[target];
11
+ if (!translator) {
12
+ if (typeof value === 'string') {
13
+ return value;
14
+ }
15
+ if (isRegExp(value)) {
16
+ return value.toString();
17
+ }
18
+ return value;
19
+ }
20
+ let result;
21
+ if (Array.isArray(value)) {
22
+ result = [];
23
+ for (const item of value) {
24
+ result.push(translator(item));
25
+ }
26
+ }
27
+ else if (isRegExp(value) || isString(value)) {
28
+ result = translator(parse(value));
29
+ }
30
+ else {
31
+ result = translator(value);
32
+ }
33
+ if (toString) {
34
+ return stringify(result);
35
+ }
36
+ else {
37
+ return result;
38
+ }
39
+ }
40
+ function translateES2018(ast) {
41
+ const astToken = ast;
42
+ let caseless = false;
43
+ let inCharset = false;
44
+ let sets = null;
45
+ transform(astToken, {
46
+ [TokenType.CHARSET]: function (token) {
47
+ const charset = token;
48
+ inCharset = true;
49
+ sets = {};
50
+ this.transform(charset.body, token, 'body');
51
+ inCharset = false;
52
+ },
53
+ [TokenType.LITERAL]: function (token) {
54
+ const literal = token;
55
+ if (caseless) {
56
+ let text = '';
57
+ let upper;
58
+ let lower;
59
+ let upperLower;
60
+ for (const c of literal.text.split('')) {
61
+ upper = c.toUpperCase();
62
+ lower = c.toLowerCase();
63
+ if (upper === lower) {
64
+ text += upper;
65
+ }
66
+ else {
67
+ upperLower = `${upper}${lower}`;
68
+ if (inCharset) {
69
+ if (!sets[upperLower]) {
70
+ sets[upperLower] = true;
71
+ text += upperLower;
72
+ }
73
+ }
74
+ else {
75
+ text += `[${upperLower}]`;
76
+ }
77
+ }
78
+ }
79
+ if (literal.text !== text) {
80
+ this.replace(text);
81
+ }
82
+ }
83
+ },
84
+ [TokenType.MODIFIED_GROUP]: function (token) {
85
+ const modifier = token;
86
+ if (modifier.modifiers.positive.includes('i')) {
87
+ caseless = true;
88
+ }
89
+ if (modifier.modifiers.negative.includes('i')) {
90
+ caseless = false;
91
+ }
92
+ this.replace({
93
+ type: TokenType.NON_CAPTURE_GROUP,
94
+ body: modifier.body,
95
+ }, true);
96
+ },
97
+ [TokenType.MODIFIER]: function (token) {
98
+ const modifier = token;
99
+ if (modifier.positive.includes('i')) {
100
+ caseless = true;
101
+ }
102
+ if (modifier.negative.includes('i')) {
103
+ caseless = false;
104
+ }
105
+ this.remove();
106
+ },
107
+ [TokenType.RANGE]: function (token) {
108
+ const range = token;
109
+ if (caseless) {
110
+ let beginUpper;
111
+ let beginLower;
112
+ if (range.begin.type === TokenType.LITERAL) {
113
+ beginUpper = range.begin.text.toUpperCase();
114
+ beginLower = range.begin.text.toLowerCase();
115
+ }
116
+ let endUpper;
117
+ let endLower;
118
+ if (range.end.type === TokenType.LITERAL) {
119
+ endUpper = range.end.text.toUpperCase();
120
+ endLower = range.end.text.toLowerCase();
121
+ }
122
+ if (beginUpper && endUpper && beginUpper !== beginLower && (beginUpper.codePointAt(0) - endUpper.codePointAt(0)) === (beginLower.codePointAt(0) - endLower.codePointAt(0))) {
123
+ const range = `${beginUpper}-${endUpper}${beginLower}-${endLower}`;
124
+ if (sets[range]) {
125
+ this.remove();
126
+ }
127
+ else {
128
+ sets[range] = true;
129
+ this.replace(range);
130
+ }
131
+ }
132
+ }
133
+ },
134
+ });
135
+ return astToken;
136
+ }