@lcap/nasl-utils 4.4.0-beta.6 → 4.4.0-beta.7

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.
Files changed (45) hide show
  1. package/out/index.d.ts +5 -0
  2. package/out/index.d.ts.map +1 -1
  3. package/out/index.js +12 -1
  4. package/out/index.js.map +1 -1
  5. package/out/process.d.ts +10 -2
  6. package/out/process.d.ts.map +1 -1
  7. package/out/process.js +24 -2
  8. package/out/process.js.map +1 -1
  9. package/out/regex-validator/ExpressionLexer.d.ts +92 -0
  10. package/out/regex-validator/ExpressionLexer.d.ts.map +1 -0
  11. package/out/regex-validator/ExpressionLexer.js +814 -0
  12. package/out/regex-validator/ExpressionLexer.js.map +1 -0
  13. package/out/regex-validator/index.d.ts +5 -0
  14. package/out/regex-validator/index.d.ts.map +1 -0
  15. package/out/regex-validator/index.js +16 -0
  16. package/out/regex-validator/index.js.map +1 -0
  17. package/out/regex-validator/presetRegexr.d.ts +6 -0
  18. package/out/regex-validator/presetRegexr.d.ts.map +1 -0
  19. package/out/regex-validator/presetRegexr.js +30 -0
  20. package/out/regex-validator/presetRegexr.js.map +1 -0
  21. package/out/regex-validator/profiles/core.d.ts +347 -0
  22. package/out/regex-validator/profiles/core.d.ts.map +1 -0
  23. package/out/regex-validator/profiles/core.js +392 -0
  24. package/out/regex-validator/profiles/core.js.map +1 -0
  25. package/out/regex-validator/profiles/javascript.d.ts +12 -0
  26. package/out/regex-validator/profiles/javascript.d.ts.map +1 -0
  27. package/out/regex-validator/profiles/javascript.js +135 -0
  28. package/out/regex-validator/profiles/javascript.js.map +1 -0
  29. package/out/regex-validator/profiles/pcre.d.ts +44 -0
  30. package/out/regex-validator/profiles/pcre.d.ts.map +1 -0
  31. package/out/regex-validator/profiles/pcre.js +62 -0
  32. package/out/regex-validator/profiles/pcre.js.map +1 -0
  33. package/out/regex-validator/profiles/profiles.d.ts +6 -0
  34. package/out/regex-validator/profiles/profiles.d.ts.map +1 -0
  35. package/out/regex-validator/profiles/profiles.js +46 -0
  36. package/out/regex-validator/profiles/profiles.js.map +1 -0
  37. package/out/regex-validator/reference_content.d.ts +3 -0
  38. package/out/regex-validator/reference_content.d.ts.map +1 -0
  39. package/out/regex-validator/reference_content.js +790 -0
  40. package/out/regex-validator/reference_content.js.map +1 -0
  41. package/out/regex-validator/utils/Utils.d.ts +5 -0
  42. package/out/regex-validator/utils/Utils.d.ts.map +1 -0
  43. package/out/regex-validator/utils/Utils.js +16 -0
  44. package/out/regex-validator/utils/Utils.js.map +1 -0
  45. package/package.json +2 -2
