@markuplint/parser-utils 4.0.0-alpha.6 → 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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2017-2023 Yusuke Hirao
3
+ Copyright (c) 2017-2024 Yusuke Hirao
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/lib/const.d.ts CHANGED
@@ -11,6 +11,7 @@ export declare const reSplitterTag: RegExp;
11
11
  * - U+0009 CHARACTER TABULATION (tab) => `\t`
12
12
  * - U+000A LINE FEED (LF) => `\n`
13
13
  * - U+000C FORM FEED (FF) => `\f`
14
+ * - U+000D CARRIAGE RETURN (CR) => `\r`
14
15
  * - U+0020 SPACE => ` `
15
16
  */
16
- export declare const defaultSpaces: readonly ["\t", "\n", "\f", " "];
17
+ export declare const defaultSpaces: readonly ["\t", "\n", "\f", "\r", " "];
package/lib/const.js CHANGED
@@ -100,6 +100,7 @@ export const reSplitterTag = /<[^>]+>/g;
100
100
  * - U+0009 CHARACTER TABULATION (tab) => `\t`
101
101
  * - U+000A LINE FEED (LF) => `\n`
102
102
  * - U+000C FORM FEED (FF) => `\f`
103
+ * - U+000D CARRIAGE RETURN (CR) => `\r`
103
104
  * - U+0020 SPACE => ` `
104
105
  */
