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.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;
@@ -21,7 +22,10 @@ var src_exports = {};
21
22
  __export(src_exports, {
22
23
  ErrorCode: () => ErrorCode,
23
24
  TagType: () => TagType,
24
- createParser: () => createParser
25
+ createParser: () => createParser,
26
+ getLines: () => getLines,
27
+ getLocation: () => getLocation,
28
+ getPosition: () => getPosition
25
29
  });
26
30
  module.exports = __toCommonJS(src_exports);
27
31
 
@@ -67,26 +71,13 @@ var TagType = /* @__PURE__ */ ((TagType2) => {
67
71
  function isWhitespaceCode(code) {
68
72
  return code <= 32 /* SPACE */;
69
73
  }
70
- function getLoc(lines, range) {
71
- const start = getPos(lines, 0, range.start);
72
- const end = range.start === range.end ? start : getPos(lines, start.line, range.end);
74
+ function getLocation(lines, startOffset, endOffset) {
75
+ const start = getPosition(lines, startOffset);
76
+ const end = startOffset === endOffset ? start : getPosAfterLine(lines, start.line, endOffset);
73
77
  return { start, end };
74
78
  }
75
- function getPos(lines, startLine, index) {
76
- let max = lines.length - 1;
77
- let line = startLine;
78
- while (line < max) {
79
- const mid = 1 + line + max >>> 1;
80
- if (lines[mid] <= index) {
81
- line = mid;
82
- } else {
83
- max = mid - 1;
84
- }
85
- }
86
- return {
87
- line,
88
- character: index - lines[line]
89
- };
79
+ function getPosition(lines, offset) {
80
+ return getPosAfterLine(lines, 0, offset);
90
81
  }
91
82
  function getLines(src) {
92
83
  const lines = [0];
@@ -103,9 +94,38 @@ function htmlEOF() {
103
94
  if (this.activeTag.concise) {
104
95
  this.closeTagEnd(this.pos, this.pos, void 0);
105
96
  } else {
106
- 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
+ );
102
+ }
103
+ }
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
+ }
114
+ function getPosAfterLine(lines, startLine, index) {
115
+ let max = lines.length - 1;
116
+ let line = startLine;
117
+ while (line < max) {
118
+ const mid = 1 + line + max >>> 1;
119
+ if (lines[mid] <= index) {
120
+ line = mid;
121
+ } else {
122
+ max = mid - 1;
107
123
  }
108
124
  }
125
+ return {
126
+ line,
127
+ character: index - lines[line]
128
+ };
109
129
  }
110
130
 
111
131
  // src/core/Parser.ts
@@ -131,15 +151,26 @@ var Parser = class {
131
151
  read(range) {
132
152
  return this.data.slice(range.start, range.end);
133
153
  }
134
- positionAt(index) {
135
- return getPos(this.lines || (this.lines = getLines(this.data)), 0, index);
154
+ positionAt(offset) {
155
+ return getPosition(
156
+ this.lines || (this.lines = getLines(this.data)),
157
+ offset
158
+ );
136
159
  }
137
160
  locationAt(range) {
138
- return getLoc(this.lines || (this.lines = getLines(this.data)), range);
161
+ return getLocation(
162
+ this.lines || (this.lines = getLines(this.data)),
163
+ range.start,
164
+ range.end
165
+ );
139
166
  }
140
167
  enterState(state) {
141
168
  this.activeState = state;
142
- 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
+ );
143
174
  }
144
175
  exitState() {
145
176
  const { activeRange, activeState } = this;
@@ -209,7 +240,9 @@ var Parser = class {
209
240
  }
210
241
  beginHtmlBlock(delimiter, singleLine) {
211
242
  var _a;
212
- 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
+ );
213
246
  content.singleLine = singleLine;
214
247
  content.delimiter = delimiter;
215
248
  content.indent = this.indent;
@@ -369,274 +402,692 @@ __export(states_exports, {
369
402
  handleDelimitedEOL: () => handleDelimitedEOL
370
403
  });
371
404
 
372
- // src/states/ATTRIBUTE.ts
373
- var HTML_VALUE_TERMINATORS = [
374
- 62 /* CLOSE_ANGLE_BRACKET */,
375
- 44 /* COMMA */,
376
- [47 /* FORWARD_SLASH */, 62 /* CLOSE_ANGLE_BRACKET */]
377
- ];
378
- var CONCISE_VALUE_TERMINATORS = [
379
- 93 /* CLOSE_SQUARE_BRACKET */,
380
- 59 /* SEMICOLON */,
381
- 44 /* COMMA */
382
- ];
383
- var HTML_NAME_TERMINATORS = [
384
- 62 /* CLOSE_ANGLE_BRACKET */,
385
- 44 /* COMMA */,
386
- 40 /* OPEN_PAREN */,
387
- 61 /* EQUAL */,
388
- [58 /* COLON */, 61 /* EQUAL */],
389
- [47 /* FORWARD_SLASH */, 62 /* CLOSE_ANGLE_BRACKET */]
390
- ];
391
- var CONCISE_NAME_TERMINATORS = [
392
- 93 /* CLOSE_SQUARE_BRACKET */,
393
- 59 /* SEMICOLON */,
394
- 61 /* EQUAL */,
395
- 44 /* COMMA */,
396
- 40 /* OPEN_PAREN */,
397
- [58 /* COLON */, 61 /* EQUAL */]
398
- ];
399
- var ATTRIBUTE = {
400
- 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",
401
416
  enter(parent, start) {
402
- return this.activeAttr = {
403
- state: ATTRIBUTE,
417
+ const tag = this.activeTag = {
418
+ state: OPEN_TAG,
419
+ type: 0 /* html */,
404
420
  parent,
405
421
  start,
406
422
  end: start,
407
- valueStart: start,
408
423
  stage: 0 /* UNKNOWN */,
409
- name: void 0,
410
- args: false,
411
- bound: false,
412
- 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
413
435
  };
436
+ this.beginMixedMode = false;
437
+ this.endingMixedModeAtEOL = false;
438
+ this.endText();
439
+ return tag;
414
440
  },
415
- exit() {
416
- this.activeAttr = void 0;
417
- },
418
- char(code, attr) {
419
- if (isWhitespaceCode(code)) {
420
- return;
421
- } else if (code === 61 /* EQUAL */ || code === 58 /* COLON */ && this.lookAtCharCodeAhead(1) === 61 /* EQUAL */ || code === 46 /* PERIOD */ && this.lookAheadFor("..")) {
422
- attr.valueStart = this.pos;
423
- this.forward = 0;
424
- if (code === 58 /* COLON */) {
425
- ensureAttrName(this, attr);
426
- attr.bound = true;
427
- this.pos += 2;
428
- this.consumeWhitespace();
429
- } else if (code === 46 /* PERIOD */) {
430
- attr.spread = true;
431
- this.pos += 3;
432
- } else {
433
- ensureAttrName(this, attr);
434
- this.pos++;
435
- 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;
436
456
  }
437
- attr.stage = 2 /* VALUE */;
438
- const expr = this.enterState(states_exports.EXPRESSION);
439
- expr.terminatedByWhitespace = true;
440
- expr.terminator = this.isConcise ? CONCISE_VALUE_TERMINATORS : HTML_VALUE_TERMINATORS;
441
- } else if (code === 40 /* OPEN_PAREN */) {
442
- ensureAttrName(this, attr);
443
- attr.stage = 3 /* ARGUMENT */;
444
- this.pos++;
445
- this.forward = 0;
446
- this.enterState(states_exports.EXPRESSION).terminator = 41 /* CLOSE_PAREN */;
447
- } else if (code === 123 /* OPEN_CURLY_BRACE */ && attr.args) {
448
- ensureAttrName(this, attr);
449
- attr.stage = 4 /* BLOCK */;
450
- this.pos++;
451
- this.forward = 0;
452
- const expr = this.enterState(states_exports.EXPRESSION);
453
- expr.terminatedByWhitespace = false;
454
- expr.terminator = 125 /* CLOSE_CURLY_BRACE */;
455
- } else if (attr.stage === 0 /* UNKNOWN */) {
456
- attr.stage = 1 /* NAME */;
457
- this.forward = 0;
458
- const expr = this.enterState(states_exports.EXPRESSION);
459
- expr.terminatedByWhitespace = true;
460
- expr.skipOperators = true;
461
- expr.terminator = this.isConcise ? CONCISE_NAME_TERMINATORS : HTML_NAME_TERMINATORS;
462
- } else {
463
- 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;
464
464
  }
465
465
  },
466
- eol() {
467
- if (this.isConcise) {
466
+ eol(_, tag) {
467
+ if (this.isConcise && tag.stage !== 4 /* ATTR_GROUP */) {
468
468
  this.exitState();
469
469
  }
470
470
  },
471
- eof(attr) {
471
+ eof(tag) {
472
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
+ }
473
481
  this.exitState();
474
482
  } else {
475
- 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
+ );
476
488
  }
477
489
  },
478
- return(child, attr) {
479
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
480
- switch (attr.stage) {
481
- case 1 /* NAME */: {
482
- attr.name = {
483
- start: child.start,
484
- end: child.end
485
- };
486
- (_b = (_a = this.options).onAttrName) == null ? void 0 : _b.call(_a, attr.name);
487
- 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;
488
524
  }
489
- case 3 /* ARGUMENT */: {
490
- if (attr.args) {
491
- 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
+ );
492
532
  return;
493
533
  }
494
- const start = child.start - 1;
495
- const end = ++this.pos;
496
- const value = {
497
- start: child.start,
498
- end: child.end
499
- };
500
- if (this.consumeWhitespaceIfBefore("{")) {
501
- attr.args = {
502
- start,
503
- end,
504
- value
505
- };
506
- } else {
507
- attr.args = true;
508
- (_d = (_c = this.options).onAttrArgs) == null ? void 0 : _d.call(_c, {
509
- start,
510
- end,
511
- value
512
- });
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;
513
541
  }
514
- break;
515
- }
516
- case 4 /* BLOCK */: {
517
- const params = attr.args;
518
- const start = params.start;
519
- const end = ++this.pos;
520
- (_f = (_e = this.options).onAttrMethod) == null ? void 0 : _f.call(_e, {
521
- start,
522
- end,
523
- params,
524
- body: {
525
- start: child.start - 1,
526
- end,
527
- value: {
528
- start: child.start,
529
- end: child.end
530
- }
531
- }
532
- });
533
542
  this.exitState();
534
- break;
535
- }
536
- case 2 /* VALUE */: {
537
- if (child.start === child.end) {
538
- 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
+ }
539
555
  }
540
- if (attr.spread) {
541
- (_h = (_g = this.options).onAttrSpread) == null ? void 0 : _h.call(_g, {
542
- start: attr.valueStart,
543
- end: child.end,
544
- value: {
545
- start: child.start,
546
- end: child.end
547
- }
548
- });
549
- } else {
550
- (_j = (_i = this.options).onAttrValue) == null ? void 0 : _j.call(_i, {
551
- start: attr.valueStart,
552
- end: child.end,
553
- bound: attr.bound,
554
- value: {
556
+ const indentSize = curPos - indentStart;
557
+ if (indentSize > this.indent.length) {
558
+ this.indent = this.data.slice(indentStart, curPos);
559
+ }
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 = {
555
692
  start: child.start,
556
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
+ });
557
708
  }
558
- });
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
+ }
559
723
  }
560
- this.exitState();
561
724
  break;
562
725
  }
563
726
  }
564
727
  }
565
728
  };
566
- function ensureAttrName(parser, attr) {
567
- var _a, _b;
568
- if (!attr.name) {
569
- (_b = (_a = parser.options).onAttrName) == null ? void 0 : _b.call(_a, {
570
- start: attr.start,
571
- end: attr.start
572
- });
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;
573
757
  }
574
758
  }
575
759
 
576
- // src/states/BEGIN_DELIMITED_HTML_BLOCK.ts
577
- var BEGIN_DELIMITED_HTML_BLOCK = {
578
- name: "BEGIN_DELIMITED_HTML_BLOCK",
760
+ // src/states/ATTRIBUTE.ts
761
+ var ATTRIBUTE = {
762
+ name: "ATTRIBUTE",
579
763
  enter(parent, start) {
580
- return {
581
- state: BEGIN_DELIMITED_HTML_BLOCK,
764
+ return this.activeAttr = {
765
+ state: ATTRIBUTE,
582
766
  parent,
583
767
  start,
584
768
  end: start,
585
- indent: this.indent,
586
- delimiter: ""
769
+ valueStart: start,
770
+ stage: 0 /* UNKNOWN */,
771
+ name: void 0,
772
+ args: false,
773
+ bound: false,
774
+ spread: false
587
775
  };
588
776
  },
589
777
  exit() {
778
+ this.activeAttr = void 0;
590
779
  },
591
- char(code, block) {
592
- if (code === 45 /* HTML_BLOCK_DELIMITER */) {
593
- block.delimiter += "-";
594
- } else {
595
- const startPos = this.pos;
596
- if (!this.consumeWhitespaceOnLine()) {
597
- this.pos = startPos + 1;
598
- this.forward = 0;
599
- 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();
600
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();
601
824
  }
602
825
  },
603
- eol(len, block) {
604
- this.beginHtmlBlock(block.delimiter, false);
605
- handleDelimitedBlockEOL(this, len, block);
606
- },
607
- eof: htmlEOF,
608
- return() {
609
- }
610
- };
611
- function handleDelimitedEOL(parser, newLineLength, content) {
612
- if (content.singleLine) {
613
- parser.endText();
614
- parser.exitState();
615
- parser.exitState();
616
- return true;
617
- }
618
- if (content.delimiter) {
619
- handleDelimitedBlockEOL(parser, newLineLength, content);
620
- return true;
621
- }
622
- return false;
623
- }
624
- function handleDelimitedBlockEOL(parser, newLineLength, {
625
- indent,
626
- delimiter
627
- }) {
628
- const endHtmlBlockLookahead = indent + delimiter;
629
- if (parser.lookAheadFor(endHtmlBlockLookahead, parser.pos + newLineLength)) {
630
- parser.startText();
631
- parser.pos += newLineLength;
632
- parser.endText();
633
- parser.pos += endHtmlBlockLookahead.length;
634
- if (parser.consumeWhitespaceOnLine(0)) {
635
- parser.endText();
636
- parser.exitState();
637
- parser.exitState();
638
- } else {
639
- parser.emitError(parser.pos, 4 /* INVALID_CHARACTER */, "A concise mode closing block delimiter can only be followed by whitespace.");
826
+ eol() {
827
+ if (this.isConcise) {
828
+ this.exitState();
829
+ }
830
+ },
831
+ eof(attr) {
832
+ if (this.isConcise) {
833
+ this.exitState();
834
+ } else {
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
+ );
840
+ }
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
+ );
640
1091
  }
641
1092
  } else if (parser.lookAheadFor(indent, parser.pos + newLineLength)) {
642
1093
  parser.startText();
@@ -682,7 +1133,11 @@ var CDATA = {
682
1133
  eol() {
683
1134
  },
684
1135
  eof(cdata) {
685
- 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
+ );
686
1141
  },
687
1142
  return() {
688
1143
  }
@@ -721,7 +1176,11 @@ var CLOSE_TAG = {
721
1176
  eol() {
722
1177
  },
723
1178
  eof(closeTag) {
724
- 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
+ );
725
1184
  },
726
1185
  return() {
727
1186
  }
@@ -763,7 +1222,11 @@ function ensureExpectedCloseTag(parser, closeTag) {
763
1222
  const closeTagNameStart = closeTag.start + 2;
764
1223
  const closeTagNameEnd = closeTag.end - 1;
765
1224
  if (!activeTag) {
766
- 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
+ );
767
1230
  return false;
768
1231
  }
769
1232
  const closeTagNamePos = {
@@ -771,12 +1234,19 @@ function ensureExpectedCloseTag(parser, closeTag) {
771
1234
  end: closeTagNameEnd
772
1235
  };
773
1236
  if (closeTagNameStart < closeTagNameEnd) {
774
- 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
+ )) {
775
1241
  if (activeTag.shorthandEnd === void 0 || !parser.matchAtPos(closeTagNamePos, {
776
1242
  start: activeTag.tagName.start,
777
1243
  end: activeTag.shorthandEnd
778
1244
  })) {
779
- 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
+ );
780
1250
  return false;
781
1251
  }
782
1252
  }
@@ -812,18 +1282,30 @@ var CONCISE_HTML_CONTENT = {
812
1282
  parentTag = this.activeTag;
813
1283
  }
814
1284
  if (!parentTag && curIndent) {
815
- 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
+ );
816
1290
  return;
817
1291
  }
818
1292
  if (parentTag) {
819
1293
  if (parentTag.type === 1 /* text */ && code !== 45 /* HTML_BLOCK_DELIMITER */) {
820
- 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
+ );
821
1299
  return;
822
1300
  }
823
1301
  if (parentTag.nestedIndent === void 0) {
824
1302
  parentTag.nestedIndent = this.indent;
825
1303
  } else if (parentTag.nestedIndent !== this.indent) {
826
- 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
+ );
827
1309
  return;
828
1310
  }
829
1311
  }
@@ -845,7 +1327,11 @@ var CONCISE_HTML_CONTENT = {
845
1327
  this.enterState(states_exports.BEGIN_DELIMITED_HTML_BLOCK);
846
1328
  this.pos--;
847
1329
  } else {
848
- 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
+ );
849
1335
  }
850
1336
  return;
851
1337
  case 47 /* FORWARD_SLASH */:
@@ -859,7 +1345,11 @@ var CONCISE_HTML_CONTENT = {
859
1345
  this.pos++;
860
1346
  return;
861
1347
  default:
862
- 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
+ );
863
1353
  return;
864
1354
  }