@@ -0,0 +1,814 @@
1
+ "use strict";
2
+ /*
3
+ RegExr: Learn, Build, & Test RegEx
4
+ Copyright (C) 2017 gskinner.com, inc.
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
18
+ */
19
+ var __importDefault = (this && this.__importDefault) || function (mod) {
20
+ return (mod && mod.__esModule) ? mod : { "default": mod };
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ const Utils_js_1 = __importDefault(require("./utils/Utils.js"));
24
+ class ExpressionLexer {
25
+ constructor() {
26
+ this.profile = null;
27
+ }
28
+ set profile(profile) {
29
+ this._profile = profile;
30
+ this.string = this.token = this.errors = this.captureGroups = this.namedGroups = null;
31
+ }
32
+ parse(str) {
33
+ if (!this._profile) {
34
+ return null;
35
+ }
36
+ if (str === this.string) {
37
+ return this.token;
38
+ }
39
+ this.token = null;
40
+ this._modes = {};
41
+ this.string = str;
42
+ this.errors = [];
43
+ let capgroups = this.captureGroups = [];
44
+ let namedgroups = this.namedGroups = {};
45
+ let brgroups = this.branchResetGroups = [];
46
+ let groups = [], refs = [], i = 0, l = str.length;
47
+ let o, c, token, charset = null;
48
+ // previous is the previous token, prv is the previous "active" token (!ignore)
49
+ let prev = null, prv = null;
50
+ let profile = this._profile, unquantifiable = profile.unquantifiable;
51
+ let charTypes = profile.charTypes;
52
+ let closeIndex = str.lastIndexOf("/");
53
+ for (let i = closeIndex + 1; i < l; i++) {
54
+ this._modes[str[i]] = true;
55
+ }
56
+ while (i < l) {
57
+ c = str[i];
58
+ token = { i: i, l: 1, prev: prev, prv: prv, modes: this._modes };
59
+ if (prev) {
60
+ prev.next = token;
61
+ }
62
+ else {
63
+ this.token = token;
64
+ }
65
+ if (i === 0 || i >= closeIndex) {
66
+ this.parseFlag(str, token);
67
+ }
68
+ else if (c === "(" && !charset) {
69
+ this.parseParen(str, token);
70
+ if (token.close === null) {
71
+ token.depth = groups.length;
72
+ groups.push(token);
73
+ }
74
+ if (token.capture) {
75
+ this.addCaptureGroup(token, groups);
76
+ }
77
+ }
78
+ else if (c === ")" && !charset) {
79
+ token.type = "groupclose";
80
+ if (groups.length) {
81
+ o = token.open = groups.pop();
82
+ o.close = token;
83
+ if (o.type === "branchreset") {
84
+ brgroups.pop();
85
+ }
86
+ }
87
+ else {
88
+ token.error = { id: "groupclose" };
89
+ }
90
+ }
91
+ else if (c === "[") {
92
+ charset = this.parseSquareBracket(str, token, charset);
93
+ }
94
+ else if (c === "]" && charset) {
95
+ token.type = "setclose";
96
+ token.open = charset;
97
+ charset.close = token;
98
+ charset = null;
99
+ }
100
+ else if (c === "+" && prv && prv.clss === "quant" && profile.tokens.possessive) {
101
+ token.type = "possessive";
102
+ token.related = [prv];
103
+ }
104
+ else if ((c === "+" || c === "*") && !charset) {
105
+ token.type = charTypes[c];
106
+ token.clss = "quant";
107
+ token.min = (c === "+" ? 1 : 0);
108
+ token.max = -1;
109
+ }
110
+ else if (c === "{" && !charset && str.substr(i).search(/^{\d+,?\d*}/) !== -1) {
111
+ this.parseQuant(str, token);
112
+ }
113
+ else if (c === "\\") {
114
+ this.parseBackSlash(str, token, charset, closeIndex);
115
+ }
116
+ else if (c === "?" && !charset) {
117
+ if (!prv || prv.clss !== "quant") {
118
+ token.type = charTypes[c];
119
+ token.clss = "quant";
120
+ token.min = 0;
121
+ token.max = 1;
122
+ }
123
+ else {
124
+ token.type = "lazy";
125
+ token.related = [prv];
126
+ }
127
+ }
128
+ else if (c === "-" && charset && prv.code !== undefined && prv.prv && prv.prv.type !== "range") {
129
+ // this may be the start of a range, but we'll need to validate after the next token.
130
+ token.type = "range";
131
+ }
132
+ else {
133
+ this.parseChar(str, token, charset);
134
+ if (!charset && this._modes.x && /\s/.test(c)) {
135
+ token.ignore = true;
136
+ token.type = "ignorews";
137
+ }
138
+ }
139
+ // post process token:
140
+ // quantifier:
141
+ if (token.clss === "quant") {
142
+ if (!prv || prv.close !== undefined || unquantifiable[prv.type] || (prv.open && unquantifiable[prv.open.type])) {
143
+ token.error = { id: "quanttarg" };
144
+ }
145
+ else {
146
+ token.related = [prv.open || prv];
147
+ }
148
+ }
149
+ // reference:
150
+ if (token.group === true) {
151
+ refs.push(token);
152
+ }
153
+ // conditional:
154
+ let curGroup = groups.length ? groups[groups.length - 1] : null;
155
+ if (curGroup && (curGroup.type === "conditional" || curGroup.type === "conditionalgroup") && token.type === "alt") {
156
+ if (!curGroup.alt) {
157
+ curGroup.alt = token;
158
+ }
159
+ else {
160
+ token.error = { id: "extraelse" };
161
+ }
162
+ token.related = [curGroup];
163
+ token.type = "conditionalelse";
164
+ token.clss = "special";
165
+ }
166
+ else if (curGroup && curGroup.type === "branchreset") {
167
+ // reset group
168
+ curGroup.curGroupNum = curGroup.inGroupNum;
169
+ }
170
+ // range:
171
+ if (prv && prv.type === "range" && prv.l === 1) {
172
+ this.validateRange(str, token);
173
+ }
174
+ // js warnings:
175
+ // TODO: this isn't ideal, but I'm hesitant to write a more robust solution for a couple of edge cases.
176
+ if (profile.id === "js") {
177
+ this.addJSWarnings(token);
178
+ }
179
+ // general:
180
+ if (token.open && !token.clss) {
181
+ token.clss = token.open.clss;
182
+ }
183
+ if (token.error) {
184
+ this.addError(token);
185
+ }
186
+ i += token.l;
187
+ prev = token;
188
+ if (!token.ignore) {
189
+ prv = token;
190
+ }
191
+ }
192
+ // post processing:
193
+ while (groups.length) {
194
+ this.addError(groups.pop(), { id: "groupopen" });
195
+ }
196
+ this.matchRefs(refs, capgroups, namedgroups);
197
+ if (charset) {
198
+ this.addError(charset, { id: "setopen" });
199
+ }
200
+ return this.token;
201
+ }
202
+ addError(token, error = token.error) {
203
+ token.error = error;
204
+ this.errors.push(token);
205
+ }
206
+ addJSWarnings(token) {
207
+ if (token.error) {
208
+ return;
209
+ }
210
+ if ((token.type === "neglookbehind" || token.type === "poslookbehind") ||
211
+ (token.type === "sticky" || token.type === "unicode" || token.type == "dotall") ||
212
+ (token.type === "unicodecat" || token.type === "unicodescript") ||
213
+ (token.type === "namedgroup")) {
214
+ token.error = { id: "jsfuture", warning: true };
215
+ }
216
+ }
217
+ addCaptureGroup(token, groups) {
218
+ // it would be nice to make branch reset groups actually highlight all of the groups that share the same number
219
+ // that would require switching to arrays of groups for each group num - requires rearchitecture throughout the app.
220
+ let capgroups = this.captureGroups, brgroups = this.branchResetGroups, namedgroups = this.namedGroups;
221
+ let curGroup = groups.length ? groups[groups.length - 1] : null;
222
+ if (brgroups.length) {
223
+ let brgroup = brgroups[brgroups.length - 1];
224
+ token.num = ++brgroup.curGroupNum;
225
+ }
226
+ else {
227
+ token.num = capgroups.length + 1;
228
+ }
229
+ if (!capgroups[token.num - 1]) {
230
+ capgroups.push(token);
231
+ }
232
+ if (token.name && !token.error) {
233
+ if (/\d/.test(token.name[0])) {
234
+ token.error = { id: "badname" };
235
+ }
236
+ else if (namedgroups[token.name]) {
237
+ token.error = { id: "dupname" };
238
+ token.related = [namedgroups[token.name]];
239
+ }
240
+ else {
241
+ namedgroups[token.name] = token;
242
+ }
243
+ }
244
+ }
245
+ getRef(token, str) {
246
+ token.clss = "ref";
247
+ token.group = true;
248
+ token.relIndex = this.captureGroups.length;
249
+ token.name = str;
250
+ }
251
+ matchRefs(refs, indexes, names) {
252
+ while (refs.length) {
253
+ let token = refs.pop(), name = token.name, group = names[name];
254
+ if (!group && !isNaN(name)) {
255
+ let sign = name[0], index = parseInt(name) + ((sign === "+" || sign === "-") ? token.relIndex : 0);
256
+ if (sign === "-") {
257
+ index++;
258
+ }
259
+ group = indexes[index - 1];
260
+ }
261
+ if (group) {
262
+ token.group = group;
263
+ token.related = [group];
264
+ token.dir = (token.i < group.i) ? 1 : (!group.close || token.i < group.close.i) ? 0 : -1;
265
+ }
266
+ else {
267
+ delete token.group;
268
+ delete token.relIndex;
269
+ this.refToOctal(token);
270
+ if (token.error) {
271
+ this.errors.push(token.error);
272
+ }
273
+ }
274
+ }
275
+ }
276
+ ;
277
+ refToOctal(token) {
278
+ // PCRE: \# unmatched, \0 \00 \## = octal
279
+ // JS: \# \0 \00 \## = octal
280
+ // PCRE matches \8 \9 to "8" "9"
281
+ // JS: without the u flag \8 \9 match "8" "9" in IE, FF & Chrome, and "\8" "\9" in Safari. We support the former.
282
+ // JS: with the u flag, Chrome & FF throw an esc error, Safari does not.
283
+ // TODO: handle \0 for PCRE? Would need more testing.
284
+ // TODO: this doesn't handle two digit refs with 8/9 in them. Ex. \18 - not even sure what this is interpreted as.
285
+ let name = token.name, profile = this._profile;
286
+ if (token.type !== "numref") {
287
+ // not a simple \4 style reference, so can't decompose into an octal.
288
+ token.error = { id: "unmatchedref" };
289
+ }
290
+ else if (/^[0-7]{2}$/.test(name) || (profile.config.reftooctalalways && /^[0-7]$/.test(name))) { // octal
291
+ let next = token.next, char = String.fromCharCode(next.code);
292
+ if (next.type === "char" && char >= "0" && char <= "7" && parseInt(name + char, 8) <= 255) {
293
+ name += char;
294
+ this.mergeNext(token);
295
+ }
296
+ token.code = parseInt(name, 8);
297
+ token.clss = "esc";
298
+ token.type = "escoctal";
299
+ delete token.name;
300
+ }
301
+ else if (name === "8" || name === "9") {
302
+ this.parseEscChar(token, name);
303
+ delete token.name;
304
+ }
305
+ else {
306
+ token.error = { id: "unmatchedref" };
307
+ }
308
+ }
309
+ ;
310
+ mergeNext(token) {
311
+ let next = token.next;
312
+ token.next = next.next;
313
+ token.next.prev = token;
314
+ token.l++;
315
+ }
316
+ ;
317
+ parseFlag(str, token) {
318
+ // note that this doesn't deal with misformed patterns or incorrect flags.
319
+ let i = token.i, c = str[i];
320
+ if (str[i] === "/") {
321
+ token.type = (i === 0) ? "open" : "close";
322
+ if (i !== 0) {
323
+ token.related = [this.token];
324
+ this.token.related = [token];
325
+ }
326
+ }
327
+ else {
328
+ token.type = this._profile.flags[c];
329
+ }
330
+ //token.clear = true;
331
+ }
332
+ ;
333
+ parseChar(str, token, charset) {
334
+ let c = str[token.i];
335
+ token.type = (!charset && this._profile.charTypes[c]) || "char";
336
+ if (!charset && c === "/") {
337
+ token.error = { id: "fwdslash" };
338
+ }
339
+ if (token.type === "char") {
340
+ token.code = c.charCodeAt(0);
341
+ }
342
+ else if (ExpressionLexer.ANCHOR_TYPES[token.type]) {
343
+ token.clss = "anchor";
344
+ }
345
+ else if (token.type === "dot") {
346
+ token.clss = "charclass";
347
+ }
348
+ return token;
349
+ }
350
+ ;
351
+ parseSquareBracket(str, token, charset) {
352
+ let match;
353
+ if (this._profile.tokens.posixcharclass && (match = str.substr(token.i).match(/^\[(:|\.)([^\]]*?)\1]/))) {
354
+ // posixcharclass: [:alpha:]
355
+ // posixcollseq: [.ch.]
356
+ // currently neither flavor supports posixcollseq, but PCRE does flag as an error:
357
+ // TODO: the expression above currently does not catch [.\].]
358
+ token.l = match[0].length;
359
+ token.value = match[2];
360
+ token.clss = "charclass";
361
+ if (match[1] === ":") {
362
+ token.type = "posixcharclass";
363
+ if (!this._profile.posixCharClasses[match[2]]) {
364
+ token.error = { id: "posixcharclassbad" };
365
+ }
366
+ else if (!charset) {
367
+ token.error = { id: "posixcharclassnoset" };
368
+ }
369
+ }
370
+ else {
371
+ token.type = "posixcollseq";
372
+ // TODO: can this be generalized? Right now, no, because we assign ids that aren't in the profile.
373
+ token.error = { id: "notsupported" };
374
+ }
375
+ }
376
+ else if (!charset) {
377
+ // set [a-z] [aeiou]
378
+ // setnot [^a-z]
379
+ token.type = token.clss = "set";
380
+ if (str[token.i + 1] === "^") {
381
+ token.l++;
382
+ token.type += "not";
383
+ }
384
+ charset = token;
385
+ }
386
+ else {
387
+ // [[] (square bracket inside a set)
388
+ this.parseChar(str, token, charset);
389
+ }
390
+ return charset;
391
+ }
392
+ ;
393
+ parseParen(str, token) {
394
+ /*
395
+ core:
396
+ . group:
397
+ . lookahead: ?= ?!
398
+ . noncap: ?:
399
+ PCRE:
400
+ . lookbehind: ?<= ?<!
401
+ . named: ?P<name> ?'name' ?<name>
402
+ . namedref: ?P=name Also: \g'name' \k'name' etc
403
+ . comment: ?#
404
+ . atomic: ?>
405
+ . recursion: ?0 ?R Also: \g<0>
406
+ . define: ?(DEFINE)
407
+ . subroutine: ?1 ?-1 ?&name ?P>name
408
+ conditionalgroup: ?(1)a|b ?(-1)a|b ?(name)a|b
409
+ conditional: ?(?=if)then|else
410
+ mode: ?c-i
411
+ branchreset: ?|
412
+ */
413
+ token.clss = token.type = "group";
414
+ if (str[token.i + 1] !== "?") {
415
+ token.close = null; // indicates that it needs a close token.
416
+ token.capture = true;
417
+ return token;
418
+ }
419
+ let sub = str.substr(token.i + 2), match, s = sub[0];
420
+ if (s === ":") {
421
+ // (?:foo)
422
+ token.type = "noncapgroup";
423
+ token.close = null;
424
+ token.l = 3;
425
+ }
426
+ else if (s === ">") {
427
+ // (?>foo)
428
+ token.type = "atomic";
429
+ token.close = null;
430
+ token.l = 3;
431
+ }
432
+ else if (s === "|") {
433
+ // (?|(a)|(b))
434
+ token.type = "branchreset";
435
+ token.close = null;
436
+ token.l = 3;
437
+ token.inGroupNum = token.curGroupNum = this.captureGroups.length;
438
+ this.branchResetGroups.push(token);
439
+ }
440
+ else if (s === "#" && (match = sub.match(/[^)]*\)/))) {
441
+ // (?#foo)
442
+ token.clss = token.type = "comment";
443
+ token.ignore = true;
444
+ token.l = 2 + match[0].length;
445
+ }
446
+ else if (/^(R|0)\)/.test(sub)) {
447
+ // (?R) (?0)
448
+ token.clss = "ref";
449
+ token.type = "recursion";
450
+ token.l = 4;
451
+ }
452
+ else if (match = sub.match(/^P=(\w+)\)/i)) {
453
+ // (?P=name)
454
+ token.type = "namedref";
455
+ this.getRef(token, match[1]);
456
+ token.l = match[0].length + 2;
457
+ }
458
+ else if (/^\(DEFINE\)/.test(sub)) {
459
+ // (?(DEFINE)foo)
460
+ token.type = "define";
461
+ token.close = null;
462
+ token.l = 10;
463
+ }
464
+ else if (match = sub.match(/^<?[=!]/)) {
465
+ // (?=foo) (?<!foo)
466
+ let isCond = token.prv.type === "conditional";
467
+ token.clss = isCond ? "special" : "lookaround";
468
+ token.close = null;
469
+ s = match[0];
470
+ token.behind = s[0] === "<";
471
+ token.negative = s[+token.behind] === "!";
472
+ token.type = isCond ? "condition" : (token.negative ? "neg" : "pos") + "look" + (token.behind ? "behind" : "ahead");
473
+ if (isCond) {
474
+ token.prv.related = [token];
475
+ token.prv.condition = token;
476
+ token.related = [token.prv];
477
+ }
478
+ token.l = s.length + 2;
479
+ }
480
+ else if ((match = sub.match(/^<(\w+)>/)) ||
481
+ (this._profile.config.namedgroupalt && ((match = sub.match(/^'(\w+)'/)) || (match = sub.match(/^P<(\w+)>/))))) {
482
+ // (?<name>foo) (?'name'foo) (?P<name>foo)
483
+ token.type = "namedgroup";
484
+ token.close = null;
485
+ token.name = match[1];
486
+ token.capture = true;
487
+ token.l = match[0].length + 2;
488
+ }
489
+ else if ((match = sub.match(/^([-+]?\d\d?)\)/)) || (match = sub.match(/^(?:&|P>)(\w+)\)/))) {
490
+ // (?1) (?-1) (?&name) (?P>name)
491
+ token.type = (isNaN(match[1]) ? "named" : "num") + "subroutine";
492
+ this.getRef(token, match[1]);
493
+ token.l = match[0].length + 2;
494
+ }
495
+ else if ((match = sub.match(/^\(([-+]?\d\d?)\)/)) || (match = sub.match(/^\((\w+)\)/))) {
496
+ // (?(1)a|b) (?(-1)a|b) (?(name)a|b)
497
+ this.getRef(token, match[1]);
498
+ token.clss = "special";
499
+ token.type = "conditionalgroup";
500
+ token.close = null;
501
+ token.l = match[0].length + 2;
502
+ }
503
+ else if (/^\(\?<?[=!]/.test(sub)) {
504
+ // (?(?=if)then|else)
505
+ token.clss = "special";
506
+ token.type = "conditional";
507
+ token.close = null;
508
+ token.l = 2;
509
+ }
510
+ else if (this.parseMode(token, sub)) {
511
+ // (?i-x)
512
+ // do nothing. handled by parseMode.
513
+ }
514
+ else {
515
+ // error, found a (? without matching anything. Treat it as a normal group and let it error out.
516
+ token.close = null;
517
+ token.capture = true;
518
+ }
519
+ if (!this._profile.tokens[token.type]) {
520
+ token.error = { id: "notsupported" };
521
+ }
522
+ return token;
523
+ }
524
+ ;
525
+ parseBackSlash(str, token, charset, closeIndex) {
526
+ // Note: Chrome does weird things with \x & \u depending on a number of factors, we ignore this.
527
+ let i = token.i, match, profile = this._profile;
528
+ let sub = str.substr(i + 1), c = sub[0], val;
529
+ if (i + 1 === (closeIndex || str.length)) {
530
+ token.error = { id: "esccharopen" };
531
+ return;
532
+ }
533
+ if (!charset && (match = sub.match(/^\d\d?/))) {
534
+ // \1 to \99
535
+ // write this as a reference for now, and re-write it later if it doesn't match a group
536
+ token.type = "numref";
537
+ this.getRef(token, match[0]);
538
+ token.l += match[0].length;
539
+ return token;
540
+ }
541
+ if (profile.tokens.namedref && !charset && (c === "g" || c === "k")) {
542
+ return this.parseRef(token, sub);
543
+ }
544
+ if (profile.tokens.unicodecat && (!profile.flags.u || this._modes.u) && (c === "p" || c === "P")) {
545
+ // unicode: \p{Ll} \pL
546
+ return this.parseUnicode(token, sub);
547
+ }
548
+ else if (profile.tokens.escsequence && c === "Q") {
549
+ // escsequence: \Q...\E
550
+ token.type = "escsequence";
551
+ let e = 2;
552
+ if ((i = sub.indexOf("\\E")) !== -1) {
553
+ token.l += i + 2;
554
+ e += 2;
555
+ }
556
+ else {
557
+ token.l += closeIndex - token.i - 1;
558
+ }
559
+ token.value = str.substr(token.i + 2, token.l - e);
560
+ }
561
+ else if (profile.tokens.escunicodeub && this._modes.u && (match = sub.match(/^u\{(\d+)}/))) {
562
+ // unicodeu: \u{0061}
563
+ token.type = "escunicodeub";
564
+ token.l += match[0].length;
565
+ token.code = parseInt(match[1], 16);
566
+ }
567
+ else if (profile.tokens.escunicodeu && (match = sub.match(/^u([\da-fA-F]{4})/))) {
568
+ // unicode: \uFFFF
569
+ // update SubstLexer if this changes:
570
+ token.type = "escunicodeu";
571
+ token.l += match[0].length;
572
+ token.code = parseInt(match[1], 16);
573
+ }
574
+ else if (profile.tokens.escunicodexb && (match = sub.match(/^x\{(.*?)}/))) {
575
+ // unicode: \x{FFFF}
576
+ token.type = "escunicodexb";
577
+ token.l += match[0].length;
578
+ val = parseInt(match[1], 16);
579
+ // PCRE errors on more than 2 digits (>255). In theory it should allow 4?
580
+ if (isNaN(val) || val > 255 || /[^\da-f]/i.test(match[1])) {
581
+ token.error = { id: "esccharbad" };
582
+ }
583
+ else {
584
+ token.code = val;
585
+ }
586
+ }
587
+ else if (match = sub.match(/^x([\da-fA-F]{0,2})/)) {
588
+ // hex ascii: \xFF
589
+ token.type = "eschexadecimal";
590
+ token.l += match[0].length;
591
+ token.code = parseInt(match[1] || 0, 16);
592
+ }
593
+ else if (match = sub.match(/^c([a-zA-Z])?/)) {
594
+ // control char: \cA \cz
595
+ // also handles: \c
596
+ // not supported in JS strings
597
+ token.type = "esccontrolchar";
598
+ if (match[1]) {
599
+ token.code = match[1].toUpperCase().charCodeAt(0) - 64; // A=65
600
+ token.l += 2;
601
+ }
602
+ else if (profile.config.ctrlcodeerr) {
603
+ token.l++;
604
+ token.error = { id: "esccharbad" };
605
+ }
606
+ else {
607
+ return this.parseChar(str, token, charset); // this builds the "/" token
608
+ }
609
+ }
610
+ else if (match = sub.match(/^[0-7]{1,3}/)) {
611
+ // octal ascii: \011
612
+ token.type = "escoctal";
613
+ sub = match[0];
614
+ if (parseInt(sub, 8) > 255) {
615
+ sub = sub.substr(0, 2);
616
+ }
617
+ token.l += sub.length;
618
+ token.code = parseInt(sub, 8);
619
+ }
620
+ else if (profile.tokens.escoctalo && (match = sub.match(/^o\{(.*?)}/i))) {
621
+ // \o{377}
622
+ token.type = "escoctal";
623
+ token.l += match[0].length;
624
+ val = parseInt(match[1], 8);
625
+ if (isNaN(val) || val > 255 || /[^0-7]/.test(match[1])) {
626
+ token.error = { id: "esccharbad" };
627
+ }
628
+ else {
629
+ token.code = val;
630
+ }
631
+ }
632
+ else {
633
+ // single char
634
+ if (token.type = profile.escCharTypes[c]) {
635
+ token.l++;
636
+ token.clss = ExpressionLexer.ANCHOR_TYPES[token.type] ? "anchor" : "charclass";
637
+ return token;
638
+ }
639
+ token.code = profile.escCharCodes[c];
640
+ if (token.code === undefined || token.code === false) {
641
+ // unrecognized.
642
+ return this.parseEscChar(token, c);
643
+ }
644
+ // update SubstLexer if this changes:
645
+ token.l++;
646
+ token.type = "esc_" + token.code;
647
+ }
648
+ token.clss = "esc";
649
+ return token;
650
+ }
651
+ ;
652
+ parseEscChar(token, c) {
653
+ // unrecognized escchar: \u \a \8, etc
654
+ // JS: allowed except if u flag set, Safari still allows \8 \9
655
+ // PCRE: allows \8 \9 but not others // TODO: support?
656
+ let profile = this._profile;
657
+ token.l = 2;
658
+ if (!profile.badEscChars[c] && (profile.tokens.escchar && !this._modes.u) || profile.escChars[c]) {
659
+ token.type = "escchar";
660
+ token.code = c.charCodeAt(0);
661
+ token.clss = "esc";
662
+ }
663
+ else {
664
+ token.error = { id: "esccharbad" };
665
+ }
666
+ }
667
+ parseRef(token, sub) {
668
+ // namedref: \k<name> \k'name' \k{name} \g{name}
669
+ // namedsubroutine: \g<name> \g'name'
670
+ // numref: \g1 \g+2 \g{2}
671
+ // numsubroutine: \g<-1> \g'1'
672
+ // recursion: \g<0> \g'0'
673
+ let c = sub[0], s = "", match;
674
+ if (match = sub.match(/^[gk](?:'\w*'|<\w*>|{\w*})/)) {
675
+ s = match[0].substr(2, match[0].length - 3);
676
+ if (c === "k" && !isNaN(s)) {
677
+ s = "";
678
+ } // TODO: specific error for numeric \k?
679
+ }
680
+ else if (match = sub.match(/^g(?:({[-+]?\d+}|<[-+]?\d+>|'[-+]?\d+')|([-+]?\d+))/)) {
681
+ s = match[2] !== undefined ? match[2] : match[1].substr(1, match[1].length - 2);
682
+ }
683
+ let isRef = c === "k" || !(sub[1] === "'" || sub[1] === "<");
684
+ if (!isRef && s == 0) {
685
+ token.type = "recursion";
686
+ token.clss = "ref";
687
+ }
688
+ else {
689
+ // namedref, extnumref, namedsubroutine, numsubroutine
690
+ token.type = (isNaN(s) ? "named" : (isRef ? "ext" : "") + "num") + (isRef ? "ref" : "subroutine");
691
+ this.getRef(token, s);
692
+ }
693
+ token.l += match ? match[0].length : 1;
694
+ }
695
+ ;
696
+ parseUnicode(token, sub) {
697
+ // unicodescript: \p{Cherokee}
698
+ // unicodecat: \p{Ll} \pL
699
+ // not: \P{Ll} \p{^Lu}
700
+ let match = sub.match(/p\{\^?([^}]*)}/i), val = match && match[1], not = sub[0] === "P";
701
+ if (!match && (match = sub.match(/[pP]([LMZSNPC])/))) {
702
+ val = match[1];
703
+ }
704
+ else {
705
+ not = not !== (sub[2] === "^");
706
+ }
707
+ token.l += match ? match[0].length : 1;
708
+ token.type = "unicodecat";
709
+ if (this._profile.unicodeScripts[val]) {
710
+ token.type = "unicodescript";
711
+ }
712
+ else if (!this._profile.unicodeCategories[val]) {
713
+ val = null;
714
+ }
715
+ if (not) {
716
+ token.type = "not" + token.type;
717
+ }
718
+ if ((!this._profile.config.unicodenegated && sub[2] === "^") || !val) {
719
+ token.error = { id: "unicodebad" };
720
+ }
721
+ token.value = val;
722
+ token.clss = "charclass";
723
+ return token;
724
+ }
725
+ ;
726
+ parseMode(token, sub) {
727
+ // (?i-x)
728
+ // supported modes in PCRE: i-caseinsens, x-freespacing, s-dotall, m-multiline, U-switchlazy, [J-samename]
729
+ let match = sub.match(/^[-a-z]+\)/i);
730
+ if (!match) {
731
+ return;
732
+ }
733
+ let supModes = this._profile.modes;
734
+ let modes = Utils_js_1.default.copy({}, this._modes), bad = false, not = false, s = match[0], c;
735
+ token.on = token.off = "";
736
+ for (let i = 0, l = s.length - 1; i < l; i++) {
737
+ c = s[i];
738
+ if (c === "-") {
739
+ not = true;
740
+ continue;
741
+ }
742
+ if (!supModes[c]) {
743
+ bad = true;
744
+ break;
745
+ }
746
+ modes[c] = !not;
747
+ token.on = token.on.replace(c, "");
748
+ if (not) {
749
+ token.off = token.off.replace(c, "");
750
+ token.off += c;
751
+ }
752
+ else {
753
+ token.on += c;
754
+ }
755
+ }
756
+ token.clss = "special";
757
+ token.type = "mode";
758
+ token.l = match[0].length + 2;
759
+ if (bad) {
760
+ token.error = { id: "modebad" };
761
+ token.errmode = c;
762
+ }
763
+ else {
764
+ this._modes = modes;
765
+ }
766
+ return token;
767
+ }
768
+ parseQuant(str, token) {
769
+ // quantifier: {0,3} {3} {1,}
770
+ token.type = token.clss = "quant";
771
+ let i = token.i;
772
+ let end = str.indexOf("}", i + 1);
773
+ token.l += end - i;
774
+ let arr = str.substring(i + 1, end).split(",");
775
+ token.min = parseInt(arr[0]);
776
+ token.max = (arr[1] === undefined) ? token.min : (arr[1] === "") ? -1 : parseInt(arr[1]);
777
+ if (token.max !== -1 && token.min > token.max) {
778
+ token.error = { id: "quantrev" };
779
+ }
780
+ return token;
781
+ }
782
+ ;
783
+ validateRange(str, end) {
784
+ // char range: [a-z] [\11-\n]
785
+ let next = end, token = end.prv, prv = token.prv;
786
+ if (prv.code === undefined || next.code === undefined) {
787
+ // not a range, rewrite as a char:
788
+ this.parseChar(str, token);
789
+ }
790
+ else {
791
+ token.clss = "set";
792
+ if (prv.code > next.code) {
793
+ // this gets added here because parse has already moved to the next token:
794
+ this.errors.push(token.error = { id: "rangerev" });
795
+ }
796
+ // preserve as separate tokens, but treat as one in the UI:
797
+ next.proxy = prv.proxy = token;
798
+ token.set = [prv, token, next];
799
+ }
800
+ }
801
+ ;
802
+ }
803
+ exports.default = ExpressionLexer;
804
+ ExpressionLexer.ANCHOR_TYPES = {
805
+ "bof": true,
806
+ "eof": true,
807
+ "bos": true,
808
+ "eos": true,
809
+ "abseos": true,
810
+ "wordboundary": true,
811
+ "notwordboundary": true,
812
+ "prevmatchend": true
813
+ };
814
+ //# sourceMappingURL=ExpressionLexer.js.map