+47
-18
README.md
+47
-18
README.md
···
10
10
<br />
11
11
</div>
12
12
13
-
Leveraging the power of sticky regexes and Babel code generation, `reghex` allows
13
+
Leveraging the power of sticky regexes and JS code generation, `reghex` allows
14
14
you to code parsers quickly, by surrounding regular expressions with a regex-like
15
15
[DSL](https://en.wikipedia.org/wiki/Domain-specific_language).
16
16
···
30
30
npm install --save reghex
31
31
```
32
32
33
-
##### 2. Add the plugin to your Babel configuration (`.babelrc`, `babel.config.js`, or `package.json:babel`)
33
+
##### 2. Add the plugin to your Babel configuration _(optional)_
34
+
35
+
In your `.babelrc`, `babel.config.js`, or `package.json:babel` add:
34
36
35
37
```json
36
38
{
···
41
43
Alternatively, you can set up [`babel-plugin-macros`](https://github.com/kentcdodds/babel-plugin-macros) and
42
44
import `reghex` from `"reghex/macro"` instead.
43
45
46
+
This step is **optional**. `reghex` can also generate its optimised JS code during runtime.
47
+
This will only incur a tiny parsing cost on initialisation, but due to the JIT of modern
48
+
JS engines there won't be any difference in performance between pre-compiled and compiled
49
+
versions otherwise.
50
+
51
+
Since the `reghex` runtime is rather small, for larger grammars it may even make sense not
52
+
to precompile the matchers at all. For this case you may pass the `{ "codegen": false }`
53
+
option to the Babel plugin, which will minify the `reghex` matcher templates without
54
+
precompiling them.
55
+
44
56
##### 3. Have fun writing parsers!
45
57
46
58
```js
47
-
import match, { parse } from 'reghex';
59
+
import { match, parse } from 'reghex';
48
60
49
61
const name = match('name')`
50
62
${/\w+/}
···
99
111
100
112
## Authoring Guide
101
113
102
-
You can write "matchers" by importing the default import from `reghex` and
114
+
You can write "matchers" by importing the `match` import from `reghex` and
103
115
using it to write a matcher expression.
104
116
105
117
```js
106
-
import match from 'reghex';
118
+
import { match } from 'reghex';
107
119
108
120
const name = match('name')`
109
121
${/\w+/}
110
122
`;
111
123
```
112
124
113
-
As can be seen above, the `match` function, which is what we've called the
114
-
default import, is called with a "node name" and is then called as a tagged
115
-
template. This template is our **parsing definition**.
125
+
As can be seen above, the `match` function, is called with a "node name" and
126
+
is then called as a tagged template. This template is our **parsing definition**.
116
127
117
128
`reghex` functions only with its Babel plugin, which will detect `match('name')`
118
129
and replace the entire tag with a parsing function, which may then look like
···
161
172
Let's extend our original example;
162
173
163
174
```js
164
-
import match from 'reghex';
175
+
import { match } from 'reghex';
165
176
166
177
const name = match('name')`
167
178
${/\w+/}
···
193
204
*/
194
205
```
195
206
207
+
Furthermore, interpolations don't have to just be RegHex matchers. They can
208
+
also be functions returning matchers or completely custom matching functions.
209
+
This is useful when your DSL becomes _self-referential_, i.e. when one matchers
210
+
start referencing each other forming a loop. To fix this we can create a
211
+
function that returns our root matcher:
212
+
213
+
```js
214
+
import { match } from 'reghex';
215
+
216
+
const value = match('value')`
217
+
(${/\w+/} | ${() => root})+
218
+
`;
219
+
220
+
const root = match('root')`
221
+
${/root/}+ ${value}
222
+
`;
223
+
```
224
+
196
225
### Regex-like DSL
197
226
198
227
We've seen in the previous examples that matchers are authored using tagged
···
208
237
in the parsed string. This is just one feature of the regex-like DSL. The
209
238
available operators are the following:
210
239
211
-
| Operator | Example | Description |
212
-
| -------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
213
-
| `?` | `${/1/}?` | An **optional** may be used to make an interpolation optional. This means that the interpolation may or may not match. |
214
-
| `*` | `${/1/}*` | A **star** can be used to match an arbitrary amount of interpolation or none at all. This means that the interpolation may repeat itself or may not be matched at all. |
215
-
| `+` | `${/1/}+` | A **plus** is used like `*` and must match one or more times. When the matcher doesn't match, that's considered a failing case, since the match isn't optional. |
216
-
| `\|` | `${/1/} \| ${/2/}` | An **alternation** can be used to match either one thing or another, falling back when the first interpolation fails. |
217
-
| `()` | `(${/1/} ${/2/})+` | A **group** can be used to apply one of the other operators to an entire group of interpolations. |
240
+
| Operator | Example | Description |
241
+
| -------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
242
+
| `?` | `${/1/}?` | An **optional** may be used to make an interpolation optional. This means that the interpolation may or may not match. |
243
+
| `*` | `${/1/}*` | A **star** can be used to match an arbitrary amount of interpolation or none at all. This means that the interpolation may repeat itself or may not be matched at all. |
244
+
| `+` | `${/1/}+` | A **plus** is used like `*` and must match one or more times. When the matcher doesn't match, that's considered a failing case, since the match isn't optional. |
245
+
| `\|` | `${/1/} \| ${/2/}` | An **alternation** can be used to match either one thing or another, falling back when the first interpolation fails. |
246
+
| `()` | `(${/1/} ${/2/})+` | A **group** can be used to apply one of the other operators to an entire group of interpolations. |
218
247
| `(?: )` | `(?: ${/1/})` | A **non-capturing group** is like a regular group, but the interpolations matched inside it don't appear in the parser's output. |
219
-
| `(?= )` | `(?= ${/1/})` | A **positive lookahead** checks whether interpolations match, and if so continues the matcher without changing the input. If it matches, it's essentially ignored. |
248
+
| `(?= )` | `(?= ${/1/})` | A **positive lookahead** checks whether interpolations match, and if so continues the matcher without changing the input. If it matches, it's essentially ignored. |
220
249
| `(?! )` | `(?! ${/1/})` | A **negative lookahead** checks whether interpolations _don't_ match, and if so continues the matcher without changing the input. If the interpolations do match the matcher is aborted. |
221
250
222
251
We can combine and compose these operators to create more complex matchers.
···
320
349
matched, which would cause other matchers to treat it like a mismatch!
321
350
322
351
```js
323
-
import match, { parse } from 'reghex';
352
+
import { match, parse } from 'reghex';
324
353
325
354
const name = match('name')((x) => {
326
355
return x[0] !== 'tim' ? x : undefined;
+3
-2
package.json
+3
-2
package.json
···
1
1
{
2
2
"name": "reghex",
3
-
"version": "1.0.2",
3
+
"version": "2.0.0-beta.4",
4
4
"description": "The magical sticky regex-based parser generator 🧙",
5
5
"author": "Phil Pluckthun <phil@kitten.sh>",
6
6
"license": "MIT",
···
48
48
"url": "https://github.com/kitten/reghex/issues"
49
49
},
50
50
"devDependencies": {
51
+
"@ampproject/rollup-plugin-closure-compiler": "^0.26.0",
51
52
"@babel/core": "7.9.6",
52
53
"@babel/plugin-transform-modules-commonjs": "^7.9.6",
53
-
"@babel/plugin-transform-object-assign": "^7.8.3",
54
54
"@rollup/plugin-buble": "^0.21.3",
55
55
"@rollup/plugin-commonjs": "^11.1.0",
56
56
"@rollup/plugin-node-resolve": "^7.1.3",
57
+
"@rollup/pluginutils": "^4.1.0",
57
58
"babel-jest": "^26.0.1",
58
59
"babel-plugin-closure-elimination": "^1.3.1",
59
60
"husky": "^4.2.5",
+29
-12
rollup.config.js
+29
-12
rollup.config.js
···
2
2
import resolve from '@rollup/plugin-node-resolve';
3
3
import buble from '@rollup/plugin-buble';
4
4
import babel from 'rollup-plugin-babel';
5
+
import compiler from '@ampproject/rollup-plugin-closure-compiler';
6
+
7
+
import simplifyJSTags from './scripts/simplify-jstags-plugin.js';
5
8
6
9
const plugins = [
7
10
commonjs({
···
18
21
transforms: {
19
22
unicodeRegExp: false,
20
23
dangerousForOf: true,
21
-
dangerousTaggedTemplateString: true,
24
+
templateString: false,
22
25
},
23
-
objectAssign: 'Object.assign',
24
26
exclude: 'node_modules/**',
25
27
}),
26
28
babel({
···
28
30
extensions: ['ts', 'tsx', 'js'],
29
31
exclude: 'node_modules/**',
30
32
presets: [],
31
-
plugins: [
32
-
'@babel/plugin-transform-object-assign',
33
-
'babel-plugin-closure-elimination',
34
-
],
33
+
plugins: ['babel-plugin-closure-elimination'],
35
34
}),
36
35
];
37
36
···
47
46
freeze: false,
48
47
strict: false,
49
48
format,
49
+
plugins: [
50
+
simplifyJSTags(),
51
+
compiler({
52
+
formatting: 'PRETTY_PRINT',
53
+
compilation_level: 'SIMPLE_OPTIMIZATIONS',
54
+
}),
55
+
],
50
56
});
51
57
52
-
export default {
53
-
input: {
54
-
core: './src/core.js',
55
-
babel: './src/babel/plugin.js',
56
-
macro: './src/babel/macro.js',
57
-
},
58
+
const base = {
58
59
onwarn: () => {},
59
60
external: () => false,
60
61
treeshake: {
···
63
64
plugins,
64
65
output: [output('cjs', '.js'), output('esm', '.mjs')],
65
66
};
67
+
68
+
export default [
69
+
{
70
+
...base,
71
+
input: {
72
+
core: './src/core.js',
73
+
},
74
+
},
75
+
{
76
+
...base,
77
+
input: {
78
+
babel: './src/babel/plugin.js',
79
+
macro: './src/babel/macro.js',
80
+
},
81
+
},
82
+
];
+162
-110
src/babel/__snapshots__/plugin.test.js.snap
+162
-110
src/babel/__snapshots__/plugin.test.js.snap
···
8
8
var _node_expression = (0, _reghex._pattern)(1),
9
9
_node_expression2 = (0, _reghex._pattern)(2);
10
10
11
-
const node = function _node(state) {
12
-
var last_index = state.index;
13
-
var match,
14
-
node = [];
11
+
const node = function (state) {
12
+
var index_1 = state.index;
13
+
var node = [];
14
+
var match;
15
15
16
16
if (match = (0, _reghex._exec)(state, _node_expression)) {
17
17
node.push(match);
18
18
} else {
19
-
state.index = last_index;
19
+
state.index = index_1;
20
20
return;
21
21
}
22
22
23
23
if (match = (0, _reghex._exec)(state, _node_expression2)) {
24
24
node.push(match);
25
25
} else {
26
-
state.index = last_index;
26
+
state.index = index_1;
27
27
return;
28
28
}
29
29
30
-
return (0, _reghex.tag)(node, 'node');
30
+
node.tag = 'node';
31
+
return node;
31
32
};"
32
33
`;
33
34
35
+
exports[`works while only minifying 1`] = `
36
+
"import { match } from 'reghex/macro';
37
+
const node = match('node')([\\"\\", \\"+|\\", \\"+(\\", \\"(\\", \\"?\\", \\"))*\\"], 1, 2, 3, 4, 5);"
38
+
`;
39
+
34
40
exports[`works with local recursion 1`] = `
35
-
"import { tag, _exec, _substr, _pattern } from 'reghex';
41
+
"import { match as m, tag, _exec, _pattern } from 'reghex';
42
+
43
+
var _inner_expression = _pattern(/inner/);
36
44
37
-
const inner = function _inner(state) {
38
-
var last_index = state.index;
39
-
var match,
40
-
node = [];
45
+
const inner = function (state) {
46
+
var index_1 = state.index;
47
+
var node = [];
48
+
var match;
41
49
42
-
if (match = _substr(state, \\"inner\\")) {
50
+
if (match = _exec(state, _inner_expression)) {
43
51
node.push(match);
44
52
} else {
45
-
state.index = last_index;
53
+
state.index = index_1;
46
54
return;
47
55
}
48
56
49
-
return tag(node, 'inner');
57
+
node.tag = 'inner';
58
+
return node;
50
59
};
51
60
52
-
const node = function _node(state) {
53
-
var last_index = state.index;
54
-
var match,
55
-
node = [];
61
+
const node = function (state) {
62
+
var index_1 = state.index;
63
+
var node = [];
64
+
var match;
56
65
57
66
if (match = inner(state)) {
58
67
node.push(match);
59
68
} else {
60
-
state.index = last_index;
69
+
state.index = index_1;
61
70
return;
62
71
}
63
72
64
-
return tag(node, 'node');
73
+
node.tag = 'node';
74
+
return node;
65
75
};"
66
76
`;
67
77
68
78
exports[`works with non-capturing groups 1`] = `
69
-
"import { _exec, _substr, _pattern, tag as _tag } from 'reghex';
79
+
"import { match, _exec, _pattern, tag as _tag } from 'reghex';
70
80
71
81
var _node_expression = _pattern(1),
72
82
_node_expression2 = _pattern(2),
73
83
_node_expression3 = _pattern(3);
74
84
75
-
const node = function _node(state) {
76
-
var last_index = state.index;
77
-
var match,
78
-
node = [];
85
+
const node = function (state) {
86
+
var index_1 = state.index;
87
+
var node = [];
88
+
var match;
79
89
80
90
if (match = _exec(state, _node_expression)) {
81
91
node.push(match);
82
92
} else {
83
-
state.index = last_index;
93
+
state.index = index_1;
84
94
return;
85
95
}
86
96
87
-
var length_0 = node.length;
97
+
var length_2 = node.length;
88
98
89
-
alternation_1: {
90
-
block_1: {
91
-
var index_1 = state.index;
99
+
alternation_3: {
100
+
block_3: {
101
+
var index_3 = state.index;
92
102
93
103
if (match = _exec(state, _node_expression2)) {
94
104
node.push(match);
95
105
} else {
96
-
node.length = length_0;
97
-
state.index = index_1;
98
-
break block_1;
106
+
state.index = index_3;
107
+
node.length = length_2;
108
+
break block_3;
99
109
}
100
110
101
-
break alternation_1;
111
+
break alternation_3;
102
112
}
103
113
104
-
loop_1: for (var iter_1 = 0; true; iter_1++) {
105
-
var index_1 = state.index;
114
+
loop_3: for (var count_3 = 0; true; count_3++) {
115
+
var index_3 = state.index;
106
116
107
117
if (!_exec(state, _node_expression3)) {
108
-
if (iter_1) {
109
-
state.index = index_1;
110
-
break loop_1;
111
-
}
118
+
if (count_3) {
119
+
state.index = index_3;
120
+
break loop_3;
121
+
} else {}
112
122
113
-
node.length = length_0;
114
-
state.index = last_index;
123
+
state.index = index_1;
124
+
node.length = length_2;
115
125
return;
116
126
}
117
127
}
118
128
}
119
129
120
-
return _tag(node, 'node');
130
+
node.tag = 'node';
131
+
return node;
132
+
};"
133
+
`;
134
+
135
+
exports[`works with self-referential thunks 1`] = `
136
+
"import { match, tag, _exec, _pattern } from 'reghex';
137
+
138
+
const inner = function (state) {
139
+
var index_1 = state.index;
140
+
var node = [];
141
+
var match;
142
+
143
+
if (match = node(state)) {
144
+
node.push(match);
145
+
} else {
146
+
state.index = index_1;
147
+
return;
148
+
}
149
+
150
+
node.tag = 'inner';
151
+
return node;
152
+
};
153
+
154
+
const node = function (state) {
155
+
var index_1 = state.index;
156
+
var node = [];
157
+
var match;
158
+
159
+
if (match = inner(state)) {
160
+
node.push(match);
161
+
} else {
162
+
state.index = index_1;
163
+
return;
164
+
}
165
+
166
+
node.tag = 'node';
167
+
return node;
121
168
};"
122
169
`;
123
170
124
171
exports[`works with standard features 1`] = `
125
-
"import { _exec, _substr, _pattern, tag as _tag } from \\"reghex\\";
172
+
"import { match, _exec, _pattern, tag as _tag } from \\"reghex\\";
126
173
127
174
var _node_expression = _pattern(1),
128
175
_node_expression2 = _pattern(2),
···
130
177
_node_expression4 = _pattern(4),
131
178
_node_expression5 = _pattern(5);
132
179
133
-
const node = function _node(state) {
134
-
var last_index = state.index;
135
-
var match,
136
-
node = [];
180
+
const node = function (state) {
181
+
var index_1 = state.index;
182
+
var node = [];
183
+
var match;
137
184
138
-
block_0: {
139
-
var index_0 = state.index;
185
+
alternation_2: {
186
+
block_2: {
187
+
var index_2 = state.index;
140
188
141
-
loop_0: for (var iter_0 = 0; true; iter_0++) {
142
-
var index_0 = state.index;
189
+
loop_2: for (var count_2 = 0; true; count_2++) {
190
+
var index_2 = state.index;
143
191
144
-
if (match = _exec(state, _node_expression)) {
145
-
node.push(match);
146
-
} else {
147
-
if (iter_0) {
148
-
state.index = index_0;
149
-
break loop_0;
150
-
}
192
+
if (match = _exec(state, _node_expression)) {
193
+
node.push(match);
194
+
} else {
195
+
if (count_2) {
196
+
state.index = index_2;
197
+
break loop_2;
198
+
} else {}
151
199
152
-
state.index = index_0;
153
-
break block_0;
200
+
state.index = index_2;
201
+
break block_2;
202
+
}
154
203
}
204
+
205
+
break alternation_2;
155
206
}
156
207
157
-
return _tag(node, 'node');
158
-
}
208
+
loop_2: for (var count_2 = 0; true; count_2++) {
209
+
var index_2 = state.index;
159
210
160
-
loop_0: for (var iter_0 = 0; true; iter_0++) {
161
-
var index_0 = state.index;
211
+
if (match = _exec(state, _node_expression2)) {
212
+
node.push(match);
213
+
} else {
214
+
if (count_2) {
215
+
state.index = index_2;
216
+
break loop_2;
217
+
} else {}
162
218
163
-
if (match = _exec(state, _node_expression2)) {
164
-
node.push(match);
165
-
} else {
166
-
if (iter_0) {
167
-
state.index = index_0;
168
-
break loop_0;
219
+
state.index = index_1;
220
+
return;
169
221
}
170
-
171
-
state.index = last_index;
172
-
return;
173
222
}
174
-
}
175
223
176
-
loop_0: while (true) {
177
-
var index_0 = state.index;
178
-
var length_0 = node.length;
224
+
loop_2: while (true) {
225
+
var index_2 = state.index;
226
+
var length_2 = node.length;
179
227
180
-
if (match = _exec(state, _node_expression3)) {
181
-
node.push(match);
182
-
} else {
183
-
node.length = length_0;
184
-
state.index = index_0;
185
-
break loop_0;
186
-
}
228
+
if (match = _exec(state, _node_expression3)) {
229
+
node.push(match);
230
+
} else {
231
+
state.index = index_2;
232
+
node.length = length_2;
233
+
break loop_2;
234
+
}
187
235
188
-
var index_2 = state.index;
236
+
var index_4 = state.index;
189
237
190
-
if (match = _exec(state, _node_expression4)) {
191
-
node.push(match);
192
-
} else {
193
-
state.index = index_2;
194
-
}
238
+
if (match = _exec(state, _node_expression4)) {
239
+
node.push(match);
240
+
} else {
241
+
state.index = index_4;
242
+
}
195
243
196
-
if (match = _exec(state, _node_expression5)) {
197
-
node.push(match);
198
-
} else {
199
-
node.length = length_0;
200
-
state.index = index_0;
201
-
break loop_0;
244
+
if (match = _exec(state, _node_expression5)) {
245
+
node.push(match);
246
+
} else {
247
+
state.index = index_2;
248
+
node.length = length_2;
249
+
break loop_2;
250
+
}
202
251
}
203
252
}
204
253
205
-
return _tag(node, 'node');
254
+
node.tag = 'node';
255
+
return node;
206
256
};"
207
257
`;
208
258
209
259
exports[`works with transform functions 1`] = `
210
-
"import { _exec, _substr, _pattern, tag as _tag } from 'reghex';
260
+
"import { match, _exec, _pattern, tag as _tag } from 'reghex';
211
261
212
262
var _inner_transform = x => x;
213
263
214
-
const first = function _inner(state) {
215
-
var last_index = state.index;
216
-
var match,
217
-
node = [];
218
-
return _inner_transform(_tag(node, 'inner'));
264
+
const first = function (state) {
265
+
var index_1 = state.index;
266
+
var node = [];
267
+
var match;
268
+
node.tag = 'inner';
269
+
return _inner_transform(node);
219
270
};
220
271
221
272
const transform = x => x;
222
273
223
-
const second = function _node(state) {
224
-
var last_index = state.index;
225
-
var match,
226
-
node = [];
227
-
return transform(_tag(node, 'node'));
274
+
const second = function (state) {
275
+
var index_1 = state.index;
276
+
var node = [];
277
+
var match;
278
+
node.tag = 'node';
279
+
return transform(node);
228
280
};"
229
281
`;
+3
-40
src/babel/__tests__/suite.js
src/core.test.js
+3
-40
src/babel/__tests__/suite.js
src/core.test.js
···
1
-
import * as reghex from '../../..';
2
-
import * as types from '@babel/types';
3
-
import { transform } from '@babel/core';
4
-
import { makeHelpers } from '../transform';
5
-
6
-
const match = (name) => (quasis, ...expressions) => {
7
-
const helpers = makeHelpers(types);
8
-
9
-
let str = '';
10
-
for (let i = 0; i < quasis.length; i++) {
11
-
str += quasis[i];
12
-
if (i < expressions.length) str += '${' + expressions[i].toString() + '}';
13
-
}
14
-
15
-
const template = `(function () { return match('${name}')\`${str}\`; })()`;
16
-
17
-
const testPlugin = () => ({
18
-
visitor: {
19
-
TaggedTemplateExpression(path) {
20
-
helpers.transformMatch(path);
21
-
},
22
-
},
23
-
});
24
-
25
-
const { code } = transform(template, {
26
-
babelrc: false,
27
-
presets: [],
28
-
plugins: [testPlugin],
29
-
});
30
-
31
-
const argKeys = Object.keys(reghex).filter((x) => {
32
-
return x.startsWith('_') || x === 'tag';
33
-
});
34
-
35
-
const args = argKeys.map((key) => reghex[key]);
36
-
return new Function(...argKeys, 'return ' + code)(...args);
37
-
};
1
+
import { match } from './core';
38
2
39
3
const expectToParse = (node, input, result, lastIndex = 0) => {
40
4
const state = { input, index: 0 };
41
-
expect(node(state)).toEqual(
42
-
result === undefined ? result : reghex.tag(result, 'node')
43
-
);
5
+
if (result) result.tag = 'node';
6
+
expect(node(state)).toEqual(result);
44
7
45
8
// NOTE: After parsing we expect the current index to exactly match the
46
9
// sum amount of matched characters
-411
src/babel/generator.js
-411
src/babel/generator.js
···
1
-
let t;
2
-
let ids = {};
3
-
4
-
export function initGenerator(_ids, _t) {
5
-
ids = _ids;
6
-
t = _t;
7
-
}
8
-
9
-
/** var id = state.index; */
10
-
class AssignIndexNode {
11
-
constructor(id) {
12
-
this.id = id;
13
-
}
14
-
15
-
statement() {
16
-
const member = t.memberExpression(ids.state, t.identifier('index'));
17
-
return t.variableDeclaration('var', [
18
-
t.variableDeclarator(this.id, member),
19
-
]);
20
-
}
21
-
}
22
-
23
-
/** state.index = id; */
24
-
class RestoreIndexNode {
25
-
constructor(id) {
26
-
this.id = id;
27
-
}
28
-
29
-
statement() {
30
-
const expression = t.assignmentExpression(
31
-
'=',
32
-
t.memberExpression(ids.state, t.identifier('index')),
33
-
this.id
34
-
);
35
-
36
-
return t.expressionStatement(expression);
37
-
}
38
-
}
39
-
40
-
/** var id = node.length; */
41
-
class AssignLengthNode {
42
-
constructor(id) {
43
-
this.id = id;
44
-
}
45
-
46
-
statement() {
47
-
return t.variableDeclaration('var', [
48
-
t.variableDeclarator(
49
-
this.id,
50
-
t.memberExpression(ids.node, t.identifier('length'))
51
-
),
52
-
]);
53
-
}
54
-
}
55
-
56
-
/** node.length = id; */
57
-
class RestoreLengthNode {
58
-
constructor(id) {
59
-
this.id = id;
60
-
}
61
-
62
-
statement() {
63
-
const expression = t.assignmentExpression(
64
-
'=',
65
-
t.memberExpression(ids.node, t.identifier('length')),
66
-
this.id
67
-
);
68
-
69
-
return t.expressionStatement(expression);
70
-
}
71
-
}
72
-
73
-
/** return; break id; */
74
-
class AbortNode {
75
-
constructor(id) {
76
-
this.id = id || null;
77
-
}
78
-
79
-
statement() {
80
-
const statement = this.id ? t.breakStatement(this.id) : t.returnStatement();
81
-
return statement;
82
-
}
83
-
}
84
-
85
-
/** if (condition) { return; break id; } */
86
-
class AbortConditionNode {
87
-
constructor(condition, opts) {
88
-
this.condition = condition || null;
89
-
90
-
this.abort = opts.abort;
91
-
this.abortCondition = opts.abortCondition || null;
92
-
this.restoreIndex = opts.restoreIndex;
93
-
}
94
-
95
-
statement() {
96
-
return t.ifStatement(
97
-
this.condition,
98
-
t.blockStatement(
99
-
[this.restoreIndex.statement(), this.abort.statement()].filter(Boolean)
100
-
),
101
-
this.abortCondition ? this.abortCondition.statement() : null
102
-
);
103
-
}
104
-
}
105
-
106
-
/** Generates a full matcher for an expression */
107
-
class ExpressionNode {
108
-
constructor(ast, depth, opts) {
109
-
this.ast = ast;
110
-
this.depth = depth || 0;
111
-
this.capturing = !!opts.capturing;
112
-
this.restoreIndex = opts.restoreIndex;
113
-
this.restoreLength = opts.restoreLength || null;
114
-
this.abortCondition = opts.abortCondition || null;
115
-
this.abort = opts.abort || null;
116
-
}
117
-
118
-
statements() {
119
-
const execMatch = this.ast.expression;
120
-
const assignMatch = t.assignmentExpression('=', ids.match, execMatch);
121
-
122
-
const successNodes = t.blockStatement([
123
-
t.expressionStatement(
124
-
t.callExpression(t.memberExpression(ids.node, t.identifier('push')), [
125
-
ids.match,
126
-
])
127
-
),
128
-
]);
129
-
130
-
const abortNodes = t.blockStatement(
131
-
[
132
-
this.abortCondition && this.abortCondition.statement(),
133
-
this.abort && this.restoreLength && this.restoreLength.statement(),
134
-
this.restoreIndex && this.restoreIndex.statement(),
135
-
this.abort && this.abort.statement(),
136
-
].filter(Boolean)
137
-
);
138
-
139
-
return [
140
-
!this.capturing
141
-
? t.ifStatement(t.unaryExpression('!', execMatch), abortNodes)
142
-
: t.ifStatement(assignMatch, successNodes, abortNodes),
143
-
];
144
-
}
145
-
}
146
-
147
-
/** Generates a full matcher for a group */
148
-
class GroupNode {
149
-
constructor(ast, depth, opts) {
150
-
this.ast = ast;
151
-
this.depth = depth || 0;
152
-
if (ast.sequence.length === 1) {
153
-
return new ExpressionNode(ast.sequence[0], depth, opts);
154
-
}
155
-
156
-
const lengthId = t.identifier(`length_${depth}`);
157
-
const childOpts = {
158
-
...opts,
159
-
capturing: !!opts.capturing && !!ast.capturing,
160
-
};
161
-
162
-
this.assignLength = null;
163
-
if (!childOpts.restoreLength && childOpts.capturing) {
164
-
this.assignLength = new AssignLengthNode(lengthId);
165
-
childOpts.restoreLength = new RestoreLengthNode(lengthId);
166
-
}
167
-
168
-
this.alternation = new AlternationNode(ast.sequence, depth + 1, childOpts);
169
-
}
170
-
171
-
statements() {
172
-
return [
173
-
this.assignLength && this.assignLength.statement(),
174
-
...this.alternation.statements(),
175
-
].filter(Boolean);
176
-
}
177
-
}
178
-
179
-
/** Generates looping logic around another group or expression matcher */
180
-
class QuantifierNode {
181
-
constructor(ast, depth, opts) {
182
-
const { quantifier } = ast;
183
-
this.ast = ast;
184
-
this.depth = depth || 0;
185
-
186
-
const invertId = t.identifier(`invert_${this.depth}`);
187
-
const loopId = t.identifier(`loop_${this.depth}`);
188
-
const iterId = t.identifier(`iter_${this.depth}`);
189
-
const indexId = t.identifier(`index_${this.depth}`);
190
-
const ChildNode = ast.type === 'group' ? GroupNode : ExpressionNode;
191
-
const childOpts = { ...opts };
192
-
193
-
this.assignIndex = null;
194
-
this.restoreIndex = null;
195
-
this.blockId = null;
196
-
this.abort = null;
197
-
198
-
if (ast.type === 'group' && !!ast.lookahead) {
199
-
this.restoreIndex = new RestoreIndexNode(indexId);
200
-
this.assignIndex = new AssignIndexNode(indexId);
201
-
}
202
-
203
-
if (ast.type === 'group' && ast.lookahead === 'negative') {
204
-
childOpts.abort = new AbortNode(invertId);
205
-
childOpts.restoreIndex = this.restoreIndex;
206
-
this.restoreIndex = opts.restoreIndex;
207
-
this.blockId = invertId;
208
-
this.abort = opts.abort;
209
-
}
210
-
211
-
if (quantifier && !quantifier.singular && quantifier.required) {
212
-
childOpts.abortCondition = new AbortConditionNode(iterId, {
213
-
...opts,
214
-
restoreIndex: new RestoreIndexNode(indexId),
215
-
abort: new AbortNode(loopId),
216
-
});
217
-
} else if (quantifier && !quantifier.singular) {
218
-
childOpts.restoreLength = null;
219
-
childOpts.restoreIndex = new RestoreIndexNode(indexId);
220
-
childOpts.abort = new AbortNode(loopId);
221
-
childOpts.abortCondition = null;
222
-
} else if (quantifier && !quantifier.required) {
223
-
childOpts.restoreIndex = new RestoreIndexNode(indexId);
224
-
childOpts.abortCondition = null;
225
-
childOpts.abort = null;
226
-
}
227
-
228
-
this.childNode = new ChildNode(ast, depth, childOpts);
229
-
}
230
-
231
-
statements() {
232
-
const { quantifier } = this.ast;
233
-
const loopId = t.identifier(`loop_${this.depth}`);
234
-
const iterId = t.identifier(`iter_${this.depth}`);
235
-
const indexId = t.identifier(`index_${this.depth}`);
236
-
const assignIndex = new AssignIndexNode(indexId);
237
-
238
-
let statements;
239
-
if (quantifier && !quantifier.singular && quantifier.required) {
240
-
statements = [
241
-
t.labeledStatement(
242
-
loopId,
243
-
t.forStatement(
244
-
t.variableDeclaration('var', [
245
-
t.variableDeclarator(iterId, t.numericLiteral(0)),
246
-
]),
247
-
t.booleanLiteral(true),
248
-
t.updateExpression('++', iterId),
249
-
t.blockStatement([
250
-
assignIndex.statement(),
251
-
...this.childNode.statements(),
252
-
])
253
-
)
254
-
),
255
-
];
256
-
} else if (quantifier && !quantifier.singular) {
257
-
statements = [
258
-
t.labeledStatement(
259
-
loopId,
260
-
t.whileStatement(
261
-
t.booleanLiteral(true),
262
-
t.blockStatement([
263
-
assignIndex.statement(),
264
-
...this.childNode.statements(),
265
-
])
266
-
)
267
-
),
268
-
];
269
-
} else if (quantifier && !quantifier.required) {
270
-
statements = [assignIndex.statement(), ...this.childNode.statements()];
271
-
} else {
272
-
statements = this.childNode.statements();
273
-
}
274
-
275
-
if (this.blockId && this.assignIndex && this.restoreIndex) {
276
-
statements = [
277
-
t.labeledStatement(
278
-
this.blockId,
279
-
t.blockStatement(
280
-
[
281
-
this.assignIndex.statement(),
282
-
...statements,
283
-
this.restoreIndex.statement(),
284
-
this.abort.statement(),
285
-
].filter(Boolean)
286
-
)
287
-
),
288
-
].filter(Boolean);
289
-
} else if (this.assignIndex && this.restoreIndex) {
290
-
statements.unshift(this.assignIndex.statement());
291
-
statements.push(this.restoreIndex.statement());
292
-
}
293
-
294
-
return statements;
295
-
}
296
-
}
297
-
298
-
/** Generates a matcher of a sequence of sub-matchers for a single sequence */
299
-
class SequenceNode {
300
-
constructor(ast, depth, opts) {
301
-
this.ast = ast;
302
-
this.depth = depth || 0;
303
-
304
-
const indexId = t.identifier(`index_${depth}`);
305
-
const blockId = t.identifier(`block_${this.depth}`);
306
-
307
-
this.returnStatement = opts.returnStatement;
308
-
this.assignIndex = ast.alternation ? new AssignIndexNode(indexId) : null;
309
-
310
-
this.quantifiers = ast.sequence.map((childAst) => {
311
-
return new QuantifierNode(childAst, depth, {
312
-
...opts,
313
-
restoreIndex: ast.alternation
314
-
? new RestoreIndexNode(indexId)
315
-
: opts.restoreIndex,
316
-
abortCondition: ast.alternation ? null : opts.abortCondition,
317
-
abort: ast.alternation ? new AbortNode(blockId) : opts.abort,
318
-
});
319
-
});
320
-
}
321
-
322
-
statements() {
323
-
const blockId = t.identifier(`block_${this.depth}`);
324
-
const alternationId = t.identifier(`alternation_${this.depth}`);
325
-
const statements = this.quantifiers.reduce((block, node) => {
326
-
block.push(...node.statements());
327
-
return block;
328
-
}, []);
329
-
330
-
if (!this.ast.alternation) {
331
-
return statements;
332
-
}
333
-
334
-
const abortNode =
335
-
this.depth === 0 ? this.returnStatement : t.breakStatement(alternationId);
336
-
337
-
return [
338
-
t.labeledStatement(
339
-
blockId,
340
-
t.blockStatement([
341
-
this.assignIndex && this.assignIndex.statement(),
342
-
...statements,
343
-
abortNode,
344
-
])
345
-
),
346
-
];
347
-
}
348
-
}
349
-
350
-
/** Generates matchers for sequences with (or without) alternations */
351
-
class AlternationNode {
352
-
constructor(ast, depth, opts) {
353
-
this.ast = ast;
354
-
this.depth = depth || 0;
355
-
this.sequences = [];
356
-
for (let current = ast; current; current = current.alternation) {
357
-
this.sequences.push(new SequenceNode(current, depth, opts));
358
-
}
359
-
}
360
-
361
-
statements() {
362
-
if (this.sequences.length === 1) {
363
-
return this.sequences[0].statements();
364
-
}
365
-
366
-
const statements = [];
367
-
for (let i = 0; i < this.sequences.length; i++) {
368
-
statements.push(...this.sequences[i].statements());
369
-
}
370
-
371
-
if (this.depth === 0) {
372
-
return statements;
373
-
}
374
-
375
-
const alternationId = t.identifier(`alternation_${this.depth}`);
376
-
return [t.labeledStatement(alternationId, t.blockStatement(statements))];
377
-
}
378
-
}
379
-
380
-
export class RootNode {
381
-
constructor(ast, nameNode, transformNode) {
382
-
const indexId = t.identifier('last_index');
383
-
const node = t.callExpression(ids.tag, [ids.node, nameNode]);
384
-
385
-
this.returnStatement = t.returnStatement(
386
-
transformNode ? t.callExpression(transformNode, [node]) : node
387
-
);
388
-
389
-
this.assignIndex = new AssignIndexNode(indexId);
390
-
this.node = new AlternationNode(ast, 0, {
391
-
returnStatement: this.returnStatement,
392
-
restoreIndex: new RestoreIndexNode(indexId, true),
393
-
restoreLength: null,
394
-
abortCondition: null,
395
-
abort: new AbortNode(),
396
-
capturing: true,
397
-
});
398
-
}
399
-
400
-
statements() {
401
-
return [
402
-
this.assignIndex.statement(),
403
-
t.variableDeclaration('var', [
404
-
t.variableDeclarator(ids.match),
405
-
t.variableDeclarator(ids.node, t.arrayExpression()),
406
-
]),
407
-
...this.node.statements(),
408
-
this.returnStatement,
409
-
];
410
-
}
411
-
}
+2
-2
src/babel/macro.js
+2
-2
src/babel/macro.js
···
1
1
import { createMacro } from 'babel-plugin-macros';
2
2
import { makeHelpers } from './transform';
3
3
4
-
function reghexMacro({ references, babel: { types: t } }) {
5
-
const helpers = makeHelpers(t);
4
+
function reghexMacro({ references, babel }) {
5
+
const helpers = makeHelpers(babel);
6
6
const defaultRefs = references.default || [];
7
7
8
8
defaultRefs.forEach((ref) => {
+8
-3
src/babel/plugin.js
+8
-3
src/babel/plugin.js
···
1
1
import { makeHelpers } from './transform';
2
2
3
-
export default function reghexPlugin({ types }) {
3
+
export default function reghexPlugin(babel, opts = {}) {
4
4
let helpers;
5
5
6
6
return {
7
7
name: 'reghex',
8
8
visitor: {
9
9
Program() {
10
-
helpers = makeHelpers(types);
10
+
helpers = makeHelpers(babel);
11
11
},
12
12
ImportDeclaration(path) {
13
+
if (opts.codegen === false) return;
13
14
helpers.updateImport(path);
14
15
},
15
16
TaggedTemplateExpression(path) {
16
17
if (helpers.isMatch(path) && helpers.getMatchImport(path)) {
17
-
helpers.transformMatch(path);
18
+
if (opts.codegen === false) {
19
+
helpers.minifyMatch(path);
20
+
} else {
21
+
helpers.transformMatch(path);
22
+
}
18
23
}
19
24
},
20
25
},
+44
-7
src/babel/plugin.test.js
+44
-7
src/babel/plugin.test.js
···
3
3
4
4
it('works with standard features', () => {
5
5
const code = `
6
-
import match from 'reghex/macro';
6
+
import { match } from 'reghex/macro';
7
7
8
8
const node = match('node')\`
9
9
\${1}+ | \${2}+ (\${3} ( \${4}? \${5} ) )*
···
16
16
).toMatchSnapshot();
17
17
});
18
18
19
+
it('works while only minifying', () => {
20
+
const code = `
21
+
import { match } from 'reghex/macro';
22
+
23
+
const node = match('node')\`
24
+
\${1}+ | \${2}+ (\${3} ( \${4}? \${5} ) )*
25
+
\`;
26
+
`;
27
+
28
+
expect(
29
+
transform(code, {
30
+
babelrc: false,
31
+
presets: [],
32
+
plugins: [[reghexPlugin, { codegen: false }]],
33
+
}).code
34
+
).toMatchSnapshot();
35
+
});
36
+
19
37
it('works with local recursion', () => {
20
38
// NOTE: A different default name is allowed
21
39
const code = `
22
-
import match_rec, { tag } from 'reghex';
40
+
import { match as m, tag } from 'reghex';
23
41
24
-
const inner = match_rec('inner')\`
42
+
const inner = m('inner')\`
25
43
\${/inner/}
26
44
\`;
27
45
28
-
const node = match_rec('node')\`
46
+
const node = m('node')\`
47
+
\${inner}
48
+
\`;
49
+
`;
50
+
51
+
expect(
52
+
transform(code, { babelrc: false, presets: [], plugins: [reghexPlugin] })
53
+
.code
54
+
).toMatchSnapshot();
55
+
});
56
+
57
+
it('works with self-referential thunks', () => {
58
+
const code = `
59
+
import { match, tag } from 'reghex';
60
+
61
+
const inner = match('inner')\`
62
+
\${() => node}
63
+
\`;
64
+
65
+
const node = match('node')\`
29
66
\${inner}
30
67
\`;
31
68
`;
···
38
75
39
76
it('works with transform functions', () => {
40
77
const code = `
41
-
import match from 'reghex';
78
+
import { match } from 'reghex';
42
79
43
80
const first = match('inner', x => x)\`\`;
44
81
···
54
91
55
92
it('works with non-capturing groups', () => {
56
93
const code = `
57
-
import match from 'reghex';
94
+
import { match } from 'reghex';
58
95
59
96
const node = match('node')\`
60
97
\${1} (\${2} | (?: \${3})+)
···
69
106
70
107
it('works together with @babel/plugin-transform-modules-commonjs', () => {
71
108
const code = `
72
-
import match from 'reghex';
109
+
import { match } from 'reghex';
73
110
74
111
const node = match('node')\`
75
112
\${1} \${2}
+58
-48
src/babel/transform.js
+58
-48
src/babel/transform.js
···
1
1
import { parse } from '../parser';
2
+
import { astRoot } from '../codegen';
2
3
import { SharedIds } from './sharedIds';
3
-
import { initGenerator, RootNode } from './generator';
4
4
5
-
export function makeHelpers(t) {
5
+
export function makeHelpers({ types: t, template }) {
6
6
const regexPatternsRe = /^[()\[\]|.+?*]|[^\\][()\[\]|.+?*$^]|\\[wdsWDS]/;
7
7
const importSourceRe = /reghex$|^reghex\/macro/;
8
8
const importName = 'reghex';
9
9
const ids = new SharedIds(t);
10
-
initGenerator(ids, t);
11
10
12
11
let _hasUpdatedImport = false;
13
12
···
18
17
if (!importSourceRe.test(path.node.source.value)) return;
19
18
_hasUpdatedImport = true;
20
19
21
-
const defaultSpecifierIndex = path.node.specifiers.findIndex((node) => {
22
-
return t.isImportDefaultSpecifier(node);
23
-
});
24
-
25
-
if (defaultSpecifierIndex > -1) {
26
-
path.node.specifiers.splice(defaultSpecifierIndex, 1);
27
-
}
28
-
29
20
if (path.node.source.value !== importName) {
30
21
path.node.source = t.stringLiteral(importName);
31
22
}
···
36
27
t.identifier('_exec')
37
28
),
38
29
t.importSpecifier(
39
-
(ids.substrId = path.scope.generateUidIdentifier('substr')),
40
-
t.identifier('_substr')
41
-
),
42
-
t.importSpecifier(
43
30
(ids.patternId = path.scope.generateUidIdentifier('pattern')),
44
31
t.identifier('_pattern')
45
32
)
···
48
35
const tagImport = path.node.specifiers.find((node) => {
49
36
return t.isImportSpecifier(node) && node.imported.name === 'tag';
50
37
});
38
+
51
39
if (!tagImport) {
52
40
path.node.specifiers.push(
53
41
t.importSpecifier(
···
87
75
binding.kind !== 'module' ||
88
76
!t.isImportDeclaration(binding.path.parent) ||
89
77
!importSourceRe.test(binding.path.parent.source.value) ||
90
-
!t.isImportDefaultSpecifier(binding.path.node)
78
+
!t.isImportSpecifier(binding.path.node)
91
79
) {
92
80
return null;
93
81
}
···
119
107
const hoistedExpressions = path.node.quasi.expressions.map(
120
108
(expression, i) => {
121
109
if (
110
+
t.isArrowFunctionExpression(expression) &&
111
+
t.isIdentifier(expression.body)
112
+
) {
113
+
expression = expression.body;
114
+
} else if (
115
+
(t.isFunctionExpression(expression) ||
116
+
t.isArrowFunctionExpression(expression)) &&
117
+
t.isBlockStatement(expression.body) &&
118
+
expression.body.body.length === 1 &&
119
+
t.isReturnStatement(expression.body.body[0]) &&
120
+
t.isIdentifier(expression.body.body[0].argument)
121
+
) {
122
+
expression = expression.body.body[0].argument;
123
+
}
124
+
125
+
if (
122
126
t.isIdentifier(expression) &&
123
127
path.scope.hasBinding(expression.name)
124
128
) {
···
127
131
const matchPath = binding.path.get('init');
128
132
if (this.isMatch(matchPath)) return expression;
129
133
}
130
-
} else if (
131
-
t.isRegExpLiteral(expression) &&
132
-
!regexPatternsRe.test(expression.pattern)
133
-
) {
134
-
// NOTE: This is an optimisation path, where the pattern regex is inlined
135
-
// and has determined to be "simple" enough to be turned into a string
136
-
return t.stringLiteral(
137
-
expression.pattern.replace(/\\./g, (x) => x[1])
138
-
);
139
134
}
140
135
141
136
const id = path.scope.generateUidIdentifier(
···
160
155
}
161
156
162
157
return hoistedExpressions.map((id) => {
163
-
// Use _substr helper instead if the expression is a string
164
-
if (t.isStringLiteral(id)) {
165
-
return t.callExpression(ids.substr, [ids.state, id]);
166
-
}
167
-
168
-
// Directly call expression if it's sure to be another matcher
169
158
const binding = path.scope.getBinding(id.name);
170
159
if (binding && t.isVariableDeclarator(binding.path.node)) {
171
160
const matchPath = binding.path.get('init');
172
-
if (this.isMatch(matchPath)) {
173
-
return t.callExpression(id, [ids.state]);
174
-
}
161
+
if (this.isMatch(matchPath)) return `${id.name}(state)`;
175
162
}
176
163
177
-
return t.callExpression(ids.exec, [ids.state, id]);
164
+
const input = t.isStringLiteral(id)
165
+
? JSON.stringify(id.value)
166
+
: id.name;
167
+
return `${ids.exec.name}(state, ${input})`;
178
168
});
179
169
},
180
170
181
171
_prepareTransform(path) {
182
172
const transformNode = path.node.tag.arguments[1];
173
+
183
174
if (!transformNode) return null;
184
-
if (t.isIdentifier(transformNode)) return transformNode;
175
+
if (t.isIdentifier(transformNode)) return transformNode.name;
185
176
186
177
const matchName = this.getMatchName(path);
187
178
const id = path.scope.generateUidIdentifier(`${matchName}_transform`);
···
190
181
path
191
182
.getStatementParent()
192
183
.insertBefore(t.variableDeclaration('var', [declarator]));
193
-
return id;
184
+
185
+
return id.name;
186
+
},
187
+
188
+
minifyMatch(path) {
189
+
if (!path.node.tag.arguments.length) {
190
+
throw path
191
+
.get('tag')
192
+
.buildCodeFrameError(
193
+
'match() must at least be called with a node name'
194
+
);
195
+
}
196
+
197
+
const quasis = path.node.quasi.quasis.map((x) =>
198
+
t.stringLiteral(x.value.cooked.replace(/\s*/g, ''))
199
+
);
200
+
const expressions = path.node.quasi.expressions;
201
+
const transform = this._prepareTransform(path);
202
+
203
+
path.replaceWith(
204
+
t.callExpression(path.node.tag, [
205
+
t.arrayExpression(quasis),
206
+
...expressions,
207
+
])
208
+
);
194
209
},
195
210
196
211
transformMatch(path) {
···
202
217
);
203
218
}
204
219
205
-
const matchName = this.getMatchName(path);
206
-
const nameNode = path.node.tag.arguments[0];
220
+
const name = path.node.tag.arguments[0];
207
221
const quasis = path.node.quasi.quasis.map((x) => x.value.cooked);
208
222
209
223
const expressions = this._prepareExpressions(path);
210
-
const transformNode = this._prepareTransform(path);
224
+
const transform = this._prepareTransform(path);
211
225
212
226
let ast;
213
227
try {
···
217
231
throw path.get('quasi').buildCodeFrameError(error.message);
218
232
}
219
233
220
-
const generator = new RootNode(ast, nameNode, transformNode);
221
-
const body = t.blockStatement(generator.statements());
222
-
const matchFunctionId = path.scope.generateUidIdentifier(matchName);
223
-
const matchFunction = t.functionExpression(
224
-
matchFunctionId,
225
-
[ids.state],
226
-
body
234
+
const code = astRoot(ast, '%%name%%', transform && '%%transform%%');
235
+
236
+
path.replaceWith(
237
+
template.expression(code)(transform ? { name, transform } : { name })
227
238
);
228
-
path.replaceWith(matchFunction);
229
239
},
230
240
};
231
241
}
+252
src/codegen.js
+252
src/codegen.js
···
1
+
const _state = 'state';
2
+
const _match = 'match';
3
+
const _node = 'node';
4
+
5
+
function js(/* arguments */) {
6
+
let body = arguments[0][0];
7
+
for (let i = 1; i < arguments.length; i++)
8
+
body = body + arguments[i] + arguments[0][i];
9
+
return body.trim();
10
+
}
11
+
12
+
const newOpts = (prev, next) => ({
13
+
index: next.index != null ? next.index : prev.index,
14
+
length: next.length != null ? next.length : prev.length,
15
+
onAbort: next.onAbort != null ? next.onAbort : prev.onAbort,
16
+
abort: next.abort != null ? next.abort : prev.abort,
17
+
capture: next.capture != null ? next.capture : prev.capture,
18
+
});
19
+
20
+
const assignIndex = (depth) =>
21
+
depth ? js`var index_${depth} = ${_state}.index;` : '';
22
+
23
+
const restoreIndex = (depth) =>
24
+
depth ? js`${_state}.index = index_${depth};` : '';
25
+
26
+
const abortOnCondition = (condition, hooks) => js`
27
+
if (${condition}) {
28
+
${restoreIndex(opts.index)}
29
+
${opts.abort || ''}
30
+
} else {
31
+
${opts.onAbort || ''}
32
+
}
33
+
`;
34
+
35
+
const astExpression = (ast, depth, opts) => {
36
+
const restoreLength =
37
+
opts.length &&
38
+
opts.abort &&
39
+
js`
40
+
${_node}.length = length_${opts.length};
41
+
`;
42
+
43
+
const abort = js`
44
+
${opts.onAbort || ''}
45
+
${restoreIndex(opts.index)}
46
+
${restoreLength || ''}
47
+
${opts.abort || ''}
48
+
`;
49
+
50
+
if (!opts.capture) {
51
+
return js`
52
+
if (!(${ast.expression})) {
53
+
${abort}
54
+
}
55
+
`;
56
+
}
57
+
58
+
return js`
59
+
if (${_match} = ${ast.expression}) {
60
+
${_node}.push(${_match});
61
+
} else {
62
+
${abort}
63
+
}
64
+
`;
65
+
};
66
+
67
+
const astGroup = (ast, depth, opts) => {
68
+
const capture = !!opts.capture && !ast.capture;
69
+
70
+
let group = '';
71
+
if (!opts.length && capture) {
72
+
return js`
73
+
${js`var length_${depth} = ${_node}.length;`}
74
+
${astSequence(
75
+
ast.sequence,
76
+
depth + 1,
77
+
newOpts(opts, {
78
+
length: depth,
79
+
capture,
80
+
})
81
+
)}
82
+
`;
83
+
}
84
+
85
+
return astSequence(
86
+
ast.sequence,
87
+
depth + 1,
88
+
newOpts(opts, {
89
+
capture,
90
+
})
91
+
);
92
+
};
93
+
94
+
const astChild = (ast, depth, opts) =>
95
+
ast.expression ? astExpression(ast, depth, opts) : astGroup(ast, depth, opts);
96
+
97
+
const astRepeating = (ast, depth, opts) => {
98
+
const label = `loop_${depth}`;
99
+
const count = `count_${depth}`;
100
+
return js`
101
+
${label}: for (var ${count} = 0; true; ${count}++) {
102
+
${assignIndex(depth)}
103
+
${astChild(
104
+
ast,
105
+
depth,
106
+
newOpts(opts, {
107
+
onAbort: js`
108
+
if (${count}) {
109
+
${restoreIndex(depth)}
110
+
break ${label};
111
+
} else {
112
+
${opts.onAbort || ''}
113
+
}
114
+
`,
115
+
})
116
+
)}
117
+
}
118
+
`;
119
+
};
120
+
121
+
const astMultiple = (ast, depth, opts) => {
122
+
const label = `loop_${depth}`;
123
+
return js`
124
+
${label}: while (true) {
125
+
${assignIndex(depth)}
126
+
${astChild(
127
+
ast,
128
+
depth,
129
+
newOpts(opts, {
130
+
length: 0,
131
+
index: depth,
132
+
abort: js`break ${label};`,
133
+
onAbort: '',
134
+
})
135
+
)}
136
+
}
137
+
`;
138
+
};
139
+
140
+
const astOptional = (ast, depth, opts) => js`
141
+
${assignIndex(depth)}
142
+
${astChild(
143
+
ast,
144
+
depth,
145
+
newOpts(opts, {
146
+
index: depth,
147
+
abort: '',
148
+
onAbort: '',
149
+
})
150
+
)}
151
+
`;
152
+
153
+
const astQuantifier = (ast, depth, opts) => {
154
+
const { index, abort } = opts;
155
+
const label = `invert_${depth}`;
156
+
157
+
if (ast.capture === '!') {
158
+
opts = newOpts(opts, {
159
+
index: depth,
160
+
abort: js`break ${label};`,
161
+
});
162
+
}
163
+
164
+
let child;
165
+
if (ast.quantifier === '+') {
166
+
child = astRepeating(ast, depth, opts);
167
+
} else if (ast.quantifier === '*') child = astMultiple(ast, depth, opts);
168
+
else if (ast.quantifier === '?') child = astOptional(ast, depth, opts);
169
+
else child = astChild(ast, depth, opts);
170
+
171
+
if (ast.capture === '!') {
172
+
return js`
173
+
${label}: {
174
+
${assignIndex(depth)}
175
+
${child}
176
+
${restoreIndex(index)}
177
+
${abort}
178
+
}
179
+
`;
180
+
} else if (ast.capture === '=') {
181
+
return js`
182
+
${assignIndex(depth)}
183
+
${child}
184
+
${restoreIndex(depth)}
185
+
`;
186
+
} else {
187
+
return child;
188
+
}
189
+
};
190
+
191
+
const astSequence = (ast, depth, opts) => {
192
+
const alternation = ast.alternation ? `alternation_${depth}` : '';
193
+
194
+
let body = '';
195
+
for (; ast; ast = ast.alternation) {
196
+
const block = `block_${depth}`;
197
+
198
+
let childOpts = opts;
199
+
if (ast.alternation) {
200
+
childOpts = newOpts(opts, {
201
+
index: depth,
202
+
abort: js`break ${block};`,
203
+
onAbort: '',
204
+
});
205
+
}
206
+
207
+
let sequence = '';
208
+
for (let i = 0; i < ast.length; i++)
209
+
sequence += astQuantifier(ast[i], depth, childOpts);
210
+
211
+
if (!ast.alternation) {
212
+
body += sequence;
213
+
} else {
214
+
body += js`
215
+
${block}: {
216
+
${assignIndex(depth)}
217
+
${sequence}
218
+
break ${alternation};
219
+
}
220
+
`;
221
+
}
222
+
}
223
+
224
+
if (!alternation) return body;
225
+
226
+
return js`
227
+
${alternation}: {
228
+
${body}
229
+
}
230
+
`;
231
+
};
232
+
233
+
const astRoot = (ast, name, transform) => js`
234
+
(function (${_state}) {
235
+
${assignIndex(1)}
236
+
var ${_node} = [];
237
+
var ${_match};
238
+
239
+
${astSequence(ast, 2, {
240
+
index: 1,
241
+
length: 0,
242
+
onAbort: '',
243
+
abort: js`return;`,
244
+
capture: true,
245
+
})}
246
+
247
+
${_node}.tag = ${name};
248
+
return ${transform ? js`(${transform})(${_node})` : _node};
249
+
})
250
+
`;
251
+
252
+
export { astRoot };
+29
-31
src/core.js
+29
-31
src/core.js
···
1
+
import { astRoot } from './codegen';
2
+
import { parse as parseDSL } from './parser';
3
+
1
4
const isStickySupported = typeof /./g.sticky === 'boolean';
2
5
3
6
export const _pattern = (input) => {
4
7
if (typeof input === 'function') return input;
5
-
6
8
const source = typeof input !== 'string' ? input.source : input;
7
9
return isStickySupported
8
10
? new RegExp(source, 'y')
9
-
: new RegExp(`^(?:${source})`, 'g');
11
+
: new RegExp(source + '|()', 'g');
10
12
};
11
13
12
-
export const _substr = (state, pattern) => {
13
-
const end = state.index + pattern.length;
14
-
const sub = state.input.slice(state.index, end);
15
-
if (sub === pattern) {
16
-
state.index = end;
17
-
return sub;
14
+
export const _exec = (state, pattern) => {
15
+
let match;
16
+
17
+
if (typeof pattern === 'function') {
18
+
if (!pattern.length) pattern = pattern();
19
+
return pattern(state);
18
20
}
19
-
};
20
21
21
-
export const _exec = (state, pattern) => {
22
-
if (typeof pattern === 'function') return pattern();
22
+
pattern.lastIndex = state.index;
23
23
24
-
let match;
25
24
if (isStickySupported) {
26
-
pattern.lastIndex = state.index;
27
-
if (pattern.test(state.input)) {
25
+
if (pattern.test(state.input))
28
26
match = state.input.slice(state.index, pattern.lastIndex);
29
-
state.index = pattern.lastIndex;
30
-
}
31
27
} else {
32
-
pattern.lastIndex = 0;
33
-
if (pattern.test(state.input.slice(state.index))) {
34
-
const lastIndex = state.index + pattern.lastIndex;
35
-
match = state.input.slice(state.index, lastIndex);
36
-
state.index = lastIndex;
37
-
}
28
+
match = pattern.exec(state.input)[0] || match;
38
29
}
39
30
31
+
state.index = pattern.lastIndex;
40
32
return match;
41
33
};
42
34
43
-
export const tag = (array, tag) => {
44
-
array.tag = tag;
45
-
return array;
46
-
};
47
-
48
35
export const parse = (pattern) => (input) => {
49
36
const state = { input, index: 0 };
50
37
return pattern(state);
51
38
};
52
39
53
-
export const match = (_name) => {
54
-
throw new TypeError(
55
-
'This match() function was not transformed. ' +
56
-
'Ensure that the Babel plugin is set up correctly and try again.'
40
+
export const match = (name, transform) => (quasis, ...expressions) => {
41
+
const ast = parseDSL(
42
+
quasis,
43
+
expressions.map((expression, i) =>
44
+
typeof expression === 'function' && expression.length
45
+
? `_${i}(state)`
46
+
: `_e(state, _${i})`
47
+
)
57
48
);
49
+
50
+
const makeMatcher = new Function(
51
+
'_e,_n,_t,' + expressions.map((_expression, i) => `_${i}`).join(','),
52
+
'return ' + astRoot(ast, '_n', transform ? '_t' : null)
53
+
);
54
+
55
+
return makeMatcher(_exec, name, transform, ...expressions.map(_pattern));
58
56
};
+27
-77
src/parser.js
+27
-77
src/parser.js
···
1
+
const syntaxError = (char) => {
2
+
throw new SyntaxError('Unexpected token "' + char + '"');
3
+
};
4
+
1
5
export const parse = (quasis, expressions) => {
2
6
let quasiIndex = 0;
3
7
let stackIndex = 0;
4
8
5
9
const sequenceStack = [];
6
-
const rootSequence = {
7
-
type: 'sequence',
8
-
sequence: [],
9
-
alternation: null,
10
-
};
10
+
const rootSequence = [];
11
11
12
12
let currentGroup = null;
13
13
let lastMatch;
14
14
let currentSequence = rootSequence;
15
15
16
-
while (stackIndex < quasis.length + expressions.length) {
16
+
for (
17
+
let quasiIndex = 0, stackIndex = 0;
18
+
stackIndex < quasis.length + expressions.length;
19
+
stackIndex++
20
+
) {
17
21
if (stackIndex % 2 !== 0) {
18
-
const expression = expressions[stackIndex++ >> 1];
19
-
20
-
currentSequence.sequence.push({
21
-
type: 'expression',
22
-
expression,
23
-
quantifier: null,
22
+
currentSequence.push({
23
+
expression: expressions[stackIndex++ >> 1],
24
24
});
25
25
}
26
26
27
27
const quasi = quasis[stackIndex >> 1];
28
-
while (quasiIndex < quasi.length) {
28
+
for (quasiIndex = 0; quasiIndex < quasi.length; ) {
29
29
const char = quasi[quasiIndex++];
30
-
31
30
if (char === ' ' || char === '\t' || char === '\r' || char === '\n') {
32
-
continue;
33
-
} else if (char === '|' && currentSequence.sequence.length > 0) {
34
-
currentSequence = currentSequence.alternation = {
35
-
type: 'sequence',
36
-
sequence: [],
37
-
alternation: null,
38
-
};
39
-
40
-
continue;
41
-
} else if (char === ')' && currentSequence.sequence.length > 0) {
31
+
} else if (char === '|' && currentSequence.length) {
32
+
currentSequence = currentSequence.alternation = [];
33
+
} else if (char === ')' && currentSequence.length) {
42
34
currentGroup = null;
43
35
currentSequence = sequenceStack.pop();
44
-
if (currentSequence) continue;
36
+
if (!currentSequence) syntaxError(char);
45
37
} else if (char === '(') {
46
-
currentGroup = {
47
-
type: 'group',
48
-
sequence: {
49
-
type: 'sequence',
50
-
sequence: [],
51
-
alternation: null,
52
-
},
53
-
capturing: true,
54
-
lookahead: null,
55
-
quantifier: null,
56
-
};
57
-
58
38
sequenceStack.push(currentSequence);
59
-
currentSequence.sequence.push(currentGroup);
39
+
currentSequence.push((currentGroup = { sequence: [] }));
60
40
currentSequence = currentGroup.sequence;
61
-
continue;
62
-
} else if (
63
-
char === '?' &&
64
-
currentSequence.sequence.length === 0 &&
65
-
currentGroup
66
-
) {
41
+
} else if (char === '?' && !currentSequence.length && currentGroup) {
67
42
const nextChar = quasi[quasiIndex++];
68
-
if (!nextChar) {
69
-
throw new SyntaxError('Unexpected end of input after ' + char);
70
-
}
71
-
72
-
if (nextChar === ':') {
73
-
currentGroup.capturing = false;
74
-
continue;
75
-
} else if (nextChar === '=') {
76
-
currentGroup.capturing = false;
77
-
currentGroup.lookahead = 'positive';
78
-
continue;
79
-
} else if (nextChar === '!') {
80
-
currentGroup.capturing = false;
81
-
currentGroup.lookahead = 'negative';
82
-
continue;
43
+
if (nextChar === ':' || nextChar === '=' || nextChar === '!') {
44
+
currentGroup.capture = nextChar;
45
+
} else {
46
+
syntaxError(char);
83
47
}
84
48
} else if (
85
49
(char === '?' || char === '+' || char === '*') &&
86
-
(lastMatch =
87
-
currentSequence.sequence[currentSequence.sequence.length - 1])
50
+
(lastMatch = currentSequence[currentSequence.length - 1])
88
51
) {
89
-
if (lastMatch.type === 'group' && lastMatch.lookahead) {
90
-
throw new SyntaxError('Unexpected quantifier on lookahead group');
91
-
}
92
-
93
-
lastMatch.quantifier = {
94
-
type: 'quantifier',
95
-
required: char === '+',
96
-
singular: char === '?',
97
-
};
98
-
99
-
continue;
52
+
lastMatch.quantifier = char;
53
+
} else {
54
+
syntaxError(char);
100
55
}
101
-
102
-
throw new SyntaxError('Unexpected token ' + char);
103
56
}
104
-
105
-
stackIndex++;
106
-
quasiIndex = 0;
107
57
}
108
58
109
59
return rootSequence;
+34
-113
src/parser.test.js
+34
-113
src/parser.test.js
···
2
2
3
3
const parseTag = (quasis, ...expressions) => parse(quasis, expressions);
4
4
5
-
it('supports parsing expressions', () => {
6
-
expect(parseTag`${1}`).toEqual({
7
-
type: 'sequence',
8
-
sequence: [
9
-
{
10
-
type: 'expression',
11
-
expression: 1,
12
-
quantifier: null,
13
-
},
14
-
],
15
-
alternation: null,
16
-
});
17
-
});
18
-
19
5
it('supports parsing expressions with quantifiers', () => {
20
6
let ast;
21
7
22
8
ast = parseTag`${1}?`;
23
-
expect(ast).toHaveProperty('sequence.0.type', 'expression');
24
-
expect(ast).toHaveProperty('sequence.0.quantifier', {
25
-
type: 'quantifier',
26
-
required: false,
27
-
singular: true,
28
-
});
9
+
expect(ast).toHaveProperty('0.quantifier', '?');
29
10
30
11
ast = parseTag`${1}+`;
31
-
expect(ast).toHaveProperty('sequence.0.type', 'expression');
32
-
expect(ast).toHaveProperty('sequence.0.quantifier', {
33
-
type: 'quantifier',
34
-
required: true,
35
-
singular: false,
36
-
});
12
+
expect(ast).toHaveProperty('0.quantifier', '+');
37
13
38
14
ast = parseTag`${1}*`;
39
-
expect(ast).toHaveProperty('sequence.0.type', 'expression');
40
-
expect(ast).toHaveProperty('sequence.0.quantifier', {
41
-
type: 'quantifier',
42
-
required: false,
43
-
singular: false,
44
-
});
15
+
expect(ast).toHaveProperty('0.quantifier', '*');
45
16
});
46
17
47
18
it('supports top-level alternations', () => {
48
19
let ast;
49
20
50
21
ast = parseTag`${1} | ${2}`;
51
-
expect(ast).toHaveProperty('sequence.length', 1);
52
-
expect(ast).toHaveProperty('sequence.0.type', 'expression');
53
-
expect(ast).toHaveProperty('sequence.0.expression', 1);
54
-
expect(ast).toHaveProperty('alternation.type', 'sequence');
55
-
expect(ast).toHaveProperty('alternation.sequence.0.expression', 2);
22
+
expect(ast).toHaveProperty('length', 1);
23
+
expect(ast).toHaveProperty('0.expression', 1);
24
+
expect(ast).toHaveProperty('alternation.0.expression', 2);
56
25
57
26
ast = parseTag`${1}? | ${2}?`;
58
-
expect(ast).toHaveProperty('sequence.0.quantifier.type', 'quantifier');
59
-
expect(ast).toHaveProperty(
60
-
'alternation.sequence.0.quantifier.type',
61
-
'quantifier'
62
-
);
27
+
expect(ast).toHaveProperty('0.quantifier', '?');
63
28
});
64
29
65
30
it('supports groups with quantifiers', () => {
66
31
let ast;
67
32
68
33
ast = parseTag`(${1} ${2})`;
69
-
expect(ast).toHaveProperty('sequence.length', 1);
70
-
expect(ast).toHaveProperty('sequence.0.type', 'group');
71
-
expect(ast).toHaveProperty('sequence.0.sequence.sequence.length', 2);
72
-
expect(ast).toHaveProperty('sequence.0.sequence.sequence.0.expression', 1);
73
-
expect(ast).toHaveProperty('sequence.0.sequence.sequence.1.expression', 2);
34
+
expect(ast).toHaveProperty('length', 1);
35
+
expect(ast).toHaveProperty('0.sequence.length', 2);
36
+
expect(ast).toHaveProperty('0.sequence.0.expression', 1);
37
+
expect(ast).toHaveProperty('0.sequence.1.expression', 2);
74
38
75
39
ast = parseTag`(${1} ${2}?)?`;
76
-
expect(ast).toHaveProperty('sequence.length', 1);
77
-
expect(ast).toHaveProperty('sequence.0.type', 'group');
78
-
expect(ast).toHaveProperty('sequence.0.quantifier.type', 'quantifier');
79
-
expect(ast).toHaveProperty('sequence.0.sequence.sequence.0.quantifier', null);
80
-
expect(ast).toHaveProperty(
81
-
'sequence.0.sequence.sequence.1.quantifier.type',
82
-
'quantifier'
83
-
);
40
+
expect(ast).toHaveProperty('length', 1);
41
+
expect(ast).toHaveProperty('0.quantifier', '?');
42
+
expect(ast).toHaveProperty('0.sequence.0.quantifier', undefined);
84
43
});
85
44
86
45
it('supports non-capturing groups', () => {
87
46
const ast = parseTag`(?: ${1})`;
88
-
expect(ast).toHaveProperty('sequence.length', 1);
89
-
expect(ast).toHaveProperty('sequence.0.type', 'group');
90
-
expect(ast).toHaveProperty('sequence.0.capturing', false);
91
-
expect(ast).toHaveProperty('sequence.0.lookahead', null);
92
-
expect(ast).toHaveProperty('sequence.0.sequence.sequence.length', 1);
47
+
expect(ast).toHaveProperty('length', 1);
48
+
expect(ast).toHaveProperty('0.capture', ':');
49
+
expect(ast).toHaveProperty('0.sequence.length', 1);
93
50
});
94
51
95
52
it('supports positive lookahead groups', () => {
96
53
const ast = parseTag`(?= ${1})`;
97
-
expect(ast).toHaveProperty('sequence.length', 1);
98
-
expect(ast).toHaveProperty('sequence.0.type', 'group');
99
-
expect(ast).toHaveProperty('sequence.0.capturing', false);
100
-
expect(ast).toHaveProperty('sequence.0.lookahead', 'positive');
101
-
expect(ast).toHaveProperty('sequence.0.sequence.sequence.length', 1);
54
+
expect(ast).toHaveProperty('length', 1);
55
+
expect(ast).toHaveProperty('0.capture', '=');
56
+
expect(ast).toHaveProperty('0.sequence.length', 1);
102
57
});
103
58
104
59
it('supports negative lookahead groups', () => {
105
60
const ast = parseTag`(?! ${1})`;
106
-
expect(ast).toHaveProperty('sequence.length', 1);
107
-
expect(ast).toHaveProperty('sequence.0.type', 'group');
108
-
expect(ast).toHaveProperty('sequence.0.capturing', false);
109
-
expect(ast).toHaveProperty('sequence.0.lookahead', 'negative');
110
-
expect(ast).toHaveProperty('sequence.0.sequence.sequence.length', 1);
111
-
});
112
-
113
-
it('throws when a quantifier is combined with a lookahead', () => {
114
-
expect(() => parseTag`(?! ${1})+`).toThrow();
115
-
expect(() => parseTag`(?! ${1})?`).toThrow();
116
-
expect(() => parseTag`(?! ${1})*`).toThrow();
61
+
expect(ast).toHaveProperty('length', 1);
62
+
expect(ast).toHaveProperty('0.capture', '!');
63
+
expect(ast).toHaveProperty('0.sequence.length', 1);
117
64
});
118
65
119
66
it('supports groups with alternates', () => {
120
67
expect(parseTag`(${1} | ${2}) ${3}`).toMatchInlineSnapshot(`
121
-
Object {
122
-
"alternation": null,
123
-
"sequence": Array [
124
-
Object {
125
-
"capturing": true,
126
-
"lookahead": null,
127
-
"quantifier": null,
128
-
"sequence": Object {
129
-
"alternation": Object {
130
-
"alternation": null,
131
-
"sequence": Array [
132
-
Object {
133
-
"expression": 2,
134
-
"quantifier": null,
135
-
"type": "expression",
136
-
},
137
-
],
138
-
"type": "sequence",
139
-
},
140
-
"sequence": Array [
141
-
Object {
142
-
"expression": 1,
143
-
"quantifier": null,
144
-
"type": "expression",
145
-
},
146
-
],
147
-
"type": "sequence",
68
+
Array [
69
+
Object {
70
+
"sequence": Array [
71
+
Object {
72
+
"expression": 1,
148
73
},
149
-
"type": "group",
150
-
},
151
-
Object {
152
-
"expression": 3,
153
-
"quantifier": null,
154
-
"type": "expression",
155
-
},
156
-
],
157
-
"type": "sequence",
158
-
}
74
+
],
75
+
},
76
+
Object {
77
+
"expression": 3,
78
+
},
79
+
]
159
80
`);
160
81
});
+178
-22
yarn.lock
+178
-22
yarn.lock
···
2
2
# yarn lockfile v1
3
3
4
4
5
+
"@ampproject/remapping@0.2.0":
6
+
version "0.2.0"
7
+
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-0.2.0.tgz#07290a5c0f5eac8a4c33d38aa0d15a3416db432e"
8
+
integrity sha512-a4EztS9/GOVQjX5Ol+Iz33TFhaXvYBF7aB6D8+Qz0/SCIxOm3UNRhGZiwcCuJ8/Ifc6NCogp3S48kc5hFxRpUw==
9
+
dependencies:
10
+
"@jridgewell/resolve-uri" "1.0.0"
11
+
sourcemap-codec "1.4.8"
12
+
13
+
"@ampproject/rollup-plugin-closure-compiler@^0.26.0":
14
+
version "0.26.0"
15
+
resolved "https://registry.yarnpkg.com/@ampproject/rollup-plugin-closure-compiler/-/rollup-plugin-closure-compiler-0.26.0.tgz#69f8265e5fdbf3e26905eaaedc60cb5982bd6be0"
16
+
integrity sha512-wuHzGE6BDhDR0L7nUPlpQDPGiGnMw+b0B+cDPG0S5TatOmFNQva8KSNdBHan3L9RbvNyYXOXicuCrZtSoBfrBg==
17
+
dependencies:
18
+
"@ampproject/remapping" "0.2.0"
19
+
acorn "7.2.0"
20
+
acorn-walk "7.1.1"
21
+
estree-walker "2.0.1"
22
+
google-closure-compiler "20200517.0.0"
23
+
magic-string "0.25.7"
24
+
uuid "8.1.0"
25
+
5
26
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3":
6
27
version "7.8.3"
7
28
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
···
229
250
"@babel/helper-simple-access" "^7.8.3"
230
251
babel-plugin-dynamic-import-node "^2.3.3"
231
252
232
-
"@babel/plugin-transform-object-assign@^7.8.3":
233
-
version "7.8.3"
234
-
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.8.3.tgz#dc3b8dd50ef03837868a37b7df791f64f288538e"
235
-
integrity sha512-i3LuN8tPDqUCRFu3dkzF2r1Nx0jp4scxtm7JxtIqI9he9Vk20YD+/zshdzR9JLsoBMlJlNR82a62vQExNEVx/Q==
236
-
dependencies:
237
-
"@babel/helper-plugin-utils" "^7.8.3"
238
-
239
253
"@babel/template@^7.3.3", "@babel/template@^7.8.3", "@babel/template@^7.8.6":
240
254
version "7.8.6"
241
255
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b"
···
463
477
"@types/yargs" "^15.0.0"
464
478
chalk "^4.0.0"
465
479
480
+
"@jridgewell/resolve-uri@1.0.0":
481
+
version "1.0.0"
482
+
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-1.0.0.tgz#3fdf5798f0b49e90155896f6291df186eac06c83"
483
+
integrity sha512-9oLAnygRMi8Q5QkYEU4XWK04B+nuoXoxjRvRxgjuChkLZFBja0YPSgdZ7dZtwhncLBcQe/I/E+fLuk5qxcYVJA==
484
+
466
485
"@rollup/plugin-buble@^0.21.3":
467
486
version "0.21.3"
468
487
resolved "https://registry.yarnpkg.com/@rollup/plugin-buble/-/plugin-buble-0.21.3.tgz#1649a915b1d051a4f430d40e7734a7f67a69b33e"
···
505
524
estree-walker "^1.0.1"
506
525
picomatch "^2.2.2"
507
526
527
+
"@rollup/pluginutils@^4.1.0":
528
+
version "4.1.0"
529
+
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.1.0.tgz#0dcc61c780e39257554feb7f77207dceca13c838"
530
+
integrity sha512-TrBhfJkFxA+ER+ew2U2/fHbebhLT/l/2pRk0hfj9KusXUuRXd2v0R58AfaZK9VXDQ4TogOSEmICVrQAA3zFnHQ==
531
+
dependencies:
532
+
estree-walker "^2.0.1"
533
+
picomatch "^2.2.2"
534
+
508
535
"@samverschueren/stream-to-observable@^0.3.0":
509
536
version "0.3.0"
510
537
resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f"
···
670
697
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe"
671
698
integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==
672
699
673
-
acorn-walk@^7.1.1:
700
+
acorn-walk@7.1.1, acorn-walk@^7.1.1:
674
701
version "7.1.1"
675
702
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.1.1.tgz#345f0dffad5c735e7373d2fec9a1023e6a44b83e"
676
703
integrity sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==
677
704
705
+
acorn@7.2.0, acorn@^7.1.1:
706
+
version "7.2.0"
707
+
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe"
708
+
integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==
709
+
678
710
acorn@^6.4.1:
679
711
version "6.4.1"
680
712
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
681
713
integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==
682
714
683
-
acorn@^7.1.1:
684
-
version "7.2.0"
685
-
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe"
686
-
integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==
687
-
688
715
aggregate-error@^3.0.0:
689
716
version "3.0.1"
690
717
resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0"
···
1028
1055
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
1029
1056
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
1030
1057
1031
-
chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
1058
+
chalk@2.x, chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
1032
1059
version "2.4.2"
1033
1060
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
1034
1061
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
···
1102
1129
strip-ansi "^6.0.0"
1103
1130
wrap-ansi "^6.2.0"
1104
1131
1132
+
clone-buffer@^1.0.0:
1133
+
version "1.0.0"
1134
+
resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
1135
+
integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg=
1136
+
1137
+
clone-stats@^1.0.0:
1138
+
version "1.0.0"
1139
+
resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680"
1140
+
integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=
1141
+
1105
1142
clone@^1.0.2:
1106
1143
version "1.0.4"
1107
1144
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
1108
1145
integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
1109
1146
1147
+
clone@^2.1.1:
1148
+
version "2.1.2"
1149
+
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
1150
+
integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
1151
+
1152
+
cloneable-readable@^1.0.0:
1153
+
version "1.1.3"
1154
+
resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec"
1155
+
integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==
1156
+
dependencies:
1157
+
inherits "^2.0.1"
1158
+
process-nextick-args "^2.0.0"
1159
+
readable-stream "^2.3.5"
1160
+
1110
1161
co@^4.6.0:
1111
1162
version "4.6.0"
1112
1163
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
···
1193
1244
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
1194
1245
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
1195
1246
1196
-
core-util-is@1.0.2:
1247
+
core-util-is@1.0.2, core-util-is@~1.0.0:
1197
1248
version "1.0.2"
1198
1249
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
1199
1250
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
···
1461
1512
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
1462
1513
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
1463
1514
1515
+
estree-walker@2.0.1, estree-walker@^2.0.1:
1516
+
version "2.0.1"
1517
+
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.1.tgz#f8e030fb21cefa183b44b7ad516b747434e7a3e0"
1518
+
integrity sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg==
1519
+
1464
1520
estree-walker@^0.6.1:
1465
1521
version "0.6.1"
1466
1522
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362"
···
1743
1799
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
1744
1800
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
1745
1801
1802
+
google-closure-compiler-java@^20200517.0.0:
1803
+
version "20200517.0.0"
1804
+
resolved "https://registry.yarnpkg.com/google-closure-compiler-java/-/google-closure-compiler-java-20200517.0.0.tgz#778370c22273c9085f4cf959ce063f8f112c02ac"
1805
+
integrity sha512-JVZBiyyXwcYi6Yc3lO6dF2hMLJA4OzPm4/mgsem/tF1vk2HsWTnL3GTaBsPB2ENVZp0hoqsd4KgpPiG9ssNWxw==
1806
+
1807
+
google-closure-compiler-js@^20200517.0.0:
1808
+
version "20200517.0.0"
1809
+
resolved "https://registry.yarnpkg.com/google-closure-compiler-js/-/google-closure-compiler-js-20200517.0.0.tgz#9cb0861f764073d1c4d3b7453b74073ccb1ecfb1"
1810
+
integrity sha512-dz6dOUHx5nhdIqMRXacAYS8aJfLvw4IKxGg28Hq/zeeDPHlX3P3iBK20NgFDfT8zdushThymtMqChSy7C5eyfA==
1811
+
1812
+
google-closure-compiler-linux@^20200517.0.0:
1813
+
version "20200517.0.0"
1814
+
resolved "https://registry.yarnpkg.com/google-closure-compiler-linux/-/google-closure-compiler-linux-20200517.0.0.tgz#2b9ecb634130060174aff5c52329a694ea4be68b"
1815
+
integrity sha512-S5xPh6TtP+ESzZrmQLcDDqtZAsCVTbdI4VS98wQlN6IMZTd94nAnOCg9mrxQNAgop2t4sdsv/KuH0BGPUWEZ+w==
1816
+
1817
+
google-closure-compiler-osx@^20200517.0.0:
1818
+
version "20200517.0.0"
1819
+
resolved "https://registry.yarnpkg.com/google-closure-compiler-osx/-/google-closure-compiler-osx-20200517.0.0.tgz#9394e9a2fd97e3729fc3bd2abcffff6aab2cfcaa"
1820
+
integrity sha512-FWIcsKqLllLjdOBZd7azijVaObydgRd0obVNi63eUfC5MX6T4qxKumGCyor2UCNY6by2ESz+PlGqCFzFhZ6b2g==
1821
+
1822
+
google-closure-compiler-windows@^20200517.0.0:
1823
+
version "20200517.0.0"
1824
+
resolved "https://registry.yarnpkg.com/google-closure-compiler-windows/-/google-closure-compiler-windows-20200517.0.0.tgz#c5cdde438c29458666a83358567b12072924ed6c"
1825
+
integrity sha512-UXhjRGwS8deTkRla/riyVq3psscgMuw78lepEPtq5NgbumgJzY2+IQP9q+4MVOfJW58Rv0JUWKAFOnBBSZWcAQ==
1826
+
1827
+
google-closure-compiler@20200517.0.0:
1828
+
version "20200517.0.0"
1829
+
resolved "https://registry.yarnpkg.com/google-closure-compiler/-/google-closure-compiler-20200517.0.0.tgz#6c47f99fc1be59bd4f9e23c5a8f2e66d64b54143"
1830
+
integrity sha512-80W9zBS9Ajk1T5InWCfsoPohDmo5T1AAyw1rHh5+dgb/jPgwC65KhY+oJozTncf+/7tyQHJXozTARwhSlBUcMg==
1831
+
dependencies:
1832
+
chalk "2.x"
1833
+
google-closure-compiler-java "^20200517.0.0"
1834
+
google-closure-compiler-js "^20200517.0.0"
1835
+
minimist "1.x"
1836
+
vinyl "2.x"
1837
+
vinyl-sourcemaps-apply "^0.2.0"
1838
+
optionalDependencies:
1839
+
google-closure-compiler-linux "^20200517.0.0"
1840
+
google-closure-compiler-osx "^20200517.0.0"
1841
+
google-closure-compiler-windows "^20200517.0.0"
1842
+
1746
1843
graceful-fs@^4.1.2, graceful-fs@^4.2.4:
1747
1844
version "4.2.4"
1748
1845
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
···
1907
2004
once "^1.3.0"
1908
2005
wrappy "1"
1909
2006
1910
-
inherits@2:
2007
+
inherits@2, inherits@^2.0.1, inherits@~2.0.3:
1911
2008
version "2.0.4"
1912
2009
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
1913
2010
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
···
2104
2201
dependencies:
2105
2202
is-docker "^2.0.0"
2106
2203
2107
-
isarray@1.0.0:
2204
+
isarray@1.0.0, isarray@~1.0.0:
2108
2205
version "1.0.0"
2109
2206
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
2110
2207
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
···
2759
2856
slice-ansi "^4.0.0"
2760
2857
wrap-ansi "^6.2.0"
2761
2858
2762
-
magic-string@^0.25.0, magic-string@^0.25.2, magic-string@^0.25.7:
2859
+
magic-string@0.25.7, magic-string@^0.25.0, magic-string@^0.25.2, magic-string@^0.25.7:
2763
2860
version "0.25.7"
2764
2861
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
2765
2862
integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
···
2853
2950
dependencies:
2854
2951
brace-expansion "^1.1.7"
2855
2952
2856
-
minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5:
2953
+
minimist@1.x, minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5:
2857
2954
version "1.2.5"
2858
2955
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
2859
2956
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
···
3241
3338
ansi-styles "^4.0.0"
3242
3339
react-is "^16.12.0"
3243
3340
3341
+
process-nextick-args@^2.0.0, process-nextick-args@~2.0.0:
3342
+
version "2.0.1"
3343
+
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
3344
+
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
3345
+
3244
3346
prompts@^2.0.1:
3245
3347
version "2.3.2"
3246
3348
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068"
···
3305
3407
parse-json "^5.0.0"
3306
3408
type-fest "^0.6.0"
3307
3409
3410
+
readable-stream@^2.3.5:
3411
+
version "2.3.7"
3412
+
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
3413
+
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
3414
+
dependencies:
3415
+
core-util-is "~1.0.0"
3416
+
inherits "~2.0.3"
3417
+
isarray "~1.0.0"
3418
+
process-nextick-args "~2.0.0"
3419
+
safe-buffer "~5.1.1"
3420
+
string_decoder "~1.1.1"
3421
+
util-deprecate "~1.0.1"
3422
+
3308
3423
regenerate-unicode-properties@^8.0.2:
3309
3424
version "8.2.0"
3310
3425
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
···
3364
3479
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
3365
3480
integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
3366
3481
3482
+
replace-ext@^1.0.0:
3483
+
version "1.0.1"
3484
+
resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a"
3485
+
integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==
3486
+
3367
3487
request-promise-core@1.1.3:
3368
3488
version "1.1.3"
3369
3489
resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9"
···
3504
3624
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
3505
3625
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
3506
3626
3507
-
safe-buffer@~5.1.1:
3627
+
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
3508
3628
version "5.1.2"
3509
3629
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
3510
3630
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
···
3704
3824
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
3705
3825
integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
3706
3826
3707
-
source-map@^0.5.0, source-map@^0.5.6:
3827
+
source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.6:
3708
3828
version "0.5.7"
3709
3829
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
3710
3830
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
···
3719
3839
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
3720
3840
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
3721
3841
3722
-
sourcemap-codec@^1.4.4:
3842
+
sourcemap-codec@1.4.8, sourcemap-codec@^1.4.4:
3723
3843
version "1.4.8"
3724
3844
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
3725
3845
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
···
3860
3980
dependencies:
3861
3981
define-properties "^1.1.3"
3862
3982
es-abstract "^1.17.5"
3983
+
3984
+
string_decoder@~1.1.1:
3985
+
version "1.1.1"
3986
+
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
3987
+
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
3988
+
dependencies:
3989
+
safe-buffer "~5.1.0"
3863
3990
3864
3991
stringify-object@^3.3.0:
3865
3992
version "3.3.0"
···
4126
4253
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
4127
4254
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
4128
4255
4256
+
util-deprecate@~1.0.1:
4257
+
version "1.0.2"
4258
+
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
4259
+
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
4260
+
4261
+
uuid@8.1.0:
4262
+
version "8.1.0"
4263
+
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.1.0.tgz#6f1536eb43249f473abc6bd58ff983da1ca30d8d"
4264
+
integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg==
4265
+
4129
4266
uuid@^3.3.2:
4130
4267
version "3.4.0"
4131
4268
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
···
4161
4298
assert-plus "^1.0.0"
4162
4299
core-util-is "1.0.2"
4163
4300
extsprintf "^1.2.0"
4301
+
4302
+
vinyl-sourcemaps-apply@^0.2.0:
4303
+
version "0.2.1"
4304
+
resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705"
4305
+
integrity sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=
4306
+
dependencies:
4307
+
source-map "^0.5.1"
4308
+
4309
+
vinyl@2.x:
4310
+
version "2.2.1"
4311
+
resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.1.tgz#23cfb8bbab5ece3803aa2c0a1eb28af7cbba1974"
4312
+
integrity sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==
4313
+
dependencies:
4314
+
clone "^2.1.1"
4315
+
clone-buffer "^1.0.0"
4316
+
clone-stats "^1.0.0"
4317
+
cloneable-readable "^1.0.0"
4318
+
remove-trailing-separator "^1.0.1"
4319
+
replace-ext "^1.0.0"
4164
4320
4165
4321
w3c-hr-time@^1.0.2:
4166
4322
version "1.0.2"