865
1355
  }
@@ -896,7 +1386,11 @@ var CONCISE_HTML_CONTENT = {
896
1386
  }
897
1387
  });
898
1388
  if (!this.consumeWhitespaceOnLine(0)) {
899
- 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
+ );
900
1394
  }
901
1395
  break;
902
1396
  }
@@ -930,7 +1424,11 @@ var DECLARATION = {
930
1424
  eol() {
931
1425
  },
932
1426
  eof(declaration) {
933
- 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
+ );
934
1432
  },
935
1433
  return() {
936
1434
  }
@@ -981,16 +1479,29 @@ var DTD = {
981
1479
  eol() {
982
1480
  },
983
1481
  eof(documentType) {
984
- 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
+ );
985
1487
  },
986
1488
  return() {
987
1489
  }
988
1490
  };
989
1491
 
990
1492
  // src/states/EXPRESSION.ts
991
- var htmlAttrsPattern = buildPattern(0 /* HTML_ATTRS */);
992
- var conciseAttrsPattern = buildPattern(1 /* CONCISE_ATTRS */);
993
- 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"];
994
1505
  var EXPRESSION = {
995
1506
  name: "EXPRESSION",
996
1507
  enter(parent, start) {
@@ -1000,8 +1511,8 @@ var EXPRESSION = {
1000
1511
  start,
1001
1512
  end: start,
1002
1513
  groupStack: [],
1003
- terminator: -1,
1004
- skipOperators: false,
1514
+ shouldTerminate,
1515
+ operators: false,
1005
1516
  terminatedByEOL: false,
1006
1517
  terminatedByWhitespace: false
1007
1518
  };
@@ -1011,12 +1522,12 @@ var EXPRESSION = {
1011
1522
  char(code, expression) {
1012
1523
  if (!expression.groupStack.length) {
1013
1524
  if (expression.terminatedByWhitespace && isWhitespaceCode(code)) {
1014
- if (!checkForOperators(this, expression)) {
1525
+ if (!checkForOperators(this, expression, false)) {
1015
1526
  this.exitState();
1016
1527
  }
1017
1528
  return;
1018
1529
  }
1019
- if (typeof expression.terminator === "number" ? expression.terminator === code : checkForTerminators(this, code, expression.terminator)) {
1530
+ if (expression.shouldTerminate(code, this.data, this.pos)) {
1020
1531
  this.exitState();
1021
1532
  return;
1022
1533
  }
@@ -1042,7 +1553,7 @@ var EXPRESSION = {
1042
1553
  this.pos++;
1043
1554
  break;
1044
1555
  default: {
1045
- if (canCharCodeBeFollowedByDivision(this.getPreviousNonWhitespaceCharCode())) {
1556
+ if (canFollowDivision(this.getPreviousNonWhitespaceCharCode())) {
1046
1557
  this.pos++;
1047
1558
  this.consumeWhitespace();
1048
1559
  } else {
@@ -1065,18 +1576,26 @@ var EXPRESSION = {
1065
1576
  case 93 /* CLOSE_SQUARE_BRACKET */:
1066
1577
  case 125 /* CLOSE_CURLY_BRACE */: {
1067
1578
  if (!expression.groupStack.length) {
1068
- 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
+ );
1069
1584
  }
1070
1585
  const expectedCode = expression.groupStack.pop();
1071
1586
  if (expectedCode !== code) {
1072
- 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
+ );
1073
1592
  }
1074
1593
  break;
1075
1594
  }
1076
1595
  }
1077
1596
  },
1078
1597
  eol(_, expression) {
1079
- if (!expression.groupStack.length && (expression.terminatedByEOL || expression.terminatedByWhitespace) && !checkForOperators(this, expression)) {
1598
+ if (!expression.groupStack.length && (expression.terminatedByEOL || expression.terminatedByWhitespace) && !checkForOperators(this, expression, true)) {
1080
1599
  this.exitState();
1081
1600
  }
1082
1601
  },
@@ -1089,69 +1608,216 @@ var EXPRESSION = {
1089
1608
  case states_exports.ATTRIBUTE: {
1090
1609
  const attr = parent;
1091
1610
  if (!attr.spread && !attr.name) {
1092
- 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
+ );
1093
1616
  }
1094
- 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
+ );
1095
1622
  }
1096
1623
  case states_exports.TAG_NAME:
1097
- 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
+ );
1098
1629
  case states_exports.PLACEHOLDER:
1099
- 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
+ );
1100
1635
  }
1101
- 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
+ );
1102
1641
  }
1103
1642
  },
1104
1643
  return() {
1105
1644
  }
1106
1645
  };
1107
- function buildPattern(type) {
1108
- const space = type === 1 /* CONCISE_ATTRS */ ? "[ \\t]" : "\\s";
1109
- const binary = `(?:[!~*%&^|?<]+=*)+|:+(?!=)|[>/+=-]+=|=>|(?<!\\+)[ \\t]*\\+(?:\\s*\\+\\s*\\+)*\\s*(?!\\+)|(?<!-)-${type === 1 /* CONCISE_ATTRS */ ? "" : "(?:\\s*-\\s*-)*\\s*"}(?!-)|(?<!\\.)\\.(?!\\.)|>${type === 0 /* HTML_ATTRS */ ? "{2,}" : "+"}|[ \\t]+(?:in(?:stanceof)?|as|extends)(?=[ \\t]+[^=/,;:>])`;
1110
- const unary = "\\b(?<![.]\\s*)(?:a(?:sync|wait)|keyof|class|function|new|typeof|void)\\b";
1111
- const lookAheadPattern = `${space}*(?:${binary})\\s*|${space}+(?=[{(]|/[^>])`;
1112
- const lookBehindPattern = `(?<=${unary}|${binary})`;
1113
- return new RegExp(`${lookAheadPattern}|${lookBehindPattern}`, "ym");
1114
- }
1115
- function checkForOperators(parser, expression) {
1116
- var _a;
1117
- if (expression.skipOperators) {
1646
+ function checkForOperators(parser, expression, eol) {
1647
+ if (!expression.operators)
1118
1648
  return false;
1649
+ const { pos, data } = parser;
1650
+ if (lookBehindForOperator(data, pos) !== -1) {
1651
+ parser.consumeWhitespace();
1652
+ parser.forward = 0;
1653
+ return true;
1119
1654
  }
1120
- const pattern = parser.isConcise ? ((_a = parser.activeTag) == null ? void 0 : _a.stage) === states_exports.TAG_STAGE.ATTR_GROUP ? conciseAttrsGroupPattern : conciseAttrsPattern : expression.terminatedByEOL ? conciseAttrsPattern : htmlAttrsPattern;
1121
- pattern.lastIndex = parser.pos;
1122
- const matches = pattern.exec(parser.data);
1123
- if (matches) {
1124
- const [match] = matches;
1125
- if (match.length === 0) {
1126
- parser.consumeWhitespace();
1127
- } else {
1128
- 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
+ }
1129
1673
  }
1130
- parser.forward = 0;
1131
- } else {
1132
- return false;
1133
1674
  }
1134
- return true;
1675
+ return false;
1135
1676
  }
1136
- function checkForTerminators(parser, code, terminators) {
1137
- outer:
1138
- for (const terminator of terminators) {
1139
- if (typeof terminator === "number") {
1140
- if (code === terminator)
1141
- return true;
1142
- } else {
1143
- if (terminator[0] === code) {
1144
- for (let i = terminator.length; i-- > 1; ) {
1145
- if (parser.data.charCodeAt(parser.pos + i) !== terminator[i])
1146
- continue outer;
1147
- }
1148
- 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;
1149
1766
  }
1150
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;
1151
1806
  }
1807
+ }
1808
+ return endPos;
1152
1809
  }
1153
- function canCharCodeBeFollowedByDivision(code) {
1154
- 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;
1155
1821
  }
1156
1822
 
1157
1823
  // src/states/HTML_COMMENT.ts
@@ -1192,7 +1858,11 @@ var HTML_COMMENT = {
1192
1858
  eol() {
1193
1859
  },
1194
1860
  eof(comment) {
1195
- 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
+ );
1196
1866
  },
1197
1867
  return() {
1198
1868
  }
@@ -1252,7 +1922,7 @@ var HTML_CONTENT = {
1252
1922
  this.endText();
1253
1923
  this.enterState(states_exports.INLINE_SCRIPT);
1254
1924
  this.pos++;
1255
- } else if (code === 47 /* FORWARD_SLASH */) {
1925
+ } else if (code === 47 /* FORWARD_SLASH */ && isWhitespaceCode(this.lookAtCharCodeAhead(-1))) {
1256
1926
  switch (this.lookAtCharCodeAhead(1)) {
1257
1927
  case 47 /* FORWARD_SLASH */:
1258
1928
  this.endText();
@@ -1366,11 +2036,10 @@ var INLINE_SCRIPT = {
1366
2036
  if (code === 123 /* OPEN_CURLY_BRACE */) {
1367
2037
  inlineScript.block = true;
1368
2038
  this.pos++;
1369
- const expr = this.enterState(states_exports.EXPRESSION);
1370
- expr.terminator = 125 /* CLOSE_CURLY_BRACE */;
1371
- expr.skipOperators = true;
2039
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseCurlyBrace;
1372
2040
  } else {
1373
2041
  const expr = this.enterState(states_exports.EXPRESSION);
2042
+ expr.operators = true;
1374
2043
  expr.terminatedByEOL = true;
1375
2044
  }
1376
2045
  },
@@ -1405,7 +2074,11 @@ var JS_COMMENT_BLOCK = {
1405
2074
  eol() {
1406
2075
  },
1407
2076
  eof(comment) {
1408
- 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
+ );
1409
2082
  },
1410
2083
  return() {
1411
2084
  }
@@ -1528,7 +2201,11 @@ var PLACEHOLDER = {
1528
2201
  },
1529
2202
  return(child) {
1530
2203
  if (child.start === child.end) {
1531
- 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
+ );
1532
2209
  }
1533
2210
  this.pos++;
1534
2211
  this.exitState();
@@ -1568,7 +2245,7 @@ function checkForPlaceholder(parser, code) {
1568
2245
  parser.enterState(PLACEHOLDER).escape = escape;
1569
2246
  parser.pos += escape ? 2 : 3;
1570
2247
  parser.forward = 0;
1571
- parser.enterState(states_exports.EXPRESSION).terminator = 125 /* CLOSE_CURLY_BRACE */;
2248
+ parser.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseCurlyBrace;
1572
2249
  return true;
1573
2250
  }
1574
2251
  }
@@ -1602,10 +2279,18 @@ var REGULAR_EXPRESSION = {
1602
2279
  }
1603
2280
  },
1604
2281
  eol(_, regExp) {
1605
- 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
+ );
1606
2287
  },
1607
2288
  eof(regExp) {
1608
- 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
+ );
1609
2294
  },
