@markuplint/parser-utils 3.4.0 → 3.6.0

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/lib/const.d.ts CHANGED
@@ -5,3 +5,6 @@ export declare const MASK_CHAR = '\uE000';
5
5
  * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element
6
6
  */
7
7
  export declare const svgElementList: string[];
8
+ export declare const reTag: RegExp;
9
+ export declare const reTagName: RegExp;
10
+ export declare const reSplitterTag: RegExp;
package/lib/const.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.svgElementList = exports.MASK_CHAR = void 0;
3
+ exports.reSplitterTag = exports.reTagName = exports.reTag = exports.svgElementList = exports.MASK_CHAR = void 0;
4
4
  exports.MASK_CHAR = '\uE000';
5
5
  /**
6
6
  * SVG Element list
@@ -97,3 +97,7 @@ exports.svgElementList = [
97
97
  'tref',
98
98
  'vkern',
99
99
  ];
100
+ exports.reTag = /^<((?:.|\s|\n)+)>\s*$/;
101
+ // eslint-disable-next-line no-control-regex
102
+ exports.reTagName = /^(?:[a-z][^\u0000\u0009\u000A\u000C\u0020/>]*)/i;
103
+ exports.reSplitterTag = /<[^>]+>/g;
@@ -4,7 +4,7 @@ exports.uuid = exports.createTokenFromRawCode = exports.tokenizer = void 0;
4
4
  const uuid_1 = require("uuid");
5
5
  const get_location_1 = require("./get-location");
6
6
  function tokenizer(raw, startLine, startCol, startOffset) {
7
- raw = raw || '';
7
+ raw = raw !== null && raw !== void 0 ? raw : '';
8
8
  const endLine = (0, get_location_1.getEndLine)(raw, startLine);
9
9
  const endCol = (0, get_location_1.getEndCol)(raw, startCol);
10
10
  const endOffset = startOffset + raw.length;
@@ -21,7 +21,7 @@ function tokenizer(raw, startLine, startCol, startOffset) {
21
21
  }
22
22
  exports.tokenizer = tokenizer;
23
23
  function createTokenFromRawCode(raw, startOffset, rawCode) {
24
- raw = raw || '';
24
+ raw = raw !== null && raw !== void 0 ? raw : '';
25
25
  const loc = (0, get_location_1.sliceFragment)(rawCode, startOffset, startOffset + raw.length);
26
26
  return {
27
27
  uuid: uuid(),
package/lib/debugger.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.attributesToDebugMaps = exports.nodeListToDebugMaps = void 0;
4
- function nodeListToDebugMaps(nodeList, withAttr = false) {
4
+ function nodeListToDebugMaps(
5
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
6
+ nodeList, withAttr = false) {
5
7
  return nodeList
6
8
  .map(n => {
7
9
  const r = [];
@@ -19,7 +21,9 @@ function nodeListToDebugMaps(nodeList, withAttr = false) {
19
21
  .flat();
20
22
  }
21
23
  exports.nodeListToDebugMaps = nodeListToDebugMaps;
22
- function attributesToDebugMaps(attributes) {
24
+ function attributesToDebugMaps(
25
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
26
+ attributes) {
23
27
  return attributes.map(n => {
24
28
  const r = [
25
29
  tokenDebug({
@@ -50,9 +54,10 @@ function attributesToDebugMaps(attributes) {
50
54
  }
51
55
  exports.attributesToDebugMaps = attributesToDebugMaps;
52
56
  function tokenDebug(n, type = '') {
57
+ var _a, _b, _c, _d;
53
58
  return `[${n.startLine}:${n.startCol}]>[${n.endLine}:${n.endCol}](${n.startOffset},${n.endOffset})${
54
59
  // @ts-ignore
55
- n.potentialName || n.nodeName || n.name || n.type || type}: ${visibleWhiteSpace(n.raw)}`;
60
+ (_d = (_c = (_b = (_a = n.potentialName) !== null && _a !== void 0 ? _a : n.nodeName) !== null && _b !== void 0 ? _b : n.name) !== null && _c !== void 0 ? _c : n.type) !== null && _d !== void 0 ? _d : type}: ${visibleWhiteSpace(n.raw)}`;
56
61
  }
57
62
  function visibleWhiteSpace(chars) {
58
63
  return chars.replace(/\n/g, '⏎').replace(/\t/g, '→').replace(/\s/g, '␣');
@@ -10,10 +10,10 @@ function detectElementType(name, option, defaultPattern) {
10
10
  }
11
11
  exports.detectElementType = detectElementType;
12
12
  function distinguishAuthoredName(name, pattern, defaultPattern) {
13
- if (pattern) {
13
+ if (pattern != null) {
14
14
  return _distinguishAuthoredName(name, pattern);
15
15
  }
16
- if (defaultPattern) {
16
+ if (defaultPattern != null) {
17
17
  return _distinguishAuthoredName(name, defaultPattern);
18
18
  }
19
19
  return false;
@@ -0,0 +1,2 @@
1
+ import type { MLASTNode } from '@markuplint/ml-ast';
2
+ export declare function flattenNodes(nodeTree: MLASTNode[], rawHtml: string, createLastText?: boolean): MLASTNode[];
@@ -0,0 +1,251 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.flattenNodes = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const remove_deprecated_node_1 = require("./remove-deprecated-node");
6
+ const tag_splitter_1 = tslib_1.__importDefault(require("./tag-splitter"));
7
+ const parser_utils_1 = require("@markuplint/parser-utils");
8
+ function flattenNodes(
9
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
10
+ nodeTree, rawHtml, createLastText = true) {
11
+ var _a, _b, _c, _d;
12
+ const nodeOrders = arrayize(nodeTree, rawHtml);
13
+ {
14
+ /**
15
+ * Correction prev/next/parent
16
+ */
17
+ let prevToken = null;
18
+ for (const node of nodeOrders) {
19
+ if (!prevToken) {
20
+ prevToken = node;
21
+ continue;
22
+ }
23
+ if (node.type !== 'endtag') {
24
+ prevToken = node;
25
+ continue;
26
+ }
27
+ const endTag = node;
28
+ if (endTag.nodeName.toLowerCase() === 'body' && prevToken.type === 'text') {
29
+ const prevWreckagesText = prevToken;
30
+ const wreckages = (0, tag_splitter_1.default)(prevWreckagesText.raw, prevWreckagesText.startLine, prevWreckagesText.startCol);
31
+ if (wreckages.length > 0 && wreckages[0]) {
32
+ // console.log('wreckages\n', wreckages);
33
+ const lastText = wreckages[0];
34
+ const raw = lastText.raw;
35
+ const startLine = lastText.line;
36
+ const startCol = lastText.col;
37
+ prevWreckagesText.raw = raw;
38
+ prevWreckagesText.endOffset = prevWreckagesText.startOffset + raw.length;
39
+ prevWreckagesText.startLine = startLine;
40
+ prevWreckagesText.endLine = (0, parser_utils_1.getEndLine)(raw, startLine);
41
+ prevWreckagesText.startCol = startCol;
42
+ prevWreckagesText.endCol = (0, parser_utils_1.getEndCol)(raw, startCol);
43
+ }
44
+ }
45
+ }
46
+ }
47
+ (0, remove_deprecated_node_1.removeDeprecatedNode)(nodeOrders);
48
+ {
49
+ /**
50
+ * getting last node
51
+ */
52
+ let lastNode = null;
53
+ for (const node of nodeOrders) {
54
+ if (node.isGhost) {
55
+ continue;
56
+ }
57
+ lastNode = node;
58
+ }
59
+ if (lastNode) {
60
+ if (lastNode.type === 'text') {
61
+ // Correction for Parse5 AST
62
+ // prev node: ? -> html
63
+ lastNode.prevNode = (_b = (_a = lastNode.parentNode) === null || _a === void 0 ? void 0 : _a.parentNode) !== null && _b !== void 0 ? _b : lastNode.parentNode;
64
+ if (lastNode.prevNode) {
65
+ lastNode.prevNode.nextNode = lastNode;
66
+ }
67
+ // parent node: body -> null
68
+ lastNode.parentNode = null;
69
+ // next node: ? -> null
70
+ lastNode.nextNode = null;
71
+ }
72
+ else if (createLastText) {
73
+ /**
74
+ * create Last spaces
75
+ */
76
+ let lastOffset = 0;
77
+ nodeOrders.forEach((node, i) => {
78
+ lastOffset = Math.max(node.endOffset, lastOffset);
79
+ });
80
+ // console.log(lastOffset);
81
+ const lastTextContent = rawHtml.slice(lastOffset);
82
+ // console.log(`"${lastTextContent}"`);
83
+ if (lastTextContent) {
84
+ const line = (_c = lastNode === null || lastNode === void 0 ? void 0 : lastNode.endLine) !== null && _c !== void 0 ? _c : 0;
85
+ const col = (_d = lastNode === null || lastNode === void 0 ? void 0 : lastNode.endCol) !== null && _d !== void 0 ? _d : 0;
86
+ const lastTextNode = {
87
+ uuid: (0, parser_utils_1.uuid)(),
88
+ raw: lastTextContent,
89
+ startOffset: lastOffset,
90
+ endOffset: lastOffset + lastTextContent.length,
91
+ startLine: line,
92
+ endLine: (0, parser_utils_1.getEndLine)(lastTextContent, line),
93
+ startCol: col,
94
+ endCol: (0, parser_utils_1.getEndCol)(lastTextContent, col),
95
+ nodeName: '#text',
96
+ type: 'text',
97
+ parentNode: null,
98
+ prevNode: lastNode,
99
+ nextNode: null,
100
+ isFragment: false,
101
+ isGhost: false,
102
+ };
103
+ lastNode.nextNode = lastTextNode;
104
+ if ((lastNode.type === 'starttag' || lastNode.type === 'endtag') && lastNode.pearNode) {
105
+ lastNode.pearNode.nextNode = lastTextNode;
106
+ }
107
+ nodeOrders.push(lastTextNode);
108
+ }
109
+ }
110
+ }
111
+ }
112
+ /**
113
+ * concat text nodes
114
+ */
115
+ const result = [];
116
+ nodeOrders.forEach(node => {
117
+ var _a, _b;
118
+ const prevNode = (_a = result[result.length - 1]) !== null && _a !== void 0 ? _a : null;
119
+ if (node.type === 'text' && (prevNode === null || prevNode === void 0 ? void 0 : prevNode.type) === 'text') {
120
+ prevNode.raw = prevNode.raw + node.raw;
121
+ prevNode.endOffset = node.endOffset;
122
+ prevNode.endLine = node.endLine;
123
+ prevNode.endCol = node.endCol;
124
+ prevNode.nextNode = node.nextNode;
125
+ if (prevNode.parentNode) {
126
+ if (prevNode.parentNode.childNodes) {
127
+ if (prevNode.parentNode.childNodes.findIndex(currentChild => currentChild.uuid === prevNode.uuid) === -1) {
128
+ prevNode.parentNode.childNodes.unshift(prevNode);
129
+ }
130
+ else {
131
+ prevNode.parentNode.childNodes = [prevNode];
132
+ }
133
+ }
134
+ prevNode.parentNode.childNodes = (_b = prevNode.parentNode.childNodes) === null || _b === void 0 ? void 0 : _b.filter(n => n.uuid !== node.uuid);
135
+ }
136
+ if (node.nextNode) {
137
+ node.nextNode.prevNode = prevNode;
138
+ }
139
+ return;
140
+ }
141
+ result.push(node);
142
+ });
143
+ {
144
+ /**
145
+ * Correction prev/next/parent
146
+ */
147
+ let prevToken = null;
148
+ for (const node of result) {
149
+ if (!prevToken) {
150
+ prevToken = node;
151
+ continue;
152
+ }
153
+ if (((prevToken.type === 'endtag' && prevToken.nodeName.toLowerCase() === 'body') ||
154
+ prevToken.type === 'doctype') &&
155
+ node.type === 'text') {
156
+ const nextNode = prevToken.nextNode;
157
+ prevToken.nextNode = node;
158
+ if (prevToken.type === 'endtag' && prevToken.pearNode) {
159
+ prevToken.pearNode.nextNode = node;
160
+ }
161
+ node.prevNode = prevToken;
162
+ node.nextNode = nextNode;
163
+ node.parentNode = prevToken.parentNode;
164
+ }
165
+ // EndTag
166
+ if (node.type === 'starttag' && node.pearNode) {
167
+ const endTag = node.pearNode;
168
+ endTag.pearNode = node;
169
+ endTag.prevNode = node.prevNode;
170
+ endTag.nextNode = node.nextNode;
171
+ }
172
+ // Children
173
+ if (node.type === 'text') {
174
+ const parent = node.parentNode;
175
+ if (parent && parent.type === 'starttag' && parent.nodeName.toLowerCase() === 'html') {
176
+ if (parent.childNodes && !parent.childNodes.some(n => n.uuid === node.uuid)) {
177
+ parent.childNodes.push(node);
178
+ }
179
+ }
180
+ }
181
+ prevToken = node;
182
+ }
183
+ }
184
+ // console.log(nodeOrders.map((n, i) => `${i}: ${n.raw.trim()}`));
185
+ return result;
186
+ }
187
+ exports.flattenNodes = flattenNodes;
188
+ function arrayize(
189
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
190
+ nodeTree, rawHtml) {
191
+ const nodeOrders = [];
192
+ let prevLine = 1;
193
+ let prevCol = 1;
194
+ let currentEndOffset = 0;
195
+ /**
196
+ * pushing list
197
+ */
198
+ (0, parser_utils_1.walk)(nodeTree, node => {
199
+ var _a;
200
+ const diff = node.startOffset - currentEndOffset;
201
+ if (diff > 0) {
202
+ const html = rawHtml.slice(currentEndOffset, node.startOffset);
203
+ /**
204
+ * first white spaces
205
+ */
206
+ if (/^\s+$/.test(html)) {
207
+ const spaces = html;
208
+ const textNode = {
209
+ uuid: (0, parser_utils_1.uuid)(),
210
+ raw: spaces,
211
+ startOffset: currentEndOffset,
212
+ endOffset: currentEndOffset + spaces.length,
213
+ startLine: prevLine,
214
+ endLine: (0, parser_utils_1.getEndLine)(spaces, prevLine),
215
+ startCol: prevCol,
216
+ endCol: (0, parser_utils_1.getEndCol)(spaces, prevCol),
217
+ nodeName: '#text',
218
+ type: 'text',
219
+ parentNode: node.parentNode,
220
+ prevNode: node.prevNode,
221
+ nextNode: node,
222
+ isFragment: false,
223
+ isGhost: false,
224
+ };
225
+ node.prevNode = textNode;
226
+ if (node.parentNode && node.parentNode.childNodes) {
227
+ const newChildNodes = [...node.parentNode.childNodes];
228
+ if (newChildNodes.some(child => {
229
+ return (
230
+ // Out of start offset
231
+ textNode.endOffset < child.startOffset ||
232
+ // Out of end offset
233
+ child.endOffset < textNode.startOffset);
234
+ })) {
235
+ newChildNodes.push(textNode);
236
+ }
237
+ newChildNodes.sort((a, b) => a.startOffset - b.startOffset);
238
+ node.parentNode.childNodes = newChildNodes;
239
+ }
240
+ nodeOrders.push(textNode);
241
+ }
242
+ }
243
+ currentEndOffset = node.startOffset + node.raw.length;
244
+ prevLine = node.endLine;
245
+ prevCol = node.endCol;
246
+ // for ghost nodes
247
+ node.endOffset = (_a = node.endOffset) !== null && _a !== void 0 ? _a : currentEndOffset;
248
+ nodeOrders.push(node);
249
+ });
250
+ return nodeOrders.slice();
251
+ }
@@ -0,0 +1 @@
1
+ export declare function getSpaceBefore(offset: number, rawCode: string): import('@markuplint/ml-ast').MLToken;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSpaceBefore = void 0;
4
+ const create_token_1 = require("./create-token");
5
+ function getSpaceBefore(offset, rawCode) {
6
+ var _a;
7
+ const aboveCode = rawCode.slice(0, offset);
8
+ const aboveAttrMatched = aboveCode.match(/\s+$/m);
9
+ const aboveAttrChar = (_a = aboveAttrMatched === null || aboveAttrMatched === void 0 ? void 0 : aboveAttrMatched[0]) !== null && _a !== void 0 ? _a : '';
10
+ const spacesBefore = (0, create_token_1.createTokenFromRawCode)(aboveAttrChar, offset - aboveAttrChar.length, rawCode);
11
+ return spacesBefore;
12
+ }
13
+ exports.getSpaceBefore = getSpaceBefore;
@@ -419,12 +419,13 @@ const idlContentMap = {
419
419
  };
