@markuplint/parser-utils 3.0.0-dev.24 → 3.0.0-dev.290

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.
@@ -1,11 +1,8 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.restoreNode = exports.ignoreBlock = void 0;
4
- const const_1 = require("./const");
5
- const create_token_1 = require("./create-token");
6
- const get_location_1 = require("./get-location");
7
- const siblings_correction_1 = require("./siblings-correction");
8
- function ignoreBlock(source, tags, maskChar = const_1.MASK_CHAR) {
1
+ import { MASK_CHAR } from './const.js';
2
+ import { uuid } from './create-token.js';
3
+ import { sliceFragment } from './get-location.js';
4
+ import { siblingsCorrection } from './siblings-correction.js';
5
+ export function ignoreBlock(source, tags, maskChar = MASK_CHAR) {
9
6
  let replaced = source;
10
7
  const stack = [];
11
8
  for (const tag of tags) {
@@ -13,7 +10,7 @@ function ignoreBlock(source, tags, maskChar = const_1.MASK_CHAR) {
13
10
  const attr = maskText(prepend(tag.start, '(?<=(?:"|\'))'), append(tag.end, '(?=(?:"|\'))'), replaced, (startTag, taggedCode, endTag) => {
14
11
  const mask = maskChar.repeat(startTag.length) +
15
12
  taggedCode.replace(/[^\n]/g, maskChar) +
16
- maskChar.repeat((endTag || '').length);
13
+ maskChar.repeat((endTag ?? '').length);
17
14
  return mask;
18
15
  });
19
16
  replaced = attr.replaced;
@@ -22,7 +19,7 @@ function ignoreBlock(source, tags, maskChar = const_1.MASK_CHAR) {
22
19
  const text = maskText(tag.start, tag.end, replaced, (startTag, taggedCode, endTag) => {
23
20
  const mask = maskChar.repeat(startTag.length) +
24
21
  taggedCode.replace(/[^\n]/g, maskChar) +
25
- maskChar.repeat((endTag || '').length);
22
+ maskChar.repeat((endTag ?? '').length);
26
23
  const taggedMask = `<!${mask.slice(2).slice(0, -1)}>`;
27
24
  return taggedMask;
28
25
  });
@@ -37,7 +34,6 @@ function ignoreBlock(source, tags, maskChar = const_1.MASK_CHAR) {
37
34
  maskChar,
38
35
  };
39
36
  }
40
- exports.ignoreBlock = ignoreBlock;
41
37
  function maskText(start, end, replaced, masking) {
42
38
  const stack = [];
43
39
  start = removeGlobalOption(start);
@@ -52,20 +48,21 @@ function maskText(start, end, replaced, masking) {
52
48
  index,
53
49
  startTag,
54
50
  taggedCode,
55
- endTag: endTag || null,
51
+ endTag: endTag ?? null,
56
52
  });
57
53
  /**
58
54
  * It will not replace line breaks because detects line number.
59
55
  */
60
- replaced = above + masking(startTag, taggedCode, endTag) + (below || '');
56
+ replaced = above + masking(startTag, taggedCode, endTag) + (below ?? '');
61
57
  }
62
58
  return {
63
59
  replaced,
64
60
  stack,
65
61
  };
66
62
  }
67
- function restoreNode(nodeList, ignoreBlock) {
68
- var _a, _b, _c, _d;
63
+ export function restoreNode(
64
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
65
+ nodeList, ignoreBlock) {
69
66
  nodeList = nodeList.slice();
70
67
  const { source, stack, maskChar } = ignoreBlock;
71
68
  for (const node of nodeList) {
@@ -81,15 +78,15 @@ function restoreNode(nodeList, ignoreBlock) {
81
78
  for (const tag of stack) {
82
79
  if (node.startOffset <= tag.index && tag.index < node.endOffset) {
83
80
  const start = tag.index - node.startOffset;
84
- const body = tag.startTag + tag.taggedCode + (tag.endTag || '');
81
+ const body = tag.startTag + tag.taggedCode + (tag.endTag ?? '');
85
82
  const above = node.raw.slice(pointer, start);
86
83
  const below = text.slice(above.length + body.length);
87
84
  if (above) {
88
85
  const offset = node.startOffset + pointer;
89
- const { raw, startOffset, endOffset, startLine, endLine, startCol, endCol } = (0, get_location_1.sliceFragment)(source, offset, offset + above.length);
86
+ const { raw, startOffset, endOffset, startLine, endLine, startCol, endCol } = sliceFragment(source, offset, offset + above.length);
90
87
  const textNode = {
91
88
  ...node,
92
- uuid: (0, create_token_1.uuid)(),
89
+ uuid: uuid(),
93
90
  type: 'text',
94
91
  raw,
95
92
  startOffset,
@@ -99,19 +96,19 @@ function restoreNode(nodeList, ignoreBlock) {
99
96
  startCol,
100
97
  endCol,
101
98
  };
102
- if ((_a = node.prevNode) === null || _a === void 0 ? void 0 : _a.nextNode) {
99
+ if (node.prevNode?.nextNode) {
103
100
  node.prevNode.nextNode = textNode;
104
101
  }
105
- if ((_b = node.nextNode) === null || _b === void 0 ? void 0 : _b.prevNode) {
102
+ if (node.nextNode?.prevNode) {
106
103
  node.nextNode.prevNode = textNode;
107
104
  }
108
105
  insertList.push(textNode);
109
106
  }
110
107
  if (body) {
111
108
  const offset = node.startOffset + pointer + above.length;
112
- const { raw, startOffset, endOffset, startLine, endLine, startCol, endCol } = (0, get_location_1.sliceFragment)(source, offset, offset + body.length);
109
+ const { raw, startOffset, endOffset, startLine, endLine, startCol, endCol } = sliceFragment(source, offset, offset + body.length);
113
110
  const bodyNode = {
114
- uuid: (0, create_token_1.uuid)(),
111
+ uuid: uuid(),
115
112
  type: 'psblock',
116
113
  nodeName: `#ps:${tag.type}`,
117
114
  raw,
@@ -127,10 +124,10 @@ function restoreNode(nodeList, ignoreBlock) {
127
124
  startCol,
128
125
  endCol,
129
126
  };
130
- if ((_c = node.prevNode) === null || _c === void 0 ? void 0 : _c.nextNode) {
127
+ if (node.prevNode?.nextNode) {
131
128
  node.prevNode.nextNode = bodyNode;
132
129
  }
133
- if ((_d = node.nextNode) === null || _d === void 0 ? void 0 : _d.prevNode) {
130
+ if (node.nextNode?.prevNode) {
134
131
  node.nextNode.prevNode = bodyNode;
135
132
  }
136
133
  insertList.push(bodyNode);
@@ -141,10 +138,10 @@ function restoreNode(nodeList, ignoreBlock) {
141
138
  }
142
139
  if (text) {
143
140
  const offset = node.endOffset - text.length;
144
- const { raw, startOffset, endOffset, startLine, endLine, startCol, endCol } = (0, get_location_1.sliceFragment)(source, offset, offset + text.length);
141
+ const { raw, startOffset, endOffset, startLine, endLine, startCol, endCol } = sliceFragment(source, offset, offset + text.length);
145
142
  const textNode = {
146
143
  ...node,
147
- uuid: (0, create_token_1.uuid)(),
144
+ uuid: uuid(),
148
145
  type: 'text',
149
146
  raw,
150
147
  startOffset,
@@ -156,7 +153,7 @@ function restoreNode(nodeList, ignoreBlock) {
156
153
  };
157
154
  insertList.push(textNode);
158
155
  }
159
- (0, siblings_correction_1.siblingsCorrection)(insertList);
156
+ siblingsCorrection(insertList);
160
157
  if (parentNode) {
161
158
  parentNode.childNodes = insertList;
162
159
  }
@@ -183,7 +180,6 @@ function restoreNode(nodeList, ignoreBlock) {
183
180
  }
184
181
  return nodeList;
185
182
  }
186
- exports.restoreNode = restoreNode;
187
183
  function snap(str, reg) {
188
184
  const matched = reg.exec(str);
189
185
  if (!matched) {
@@ -1,7 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ignoreFrontMatter = void 0;
4
- function ignoreFrontMatter(code) {
1
+ export function ignoreFrontMatter(code) {
5
2
  const reStart = /^(?:\s*\r?\n)?---\r?\n/.exec(code);
6
3
  if (!reStart) {
7
4
  return code;
@@ -18,4 +15,3 @@ function ignoreFrontMatter(code) {
18
15
  const masked = frontMatter.replace(/[^\r\n]/g, ' ');
19
16
  return masked + afterCode;
20
17
  }
21
- exports.ignoreFrontMatter = ignoreFrontMatter;
package/lib/index.d.ts CHANGED
@@ -1,10 +1,16 @@
1
- export * from './decision';
2
- export * from './get-location';
3
- export * from './create-token';
4
- export * from './idl-attributes';
5
- export * from './walker';
6
- export * from './ignore-block';
7
- export * from './ignore-front-matter';
8
- export * from './debugger';
9
- export * from './parser-error';
10
- export * from './detect-element-type';
1
+ export * from './const.js';
2
+ export * from './create-token.js';
3
+ export * from './debugger.js';
4
+ export * from './decision.js';
5
+ export * from './detect-element-type.js';
6
+ export * from './flatten-nodes.js';
7
+ export * from './get-location.js';
8
+ export * from './get-space-before.js';
9
+ export * from './idl-attributes.js';
10
+ export * from './ignore-block.js';
11
+ export * from './ignore-front-matter.js';
12
+ export * from './parse-attr.js';
13
+ export * from './parser-error.js';
14
+ export * from './remove-deprecated-node.js';
15
+ export * from './tag-splitter.js';
16
+ export * from './walker.js';
package/lib/index.js CHANGED
@@ -1,13 +1,16 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- tslib_1.__exportStar(require("./decision"), exports);
5
- tslib_1.__exportStar(require("./get-location"), exports);
6
- tslib_1.__exportStar(require("./create-token"), exports);
7
- tslib_1.__exportStar(require("./idl-attributes"), exports);
8
- tslib_1.__exportStar(require("./walker"), exports);
9
- tslib_1.__exportStar(require("./ignore-block"), exports);
10
- tslib_1.__exportStar(require("./ignore-front-matter"), exports);
11
- tslib_1.__exportStar(require("./debugger"), exports);
12
- tslib_1.__exportStar(require("./parser-error"), exports);
13
- tslib_1.__exportStar(require("./detect-element-type"), exports);
1
+ export * from './const.js';
2
+ export * from './create-token.js';
3
+ export * from './debugger.js';
4
+ export * from './decision.js';
5
+ export * from './detect-element-type.js';
6
+ export * from './flatten-nodes.js';
7
+ export * from './get-location.js';
8
+ export * from './get-space-before.js';
9
+ export * from './idl-attributes.js';
10
+ export * from './ignore-block.js';
11
+ export * from './ignore-front-matter.js';
12
+ export * from './parse-attr.js';
13
+ export * from './parser-error.js';
14
+ export * from './remove-deprecated-node.js';
15
+ export * from './tag-splitter.js';
16
+ export * from './walker.js';
@@ -0,0 +1,24 @@
1
+ import type { MLASTHTMLAttr } from '@markuplint/ml-ast';
2
+ type ParseAttrOptions = {
3
+ readonly booleanish?: boolean;
4
+ readonly valueDelimiters?: readonly ValueDelimiter[];
5
+ readonly equal?: string;
6
+ };
7
+ type ValueDelimiter = {
8
+ readonly start: string;
9
+ readonly end: string;
10
+ };
11
+ export declare const defaultValueDelimiters: readonly ValueDelimiter[];
12
+ export declare function parseAttr(raw: string, offset: number, html: string, options?: ParseAttrOptions): MLASTHTMLAttr;
13
+ export declare function tokenize(raw: string, options?: ParseAttrOptions): {
14
+ beforeName: string;
15
+ name: string;
16
+ afterName: string;
17
+ equal: string;
18
+ beforeValue: string;
19
+ startQuote: string;
20
+ value: string;
21
+ endQuote: string;
22
+ afterAttr: string;
23
+ };
24
+ export {};
@@ -0,0 +1,144 @@
1
+ import { createTokenFromRawCode, tokenizer, uuid } from './create-token.js';
2
+ export const defaultValueDelimiters = [
3
+ {
4
+ start: "'",
5
+ end: "'",
6
+ },
7
+ {
8
+ start: '"',
9
+ end: '"',
10
+ },
11
+ ];
12
+ const defaultEqual = '=';
13
+ const spaceRegex = /^\s$/;
14
+ export function parseAttr(raw, offset, html, options) {
15
+ const tokens = tokenize(raw, options);
16
+ tokens.beforeName;
17
+ const attrToken = createTokenFromRawCode(raw, offset, html);
18
+ const spacesBeforeName = tokenizer(tokens.beforeName, attrToken.startLine, attrToken.startCol, attrToken.startOffset);
19
+ const name = tokenizer(tokens.name, spacesBeforeName.endLine, spacesBeforeName.endCol, spacesBeforeName.endOffset);
20
+ const spacesBeforeEqual = tokenizer(tokens.afterName, name.endLine, name.endCol, name.endOffset);
21
+ const equal = tokenizer(tokens.equal, spacesBeforeEqual.endLine, spacesBeforeEqual.endCol, spacesBeforeEqual.endOffset);
22
+ const spacesAfterEqual = tokenizer(tokens.beforeValue, equal.endLine, equal.endCol, equal.endOffset);
23
+ const startQuote = tokenizer(tokens.startQuote, spacesAfterEqual.endLine, spacesAfterEqual.endCol, spacesAfterEqual.endOffset);
24
+ const value = tokenizer(tokens.value, startQuote.endLine, startQuote.endCol, startQuote.endOffset);
25
+ const endQuote = tokenizer(tokens.endQuote, value.endLine, value.endCol, value.endOffset);
26
+ const attr = {
27
+ type: 'html-attr',
28
+ uuid: uuid(),
29
+ raw: attrToken.raw,
30
+ startOffset: attrToken.startOffset,
31
+ endOffset: attrToken.endOffset,
32
+ startLine: attrToken.startLine,
33
+ endLine: attrToken.endLine,
34
+ startCol: attrToken.startCol,
35
+ endCol: attrToken.endCol,
36
+ spacesBeforeName,
37
+ name,
38
+ spacesBeforeEqual,
39
+ equal,
40
+ spacesAfterEqual,
41
+ startQuote,
42
+ value,
43
+ endQuote,
44
+ isDuplicatable: false,
45
+ nodeName: name.raw,
46
+ parentNode: null,
47
+ nextNode: null,
48
+ prevNode: null,
49
+ isFragment: false,
50
+ isGhost: false,
51
+ };
52
+ return attr;
53
+ }
54
+ export function tokenize(raw, options) {
55
+ const valueDelimiters = options?.valueDelimiters ?? defaultValueDelimiters;
56
+ const equalDelimiter = options?.equal ?? defaultEqual;
57
+ let state = 'b-name';
58
+ const charactors = raw.split('');
59
+ let beforeName = '';
60
+ let name = '';
61
+ let afterName = '';
62
+ let equal = '';
63
+ let valueDelimiter = null;
64
+ let beforeValue = '';
65
+ let startQuote = '';
66
+ let value = '';
67
+ let endQuote = '';
68
+ let afterAttr = '';
69
+ while (charactors.length > 0) {
70
+ const charactor = charactors.shift();
71
+ if (state === 'b-name') {
72
+ if (spaceRegex.test(charactor)) {
73
+ beforeName += charactor;
74
+ continue;
75
+ }
76
+ name += charactor;
77
+ state = 'name';
78
+ continue;
79
+ }
80
+ if (state === 'name') {
81
+ if (equalDelimiter === charactor) {
82
+ equal = equalDelimiter;
83
+ state = 'value-start';
84
+ continue;
85
+ }
86
+ if (spaceRegex.test(charactor)) {
87
+ afterName += charactor;
88
+ state = 'a-name';
89
+ continue;
90
+ }
91
+ name += charactor;
92
+ continue;
93
+ }
94
+ if (state === 'a-name') {
95
+ if (equalDelimiter === charactor) {
96
+ equal = equalDelimiter;
97
+ state = 'value-start';
98
+ continue;
99
+ }
100
+ if (spaceRegex.test(charactor)) {
101
+ afterName += charactor;
102
+ continue;
103
+ }
104
+ break;
105
+ }
106
+ if (state === 'value-start') {
107
+ if (spaceRegex.test(charactor)) {
108
+ beforeValue += charactor;
109
+ continue;
110
+ }
111
+ valueDelimiter = valueDelimiters.find(d => d.start === charactor) ?? null;
112
+ if (valueDelimiter) {
113
+ startQuote += valueDelimiter.start;
114
+ }
115
+ else {
116
+ value += beforeValue + charactor;
117
+ beforeValue = '';
118
+ }
119
+ state = 'value';
120
+ continue;
121
+ }
122
+ if (state !== 'value') {
123
+ throw new Error('ParseError: unknown parse state in the attribute');
124
+ }
125
+ value += charactor;
126
+ }
127
+ if (valueDelimiter) {
128
+ const endQuoteIndex = value.lastIndexOf(valueDelimiter.end);
129
+ endQuote = value.slice(endQuoteIndex, endQuoteIndex + 1);
130
+ afterAttr = value.slice(endQuoteIndex + 1);
131
+ value = value.slice(0, endQuoteIndex);
132
+ }
133
+ return {
134
+ beforeName,
135
+ name,
136
+ afterName,
137
+ equal,
138
+ beforeValue,
139
+ startQuote,
140
+ value,
141
+ endQuote,
142
+ afterAttr,
143
+ };
144
+ }
@@ -1,13 +1,26 @@
1
+ export type ParserErrorInfo = {
2
+ readonly line?: number;
3
+ readonly col?: number;
4
+ readonly raw?: string;
5
+ };
1
6
  export declare class ParserError extends Error {
2
7
  readonly col: number;
3
8
  readonly line: number;
4
9
  name: string;
5
- readonly nodeName: string | null;
6
10
  readonly raw: string;
7
- constructor(message: string, { line, col, raw, nodeName, }: {
8
- line?: number;
9
- col?: number;
10
- raw?: string;
11
- nodeName?: string | null;
11
+ constructor(message: string, info: ParserErrorInfo);
12
+ }
13
+ export declare class TargetParserError extends ParserError {
14
+ name: string;
15
+ readonly nodeName: string | null;
16
+ constructor(message: string, info: ParserErrorInfo & {
17
+ readonly nodeName?: string | null;
18
+ });
19
+ }
20
+ export declare class ConfigParserError extends ParserError {
21
+ readonly filePath: string;
22
+ name: string;
23
+ constructor(message: string, info: ParserErrorInfo & {
24
+ readonly filePath: string;
12
25
  });
13
26
  }
@@ -1,14 +1,29 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ParserError = void 0;
4
- class ParserError extends Error {
5
- constructor(message, { line = 1, col = 0, raw = '', nodeName = null, }) {
6
- super(nodeName ? `The ${nodeName} is invalid element (${line}:${col}): ${message}` : message);
1
+ export class ParserError extends Error {
2
+ constructor(message, info) {
3
+ super(message);
7
4
  this.name = 'ParserError';
8
- this.line = line;
9
- this.col = col;
10
- this.raw = raw;
11
- this.nodeName = nodeName;
5
+ this.line = info.line ?? 1;
6
+ this.col = info.col ?? 0;
7
+ this.raw = info.raw ?? '';
8
+ }
9
+ }
10
+ export class TargetParserError extends ParserError {
11
+ constructor(message, info) {
12
+ const errMsg = info.nodeName
13
+ ? `The ${info.nodeName} is invalid element (${info.line}:${info.col}): ${message}`
14
+ : message;
15
+ super(errMsg, info);
16
+ this.name = 'TargetParserError';
17
+ this.nodeName = info.nodeName ?? null;
18
+ }
19
+ }
20
+ export class ConfigParserError extends ParserError {
21
+ constructor(message, info) {
22
+ const pos = info.line != null && info.line != null ? `(${info.line}:${info.col})` : '';
23
+ const file = ` in ${info.filePath}${pos}`;
24
+ const errMsg = `${message}${file}`;
25
+ super(errMsg, info);
26
+ this.name = 'ConfigParserError';
27
+ this.filePath = info.filePath;
12
28
  }
13
29
  }
14
- exports.ParserError = ParserError;
@@ -0,0 +1,7 @@
1
+ import type { MLASTNode } from '@markuplint/ml-ast';
2
+ /**
3
+ *
4
+ * @disruptive
5
+ * @param nodeOrders [Disruptive change]
6
+ */
7
+ export declare function removeDeprecatedNode(nodeOrders: MLASTNode[]): void;
@@ -0,0 +1,39 @@
1
+ /**
2
+ *
3
+ * @disruptive
4
+ * @param nodeOrders [Disruptive change]
5
+ */
6
+ export function removeDeprecatedNode(
7
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
8
+ nodeOrders) {
9
+ /**
10
+ * sorting
11
+ */
12
+ nodeOrders.sort((a, b) => {
13
+ if (a.isGhost || b.isGhost) {
14
+ return 0;
15
+ }
16
+ return a.startOffset - b.startOffset;
17
+ });
18
+ /**
19
+ * remove duplicated node
20
+ */
21
+ const stack = {};
22
+ const removeIndexes = [];
23
+ nodeOrders.forEach((node, i) => {
24
+ if (node.isGhost) {
25
+ return;
26
+ }
27
+ const id = `${node.startLine}:${node.startCol}:${node.endLine}:${node.endCol}`;
28
+ if (stack[id] != null) {
29
+ removeIndexes.push(i);
30
+ }
31
+ stack[id] = i;
32
+ });
33
+ let r = nodeOrders.length;
34
+ while (r-- > 0) {
35
+ if (removeIndexes.includes(r)) {
36
+ nodeOrders.splice(r, 1);
37
+ }
38
+ }
39
+ }
@@ -1,6 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.siblingsCorrection = void 0;
4
1
  /**
5
2
  * Correct the references to prevNode and nextNode in the order listed.
6
3
  *
@@ -8,13 +5,17 @@ exports.siblingsCorrection = void 0;
8
5
  * @affects nodeList[].prevNode
9
6
  * @affects nodeList[].nextNode
10
7
  */
11
- function siblingsCorrection(nodeList) {
8
+ export function siblingsCorrection(
9
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
10
+ nodeList) {
12
11
  for (let i = 0; i < nodeList.length; i++) {
13
- const prevNode = nodeList[i - 1] || null;
12
+ const prevNode = nodeList[i - 1] ?? null;
14
13
  const node = nodeList[i];
15
- const nextNode = nodeList[i + 1] || null;
14
+ if (!node) {
15
+ continue;
16
+ }
17
+ const nextNode = nodeList[i + 1] ?? null;
16
18
  node.prevNode = prevNode;
17
19
  node.nextNode = nextNode;
18
20
  }
19
21
  }
20
- exports.siblingsCorrection = siblingsCorrection;
@@ -0,0 +1,7 @@
1
+ export interface N {
2
+ type: 'text' | 'starttag' | 'endtag' | 'comment' | 'boguscomment';
3
+ raw: string;
4
+ line: number;
5
+ col: number;
6
+ }
7
+ export default function tagSplitter(raw: string, line: number, col: number): N[];
@@ -0,0 +1,89 @@
1
+ import { reSplitterTag, reTagName } from './const.js';
2
+ import { getEndCol, getEndLine } from '@markuplint/parser-utils';
3
+ export default function tagSplitter(raw, line, col) {
4
+ return withLocation(tagSplitterAsString(raw), line, col);
5
+ }
6
+ function tagSplitterAsString(raw) {
7
+ const tagMatches = raw.match(reSplitterTag);
8
+ if (!tagMatches) {
9
+ return [raw];
10
+ }
11
+ const tokens = Array.from(tagMatches);
12
+ tokens.unshift(); // remove all match
13
+ const nodes = [];
14
+ let rest = raw;
15
+ for (const token of tokens) {
16
+ const index = rest.indexOf(token);
17
+ let length = token.length;
18
+ if (index > 0) {
19
+ const text = rest.slice(0, index);
20
+ nodes.push(text);
21
+ length += text.length;
22
+ }
23
+ nodes.push(token);
24
+ rest = rest.slice(length);
25
+ }
26
+ if (rest) {
27
+ nodes.push(rest);
28
+ }
29
+ return nodes;
30
+ }
31
+ function withLocation(nodes, line, col) {
32
+ const result = [];
33
+ for (const node of nodes) {
34
+ if (node[0] !== '<') {
35
+ result.push({
36
+ type: 'text',
37
+ raw: node,
38
+ line,
39
+ col,
40
+ });
41
+ }
42
+ else {
43
+ const label = node.slice(1).slice(0, -1);
44
+ if (reTagName.test(label)) {
45
+ result.push({
46
+ type: 'starttag',
47
+ raw: node,
48
+ line,
49
+ col,
50
+ });
51
+ }
52
+ else if (label[0] === '/') {
53
+ result.push({
54
+ type: 'endtag',
55
+ raw: node,
56
+ line,
57
+ col,
58
+ });
59
+ }
60
+ else if (label[0] === '!') {
61
+ result.push({
62
+ type: 'comment',
63
+ raw: node,
64
+ line,
65
+ col,
66
+ });
67
+ }
68
+ else if (label[0] === '?') {
69
+ result.push({
70
+ type: 'boguscomment',
71
+ raw: node,
72
+ line,
73
+ col,
74
+ });
75
+ }
76
+ else {
77
+ result.push({
78
+ type: 'text',
79
+ raw: node,
80
+ line,
81
+ col,
82
+ });
83
+ }
84
+ }
85
+ line = getEndLine(node, line);
86
+ col = getEndCol(node, col);
87
+ }
88
+ return result;
89
+ }