1610
2295
  return() {
1611
2296
  }
@@ -1639,7 +2324,11 @@ var STRING = {
1639
2324
  eol() {
1640
2325
  },
1641
2326
  eof(string) {
1642
- 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
+ );
1643
2332
  },
1644
2333
  return() {
1645
2334
  }
@@ -1667,7 +2356,11 @@ var TAG_NAME = {
1667
2356
  switch (tagName.shorthandCode) {
1668
2357
  case 35 /* NUMBER_SIGN */:
1669
2358
  if (this.activeTag.hasShorthandId) {
1670
- 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
+ );
1671
2364
  }
1672
2365
  this.activeTag.hasShorthandId = true;
1673
2366
  (_b = (_a = this.options).onTagShorthandId) == null ? void 0 : _b.call(_a, {
@@ -1698,12 +2391,26 @@ var TAG_NAME = {
1698
2391
  tag.type = tagType;
1699
2392
  if (tagType === 3 /* statement */) {
1700
2393
  if (!tag.concise) {
1701
- 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
+ );
1702
2401
  }
1703
2402
  if (tag.parentTag) {
1704
- 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
+ );
1705
2410
  }
1706
- this.enterState(states_exports.EXPRESSION).terminatedByEOL = true;
2411
+ const expr = this.enterState(states_exports.EXPRESSION);
2412
+ expr.operators = true;
2413
+ expr.terminatedByEOL = true;
1707
2414
  }
1708
2415
  }
1709
2416
  break;
@@ -1714,7 +2421,7 @@ var TAG_NAME = {
1714
2421
  if (code === 36 /* DOLLAR */ && this.lookAtCharCodeAhead(1) === 123 /* OPEN_CURLY_BRACE */) {
1715
2422
  this.pos += 2;
1716
2423
  this.forward = 0;
1717
- this.enterState(states_exports.EXPRESSION).terminator = 125 /* CLOSE_CURLY_BRACE */;
2424
+ this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseCurlyBrace;
1718
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 */)) {
1719
2426
  this.activeTag.shorthandEnd = this.pos;
1720
2427
  this.exitState();
@@ -1736,7 +2443,11 @@ var TAG_NAME = {
1736
2443
  if (child.terminatedByEOL)
1737
2444
  return;
1738
2445
  if (child.start === child.end) {
1739
- 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
+ );
1740
2451
  }
1741
2452
  const { quasis, expressions } = tagName;
1742
2453
  const start = child.start - 2;
@@ -1769,334 +2480,43 @@ var TEMPLATE_STRING = {
1769
2480
  exit() {
1770
2481
  },
1771
2482
  char(code) {
1772
- if (code === 36 /* DOLLAR */ && this.lookAtCharCodeAhead(1) === 123 /* OPEN_CURLY_BRACE */) {
1773
- this.pos++;
1774
- const expr = this.enterState(states_exports.EXPRESSION);
1775
- expr.skipOperators = true;
1776
- expr.terminator = 125 /* CLOSE_CURLY_BRACE */;
1777
- } else {
1778
- 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 */:
1779
2491
  this.pos++;
1780
- } else if (code === 96 /* BACKTICK */) {
2492
+ break;
2493
+ case 96 /* BACKTICK */:
1781
2494
  this.pos++;
1782
2495
  this.exitState();
1783
- }
2496
+ break;
1784
2497
  }
1785
2498
  },
1786
2499
  eof(templateString) {
1787
- 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
+ );
1788
2505
  },
1789
2506
  eol() {
1790
2507
  },
1791
2508
  return(child) {
1792
2509
  if (child.start === child.end) {
1793
- 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
+ );
1794
2515
  }
1795
2516
  this.pos++;
1796
2517
  }