420
420
  const list = Object.entries(idlContentMap);
421
421
  function searchIDLAttribute(name) {
422
+ var _a;
422
423
  const camelizedName = camelize(name);
423
- const [idlPropName, contentAttrName] = (/^on[a-z]/.test(name) && [name.toLowerCase(), name.toLowerCase()]) ||
424
- list.find(([idlPropName, contentAttrName]) => idlPropName.toLowerCase() === camelizedName.toLowerCase() ||
424
+ const [idlPropName, contentAttrName] = /^on[a-z]/.test(name)
425
+ ? [name.toLowerCase(), name.toLowerCase()]
426
+ : (_a = list.find(([idlPropName, contentAttrName]) => idlPropName.toLowerCase() === camelizedName.toLowerCase() ||
425
427
  contentAttrName.toLowerCase() === name.toLowerCase() ||
426
- hyphenize(idlPropName) === name.toLowerCase()) ||
427
- [];
428
+ hyphenize(idlPropName) === name.toLowerCase())) !== null && _a !== void 0 ? _a : [];
428
429
  return {
429
430
  idlPropName,
430
431
  contentAttrName,
@@ -1,4 +1,4 @@
1
1
  import type { IgnoreBlock, IgnoreTag } from './types';
2
2
  import type { MLASTNode } from '@markuplint/ml-ast';
3
- export declare function ignoreBlock(source: string, tags: IgnoreTag[], maskChar?: string): IgnoreBlock;
3
+ export declare function ignoreBlock(source: string, tags: readonly IgnoreTag[], maskChar?: string): IgnoreBlock;
4
4
  export declare function restoreNode(nodeList: MLASTNode[], ignoreBlock: IgnoreBlock): MLASTNode[];
@@ -13,7 +13,7 @@ function ignoreBlock(source, tags, maskChar = const_1.MASK_CHAR) {
13
13
  const attr = maskText(prepend(tag.start, '(?<=(?:"|\'))'), append(tag.end, '(?=(?:"|\'))'), replaced, (startTag, taggedCode, endTag) => {
14
14
  const mask = maskChar.repeat(startTag.length) +
15
15
  taggedCode.replace(/[^\n]/g, maskChar) +
16
- maskChar.repeat((endTag || '').length);
16
+ maskChar.repeat((endTag !== null && endTag !== void 0 ? endTag : '').length);
17
17
  return mask;
18
18
  });
19
19
  replaced = attr.replaced;
@@ -22,7 +22,7 @@ function ignoreBlock(source, tags, maskChar = const_1.MASK_CHAR) {
22
22
  const text = maskText(tag.start, tag.end, replaced, (startTag, taggedCode, endTag) => {
23
23
  const mask = maskChar.repeat(startTag.length) +
24
24
  taggedCode.replace(/[^\n]/g, maskChar) +
25
- maskChar.repeat((endTag || '').length);
25
+ maskChar.repeat((endTag !== null && endTag !== void 0 ? endTag : '').length);
26
26
  const taggedMask = `<!${mask.slice(2).slice(0, -1)}>`;
27
27
  return taggedMask;
28
28
  });
@@ -52,20 +52,22 @@ function maskText(start, end, replaced, masking) {
52
52
  index,
53
53
  startTag,
54
54
  taggedCode,
55
- endTag: endTag || null,
55
+ endTag: endTag !== null && endTag !== void 0 ? endTag : null,
56
56
  });
57
57
  /**
58
58
  * It will not replace line breaks because detects line number.
59
59
  */
60
- replaced = above + masking(startTag, taggedCode, endTag) + (below || '');
60
+ replaced = above + masking(startTag, taggedCode, endTag) + (below !== null && below !== void 0 ? below : '');
61
61
  }
62
62
  return {
63
63
  replaced,
64
64
  stack,
65
65
  };
66
66
  }
67
- function restoreNode(nodeList, ignoreBlock) {
68
- var _a, _b, _c, _d;
67
+ function restoreNode(
68
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
69
+ nodeList, ignoreBlock) {
70
+ var _a, _b, _c, _d, _e;
69
71
  nodeList = nodeList.slice();
70
72
  const { source, stack, maskChar } = ignoreBlock;
71
73
  for (const node of nodeList) {
@@ -81,7 +83,7 @@ function restoreNode(nodeList, ignoreBlock) {
81
83
  for (const tag of stack) {
82
84
  if (node.startOffset <= tag.index && tag.index < node.endOffset) {
83
85
  const start = tag.index - node.startOffset;
84
- const body = tag.startTag + tag.taggedCode + (tag.endTag || '');
86
+ const body = tag.startTag + tag.taggedCode + ((_a = tag.endTag) !== null && _a !== void 0 ? _a : '');
85
87
  const above = node.raw.slice(pointer, start);
86
88
  const below = text.slice(above.length + body.length);
87
89
  if (above) {
@@ -99,10 +101,10 @@ function restoreNode(nodeList, ignoreBlock) {
99
101
  startCol,
100
102
  endCol,
101
103
  };
102
- if ((_a = node.prevNode) === null || _a === void 0 ? void 0 : _a.nextNode) {
104
+ if ((_b = node.prevNode) === null || _b === void 0 ? void 0 : _b.nextNode) {
103
105
  node.prevNode.nextNode = textNode;
104
106
  }
105
- if ((_b = node.nextNode) === null || _b === void 0 ? void 0 : _b.prevNode) {
107
+ if ((_c = node.nextNode) === null || _c === void 0 ? void 0 : _c.prevNode) {
106
108
  node.nextNode.prevNode = textNode;
107
109
  }
108
110
  insertList.push(textNode);
@@ -127,10 +129,10 @@ function restoreNode(nodeList, ignoreBlock) {
127
129
  startCol,
128
130
  endCol,
129
131
  };
130
- if ((_c = node.prevNode) === null || _c === void 0 ? void 0 : _c.nextNode) {
132
+ if ((_d = node.prevNode) === null || _d === void 0 ? void 0 : _d.nextNode) {
131
133
  node.prevNode.nextNode = bodyNode;
132
134
  }
133
- if ((_d = node.nextNode) === null || _d === void 0 ? void 0 : _d.prevNode) {
135
+ if ((_e = node.nextNode) === null || _e === void 0 ? void 0 : _e.prevNode) {
134
136
  node.nextNode.prevNode = bodyNode;
135
137
  }
136
138
  insertList.push(bodyNode);
package/lib/index.d.ts CHANGED
@@ -1,10 +1,16 @@
1
+ export * from './const';
2
+ export * from './create-token';
3
+ export * from './debugger';
1
4
  export * from './decision';
5
+ export * from './detect-element-type';
6
+ export * from './flatten-nodes';
2
7
  export * from './get-location';
3
- export * from './create-token';
8
+ export * from './get-space-before';
4
9
  export * from './idl-attributes';
5
- export * from './walker';
6
10
  export * from './ignore-block';
7
11
  export * from './ignore-front-matter';
8
- export * from './debugger';
12
+ export * from './parse-attr';
9
13
  export * from './parser-error';
10
- export * from './detect-element-type';
14
+ export * from './remove-deprecated-node';
15
+ export * from './tag-splitter';
16
+ export * from './walker';
package/lib/index.js CHANGED
@@ -1,13 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./const"), exports);
5
+ tslib_1.__exportStar(require("./create-token"), exports);
6
+ tslib_1.__exportStar(require("./debugger"), exports);
4
7
  tslib_1.__exportStar(require("./decision"), exports);
8
+ tslib_1.__exportStar(require("./detect-element-type"), exports);
9
+ tslib_1.__exportStar(require("./flatten-nodes"), exports);
5
10
  tslib_1.__exportStar(require("./get-location"), exports);
6
- tslib_1.__exportStar(require("./create-token"), exports);
11
+ tslib_1.__exportStar(require("./get-space-before"), exports);
7
12
  tslib_1.__exportStar(require("./idl-attributes"), exports);
8
- tslib_1.__exportStar(require("./walker"), exports);
9
13
  tslib_1.__exportStar(require("./ignore-block"), exports);
10
14
  tslib_1.__exportStar(require("./ignore-front-matter"), exports);
11
- tslib_1.__exportStar(require("./debugger"), exports);
15
+ tslib_1.__exportStar(require("./parse-attr"), exports);
12
16
  tslib_1.__exportStar(require("./parser-error"), exports);
13
- tslib_1.__exportStar(require("./detect-element-type"), exports);
17
+ tslib_1.__exportStar(require("./remove-deprecated-node"), exports);
18
+ tslib_1.__exportStar(require("./tag-splitter"), exports);
19
+ tslib_1.__exportStar(require("./walker"), exports);
@@ -0,0 +1,27 @@
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(
14
+ raw: string,
15
+ options?: ParseAttrOptions,
16
+ ): {
17
+ beforeName: string;
18
+ name: string;
19
+ afterName: string;
20
+ equal: string;
21
+ beforeValue: string;
22
+ startQuote: string;
23
+ value: string;
24
+ endQuote: string;
25
+ afterAttr: string;
26
+ };
27
+ export {};
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tokenize = exports.parseAttr = exports.defaultValueDelimiters = void 0;
4
+ const create_token_1 = require("./create-token");
5
+ exports.defaultValueDelimiters = [
6
+ {
7
+ start: "'",
8
+ end: "'",
9
+ },
10
+ {
11
+ start: '"',
12
+ end: '"',
13
+ },
14
+ ];
15
+ const defaultEqual = '=';
16
+ const spaceRegex = /^\s$/;
17
+ function parseAttr(raw, offset, html, options) {
18
+ const tokens = tokenize(raw, options);
19
+ tokens.beforeName;
20
+ const attrToken = (0, create_token_1.createTokenFromRawCode)(raw, offset, html);
21
+ const spacesBeforeName = (0, create_token_1.tokenizer)(tokens.beforeName, attrToken.startLine, attrToken.startCol, attrToken.startOffset);
22
+ const name = (0, create_token_1.tokenizer)(tokens.name, spacesBeforeName.endLine, spacesBeforeName.endCol, spacesBeforeName.endOffset);
23
+ const spacesBeforeEqual = (0, create_token_1.tokenizer)(tokens.afterName, name.endLine, name.endCol, name.endOffset);
24
+ const equal = (0, create_token_1.tokenizer)(tokens.equal, spacesBeforeEqual.endLine, spacesBeforeEqual.endCol, spacesBeforeEqual.endOffset);
25
+ const spacesAfterEqual = (0, create_token_1.tokenizer)(tokens.beforeValue, equal.endLine, equal.endCol, equal.endOffset);
26
+ const startQuote = (0, create_token_1.tokenizer)(tokens.startQuote, spacesAfterEqual.endLine, spacesAfterEqual.endCol, spacesAfterEqual.endOffset);
27
+ const value = (0, create_token_1.tokenizer)(tokens.value, startQuote.endLine, startQuote.endCol, startQuote.endOffset);
28
+ const endQuote = (0, create_token_1.tokenizer)(tokens.endQuote, value.endLine, value.endCol, value.endOffset);
29
+ const attr = {
30
+ type: 'html-attr',
31
+ uuid: (0, create_token_1.uuid)(),
32
+ raw: attrToken.raw,
33
+ startOffset: attrToken.startOffset,
34
+ endOffset: attrToken.endOffset,
35
+ startLine: attrToken.startLine,
36
+ endLine: attrToken.endLine,
37
+ startCol: attrToken.startCol,
38
+ endCol: attrToken.endCol,
39
+ spacesBeforeName,
40
+ name,
41
+ spacesBeforeEqual,
42
+ equal,
43
+ spacesAfterEqual,
44
+ startQuote,
45
+ value,
46
+ endQuote,
47
+ isDuplicatable: false,
48
+ nodeName: name.raw,
49
+ parentNode: null,
50
+ nextNode: null,
51
+ prevNode: null,
52
+ isFragment: false,
53
+ isGhost: false,
54
+ };
55
+ return attr;
56
+ }
57
+ exports.parseAttr = parseAttr;
58
+ function tokenize(raw, options) {
59
+ var _a, _b, _c;
60
+ const valueDelimiters = (_a = options === null || options === void 0 ? void 0 : options.valueDelimiters) !== null && _a !== void 0 ? _a : exports.defaultValueDelimiters;
61
+ const equalDelimiter = (_b = options === null || options === void 0 ? void 0 : options.equal) !== null && _b !== void 0 ? _b : defaultEqual;
62
+ let state = 'b-name';
63
+ const charactors = raw.split('');
64
+ let beforeName = '';
65
+ let name = '';
66
+ let afterName = '';
67
+ let equal = '';
68
+ let valueDelimiter = null;
69
+ let beforeValue = '';
70
+ let startQuote = '';
71
+ let value = '';
72
+ let endQuote = '';
73
+ let afterAttr = '';
74
+ while (charactors.length > 0) {
75
+ const charactor = charactors.shift();
76
+ if (state === 'b-name') {
77
+ if (spaceRegex.test(charactor)) {
78
+ beforeName += charactor;
79
+ continue;
80
+ }
81
+ name += charactor;
82
+ state = 'name';
83
+ continue;
84
+ }
85
+ if (state === 'name') {
86
+ if (equalDelimiter === charactor) {
87
+ equal = equalDelimiter;
88
+ state = 'value-start';
89
+ continue;
90
+ }
91
+ if (spaceRegex.test(charactor)) {
92
+ afterName += charactor;
93
+ state = 'a-name';
94
+ continue;
95
+ }
96
+ name += charactor;
97
+ continue;
98
+ }
99
+ if (state === 'a-name') {
100
+ if (equalDelimiter === charactor) {
101
+ equal = equalDelimiter;
102
+ state = 'value-start';
103
+ continue;
104
+ }
105
+ if (spaceRegex.test(charactor)) {
106
+ afterName += charactor;
107
+ continue;
108
+ }
109
+ break;
110
+ }
111
+ if (state === 'value-start') {
112
+ if (spaceRegex.test(charactor)) {
113
+ beforeValue += charactor;
114
+ continue;
115
+ }
116
+ valueDelimiter = (_c = valueDelimiters.find(d => d.start === charactor)) !== null && _c !== void 0 ? _c : null;
117
+ if (valueDelimiter) {
118
+ startQuote += valueDelimiter.start;
119
+ }
120
+ else {
121
+ value += beforeValue + charactor;
122
+ beforeValue = '';
123
+ }
124
+ state = 'value';
125
+ continue;
126
+ }
127
+ if (state !== 'value') {
128
+ throw new Error('ParseError: unknown parse state in the attribute');
129
+ }
130
+ value += charactor;
131
+ }
132
+ if (valueDelimiter) {
133
+ const endQuoteIndex = value.lastIndexOf(valueDelimiter.end);
134
+ endQuote = value.slice(endQuoteIndex, endQuoteIndex + 1);
135
+ afterAttr = value.slice(endQuoteIndex + 1);
136
+ value = value.slice(0, endQuoteIndex);
137
+ }
138
+ return {
139
+ beforeName,
140
+ name,
141
+ afterName,
142
+ equal,
143
+ beforeValue,
144
+ startQuote,
145
+ value,
146
+ endQuote,
147
+ afterAttr,
148
+ };
149
+ }
150
+ exports.tokenize = tokenize;
@@ -12,10 +12,10 @@ export declare class ParserError extends Error {
12
12
  raw,
13
13
  nodeName,
14
14
  }: {
15
- line?: number;
16
- col?: number;
17
- raw?: string;
18
- nodeName?: string | null;
15
+ readonly line?: number;
16
+ readonly col?: number;
17
+ readonly raw?: string;
18
+ readonly nodeName?: string | null;
19
19
  },
20
20
  );
21
21
  }
@@ -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,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.removeDeprecatedNode = void 0;
4
+ /**
5
+ *
6
+ * @disruptive
7
+ * @param nodeOrders [Disruptive change]
8
+ */
9
+ function removeDeprecatedNode(
10
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
11
+ nodeOrders) {
12
+ /**
13
+ * sorting
14
+ */
15
+ nodeOrders.sort((a, b) => {
16
+ if (a.isGhost || b.isGhost) {
17
+ return 0;
18
+ }
19
+ return a.startOffset - b.startOffset;
20
+ });
21
+ /**
22
+ * remove duplicated node
23
+ */
24
+ const stack = {};
25
+ const removeIndexes = [];
26
+ nodeOrders.forEach((node, i) => {
27
+ if (node.isGhost) {
28
+ return;
29
+ }
30
+ const id = `${node.startLine}:${node.startCol}:${node.endLine}:${node.endCol}`;
31
+ if (stack[id] != null) {
32
+ removeIndexes.push(i);
33
+ }
34
+ stack[id] = i;
35
+ });
36
+ let r = nodeOrders.length;
37
+ while (r-- > 0) {
38
+ if (removeIndexes.includes(r)) {
39
+ nodeOrders.splice(r, 1);
40
+ }
41
+ }
42
+ }
43
+ exports.removeDeprecatedNode = removeDeprecatedNode;
@@ -8,14 +8,17 @@ exports.siblingsCorrection = void 0;
8
8
  * @affects nodeList[].prevNode
9
9
  * @affects nodeList[].nextNode
10
10
  */
11
- function siblingsCorrection(nodeList) {
11
+ function siblingsCorrection(
12
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
13
+ nodeList) {
14
+ var _a, _b;
12
15
  for (let i = 0; i < nodeList.length; i++) {
13
- const prevNode = nodeList[i - 1] || null;
16
+ const prevNode = (_a = nodeList[i - 1]) !== null && _a !== void 0 ? _a : null;
14
17
  const node = nodeList[i];
15
18
  if (!node) {
16
19
  continue;
17
20
  }
18
- const nextNode = nodeList[i + 1] || null;
21
+ const nextNode = (_b = nodeList[i + 1]) !== null && _b !== void 0 ? _b : null;
19
22
  node.prevNode = prevNode;
20
23
  node.nextNode = nextNode;
21
24
  }
@@ -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,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const const_1 = require("./const");
4
+ const parser_utils_1 = require("@markuplint/parser-utils");
5
+ function tagSplitter(raw, line, col) {
6
+ return withLocation(tagSplitterAsString(raw), line, col);
7
+ }
8
+ exports.default = tagSplitter;
9
+ function tagSplitterAsString(raw) {
10
+ const tagMatches = raw.match(const_1.reSplitterTag);
11
+ if (!tagMatches) {
12
+ return [raw];
13
+ }
14
+ const tokens = Array.from(tagMatches);
15
+ tokens.unshift(); // remove all match
16
+ const nodes = [];
17
+ let rest = raw;
18
+ for (const token of tokens) {
19
+ const index = rest.indexOf(token);
20
+ let length = token.length;
21
+ if (index > 0) {
22
+ const text = rest.slice(0, index);
23
+ nodes.push(text);
24
+ length += text.length;
25
+ }
26
+ nodes.push(token);
27
+ rest = rest.slice(length);
28
+ }
29
+ if (rest) {
30
+ nodes.push(rest);
31
+ }
32
+ return nodes;
33
+ }
34
+ function withLocation(nodes, line, col) {
35
+ const result = [];
36
+ for (const node of nodes) {
37
+ if (node[0] !== '<') {
38
+ result.push({
39
+ type: 'text',
40
+ raw: node,
41
+ line,
42
+ col,
43
+ });
44
+ }
45
+ else {
46
+ const label = node.slice(1).slice(0, -1);
47
+ if (const_1.reTagName.test(label)) {
48
+ result.push({
49
+ type: 'starttag',
50
+ raw: node,
51
+ line,
52
+ col,
53
+ });
54
+ }
55
+ else if (label[0] === '/') {
56
+ result.push({
57
+ type: 'endtag',
58
+ raw: node,
59
+ line,
60
+ col,
61
+ });
62
+ }
63
+ else if (label[0] === '!') {
64
+ result.push({
65
+ type: 'comment',
66
+ raw: node,
67
+ line,
68
+ col,
69
+ });
70
+ }
71
+ else if (label[0] === '?') {
72
+ result.push({
73
+ type: 'boguscomment',
74
+ raw: node,
75
+ line,
76
+ col,
77
+ });
78
+ }
79
+ else {
80
+ result.push({
81
+ type: 'text',
82
+ raw: node,
83
+ line,
84
+ col,
85
+ });
86
+ }
87
+ }
88
+ line = (0, parser_utils_1.getEndLine)(node, line);
89
+ col = (0, parser_utils_1.getEndCol)(node, col);
90
+ }
91
+ return result;
92
+ }
package/lib/types.d.ts CHANGED
@@ -1,18 +1,18 @@
1
1
  export type Code = {
2
- type: string;
3
- index: number;
4
- startTag: string;
5
- taggedCode: string;
6
- endTag: string | null;
2
+ readonly type: string;
3
+ readonly index: number;
4
+ readonly startTag: string;
5
+ readonly taggedCode: string;
6
+ readonly endTag: string | null;
7
7
  };
8
8
  export type IgnoreTag = {
9
- type: string;
10
- start: RegExp;
11
- end: RegExp;
9
+ readonly type: string;
10
+ readonly start: Readonly<RegExp>;
11
+ readonly end: Readonly<RegExp>;
12
12
  };
13
13
  export type IgnoreBlock = {
14
- source: string;
15
- replaced: string;
16
- stack: Code[];
17
- maskChar: string;
14
+ readonly source: string;
15
+ readonly replaced: string;
16
+ readonly stack: readonly Code[];
17
+ readonly maskChar: string;
18
18
  };
package/lib/walker.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  import type { MLASTNode, Walker } from '@markuplint/ml-ast';
2
- export declare function walk(nodeList: MLASTNode[], walker: Walker, depth?: number): void;
2
+ export declare function walk(nodeList: readonly MLASTNode[], walker: Walker, depth?: number): void;
package/lib/walker.js CHANGED
@@ -1,14 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.walk = void 0;
4
- function walk(nodeList, walker, depth = 0) {
4
+ function walk(
5
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
6
+ nodeList, walker, depth = 0) {
5
7
  for (const node of nodeList) {
6
8
  walker(node, depth);
7
9
  if ('childNodes' in node) {
8
10
  if (node.type === 'endtag') {
9
11
  continue;
10
12
  }
11
- if (node.childNodes && node.childNodes.length) {
13
+ if (node.childNodes && node.childNodes.length > 0) {
12
14
  walk(node.childNodes, walker, depth + 1);
13
15
  }
14
16
  if ('pearNode' in node && node.pearNode) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markuplint/parser-utils",
3
- "version": "3.4.0",
3
+ "version": "3.6.0",
4
4
  "description": "Utility module for markuplint parser plugin",
5
5
  "repository": "git@github.com:markuplint/markuplint.git",
6
6
  "author": "Yusuke Hirao <yusukehirao@me.com>",
@@ -19,16 +19,17 @@
19
19
  "clean": "tsc --build --clean"
20
20
  },
21
21
  "devDependencies": {
22
- "@types/uuid": "^9.0.0"
22
+ "@types/uuid": "^9.0.0",
23
+ "type-fest": "^3.7.0"
23
24
  },
24
25
  "dependencies": {
25
- "@markuplint/ml-ast": "3.0.0",
26
- "@markuplint/types": "3.3.0",
26
+ "@markuplint/ml-ast": "3.1.0",
27
+ "@markuplint/types": "3.5.0",
27
28
  "tslib": "^2.4.1",
28
29
  "uuid": "^9.0.0"
29
30
  },
30
31
  "peerDependencies": {
31
32
  "@markuplint/ml-core": "3.x"
32
33
  },
33
- "gitHead": "a83e0f5f214a9bbcc0286b9e269074ddca6189e7"
34
+ "gitHead": "715dd53d3b1064a9bcf616c1533921cad9e3b187"
34
35
  }