htmljs-parser 5.1.1 → 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.js CHANGED
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  var __defProp = Object.defineProperty;
2
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -93,10 +94,23 @@ function htmlEOF() {
93
94
  if (this.activeTag.concise) {
94
95
  this.closeTagEnd(this.pos, this.pos, void 0);
95
96
  } else {
96
- return this.emitError(this.activeTag, 22 /* MISSING_END_TAG */, 'Missing ending "' + this.read(this.activeTag.tagName) + '" tag');
97
+ return this.emitError(
98
+ this.activeTag,
99
+ 22 /* MISSING_END_TAG */,
100
+ 'Missing ending "' + this.read(this.activeTag.tagName) + '" tag'
101
+ );
97
102
  }
98
103
  }
99
104
  }
105
+ function matchesCloseParen(code) {
106
+ return code === 41 /* CLOSE_PAREN */;
107
+ }
108
+ function matchesCloseCurlyBrace(code) {
109
+ return code === 125 /* CLOSE_CURLY_BRACE */;
110
+ }
111
+ function matchesPipe(code) {
112
+ return code === 124 /* PIPE */;
113
+ }
100
114
  function getPosAfterLine(lines, startLine, index) {
101
115
  let max = lines.length - 1;
102
116
  let line = startLine;
@@ -138,14 +152,25 @@ var Parser = class {
138
152
  return this.data.slice(range.start, range.end);
139
153
  }
140
154
  positionAt(offset) {
141
- return getPosition(this.lines || (this.lines = getLines(this.data)), offset);
155
+ return getPosition(
156
+ this.lines || (this.lines = getLines(this.data)),
157
+ offset
158
+ );
142
159
  }
143
160
  locationAt(range) {
144
- return getLocation(this.lines || (this.lines = getLines(this.data)), range.start, range.end);
161
+ return getLocation(
162
+ this.lines || (this.lines = getLines(this.data)),
163
+ range.start,
164
+ range.end
165
+ );
145
166
  }
146
167
  enterState(state) {
147
168
  this.activeState = state;
148
- return this.activeRange = state.enter.call(this, this.activeRange, this.pos);
169
+ return this.activeRange = state.enter.call(
170
+ this,
171
+ this.activeRange,
172
+ this.pos
173
+ );
149
174
  }
150
175
  exitState() {
151
176
  const { activeRange, activeState } = this;
@@ -215,7 +240,9 @@ var Parser = class {
215
240
  }
216
241
  beginHtmlBlock(delimiter, singleLine) {
217
242
  var _a;
218
- const content = this.enterState(((_a = this.activeTag) == null ? void 0 : _a.type) === 1 /* text */ ? states_exports.PARSED_TEXT_CONTENT : states_exports.HTML_CONTENT);
243
+ const content = this.enterState(
244
+ ((_a = this.activeTag) == null ? void 0 : _a.type) === 1 /* text */ ? states_exports.PARSED_TEXT_CONTENT : states_exports.HTML_CONTENT
245
+ );
219
246
  content.singleLine = singleLine;
220
247
  content.delimiter = delimiter;
221
248
  content.indent = this.indent;
@@ -375,294 +402,712 @@ __export(states_exports, {
375
402
  handleDelimitedEOL: () => handleDelimitedEOL
376
403
  });
377
404
 
378
- // src/states/ATTRIBUTE.ts
379
- var HTML_VALUE_TERMINATORS = [
380
- 62 /* CLOSE_ANGLE_BRACKET */,
381
- 44 /* COMMA */,
382
- [47 /* FORWARD_SLASH */, 62 /* CLOSE_ANGLE_BRACKET */]
383
- ];
384
- var CONCISE_VALUE_TERMINATORS = [
385
- 93 /* CLOSE_SQUARE_BRACKET */,
386
- 59 /* SEMICOLON */,
387
- 44 /* COMMA */
388
- ];
389
- var HTML_NAME_TERMINATORS = [
390
- 62 /* CLOSE_ANGLE_BRACKET */,
391
- 44 /* COMMA */,
392
- 40 /* OPEN_PAREN */,
393
- 61 /* EQUAL */,
394
- [58 /* COLON */, 61 /* EQUAL */],
395
- [47 /* FORWARD_SLASH */, 62 /* CLOSE_ANGLE_BRACKET */]
396
- ];
397
- var CONCISE_NAME_TERMINATORS = [
398
- 93 /* CLOSE_SQUARE_BRACKET */,
399
- 59 /* SEMICOLON */,
400
- 61 /* EQUAL */,
401
- 44 /* COMMA */,
402
- 40 /* OPEN_PAREN */,
403
- [58 /* COLON */, 61 /* EQUAL */]
404
- ];
405
- var ATTRIBUTE = {
406
- name: "ATTRIBUTE",
405
+ // src/states/OPEN_TAG.ts
406
+ var TAG_STAGE = /* @__PURE__ */ ((TAG_STAGE2) => {
407
+ TAG_STAGE2[TAG_STAGE2["UNKNOWN"] = 0] = "UNKNOWN";
408
+ TAG_STAGE2[TAG_STAGE2["VAR"] = 1] = "VAR";
409
+ TAG_STAGE2[TAG_STAGE2["ARGUMENT"] = 2] = "ARGUMENT";
410
+ TAG_STAGE2[TAG_STAGE2["PARAMS"] = 3] = "PARAMS";
411
+ TAG_STAGE2[TAG_STAGE2["ATTR_GROUP"] = 4] = "ATTR_GROUP";
412
+ return TAG_STAGE2;
413
+ })(TAG_STAGE || {});
414
+ var OPEN_TAG = {
415
+ name: "OPEN_TAG",
407
416
  enter(parent, start) {
408
- return this.activeAttr = {
409
- state: ATTRIBUTE,
417
+ const tag = this.activeTag = {
418
+ state: OPEN_TAG,
419
+ type: 0 /* html */,
410
420
  parent,
411
421
  start,
412
422
  end: start,
413
- valueStart: start,
414
423
  stage: 0 /* UNKNOWN */,
415
- name: void 0,
416
- args: false,
417
- bound: false,
418
- spread: false
424
+ parentTag: this.activeTag,
425
+ nestedIndent: void 0,
426
+ indent: this.indent,
427
+ hasShorthandId: false,
428
+ hasArgs: false,
429
+ hasAttrs: false,
430
+ selfClosed: false,
431
+ shorthandEnd: -1,
432
+ tagName: void 0,
433
+ concise: this.isConcise,
434
+ beginMixedMode: this.beginMixedMode || this.endingMixedModeAtEOL
419
435
  };
436
+ this.beginMixedMode = false;
437
+ this.endingMixedModeAtEOL = false;
438
+ this.endText();
439
+ return tag;
420
440
  },
421
- exit() {
422
- this.activeAttr = void 0;
423
- },
424
- char(code, attr) {
425
- if (isWhitespaceCode(code)) {
426
- return;
427
- } else if (code === 61 /* EQUAL */ || code === 58 /* COLON */ && this.lookAtCharCodeAhead(1) === 61 /* EQUAL */ || code === 46 /* PERIOD */ && this.lookAheadFor("..")) {
428
- attr.valueStart = this.pos;
429
- this.forward = 0;
430
- if (code === 58 /* COLON */) {
431
- ensureAttrName(this, attr);
432
- attr.bound = true;
433
- this.pos += 2;
434
- this.consumeWhitespace();
435
- } else if (code === 46 /* PERIOD */) {
436
- attr.spread = true;
437
- this.pos += 3;
438
- } else {
439
- ensureAttrName(this, attr);
440
- this.pos++;
441
- this.consumeWhitespace();
441
+ exit(tag) {
442
+ var _a, _b;
443
+ const { selfClosed } = tag;
444
+ (_b = (_a = this.options).onOpenTagEnd) == null ? void 0 : _b.call(_a, {
445
+ start: this.pos - (this.isConcise ? 0 : selfClosed ? 2 : 1),
446
+ end: this.pos,
447
+ selfClosed
448
+ });
449
+ switch (selfClosed ? 2 /* void */ : tag.type) {
450
+ case 2 /* void */:
451
+ case 3 /* statement */: {
452
+ if (tag.beginMixedMode)
453
+ this.endingMixedModeAtEOL = true;
454
+ this.activeTag = tag.parentTag;
455
+ break;
442
456
  }
443
- attr.stage = 2 /* VALUE */;
444
- const expr = this.enterState(states_exports.EXPRESSION);
445
- expr.terminatedByWhitespace = true;
446
- expr.terminator = this.isConcise ? CONCISE_VALUE_TERMINATORS : HTML_VALUE_TERMINATORS;
447
- } else if (code === 40 /* OPEN_PAREN */) {
448
- ensureAttrName(this, attr);
449
- attr.stage = 3 /* ARGUMENT */;
450
- this.pos++;
451
- this.forward = 0;
452
- this.enterState(states_exports.EXPRESSION).terminator = 41 /* CLOSE_PAREN */;
453
- } else if (code === 123 /* OPEN_CURLY_BRACE */ && attr.args) {
454
- ensureAttrName(this, attr);
455
- attr.stage = 4 /* BLOCK */;
456
- this.pos++;
457
- this.forward = 0;
458
- const expr = this.enterState(states_exports.EXPRESSION);
459
- expr.terminatedByWhitespace = false;
460
- expr.terminator = 125 /* CLOSE_CURLY_BRACE */;
461
- } else if (attr.stage === 0 /* UNKNOWN */) {
462
- attr.stage = 1 /* NAME */;
463
- this.forward = 0;
464
- const expr = this.enterState(states_exports.EXPRESSION);
465
- expr.terminatedByWhitespace = true;
466
- expr.skipOperators = true;
467
- expr.terminator = this.isConcise ? CONCISE_NAME_TERMINATORS : HTML_NAME_TERMINATORS;
468
- } else {
469
- this.exitState();
457
+ case 1 /* text */:
458
+ if (this.isConcise) {
459
+ this.enterState(states_exports.CONCISE_HTML_CONTENT);
460
+ } else {
461
+ this.enterState(states_exports.PARSED_TEXT_CONTENT);
462
+ }
463
+ break;
470
464
  }
471
465
  },
472
- eol() {
473
- if (this.isConcise) {
466
+ eol(_, tag) {
467
+ if (this.isConcise && tag.stage !== 4 /* ATTR_GROUP */) {
474
468
  this.exitState();
475
469
  }
476
470
  },
477
- eof(attr) {
471
+ eof(tag) {
478
472
  if (this.isConcise) {
473
+ if (tag.stage === 4 /* ATTR_GROUP */) {
474
+ this.emitError(
475
+ tag,
476
+ 19 /* MALFORMED_OPEN_TAG */,
477
+ 'EOF reached while within an attribute group (e.g. "[ ... ]").'
478
+ );
479
+ return;
480
+ }
479
481
  this.exitState();
480
482
  } else {
481
- 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');
483
+ this.emitError(
484
+ tag,
485
+ 19 /* MALFORMED_OPEN_TAG */,
486
+ "EOF reached while parsing open tag"
487
+ );
482
488
  }
483
489
  },
484
- return(child, attr) {
485
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
486
- switch (attr.stage) {
487
- case 1 /* NAME */: {
488
- attr.name = {
489
- start: child.start,
490
- end: child.end
491
- };
492
- (_b = (_a = this.options).onAttrName) == null ? void 0 : _b.call(_a, attr.name);
493
- break;
490
+ char(code, tag) {
491
+ if (this.isConcise) {
492
+ if (code === 59 /* SEMICOLON */) {
493
+ this.pos++;
494
+ this.exitState();
495
+ if (!this.consumeWhitespaceOnLine(0)) {
496
+ switch (this.lookAtCharCodeAhead(0)) {
497
+ case 47 /* FORWARD_SLASH */:
498
+ switch (this.lookAtCharCodeAhead(1)) {
499
+ case 47 /* FORWARD_SLASH */:
500
+ this.enterState(states_exports.JS_COMMENT_LINE);
501
+ this.pos += 2;
502
+ return;
503
+ case 42 /* ASTERISK */:
504
+ this.enterState(states_exports.JS_COMMENT_BLOCK);
505
+ this.pos += 2;
506
+ return;
507
+ }
508
+ break;
509
+ case 60 /* OPEN_ANGLE_BRACKET */:
510
+ if (this.lookAheadFor("!--")) {
511
+ this.enterState(states_exports.HTML_COMMENT);
512
+ this.pos += 4;
513
+ return;
514
+ }
515
+ break;
516
+ }
517
+ this.emitError(
518
+ this.pos,
519
+ 5 /* INVALID_CODE_AFTER_SEMICOLON */,
520
+ "A semicolon indicates the end of a line. Only comments may follow it."
521
+ );
522
+ }
523
+ return;
494
524
  }
495
- case 3 /* ARGUMENT */: {
496
- if (attr.args) {
497
- this.emitError(child, 1 /* INVALID_ATTRIBUTE_ARGUMENT */, "An attribute can only have one set of arguments");
525
+ if (code === 45 /* HTML_BLOCK_DELIMITER */) {
526
+ if (this.lookAtCharCodeAhead(1) !== 45 /* HTML_BLOCK_DELIMITER */) {
527
+ this.emitError(
528
+ tag,
529
+ 19 /* MALFORMED_OPEN_TAG */,
530
+ '"-" not allowed as first character of attribute name'
531
+ );
498
532
  return;
499
533
  }
500
- const start = child.start - 1;
501
- const end = ++this.pos;
502
- const value = {
503
- start: child.start,
504
- end: child.end
505
- };
506
- if (this.consumeWhitespaceIfBefore("{")) {
507
- attr.args = {
508
- start,
509
- end,
510
- value
511
- };
512
- } else {
513
- attr.args = true;
514
- (_d = (_c = this.options).onAttrArgs) == null ? void 0 : _d.call(_c, {
515
- start,
516
- end,
517
- value
518
- });
534
+ if (tag.stage === 4 /* ATTR_GROUP */) {
535
+ this.emitError(
536
+ this.pos,
537
+ 19 /* MALFORMED_OPEN_TAG */,
538
+ "Attribute group was not properly ended"
539
+ );
540
+ return;
519
541
  }
520
- break;
521
- }
522
- case 4 /* BLOCK */: {
523
- const params = attr.args;
524
- const start = params.start;
525
- const end = ++this.pos;
526
- (_f = (_e = this.options).onAttrMethod) == null ? void 0 : _f.call(_e, {
527
- start,
528
- end,
529
- params,
530
- body: {
531
- start: child.start - 1,
532
- end,
533
- value: {
534
- start: child.start,
535
- end: child.end
536
- }
537
- }
538
- });
539
542
  this.exitState();
540
- break;
541
- }
542
- case 2 /* VALUE */: {
543
- if (child.start === child.end) {
544
- return this.emitError(child, 3 /* INVALID_ATTRIBUTE_VALUE */, "Missing value for attribute");
543
+ const maxPos = this.maxPos;
544
+ let curPos = this.pos + 1;
545
+ while (curPos < maxPos && this.data.charCodeAt(++curPos) !== 10 /* NEWLINE */)
546
+ ;
547
+ const indentStart = ++curPos;
548
+ while (curPos < maxPos) {
549
+ const nextCode = this.data.charCodeAt(curPos);
550
+ if (nextCode === 32 /* SPACE */ || nextCode === 9 /* TAB */) {
551
+ curPos++;
552
+ } else {
553
+ break;
554
+ }
545
555
  }
546
- if (attr.spread) {
547
- (_h = (_g = this.options).onAttrSpread) == null ? void 0 : _h.call(_g, {
548
- start: attr.valueStart,
549
- end: child.end,
550
- value: {
551
- start: child.start,
552
- end: child.end
553
- }
554
- });
555
- } else {
556
- (_j = (_i = this.options).onAttrValue) == null ? void 0 : _j.call(_i, {
557
- start: attr.valueStart,
558
- end: child.end,
559
- bound: attr.bound,
560
- value: {
561
- start: child.start,
562
- end: child.end
563
- }
564
- });
556
+ const indentSize = curPos - indentStart;
557
+ if (indentSize > this.indent.length) {
558
+ this.indent = this.data.slice(indentStart, curPos);
565
559
  }
566
- this.exitState();
567
- break;
560
+ this.enterState(states_exports.BEGIN_DELIMITED_HTML_BLOCK);
561
+ return;
562
+ } else if (code === 91 /* OPEN_SQUARE_BRACKET */) {
563
+ if (tag.stage === 4 /* ATTR_GROUP */) {
564
+ this.emitError(
565
+ this.pos,
566
+ 19 /* MALFORMED_OPEN_TAG */,
567
+ 'Unexpected "[" character within open tag.'
568
+ );
569
+ return;
570
+ }
571
+ tag.stage = 4 /* ATTR_GROUP */;
572
+ return;
573
+ } else if (code === 93 /* CLOSE_SQUARE_BRACKET */) {
574
+ if (tag.stage !== 4 /* ATTR_GROUP */) {
575
+ this.emitError(
576
+ this.pos,
577
+ 19 /* MALFORMED_OPEN_TAG */,
578
+ 'Unexpected "]" character within open tag.'
579
+ );
580
+ return;
581
+ }
582
+ tag.stage = 0 /* UNKNOWN */;
583
+ return;
584
+ }
585
+ } else if (code === 62 /* CLOSE_ANGLE_BRACKET */) {
586
+ this.pos++;
587
+ this.exitState();
588
+ return;
589
+ } else if (code === 47 /* FORWARD_SLASH */ && this.lookAtCharCodeAhead(1) === 62 /* CLOSE_ANGLE_BRACKET */) {
590
+ tag.selfClosed = true;
591
+ this.pos += 2;
592
+ this.exitState();
593
+ return;
594
+ }
595
+ if (code === 60 /* OPEN_ANGLE_BRACKET */) {
596
+ return this.emitError(
597
+ this.pos,
598
+ 2 /* INVALID_ATTRIBUTE_NAME */,
599
+ 'Invalid attribute name. Attribute name cannot begin with the "<" character.'
600
+ );
601
+ }
602
+ if (code === 47 /* FORWARD_SLASH */) {
603
+ switch (this.lookAtCharCodeAhead(1)) {
604
+ case 47 /* FORWARD_SLASH */:
605
+ this.enterState(states_exports.JS_COMMENT_LINE);
606
+ this.pos++;
607
+ return;
608
+ case 42 /* ASTERISK */:
609
+ this.enterState(states_exports.JS_COMMENT_BLOCK);
610
+ this.pos++;
611
+ return;
612
+ }
613
+ }
614
+ if (isWhitespaceCode(code)) {
615
+ } else if (code === 44 /* COMMA */) {
616
+ this.pos++;
617
+ this.forward = 0;
618
+ this.consumeWhitespace();
619
+ } else if (code === 47 /* FORWARD_SLASH */ && !tag.hasAttrs) {
620
+ tag.stage = 1 /* VAR */;
621
+ this.pos++;
622
+ this.forward = 0;
623
+ if (isWhitespaceCode(this.lookAtCharCodeAhead(0))) {
624
+ return this.emitError(
625
+ this.pos,
626
+ 23 /* MISSING_TAG_VARIABLE */,
627
+ "A slash was found that was not followed by a variable name or lhs expression"
628
+ );
629
+ }
630
+ const expr = this.enterState(states_exports.EXPRESSION);
631
+ expr.operators = true;
632
+ expr.terminatedByWhitespace = true;
633
+ expr.shouldTerminate = this.isConcise ? shouldTerminateConciseTagVar : shouldTerminateHtmlTagVar;
634
+ } else if (code === 40 /* OPEN_PAREN */ && !tag.hasAttrs) {
635
+ if (tag.hasArgs) {
636
+ this.emitError(
637
+ this.pos,
638
+ 11 /* INVALID_TAG_ARGUMENT */,
639
+ "A tag can only have one argument"
640
+ );
641
+ return;
642
+ }
643
+ tag.stage = 2 /* ARGUMENT */;
644
+ this.pos++;
645
+ this.forward = 0;
646
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseParen;
647
+ } else if (code === 124 /* PIPE */ && !tag.hasAttrs) {
648
+ tag.stage = 3 /* PARAMS */;
649
+ this.pos++;
650
+ this.forward = 0;
651
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesPipe;
652
+ } else {
653
+ this.forward = 0;
654
+ if (tag.tagName) {
655
+ this.enterState(states_exports.ATTRIBUTE);
656
+ tag.hasAttrs = true;
657
+ } else {
658
+ this.enterState(states_exports.TAG_NAME);
659
+ }
660
+ }
661
+ },
662
+ return(child, tag) {
663
+ var _a, _b, _c, _d, _e, _f;
664
+ switch (child.state) {
665
+ case states_exports.JS_COMMENT_BLOCK: {
666
+ break;
667
+ }
668
+ case states_exports.EXPRESSION: {
669
+ switch (tag.stage) {
670
+ case 1 /* VAR */: {
671
+ if (child.start === child.end) {
672
+ return this.emitError(
673
+ child,
674
+ 23 /* MISSING_TAG_VARIABLE */,
675
+ "A slash was found that was not followed by a variable name or lhs expression"
676
+ );
677
+ }
678
+ (_b = (_a = this.options).onTagVar) == null ? void 0 : _b.call(_a, {
679
+ start: child.start - 1,
680
+ end: child.end,
681
+ value: {
682
+ start: child.start,
683
+ end: child.end
684
+ }
685
+ });
686
+ break;
687
+ }
688
+ case 2 /* ARGUMENT */: {
689
+ const start = child.start - 1;
690
+ const end = ++this.pos;
691
+ const value = {
692
+ start: child.start,
693
+ end: child.end
694
+ };
695
+ if (this.consumeWhitespaceIfBefore("{")) {
696
+ const attr = this.enterState(states_exports.ATTRIBUTE);
697
+ attr.start = start;
698
+ attr.args = { start, end, value };
699
+ tag.hasAttrs = true;
700
+ this.forward = 0;
701
+ } else {
702
+ tag.hasArgs = true;
703
+ (_d = (_c = this.options).onTagArgs) == null ? void 0 : _d.call(_c, {
704
+ start,
705
+ end,
706
+ value
707
+ });
708
+ }
709
+ break;
710
+ }
711
+ case 3 /* PARAMS */: {
712
+ const end = ++this.pos;
713
+ (_f = (_e = this.options).onTagParams) == null ? void 0 : _f.call(_e, {
714
+ start: child.start - 1,
715
+ end,
716
+ value: {
717
+ start: child.start,
718
+ end: child.end
719
+ }
720
+ });
721
+ break;
722
+ }
723
+ }
724
+ break;
568
725
  }
569
726
  }
570
727
  }
571
728
  };
572
- function ensureAttrName(parser, attr) {
573
- var _a, _b;
574
- if (!attr.name) {
575
- (_b = (_a = parser.options).onAttrName) == null ? void 0 : _b.call(_a, {
576
- start: attr.start,
577
- end: attr.start
578
- });
729
+ function shouldTerminateConciseTagVar(code, data, pos) {
730
+ switch (code) {
731
+ case 44 /* COMMA */:
732
+ case 61 /* EQUAL */:
733
+ case 124 /* PIPE */:
734
+ case 40 /* OPEN_PAREN */:
735
+ case 59 /* SEMICOLON */:
736
+ return true;
737
+ case 58 /* COLON */:
738
+ return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
739
+ default:
740
+ return false;
741
+ }
742
+ }
743
+ function shouldTerminateHtmlTagVar(code, data, pos) {
744
+ switch (code) {
745
+ case 124 /* PIPE */:
746
+ case 44 /* COMMA */:
747
+ case 61 /* EQUAL */:
748
+ case 40 /* OPEN_PAREN */:
749
+ case 62 /* CLOSE_ANGLE_BRACKET */:
750
+ return true;
751
+ case 58 /* COLON */:
752
+ return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
753
+ case 47 /* FORWARD_SLASH */:
754
+ return data.charCodeAt(pos + 1) === 62 /* CLOSE_ANGLE_BRACKET */;
755
+ default:
756
+ return false;
579
757
  }
580
758
  }
581
759
 
582
- // src/states/BEGIN_DELIMITED_HTML_BLOCK.ts
583
- var BEGIN_DELIMITED_HTML_BLOCK = {
584
- name: "BEGIN_DELIMITED_HTML_BLOCK",
760
+ // src/states/ATTRIBUTE.ts
761
+ var ATTRIBUTE = {
762
+ name: "ATTRIBUTE",
585
763
  enter(parent, start) {
586
- return {
587
- state: BEGIN_DELIMITED_HTML_BLOCK,
764
+ return this.activeAttr = {
765
+ state: ATTRIBUTE,
588
766
  parent,
589
767
  start,
590
768
  end: start,
591
- indent: this.indent,
592
- delimiter: ""
769
+ valueStart: start,
770
+ stage: 0 /* UNKNOWN */,
771
+ name: void 0,
772
+ args: false,
773
+ bound: false,
774
+ spread: false
593
775
  };
594
776
  },
595
777
  exit() {
778
+ this.activeAttr = void 0;
596
779
  },
597
- char(code, block) {
598
- if (code === 45 /* HTML_BLOCK_DELIMITER */) {
599
- block.delimiter += "-";
600
- } else {
601
- const startPos = this.pos;
602
- if (!this.consumeWhitespaceOnLine()) {
603
- this.pos = startPos + 1;
604
- this.forward = 0;
605
- this.beginHtmlBlock(void 0, true);
780
+ char(code, attr) {
781
+ if (isWhitespaceCode(code)) {
782
+ return;
783
+ } else if (code === 61 /* EQUAL */ || code === 58 /* COLON */ && this.lookAtCharCodeAhead(1) === 61 /* EQUAL */ || code === 46 /* PERIOD */ && this.lookAheadFor("..")) {
784
+ attr.valueStart = this.pos;
785
+ this.forward = 0;
786
+ if (code === 58 /* COLON */) {
787
+ ensureAttrName(this, attr);
788
+ attr.bound = true;
789
+ this.pos += 2;
790
+ this.consumeWhitespace();
791
+ } else if (code === 46 /* PERIOD */) {
792
+ attr.spread = true;
793
+ this.pos += 3;
794
+ } else {
795
+ ensureAttrName(this, attr);
796
+ this.pos++;
797
+ this.consumeWhitespace();
606
798
  }
799
+ attr.stage = 2 /* VALUE */;
800
+ const expr = this.enterState(states_exports.EXPRESSION);
801
+ expr.operators = true;
802
+ expr.terminatedByWhitespace = true;
803
+ expr.shouldTerminate = this.isConcise ? this.activeTag.stage === 4 /* ATTR_GROUP */ ? shouldTerminateConciseGroupedAttrValue : shouldTerminateConciseAttrValue : shouldTerminateHtmlAttrValue;
804
+ } else if (code === 40 /* OPEN_PAREN */) {
805
+ ensureAttrName(this, attr);
806
+ attr.stage = 3 /* ARGUMENT */;
807
+ this.pos++;
808
+ this.forward = 0;
809
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseParen;
810
+ } else if (code === 123 /* OPEN_CURLY_BRACE */ && attr.args) {
811
+ ensureAttrName(this, attr);
812
+ attr.stage = 4 /* BLOCK */;
813
+ this.pos++;
814
+ this.forward = 0;
815
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseCurlyBrace;
816
+ } else if (attr.stage === 0 /* UNKNOWN */) {
817
+ attr.stage = 1 /* NAME */;
818
+ this.forward = 0;
819
+ const expr = this.enterState(states_exports.EXPRESSION);
820
+ expr.terminatedByWhitespace = true;
821
+ expr.shouldTerminate = this.isConcise ? this.activeTag.stage === 4 /* ATTR_GROUP */ ? shouldTerminateConciseGroupedAttrName : shouldTerminateConciseAttrName : shouldTerminateHtmlAttrName;
822
+ } else {
823
+ this.exitState();
607
824
  }
608
825
  },
609
- eol(len, block) {
610
- this.beginHtmlBlock(block.delimiter, false);
611
- handleDelimitedBlockEOL(this, len, block);
826
+ eol() {
827
+ if (this.isConcise) {
828
+ this.exitState();
829
+ }
612
830
  },
613
- eof: htmlEOF,
614
- return() {
615
- }
616
- };
617
- function handleDelimitedEOL(parser, newLineLength, content) {
618
- if (content.singleLine) {
619
- parser.endText();
620
- parser.exitState();
621
- parser.exitState();
622
- return true;
623
- }
624
- if (content.delimiter) {
625
- handleDelimitedBlockEOL(parser, newLineLength, content);
626
- return true;
627
- }
628
- return false;
629
- }
630
- function handleDelimitedBlockEOL(parser, newLineLength, {
631
- indent,
632
- delimiter
633
- }) {
634
- const endHtmlBlockLookahead = indent + delimiter;
635
- if (parser.lookAheadFor(endHtmlBlockLookahead, parser.pos + newLineLength)) {
636
- parser.startText();
637
- parser.pos += newLineLength;
638
- parser.endText();
639
- parser.pos += endHtmlBlockLookahead.length;
640
- if (parser.consumeWhitespaceOnLine(0)) {
641
- parser.endText();
642
- parser.exitState();
643
- parser.exitState();
831
+ eof(attr) {
832
+ if (this.isConcise) {
833
+ this.exitState();
644
834
  } else {
645
- parser.emitError(parser.pos, 4 /* INVALID_CHARACTER */, "A concise mode closing block delimiter can only be followed by whitespace.");
835
+ this.emitError(
836
+ attr,
837
+ 19 /* MALFORMED_OPEN_TAG */,
838
+ 'EOF reached while parsing attribute "' + (attr.name ? this.read(attr.name) : "default") + '" for the "' + this.read(this.activeTag.tagName) + '" tag'
839
+ );
646
840
  }
647
- } else if (parser.lookAheadFor(indent, parser.pos + newLineLength)) {
648
- parser.startText();
649
- parser.pos += indent.length;
650
- } else if (indent && !parser.onlyWhitespaceRemainsOnLine(newLineLength)) {
651
- parser.endText();
652
- parser.exitState();
653
- parser.exitState();
654
- } else {
655
- parser.startText();
656
- }
657
- }
658
-
659
- // src/states/CDATA.ts
660
- var CDATA = {
661
- name: "CDATA",
662
- enter(parent, start) {
663
- return {
664
- state: CDATA,
665
- parent,
841
+ },
842
+ return(child, attr) {
843
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
844
+ switch (attr.stage) {
845
+ case 1 /* NAME */: {
846
+ attr.name = {
847
+ start: child.start,
848
+ end: child.end
849
+ };
850
+ (_b = (_a = this.options).onAttrName) == null ? void 0 : _b.call(_a, attr.name);
851
+ break;
852
+ }
853
+ case 3 /* ARGUMENT */: {
854
+ if (attr.args) {
855
+ this.emitError(
856
+ child,
857
+ 1 /* INVALID_ATTRIBUTE_ARGUMENT */,
858
+ "An attribute can only have one set of arguments"
859
+ );
860
+ return;
861
+ }
862
+ const start = child.start - 1;
863
+ const end = ++this.pos;
864
+ const value = {
865
+ start: child.start,
866
+ end: child.end
867
+ };
868
+ if (this.consumeWhitespaceIfBefore("{")) {
869
+ attr.args = {
870
+ start,
871
+ end,
872
+ value
873
+ };
874
+ } else {
875
+ attr.args = true;
876
+ (_d = (_c = this.options).onAttrArgs) == null ? void 0 : _d.call(_c, {
877
+ start,
878
+ end,
879
+ value
880
+ });
881
+ }
882
+ break;
883
+ }
884
+ case 4 /* BLOCK */: {
885
+ const params = attr.args;
886
+ const start = params.start;
887
+ const end = ++this.pos;
888
+ (_f = (_e = this.options).onAttrMethod) == null ? void 0 : _f.call(_e, {
889
+ start,
890
+ end,
891
+ params,
892
+ body: {
893
+ start: child.start - 1,
894
+ end,
895
+ value: {
896
+ start: child.start,
897
+ end: child.end
898
+ }
899
+ }
900
+ });
901
+ this.exitState();
902
+ break;
903
+ }
904
+ case 2 /* VALUE */: {
905
+ if (child.start === child.end) {
906
+ return this.emitError(
907
+ child,
908
+ 3 /* INVALID_ATTRIBUTE_VALUE */,
909
+ "Missing value for attribute"
910
+ );
911
+ }
912
+ if (attr.spread) {
913
+ (_h = (_g = this.options).onAttrSpread) == null ? void 0 : _h.call(_g, {
914
+ start: attr.valueStart,
915
+ end: child.end,
916
+ value: {
917
+ start: child.start,
918
+ end: child.end
919
+ }
920
+ });
921
+ } else {
922
+ (_j = (_i = this.options).onAttrValue) == null ? void 0 : _j.call(_i, {
923
+ start: attr.valueStart,
924
+ end: child.end,
925
+ bound: attr.bound,
926
+ value: {
927
+ start: child.start,
928
+ end: child.end
929
+ }
930
+ });
931
+ }
932
+ this.exitState();
933
+ break;
934
+ }
935
+ }
936
+ }
937
+ };
938
+ function ensureAttrName(parser, attr) {
939
+ var _a, _b;
940
+ if (!attr.name) {
941
+ (_b = (_a = parser.options).onAttrName) == null ? void 0 : _b.call(_a, {
942
+ start: attr.start,
943
+ end: attr.start
944
+ });
945
+ }
946
+ }
947
+ function shouldTerminateHtmlAttrName(code, data, pos) {
948
+ switch (code) {
949
+ case 44 /* COMMA */:
950
+ case 61 /* EQUAL */:
951
+ case 40 /* OPEN_PAREN */:
952
+ case 62 /* CLOSE_ANGLE_BRACKET */:
953
+ return true;
954
+ case 58 /* COLON */:
955
+ return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
956
+ case 47 /* FORWARD_SLASH */:
957
+ return data.charCodeAt(pos + 1) === 62 /* CLOSE_ANGLE_BRACKET */;
958
+ default:
959
+ return false;
960
+ }
961
+ }
962
+ function shouldTerminateHtmlAttrValue(code, data, pos) {
963
+ switch (code) {
964
+ case 44 /* COMMA */:
965
+ return true;
966
+ case 47 /* FORWARD_SLASH */:
967
+ return data.charCodeAt(pos + 1) === 62 /* CLOSE_ANGLE_BRACKET */;
968
+ case 62 /* CLOSE_ANGLE_BRACKET */:
969
+ return data.charCodeAt(pos - 1) !== 61 /* EQUAL */;
970
+ default:
971
+ return false;
972
+ }
973
+ }
974
+ function shouldTerminateConciseAttrName(code, data, pos) {
975
+ switch (code) {
976
+ case 44 /* COMMA */:
977
+ case 61 /* EQUAL */:
978
+ case 40 /* OPEN_PAREN */:
979
+ case 59 /* SEMICOLON */:
980
+ return true;
981
+ case 58 /* COLON */:
982
+ return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
983
+ case 45 /* HYPHEN */:
984
+ return data.charCodeAt(pos + 1) === 45 /* HYPHEN */ && isWhitespaceCode(data.charCodeAt(pos - 1));
985
+ default:
986
+ return false;
987
+ }
988
+ }
989
+ function shouldTerminateConciseAttrValue(code, data, pos) {
990
+ switch (code) {
991
+ case 44 /* COMMA */:
992
+ case 59 /* SEMICOLON */:
993
+ return true;
994
+ case 45 /* HYPHEN */:
995
+ return data.charCodeAt(pos + 1) === 45 /* HYPHEN */ && isWhitespaceCode(data.charCodeAt(pos - 1));
996
+ default:
997
+ return false;
998
+ }
999
+ }
1000
+ function shouldTerminateConciseGroupedAttrName(code, data, pos) {
1001
+ switch (code) {
1002
+ case 44 /* COMMA */:
1003
+ case 61 /* EQUAL */:
1004
+ case 40 /* OPEN_PAREN */:
1005
+ case 93 /* CLOSE_SQUARE_BRACKET */:
1006
+ return true;
1007
+ case 58 /* COLON */:
1008
+ return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
1009
+ default:
1010
+ return false;
1011
+ }
1012
+ }
1013
+ function shouldTerminateConciseGroupedAttrValue(code) {
1014
+ switch (code) {
1015
+ case 44 /* COMMA */:
1016
+ case 93 /* CLOSE_SQUARE_BRACKET */:
1017
+ return true;
1018
+ default:
1019
+ return false;
1020
+ }
1021
+ }
1022
+
1023
+ // src/states/BEGIN_DELIMITED_HTML_BLOCK.ts
1024
+ var BEGIN_DELIMITED_HTML_BLOCK = {
1025
+ name: "BEGIN_DELIMITED_HTML_BLOCK",
1026
+ enter(parent, start) {
1027
+ return {
1028
+ state: BEGIN_DELIMITED_HTML_BLOCK,
1029
+ parent,
1030
+ start,
1031
+ end: start,
1032
+ indent: this.indent,
1033
+ delimiter: ""
1034
+ };
1035
+ },
1036
+ exit() {
1037
+ },
1038
+ char(code, block) {
1039
+ if (code === 45 /* HTML_BLOCK_DELIMITER */) {
1040
+ block.delimiter += "-";
1041
+ } else {
1042
+ const startPos = this.pos;
1043
+ if (!this.consumeWhitespaceOnLine()) {
1044
+ this.pos = startPos + 1;
1045
+ this.forward = 0;
1046
+ this.beginHtmlBlock(void 0, true);
1047
+ }
1048
+ }
1049
+ },
1050
+ eol(len, block) {
1051
+ this.beginHtmlBlock(block.delimiter, false);
1052
+ handleDelimitedBlockEOL(this, len, block);
1053
+ },
1054
+ eof: htmlEOF,
1055
+ return() {
1056
+ }
1057
+ };
1058
+ function handleDelimitedEOL(parser, newLineLength, content) {
1059
+ if (content.singleLine) {
1060
+ parser.endText();
1061
+ parser.exitState();
1062
+ parser.exitState();
1063
+ return true;
1064
+ }
1065
+ if (content.delimiter) {
1066
+ handleDelimitedBlockEOL(parser, newLineLength, content);
1067
+ return true;
1068
+ }
1069
+ return false;
1070
+ }
1071
+ function handleDelimitedBlockEOL(parser, newLineLength, {
1072
+ indent,
1073
+ delimiter
1074
+ }) {
1075
+ const endHtmlBlockLookahead = indent + delimiter;
1076
+ if (parser.lookAheadFor(endHtmlBlockLookahead, parser.pos + newLineLength)) {
1077
+ parser.startText();
1078
+ parser.pos += newLineLength;
1079
+ parser.endText();
1080
+ parser.pos += endHtmlBlockLookahead.length;
1081
+ if (parser.consumeWhitespaceOnLine(0)) {
1082
+ parser.endText();
1083
+ parser.exitState();
1084
+ parser.exitState();
1085
+ } else {
1086
+ parser.emitError(
1087
+ parser.pos,
1088
+ 4 /* INVALID_CHARACTER */,
1089
+ "A concise mode closing block delimiter can only be followed by whitespace."
1090
+ );
1091
+ }
1092
+ } else if (parser.lookAheadFor(indent, parser.pos + newLineLength)) {
1093
+ parser.startText();
1094
+ parser.pos += indent.length;
1095
+ } else if (indent && !parser.onlyWhitespaceRemainsOnLine(newLineLength)) {
1096
+ parser.endText();
1097
+ parser.exitState();
1098
+ parser.exitState();
1099
+ } else {
1100
+ parser.startText();
1101
+ }
1102
+ }
1103
+
1104
+ // src/states/CDATA.ts
1105
+ var CDATA = {
1106
+ name: "CDATA",
1107
+ enter(parent, start) {
1108
+ return {
1109
+ state: CDATA,
1110
+ parent,
666
1111
  start,
667
1112
  end: start
668
1113
  };
@@ -688,7 +1133,11 @@ var CDATA = {
688
1133
  eol() {
689
1134
  },
690
1135
  eof(cdata) {
691
- this.emitError(cdata, 14 /* MALFORMED_CDATA */, "EOF reached while parsing CDATA");
1136
+ this.emitError(
1137
+ cdata,
1138
+ 14 /* MALFORMED_CDATA */,
1139
+ "EOF reached while parsing CDATA"
1140
+ );
692
1141
  },
693
1142
  return() {
694
1143
  }
@@ -727,7 +1176,11 @@ var CLOSE_TAG = {
727
1176
  eol() {
728
1177
  },
729
1178
  eof(closeTag) {
730
- this.emitError(closeTag, 15 /* MALFORMED_CLOSE_TAG */, "EOF reached while parsing closing tag");
1179
+ this.emitError(
1180
+ closeTag,
1181
+ 15 /* MALFORMED_CLOSE_TAG */,
1182
+ "EOF reached while parsing closing tag"
1183
+ );
731
1184
  },
732
1185
  return() {
733
1186
  }
@@ -769,7 +1222,11 @@ function ensureExpectedCloseTag(parser, closeTag) {
769
1222
  const closeTagNameStart = closeTag.start + 2;
770
1223
  const closeTagNameEnd = closeTag.end - 1;
771
1224
  if (!activeTag) {
772
- parser.emitError(closeTag, 0 /* EXTRA_CLOSING_TAG */, 'The closing "' + parser.read({ start: closeTagNameStart, end: closeTagNameEnd }) + '" tag was not expected');
1225
+ parser.emitError(
1226
+ closeTag,
1227
+ 0 /* EXTRA_CLOSING_TAG */,
1228
+ 'The closing "' + parser.read({ start: closeTagNameStart, end: closeTagNameEnd }) + '" tag was not expected'
1229
+ );
773
1230
  return false;
774
1231
  }
775
1232
  const closeTagNamePos = {
@@ -777,12 +1234,19 @@ function ensureExpectedCloseTag(parser, closeTag) {
777
1234
  end: closeTagNameEnd
778
1235
  };
779
1236
  if (closeTagNameStart < closeTagNameEnd) {
780
- if (!parser.matchAtPos(closeTagNamePos, activeTag.tagName.end > activeTag.tagName.start ? activeTag.tagName : "div")) {
1237
+ if (!parser.matchAtPos(
1238
+ closeTagNamePos,
1239
+ activeTag.tagName.end > activeTag.tagName.start ? activeTag.tagName : "div"
1240
+ )) {
781
1241
  if (activeTag.shorthandEnd === void 0 || !parser.matchAtPos(closeTagNamePos, {
782
1242
  start: activeTag.tagName.start,
783
1243
  end: activeTag.shorthandEnd
784
1244
  })) {
785
- 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');
1245
+ parser.emitError(
1246
+ closeTag,
1247
+ 21 /* MISMATCHED_CLOSING_TAG */,
1248
+ 'The closing "' + parser.read(closeTagNamePos) + '" tag does not match the corresponding opening "' + (parser.read(activeTag.tagName) || "div") + '" tag'
1249
+ );
786
1250
  return false;
787
1251
  }
788
1252
  }
@@ -818,18 +1282,30 @@ var CONCISE_HTML_CONTENT = {
818
1282
  parentTag = this.activeTag;
819
1283
  }
820
1284
  if (!parentTag && curIndent) {
821
- this.emitError(this.pos, 7 /* INVALID_INDENTATION */, "Line has extra indentation at the beginning");
1285
+ this.emitError(
1286
+ this.pos,
1287
+ 7 /* INVALID_INDENTATION */,
1288
+ "Line has extra indentation at the beginning"
1289
+ );
822
1290
  return;
823
1291
  }
824
1292
  if (parentTag) {
825
1293
  if (parentTag.type === 1 /* text */ && code !== 45 /* HTML_BLOCK_DELIMITER */) {
826
- this.emitError(this.pos, 8 /* INVALID_LINE_START */, 'A line within a tag that only allows text content must begin with a "-" character');
1294
+ this.emitError(
1295
+ this.pos,
1296
+ 8 /* INVALID_LINE_START */,
1297
+ 'A line within a tag that only allows text content must begin with a "-" character'
1298
+ );
827
1299
  return;
828
1300
  }
829
1301
  if (parentTag.nestedIndent === void 0) {
830
1302
  parentTag.nestedIndent = this.indent;
831
1303
  } else if (parentTag.nestedIndent !== this.indent) {
832
- this.emitError(this.pos, 7 /* INVALID_INDENTATION */, "Line indentation does match indentation of previous line");
1304
+ this.emitError(
1305
+ this.pos,
1306
+ 7 /* INVALID_INDENTATION */,
1307
+ "Line indentation does match indentation of previous line"
1308
+ );
833
1309
  return;
834
1310
  }
835
1311
  }
@@ -851,7 +1327,11 @@ var CONCISE_HTML_CONTENT = {
851
1327
  this.enterState(states_exports.BEGIN_DELIMITED_HTML_BLOCK);
852
1328
  this.pos--;
853
1329
  } else {
854
- 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');
1330
+ this.emitError(
1331
+ this.pos,
1332
+ 8 /* INVALID_LINE_START */,
1333
+ 'A line in concise mode cannot start with a single hyphen. Use "--" instead. See: https://github.com/marko-js/htmljs-parser/issues/43'
1334
+ );
855
1335
  }
856
1336
  return;
857
1337
  case 47 /* FORWARD_SLASH */:
@@ -865,7 +1345,11 @@ var CONCISE_HTML_CONTENT = {
865
1345
  this.pos++;
866
1346
  return;
867
1347
  default:
868
- this.emitError(this.pos, 8 /* INVALID_LINE_START */, 'A line in concise mode cannot start with "/" unless it starts a "//" or "/*" comment');
1348
+ this.emitError(
1349
+ this.pos,
1350
+ 8 /* INVALID_LINE_START */,
1351
+ 'A line in concise mode cannot start with "/" unless it starts a "//" or "/*" comment'
1352
+ );
869
1353
  return;
870
1354
  }
871
1355
  }
@@ -902,7 +1386,11 @@ var CONCISE_HTML_CONTENT = {
902
1386
  }
903
1387
  });
904
1388
  if (!this.consumeWhitespaceOnLine(0)) {
905
- this.emitError(this.pos, 4 /* INVALID_CHARACTER */, "In concise mode a javascript comment block can only be followed by whitespace characters and a newline.");
1389
+ this.emitError(
1390
+ this.pos,
1391
+ 4 /* INVALID_CHARACTER */,
1392
+ "In concise mode a javascript comment block can only be followed by whitespace characters and a newline."
1393
+ );
906
1394
  }
907
1395
  break;
908
1396
  }
@@ -936,7 +1424,11 @@ var DECLARATION = {
936
1424
  eol() {
937
1425
  },
938
1426
  eof(declaration) {
939
- this.emitError(declaration, 17 /* MALFORMED_DECLARATION */, "EOF reached while parsing declaration");
1427
+ this.emitError(
1428
+ declaration,
1429
+ 17 /* MALFORMED_DECLARATION */,
1430
+ "EOF reached while parsing declaration"
1431
+ );
940
1432
  },
941
1433
  return() {
942
1434
  }
@@ -987,16 +1479,29 @@ var DTD = {
987
1479
  eol() {
988
1480
  },
989
1481
  eof(documentType) {
990
- this.emitError(documentType, 18 /* MALFORMED_DOCUMENT_TYPE */, "EOF reached while parsing document type");
1482
+ this.emitError(
1483
+ documentType,
1484
+ 18 /* MALFORMED_DOCUMENT_TYPE */,
1485
+ "EOF reached while parsing document type"
1486
+ );
991
1487
  },
992
1488
  return() {
993
1489
  }
994
1490
  };
995
1491
 
996
1492
  // src/states/EXPRESSION.ts
997
- var htmlAttrsPattern = buildPattern(0 /* HTML_ATTRS */);
998
- var conciseAttrsPattern = buildPattern(1 /* CONCISE_ATTRS */);
999
- var conciseAttrsGroupPattern = buildPattern(2 /* CONCISE_ATTRS_GROUP */);
1493
+ var shouldTerminate = () => false;
1494
+ var unaryKeywords = [
1495
+ "async",
1496
+ "await",
1497
+ "keyof",
1498
+ "class",
1499
+ "function",
1500
+ "new",
1501
+ "typeof",
1502
+ "void"
1503
+ ];
1504
+ var binaryKeywords = ["instanceof", "in", "as", "extends"];
1000
1505
  var EXPRESSION = {
1001
1506
  name: "EXPRESSION",
1002
1507
  enter(parent, start) {
@@ -1006,8 +1511,8 @@ var EXPRESSION = {
1006
1511
  start,
1007
1512
  end: start,
1008
1513
  groupStack: [],
1009
- terminator: -1,
1010
- skipOperators: false,
1514
+ shouldTerminate,
1515
+ operators: false,
1011
1516
  terminatedByEOL: false,
1012
1517
  terminatedByWhitespace: false
1013
1518
  };
@@ -1017,12 +1522,12 @@ var EXPRESSION = {
1017
1522
  char(code, expression) {
1018
1523
  if (!expression.groupStack.length) {
1019
1524
  if (expression.terminatedByWhitespace && isWhitespaceCode(code)) {
1020
- if (!checkForOperators(this, expression)) {
1525
+ if (!checkForOperators(this, expression, false)) {
1021
1526
  this.exitState();
1022
1527
  }
1023
1528
  return;
1024
1529
  }
1025
- if (typeof expression.terminator === "number" ? expression.terminator === code : checkForTerminators(this, code, expression.terminator)) {
1530
+ if (expression.shouldTerminate(code, this.data, this.pos)) {
1026
1531
  this.exitState();
1027
1532
  return;
1028
1533
  }
@@ -1048,7 +1553,7 @@ var EXPRESSION = {
1048
1553
  this.pos++;
1049
1554
  break;
1050
1555
  default: {
1051
- if (canCharCodeBeFollowedByDivision(this.getPreviousNonWhitespaceCharCode())) {
1556
+ if (canFollowDivision(this.getPreviousNonWhitespaceCharCode())) {
1052
1557
  this.pos++;
1053
1558
  this.consumeWhitespace();
1054
1559
  } else {
@@ -1071,18 +1576,26 @@ var EXPRESSION = {
1071
1576
  case 93 /* CLOSE_SQUARE_BRACKET */:
1072
1577
  case 125 /* CLOSE_CURLY_BRACE */: {
1073
1578
  if (!expression.groupStack.length) {
1074
- 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.');
1579
+ return this.emitError(
1580
+ expression,
1581
+ 6 /* INVALID_EXPRESSION */,
1582
+ 'Mismatched group. A closing "' + String.fromCharCode(code) + '" character was found but it is not matched with a corresponding opening character.'
1583
+ );
1075
1584
  }
1076
1585
  const expectedCode = expression.groupStack.pop();
1077
1586
  if (expectedCode !== code) {
1078
- return this.emitError(expression, 6 /* INVALID_EXPRESSION */, 'Mismatched group. A "' + String.fromCharCode(code) + '" character was found when "' + String.fromCharCode(expectedCode) + '" was expected.');
1587
+ return this.emitError(
1588
+ expression,
1589
+ 6 /* INVALID_EXPRESSION */,
1590
+ 'Mismatched group. A "' + String.fromCharCode(code) + '" character was found when "' + String.fromCharCode(expectedCode) + '" was expected.'
1591
+ );
1079
1592
  }
1080
1593
  break;
1081
1594
  }
1082
1595
  }
1083
1596
  },
1084
1597
  eol(_, expression) {
1085
- if (!expression.groupStack.length && (expression.terminatedByEOL || expression.terminatedByWhitespace) && !checkForOperators(this, expression)) {
1598
+ if (!expression.groupStack.length && (expression.terminatedByEOL || expression.terminatedByWhitespace) && !checkForOperators(this, expression, true)) {
1086
1599
  this.exitState();
1087
1600
  }
1088
1601
  },
@@ -1095,69 +1608,216 @@ var EXPRESSION = {
1095
1608
  case states_exports.ATTRIBUTE: {
1096
1609
  const attr = parent;
1097
1610
  if (!attr.spread && !attr.name) {
1098
- return this.emitError(expression, 19 /* MALFORMED_OPEN_TAG */, 'EOF reached while parsing attribute name for the "' + this.read(this.activeTag.tagName) + '" tag');
1611
+ return this.emitError(
1612
+ expression,
1613
+ 19 /* MALFORMED_OPEN_TAG */,
1614
+ 'EOF reached while parsing attribute name for the "' + this.read(this.activeTag.tagName) + '" tag'
1615
+ );
1099
1616
  }
1100
- 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`);
1617
+ return this.emitError(
1618
+ expression,
1619
+ 19 /* MALFORMED_OPEN_TAG */,
1620
+ `EOF reached while parsing attribute value for the ${attr.spread ? "..." : attr.name ? `"${this.read(attr.name)}"` : `"default"`} attribute`
1621
+ );
1101
1622
  }
1102
1623
  case states_exports.TAG_NAME:
1103
- return this.emitError(expression, 19 /* MALFORMED_OPEN_TAG */, "EOF reached while parsing tag name");
1624
+ return this.emitError(
1625
+ expression,
1626
+ 19 /* MALFORMED_OPEN_TAG */,
1627
+ "EOF reached while parsing tag name"
1628
+ );
1104
1629
  case states_exports.PLACEHOLDER:
1105
- return this.emitError(expression, 20 /* MALFORMED_PLACEHOLDER */, "EOF reached while parsing placeholder");
1630
+ return this.emitError(
1631
+ expression,
1632
+ 20 /* MALFORMED_PLACEHOLDER */,
1633
+ "EOF reached while parsing placeholder"
1634
+ );
1106
1635
  }
1107
- return this.emitError(expression, 6 /* INVALID_EXPRESSION */, "EOF reached while parsing expression");
1636
+ return this.emitError(
1637
+ expression,
1638
+ 6 /* INVALID_EXPRESSION */,
1639
+ "EOF reached while parsing expression"
1640
+ );
1108
1641
  }
1109
1642
  },
1110
1643
  return() {
1111
1644
  }
1112
1645
  };
1113
- function buildPattern(type) {
1114
- const space = type === 1 /* CONCISE_ATTRS */ ? "[ \\t]" : "\\s";
1115
- const binary = `(?:[!~*%&^|?<]+=*)+|:+(?!=)|[>/+=-]+=|=>|(?<!\\+)[ \\t]*\\+(?:\\s*\\+\\s*\\+)*\\s*(?!\\+)|(?<!-)-${type === 1 /* CONCISE_ATTRS */ ? "" : "(?:\\s*-\\s*-)*\\s*"}(?!-)|(?<!\\.)\\.(?!\\.)|>${type === 0 /* HTML_ATTRS */ ? "{2,}" : "+"}|[ \\t]+(?:in(?:stanceof)?|as|extends)(?=[ \\t]+[^=/,;:>])`;
1116
- const unary = "\\b(?<![.]\\s*)(?:a(?:sync|wait)|keyof|class|function|new|typeof|void)\\b";
1117
- const lookAheadPattern = `${space}*(?:${binary})\\s*|${space}+(?=[{(]|/[^>])`;
1118
- const lookBehindPattern = `(?<=${unary}|${binary})`;
1119
- return new RegExp(`${lookAheadPattern}|${lookBehindPattern}`, "ym");
1120
- }
1121
- function checkForOperators(parser, expression) {
1122
- var _a;
1123
- if (expression.skipOperators) {
1646
+ function checkForOperators(parser, expression, eol) {
1647
+ if (!expression.operators)
1124
1648
  return false;
1649
+ const { pos, data } = parser;
1650
+ if (lookBehindForOperator(data, pos) !== -1) {
1651
+ parser.consumeWhitespace();
1652
+ parser.forward = 0;
1653
+ return true;
1125
1654
  }
1126
- const pattern = parser.isConcise ? ((_a = parser.activeTag) == null ? void 0 : _a.stage) === states_exports.TAG_STAGE.ATTR_GROUP ? conciseAttrsGroupPattern : conciseAttrsPattern : expression.terminatedByEOL ? conciseAttrsPattern : htmlAttrsPattern;
1127
- pattern.lastIndex = parser.pos;
1128
- const matches = pattern.exec(parser.data);
1129
- if (matches) {
1130
- const [match] = matches;
1131
- if (match.length === 0) {
1132
- parser.consumeWhitespace();
1133
- } else {
1134
- parser.pos += match.length;
1655
+ const terminatedByEOL = expression.terminatedByEOL || parser.isConcise;
1656
+ if (!(terminatedByEOL && eol)) {
1657
+ const nextNonSpace = lookAheadWhile(
1658
+ terminatedByEOL ? isIndentCode : isWhitespaceCode,
1659
+ data,
1660
+ pos + 1
1661
+ );
1662
+ if (!expression.shouldTerminate(
1663
+ data.charCodeAt(nextNonSpace),
1664
+ data,
1665
+ nextNonSpace
1666
+ )) {
1667
+ const lookAheadPos = lookAheadForOperator(data, nextNonSpace);
1668
+ if (lookAheadPos !== -1) {
1669
+ parser.pos = lookAheadPos;
1670
+ parser.forward = 0;
1671
+ return true;
1672
+ }
1135
1673
  }
1136
- parser.forward = 0;
1137
- } else {
1138
- return false;
1139
1674
  }
1140
- return true;
1675
+ return false;
1141
1676
  }
1142
- function checkForTerminators(parser, code, terminators) {
1143
- outer:
1144
- for (const terminator of terminators) {
1145
- if (typeof terminator === "number") {
1146
- if (code === terminator)
1147
- return true;
1148
- } else {
1149
- if (terminator[0] === code) {
1150
- for (let i = terminator.length; i-- > 1; ) {
1151
- if (parser.data.charCodeAt(parser.pos + i) !== terminator[i])
1152
- continue outer;
1153
- }
1154
- return true;
1677
+ function lookBehindForOperator(data, pos) {
1678
+ const curPos = pos - 1;
1679
+ const code = data.charCodeAt(curPos);
1680
+ switch (code) {
1681
+ case 38 /* AMPERSAND */:
1682
+ case 42 /* ASTERISK */:
1683
+ case 94 /* CARET */:
1684
+ case 58 /* COLON */:
1685
+ case 61 /* EQUAL */:
1686
+ case 33 /* EXCLAMATION */:
1687
+ case 60 /* OPEN_ANGLE_BRACKET */:
1688
+ case 62 /* CLOSE_ANGLE_BRACKET */:
1689
+ case 37 /* PERCENT */:
1690
+ case 46 /* PERIOD */:
1691
+ case 124 /* PIPE */:
1692
+ case 63 /* QUESTION */:
1693
+ case 126 /* TILDE */:
1694
+ return curPos;
1695
+ case 43 /* PLUS */:
1696
+ case 45 /* HYPHEN */: {
1697
+ if (data.charCodeAt(curPos - 1) === code) {
1698
+ return lookBehindForOperator(
1699
+ data,
1700
+ lookBehindWhile(isWhitespaceCode, data, curPos - 2)
1701
+ );
1702
+ }
1703
+ return curPos;
1704
+ }
1705
+ default: {
1706
+ for (const keyword of unaryKeywords) {
1707
+ const keywordPos = lookBehindFor(data, curPos, keyword);
1708
+ if (keywordPos !== -1) {
1709
+ return data.charCodeAt(keywordPos - 1) === 46 /* PERIOD */ ? -1 : keywordPos;
1710
+ }
1711
+ }
1712
+ return -1;
1713
+ }
1714
+ }
1715
+ }
1716
+ function lookAheadForOperator(data, pos) {
1717
+ switch (data.charCodeAt(pos)) {
1718
+ case 38 /* AMPERSAND */:
1719
+ case 42 /* ASTERISK */:
1720
+ case 94 /* CARET */:
1721
+ case 33 /* EXCLAMATION */:
1722
+ case 60 /* OPEN_ANGLE_BRACKET */:
1723
+ case 37 /* PERCENT */:
1724
+ case 124 /* PIPE */:
1725
+ case 63 /* QUESTION */:
1726
+ case 126 /* TILDE */:
1727
+ case 43 /* PLUS */:
1728
+ case 45 /* HYPHEN */:
1729
+ case 58 /* COLON */:
1730
+ case 62 /* CLOSE_ANGLE_BRACKET */:
1731
+ case 61 /* EQUAL */:
1732
+ return pos + 1;
1733
+ case 47 /* FORWARD_SLASH */:
1734
+ case 123 /* OPEN_CURLY_BRACE */:
1735
+ case 40 /* OPEN_PAREN */:
1736
+ return pos;
1737
+ case 46 /* PERIOD */:
1738
+ return data.charCodeAt(pos + 1) === 46 /* PERIOD */ ? -1 : pos + 1;
1739
+ default: {
1740
+ for (const keyword of binaryKeywords) {
1741
+ let nextPos = lookAheadFor(data, pos, keyword);
1742
+ if (nextPos === -1)
1743
+ continue;
1744
+ const max = data.length - 1;
1745
+ if (nextPos === max)
1746
+ return -1;
1747
+ let nextCode = data.charCodeAt(nextPos + 1);
1748
+ if (isWhitespaceCode(nextCode)) {
1749
+ nextPos = lookAheadWhile(isWhitespaceCode, data, nextPos + 2);
1750
+ if (nextPos === max)
1751
+ return -1;
1752
+ nextCode = data.charCodeAt(nextPos);
1753
+ } else if (isWordCode(nextCode)) {
1754
+ return -1;
1755
+ }
1756
+ switch (nextCode) {
1757
+ case 58 /* COLON */:
1758
+ case 44 /* COMMA */:
1759
+ case 61 /* EQUAL */:
1760
+ case 47 /* FORWARD_SLASH */:
1761
+ case 62 /* CLOSE_ANGLE_BRACKET */:
1762
+ case 59 /* SEMICOLON */:
1763
+ return -1;
1764
+ default:
1765
+ return nextPos;
1155
1766
  }
1156
1767
  }
1768
+ return -1;
1769
+ }
1770
+ }
1771
+ }
1772
+ function canFollowDivision(code) {
1773
+ 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 */;
1774
+ }
1775
+ function isWordCode(code) {
1776
+ 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 */;
1777
+ }
1778
+ function isIndentCode(code) {
1779
+ return code === 9 /* TAB */ || code === 32 /* SPACE */;
1780
+ }
1781
+ function lookAheadWhile(match, data, pos) {
1782
+ const max = data.length;
1783
+ for (let i = pos; i < max; i++) {
1784
+ if (!match(data.charCodeAt(i)))
1785
+ return i;
1786
+ }
1787
+ return max - 1;
1788
+ }
1789
+ function lookBehindWhile(match, data, pos) {
1790
+ let i = pos;
1791
+ do {
1792
+ if (!match(data.charCodeAt(i))) {
1793
+ return i + 1;
1794
+ }
1795
+ } while (i--);
1796
+ return 0;
1797
+ }
1798
+ function lookBehindFor(data, pos, str) {
1799
+ let i = str.length;
1800
+ const endPos = pos - i + 1;
1801
+ if (endPos < 0)
1802
+ return -1;
1803
+ while (i--) {
1804
+ if (data.charCodeAt(endPos + i) !== str.charCodeAt(i)) {
1805
+ return -1;
1157
1806
  }
1807
+ }
1808
+ return endPos;
1158
1809
  }
1159
- function canCharCodeBeFollowedByDivision(code) {
1160
- 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 */;
1810
+ function lookAheadFor(data, pos, str) {
1811
+ let i = str.length;
1812
+ const endPos = pos + i;
1813
+ if (endPos > data.length)
1814
+ return -1;
1815
+ while (i--) {
1816
+ if (data.charCodeAt(pos + i) !== str.charCodeAt(i)) {
1817
+ return -1;
1818
+ }
1819
+ }
1820
+ return endPos - 1;
1161
1821
  }
1162
1822
 
1163
1823
  // src/states/HTML_COMMENT.ts
@@ -1198,7 +1858,11 @@ var HTML_COMMENT = {
1198
1858
  eol() {
1199
1859
  },
1200
1860
  eof(comment) {
1201
- this.emitError(comment, 16 /* MALFORMED_COMMENT */, "EOF reached while parsing comment");
1861
+ this.emitError(
1862
+ comment,
1863
+ 16 /* MALFORMED_COMMENT */,
1864
+ "EOF reached while parsing comment"
1865
+ );
1202
1866
  },
1203
1867
  return() {
1204
1868
  }
@@ -1372,11 +2036,10 @@ var INLINE_SCRIPT = {
1372
2036
  if (code === 123 /* OPEN_CURLY_BRACE */) {
1373
2037
  inlineScript.block = true;
1374
2038
  this.pos++;
1375
- const expr = this.enterState(states_exports.EXPRESSION);
1376
- expr.terminator = 125 /* CLOSE_CURLY_BRACE */;
1377
- expr.skipOperators = true;
2039
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseCurlyBrace;
1378
2040
  } else {
1379
2041
  const expr = this.enterState(states_exports.EXPRESSION);
2042
+ expr.operators = true;
1380
2043
  expr.terminatedByEOL = true;
1381
2044
  }
1382
2045
  },
@@ -1411,7 +2074,11 @@ var JS_COMMENT_BLOCK = {
1411
2074
  eol() {
1412
2075
  },
1413
2076
  eof(comment) {
1414
- this.emitError(comment, 16 /* MALFORMED_COMMENT */, "EOF reached while parsing multi-line JavaScript comment");
2077
+ this.emitError(
2078
+ comment,
2079
+ 16 /* MALFORMED_COMMENT */,
2080
+ "EOF reached while parsing multi-line JavaScript comment"
2081
+ );
1415
2082
  },
1416
2083
  return() {
1417
2084
  }
@@ -1534,7 +2201,11 @@ var PLACEHOLDER = {
1534
2201
  },
1535
2202
  return(child) {
1536
2203
  if (child.start === child.end) {
1537
- this.emitError(child, 20 /* MALFORMED_PLACEHOLDER */, "Invalid placeholder, the expression cannot be missing");
2204
+ this.emitError(
2205
+ child,
2206
+ 20 /* MALFORMED_PLACEHOLDER */,
2207
+ "Invalid placeholder, the expression cannot be missing"
2208
+ );
1538
2209
  }
1539
2210
  this.pos++;
1540
2211
  this.exitState();
@@ -1574,7 +2245,7 @@ function checkForPlaceholder(parser, code) {
1574
2245
  parser.enterState(PLACEHOLDER).escape = escape;
1575
2246
  parser.pos += escape ? 2 : 3;
1576
2247
  parser.forward = 0;
1577
- parser.enterState(states_exports.EXPRESSION).terminator = 125 /* CLOSE_CURLY_BRACE */;
2248
+ parser.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseCurlyBrace;
1578
2249
  return true;
1579
2250
  }
1580
2251
  }
@@ -1608,10 +2279,18 @@ var REGULAR_EXPRESSION = {
1608
2279
  }
1609
2280
  },
1610
2281
  eol(_, regExp) {
1611
- this.emitError(regExp, 9 /* INVALID_REGULAR_EXPRESSION */, "EOL reached while parsing regular expression");
2282
+ this.emitError(
2283
+ regExp,
2284
+ 9 /* INVALID_REGULAR_EXPRESSION */,
2285
+ "EOL reached while parsing regular expression"
2286
+ );
1612
2287
  },
1613
2288
  eof(regExp) {
1614
- this.emitError(regExp, 9 /* INVALID_REGULAR_EXPRESSION */, "EOF reached while parsing regular expression");
2289
+ this.emitError(
2290
+ regExp,
2291
+ 9 /* INVALID_REGULAR_EXPRESSION */,
2292
+ "EOF reached while parsing regular expression"
2293
+ );
1615
2294
  },
1616
2295
  return() {
1617
2296
  }
@@ -1645,7 +2324,11 @@ var STRING = {
1645
2324
  eol() {
1646
2325
  },
1647
2326
  eof(string) {
1648
- this.emitError(string, 10 /* INVALID_STRING */, "EOF reached while parsing string expression");
2327
+ this.emitError(
2328
+ string,
2329
+ 10 /* INVALID_STRING */,
2330
+ "EOF reached while parsing string expression"
2331
+ );
1649
2332
  },
1650
2333
  return() {
1651
2334
  }
@@ -1673,7 +2356,11 @@ var TAG_NAME = {
1673
2356
  switch (tagName.shorthandCode) {
1674
2357
  case 35 /* NUMBER_SIGN */:
1675
2358
  if (this.activeTag.hasShorthandId) {
1676
- return this.emitError(tagName, 12 /* INVALID_TAG_SHORTHAND */, "Multiple shorthand ID parts are not allowed on the same tag");
2359
+ return this.emitError(
2360
+ tagName,
2361
+ 12 /* INVALID_TAG_SHORTHAND */,
2362
+ "Multiple shorthand ID parts are not allowed on the same tag"
2363
+ );
1677
2364
  }
1678
2365
  this.activeTag.hasShorthandId = true;
1679
2366
  (_b = (_a = this.options).onTagShorthandId) == null ? void 0 : _b.call(_a, {
@@ -1704,12 +2391,26 @@ var TAG_NAME = {
1704
2391
  tag.type = tagType;
1705
2392
  if (tagType === 3 /* statement */) {
1706
2393
  if (!tag.concise) {
1707
- return this.emitError(tagName, 24 /* RESERVED_TAG_NAME */, `The "${this.read(tagName)}" tag is reserved and cannot be used as an HTML tag.`);
2394
+ return this.emitError(
2395
+ tagName,
2396
+ 24 /* RESERVED_TAG_NAME */,
2397
+ `The "${this.read(
2398
+ tagName
2399
+ )}" tag is reserved and cannot be used as an HTML tag.`
2400
+ );
1708
2401
  }
1709
2402
  if (tag.parentTag) {
1710
- return this.emitError(tagName, 25 /* ROOT_TAG_ONLY */, `"${this.read(tagName)}" can only be used at the root of the template.`);
2403
+ return this.emitError(
2404
+ tagName,
2405
+ 25 /* ROOT_TAG_ONLY */,
2406
+ `"${this.read(
2407
+ tagName
2408
+ )}" can only be used at the root of the template.`
2409
+ );
1711
2410
  }
1712
- this.enterState(states_exports.EXPRESSION).terminatedByEOL = true;
2411
+ const expr = this.enterState(states_exports.EXPRESSION);
2412
+ expr.operators = true;
2413
+ expr.terminatedByEOL = true;
1713
2414
  }
1714
2415
  }
1715
2416
  break;
@@ -1720,7 +2421,7 @@ var TAG_NAME = {
1720
2421
  if (code === 36 /* DOLLAR */ && this.lookAtCharCodeAhead(1) === 123 /* OPEN_CURLY_BRACE */) {
1721
2422
  this.pos += 2;
1722
2423
  this.forward = 0;
1723
- this.enterState(states_exports.EXPRESSION).terminator = 125 /* CLOSE_CURLY_BRACE */;
2424
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseCurlyBrace;
1724
2425
  } 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 */)) {
1725
2426
  this.activeTag.shorthandEnd = this.pos;
1726
2427
  this.exitState();
@@ -1742,7 +2443,11 @@ var TAG_NAME = {
1742
2443
  if (child.terminatedByEOL)
1743
2444
  return;
1744
2445
  if (child.start === child.end) {
1745
- this.emitError(child, 20 /* MALFORMED_PLACEHOLDER */, "Invalid placeholder, the expression cannot be missing");
2446
+ this.emitError(
2447
+ child,
2448
+ 20 /* MALFORMED_PLACEHOLDER */,
2449
+ "Invalid placeholder, the expression cannot be missing"
2450
+ );
1746
2451
  }
1747
2452
  const { quasis, expressions } = tagName;
1748
2453
  const start = child.start - 2;
@@ -1775,334 +2480,43 @@ var TEMPLATE_STRING = {
1775
2480
  exit() {
1776
2481
  },
1777
2482
  char(code) {
1778
- if (code === 36 /* DOLLAR */ && this.lookAtCharCodeAhead(1) === 123 /* OPEN_CURLY_BRACE */) {
1779
- this.pos++;
1780
- const expr = this.enterState(states_exports.EXPRESSION);
1781
- expr.skipOperators = true;
1782
- expr.terminator = 125 /* CLOSE_CURLY_BRACE */;
1783
- } else {
1784
- if (code === 92 /* BACK_SLASH */) {
2483
+ switch (code) {
2484
+ case 36 /* DOLLAR */:
2485
+ if (this.lookAtCharCodeAhead(1) === 123 /* OPEN_CURLY_BRACE */) {
2486
+ this.pos++;
2487
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseCurlyBrace;
2488
+ }
2489
+ break;
2490
+ case 92 /* BACK_SLASH */:
1785
2491
  this.pos++;
1786
- } else if (code === 96 /* BACKTICK */) {
2492
+ break;
2493
+ case 96 /* BACKTICK */:
1787
2494
  this.pos++;
1788
2495
  this.exitState();
1789
- }
2496
+ break;
1790
2497
  }
1791
2498
  },
1792
2499
  eof(templateString) {
1793
- this.emitError(templateString, 13 /* INVALID_TEMPLATE_STRING */, "EOF reached while parsing template string expression");
2500
+ this.emitError(
2501
+ templateString,
2502
+ 13 /* INVALID_TEMPLATE_STRING */,
2503
+ "EOF reached while parsing template string expression"
2504
+ );
1794
2505
  },
1795
2506
  eol() {
1796
2507
  },
1797
2508
  return(child) {
1798
2509
  if (child.start === child.end) {
1799
- this.emitError(child, 20 /* MALFORMED_PLACEHOLDER */, "Invalid placeholder, the expression cannot be missing");
2510
+ this.emitError(
2511
+ child,
2512
+ 20 /* MALFORMED_PLACEHOLDER */,
2513
+ "Invalid placeholder, the expression cannot be missing"
2514
+ );
1800
2515
  }
1801
2516
  this.pos++;
1802
2517
  }
1803
2518
  };
1804
2519
 
1805
- // src/states/OPEN_TAG.ts
1806
- var TAG_STAGE = /* @__PURE__ */ ((TAG_STAGE2) => {
1807
- TAG_STAGE2[TAG_STAGE2["UNKNOWN"] = 0] = "UNKNOWN";
1808
- TAG_STAGE2[TAG_STAGE2["VAR"] = 1] = "VAR";
1809
- TAG_STAGE2[TAG_STAGE2["ARGUMENT"] = 2] = "ARGUMENT";
1810
- TAG_STAGE2[TAG_STAGE2["PARAMS"] = 3] = "PARAMS";
1811
- TAG_STAGE2[TAG_STAGE2["ATTR_GROUP"] = 4] = "ATTR_GROUP";
1812
- return TAG_STAGE2;
1813
- })(TAG_STAGE || {});
1814
- var CONCISE_TAG_VAR_TERMINATORS = [
1815
- 59 /* SEMICOLON */,
1816
- 40 /* OPEN_PAREN */,
1817
- 124 /* PIPE */,
1818
- 61 /* EQUAL */,
1819
- 44 /* COMMA */,
1820
- [58 /* COLON */, 61 /* EQUAL */]
1821
- ];
1822
- var HTML_TAG_VAR_TERMINATORS = [
1823
- 62 /* CLOSE_ANGLE_BRACKET */,
1824
- 40 /* OPEN_PAREN */,
1825
- 124 /* PIPE */,
1826
- 61 /* EQUAL */,
1827
- 44 /* COMMA */,
1828
- [58 /* COLON */, 61 /* EQUAL */],
1829
- [47 /* FORWARD_SLASH */, 62 /* CLOSE_ANGLE_BRACKET */]
1830
- ];
1831
- var OPEN_TAG = {
1832
- name: "OPEN_TAG",
1833
- enter(parent, start) {
1834
- const tag = this.activeTag = {
1835
- state: OPEN_TAG,
1836
- type: 0 /* html */,
1837
- parent,
1838
- start,
1839
- end: start,
1840
- stage: 0 /* UNKNOWN */,
1841
- parentTag: this.activeTag,
1842
- nestedIndent: void 0,
1843
- indent: this.indent,
1844
- hasShorthandId: false,
1845
- hasArgs: false,
1846
- hasAttrs: false,
1847
- selfClosed: false,
1848
- shorthandEnd: -1,
1849
- tagName: void 0,
1850
- concise: this.isConcise,
1851
- beginMixedMode: this.beginMixedMode || this.endingMixedModeAtEOL
1852
- };
1853
- this.beginMixedMode = false;
1854
- this.endingMixedModeAtEOL = false;
1855
- this.endText();
1856
- return tag;
1857
- },
1858
- exit(tag) {
1859
- var _a, _b;
1860
- const { selfClosed } = tag;
1861
- (_b = (_a = this.options).onOpenTagEnd) == null ? void 0 : _b.call(_a, {
1862
- start: this.pos - (this.isConcise ? 0 : selfClosed ? 2 : 1),
1863
- end: this.pos,
1864
- selfClosed
1865
- });
1866
- switch (selfClosed ? 2 /* void */ : tag.type) {
1867
- case 2 /* void */:
1868
- case 3 /* statement */: {
1869
- if (tag.beginMixedMode)
1870
- this.endingMixedModeAtEOL = true;
1871
- this.activeTag = tag.parentTag;
1872
- break;
1873
- }
1874
- case 1 /* text */:
1875
- if (this.isConcise) {
1876
- this.enterState(states_exports.CONCISE_HTML_CONTENT);
1877
- } else {
1878
- this.enterState(states_exports.PARSED_TEXT_CONTENT);
1879
- }
1880
- break;
1881
- }
1882
- },
1883
- eol(_, tag) {
1884
- if (this.isConcise && tag.stage !== 4 /* ATTR_GROUP */) {
1885
- this.exitState();
1886
- }
1887
- },
1888
- eof(tag) {
1889
- if (this.isConcise) {
1890
- if (tag.stage === 4 /* ATTR_GROUP */) {
1891
- this.emitError(tag, 19 /* MALFORMED_OPEN_TAG */, 'EOF reached while within an attribute group (e.g. "[ ... ]").');
1892
- return;
1893
- }
1894
- this.exitState();
1895
- } else {
1896
- this.emitError(tag, 19 /* MALFORMED_OPEN_TAG */, "EOF reached while parsing open tag");
1897
- }
1898
- },
1899
- char(code, tag) {
1900
- if (this.isConcise) {
1901
- if (code === 59 /* SEMICOLON */) {
1902
- this.pos++;
1903
- this.exitState();
1904
- if (!this.consumeWhitespaceOnLine(0)) {
1905
- switch (this.lookAtCharCodeAhead(0)) {
1906
- case 47 /* FORWARD_SLASH */:
1907
- switch (this.lookAtCharCodeAhead(1)) {
1908
- case 47 /* FORWARD_SLASH */:
1909
- this.enterState(states_exports.JS_COMMENT_LINE);
1910
- this.pos += 2;
1911
- return;
1912
- case 42 /* ASTERISK */:
1913
- this.enterState(states_exports.JS_COMMENT_BLOCK);
1914
- this.pos += 2;
1915
- return;
1916
- }
1917
- break;
1918
- case 60 /* OPEN_ANGLE_BRACKET */:
1919
- if (this.lookAheadFor("!--")) {
1920
- this.enterState(states_exports.HTML_COMMENT);
1921
- this.pos += 4;
1922
- return;
1923
- }
1924
- break;
1925
- }
1926
- this.emitError(this.pos, 5 /* INVALID_CODE_AFTER_SEMICOLON */, "A semicolon indicates the end of a line. Only comments may follow it.");
1927
- }
1928
- return;
1929
- }
1930
- if (code === 45 /* HTML_BLOCK_DELIMITER */) {
1931
- if (this.lookAtCharCodeAhead(1) !== 45 /* HTML_BLOCK_DELIMITER */) {
1932
- this.emitError(tag, 19 /* MALFORMED_OPEN_TAG */, '"-" not allowed as first character of attribute name');
1933
- return;
1934
- }
1935
- if (tag.stage === 4 /* ATTR_GROUP */) {
1936
- this.emitError(this.pos, 19 /* MALFORMED_OPEN_TAG */, "Attribute group was not properly ended");
1937
- return;
1938
- }
1939
- this.exitState();
1940
- const maxPos = this.maxPos;
1941
- let curPos = this.pos + 1;
1942
- while (curPos < maxPos && this.data.charCodeAt(++curPos) !== 10 /* NEWLINE */)
1943
- ;
1944
- const indentStart = ++curPos;
1945
- while (curPos < maxPos) {
1946
- const nextCode = this.data.charCodeAt(curPos);
1947
- if (nextCode === 32 /* SPACE */ || nextCode === 9 /* TAB */) {
1948
- curPos++;
1949
- } else {
1950
- break;
1951
- }
1952
- }
1953
- const indentSize = curPos - indentStart;
1954
- if (indentSize > this.indent.length) {
1955
- this.indent = this.data.slice(indentStart, curPos);
1956
- }
1957
- this.enterState(states_exports.BEGIN_DELIMITED_HTML_BLOCK);
1958
- return;
1959
- } else if (code === 91 /* OPEN_SQUARE_BRACKET */) {
1960
- if (tag.stage === 4 /* ATTR_GROUP */) {
1961
- this.emitError(this.pos, 19 /* MALFORMED_OPEN_TAG */, 'Unexpected "[" character within open tag.');
1962
- return;
1963
- }
1964
- tag.stage = 4 /* ATTR_GROUP */;
1965
- return;
1966
- } else if (code === 93 /* CLOSE_SQUARE_BRACKET */) {
1967
- if (tag.stage !== 4 /* ATTR_GROUP */) {
1968
- this.emitError(this.pos, 19 /* MALFORMED_OPEN_TAG */, 'Unexpected "]" character within open tag.');
1969
- return;
1970
- }
1971
- tag.stage = 0 /* UNKNOWN */;
1972
- return;
1973
- }
1974
- } else if (code === 62 /* CLOSE_ANGLE_BRACKET */) {
1975
- this.pos++;
1976
- this.exitState();
1977
- return;
1978
- } else if (code === 47 /* FORWARD_SLASH */ && this.lookAtCharCodeAhead(1) === 62 /* CLOSE_ANGLE_BRACKET */) {
1979
- tag.selfClosed = true;
1980
- this.pos += 2;
1981
- this.exitState();
1982
- return;
1983
- }
1984
- if (code === 60 /* OPEN_ANGLE_BRACKET */) {
1985
- return this.emitError(this.pos, 2 /* INVALID_ATTRIBUTE_NAME */, 'Invalid attribute name. Attribute name cannot begin with the "<" character.');
1986
- }
1987
- if (code === 47 /* FORWARD_SLASH */) {
1988
- switch (this.lookAtCharCodeAhead(1)) {
1989
- case 47 /* FORWARD_SLASH */:
1990
- this.enterState(states_exports.JS_COMMENT_LINE);
1991
- this.pos++;
1992
- return;
1993
- case 42 /* ASTERISK */:
1994
- this.enterState(states_exports.JS_COMMENT_BLOCK);
1995
- this.pos++;
1996
- return;
1997
- }
1998
- }
1999
- if (isWhitespaceCode(code)) {
2000
- } else if (code === 44 /* COMMA */) {
2001
- this.pos++;
2002
- this.forward = 0;
2003
- this.consumeWhitespace();
2004
- } else if (code === 47 /* FORWARD_SLASH */ && !tag.hasAttrs) {
2005
- tag.stage = 1 /* VAR */;
2006
- this.pos++;
2007
- this.forward = 0;
2008
- if (isWhitespaceCode(this.lookAtCharCodeAhead(0))) {
2009
- return this.emitError(this.pos, 23 /* MISSING_TAG_VARIABLE */, "A slash was found that was not followed by a variable name or lhs expression");
2010
- }
2011
- const expr = this.enterState(states_exports.EXPRESSION);
2012
- expr.terminatedByWhitespace = true;
2013
- expr.terminator = this.isConcise ? CONCISE_TAG_VAR_TERMINATORS : HTML_TAG_VAR_TERMINATORS;
2014
- } else if (code === 40 /* OPEN_PAREN */ && !tag.hasAttrs) {
2015
- if (tag.hasArgs) {
2016
- this.emitError(this.pos, 11 /* INVALID_TAG_ARGUMENT */, "A tag can only have one argument");
2017
- return;
2018
- }
2019
- tag.stage = 2 /* ARGUMENT */;
2020
- this.pos++;
2021
- this.forward = 0;
2022
- const expr = this.enterState(states_exports.EXPRESSION);
2023
- expr.skipOperators = true;
2024
- expr.terminator = 41 /* CLOSE_PAREN */;
2025
- } else if (code === 124 /* PIPE */ && !tag.hasAttrs) {
2026
- tag.stage = 3 /* PARAMS */;
2027
- this.pos++;
2028
- this.forward = 0;
2029
- const expr = this.enterState(states_exports.EXPRESSION);
2030
- expr.skipOperators = true;
2031
- expr.terminator = 124 /* PIPE */;
2032
- } else {
2033
- this.forward = 0;
2034
- if (tag.tagName) {
2035
- this.enterState(states_exports.ATTRIBUTE);
2036
- tag.hasAttrs = true;
2037
- } else {
2038
- this.enterState(states_exports.TAG_NAME);
2039
- }
2040
- }
2041
- },
2042
- return(child, tag) {
2043
- var _a, _b, _c, _d, _e, _f;
2044
- switch (child.state) {
2045
- case states_exports.JS_COMMENT_BLOCK: {
2046
- break;
2047
- }
2048
- case states_exports.EXPRESSION: {
2049
- switch (tag.stage) {
2050
- case 1 /* VAR */: {
2051
- if (child.start === child.end) {
2052
- return this.emitError(child, 23 /* MISSING_TAG_VARIABLE */, "A slash was found that was not followed by a variable name or lhs expression");
2053
- }
2054
- (_b = (_a = this.options).onTagVar) == null ? void 0 : _b.call(_a, {
2055
- start: child.start - 1,
2056
- end: child.end,
2057
- value: {
2058
- start: child.start,
2059
- end: child.end
2060
- }
2061
- });
2062
- break;
2063
- }
2064
- case 2 /* ARGUMENT */: {
2065
- const start = child.start - 1;
2066
- const end = ++this.pos;
2067
- const value = {
2068
- start: child.start,
2069
- end: child.end
2070
- };
2071
- if (this.consumeWhitespaceIfBefore("{")) {
2072
- const attr = this.enterState(states_exports.ATTRIBUTE);
2073
- attr.start = start;
2074
- attr.args = { start, end, value };
2075
- tag.hasAttrs = true;
2076
- this.forward = 0;
2077
- } else {
2078
- tag.hasArgs = true;
2079
- (_d = (_c = this.options).onTagArgs) == null ? void 0 : _d.call(_c, {
2080
- start,
2081
- end,
2082
- value
2083
- });
2084
- }
2085
- break;
2086
- }
2087
- case 3 /* PARAMS */: {
2088
- const end = ++this.pos;
2089
- (_f = (_e = this.options).onTagParams) == null ? void 0 : _f.call(_e, {
2090
- start: child.start - 1,
2091
- end,
2092
- value: {
2093
- start: child.start,
2094
- end: child.end
2095
- }
2096
- });
2097
- break;
2098
- }
2099
- }
2100
- break;
2101
- }
2102
- }
2103
- }
2104
- };
2105
-
2106
2520
  // src/index.ts
2107
2521
  function createParser(handlers) {
2108
2522
  const parser = new Parser(handlers);