@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.
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,13 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.svgElementList = exports.MASK_CHAR = void 0;
4
- exports.MASK_CHAR = '\uE000';
1
+ export const MASK_CHAR = '\uE000';
5
2
  /**
6
3
  * SVG Element list
7
4
  *
8
5
  * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element
9
6
  */
10
- exports.svgElementList = [
7
+ export const svgElementList = [
11
8
  'a',
12
9
  'animate',
13
10
  'animateMotion',
@@ -97,3 +94,7 @@ exports.svgElementList = [
97
94
  'tref',
98
95
  'vkern',
99
96
  ];
97
+ export const reTag = /^<((?:.|\s|\n)+)>\s*$/;
98
+ // eslint-disable-next-line no-control-regex
99
+ export const reTagName = /^(?:[a-z][^\u0000\u0009\u000A\u000C\u0020/>]*)/i;
100
+ export const reSplitterTag = /<[^>]+>/g;
@@ -1,12 +1,9 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.uuid = exports.createTokenFromRawCode = exports.tokenizer = void 0;
4
- const uuid_1 = require("uuid");
5
- const get_location_1 = require("./get-location");
6
- function tokenizer(raw, startLine, startCol, startOffset) {
7
- raw = raw || '';
8
- const endLine = (0, get_location_1.getEndLine)(raw, startLine);
9
- const endCol = (0, get_location_1.getEndCol)(raw, startCol);
1
+ import { v4 as uuid4 } from 'uuid';
2
+ import { getEndCol, getEndLine, sliceFragment } from './get-location.js';
3
+ export function tokenizer(raw, startLine, startCol, startOffset) {
4
+ raw = raw ?? '';
5
+ const endLine = getEndLine(raw, startLine);
6
+ const endCol = getEndCol(raw, startCol);
10
7
  const endOffset = startOffset + raw.length;
11
8
  return {
12
9
  uuid: uuid(),
@@ -19,17 +16,14 @@ function tokenizer(raw, startLine, startCol, startOffset) {
19
16
  endCol,
20
17
  };
21
18
  }
22
- exports.tokenizer = tokenizer;
23
- function createTokenFromRawCode(raw, startOffset, rawCode) {
24
- raw = raw || '';
25
- const loc = (0, get_location_1.sliceFragment)(rawCode, startOffset, startOffset + raw.length);
19
+ export function createTokenFromRawCode(raw, startOffset, rawCode) {
20
+ raw = raw ?? '';
21
+ const loc = sliceFragment(rawCode, startOffset, startOffset + raw.length);
26
22
  return {
27
23
  uuid: uuid(),
28
24
  ...loc,
29
25
  };
30
26
  }
31
- exports.createTokenFromRawCode = createTokenFromRawCode;
32
- function uuid() {
33
- return (0, uuid_1.v4)();
27
+ export function uuid() {
28
+ return uuid4();
34
29
  }
35
- exports.uuid = uuid;
package/lib/debugger.js CHANGED
@@ -1,7 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.attributesToDebugMaps = exports.nodeListToDebugMaps = void 0;
4
- function nodeListToDebugMaps(nodeList, withAttr = false) {
1
+ export function nodeListToDebugMaps(
2
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
3
+ nodeList, withAttr = false) {
5
4
  return nodeList
6
5
  .map(n => {
7
6
  const r = [];
@@ -18,8 +17,9 @@ function nodeListToDebugMaps(nodeList, withAttr = false) {
18
17
  })
19
18
  .flat();
20
19
  }
21
- exports.nodeListToDebugMaps = nodeListToDebugMaps;
22
- function attributesToDebugMaps(attributes) {
20
+ export function attributesToDebugMaps(
21
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
22
+ attributes) {
23
23
  return attributes.map(n => {
24
24
  const r = [
25
25
  tokenDebug({
@@ -48,11 +48,10 @@ function attributesToDebugMaps(attributes) {
48
48
  return r;
49
49
  });
50
50
  }
51
- exports.attributesToDebugMaps = attributesToDebugMaps;
52
51
  function tokenDebug(n, type = '') {
53
52
  return `[${n.startLine}:${n.startCol}]>[${n.endLine}:${n.endCol}](${n.startOffset},${n.endOffset})${
54
53
  // @ts-ignore
55
- n.potentialName || n.nodeName || n.name || n.type || type}: ${visibleWhiteSpace(n.raw)}`;
54
+ n.potentialName ?? n.nodeName ?? n.name ?? n.type ?? type}: ${visibleWhiteSpace(n.raw)}`;
56
55
  }
57
56
  function visibleWhiteSpace(chars) {
58
57
  return chars.replace(/\n/g, '⏎').replace(/\t/g, '→').replace(/\s/g, '␣');
package/lib/decision.js CHANGED
@@ -1,20 +1,15 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isPotentialCustomElementName = exports.isSVGElement = void 0;
4
- const types_1 = require("@markuplint/types");
5
- const const_1 = require("./const");
1
+ import { isCustomElementName } from '@markuplint/types';
2
+ import { svgElementList } from './const.js';
6
3
  /**
7
4
  *
8
5
  *
9
6
  * @param nodeName
10
7
  * @returns
11
8
  */
12
- function isSVGElement(nodeName) {
13
- return const_1.svgElementList.includes(nodeName);
9
+ export function isSVGElement(nodeName) {
10
+ return svgElementList.includes(nodeName);
14
11
  }
15
- exports.isSVGElement = isSVGElement;
16
- const isCEN = (0, types_1.isCustomElementName)();
17
- function isPotentialCustomElementName(tagName) {
12
+ const isCEN = isCustomElementName();
13
+ export function isPotentialCustomElementName(tagName) {
18
14
  return isCEN(tagName);
19
15
  }
20
- exports.isPotentialCustomElementName = isPotentialCustomElementName;
@@ -1,19 +1,15 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.detectElementType = void 0;
4
- const decision_1 = require("./decision");
5
- function detectElementType(name, option, defaultPattern) {
1
+ import { isPotentialCustomElementName } from './decision.js';
2
+ export function detectElementType(name, option, defaultPattern) {
6
3
  if (distinguishAuthoredName(name, option, defaultPattern)) {
7
4
  return 'authored';
8
5
  }
9
- return (0, decision_1.isPotentialCustomElementName)(name) ? 'web-component' : 'html';
6
+ return isPotentialCustomElementName(name) ? 'web-component' : 'html';
10
7
  }
11
- exports.detectElementType = detectElementType;
12
8
  function distinguishAuthoredName(name, pattern, defaultPattern) {
13
- if (pattern) {
9
+ if (pattern != null) {
14
10
  return _distinguishAuthoredName(name, pattern);
15
11
  }
16
- if (defaultPattern) {
12
+ if (defaultPattern != null) {
17
13
  return _distinguishAuthoredName(name, defaultPattern);
18
14
  }
19
15
  return false;
@@ -30,7 +26,7 @@ function _distinguishAuthoredName(name, patterns) {
30
26
  }
31
27
  function toRegexp(pattern) {
32
28
  const matched = pattern.match(/^\/(.+)\/([ig]*)$/i);
33
- if (matched) {
29
+ if (matched && matched[1]) {
34
30
  return new RegExp(matched[1], matched[2]);
35
31
  }
36
32
  return new RegExp(pattern);
@@ -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,245 @@
1
+ import { uuid } from './create-token.js';
2
+ import { getEndCol, getEndLine } from './get-location.js';
3
+ import { removeDeprecatedNode } from './remove-deprecated-node.js';
4
+ import tagSplitter from './tag-splitter.js';
5
+ import { walk } from './walker.js';
6
+ export function flattenNodes(
7
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
8
+ nodeTree, rawHtml, createLastText = true) {
9
+ const nodeOrders = arrayize(nodeTree, rawHtml);
10
+ {
11
+ /**
12
+ * Correction prev/next/parent
13
+ */
14
+ let prevToken = null;
15
+ for (const node of nodeOrders) {
16
+ if (!prevToken) {
17
+ prevToken = node;
18
+ continue;
19
+ }
20
+ if (node.type !== 'endtag') {
21
+ prevToken = node;
22
+ continue;
23
+ }
24
+ const endTag = node;
25
+ if (endTag.nodeName.toLowerCase() === 'body' && prevToken.type === 'text') {
26
+ const prevWreckagesText = prevToken;
27
+ const wreckages = tagSplitter(prevWreckagesText.raw, prevWreckagesText.startLine, prevWreckagesText.startCol);
28
+ if (wreckages.length > 0 && wreckages[0]) {
29
+ // console.log('wreckages\n', wreckages);
30
+ const lastText = wreckages[0];
31
+ const raw = lastText.raw;
32
+ const startLine = lastText.line;
33
+ const startCol = lastText.col;
34
+ prevWreckagesText.raw = raw;
35
+ prevWreckagesText.endOffset = prevWreckagesText.startOffset + raw.length;
36
+ prevWreckagesText.startLine = startLine;
37
+ prevWreckagesText.endLine = getEndLine(raw, startLine);
38
+ prevWreckagesText.startCol = startCol;
39
+ prevWreckagesText.endCol = getEndCol(raw, startCol);
40
+ }
41
+ }
42
+ }
43
+ }
44
+ removeDeprecatedNode(nodeOrders);
45
+ {
46
+ /**
47
+ * getting last node
48
+ */
49
+ let lastNode = null;
50
+ for (const node of nodeOrders) {
51
+ if (node.isGhost) {
52
+ continue;
53
+ }
54
+ lastNode = node;
55
+ }
56
+ if (lastNode) {
57
+ if (lastNode.type === 'text') {
58
+ // Correction for Parse5 AST
59
+ // prev node: ? -> html
60
+ lastNode.prevNode = lastNode.parentNode?.parentNode ?? lastNode.parentNode;
61
+ if (lastNode.prevNode) {
62
+ lastNode.prevNode.nextNode = lastNode;
63
+ }
64
+ // parent node: body -> null
65
+ lastNode.parentNode = null;
66
+ // next node: ? -> null
67
+ lastNode.nextNode = null;
68
+ }
69
+ else if (createLastText) {
70
+ /**
71
+ * create Last spaces
72
+ */
73
+ let lastOffset = 0;
74
+ nodeOrders.forEach((node, i) => {
75
+ lastOffset = Math.max(node.endOffset, lastOffset);
76
+ });
77
+ // console.log(lastOffset);
78
+ const lastTextContent = rawHtml.slice(lastOffset);
79
+ // console.log(`"${lastTextContent}"`);
80
+ if (lastTextContent) {
81
+ const line = lastNode?.endLine ?? 0;
82
+ const col = lastNode?.endCol ?? 0;
83
+ const lastTextNode = {
84
+ uuid: uuid(),
85
+ raw: lastTextContent,
86
+ startOffset: lastOffset,
87
+ endOffset: lastOffset + lastTextContent.length,
88
+ startLine: line,
89
+ endLine: getEndLine(lastTextContent, line),
90
+ startCol: col,
91
+ endCol: getEndCol(lastTextContent, col),
92
+ nodeName: '#text',
93
+ type: 'text',
94
+ parentNode: null,
95
+ prevNode: lastNode,
96
+ nextNode: null,
97
+ isFragment: false,
98
+ isGhost: false,
99
+ };
100
+ lastNode.nextNode = lastTextNode;
101
+ if ((lastNode.type === 'starttag' || lastNode.type === 'endtag') && lastNode.pearNode) {
102
+ lastNode.pearNode.nextNode = lastTextNode;
103
+ }
104
+ nodeOrders.push(lastTextNode);
105
+ }
106
+ }
107
+ }
108
+ }
109
+ /**
110
+ * concat text nodes
111
+ */
112
+ const result = [];
113
+ nodeOrders.forEach(node => {
114
+ const prevNode = result[result.length - 1] ?? null;
115
+ if (node.type === 'text' && prevNode?.type === 'text') {
116
+ prevNode.raw = prevNode.raw + node.raw;
117
+ prevNode.endOffset = node.endOffset;
118
+ prevNode.endLine = node.endLine;
119
+ prevNode.endCol = node.endCol;
120
+ prevNode.nextNode = node.nextNode;
121
+ if (prevNode.parentNode) {
122
+ if (prevNode.parentNode.childNodes) {
123
+ if (prevNode.parentNode.childNodes.findIndex(currentChild => currentChild.uuid === prevNode.uuid) === -1) {
124
+ prevNode.parentNode.childNodes.unshift(prevNode);
125
+ }
126
+ else {
127
+ prevNode.parentNode.childNodes = [prevNode];
128
+ }
129
+ }
130
+ prevNode.parentNode.childNodes = prevNode.parentNode.childNodes?.filter(n => n.uuid !== node.uuid);
131
+ }
132
+ if (node.nextNode) {
133
+ node.nextNode.prevNode = prevNode;
134
+ }
135
+ return;
136
+ }
137
+ result.push(node);
138
+ });
139
+ {
140
+ /**
141
+ * Correction prev/next/parent
142
+ */
143
+ let prevToken = null;
144
+ for (const node of result) {
145
+ if (!prevToken) {
146
+ prevToken = node;
147
+ continue;
148
+ }
149
+ if (((prevToken.type === 'endtag' && prevToken.nodeName.toLowerCase() === 'body') ||
150
+ prevToken.type === 'doctype') &&
151
+ node.type === 'text') {
152
+ const nextNode = prevToken.nextNode;
153
+ prevToken.nextNode = node;
154
+ if (prevToken.type === 'endtag' && prevToken.pearNode) {
155
+ prevToken.pearNode.nextNode = node;
156
+ }
157
+ node.prevNode = prevToken;
158
+ node.nextNode = nextNode;
159
+ node.parentNode = prevToken.parentNode;
160
+ }
161
+ // EndTag
162
+ if (node.type === 'starttag' && node.pearNode) {
163
+ const endTag = node.pearNode;
164
+ endTag.pearNode = node;
165
+ endTag.prevNode = node.prevNode;
166
+ endTag.nextNode = node.nextNode;
167
+ }
168
+ // Children
169
+ if (node.type === 'text') {
170
+ const parent = node.parentNode;
171
+ if (parent && parent.type === 'starttag' && parent.nodeName.toLowerCase() === 'html') {
172
+ if (parent.childNodes && !parent.childNodes.some(n => n.uuid === node.uuid)) {
173
+ parent.childNodes.push(node);
174
+ }
175
+ }
176
+ }
177
+ prevToken = node;
178
+ }
179
+ }
180
+ // console.log(nodeOrders.map((n, i) => `${i}: ${n.raw.trim()}`));
181
+ return result;
182
+ }
183
+ function arrayize(
184
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
185
+ nodeTree, rawHtml) {
186
+ const nodeOrders = [];
187
+ let prevLine = 1;
188
+ let prevCol = 1;
189
+ let currentEndOffset = 0;
190
+ /**
191
+ * pushing list
192
+ */
193
+ walk(nodeTree, node => {
194
+ const diff = node.startOffset - currentEndOffset;
195
+ if (diff > 0) {
196
+ const html = rawHtml.slice(currentEndOffset, node.startOffset);
197
+ /**
198
+ * first white spaces
199
+ */
200
+ if (/^\s+$/.test(html)) {
201
+ const spaces = html;
202
+ const textNode = {
203
+ uuid: uuid(),
204
+ raw: spaces,
205
+ startOffset: currentEndOffset,
206
+ endOffset: currentEndOffset + spaces.length,
207
+ startLine: prevLine,
208
+ endLine: getEndLine(spaces, prevLine),
209
+ startCol: prevCol,
210
+ endCol: getEndCol(spaces, prevCol),
211
+ nodeName: '#text',
212
+ type: 'text',
213
+ parentNode: node.parentNode,
214
+ prevNode: node.prevNode,
215
+ nextNode: node,
216
+ isFragment: false,
217
+ isGhost: false,
218
+ };
219
+ node.prevNode = textNode;
220
+ if (node.parentNode && node.parentNode.childNodes) {
221
+ const newChildNodes = [...node.parentNode.childNodes];
222
+ if (newChildNodes.some(child => {
223
+ return (
224
+ // Out of start offset
225
+ textNode.endOffset < child.startOffset ||
226
+ // Out of end offset
227
+ child.endOffset < textNode.startOffset);
228
+ })) {
229
+ newChildNodes.push(textNode);
230
+ }
231
+ newChildNodes.sort((a, b) => a.startOffset - b.startOffset);
232
+ node.parentNode.childNodes = newChildNodes;
233
+ }
234
+ nodeOrders.push(textNode);
235
+ }
236
+ }
237
+ currentEndOffset = node.startOffset + node.raw.length;
238
+ prevLine = node.endLine;
239
+ prevCol = node.endCol;
240
+ // for ghost nodes
241
+ node.endOffset = node.endOffset ?? currentEndOffset;
242
+ nodeOrders.push(node);
243
+ });
244
+ return nodeOrders.slice();
245
+ }
@@ -1,27 +1,20 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sliceFragment = exports.getEndCol = exports.getEndLine = exports.getCol = exports.getLine = void 0;
4
- function getLine(html, startOffset) {
1
+ export function getLine(html, startOffset) {
5
2
  return html.slice(0, startOffset).split(/\n/g).length;
6
3
  }
7
- exports.getLine = getLine;
8
- function getCol(html, startOffset) {
4
+ export function getCol(html, startOffset) {
9
5
  const lines = html.slice(0, startOffset).split(/\n/g);
10
- return lines[lines.length - 1].length + 1;
6
+ return (lines[lines.length - 1] ?? '').length + 1;
11
7
  }
12
- exports.getCol = getCol;
13
- function getEndLine(html, line) {
8
+ export function getEndLine(html, line) {
14
9
  return html.split(/\r?\n/).length - 1 + line;
15
10
  }
16
- exports.getEndLine = getEndLine;
17
- function getEndCol(html, col) {
11
+ export function getEndCol(html, col) {
18
12
  const lines = html.split(/\r?\n/);
19
13
  const lineCount = lines.length;
20
14
  const lastLine = lines.pop();
21
15
  return lineCount > 1 ? lastLine.length + 1 : col + html.length;
22
16
  }
23
- exports.getEndCol = getEndCol;
24
- function sliceFragment(rawHtml, start, end) {
17
+ export function sliceFragment(rawHtml, start, end) {
25
18
  const raw = rawHtml.slice(start, end);
26
19
  return {
27
20
  startOffset: start,
@@ -33,4 +26,3 @@ function sliceFragment(rawHtml, start, end) {
33
26
  raw,
34
27
  };
35
28
  }
36
- exports.sliceFragment = sliceFragment;
@@ -0,0 +1 @@
1
+ export declare function getSpaceBefore(offset: number, rawCode: string): import("packages/@markuplint/ml-ast/lib/types.js").MLToken;
@@ -0,0 +1,8 @@
1
+ import { createTokenFromRawCode } from './create-token.js';
2
+ export function getSpaceBefore(offset, rawCode) {
3
+ const aboveCode = rawCode.slice(0, offset);
4
+ const aboveAttrMatched = aboveCode.match(/\s+$/m);
5
+ const aboveAttrChar = aboveAttrMatched?.[0] ?? '';
6
+ const spacesBefore = createTokenFromRawCode(aboveAttrChar, offset - aboveAttrChar.length, rawCode);
7
+ return spacesBefore;
8
+ }
@@ -1,6 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.searchIDLAttribute = void 0;
4
1
  /**
5
2
  * IDL attributes VS Content attributes
6
3
  *
@@ -108,6 +105,9 @@ const idlContentMap = {
108
105
  pattern: 'pattern',
109
106
  placeholder: 'placeholder',
110
107
  playsInline: 'playsinline',
108
+ popover: 'popover',
109
+ popoverTarget: 'popovertarget',
110
+ popoverTargetAction: 'popovertargetaction',
111
111
  poster: 'poster',
112
112
  preload: 'preload',
113
113
  profile: 'profile',
@@ -397,23 +397,38 @@ const idlContentMap = {
397
397
  yChannelSelector: 'yChannelSelector',
398
398
  z: 'z',
399
399
  zoomAndPan: 'zoomAndPan',
400
+ /**
401
+ * PerformanceElementTiming API
402
+ *
403
+ * @experimental
404
+ * @see https://wicg.github.io/element-timing/#sec-modifications-DOM
405
+ * @see https://wicg.github.io/element-timing/#sec-elements-exposed
406
+ */
407
+ elementTiming: 'elementtiming',
408
+ /**
409
+ * IFrame credentialless
410
+ *
411
+ * @experimental
412
+ * @warning No specification found
413
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/credentialless
414
+ */
415
+ credentialless: 'credentialless',
400
416
  };
401
417
  const list = Object.entries(idlContentMap);
402
- function searchIDLAttribute(name) {
418
+ export function searchIDLAttribute(name) {
403
419
  const camelizedName = camelize(name);
404
- const [idlPropName, contentAttrName] = (/^on[a-z]/.test(name) && [name.toLowerCase(), name.toLowerCase()]) ||
405
- list.find(([idlPropName, contentAttrName]) => idlPropName.toLowerCase() === camelizedName.toLowerCase() ||
420
+ const [idlPropName, contentAttrName] = /^on[a-z]/.test(name)
421
+ ? [name.toLowerCase(), name.toLowerCase()]
422
+ : list.find(([idlPropName, contentAttrName]) => idlPropName.toLowerCase() === camelizedName.toLowerCase() ||
406
423
  contentAttrName.toLowerCase() === name.toLowerCase() ||
407
- hyphenize(idlPropName) === name.toLowerCase()) ||
408
- [];
424
+ hyphenize(idlPropName) === name.toLowerCase()) ?? [];
409
425
  return {
410
426
  idlPropName,
411
427
  contentAttrName,
412
428
  };
413
429
  }
414
- exports.searchIDLAttribute = searchIDLAttribute;
415
430
  function camelize(str) {
416
- return str.replace(/[:-][a-z]/g, $0 => $0[1].toUpperCase());
431
+ return str.replace(/[:-][a-z]/g, $0 => $0[1]?.toUpperCase() ?? '');
417
432
  }
418
433
  function hyphenize(str) {
419
434
  return str.replace(/[A-Z]/g, $0 => `-${$0.toLowerCase()}`);
@@ -1,4 +1,4 @@
1
- import type { IgnoreBlock, IgnoreTag } from './types';
1
+ import type { IgnoreBlock, IgnoreTag } from './types.js';
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[];