htmljs-parser 5.0.4 → 5.1.2

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/dist/index.mjs CHANGED
@@ -46,26 +46,13 @@ var TagType = /* @__PURE__ */ ((TagType2) => {
46
46
  function isWhitespaceCode(code) {
47
47
  return code <= 32 /* SPACE */;
48
48
  }
49
- function getLoc(lines, range) {
50
- const start = getPos(lines, 0, range.start);
51
- const end = range.start === range.end ? start : getPos(lines, start.line, range.end);
49
+ function getLocation(lines, startOffset, endOffset) {
50
+ const start = getPosition(lines, startOffset);
51
+ const end = startOffset === endOffset ? start : getPosAfterLine(lines, start.line, endOffset);
52
52
  return { start, end };
53
53
  }
54
- function getPos(lines, startLine, index) {
55
- let max = lines.length - 1;
56
- let line = startLine;
57
- while (line < max) {
58
- const mid = 1 + line + max >>> 1;
59
- if (lines[mid] <= index) {
60
- line = mid;
61
- } else {
62
- max = mid - 1;
63
- }
64
- }
65
- return {
66
- line,
67
- character: index - lines[line]
68
- };
54
+ function getPosition(lines, offset) {
55
+ return getPosAfterLine(lines, 0, offset);
69
56
  }
70
57
  function getLines(src) {
71
58
  const lines = [0];
@@ -82,9 +69,38 @@ function htmlEOF() {
82
69
  if (this.activeTag.concise) {
83
70
  this.closeTagEnd(this.pos, this.pos, void 0);
84
71
  } else {
85
- return this.emitError(this.activeTag, 22 /* MISSING_END_TAG */, 'Missing ending "' + this.read(this.activeTag.tagName) + '" tag');
72
+ return this.emitError(
73
+ this.activeTag,
74
+ 22 /* MISSING_END_TAG */,
75
+ 'Missing ending "' + this.read(this.activeTag.tagName) + '" tag'
76
+ );
77
+ }
78
+ }
79
+ }
80
+ function matchesCloseParen(code) {
81
+ return code === 41 /* CLOSE_PAREN */;
82
+ }
83
+ function matchesCloseCurlyBrace(code) {
84
+ return code === 125 /* CLOSE_CURLY_BRACE */;
85
+ }
86
+ function matchesPipe(code) {
87
+ return code === 124 /* PIPE */;
88
+ }
89
+ function getPosAfterLine(lines, startLine, index) {
90
+ let max = lines.length - 1;
91
+ let line = startLine;
92
+ while (line < max) {
93
+ const mid = 1 + line + max >>> 1;
94
+ if (lines[mid] <= index) {
95
+ line = mid;
96
+ } else {
97
+ max = mid - 1;
86
98
  }
87
99
  }
100
+ return {
101
+ line,
102
+ character: index - lines[line]
103
+ };
88
104
  }
89
105
 
90
106
  // src/core/Parser.ts
@@ -110,15 +126,26 @@ var Parser = class {
110
126
  read(range) {
111
127
  return this.data.slice(range.start, range.end);
112
128
  }
113
- positionAt(index) {
114
- return getPos(this.lines || (this.lines = getLines(this.data)), 0, index);
129
+ positionAt(offset) {
130
+ return getPosition(
131
+ this.lines || (this.lines = getLines(this.data)),
132
+ offset
133
+ );
115
134
  }
116
135
  locationAt(range) {
117
- return getLoc(this.lines || (this.lines = getLines(this.data)), range);
136
+ return getLocation(
137
+ this.lines || (this.lines = getLines(this.data)),
138
+ range.start,
139
+ range.end
140
+ );
118
141
  }
119
142
  enterState(state) {
120
143
  this.activeState = state;
121
- return this.activeRange = state.enter.call(this, this.activeRange, this.pos);
144
+ return this.activeRange = state.enter.call(
145
+ this,
146
+ this.activeRange,
147
+ this.pos
148
+ );
122
149
  }
123
150
  exitState() {
124
151
  const { activeRange, activeState } = this;
@@ -188,7 +215,9 @@ var Parser = class {
188
215
  }
189
216
  beginHtmlBlock(delimiter, singleLine) {
190
217
  var _a;
191
- const content = this.enterState(((_a = this.activeTag) == null ? void 0 : _a.type) === 1 /* text */ ? states_exports.PARSED_TEXT_CONTENT : states_exports.HTML_CONTENT);
218
+ const content = this.enterState(
219
+ ((_a = this.activeTag) == null ? void 0 : _a.type) === 1 /* text */ ? states_exports.PARSED_TEXT_CONTENT : states_exports.HTML_CONTENT
220
+ );
192
221
  content.singleLine = singleLine;
193
222
  content.delimiter = delimiter;
194
223
  content.indent = this.indent;
@@ -348,274 +377,692 @@ __export(states_exports, {
348
377
  handleDelimitedEOL: () => handleDelimitedEOL
349
378
  });
350
379
 
351
- // src/states/ATTRIBUTE.ts
352
- var HTML_VALUE_TERMINATORS = [
353
- 62 /* CLOSE_ANGLE_BRACKET */,
354
- 44 /* COMMA */,
355
- [47 /* FORWARD_SLASH */, 62 /* CLOSE_ANGLE_BRACKET */]
356
- ];
357
- var CONCISE_VALUE_TERMINATORS = [
358
- 93 /* CLOSE_SQUARE_BRACKET */,
359
- 59 /* SEMICOLON */,
360
- 44 /* COMMA */
361
- ];
362
- var HTML_NAME_TERMINATORS = [
363
- 62 /* CLOSE_ANGLE_BRACKET */,
364
- 44 /* COMMA */,
365
- 40 /* OPEN_PAREN */,
366
- 61 /* EQUAL */,
367
- [58 /* COLON */, 61 /* EQUAL */],
368
- [47 /* FORWARD_SLASH */, 62 /* CLOSE_ANGLE_BRACKET */]
369
- ];
370
- var CONCISE_NAME_TERMINATORS = [
371
- 93 /* CLOSE_SQUARE_BRACKET */,
372
- 59 /* SEMICOLON */,
373
- 61 /* EQUAL */,
374
- 44 /* COMMA */,
375
- 40 /* OPEN_PAREN */,
376
- [58 /* COLON */, 61 /* EQUAL */]
377
- ];
378
- var ATTRIBUTE = {
379
- name: "ATTRIBUTE",
380
+ // src/states/OPEN_TAG.ts
381
+ var TAG_STAGE = /* @__PURE__ */ ((TAG_STAGE2) => {
382
+ TAG_STAGE2[TAG_STAGE2["UNKNOWN"] = 0] = "UNKNOWN";
383
+ TAG_STAGE2[TAG_STAGE2["VAR"] = 1] = "VAR";
384
+ TAG_STAGE2[TAG_STAGE2["ARGUMENT"] = 2] = "ARGUMENT";
385
+ TAG_STAGE2[TAG_STAGE2["PARAMS"] = 3] = "PARAMS";
386
+ TAG_STAGE2[TAG_STAGE2["ATTR_GROUP"] = 4] = "ATTR_GROUP";
387
+ return TAG_STAGE2;
388
+ })(TAG_STAGE || {});
389
+ var OPEN_TAG = {
390
+ name: "OPEN_TAG",
380
391
  enter(parent, start) {
381
- return this.activeAttr = {
382
- state: ATTRIBUTE,
392
+ const tag = this.activeTag = {
393
+ state: OPEN_TAG,
394
+ type: 0 /* html */,
383
395
  parent,
384
396
  start,
385
397
  end: start,
386
- valueStart: start,
387
398
  stage: 0 /* UNKNOWN */,
388
- name: void 0,
389
- args: false,
390
- bound: false,
391
- spread: false
399
+ parentTag: this.activeTag,
400
+ nestedIndent: void 0,
401
+ indent: this.indent,
402
+ hasShorthandId: false,
403
+ hasArgs: false,
404
+ hasAttrs: false,
405
+ selfClosed: false,
406
+ shorthandEnd: -1,
407
+ tagName: void 0,
408
+ concise: this.isConcise,
409
+ beginMixedMode: this.beginMixedMode || this.endingMixedModeAtEOL
392
410
  };
411
+ this.beginMixedMode = false;
412
+ this.endingMixedModeAtEOL = false;
413
+ this.endText();
414
+ return tag;
393
415
  },
394
- exit() {
395
- this.activeAttr = void 0;
396
- },
397
- char(code, attr) {
398
- if (isWhitespaceCode(code)) {
399
- return;
400
- } else if (code === 61 /* EQUAL */ || code === 58 /* COLON */ && this.lookAtCharCodeAhead(1) === 61 /* EQUAL */ || code === 46 /* PERIOD */ && this.lookAheadFor("..")) {
401
- attr.valueStart = this.pos;
402
- this.forward = 0;
403
- if (code === 58 /* COLON */) {
404
- ensureAttrName(this, attr);
405
- attr.bound = true;
406
- this.pos += 2;
407
- this.consumeWhitespace();
408
- } else if (code === 46 /* PERIOD */) {
409
- attr.spread = true;
410
- this.pos += 3;
411
- } else {
412
- ensureAttrName(this, attr);
413
- this.pos++;
414
- this.consumeWhitespace();
416
+ exit(tag) {
417
+ var _a, _b;
418
+ const { selfClosed } = tag;
419
+ (_b = (_a = this.options).onOpenTagEnd) == null ? void 0 : _b.call(_a, {
420
+ start: this.pos - (this.isConcise ? 0 : selfClosed ? 2 : 1),
421
+ end: this.pos,
422
+ selfClosed
423
+ });
424
+ switch (selfClosed ? 2 /* void */ : tag.type) {
425
+ case 2 /* void */:
426
+ case 3 /* statement */: {
427
+ if (tag.beginMixedMode)
428
+ this.endingMixedModeAtEOL = true;
429
+ this.activeTag = tag.parentTag;
430
+ break;
415
431
  }
416
- attr.stage = 2 /* VALUE */;
417
- const expr = this.enterState(states_exports.EXPRESSION);
418
- expr.terminatedByWhitespace = true;
419
- expr.terminator = this.isConcise ? CONCISE_VALUE_TERMINATORS : HTML_VALUE_TERMINATORS;
420
- } else if (code === 40 /* OPEN_PAREN */) {
421
- ensureAttrName(this, attr);
422
- attr.stage = 3 /* ARGUMENT */;
423
- this.pos++;
424
- this.forward = 0;
425
- this.enterState(states_exports.EXPRESSION).terminator = 41 /* CLOSE_PAREN */;
426
- } else if (code === 123 /* OPEN_CURLY_BRACE */ && attr.args) {
427
- ensureAttrName(this, attr);
428
- attr.stage = 4 /* BLOCK */;
429
- this.pos++;
430
- this.forward = 0;
431
- const expr = this.enterState(states_exports.EXPRESSION);
432
- expr.terminatedByWhitespace = false;
433
- expr.terminator = 125 /* CLOSE_CURLY_BRACE */;
434
- } else if (attr.stage === 0 /* UNKNOWN */) {
435
- attr.stage = 1 /* NAME */;
436
- this.forward = 0;
437
- const expr = this.enterState(states_exports.EXPRESSION);
438
- expr.terminatedByWhitespace = true;
439
- expr.skipOperators = true;
440
- expr.terminator = this.isConcise ? CONCISE_NAME_TERMINATORS : HTML_NAME_TERMINATORS;
441
- } else {
442
- this.exitState();
432
+ case 1 /* text */:
433
+ if (this.isConcise) {
434
+ this.enterState(states_exports.CONCISE_HTML_CONTENT);
435
+ } else {
436
+ this.enterState(states_exports.PARSED_TEXT_CONTENT);
437
+ }
438
+ break;
443
439
  }
444
440
  },
445
- eol() {
446
- if (this.isConcise) {
441
+ eol(_, tag) {
442
+ if (this.isConcise && tag.stage !== 4 /* ATTR_GROUP */) {
447
443
  this.exitState();
448
444
  }
449
445
  },
450
- eof(attr) {
446
+ eof(tag) {
451
447
  if (this.isConcise) {
448
+ if (tag.stage === 4 /* ATTR_GROUP */) {
449
+ this.emitError(
450
+ tag,
451
+ 19 /* MALFORMED_OPEN_TAG */,
452
+ 'EOF reached while within an attribute group (e.g. "[ ... ]").'
453
+ );
454
+ return;
455
+ }
452
456
  this.exitState();
453
457
  } else {
454
- this.emitError(attr, 19 /* MALFORMED_OPEN_TAG */, 'EOF reached while parsing attribute "' + (attr.name ? this.read(attr.name) : "default") + '" for the "' + this.read(this.activeTag.tagName) + '" tag');
458
+ this.emitError(
459
+ tag,
460
+ 19 /* MALFORMED_OPEN_TAG */,
461
+ "EOF reached while parsing open tag"
462
+ );
455
463
  }
456
464
  },
457
- return(child, attr) {
458
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
459
- switch (attr.stage) {
460
- case 1 /* NAME */: {
461
- attr.name = {
462
- start: child.start,
463
- end: child.end
464
- };
465
- (_b = (_a = this.options).onAttrName) == null ? void 0 : _b.call(_a, attr.name);
466
- break;
465
+ char(code, tag) {
466
+ if (this.isConcise) {
467
+ if (code === 59 /* SEMICOLON */) {
468
+ this.pos++;
469
+ this.exitState();
470
+ if (!this.consumeWhitespaceOnLine(0)) {
471
+ switch (this.lookAtCharCodeAhead(0)) {
472
+ case 47 /* FORWARD_SLASH */:
473
+ switch (this.lookAtCharCodeAhead(1)) {
474
+ case 47 /* FORWARD_SLASH */:
475
+ this.enterState(states_exports.JS_COMMENT_LINE);
476
+ this.pos += 2;
477
+ return;
478
+ case 42 /* ASTERISK */:
479
+ this.enterState(states_exports.JS_COMMENT_BLOCK);
480
+ this.pos += 2;
481
+ return;
482
+ }
483
+ break;
484
+ case 60 /* OPEN_ANGLE_BRACKET */:
485
+ if (this.lookAheadFor("!--")) {
486
+ this.enterState(states_exports.HTML_COMMENT);
487
+ this.pos += 4;
488
+ return;
489
+ }
490
+ break;
491
+ }
492
+ this.emitError(
493
+ this.pos,
494
+ 5 /* INVALID_CODE_AFTER_SEMICOLON */,
495
+ "A semicolon indicates the end of a line. Only comments may follow it."
496
+ );
497
+ }
498
+ return;
467
499
  }
468
- case 3 /* ARGUMENT */: {
469
- if (attr.args) {
470
- this.emitError(child, 1 /* INVALID_ATTRIBUTE_ARGUMENT */, "An attribute can only have one set of arguments");
500
+ if (code === 45 /* HTML_BLOCK_DELIMITER */) {
501
+ if (this.lookAtCharCodeAhead(1) !== 45 /* HTML_BLOCK_DELIMITER */) {
502
+ this.emitError(
503
+ tag,
504
+ 19 /* MALFORMED_OPEN_TAG */,
505
+ '"-" not allowed as first character of attribute name'
506
+ );
471
507
  return;
472
508
  }
473
- const start = child.start - 1;
474
- const end = ++this.pos;
475
- const value = {
476
- start: child.start,
477
- end: child.end
478
- };
479
- if (this.consumeWhitespaceIfBefore("{")) {
480
- attr.args = {
481
- start,
482
- end,
483
- value
484
- };
485
- } else {
486
- attr.args = true;
487
- (_d = (_c = this.options).onAttrArgs) == null ? void 0 : _d.call(_c, {
488
- start,
489
- end,
490
- value
491
- });
509
+ if (tag.stage === 4 /* ATTR_GROUP */) {
510
+ this.emitError(
511
+ this.pos,
512
+ 19 /* MALFORMED_OPEN_TAG */,
513
+ "Attribute group was not properly ended"
514
+ );
515
+ return;
492
516
  }
493
- break;
494
- }
495
- case 4 /* BLOCK */: {
496
- const params = attr.args;
497
- const start = params.start;
498
- const end = ++this.pos;
499
- (_f = (_e = this.options).onAttrMethod) == null ? void 0 : _f.call(_e, {
500
- start,
501
- end,
502
- params,
503
- body: {
504
- start: child.start - 1,
505
- end,
506
- value: {
507
- start: child.start,
508
- end: child.end
509
- }
510
- }
511
- });
512
517
  this.exitState();
513
- break;
514
- }
515
- case 2 /* VALUE */: {
516
- if (child.start === child.end) {
517
- return this.emitError(child, 3 /* INVALID_ATTRIBUTE_VALUE */, "Missing value for attribute");
518
+ const maxPos = this.maxPos;
519
+ let curPos = this.pos + 1;
520
+ while (curPos < maxPos && this.data.charCodeAt(++curPos) !== 10 /* NEWLINE */)
521
+ ;
522
+ const indentStart = ++curPos;
523
+ while (curPos < maxPos) {
524
+ const nextCode = this.data.charCodeAt(curPos);
525
+ if (nextCode === 32 /* SPACE */ || nextCode === 9 /* TAB */) {
526
+ curPos++;
527
+ } else {
528
+ break;
529
+ }
518
530
  }
519
- if (attr.spread) {
520
- (_h = (_g = this.options).onAttrSpread) == null ? void 0 : _h.call(_g, {
521
- start: attr.valueStart,
522
- end: child.end,
523
- value: {
524
- start: child.start,
525
- end: child.end
526
- }
527
- });
528
- } else {
529
- (_j = (_i = this.options).onAttrValue) == null ? void 0 : _j.call(_i, {
530
- start: attr.valueStart,
531
- end: child.end,
532
- bound: attr.bound,
533
- value: {
531
+ const indentSize = curPos - indentStart;
532
+ if (indentSize > this.indent.length) {
533
+ this.indent = this.data.slice(indentStart, curPos);
534
+ }
535
+ this.enterState(states_exports.BEGIN_DELIMITED_HTML_BLOCK);
536
+ return;
537
+ } else if (code === 91 /* OPEN_SQUARE_BRACKET */) {
538
+ if (tag.stage === 4 /* ATTR_GROUP */) {
539
+ this.emitError(
540
+ this.pos,
541
+ 19 /* MALFORMED_OPEN_TAG */,
542
+ 'Unexpected "[" character within open tag.'
543
+ );
544
+ return;
545
+ }
546
+ tag.stage = 4 /* ATTR_GROUP */;
547
+ return;
548
+ } else if (code === 93 /* CLOSE_SQUARE_BRACKET */) {
549
+ if (tag.stage !== 4 /* ATTR_GROUP */) {
550
+ this.emitError(
551
+ this.pos,
552
+ 19 /* MALFORMED_OPEN_TAG */,
553
+ 'Unexpected "]" character within open tag.'
554
+ );
555
+ return;
556
+ }
557
+ tag.stage = 0 /* UNKNOWN */;
558
+ return;
559
+ }
560
+ } else if (code === 62 /* CLOSE_ANGLE_BRACKET */) {
561
+ this.pos++;
562
+ this.exitState();
563
+ return;
564
+ } else if (code === 47 /* FORWARD_SLASH */ && this.lookAtCharCodeAhead(1) === 62 /* CLOSE_ANGLE_BRACKET */) {
565
+ tag.selfClosed = true;
566
+ this.pos += 2;
567
+ this.exitState();
568
+ return;
569
+ }
570
+ if (code === 60 /* OPEN_ANGLE_BRACKET */) {
571
+ return this.emitError(
572
+ this.pos,
573
+ 2 /* INVALID_ATTRIBUTE_NAME */,
574
+ 'Invalid attribute name. Attribute name cannot begin with the "<" character.'
575
+ );
576
+ }
577
+ if (code === 47 /* FORWARD_SLASH */) {
578
+ switch (this.lookAtCharCodeAhead(1)) {
579
+ case 47 /* FORWARD_SLASH */:
580
+ this.enterState(states_exports.JS_COMMENT_LINE);
581
+ this.pos++;
582
+ return;
583
+ case 42 /* ASTERISK */:
584
+ this.enterState(states_exports.JS_COMMENT_BLOCK);
585
+ this.pos++;
586
+ return;
587
+ }
588
+ }
589
+ if (isWhitespaceCode(code)) {
590
+ } else if (code === 44 /* COMMA */) {
591
+ this.pos++;
592
+ this.forward = 0;
593
+ this.consumeWhitespace();
594
+ } else if (code === 47 /* FORWARD_SLASH */ && !tag.hasAttrs) {
595
+ tag.stage = 1 /* VAR */;
596
+ this.pos++;
597
+ this.forward = 0;
598
+ if (isWhitespaceCode(this.lookAtCharCodeAhead(0))) {
599
+ return this.emitError(
600
+ this.pos,
601
+ 23 /* MISSING_TAG_VARIABLE */,
602
+ "A slash was found that was not followed by a variable name or lhs expression"
603
+ );
604
+ }
605
+ const expr = this.enterState(states_exports.EXPRESSION);
606
+ expr.operators = true;
607
+ expr.terminatedByWhitespace = true;
608
+ expr.shouldTerminate = this.isConcise ? shouldTerminateConciseTagVar : shouldTerminateHtmlTagVar;
609
+ } else if (code === 40 /* OPEN_PAREN */ && !tag.hasAttrs) {
610
+ if (tag.hasArgs) {
611
+ this.emitError(
612
+ this.pos,
613
+ 11 /* INVALID_TAG_ARGUMENT */,
614
+ "A tag can only have one argument"
615
+ );
616
+ return;
617
+ }
618
+ tag.stage = 2 /* ARGUMENT */;
619
+ this.pos++;
620
+ this.forward = 0;
621
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseParen;
622
+ } else if (code === 124 /* PIPE */ && !tag.hasAttrs) {
623
+ tag.stage = 3 /* PARAMS */;
624
+ this.pos++;
625
+ this.forward = 0;
626
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesPipe;
627
+ } else {
628
+ this.forward = 0;
629
+ if (tag.tagName) {
630
+ this.enterState(states_exports.ATTRIBUTE);
631
+ tag.hasAttrs = true;
632
+ } else {
633
+ this.enterState(states_exports.TAG_NAME);
634
+ }
635
+ }
636
+ },
637
+ return(child, tag) {
638
+ var _a, _b, _c, _d, _e, _f;
639
+ switch (child.state) {
640
+ case states_exports.JS_COMMENT_BLOCK: {
641
+ break;
642
+ }
643
+ case states_exports.EXPRESSION: {
644
+ switch (tag.stage) {
645
+ case 1 /* VAR */: {
646
+ if (child.start === child.end) {
647
+ return this.emitError(
648
+ child,
649
+ 23 /* MISSING_TAG_VARIABLE */,
650
+ "A slash was found that was not followed by a variable name or lhs expression"
651
+ );
652
+ }
653
+ (_b = (_a = this.options).onTagVar) == null ? void 0 : _b.call(_a, {
654
+ start: child.start - 1,
655
+ end: child.end,
656
+ value: {
657
+ start: child.start,
658
+ end: child.end
659
+ }
660
+ });
661
+ break;
662
+ }
663
+ case 2 /* ARGUMENT */: {
664
+ const start = child.start - 1;
665
+ const end = ++this.pos;
666
+ const value = {
534
667
  start: child.start,
535
668
  end: child.end
669
+ };
670
+ if (this.consumeWhitespaceIfBefore("{")) {
671
+ const attr = this.enterState(states_exports.ATTRIBUTE);
672
+ attr.start = start;
673
+ attr.args = { start, end, value };
674
+ tag.hasAttrs = true;
675
+ this.forward = 0;
676
+ } else {
677
+ tag.hasArgs = true;
678
+ (_d = (_c = this.options).onTagArgs) == null ? void 0 : _d.call(_c, {
679
+ start,
680
+ end,
681
+ value
682
+ });
536
683
  }
537
- });
684
+ break;
685
+ }
686
+ case 3 /* PARAMS */: {
687
+ const end = ++this.pos;
688
+ (_f = (_e = this.options).onTagParams) == null ? void 0 : _f.call(_e, {
689
+ start: child.start - 1,
690
+ end,
691
+ value: {
692
+ start: child.start,
693
+ end: child.end
694
+ }
695
+ });
696
+ break;
697
+ }
538
698
  }
539
- this.exitState();
540
699
  break;
541
700
  }
542
701
  }
543
702
  }
544
703
  };
545
- function ensureAttrName(parser, attr) {
546
- var _a, _b;
547
- if (!attr.name) {
548
- (_b = (_a = parser.options).onAttrName) == null ? void 0 : _b.call(_a, {
549
- start: attr.start,
550
- end: attr.start
551
- });
704
+ function shouldTerminateConciseTagVar(code, data, pos) {
705
+ switch (code) {
706
+ case 44 /* COMMA */:
707
+ case 61 /* EQUAL */:
708
+ case 124 /* PIPE */:
709
+ case 40 /* OPEN_PAREN */:
710
+ case 59 /* SEMICOLON */:
711
+ return true;
712
+ case 58 /* COLON */:
713
+ return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
714
+ default:
715
+ return false;
716
+ }
717
+ }
718
+ function shouldTerminateHtmlTagVar(code, data, pos) {
719
+ switch (code) {
720
+ case 124 /* PIPE */:
721
+ case 44 /* COMMA */:
722
+ case 61 /* EQUAL */:
723
+ case 40 /* OPEN_PAREN */:
724
+ case 62 /* CLOSE_ANGLE_BRACKET */:
725
+ return true;
726
+ case 58 /* COLON */:
727
+ return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
728
+ case 47 /* FORWARD_SLASH */:
729
+ return data.charCodeAt(pos + 1) === 62 /* CLOSE_ANGLE_BRACKET */;
730
+ default:
731
+ return false;
552
732
  }
553
733
  }
554
734
 
555
- // src/states/BEGIN_DELIMITED_HTML_BLOCK.ts
556
- var BEGIN_DELIMITED_HTML_BLOCK = {
557
- name: "BEGIN_DELIMITED_HTML_BLOCK",
735
+ // src/states/ATTRIBUTE.ts
736
+ var ATTRIBUTE = {
737
+ name: "ATTRIBUTE",
558
738
  enter(parent, start) {
559
- return {
560
- state: BEGIN_DELIMITED_HTML_BLOCK,
739
+ return this.activeAttr = {
740
+ state: ATTRIBUTE,
561
741
  parent,
562
742
  start,
563
743
  end: start,
564
- indent: this.indent,
565
- delimiter: ""
744
+ valueStart: start,
745
+ stage: 0 /* UNKNOWN */,
746
+ name: void 0,
747
+ args: false,
748
+ bound: false,
749
+ spread: false
566
750
  };
567
751
  },
568
752
  exit() {
753
+ this.activeAttr = void 0;
569
754
  },
570
- char(code, block) {
571
- if (code === 45 /* HTML_BLOCK_DELIMITER */) {
572
- block.delimiter += "-";
573
- } else {
574
- const startPos = this.pos;
575
- if (!this.consumeWhitespaceOnLine()) {
576
- this.pos = startPos + 1;
577
- this.forward = 0;
578
- this.beginHtmlBlock(void 0, true);
755
+ char(code, attr) {
756
+ if (isWhitespaceCode(code)) {
757
+ return;
758
+ } else if (code === 61 /* EQUAL */ || code === 58 /* COLON */ && this.lookAtCharCodeAhead(1) === 61 /* EQUAL */ || code === 46 /* PERIOD */ && this.lookAheadFor("..")) {
759
+ attr.valueStart = this.pos;
760
+ this.forward = 0;
761
+ if (code === 58 /* COLON */) {
762
+ ensureAttrName(this, attr);
763
+ attr.bound = true;
764
+ this.pos += 2;
765
+ this.consumeWhitespace();
766
+ } else if (code === 46 /* PERIOD */) {
767
+ attr.spread = true;
768
+ this.pos += 3;
769
+ } else {
770
+ ensureAttrName(this, attr);
771
+ this.pos++;
772
+ this.consumeWhitespace();
579
773
  }
774
+ attr.stage = 2 /* VALUE */;
775
+ const expr = this.enterState(states_exports.EXPRESSION);
776
+ expr.operators = true;
777
+ expr.terminatedByWhitespace = true;
778
+ expr.shouldTerminate = this.isConcise ? this.activeTag.stage === 4 /* ATTR_GROUP */ ? shouldTerminateConciseGroupedAttrValue : shouldTerminateConciseAttrValue : shouldTerminateHtmlAttrValue;
779
+ } else if (code === 40 /* OPEN_PAREN */) {
780
+ ensureAttrName(this, attr);
781
+ attr.stage = 3 /* ARGUMENT */;
782
+ this.pos++;
783
+ this.forward = 0;
784
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseParen;
785
+ } else if (code === 123 /* OPEN_CURLY_BRACE */ && attr.args) {
786
+ ensureAttrName(this, attr);
787
+ attr.stage = 4 /* BLOCK */;
788
+ this.pos++;
789
+ this.forward = 0;
790
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseCurlyBrace;
791
+ } else if (attr.stage === 0 /* UNKNOWN */) {
792
+ attr.stage = 1 /* NAME */;
793
+ this.forward = 0;
794
+ const expr = this.enterState(states_exports.EXPRESSION);
795
+ expr.terminatedByWhitespace = true;
796
+ expr.shouldTerminate = this.isConcise ? this.activeTag.stage === 4 /* ATTR_GROUP */ ? shouldTerminateConciseGroupedAttrName : shouldTerminateConciseAttrName : shouldTerminateHtmlAttrName;
797
+ } else {
798
+ this.exitState();
580
799
  }
581
800
  },
582
- eol(len, block) {
583
- this.beginHtmlBlock(block.delimiter, false);
584
- handleDelimitedBlockEOL(this, len, block);
585
- },
586
- eof: htmlEOF,
587
- return() {
588
- }
589
- };
590
- function handleDelimitedEOL(parser, newLineLength, content) {
591
- if (content.singleLine) {
592
- parser.endText();
593
- parser.exitState();
594
- parser.exitState();
595
- return true;
596
- }
597
- if (content.delimiter) {
598
- handleDelimitedBlockEOL(parser, newLineLength, content);
599
- return true;
600
- }
601
- return false;
602
- }
603
- function handleDelimitedBlockEOL(parser, newLineLength, {
604
- indent,
605
- delimiter
606
- }) {
607
- const endHtmlBlockLookahead = indent + delimiter;
608
- if (parser.lookAheadFor(endHtmlBlockLookahead, parser.pos + newLineLength)) {
609
- parser.startText();
610
- parser.pos += newLineLength;
611
- parser.endText();
612
- parser.pos += endHtmlBlockLookahead.length;
613
- if (parser.consumeWhitespaceOnLine(0)) {
614
- parser.endText();
615
- parser.exitState();
616
- parser.exitState();
617
- } else {
618
- parser.emitError(parser.pos, 4 /* INVALID_CHARACTER */, "A concise mode closing block delimiter can only be followed by whitespace.");
801
+ eol() {
802
+ if (this.isConcise) {
803
+ this.exitState();
804
+ }
805
+ },
806
+ eof(attr) {
807
+ if (this.isConcise) {
808
+ this.exitState();
809
+ } else {
810
+ this.emitError(
811
+ attr,
812
+ 19 /* MALFORMED_OPEN_TAG */,
813
+ 'EOF reached while parsing attribute "' + (attr.name ? this.read(attr.name) : "default") + '" for the "' + this.read(this.activeTag.tagName) + '" tag'
814
+ );
815
+ }
816
+ },
817
+ return(child, attr) {
818
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
819
+ switch (attr.stage) {
820
+ case 1 /* NAME */: {
821
+ attr.name = {
822
+ start: child.start,
823
+ end: child.end
824
+ };
825
+ (_b = (_a = this.options).onAttrName) == null ? void 0 : _b.call(_a, attr.name);
826
+ break;
827
+ }
828
+ case 3 /* ARGUMENT */: {
829
+ if (attr.args) {
830
+ this.emitError(
831
+ child,
832
+ 1 /* INVALID_ATTRIBUTE_ARGUMENT */,
833
+ "An attribute can only have one set of arguments"
834
+ );
835
+ return;
836
+ }
837
+ const start = child.start - 1;
838
+ const end = ++this.pos;
839
+ const value = {
840
+ start: child.start,
841
+ end: child.end
842
+ };
843
+ if (this.consumeWhitespaceIfBefore("{")) {
844
+ attr.args = {
845
+ start,
846
+ end,
847
+ value
848
+ };
849
+ } else {
850
+ attr.args = true;
851
+ (_d = (_c = this.options).onAttrArgs) == null ? void 0 : _d.call(_c, {
852
+ start,
853
+ end,
854
+ value
855
+ });
856
+ }
857
+ break;
858
+ }
859
+ case 4 /* BLOCK */: {
860
+ const params = attr.args;
861
+ const start = params.start;
862
+ const end = ++this.pos;
863
+ (_f = (_e = this.options).onAttrMethod) == null ? void 0 : _f.call(_e, {
864
+ start,
865
+ end,
866
+ params,
867
+ body: {
868
+ start: child.start - 1,
869
+ end,
870
+ value: {
871
+ start: child.start,
872
+ end: child.end
873
+ }
874
+ }
875
+ });
876
+ this.exitState();
877
+ break;
878
+ }
879
+ case 2 /* VALUE */: {
880
+ if (child.start === child.end) {
881
+ return this.emitError(
882
+ child,
883
+ 3 /* INVALID_ATTRIBUTE_VALUE */,
884
+ "Missing value for attribute"
885
+ );
886
+ }
887
+ if (attr.spread) {
888
+ (_h = (_g = this.options).onAttrSpread) == null ? void 0 : _h.call(_g, {
889
+ start: attr.valueStart,
890
+ end: child.end,
891
+ value: {
892
+ start: child.start,
893
+ end: child.end
894
+ }
895
+ });
896
+ } else {
897
+ (_j = (_i = this.options).onAttrValue) == null ? void 0 : _j.call(_i, {
898
+ start: attr.valueStart,
899
+ end: child.end,
900
+ bound: attr.bound,
901
+ value: {
902
+ start: child.start,
903
+ end: child.end
904
+ }
905
+ });
906
+ }
907
+ this.exitState();
908
+ break;
909
+ }
910
+ }
911
+ }
912
+ };
913
+ function ensureAttrName(parser, attr) {
914
+ var _a, _b;
915
+ if (!attr.name) {
916
+ (_b = (_a = parser.options).onAttrName) == null ? void 0 : _b.call(_a, {
917
+ start: attr.start,
918
+ end: attr.start
919
+ });
920
+ }
921
+ }
922
+ function shouldTerminateHtmlAttrName(code, data, pos) {
923
+ switch (code) {
924
+ case 44 /* COMMA */:
925
+ case 61 /* EQUAL */:
926
+ case 40 /* OPEN_PAREN */:
927
+ case 62 /* CLOSE_ANGLE_BRACKET */:
928
+ return true;
929
+ case 58 /* COLON */:
930
+ return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
931
+ case 47 /* FORWARD_SLASH */:
932
+ return data.charCodeAt(pos + 1) === 62 /* CLOSE_ANGLE_BRACKET */;
933
+ default:
934
+ return false;
935
+ }
936
+ }
937
+ function shouldTerminateHtmlAttrValue(code, data, pos) {
938
+ switch (code) {
939
+ case 44 /* COMMA */:
940
+ return true;
941
+ case 47 /* FORWARD_SLASH */:
942
+ return data.charCodeAt(pos + 1) === 62 /* CLOSE_ANGLE_BRACKET */;
943
+ case 62 /* CLOSE_ANGLE_BRACKET */:
944
+ return data.charCodeAt(pos - 1) !== 61 /* EQUAL */;
945
+ default:
946
+ return false;
947
+ }
948
+ }
949
+ function shouldTerminateConciseAttrName(code, data, pos) {
950
+ switch (code) {
951
+ case 44 /* COMMA */:
952
+ case 61 /* EQUAL */:
953
+ case 40 /* OPEN_PAREN */:
954
+ case 59 /* SEMICOLON */:
955
+ return true;
956
+ case 58 /* COLON */:
957
+ return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
958
+ case 45 /* HYPHEN */:
959
+ return data.charCodeAt(pos + 1) === 45 /* HYPHEN */ && isWhitespaceCode(data.charCodeAt(pos - 1));
960
+ default:
961
+ return false;
962
+ }
963
+ }
964
+ function shouldTerminateConciseAttrValue(code, data, pos) {
965
+ switch (code) {
966
+ case 44 /* COMMA */:
967
+ case 59 /* SEMICOLON */:
968
+ return true;
969
+ case 45 /* HYPHEN */:
970
+ return data.charCodeAt(pos + 1) === 45 /* HYPHEN */ && isWhitespaceCode(data.charCodeAt(pos - 1));
971
+ default:
972
+ return false;
973
+ }
974
+ }
975
+ function shouldTerminateConciseGroupedAttrName(code, data, pos) {
976
+ switch (code) {
977
+ case 44 /* COMMA */:
978
+ case 61 /* EQUAL */:
979
+ case 40 /* OPEN_PAREN */:
980
+ case 93 /* CLOSE_SQUARE_BRACKET */:
981
+ return true;
982
+ case 58 /* COLON */:
983
+ return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
984
+ default:
985
+ return false;
986
+ }
987
+ }
988
+ function shouldTerminateConciseGroupedAttrValue(code) {
989
+ switch (code) {
990
+ case 44 /* COMMA */:
991
+ case 93 /* CLOSE_SQUARE_BRACKET */:
992
+ return true;
993
+ default:
994
+ return false;
995
+ }
996
+ }
997
+
998
+ // src/states/BEGIN_DELIMITED_HTML_BLOCK.ts
999
+ var BEGIN_DELIMITED_HTML_BLOCK = {
1000
+ name: "BEGIN_DELIMITED_HTML_BLOCK",
1001
+ enter(parent, start) {
1002
+ return {
1003
+ state: BEGIN_DELIMITED_HTML_BLOCK,
1004
+ parent,
1005
+ start,
1006
+ end: start,
1007
+ indent: this.indent,
1008
+ delimiter: ""
1009
+ };
1010
+ },
1011
+ exit() {
1012
+ },
1013
+ char(code, block) {
1014
+ if (code === 45 /* HTML_BLOCK_DELIMITER */) {
1015
+ block.delimiter += "-";
1016
+ } else {
1017
+ const startPos = this.pos;
1018
+ if (!this.consumeWhitespaceOnLine()) {
1019
+ this.pos = startPos + 1;
1020
+ this.forward = 0;
1021
+ this.beginHtmlBlock(void 0, true);
1022
+ }
1023
+ }
1024
+ },
1025
+ eol(len, block) {
1026
+ this.beginHtmlBlock(block.delimiter, false);
1027
+ handleDelimitedBlockEOL(this, len, block);
1028
+ },
1029
+ eof: htmlEOF,
1030
+ return() {
1031
+ }
1032
+ };
1033
+ function handleDelimitedEOL(parser, newLineLength, content) {
1034
+ if (content.singleLine) {
1035
+ parser.endText();
1036
+ parser.exitState();
1037
+ parser.exitState();
1038
+ return true;
1039
+ }
1040
+ if (content.delimiter) {
1041
+ handleDelimitedBlockEOL(parser, newLineLength, content);
1042
+ return true;
1043
+ }
1044
+ return false;
1045
+ }
1046
+ function handleDelimitedBlockEOL(parser, newLineLength, {
1047
+ indent,
1048
+ delimiter
1049
+ }) {
1050
+ const endHtmlBlockLookahead = indent + delimiter;
1051
+ if (parser.lookAheadFor(endHtmlBlockLookahead, parser.pos + newLineLength)) {
1052
+ parser.startText();
1053
+ parser.pos += newLineLength;
1054
+ parser.endText();
1055
+ parser.pos += endHtmlBlockLookahead.length;
1056
+ if (parser.consumeWhitespaceOnLine(0)) {
1057
+ parser.endText();
1058
+ parser.exitState();
1059
+ parser.exitState();
1060
+ } else {
1061
+ parser.emitError(
1062
+ parser.pos,
1063
+ 4 /* INVALID_CHARACTER */,
1064
+ "A concise mode closing block delimiter can only be followed by whitespace."
1065
+ );
619
1066
  }
620
1067
  } else if (parser.lookAheadFor(indent, parser.pos + newLineLength)) {
621
1068
  parser.startText();
@@ -661,7 +1108,11 @@ var CDATA = {
661
1108
  eol() {
662
1109
  },
663
1110
  eof(cdata) {
664
- this.emitError(cdata, 14 /* MALFORMED_CDATA */, "EOF reached while parsing CDATA");
1111
+ this.emitError(
1112
+ cdata,
1113
+ 14 /* MALFORMED_CDATA */,
1114
+ "EOF reached while parsing CDATA"
1115
+ );
665
1116
  },
666
1117
  return() {
667
1118
  }
@@ -700,7 +1151,11 @@ var CLOSE_TAG = {
700
1151
  eol() {
701
1152
  },
702
1153
  eof(closeTag) {
703
- this.emitError(closeTag, 15 /* MALFORMED_CLOSE_TAG */, "EOF reached while parsing closing tag");
1154
+ this.emitError(
1155
+ closeTag,
1156
+ 15 /* MALFORMED_CLOSE_TAG */,
1157
+ "EOF reached while parsing closing tag"
1158
+ );
704
1159
  },
705
1160
  return() {
706
1161
  }
@@ -742,7 +1197,11 @@ function ensureExpectedCloseTag(parser, closeTag) {
742
1197
  const closeTagNameStart = closeTag.start + 2;
743
1198
  const closeTagNameEnd = closeTag.end - 1;
744
1199
  if (!activeTag) {
745
- parser.emitError(closeTag, 0 /* EXTRA_CLOSING_TAG */, 'The closing "' + parser.read({ start: closeTagNameStart, end: closeTagNameEnd }) + '" tag was not expected');
1200
+ parser.emitError(
1201
+ closeTag,
1202
+ 0 /* EXTRA_CLOSING_TAG */,
1203
+ 'The closing "' + parser.read({ start: closeTagNameStart, end: closeTagNameEnd }) + '" tag was not expected'
1204
+ );
746
1205
  return false;
747
1206
  }
748
1207
  const closeTagNamePos = {
@@ -750,12 +1209,19 @@ function ensureExpectedCloseTag(parser, closeTag) {
750
1209
  end: closeTagNameEnd
751
1210
  };
752
1211
  if (closeTagNameStart < closeTagNameEnd) {
753
- if (!parser.matchAtPos(closeTagNamePos, activeTag.tagName.end > activeTag.tagName.start ? activeTag.tagName : "div")) {
1212
+ if (!parser.matchAtPos(
1213
+ closeTagNamePos,
1214
+ activeTag.tagName.end > activeTag.tagName.start ? activeTag.tagName : "div"
1215
+ )) {
754
1216
  if (activeTag.shorthandEnd === void 0 || !parser.matchAtPos(closeTagNamePos, {
755
1217
  start: activeTag.tagName.start,
756
1218
  end: activeTag.shorthandEnd
757
1219
  })) {
758
- parser.emitError(closeTag, 21 /* MISMATCHED_CLOSING_TAG */, 'The closing "' + parser.read(closeTagNamePos) + '" tag does not match the corresponding opening "' + (parser.read(activeTag.tagName) || "div") + '" tag');
1220
+ parser.emitError(
1221
+ closeTag,
1222
+ 21 /* MISMATCHED_CLOSING_TAG */,
1223
+ 'The closing "' + parser.read(closeTagNamePos) + '" tag does not match the corresponding opening "' + (parser.read(activeTag.tagName) || "div") + '" tag'
1224
+ );
759
1225
  return false;
760
1226
  }
761
1227
  }
@@ -791,18 +1257,30 @@ var CONCISE_HTML_CONTENT = {
791
1257
  parentTag = this.activeTag;
792
1258
  }
793
1259
  if (!parentTag && curIndent) {
794
- this.emitError(this.pos, 7 /* INVALID_INDENTATION */, "Line has extra indentation at the beginning");
1260
+ this.emitError(
1261
+ this.pos,
1262
+ 7 /* INVALID_INDENTATION */,
1263
+ "Line has extra indentation at the beginning"
1264
+ );
795
1265
  return;
796
1266
  }
797
1267
  if (parentTag) {
798
1268
  if (parentTag.type === 1 /* text */ && code !== 45 /* HTML_BLOCK_DELIMITER */) {
799
- this.emitError(this.pos, 8 /* INVALID_LINE_START */, 'A line within a tag that only allows text content must begin with a "-" character');
1269
+ this.emitError(
1270
+ this.pos,
1271
+ 8 /* INVALID_LINE_START */,
1272
+ 'A line within a tag that only allows text content must begin with a "-" character'
1273
+ );
800
1274
  return;
801
1275
  }
802
1276
  if (parentTag.nestedIndent === void 0) {
803
1277
  parentTag.nestedIndent = this.indent;
804
1278
  } else if (parentTag.nestedIndent !== this.indent) {
805
- this.emitError(this.pos, 7 /* INVALID_INDENTATION */, "Line indentation does match indentation of previous line");
1279
+ this.emitError(
1280
+ this.pos,
1281
+ 7 /* INVALID_INDENTATION */,
1282
+ "Line indentation does match indentation of previous line"
1283
+ );
806
1284
  return;
807
1285
  }
808
1286
  }
@@ -824,7 +1302,11 @@ var CONCISE_HTML_CONTENT = {
824
1302
  this.enterState(states_exports.BEGIN_DELIMITED_HTML_BLOCK);
825
1303
  this.pos--;
826
1304
  } else {
827
- this.emitError(this.pos, 8 /* INVALID_LINE_START */, 'A line in concise mode cannot start with a single hyphen. Use "--" instead. See: https://github.com/marko-js/htmljs-parser/issues/43');
1305
+ this.emitError(
1306
+ this.pos,
1307
+ 8 /* INVALID_LINE_START */,
1308
+ 'A line in concise mode cannot start with a single hyphen. Use "--" instead. See: https://github.com/marko-js/htmljs-parser/issues/43'
1309
+ );
828
1310
  }
829
1311
  return;
830
1312
  case 47 /* FORWARD_SLASH */:
@@ -838,7 +1320,11 @@ var CONCISE_HTML_CONTENT = {
838
1320
  this.pos++;
839
1321
  return;
840
1322
  default:
841
- this.emitError(this.pos, 8 /* INVALID_LINE_START */, 'A line in concise mode cannot start with "/" unless it starts a "//" or "/*" comment');
1323
+ this.emitError(
1324
+ this.pos,
1325
+ 8 /* INVALID_LINE_START */,
1326
+ 'A line in concise mode cannot start with "/" unless it starts a "//" or "/*" comment'
1327
+ );
842
1328
  return;
843
1329
  }
844
1330
  }
@@ -875,7 +1361,11 @@ var CONCISE_HTML_CONTENT = {
875
1361
  }
876
1362
  });
877
1363
  if (!this.consumeWhitespaceOnLine(0)) {
878
- this.emitError(this.pos, 4 /* INVALID_CHARACTER */, "In concise mode a javascript comment block can only be followed by whitespace characters and a newline.");
1364
+ this.emitError(
1365
+ this.pos,
1366
+ 4 /* INVALID_CHARACTER */,
1367
+ "In concise mode a javascript comment block can only be followed by whitespace characters and a newline."
1368
+ );
879
1369
  }
880
1370
  break;
881
1371
  }
@@ -909,7 +1399,11 @@ var DECLARATION = {
909
1399
  eol() {
910
1400
  },
911
1401
  eof(declaration) {
912
- this.emitError(declaration, 17 /* MALFORMED_DECLARATION */, "EOF reached while parsing declaration");
1402
+ this.emitError(
1403
+ declaration,
1404
+ 17 /* MALFORMED_DECLARATION */,
1405
+ "EOF reached while parsing declaration"
1406
+ );
913
1407
  },
914
1408
  return() {
915
1409
  }
@@ -960,16 +1454,29 @@ var DTD = {
960
1454
  eol() {
961
1455
  },
962
1456
  eof(documentType) {
963
- this.emitError(documentType, 18 /* MALFORMED_DOCUMENT_TYPE */, "EOF reached while parsing document type");
1457
+ this.emitError(
1458
+ documentType,
1459
+ 18 /* MALFORMED_DOCUMENT_TYPE */,
1460
+ "EOF reached while parsing document type"
1461
+ );
964
1462
  },
965
1463
  return() {
966
1464
  }
967
1465
  };
968
1466
 
969
1467
  // src/states/EXPRESSION.ts
970
- var htmlAttrsPattern = buildPattern(0 /* HTML_ATTRS */);
971
- var conciseAttrsPattern = buildPattern(1 /* CONCISE_ATTRS */);
972
- var conciseAttrsGroupPattern = buildPattern(2 /* CONCISE_ATTRS_GROUP */);
1468
+ var shouldTerminate = () => false;
1469
+ var unaryKeywords = [
1470
+ "async",
1471
+ "await",
1472
+ "keyof",
1473
+ "class",
1474
+ "function",
1475
+ "new",
1476
+ "typeof",
1477
+ "void"
1478
+ ];
1479
+ var binaryKeywords = ["instanceof", "in", "as", "extends"];
973
1480
  var EXPRESSION = {
974
1481
  name: "EXPRESSION",
975
1482
  enter(parent, start) {
@@ -979,8 +1486,8 @@ var EXPRESSION = {
979
1486
  start,
980
1487
  end: start,
981
1488
  groupStack: [],
982
- terminator: -1,
983
- skipOperators: false,
1489
+ shouldTerminate,
1490
+ operators: false,
984
1491
  terminatedByEOL: false,
985
1492
  terminatedByWhitespace: false
986
1493
  };
@@ -990,12 +1497,12 @@ var EXPRESSION = {
990
1497
  char(code, expression) {
991
1498
  if (!expression.groupStack.length) {
992
1499
  if (expression.terminatedByWhitespace && isWhitespaceCode(code)) {
993
- if (!checkForOperators(this, expression)) {
1500
+ if (!checkForOperators(this, expression, false)) {
994
1501
  this.exitState();
995
1502
  }
996
1503
  return;
997
1504
  }
998
- if (typeof expression.terminator === "number" ? expression.terminator === code : checkForTerminators(this, code, expression.terminator)) {
1505
+ if (expression.shouldTerminate(code, this.data, this.pos)) {
999
1506
  this.exitState();
1000
1507
  return;
1001
1508
  }
@@ -1021,7 +1528,7 @@ var EXPRESSION = {
1021
1528
  this.pos++;
1022
1529
  break;
1023
1530
  default: {
1024
- if (canCharCodeBeFollowedByDivision(this.getPreviousNonWhitespaceCharCode())) {
1531
+ if (canFollowDivision(this.getPreviousNonWhitespaceCharCode())) {
1025
1532
  this.pos++;
1026
1533
  this.consumeWhitespace();
1027
1534
  } else {
@@ -1044,18 +1551,26 @@ var EXPRESSION = {
1044
1551
  case 93 /* CLOSE_SQUARE_BRACKET */:
1045
1552
  case 125 /* CLOSE_CURLY_BRACE */: {
1046
1553
  if (!expression.groupStack.length) {
1047
- return this.emitError(expression, 6 /* INVALID_EXPRESSION */, 'Mismatched group. A closing "' + String.fromCharCode(code) + '" character was found but it is not matched with a corresponding opening character.');
1554
+ return this.emitError(
1555
+ expression,
1556
+ 6 /* INVALID_EXPRESSION */,
1557
+ 'Mismatched group. A closing "' + String.fromCharCode(code) + '" character was found but it is not matched with a corresponding opening character.'
1558
+ );
1048
1559
  }
1049
1560
  const expectedCode = expression.groupStack.pop();
1050
1561
  if (expectedCode !== code) {
1051
- return this.emitError(expression, 6 /* INVALID_EXPRESSION */, 'Mismatched group. A "' + String.fromCharCode(code) + '" character was found when "' + String.fromCharCode(expectedCode) + '" was expected.');
1562
+ return this.emitError(
1563
+ expression,
1564
+ 6 /* INVALID_EXPRESSION */,
1565
+ 'Mismatched group. A "' + String.fromCharCode(code) + '" character was found when "' + String.fromCharCode(expectedCode) + '" was expected.'
1566
+ );
1052
1567
  }
1053
1568
  break;
1054
1569
  }
1055
1570
  }
1056
1571
  },
1057
1572
  eol(_, expression) {
1058
- if (!expression.groupStack.length && (expression.terminatedByEOL || expression.terminatedByWhitespace) && !checkForOperators(this, expression)) {
1573
+ if (!expression.groupStack.length && (expression.terminatedByEOL || expression.terminatedByWhitespace) && !checkForOperators(this, expression, true)) {
1059
1574
  this.exitState();
1060
1575
  }
1061
1576
  },
@@ -1068,69 +1583,216 @@ var EXPRESSION = {
1068
1583
  case states_exports.ATTRIBUTE: {
1069
1584
  const attr = parent;
1070
1585
  if (!attr.spread && !attr.name) {
1071
- return this.emitError(expression, 19 /* MALFORMED_OPEN_TAG */, 'EOF reached while parsing attribute name for the "' + this.read(this.activeTag.tagName) + '" tag');
1586
+ return this.emitError(
1587
+ expression,
1588
+ 19 /* MALFORMED_OPEN_TAG */,
1589
+ 'EOF reached while parsing attribute name for the "' + this.read(this.activeTag.tagName) + '" tag'
1590
+ );
1072
1591
  }
1073
- return this.emitError(expression, 19 /* MALFORMED_OPEN_TAG */, `EOF reached while parsing attribute value for the ${attr.spread ? "..." : attr.name ? `"${this.read(attr.name)}"` : `"default"`} attribute`);
1592
+ return this.emitError(
1593
+ expression,
1594
+ 19 /* MALFORMED_OPEN_TAG */,
1595
+ `EOF reached while parsing attribute value for the ${attr.spread ? "..." : attr.name ? `"${this.read(attr.name)}"` : `"default"`} attribute`
1596
+ );
1074
1597
  }
1075
1598
  case states_exports.TAG_NAME:
1076
- return this.emitError(expression, 19 /* MALFORMED_OPEN_TAG */, "EOF reached while parsing tag name");
1599
+ return this.emitError(
1600
+ expression,
1601
+ 19 /* MALFORMED_OPEN_TAG */,
1602
+ "EOF reached while parsing tag name"
1603
+ );
1077
1604
  case states_exports.PLACEHOLDER:
1078
- return this.emitError(expression, 20 /* MALFORMED_PLACEHOLDER */, "EOF reached while parsing placeholder");
1605
+ return this.emitError(
1606
+ expression,
1607
+ 20 /* MALFORMED_PLACEHOLDER */,
1608
+ "EOF reached while parsing placeholder"
1609
+ );
1079
1610
  }
1080
- return this.emitError(expression, 6 /* INVALID_EXPRESSION */, "EOF reached while parsing expression");
1611
+ return this.emitError(
1612
+ expression,
1613
+ 6 /* INVALID_EXPRESSION */,
1614
+ "EOF reached while parsing expression"
1615
+ );
1081
1616
  }
1082
1617
  },
1083
1618
  return() {
1084
1619
  }
1085
1620
  };
1086
- function buildPattern(type) {
1087
- const space = type === 1 /* CONCISE_ATTRS */ ? "[ \\t]" : "\\s";
1088
- const binary = `(?:[!~*%&^|?<]+=*)+|:+(?!=)|[>/+=-]+=|=>|(?<!\\+)[ \\t]*\\+(?:\\s*\\+\\s*\\+)*\\s*(?!\\+)|(?<!-)-${type === 1 /* CONCISE_ATTRS */ ? "" : "(?:\\s*-\\s*-)*\\s*"}(?!-)|(?<!\\.)\\.(?!\\.)|>${type === 0 /* HTML_ATTRS */ ? "{2,}" : "+"}|[ \\t]+(?:in(?:stanceof)?|as|extends)(?=[ \\t]+[^=/,;:>])`;
1089
- const unary = "\\b(?<![.]\\s*)(?:a(?:sync|wait)|keyof|class|function|new|typeof|void)\\b";
1090
- const lookAheadPattern = `${space}*(?:${binary})\\s*|${space}+(?=[{(]|/[^>])`;
1091
- const lookBehindPattern = `(?<=${unary}|${binary})`;
1092
- return new RegExp(`${lookAheadPattern}|${lookBehindPattern}`, "ym");
1093
- }
1094
- function checkForOperators(parser, expression) {
1095
- var _a;
1096
- if (expression.skipOperators) {
1621
+ function checkForOperators(parser, expression, eol) {
1622
+ if (!expression.operators)
1097
1623
  return false;
1624
+ const { pos, data } = parser;
1625
+ if (lookBehindForOperator(data, pos) !== -1) {
1626
+ parser.consumeWhitespace();
1627
+ parser.forward = 0;
1628
+ return true;
1098
1629
  }
1099
- const pattern = parser.isConcise ? ((_a = parser.activeTag) == null ? void 0 : _a.stage) === states_exports.TAG_STAGE.ATTR_GROUP ? conciseAttrsGroupPattern : conciseAttrsPattern : expression.terminatedByEOL ? conciseAttrsPattern : htmlAttrsPattern;
1100
- pattern.lastIndex = parser.pos;
1101
- const matches = pattern.exec(parser.data);
1102
- if (matches) {
1103
- const [match] = matches;
1104
- if (match.length === 0) {
1105
- parser.consumeWhitespace();
1106
- } else {
1107
- parser.pos += match.length;
1630
+ const terminatedByEOL = expression.terminatedByEOL || parser.isConcise;
1631
+ if (!(terminatedByEOL && eol)) {
1632
+ const nextNonSpace = lookAheadWhile(
1633
+ terminatedByEOL ? isIndentCode : isWhitespaceCode,
1634
+ data,
1635
+ pos + 1
1636
+ );
1637
+ if (!expression.shouldTerminate(
1638
+ data.charCodeAt(nextNonSpace),
1639
+ data,
1640
+ nextNonSpace
1641
+ )) {
1642
+ const lookAheadPos = lookAheadForOperator(data, nextNonSpace);
1643
+ if (lookAheadPos !== -1) {
1644
+ parser.pos = lookAheadPos;
1645
+ parser.forward = 0;
1646
+ return true;
1647
+ }
1108
1648
  }
1109
- parser.forward = 0;
1110
- } else {
1111
- return false;
1112
1649
  }
1113
- return true;
1650
+ return false;
1114
1651
  }
1115
- function checkForTerminators(parser, code, terminators) {
1116
- outer:
1117
- for (const terminator of terminators) {
1118
- if (typeof terminator === "number") {
1119
- if (code === terminator)
1120
- return true;
1121
- } else {
1122
- if (terminator[0] === code) {
1123
- for (let i = terminator.length; i-- > 1; ) {
1124
- if (parser.data.charCodeAt(parser.pos + i) !== terminator[i])
1125
- continue outer;
1126
- }
1127
- return true;
1652
+ function lookBehindForOperator(data, pos) {
1653
+ const curPos = pos - 1;
1654
+ const code = data.charCodeAt(curPos);
1655
+ switch (code) {
1656
+ case 38 /* AMPERSAND */:
1657
+ case 42 /* ASTERISK */:
1658
+ case 94 /* CARET */:
1659
+ case 58 /* COLON */:
1660
+ case 61 /* EQUAL */:
1661
+ case 33 /* EXCLAMATION */:
1662
+ case 60 /* OPEN_ANGLE_BRACKET */:
1663
+ case 62 /* CLOSE_ANGLE_BRACKET */:
1664
+ case 37 /* PERCENT */:
1665
+ case 46 /* PERIOD */:
1666
+ case 124 /* PIPE */:
1667
+ case 63 /* QUESTION */:
1668
+ case 126 /* TILDE */:
1669
+ return curPos;
1670
+ case 43 /* PLUS */:
1671
+ case 45 /* HYPHEN */: {
1672
+ if (data.charCodeAt(curPos - 1) === code) {
1673
+ return lookBehindForOperator(
1674
+ data,
1675
+ lookBehindWhile(isWhitespaceCode, data, curPos - 2)
1676
+ );
1677
+ }
1678
+ return curPos;
1679
+ }
1680
+ default: {
1681
+ for (const keyword of unaryKeywords) {
1682
+ const keywordPos = lookBehindFor(data, curPos, keyword);
1683
+ if (keywordPos !== -1) {
1684
+ return data.charCodeAt(keywordPos - 1) === 46 /* PERIOD */ ? -1 : keywordPos;
1685
+ }
1686
+ }
1687
+ return -1;
1688
+ }
1689
+ }
1690
+ }
1691
+ function lookAheadForOperator(data, pos) {
1692
+ switch (data.charCodeAt(pos)) {
1693
+ case 38 /* AMPERSAND */:
1694
+ case 42 /* ASTERISK */:
1695
+ case 94 /* CARET */:
1696
+ case 33 /* EXCLAMATION */:
1697
+ case 60 /* OPEN_ANGLE_BRACKET */:
1698
+ case 37 /* PERCENT */:
1699
+ case 124 /* PIPE */:
1700
+ case 63 /* QUESTION */:
1701
+ case 126 /* TILDE */:
1702
+ case 43 /* PLUS */:
1703
+ case 45 /* HYPHEN */:
1704
+ case 58 /* COLON */:
1705
+ case 62 /* CLOSE_ANGLE_BRACKET */:
1706
+ case 61 /* EQUAL */:
1707
+ return pos + 1;
1708
+ case 47 /* FORWARD_SLASH */:
1709
+ case 123 /* OPEN_CURLY_BRACE */:
1710
+ case 40 /* OPEN_PAREN */:
1711
+ return pos;
1712
+ case 46 /* PERIOD */:
1713
+ return data.charCodeAt(pos + 1) === 46 /* PERIOD */ ? -1 : pos + 1;
1714
+ default: {
1715
+ for (const keyword of binaryKeywords) {
1716
+ let nextPos = lookAheadFor(data, pos, keyword);
1717
+ if (nextPos === -1)
1718
+ continue;
1719
+ const max = data.length - 1;
1720
+ if (nextPos === max)
1721
+ return -1;
1722
+ let nextCode = data.charCodeAt(nextPos + 1);
1723
+ if (isWhitespaceCode(nextCode)) {
1724
+ nextPos = lookAheadWhile(isWhitespaceCode, data, nextPos + 2);
1725
+ if (nextPos === max)
1726
+ return -1;
1727
+ nextCode = data.charCodeAt(nextPos);
1728
+ } else if (isWordCode(nextCode)) {
1729
+ return -1;
1730
+ }
1731
+ switch (nextCode) {
1732
+ case 58 /* COLON */:
1733
+ case 44 /* COMMA */:
1734
+ case 61 /* EQUAL */:
1735
+ case 47 /* FORWARD_SLASH */:
1736
+ case 62 /* CLOSE_ANGLE_BRACKET */:
1737
+ case 59 /* SEMICOLON */:
1738
+ return -1;
1739
+ default:
1740
+ return nextPos;
1128
1741
  }
1129
1742
  }
1743
+ return -1;
1744
+ }
1745
+ }
1746
+ }
1747
+ function canFollowDivision(code) {
1748
+ return isWordCode(code) || code === 37 /* PERCENT */ || code === 41 /* CLOSE_PAREN */ || code === 46 /* PERIOD */ || code === 60 /* OPEN_ANGLE_BRACKET */ || code === 93 /* CLOSE_SQUARE_BRACKET */ || code === 125 /* CLOSE_CURLY_BRACE */;
1749
+ }
1750
+ function isWordCode(code) {
1751
+ return code >= 65 /* UPPER_A */ && code <= 90 /* UPPER_Z */ || code >= 97 /* LOWER_A */ && code <= 122 /* LOWER_Z */ || code >= 48 /* NUMBER_0 */ && code <= 57 /* NUMBER_9 */ || code === 95 /* UNDERSCORE */;
1752
+ }
1753
+ function isIndentCode(code) {
1754
+ return code === 9 /* TAB */ || code === 32 /* SPACE */;
1755
+ }
1756
+ function lookAheadWhile(match, data, pos) {
1757
+ const max = data.length;
1758
+ for (let i = pos; i < max; i++) {
1759
+ if (!match(data.charCodeAt(i)))
1760
+ return i;
1761
+ }
1762
+ return max - 1;
1763
+ }
1764
+ function lookBehindWhile(match, data, pos) {
1765
+ let i = pos;
1766
+ do {
1767
+ if (!match(data.charCodeAt(i))) {
1768
+ return i + 1;
1769
+ }
1770
+ } while (i--);
1771
+ return 0;
1772
+ }
1773
+ function lookBehindFor(data, pos, str) {
1774
+ let i = str.length;
1775
+ const endPos = pos - i + 1;
1776
+ if (endPos < 0)
1777
+ return -1;
1778
+ while (i--) {
1779
+ if (data.charCodeAt(endPos + i) !== str.charCodeAt(i)) {
1780
+ return -1;
1130
1781
  }
1782
+ }
1783
+ return endPos;
1131
1784
  }
1132
- function canCharCodeBeFollowedByDivision(code) {
1133
- return code >= 48 /* NUMBER_0 */ && code <= 57 /* NUMBER_9 */ || code >= 65 /* UPPER_A */ && code <= 90 /* UPPER_Z */ || code >= 97 /* LOWER_A */ && code <= 122 /* LOWER_Z */ || code === 37 /* PERCENT */ || code === 41 /* CLOSE_PAREN */ || code === 46 /* PERIOD */ || code === 60 /* OPEN_ANGLE_BRACKET */ || code === 93 /* CLOSE_SQUARE_BRACKET */ || code === 125 /* CLOSE_CURLY_BRACE */;
1785
+ function lookAheadFor(data, pos, str) {
1786
+ let i = str.length;
1787
+ const endPos = pos + i;
1788
+ if (endPos > data.length)
1789
+ return -1;
1790
+ while (i--) {
1791
+ if (data.charCodeAt(pos + i) !== str.charCodeAt(i)) {
1792
+ return -1;
1793
+ }
1794
+ }
1795
+ return endPos - 1;
1134
1796
  }
1135
1797
 
1136
1798
  // src/states/HTML_COMMENT.ts
@@ -1171,7 +1833,11 @@ var HTML_COMMENT = {
1171
1833
  eol() {
1172
1834
  },
1173
1835
  eof(comment) {
1174
- this.emitError(comment, 16 /* MALFORMED_COMMENT */, "EOF reached while parsing comment");
1836
+ this.emitError(
1837
+ comment,
1838
+ 16 /* MALFORMED_COMMENT */,
1839
+ "EOF reached while parsing comment"
1840
+ );
1175
1841
  },
1176
1842
  return() {
1177
1843
  }
@@ -1231,7 +1897,7 @@ var HTML_CONTENT = {
1231
1897
  this.endText();
1232
1898
  this.enterState(states_exports.INLINE_SCRIPT);
1233
1899
  this.pos++;
1234
- } else if (code === 47 /* FORWARD_SLASH */) {
1900
+ } else if (code === 47 /* FORWARD_SLASH */ && isWhitespaceCode(this.lookAtCharCodeAhead(-1))) {
1235
1901
  switch (this.lookAtCharCodeAhead(1)) {
1236
1902
  case 47 /* FORWARD_SLASH */:
1237
1903
  this.endText();
@@ -1345,11 +2011,10 @@ var INLINE_SCRIPT = {
1345
2011
  if (code === 123 /* OPEN_CURLY_BRACE */) {
1346
2012
  inlineScript.block = true;
1347
2013
  this.pos++;
1348
- const expr = this.enterState(states_exports.EXPRESSION);
1349
- expr.terminator = 125 /* CLOSE_CURLY_BRACE */;
1350
- expr.skipOperators = true;
2014
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseCurlyBrace;
1351
2015
  } else {
1352
2016
  const expr = this.enterState(states_exports.EXPRESSION);
2017
+ expr.operators = true;
1353
2018
  expr.terminatedByEOL = true;
1354
2019
  }
1355
2020
  },
@@ -1384,7 +2049,11 @@ var JS_COMMENT_BLOCK = {
1384
2049
  eol() {
1385
2050
  },
1386
2051
  eof(comment) {
1387
- this.emitError(comment, 16 /* MALFORMED_COMMENT */, "EOF reached while parsing multi-line JavaScript comment");
2052
+ this.emitError(
2053
+ comment,
2054
+ 16 /* MALFORMED_COMMENT */,
2055
+ "EOF reached while parsing multi-line JavaScript comment"
2056
+ );
1388
2057
  },
1389
2058
  return() {
1390
2059
  }
@@ -1507,7 +2176,11 @@ var PLACEHOLDER = {
1507
2176
  },
1508
2177
  return(child) {
1509
2178
  if (child.start === child.end) {
1510
- this.emitError(child, 20 /* MALFORMED_PLACEHOLDER */, "Invalid placeholder, the expression cannot be missing");
2179
+ this.emitError(
2180
+ child,
2181
+ 20 /* MALFORMED_PLACEHOLDER */,
2182
+ "Invalid placeholder, the expression cannot be missing"
2183
+ );
1511
2184
  }
1512
2185
  this.pos++;
1513
2186
  this.exitState();
@@ -1547,7 +2220,7 @@ function checkForPlaceholder(parser, code) {
1547
2220
  parser.enterState(PLACEHOLDER).escape = escape;
1548
2221
  parser.pos += escape ? 2 : 3;
1549
2222
  parser.forward = 0;
1550
- parser.enterState(states_exports.EXPRESSION).terminator = 125 /* CLOSE_CURLY_BRACE */;
2223
+ parser.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseCurlyBrace;
1551
2224
  return true;
1552
2225
  }
1553
2226
  }
@@ -1581,10 +2254,18 @@ var REGULAR_EXPRESSION = {
1581
2254
  }
1582
2255
  },
1583
2256
  eol(_, regExp) {
1584
- this.emitError(regExp, 9 /* INVALID_REGULAR_EXPRESSION */, "EOL reached while parsing regular expression");
2257
+ this.emitError(
2258
+ regExp,
2259
+ 9 /* INVALID_REGULAR_EXPRESSION */,
2260
+ "EOL reached while parsing regular expression"
2261
+ );
1585
2262
  },
1586
2263
  eof(regExp) {
1587
- this.emitError(regExp, 9 /* INVALID_REGULAR_EXPRESSION */, "EOF reached while parsing regular expression");
2264
+ this.emitError(
2265
+ regExp,
2266
+ 9 /* INVALID_REGULAR_EXPRESSION */,
2267
+ "EOF reached while parsing regular expression"
2268
+ );
1588
2269
  },
1589
2270
  return() {
1590
2271
  }
@@ -1618,7 +2299,11 @@ var STRING = {
1618
2299
  eol() {
1619
2300
  },
1620
2301
  eof(string) {
1621
- this.emitError(string, 10 /* INVALID_STRING */, "EOF reached while parsing string expression");
2302
+ this.emitError(
2303
+ string,
2304
+ 10 /* INVALID_STRING */,
2305
+ "EOF reached while parsing string expression"
2306
+ );
1622
2307
  },
1623
2308
  return() {
1624
2309
  }
@@ -1646,7 +2331,11 @@ var TAG_NAME = {
1646
2331
  switch (tagName.shorthandCode) {
1647
2332
  case 35 /* NUMBER_SIGN */:
1648
2333
  if (this.activeTag.hasShorthandId) {
1649
- return this.emitError(tagName, 12 /* INVALID_TAG_SHORTHAND */, "Multiple shorthand ID parts are not allowed on the same tag");
2334
+ return this.emitError(
2335
+ tagName,
2336
+ 12 /* INVALID_TAG_SHORTHAND */,
2337
+ "Multiple shorthand ID parts are not allowed on the same tag"
2338
+ );
1650
2339
  }
1651
2340
  this.activeTag.hasShorthandId = true;
1652
2341
  (_b = (_a = this.options).onTagShorthandId) == null ? void 0 : _b.call(_a, {
@@ -1677,12 +2366,26 @@ var TAG_NAME = {
1677
2366
  tag.type = tagType;
1678
2367
  if (tagType === 3 /* statement */) {
1679
2368
  if (!tag.concise) {
1680
- return this.emitError(tagName, 24 /* RESERVED_TAG_NAME */, `The "${this.read(tagName)}" tag is reserved and cannot be used as an HTML tag.`);
2369
+ return this.emitError(
2370
+ tagName,
2371
+ 24 /* RESERVED_TAG_NAME */,
2372
+ `The "${this.read(
2373
+ tagName
2374
+ )}" tag is reserved and cannot be used as an HTML tag.`
2375
+ );
1681
2376
  }
1682
2377
  if (tag.parentTag) {
1683
- return this.emitError(tagName, 25 /* ROOT_TAG_ONLY */, `"${this.read(tagName)}" can only be used at the root of the template.`);
2378
+ return this.emitError(
2379
+ tagName,
2380
+ 25 /* ROOT_TAG_ONLY */,
2381
+ `"${this.read(
2382
+ tagName
2383
+ )}" can only be used at the root of the template.`
2384
+ );
1684
2385
  }
1685
- this.enterState(states_exports.EXPRESSION).terminatedByEOL = true;
2386
+ const expr = this.enterState(states_exports.EXPRESSION);
2387
+ expr.operators = true;
2388
+ expr.terminatedByEOL = true;
1686
2389
  }
1687
2390
  }
1688
2391
  break;
@@ -1693,7 +2396,7 @@ var TAG_NAME = {
1693
2396
  if (code === 36 /* DOLLAR */ && this.lookAtCharCodeAhead(1) === 123 /* OPEN_CURLY_BRACE */) {
1694
2397
  this.pos += 2;
1695
2398
  this.forward = 0;
1696
- this.enterState(states_exports.EXPRESSION).terminator = 125 /* CLOSE_CURLY_BRACE */;
2399
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseCurlyBrace;
1697
2400
  } else if (isWhitespaceCode(code) || code === 61 /* EQUAL */ || code === 58 /* COLON */ && this.lookAtCharCodeAhead(1) === 61 /* EQUAL */ || code === 40 /* OPEN_PAREN */ || code === 47 /* FORWARD_SLASH */ || code === 124 /* PIPE */ || (this.isConcise ? code === 59 /* SEMICOLON */ : code === 62 /* CLOSE_ANGLE_BRACKET */)) {
1698
2401
  this.activeTag.shorthandEnd = this.pos;
1699
2402
  this.exitState();
@@ -1715,7 +2418,11 @@ var TAG_NAME = {
1715
2418
  if (child.terminatedByEOL)
1716
2419
  return;
1717
2420
  if (child.start === child.end) {
1718
- this.emitError(child, 20 /* MALFORMED_PLACEHOLDER */, "Invalid placeholder, the expression cannot be missing");
2421
+ this.emitError(
2422
+ child,
2423
+ 20 /* MALFORMED_PLACEHOLDER */,
2424
+ "Invalid placeholder, the expression cannot be missing"
2425
+ );
1719
2426
  }
1720
2427
  const { quasis, expressions } = tagName;
1721
2428
  const start = child.start - 2;
@@ -1748,334 +2455,43 @@ var TEMPLATE_STRING = {
1748
2455
  exit() {
1749
2456
  },
1750
2457
  char(code) {
1751
- if (code === 36 /* DOLLAR */ && this.lookAtCharCodeAhead(1) === 123 /* OPEN_CURLY_BRACE */) {
1752
- this.pos++;
1753
- const expr = this.enterState(states_exports.EXPRESSION);
1754
- expr.skipOperators = true;
1755
- expr.terminator = 125 /* CLOSE_CURLY_BRACE */;
1756
- } else {
1757
- if (code === 92 /* BACK_SLASH */) {
2458
+ switch (code) {
2459
+ case 36 /* DOLLAR */:
2460
+ if (this.lookAtCharCodeAhead(1) === 123 /* OPEN_CURLY_BRACE */) {
2461
+ this.pos++;
2462
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseCurlyBrace;
2463
+ }
2464
+ break;
2465
+ case 92 /* BACK_SLASH */:
1758
2466
  this.pos++;
1759
- } else if (code === 96 /* BACKTICK */) {
2467
+ break;
2468
+ case 96 /* BACKTICK */:
1760
2469
  this.pos++;
1761
2470
  this.exitState();
1762
- }
2471
+ break;
1763
2472
  }
1764
2473
  },
1765
2474
  eof(templateString) {
1766
- this.emitError(templateString, 13 /* INVALID_TEMPLATE_STRING */, "EOF reached while parsing template string expression");
2475
+ this.emitError(
2476
+ templateString,
2477
+ 13 /* INVALID_TEMPLATE_STRING */,
2478
+ "EOF reached while parsing template string expression"
2479
+ );
1767
2480
  },
1768
2481
  eol() {
1769
2482
  },
1770
2483
  return(child) {
1771
2484
  if (child.start === child.end) {
1772
- this.emitError(child, 20 /* MALFORMED_PLACEHOLDER */, "Invalid placeholder, the expression cannot be missing");
2485
+ this.emitError(
2486
+ child,
2487
+ 20 /* MALFORMED_PLACEHOLDER */,
2488
+ "Invalid placeholder, the expression cannot be missing"
2489
+ );
1773
2490
  }
1774
2491
  this.pos++;
1775
2492
  }
1776
2493
  };
1777
2494
 
1778
- // src/states/OPEN_TAG.ts
1779
- var TAG_STAGE = /* @__PURE__ */ ((TAG_STAGE2) => {
1780
- TAG_STAGE2[TAG_STAGE2["UNKNOWN"] = 0] = "UNKNOWN";
1781
- TAG_STAGE2[TAG_STAGE2["VAR"] = 1] = "VAR";
1782
- TAG_STAGE2[TAG_STAGE2["ARGUMENT"] = 2] = "ARGUMENT";
1783
- TAG_STAGE2[TAG_STAGE2["PARAMS"] = 3] = "PARAMS";
1784
- TAG_STAGE2[TAG_STAGE2["ATTR_GROUP"] = 4] = "ATTR_GROUP";
1785
- return TAG_STAGE2;
1786
- })(TAG_STAGE || {});
1787
- var CONCISE_TAG_VAR_TERMINATORS = [
1788
- 59 /* SEMICOLON */,
1789
- 40 /* OPEN_PAREN */,
1790
- 124 /* PIPE */,
1791
- 61 /* EQUAL */,
1792
- 44 /* COMMA */,
1793
- [58 /* COLON */, 61 /* EQUAL */]
1794
- ];
1795
- var HTML_TAG_VAR_TERMINATORS = [
1796
- 62 /* CLOSE_ANGLE_BRACKET */,
1797
- 40 /* OPEN_PAREN */,
1798
- 124 /* PIPE */,
1799
- 61 /* EQUAL */,
1800
- 44 /* COMMA */,
1801
- [58 /* COLON */, 61 /* EQUAL */],
1802
- [47 /* FORWARD_SLASH */, 62 /* CLOSE_ANGLE_BRACKET */]
1803
- ];
1804
- var OPEN_TAG = {
1805
- name: "OPEN_TAG",
1806
- enter(parent, start) {
1807
- const tag = this.activeTag = {
1808
- state: OPEN_TAG,
1809
- type: 0 /* html */,
1810
- parent,
1811
- start,
1812
- end: start,
1813
- stage: 0 /* UNKNOWN */,
1814
- parentTag: this.activeTag,
1815
- nestedIndent: void 0,
1816
- indent: this.indent,
1817
- hasShorthandId: false,
1818
- hasArgs: false,
1819
- hasAttrs: false,
1820
- selfClosed: false,
1821
- shorthandEnd: -1,
1822
- tagName: void 0,
1823
- concise: this.isConcise,
1824
- beginMixedMode: this.beginMixedMode || this.endingMixedModeAtEOL
1825
- };
1826
- this.beginMixedMode = false;
1827
- this.endingMixedModeAtEOL = false;
1828
- this.endText();
1829
- return tag;
1830
- },
1831
- exit(tag) {
1832
- var _a, _b;
1833
- const { selfClosed } = tag;
1834
- (_b = (_a = this.options).onOpenTagEnd) == null ? void 0 : _b.call(_a, {
1835
- start: this.pos - (this.isConcise ? 0 : selfClosed ? 2 : 1),
1836
- end: this.pos,
1837
- selfClosed
1838
- });
1839
- switch (selfClosed ? 2 /* void */ : tag.type) {
1840
- case 2 /* void */:
1841
- case 3 /* statement */: {
1842
- if (tag.beginMixedMode)
1843
- this.endingMixedModeAtEOL = true;
1844
- this.activeTag = tag.parentTag;
1845
- break;
1846
- }
1847
- case 1 /* text */:
1848
- if (this.isConcise) {
1849
- this.enterState(states_exports.CONCISE_HTML_CONTENT);
1850
- } else {
1851
- this.enterState(states_exports.PARSED_TEXT_CONTENT);
1852
- }
1853
- break;
1854
- }
1855
- },
1856
- eol(_, tag) {
1857
- if (this.isConcise && tag.stage !== 4 /* ATTR_GROUP */) {
1858
- this.exitState();
1859
- }
1860
- },
1861
- eof(tag) {
1862
- if (this.isConcise) {
1863
- if (tag.stage === 4 /* ATTR_GROUP */) {
1864
- this.emitError(tag, 19 /* MALFORMED_OPEN_TAG */, 'EOF reached while within an attribute group (e.g. "[ ... ]").');
1865
- return;
1866
- }
1867
- this.exitState();
1868
- } else {
1869
- this.emitError(tag, 19 /* MALFORMED_OPEN_TAG */, "EOF reached while parsing open tag");
1870
- }
1871
- },
1872
- char(code, tag) {
1873
- if (this.isConcise) {
1874
- if (code === 59 /* SEMICOLON */) {
1875
- this.pos++;
1876
- this.exitState();
1877
- if (!this.consumeWhitespaceOnLine(0)) {
1878
- switch (this.lookAtCharCodeAhead(0)) {
1879
- case 47 /* FORWARD_SLASH */:
1880
- switch (this.lookAtCharCodeAhead(1)) {
1881
- case 47 /* FORWARD_SLASH */:
1882
- this.enterState(states_exports.JS_COMMENT_LINE);
1883
- this.pos += 2;
1884
- return;
1885
- case 42 /* ASTERISK */:
1886
- this.enterState(states_exports.JS_COMMENT_BLOCK);
1887
- this.pos += 2;
1888
- return;
1889
- }
1890
- break;
1891
- case 60 /* OPEN_ANGLE_BRACKET */:
1892
- if (this.lookAheadFor("!--")) {
1893
- this.enterState(states_exports.HTML_COMMENT);
1894
- this.pos += 4;
1895
- return;
1896
- }
1897
- break;
1898
- }
1899
- this.emitError(this.pos, 5 /* INVALID_CODE_AFTER_SEMICOLON */, "A semicolon indicates the end of a line. Only comments may follow it.");
1900
- }
1901
- return;
1902
- }
1903
- if (code === 45 /* HTML_BLOCK_DELIMITER */) {
1904
- if (this.lookAtCharCodeAhead(1) !== 45 /* HTML_BLOCK_DELIMITER */) {
1905
- this.emitError(tag, 19 /* MALFORMED_OPEN_TAG */, '"-" not allowed as first character of attribute name');
1906
- return;
1907
- }
1908
- if (tag.stage === 4 /* ATTR_GROUP */) {
1909
- this.emitError(this.pos, 19 /* MALFORMED_OPEN_TAG */, "Attribute group was not properly ended");
1910
- return;
1911
- }
1912
- this.exitState();
1913
- const maxPos = this.maxPos;
1914
- let curPos = this.pos + 1;
1915
- while (curPos < maxPos && this.data.charCodeAt(++curPos) !== 10 /* NEWLINE */)
1916
- ;
1917
- const indentStart = ++curPos;
1918
- while (curPos < maxPos) {
1919
- const nextCode = this.data.charCodeAt(curPos);
1920
- if (nextCode === 32 /* SPACE */ || nextCode === 9 /* TAB */) {
1921
- curPos++;
1922
- } else {
1923
- break;
1924
- }
1925
- }
1926
- const indentSize = curPos - indentStart;
1927
- if (indentSize > this.indent.length) {
1928
- this.indent = this.data.slice(indentStart, curPos);
1929
- }
1930
- this.enterState(states_exports.BEGIN_DELIMITED_HTML_BLOCK);
1931
- return;
1932
- } else if (code === 91 /* OPEN_SQUARE_BRACKET */) {
1933
- if (tag.stage === 4 /* ATTR_GROUP */) {
1934
- this.emitError(this.pos, 19 /* MALFORMED_OPEN_TAG */, 'Unexpected "[" character within open tag.');
1935
- return;
1936
- }
1937
- tag.stage = 4 /* ATTR_GROUP */;
1938
- return;
1939
- } else if (code === 93 /* CLOSE_SQUARE_BRACKET */) {
1940
- if (tag.stage !== 4 /* ATTR_GROUP */) {
1941
- this.emitError(this.pos, 19 /* MALFORMED_OPEN_TAG */, 'Unexpected "]" character within open tag.');
1942
- return;
1943
- }
1944
- tag.stage = 0 /* UNKNOWN */;
1945
- return;
1946
- }
1947
- } else if (code === 62 /* CLOSE_ANGLE_BRACKET */) {
1948
- this.pos++;
1949
- this.exitState();
1950
- return;
1951
- } else if (code === 47 /* FORWARD_SLASH */ && this.lookAtCharCodeAhead(1) === 62 /* CLOSE_ANGLE_BRACKET */) {
1952
- tag.selfClosed = true;
1953
- this.pos += 2;
1954
- this.exitState();
1955
- return;
1956
- }
1957
- if (code === 60 /* OPEN_ANGLE_BRACKET */) {
1958
- return this.emitError(this.pos, 2 /* INVALID_ATTRIBUTE_NAME */, 'Invalid attribute name. Attribute name cannot begin with the "<" character.');
1959
- }
1960
- if (code === 47 /* FORWARD_SLASH */) {
1961
- switch (this.lookAtCharCodeAhead(1)) {
1962
- case 47 /* FORWARD_SLASH */:
1963
- this.enterState(states_exports.JS_COMMENT_LINE);
1964
- this.pos++;
1965
- return;
1966
- case 42 /* ASTERISK */:
1967
- this.enterState(states_exports.JS_COMMENT_BLOCK);
1968
- this.pos++;
1969
- return;
1970
- }
1971
- }
1972
- if (isWhitespaceCode(code)) {
1973
- } else if (code === 44 /* COMMA */) {
1974
- this.pos++;
1975
- this.forward = 0;
1976
- this.consumeWhitespace();
1977
- } else if (code === 47 /* FORWARD_SLASH */ && !tag.hasAttrs) {
1978
- tag.stage = 1 /* VAR */;
1979
- this.pos++;
1980
- this.forward = 0;
1981
- if (isWhitespaceCode(this.lookAtCharCodeAhead(0))) {
1982
- return this.emitError(this.pos, 23 /* MISSING_TAG_VARIABLE */, "A slash was found that was not followed by a variable name or lhs expression");
1983
- }
1984
- const expr = this.enterState(states_exports.EXPRESSION);
1985
- expr.terminatedByWhitespace = true;
1986
- expr.terminator = this.isConcise ? CONCISE_TAG_VAR_TERMINATORS : HTML_TAG_VAR_TERMINATORS;
1987
- } else if (code === 40 /* OPEN_PAREN */ && !tag.hasAttrs) {
1988
- if (tag.hasArgs) {
1989
- this.emitError(this.pos, 11 /* INVALID_TAG_ARGUMENT */, "A tag can only have one argument");
1990
- return;
1991
- }
1992
- tag.stage = 2 /* ARGUMENT */;
1993
- this.pos++;
1994
- this.forward = 0;
1995
- const expr = this.enterState(states_exports.EXPRESSION);
1996
- expr.skipOperators = true;
1997
- expr.terminator = 41 /* CLOSE_PAREN */;
1998
- } else if (code === 124 /* PIPE */ && !tag.hasAttrs) {
1999
- tag.stage = 3 /* PARAMS */;
2000
- this.pos++;
2001
- this.forward = 0;
2002
- const expr = this.enterState(states_exports.EXPRESSION);
2003
- expr.skipOperators = true;
2004
- expr.terminator = 124 /* PIPE */;
2005
- } else {
2006
- this.forward = 0;
2007
- if (tag.tagName) {
2008
- this.enterState(states_exports.ATTRIBUTE);
2009
- tag.hasAttrs = true;
2010
- } else {
2011
- this.enterState(states_exports.TAG_NAME);
2012
- }
2013
- }
2014
- },
2015
- return(child, tag) {
2016
- var _a, _b, _c, _d, _e, _f;
2017
- switch (child.state) {
2018
- case states_exports.JS_COMMENT_BLOCK: {
2019
- break;
2020
- }
2021
- case states_exports.EXPRESSION: {
2022
- switch (tag.stage) {
2023
- case 1 /* VAR */: {
2024
- if (child.start === child.end) {
2025
- return this.emitError(child, 23 /* MISSING_TAG_VARIABLE */, "A slash was found that was not followed by a variable name or lhs expression");
2026
- }
2027
- (_b = (_a = this.options).onTagVar) == null ? void 0 : _b.call(_a, {
2028
- start: child.start - 1,
2029
- end: child.end,
2030
- value: {
2031
- start: child.start,
2032
- end: child.end
2033
- }
2034
- });
2035
- break;
2036
- }
2037
- case 2 /* ARGUMENT */: {
2038
- const start = child.start - 1;
2039
- const end = ++this.pos;
2040
- const value = {
2041
- start: child.start,
2042
- end: child.end
2043
- };
2044
- if (this.consumeWhitespaceIfBefore("{")) {
2045
- const attr = this.enterState(states_exports.ATTRIBUTE);
2046
- attr.start = start;
2047
- attr.args = { start, end, value };
2048
- tag.hasAttrs = true;
2049
- this.forward = 0;
2050
- } else {
2051
- tag.hasArgs = true;
2052
- (_d = (_c = this.options).onTagArgs) == null ? void 0 : _d.call(_c, {
2053
- start,
2054
- end,
2055
- value
2056
- });
2057
- }
2058
- break;
2059
- }
2060
- case 3 /* PARAMS */: {
2061
- const end = ++this.pos;
2062
- (_f = (_e = this.options).onTagParams) == null ? void 0 : _f.call(_e, {
2063
- start: child.start - 1,
2064
- end,
2065
- value: {
2066
- start: child.start,
2067
- end: child.end
2068
- }
2069
- });
2070
- break;
2071
- }
2072
- }
2073
- break;
2074
- }
2075
- }
2076
- }
2077
- };
2078
-
2079
2495
  // src/index.ts
2080
2496
  function createParser(handlers) {
2081
2497
  const parser = new Parser(handlers);
@@ -2097,5 +2513,8 @@ function createParser(handlers) {
2097
2513
  export {
2098
2514
  ErrorCode,
2099
2515
  TagType,
2100
- createParser
2516
+ createParser,
2517
+ getLines,
2518
+ getLocation,
2519
+ getPosition
2101
2520
  };