@trenskow/parse 0.1.7 → 0.1.9
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.
- package/.vscode/launch.json +1 -1
- package/.vscode/settings.json +6 -0
- package/index.js +83 -27
- package/package.json +1 -1
- package/test.js +26 -6
package/.vscode/launch.json
CHANGED
package/index.js
CHANGED
|
@@ -1,20 +1,42 @@
|
|
|
1
1
|
// Created 02/05/22 by Kristian Trenskow
|
|
2
2
|
// See LICENSE for license.
|
|
3
3
|
|
|
4
|
-
export default (
|
|
4
|
+
export default (...args) => {
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
let boundaries;
|
|
7
|
+
let options;
|
|
8
|
+
|
|
9
|
+
if (typeof args[0] === 'string') {
|
|
10
|
+
boundaries = args.slice(0, 2);
|
|
11
|
+
options = args[2];
|
|
12
|
+
} else {
|
|
13
|
+
[ boundaries, options ] = args;
|
|
8
14
|
}
|
|
9
15
|
|
|
10
|
-
if (
|
|
11
|
-
throw new TypeError('
|
|
16
|
+
if (!Array.isArray(boundaries)) {
|
|
17
|
+
throw new TypeError('Boundaries must be an array.');
|
|
12
18
|
}
|
|
13
19
|
|
|
14
|
-
if (
|
|
15
|
-
|
|
20
|
+
if (boundaries.every((boundary) => typeof boundary === 'string')) {
|
|
21
|
+
boundaries = [boundaries];
|
|
16
22
|
}
|
|
17
23
|
|
|
24
|
+
boundaries
|
|
25
|
+
.forEach((boundaries) => {
|
|
26
|
+
if (boundaries.length !== 2) {
|
|
27
|
+
throw new TypeError('Boundaries must be an array containing the opening and closing boundary.');
|
|
28
|
+
}
|
|
29
|
+
if (!boundaries.every((boundary) => typeof boundary === 'string')) {
|
|
30
|
+
throw new TypeError('Boundaries must be strings.');
|
|
31
|
+
}
|
|
32
|
+
if (!boundaries.every((boundary) => boundary.length > 0)) {
|
|
33
|
+
throw new TypeError('Boundaries cannot be zero-length.');
|
|
34
|
+
}
|
|
35
|
+
if (boundaries.every((boundary) => boundary === boundaries[0])) {
|
|
36
|
+
throw new TypeError('Boundary tokens cannot be the same.');
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
18
40
|
if (typeof options === 'undefined') options = {};
|
|
19
41
|
if (typeof options !== 'object' || options === null) {
|
|
20
42
|
throw new TypeError('Options must be an object.');
|
|
@@ -37,6 +59,12 @@ export default (opening, closing, options) => {
|
|
|
37
59
|
throw new TypeError('Max depth must be a number.');
|
|
38
60
|
}
|
|
39
61
|
|
|
62
|
+
if (typeof options.boundaries === 'undefined') options.boundaries = 'exclude';
|
|
63
|
+
|
|
64
|
+
if (!['exclude', 'include'].includes(options.boundaries)) {
|
|
65
|
+
throw new TypeError('Boundaries must be either `\'exclude\'` (default) or `\'include\'`.');
|
|
66
|
+
}
|
|
67
|
+
|
|
40
68
|
if (maxDepth < 0) {
|
|
41
69
|
throw new TypeError('Max depth must be greater than zero.');
|
|
42
70
|
}
|
|
@@ -46,18 +74,24 @@ export default (opening, closing, options) => {
|
|
|
46
74
|
return {
|
|
47
75
|
do: (text) => {
|
|
48
76
|
|
|
49
|
-
|
|
77
|
+
let foundBoundaries = [];
|
|
50
78
|
|
|
51
|
-
|
|
79
|
+
const next = (text, offset, depth) => {
|
|
52
80
|
|
|
53
|
-
let
|
|
81
|
+
let result = [''];
|
|
54
82
|
|
|
55
83
|
let idx = offset;
|
|
56
84
|
let ignoredDepths = 0;
|
|
57
85
|
|
|
86
|
+
const appendResult = (text) => {
|
|
87
|
+
result[result.length - 1] += text;
|
|
88
|
+
};
|
|
89
|
+
|
|
58
90
|
for (idx ; idx < text.length ; idx++) {
|
|
59
91
|
|
|
60
|
-
|
|
92
|
+
const nextBoundary = foundBoundaries[foundBoundaries.length - 1];
|
|
93
|
+
|
|
94
|
+
if (text[idx] === '\\') appendResult(text[++idx]);
|
|
61
95
|
else {
|
|
62
96
|
|
|
63
97
|
const matchedIgnore = ignoreInside
|
|
@@ -66,7 +100,7 @@ export default (opening, closing, options) => {
|
|
|
66
100
|
.map(([_, matched]) => matched)[0];
|
|
67
101
|
|
|
68
102
|
if (typeof matchedIgnore !== 'undefined') {
|
|
69
|
-
|
|
103
|
+
appendResult(matchedIgnore);
|
|
70
104
|
if (matchedIgnore === ignoring[ignoring.length - 1]) {
|
|
71
105
|
ignoring.pop();
|
|
72
106
|
} else {
|
|
@@ -74,50 +108,72 @@ export default (opening, closing, options) => {
|
|
|
74
108
|
}
|
|
75
109
|
}
|
|
76
110
|
else if (ignoring.length === 0) {
|
|
77
|
-
|
|
111
|
+
|
|
112
|
+
const boundary = boundaries.find((boundaries) => text.substring(idx, idx + boundaries[0].length) === boundaries[0]);
|
|
113
|
+
|
|
114
|
+
if (typeof boundary !== 'undefined') {
|
|
78
115
|
|
|
79
116
|
if (maxDepth > depth) {
|
|
80
|
-
|
|
117
|
+
|
|
118
|
+
foundBoundaries.push(boundary);
|
|
119
|
+
|
|
81
120
|
let value;
|
|
82
|
-
|
|
121
|
+
|
|
122
|
+
[idx, value] = next(text, idx + boundary[0].length, depth + 1);
|
|
123
|
+
|
|
83
124
|
result.push(value);
|
|
84
|
-
|
|
125
|
+
|
|
126
|
+
result.push('');
|
|
127
|
+
|
|
85
128
|
} else {
|
|
86
|
-
|
|
129
|
+
appendResult(text[idx]);
|
|
87
130
|
ignoredDepths++;
|
|
88
131
|
}
|
|
89
132
|
|
|
90
|
-
} else if (text.substring(idx, idx +
|
|
133
|
+
} else if (typeof nextBoundary !== 'undefined' && text.substring(idx, idx + nextBoundary[1].length) === nextBoundary[1]) {
|
|
91
134
|
|
|
92
135
|
if (ignoredDepths === 0) {
|
|
93
136
|
|
|
94
|
-
|
|
137
|
+
foundBoundaries.pop();
|
|
95
138
|
|
|
96
|
-
if (
|
|
97
|
-
result = result[0];
|
|
139
|
+
if (depth > 0 && options.boundaries === 'include') {
|
|
140
|
+
if (Array.isArray(result[0])) result[0] = [nextBoundary[0]].concat(result[0]);
|
|
141
|
+
else result[0] = `${nextBoundary[0]}${result[0]}`;
|
|
142
|
+
if (Array.isArray(result[result.length - 1])) result.push(nextBoundary[1]);
|
|
143
|
+
else result[result.length - 1] = `${result[result.length - 1]}${nextBoundary[1]}`;
|
|
98
144
|
}
|
|
99
145
|
|
|
100
|
-
|
|
146
|
+
idx += nextBoundary[1].length - 1;
|
|
147
|
+
|
|
148
|
+
break;
|
|
101
149
|
|
|
102
150
|
} else {
|
|
103
|
-
|
|
151
|
+
appendResult(text[idx]);
|
|
104
152
|
ignoredDepths--;
|
|
105
153
|
}
|
|
106
154
|
|
|
107
155
|
} else {
|
|
108
|
-
|
|
156
|
+
appendResult(text[idx]);
|
|
109
157
|
}
|
|
110
158
|
}
|
|
111
|
-
else
|
|
159
|
+
else appendResult(text[idx]);
|
|
112
160
|
|
|
113
161
|
}
|
|
114
162
|
}
|
|
115
163
|
|
|
116
|
-
|
|
164
|
+
if (Array.isArray(result)) {
|
|
165
|
+
result = result.filter((value) => value.length > 0);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (result.length === 1 && typeof result[0] === 'string') {
|
|
169
|
+
result = result[0];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return [idx, result];
|
|
117
173
|
|
|
118
174
|
};
|
|
119
175
|
|
|
120
|
-
return next(text
|
|
176
|
+
return next(text, 0, 0)[1];
|
|
121
177
|
|
|
122
178
|
}
|
|
123
179
|
};
|
package/package.json
CHANGED
package/test.js
CHANGED
|
@@ -34,6 +34,21 @@ describe('parser', () => {
|
|
|
34
34
|
'.'
|
|
35
35
|
]);
|
|
36
36
|
});
|
|
37
|
+
it ('should come back with parsed tree (with escapes and boundaries).', () => {
|
|
38
|
+
expect(parse([['[', ']'], ['{', '}']], { boundaries: 'include' }).do('This [is {my [\\[nested\\]] string}].')).to.eql(
|
|
39
|
+
[
|
|
40
|
+
'This ',
|
|
41
|
+
[
|
|
42
|
+
'[is ',
|
|
43
|
+
[
|
|
44
|
+
'{my ',
|
|
45
|
+
'[[nested]]',
|
|
46
|
+
' string}'
|
|
47
|
+
],
|
|
48
|
+
']'
|
|
49
|
+
],
|
|
50
|
+
'.']);
|
|
51
|
+
});
|
|
37
52
|
it ('should come back with parsed tree (long tokens).', () => {
|
|
38
53
|
expect(parse('hello', 'goodbye').do('This hello is hello my hello nested goodbye string goodbye goodbye.')).to.eql([
|
|
39
54
|
'This ',
|
|
@@ -71,23 +86,23 @@ describe('parser', () => {
|
|
|
71
86
|
});
|
|
72
87
|
it ('should throw an error if closing token is missing.', () => {
|
|
73
88
|
expect(() => {
|
|
74
|
-
parse('['
|
|
75
|
-
}).to.throw('
|
|
89
|
+
parse('[').do('[this');
|
|
90
|
+
}).to.throw('Boundaries must be an array containing the opening and closing boundary.');
|
|
76
91
|
});
|
|
77
92
|
it ('should throw an error if opening or closing tokens are not a string.', () => {
|
|
78
93
|
expect(() => {
|
|
79
|
-
parse(0, 1).do('[this');
|
|
80
|
-
}).to.throw('
|
|
94
|
+
parse([[0, 1]]).do('[this');
|
|
95
|
+
}).to.throw('Boundaries must be strings.');
|
|
81
96
|
});
|
|
82
97
|
it ('should throw an error if opening or closing tokens are zero-length.', () => {
|
|
83
98
|
expect(() => {
|
|
84
99
|
parse('', '').do('[this');
|
|
85
|
-
}).to.throw('
|
|
100
|
+
}).to.throw('Boundaries cannot be zero-length.');
|
|
86
101
|
});
|
|
87
102
|
it ('should throw an error if opening or closing are the same.', () => {
|
|
88
103
|
expect(() => {
|
|
89
104
|
parse('123', '123').do('[this');
|
|
90
|
-
}).to.throw('
|
|
105
|
+
}).to.throw('Boundary tokens cannot be the same.');
|
|
91
106
|
});
|
|
92
107
|
it ('should throw an error if options is not an object.', () => {
|
|
93
108
|
expect(() => {
|
|
@@ -109,4 +124,9 @@ describe('parser', () => {
|
|
|
109
124
|
parse('[', ']', { maxDepth: -1 });
|
|
110
125
|
}).to.throw('Max depth must be greater than zero.');
|
|
111
126
|
});
|
|
127
|
+
it ('should throw an error if boundaries is unknown value.', () => {
|
|
128
|
+
expect(() => {
|
|
129
|
+
parse('[', ']', { boundaries: 'wrong' });
|
|
130
|
+
}).to.throw('Boundaries must be either `\'exclude\'` (default) or `\'include\'`.');
|
|
131
|
+
});
|
|
112
132
|
});
|