@markuplint/parser-utils 4.0.0-alpha.7 → 4.0.0-alpha.8

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,4 +1,4 @@
1
1
  import type { IgnoreBlock, IgnoreTag } from './types.js';
2
2
  import type { MLASTNode } from '@markuplint/ml-ast';
3
3
  export declare function ignoreBlock(source: string, tags: readonly IgnoreTag[], maskChar?: string): IgnoreBlock;
4
- export declare function restoreNode(nodeList: MLASTNode[], ignoreBlock: IgnoreBlock): MLASTNode[];
4
+ export declare function restoreNode(nodeList: MLASTNode[], ignoreBlock: IgnoreBlock, throwErrorWhenTagHasUnresolved?: boolean): MLASTNode[];
@@ -1,21 +1,11 @@
1
1
  import { MASK_CHAR } from './const.js';
2
2
  import { uuid } from './create-token.js';
3
- import { sliceFragment } from './get-location.js';
4
- import { siblingsCorrection } from './siblings-correction.js';
3
+ import { getCol, getLine } from './get-location.js';
4
+ import { ParserError } from './parser-error.js';
5
5
  export function ignoreBlock(source, tags, maskChar = MASK_CHAR) {
6
6
  let replaced = source;
7
7
  const stack = [];
8
8
  for (const tag of tags) {
9
- // Replace tags in attributes
10
- const attr = maskText(prepend(tag.start, '(?<=(?:"|\'))'), append(tag.end, '(?=(?:"|\'))'), replaced, (startTag, taggedCode, endTag) => {
11
- const mask = maskChar.repeat(startTag.length) +
12
- taggedCode.replaceAll(/[^\n]/g, maskChar) +
13
- maskChar.repeat((endTag ?? '').length);
14
- return mask;
15
- });
16
- replaced = attr.replaced;
17
- stack.push(...attr.stack.map(res => ({ ...res, type: tag.type })));
18
- // Replace tags in other nodes
19
9
  const text = maskText(tag.start, tag.end, replaced, (startTag, taggedCode, endTag) => {
20
10
  const mask = maskChar.repeat(startTag.length) +
21
11
  taggedCode.replaceAll(/[^\n]/g, maskChar) +
@@ -49,6 +39,7 @@ function maskText(start, end, replaced, masking) {
49
39
  startTag,
50
40
  taggedCode,
51
41
  endTag: endTag ?? null,
42
+ resolved: false,
52
43
  });
53
44
  /**
54
45
  * It will not replace line breaks because detects line number.
@@ -62,7 +53,9 @@ function maskText(start, end, replaced, masking) {
62
53
  }
63
54
  export function restoreNode(
64
55
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
65
- nodeList, ignoreBlock) {
56
+ nodeList,
57
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
58
+ ignoreBlock, throwErrorWhenTagHasUnresolved = true) {
66
59
  nodeList = [...nodeList];
67
60
  const { source, stack, maskChar } = ignoreBlock;
68
61
  for (const tag of stack) {
@@ -70,9 +63,6 @@ nodeList, ignoreBlock) {
70
63
  if (!node) {
71
64
  continue;
72
65
  }
73
- if (node.type !== 'comment') {
74
- continue;
75
- }
76
66
  const psNode = {
77
67
  uuid: uuid(),
78
68
  type: 'psblock',
@@ -102,101 +92,9 @@ nodeList, ignoreBlock) {
102
92
  }
103
93
  const index = nodeList.indexOf(node);
104
94
  nodeList.splice(index, 1, psNode);
95
+ tag.resolved = true;
105
96
  }
106
97
  for (const node of nodeList) {
107
- if (node.type === 'comment' || node.type === 'text' || node.type === 'psblock') {
108
- if (!hasIgnoreBlock(node.raw, maskChar)) {
109
- continue;
110
- }
111
- const parentNode = node.parentNode;
112
- const index = nodeList.indexOf(node);
113
- const insertList = [];
114
- let text = node.raw;
115
- let pointer = 0;
116
- for (const tag of stack) {
117
- if (node.startOffset <= tag.index && tag.index < node.endOffset) {
118
- const start = tag.index - node.startOffset;
119
- const body = tag.startTag + tag.taggedCode + (tag.endTag ?? '');
120
- const above = node.raw.slice(pointer, start);
121
- const below = text.slice(above.length + body.length);
122
- if (above) {
123
- const offset = node.startOffset + pointer;
124
- const { raw, startOffset, endOffset, startLine, endLine, startCol, endCol } = sliceFragment(source, offset, offset + above.length);
125
- const textNode = {
126
- ...node,
127
- uuid: uuid(),
128
- type: 'text',
129
- raw,
130
- startOffset,
131
- endOffset,
132
- startLine,
133
- endLine,
134
- startCol,
135
- endCol,
136
- };
137
- if (node.prevNode?.nextNode) {
138
- node.prevNode.nextNode = textNode;
139
- }
140
- if (node.nextNode?.prevNode) {
141
- node.nextNode.prevNode = textNode;
142
- }
143
- insertList.push(textNode);
144
- }
145
- if (body) {
146
- const offset = node.startOffset + pointer + above.length;
147
- const { raw, startOffset, endOffset, startLine, endLine, startCol, endCol } = sliceFragment(source, offset, offset + body.length);
148
- const bodyNode = {
149
- uuid: uuid(),
150
- type: 'psblock',
151
- nodeName: `#ps:${tag.type}`,
152
- raw,
153
- parentNode: node.parentNode,
154
- prevNode: null,
155
- nextNode: null,
156
- isFragment: node.isFragment,
157
- isGhost: false,
158
- startOffset,
159
- endOffset,
160
- startLine,
161
- endLine,
162
- startCol,
163
- endCol,
164
- };
165
- if (node.prevNode?.nextNode) {
166
- node.prevNode.nextNode = bodyNode;
167
- }
168
- if (node.nextNode?.prevNode) {
169
- node.nextNode.prevNode = bodyNode;
170
- }
171
- insertList.push(bodyNode);
172
- }
173
- text = below;
174
- pointer = start + body.length;
175
- }
176
- }
177
- if (text) {
178
- const offset = node.endOffset - text.length;
179
- const { raw, startOffset, endOffset, startLine, endLine, startCol, endCol } = sliceFragment(source, offset, offset + text.length);
180
- const textNode = {
181
- ...node,
182
- uuid: uuid(),
183
- type: 'text',
184
- raw,
185
- startOffset,
186
- endOffset,
187
- startLine,
188
- endLine,
189
- startCol,
190
- endCol,
191
- };
192
- insertList.push(textNode);
193
- }
194
- siblingsCorrection(insertList);
195
- if (parentNode) {
196
- parentNode.childNodes = insertList;
197
- }
198
- nodeList.splice(index, 1, ...insertList);
199
- }
200
98
  if (node.type === 'starttag') {
201
99
  for (const attr of node.attributes) {
202
100
  if (attr.type === 'ps-attr' || attr.value.raw === '' || !hasIgnoreBlock(attr.value.raw, maskChar)) {
@@ -211,8 +109,35 @@ nodeList, ignoreBlock) {
211
109
  const below = attr.value.raw.slice(offset + length);
212
110
  attr.value.raw = above + raw + below;
213
111
  attr.isDynamicValue = true;
112
+ tag.resolved = true;
214
113
  }
114
+ attr.raw =
115
+ attr.spacesBeforeName.raw +
116
+ attr.name.raw +
117
+ attr.spacesBeforeEqual.raw +
118
+ attr.equal.raw +
119
+ attr.spacesAfterEqual.raw +
120
+ attr.startQuote.raw +
121
+ attr.value.raw +
122
+ attr.endQuote.raw;
215
123
  }
124
+ // Update node raw
125
+ const length = attr.raw.length;
126
+ const offset = attr.startOffset - node.startOffset - attr.spacesBeforeName.raw.length;
127
+ const above = node.raw.slice(0, offset);
128
+ const below = node.raw.slice(offset + length);
129
+ node.raw = above + attr.raw + below;
130
+ }
131
+ }
132
+ }
133
+ if (throwErrorWhenTagHasUnresolved) {
134
+ for (const tag of stack) {
135
+ if (!tag.resolved) {
136
+ throw new ParserError('Parsing failed. Unsupported syntax detected', {
137
+ line: getLine(source, tag.index),
138
+ col: getCol(source, tag.index),
139
+ raw: tag.startTag + tag.taggedCode + (tag.endTag ?? ''),
140
+ });
216
141
  }
217
142
  }
218
143
  }
@@ -235,18 +160,6 @@ function removeGlobalOption(reg) {
235
160
  }
236
161
  return new RegExp(reg.source, reg.ignoreCase ? 'i' : '');
237
162
  }
238
- function prepend(reg, str) {
239
- if (typeof reg === 'string') {
240
- return new RegExp(str + escapeRegExpForStr(reg));
241
- }
242
- return new RegExp(str + reg.source, reg.ignoreCase ? 'i' : '');
243
- }
244
- function append(reg, str) {
245
- if (typeof reg === 'string') {
246
- return new RegExp(escapeRegExpForStr(reg) + str);
247
- }
248
- return new RegExp(reg.source + str, reg.ignoreCase ? 'i' : '');
249
- }
250
163
  function hasIgnoreBlock(textContent, maskChar) {
251
164
  return textContent.includes(maskChar);
252
165
  }
package/lib/types.d.ts CHANGED
@@ -4,6 +4,7 @@ export type Code = {
4
4
  readonly startTag: string;
5
5
  readonly taggedCode: string;
6
6
  readonly endTag: string | null;
7
+ resolved: boolean;
7
8
  };
8
9
  export type IgnoreTag = {
9
10
  readonly type: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markuplint/parser-utils",
3
- "version": "4.0.0-alpha.7",
3
+ "version": "4.0.0-alpha.8",
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>",
@@ -24,12 +24,12 @@
24
24
  "clean": "tsc --build --clean"
25
25
  },
26
26
  "dependencies": {
27
- "@markuplint/ml-ast": "4.0.0-alpha.7",
28
- "@markuplint/types": "4.0.0-alpha.7",
27
+ "@markuplint/ml-ast": "4.0.0-alpha.8",
28
+ "@markuplint/types": "4.0.0-alpha.8",
29
29
  "@types/uuid": "^9.0.7",
30
30
  "espree": "^9.6.1",
31
31
  "type-fest": "^4.9.0",
32
32
  "uuid": "^9.0.1"
33
33
  },
34
- "gitHead": "571129bf6498541125e1e7c3907d5ed9af53459a"
34
+ "gitHead": "5bcd25f13ff804af0d09aaabd87e495af668e6a8"
35
35
  }