1797
2518
  };
1798
2519
 
1799
- // src/states/OPEN_TAG.ts
1800
- var TAG_STAGE = /* @__PURE__ */ ((TAG_STAGE2) => {
1801
- TAG_STAGE2[TAG_STAGE2["UNKNOWN"] = 0] = "UNKNOWN";
1802
- TAG_STAGE2[TAG_STAGE2["VAR"] = 1] = "VAR";
1803
- TAG_STAGE2[TAG_STAGE2["ARGUMENT"] = 2] = "ARGUMENT";
1804
- TAG_STAGE2[TAG_STAGE2["PARAMS"] = 3] = "PARAMS";
1805
- TAG_STAGE2[TAG_STAGE2["ATTR_GROUP"] = 4] = "ATTR_GROUP";
1806
- return TAG_STAGE2;
1807
- })(TAG_STAGE || {});
1808
- var CONCISE_TAG_VAR_TERMINATORS = [
1809
- 59 /* SEMICOLON */,
1810
- 40 /* OPEN_PAREN */,
1811
- 124 /* PIPE */,
1812
- 61 /* EQUAL */,
1813
- 44 /* COMMA */,
1814
- [58 /* COLON */, 61 /* EQUAL */]
1815
- ];
1816
- var HTML_TAG_VAR_TERMINATORS = [
1817
- 62 /* CLOSE_ANGLE_BRACKET */,
1818
- 40 /* OPEN_PAREN */,
1819
- 124 /* PIPE */,
1820
- 61 /* EQUAL */,
1821
- 44 /* COMMA */,
1822
- [58 /* COLON */, 61 /* EQUAL */],
1823
- [47 /* FORWARD_SLASH */, 62 /* CLOSE_ANGLE_BRACKET */]
1824
- ];
1825
- var OPEN_TAG = {
1826
- name: "OPEN_TAG",
1827
- enter(parent, start) {
1828
- const tag = this.activeTag = {
1829
- state: OPEN_TAG,
1830
- type: 0 /* html */,
1831
- parent,
1832
- start,
1833
- end: start,
1834
- stage: 0 /* UNKNOWN */,
1835
- parentTag: this.activeTag,
1836
- nestedIndent: void 0,
1837
- indent: this.indent,
1838
- hasShorthandId: false,
1839
- hasArgs: false,
1840
- hasAttrs: false,
1841
- selfClosed: false,
1842
- shorthandEnd: -1,
1843
- tagName: void 0,
1844
- concise: this.isConcise,
1845
- beginMixedMode: this.beginMixedMode || this.endingMixedModeAtEOL
1846
- };
1847
- this.beginMixedMode = false;
1848
- this.endingMixedModeAtEOL = false;
1849
- this.endText();
1850
- return tag;
1851
- },
1852
- exit(tag) {
1853
- var _a, _b;
1854
- const { selfClosed } = tag;
1855
- (_b = (_a = this.options).onOpenTagEnd) == null ? void 0 : _b.call(_a, {
1856
- start: this.pos - (this.isConcise ? 0 : selfClosed ? 2 : 1),
1857
- end: this.pos,
1858
- selfClosed
1859
- });
1860
- switch (selfClosed ? 2 /* void */ : tag.type) {
1861
- case 2 /* void */:
1862
- case 3 /* statement */: {
1863
- if (tag.beginMixedMode)
1864
- this.endingMixedModeAtEOL = true;
1865
- this.activeTag = tag.parentTag;
1866
- break;
1867
- }
1868
- case 1 /* text */:
1869
- if (this.isConcise) {
1870
- this.enterState(states_exports.CONCISE_HTML_CONTENT);
1871
- } else {
1872
- this.enterState(states_exports.PARSED_TEXT_CONTENT);
1873
- }
1874
- break;
1875
- }
1876
- },
1877
- eol(_, tag) {
1878
- if (this.isConcise && tag.stage !== 4 /* ATTR_GROUP */) {
1879
- this.exitState();
1880
- }
1881
- },
1882
- eof(tag) {
1883
- if (this.isConcise) {
1884
- if (tag.stage === 4 /* ATTR_GROUP */) {
1885
- this.emitError(tag, 19 /* MALFORMED_OPEN_TAG */, 'EOF reached while within an attribute group (e.g. "[ ... ]").');
1886
- return;
1887
- }
1888
- this.exitState();
1889
- } else {
1890
- this.emitError(tag, 19 /* MALFORMED_OPEN_TAG */, "EOF reached while parsing open tag");
1891
- }
1892
- },
1893
- char(code, tag) {
1894
- if (this.isConcise) {
1895
- if (code === 59 /* SEMICOLON */) {
1896
- this.pos++;
1897
- this.exitState();
1898
- if (!this.consumeWhitespaceOnLine(0)) {
1899
- switch (this.lookAtCharCodeAhead(0)) {
1900
- case 47 /* FORWARD_SLASH */:
1901
- switch (this.lookAtCharCodeAhead(1)) {
1902
- case 47 /* FORWARD_SLASH */:
1903
- this.enterState(states_exports.JS_COMMENT_LINE);
1904
- this.pos += 2;
1905
- return;
1906
- case 42 /* ASTERISK */:
1907
- this.enterState(states_exports.JS_COMMENT_BLOCK);
1908
- this.pos += 2;
1909
- return;
1910
- }
1911
- break;
1912
- case 60 /* OPEN_ANGLE_BRACKET */:
1913
- if (this.lookAheadFor("!--")) {
1914
- this.enterState(states_exports.HTML_COMMENT);
1915
- this.pos += 4;
1916
- return;
1917
- }
1918
- break;
1919
- }
1920
- this.emitError(this.pos, 5 /* INVALID_CODE_AFTER_SEMICOLON */, "A semicolon indicates the end of a line. Only comments may follow it.");
1921
- }
1922
- return;
1923
- }
1924
- if (code === 45 /* HTML_BLOCK_DELIMITER */) {
1925
- if (this.lookAtCharCodeAhead(1) !== 45 /* HTML_BLOCK_DELIMITER */) {
1926
- this.emitError(tag, 19 /* MALFORMED_OPEN_TAG */, '"-" not allowed as first character of attribute name');
1927
- return;
1928
- }
1929
- if (tag.stage === 4 /* ATTR_GROUP */) {
1930
- this.emitError(this.pos, 19 /* MALFORMED_OPEN_TAG */, "Attribute group was not properly ended");
1931
- return;
1932
- }
1933
- this.exitState();
1934
- const maxPos = this.maxPos;
1935
- let curPos = this.pos + 1;
1936
- while (curPos < maxPos && this.data.charCodeAt(++curPos) !== 10 /* NEWLINE */)
1937
- ;
1938
- const indentStart = ++curPos;
1939
- while (curPos < maxPos) {
1940
- const nextCode = this.data.charCodeAt(curPos);
1941
- if (nextCode === 32 /* SPACE */ || nextCode === 9 /* TAB */) {
1942
- curPos++;
1943
- } else {
1944
- break;
1945
- }
1946
- }
1947
- const indentSize = curPos - indentStart;
1948
- if (indentSize > this.indent.length) {
1949
- this.indent = this.data.slice(indentStart, curPos);
1950
- }
1951
- this.enterState(states_exports.BEGIN_DELIMITED_HTML_BLOCK);
1952
- return;
1953
- } else if (code === 91 /* OPEN_SQUARE_BRACKET */) {
1954
- if (tag.stage === 4 /* ATTR_GROUP */) {
1955
- this.emitError(this.pos, 19 /* MALFORMED_OPEN_TAG */, 'Unexpected "[" character within open tag.');
1956
- return;
1957
- }
1958
- tag.stage = 4 /* ATTR_GROUP */;
1959
- return;
1960
- } else if (code === 93 /* CLOSE_SQUARE_BRACKET */) {
1961
- if (tag.stage !== 4 /* ATTR_GROUP */) {
1962
- this.emitError(this.pos, 19 /* MALFORMED_OPEN_TAG */, 'Unexpected "]" character within open tag.');
1963
- return;
1964
- }
1965
- tag.stage = 0 /* UNKNOWN */;
1966
- return;
1967
- }
1968
- } else if (code === 62 /* CLOSE_ANGLE_BRACKET */) {
1969
- this.pos++;
1970
- this.exitState();
1971
- return;
1972
- } else if (code === 47 /* FORWARD_SLASH */ && this.lookAtCharCodeAhead(1) === 62 /* CLOSE_ANGLE_BRACKET */) {
1973
- tag.selfClosed = true;
1974
- this.pos += 2;
1975
- this.exitState();
1976
- return;
1977
- }
1978
- if (code === 60 /* OPEN_ANGLE_BRACKET */) {
1979
- return this.emitError(this.pos, 2 /* INVALID_ATTRIBUTE_NAME */, 'Invalid attribute name. Attribute name cannot begin with the "<" character.');
1980
- }
1981
- if (code === 47 /* FORWARD_SLASH */) {
1982
- switch (this.lookAtCharCodeAhead(1)) {
1983
- case 47 /* FORWARD_SLASH */:
1984
- this.enterState(states_exports.JS_COMMENT_LINE);
1985
- this.pos++;
1986
- return;
1987
- case 42 /* ASTERISK */:
1988
- this.enterState(states_exports.JS_COMMENT_BLOCK);
1989
- this.pos++;
1990
- return;
1991
- }
1992
- }
1993
- if (isWhitespaceCode(code)) {
1994
- } else if (code === 44 /* COMMA */) {
1995
- this.pos++;
1996
- this.forward = 0;
1997
- this.consumeWhitespace();
1998
- } else if (code === 47 /* FORWARD_SLASH */ && !tag.hasAttrs) {
1999
- tag.stage = 1 /* VAR */;
2000
- this.pos++;
2001
- this.forward = 0;
2002
- if (isWhitespaceCode(this.lookAtCharCodeAhead(0))) {
2003
- return this.emitError(this.pos, 23 /* MISSING_TAG_VARIABLE */, "A slash was found that was not followed by a variable name or lhs expression");
2004
- }
2005
- const expr = this.enterState(states_exports.EXPRESSION);
2006
- expr.terminatedByWhitespace = true;
2007
- expr.terminator = this.isConcise ? CONCISE_TAG_VAR_TERMINATORS : HTML_TAG_VAR_TERMINATORS;
2008
- } else if (code === 40 /* OPEN_PAREN */ && !tag.hasAttrs) {
2009
- if (tag.hasArgs) {
2010
- this.emitError(this.pos, 11 /* INVALID_TAG_ARGUMENT */, "A tag can only have one argument");
2011
- return;
2012
- }
2013
- tag.stage = 2 /* ARGUMENT */;
2014
- this.pos++;
2015
- this.forward = 0;
2016
- const expr = this.enterState(states_exports.EXPRESSION);
2017
- expr.skipOperators = true;
2018
- expr.terminator = 41 /* CLOSE_PAREN */;
2019
- } else if (code === 124 /* PIPE */ && !tag.hasAttrs) {
2020
- tag.stage = 3 /* PARAMS */;
2021
- this.pos++;
2022
- this.forward = 0;
2023
- const expr = this.enterState(states_exports.EXPRESSION);
2024
- expr.skipOperators = true;
2025
- expr.terminator = 124 /* PIPE */;
2026
- } else {
2027
- this.forward = 0;
2028
- if (tag.tagName) {
2029
- this.enterState(states_exports.ATTRIBUTE);
2030
- tag.hasAttrs = true;
2031
- } else {
2032
- this.enterState(states_exports.TAG_NAME);
2033
- }
2034
- }
2035
- },
2036
- return(child, tag) {
2037
- var _a, _b, _c, _d, _e, _f;
2038
- switch (child.state) {
2039
- case states_exports.JS_COMMENT_BLOCK: {
2040
- break;
2041
- }
2042
- case states_exports.EXPRESSION: {
2043
- switch (tag.stage) {
2044
- case 1 /* VAR */: {
2045
- if (child.start === child.end) {
2046
- return this.emitError(child, 23 /* MISSING_TAG_VARIABLE */, "A slash was found that was not followed by a variable name or lhs expression");
2047
- }
2048
- (_b = (_a = this.options).onTagVar) == null ? void 0 : _b.call(_a, {
2049
- start: child.start - 1,
2050
- end: child.end,
2051
- value: {
2052
- start: child.start,
2053
- end: child.end
2054
- }
2055
- });
2056
- break;
2057
- }
2058
- case 2 /* ARGUMENT */: {
2059
- const start = child.start - 1;
2060
- const end = ++this.pos;
2061
- const value = {
2062
- start: child.start,
2063
- end: child.end
2064
- };
2065
- if (this.consumeWhitespaceIfBefore("{")) {
2066
- const attr = this.enterState(states_exports.ATTRIBUTE);
2067
- attr.start = start;
2068
- attr.args = { start, end, value };
2069
- tag.hasAttrs = true;
2070
- this.forward = 0;
2071
- } else {
2072
- tag.hasArgs = true;
2073
- (_d = (_c = this.options).onTagArgs) == null ? void 0 : _d.call(_c, {
2074
- start,
2075
- end,
2076
- value
2077
- });
2078
- }
2079
- break;
2080
- }
2081
- case 3 /* PARAMS */: {
2082
- const end = ++this.pos;
2083
- (_f = (_e = this.options).onTagParams) == null ? void 0 : _f.call(_e, {
2084
- start: child.start - 1,
2085
- end,
2086
- value: {
2087
- start: child.start,
2088
- end: child.end
2089
- }
2090
- });
2091
- break;
2092
- }
2093
- }
2094
- break;
2095
- }
2096
- }
2097
- }
2098
- };
2099
-
2100
2520
  // src/index.ts
2101
2521
  function createParser(handlers) {
2102
2522
  const parser = new Parser(handlers);
@@ -2119,5 +2539,8 @@ function createParser(handlers) {
2119
2539
  0 && (module.exports = {
2120
2540
  ErrorCode,
2121
2541
  TagType,
2122
- createParser
2542
+ createParser,
2543
+ getLines,
2544
+ getLocation,
2545
+ getPosition
2123
2546
  });