105
- export const defaultSpaces = ['\t', '\n', '\f', ' '];
106
+ export const defaultSpaces = ['\t', '\n', '\f', '\r', ' '];
@@ -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,103 +53,48 @@ 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
- for (const node of nodeList) {
69
- if (node.type === 'comment' || node.type === 'text' || node.type === 'psblock') {
70
- if (!hasIgnoreBlock(node.raw, maskChar)) {
71
- continue;
72
- }
73
- const parentNode = node.parentNode;
74
- const index = nodeList.indexOf(node);
75
- const insertList = [];
76
- let text = node.raw;
77
- let pointer = 0;
78
- for (const tag of stack) {
79
- if (node.startOffset <= tag.index && tag.index < node.endOffset) {
80
- const start = tag.index - node.startOffset;
81
- const body = tag.startTag + tag.taggedCode + (tag.endTag ?? '');
82
- const above = node.raw.slice(pointer, start);
83
- const below = text.slice(above.length + body.length);
84
- if (above) {
85
- const offset = node.startOffset + pointer;
86
- const { raw, startOffset, endOffset, startLine, endLine, startCol, endCol } = sliceFragment(source, offset, offset + above.length);
87
- const textNode = {
88
- ...node,
89
- uuid: uuid(),
90
- type: 'text',
91
- raw,
92
- startOffset,
93
- endOffset,
94
- startLine,
95
- endLine,
96
- startCol,
97
- endCol,
98
- };
99
- if (node.prevNode?.nextNode) {
100
- node.prevNode.nextNode = textNode;
101
- }
102
- if (node.nextNode?.prevNode) {
103
- node.nextNode.prevNode = textNode;
104
- }
105
- insertList.push(textNode);
106
- }
107
- if (body) {
108
- const offset = node.startOffset + pointer + above.length;
109
- const { raw, startOffset, endOffset, startLine, endLine, startCol, endCol } = sliceFragment(source, offset, offset + body.length);
110
- const bodyNode = {
111
- uuid: uuid(),
112
- type: 'psblock',
113
- nodeName: `#ps:${tag.type}`,
114
- raw,
115
- parentNode: node.parentNode,
116
- prevNode: null,
117
- nextNode: null,
118
- isFragment: node.isFragment,
119
- isGhost: false,
120
- startOffset,
121
- endOffset,
122
- startLine,
123
- endLine,
124
- startCol,
125
- endCol,
126
- };
127
- if (node.prevNode?.nextNode) {
128
- node.prevNode.nextNode = bodyNode;
129
- }
130
- if (node.nextNode?.prevNode) {
131
- node.nextNode.prevNode = bodyNode;
132
- }
133
- insertList.push(bodyNode);
134
- }
135
- text = below;
136
- pointer = start + body.length;
137
- }
138
- }
139
- if (text) {
140
- const offset = node.endOffset - text.length;
141
- const { raw, startOffset, endOffset, startLine, endLine, startCol, endCol } = sliceFragment(source, offset, offset + text.length);
142
- const textNode = {
143
- ...node,
144
- uuid: uuid(),
145
- type: 'text',
146
- raw,
147
- startOffset,
148
- endOffset,
149
- startLine,
150
- endLine,
151
- startCol,
152
- endCol,
153
- };
154
- insertList.push(textNode);
155
- }
156
- siblingsCorrection(insertList);
157
- if (parentNode) {
158
- parentNode.childNodes = insertList;
159
- }
160
- nodeList.splice(index, 1, ...insertList);
61
+ for (const tag of stack) {
62
+ const node = nodeList.find(node => node.startOffset === tag.index);
63
+ if (!node) {
64
+ continue;
161
65
  }
66
+ const psNode = {
67
+ uuid: uuid(),
68
+ type: 'psblock',
69
+ nodeName: `#ps:${tag.type}`,
70
+ raw: `${tag.startTag}${tag.taggedCode}${tag.endTag ?? ''}`,
71
+ parentNode: node.parentNode,
72
+ prevNode: null,
73
+ nextNode: null,
74
+ isFragment: node.isFragment,
75
+ isGhost: false,
76
+ startOffset: node.startOffset,
77
+ endOffset: node.endOffset,
78
+ startLine: node.startLine,
79
+ endLine: node.endLine,
80
+ startCol: node.startCol,
81
+ endCol: node.endCol,
82
+ };
83
+ if (node.prevNode?.nextNode) {
84
+ node.prevNode.nextNode = psNode;
85
+ }
86
+ if (node.nextNode?.prevNode) {
87
+ node.nextNode.prevNode = psNode;
88
+ }
89
+ if (node.parentNode?.childNodes) {
90
+ const index = node.parentNode.childNodes.indexOf(node);
91
+ node.parentNode.childNodes.splice(index, 1, psNode);
92
+ }
93
+ const index = nodeList.indexOf(node);
94
+ nodeList.splice(index, 1, psNode);
95
+ tag.resolved = true;
96
+ }
97
+ for (const node of nodeList) {
162
98
  if (node.type === 'starttag') {
163
99
  for (const attr of node.attributes) {
164
100
  if (attr.type === 'ps-attr' || attr.value.raw === '' || !hasIgnoreBlock(attr.value.raw, maskChar)) {
@@ -173,8 +109,35 @@ nodeList, ignoreBlock) {
173
109
  const below = attr.value.raw.slice(offset + length);
174
110
  attr.value.raw = above + raw + below;
175
111
  attr.isDynamicValue = true;
112
+ tag.resolved = true;
176
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;
177
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
+ });
178
141
  }
179
142
  }
180
143
  }
@@ -197,18 +160,6 @@ function removeGlobalOption(reg) {
197
160
  }
198
161
  return new RegExp(reg.source, reg.ignoreCase ? 'i' : '');
199
162
  }
200
- function prepend(reg, str) {
201
- if (typeof reg === 'string') {
202
- return new RegExp(str + escapeRegExpForStr(reg));
203
- }
204
- return new RegExp(str + reg.source, reg.ignoreCase ? 'i' : '');
205
- }
206
- function append(reg, str) {
207
- if (typeof reg === 'string') {
208
- return new RegExp(escapeRegExpForStr(reg) + str);
209
- }
210
- return new RegExp(reg.source + str, reg.ignoreCase ? 'i' : '');
211
- }
212
163
  function hasIgnoreBlock(textContent, maskChar) {
213
164
  return textContent.includes(maskChar);
214
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.6",
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.6",
28
- "@markuplint/types": "4.0.0-alpha.6",
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
- "type-fest": "^4.8.2",
31
+ "type-fest": "^4.9.0",
32
32
  "uuid": "^9.0.1"
33
33
  },
34
- "gitHead": "06e1242d274c72cf08a10a572b06ac35d1b924a4"
34
+ "gitHead": "5bcd25f13ff804af0d09aaabd87e495af668e6a8"
35
35
  }