weml-monaco 0.4.2 → 0.4.4

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/CHANGELOG.md CHANGED
@@ -8,6 +8,25 @@ This package mirrors the language logic of the VS Code extension; entries below
8
8
  track the port catching up with the VS Code provider changes (see the root
9
9
  `CHANGELOG.md` for the extension).
10
10
 
11
+ ## [0.4.4] — 2026-09-07
12
+
13
+ Synced with VS Code extension `0.7.12`.
14
+
15
+ ### Fixed
16
+ - Preserve surrounding word separators in nested inline wrappers containing
17
+ sentence elements when applying canonical formatting.
18
+
19
+ ## [0.4.3] — 2026-09-07
20
+
21
+ Synced with VS Code extension `0.7.11`.
22
+
23
+ ### Changed
24
+ - Updated the shared V2 normalizer: remove comments and empty text wrappers
25
+ without IDs, preserve word separators, normalize Unicode attribute separators
26
+ and trim attribute values.
27
+ - Improved void-tag scanning and whitespace cleanup between blocks, while
28
+ retaining browser and HTML-parser compatibility.
29
+
11
30
  ## [0.4.2] — 2026-08-30
12
31
 
13
32
  Synced with VS Code extension `0.7.9`.
package/dist/index.cjs CHANGED
@@ -6125,7 +6125,13 @@ var require_wemlContentNormalizeV2 = __commonJS({
6125
6125
  "wbr",
6126
6126
  "param"
6127
6127
  ]);
6128
- var VOID_TAG_RE = /<[ \t\n\f\r]*(area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr|param)(?=[ \t\n\f\r/>])((?:[^<>"']|"[^"]*"|'[^']*')*?)>/gi;
6128
+ var EMPTY_TEXT_WRAPPERS = /* @__PURE__ */ new Set([
6129
+ "w-format",
6130
+ "w-lang",
6131
+ "w-color",
6132
+ "w-non-egw",
6133
+ "w-sent"
6134
+ ]);
6129
6135
  var ENTITY_RE2 = /&(#[xX][0-9a-fA-F]+|#[0-9]+|[a-zA-Z][a-zA-Z0-9]*);?/g;
6130
6136
  var PH_OPEN = "\uE000";
6131
6137
  var PH_CLOSE = "\uE001";
@@ -6166,6 +6172,7 @@ var require_wemlContentNormalizeV2 = __commonJS({
6166
6172
  function formatWeml(input) {
6167
6173
  const { html, entities: entities2, marker } = protectEntities(input);
6168
6174
  const doc = parse2(normalizeVoidTagSyntax(html));
6175
+ removeEmptyWrappers(doc);
6169
6176
  const title = doc.querySelector("head title");
6170
6177
  if (title) processInlineContent(title, true);
6171
6178
  const body = doc.querySelector("body");
@@ -6211,47 +6218,135 @@ var require_wemlContentNormalizeV2 = __commonJS({
6211
6218
  }
6212
6219
  function normalizeVoidTagSyntax(input) {
6213
6220
  function slashBelongsToUnquotedValue(attrs) {
6214
- let index = 0;
6215
- const whitespace = /* @__PURE__ */ new Set([" ", " ", "\n", "\f", "\r"]);
6216
- while (index < attrs.length) {
6217
- while (index < attrs.length && whitespace.has(attrs[index])) index += 1;
6218
- if (index >= attrs.length || attrs[index] === "/") return false;
6219
- while (index < attrs.length && !whitespace.has(attrs[index]) && !["=", "/"].includes(attrs[index])) index += 1;
6220
- while (index < attrs.length && whitespace.has(attrs[index])) index += 1;
6221
- if (index >= attrs.length || attrs[index] !== "=") continue;
6222
- index += 1;
6223
- while (index < attrs.length && whitespace.has(attrs[index])) index += 1;
6224
- if (index >= attrs.length) return false;
6225
- if (attrs[index] === '"' || attrs[index] === "'") {
6226
- const quote = attrs[index];
6227
- index += 1;
6228
- while (index < attrs.length && attrs[index] !== quote) index += 1;
6229
- if (index < attrs.length) index += 1;
6221
+ let index2 = 0;
6222
+ const whitespace = /* @__PURE__ */ new Set([" ", " ", "\n", "\f", "\r", "\v"]);
6223
+ while (index2 < attrs.length) {
6224
+ while (index2 < attrs.length && whitespace.has(attrs[index2])) index2 += 1;
6225
+ if (index2 >= attrs.length || attrs[index2] === "/") return false;
6226
+ while (index2 < attrs.length && !whitespace.has(attrs[index2]) && !["=", "/"].includes(attrs[index2])) index2 += 1;
6227
+ while (index2 < attrs.length && whitespace.has(attrs[index2])) index2 += 1;
6228
+ if (index2 >= attrs.length || attrs[index2] !== "=") continue;
6229
+ index2 += 1;
6230
+ while (index2 < attrs.length && whitespace.has(attrs[index2])) index2 += 1;
6231
+ if (index2 >= attrs.length) return false;
6232
+ if (attrs[index2] === '"' || attrs[index2] === "'") {
6233
+ const quote = attrs[index2];
6234
+ index2 += 1;
6235
+ while (index2 < attrs.length && attrs[index2] !== quote) index2 += 1;
6236
+ if (index2 < attrs.length) index2 += 1;
6230
6237
  continue;
6231
6238
  }
6232
- const valueStart = index;
6233
- while (index < attrs.length && !whitespace.has(attrs[index])) index += 1;
6234
- if (index === attrs.length) {
6239
+ const valueStart = index2;
6240
+ while (index2 < attrs.length && !whitespace.has(attrs[index2])) index2 += 1;
6241
+ if (index2 === attrs.length) {
6235
6242
  return valueStart < attrs.length && attrs.endsWith("/");
6236
6243
  }
6237
6244
  }
6238
6245
  return false;
6239
6246
  }
6240
- return input.replace(VOID_TAG_RE, (_, name, rawAttrs) => {
6241
- let attrs = trimRawEndWhitespace(rawAttrs);
6242
- if (attrs.endsWith("/") && !slashBelongsToUnquotedValue(attrs)) {
6243
- attrs = trimRawEndWhitespace(attrs.slice(0, -1));
6247
+ const result = [];
6248
+ let index = 0;
6249
+ while (index < input.length) {
6250
+ if (input[index] !== "<") {
6251
+ result.push(input[index++]);
6252
+ continue;
6244
6253
  }
6245
- return `<${name.toLowerCase()}${attrs} />`;
6246
- });
6254
+ const start = index;
6255
+ if (input.startsWith("<!--", index) || input.startsWith("<?", index)) {
6256
+ const delimiter = input.startsWith("<!--", index) ? "-->" : "?>";
6257
+ let end2 = input.indexOf(delimiter, index + 2);
6258
+ end2 = end2 < 0 ? input.length : end2 + delimiter.length;
6259
+ result.push(input.slice(start, end2));
6260
+ index = end2;
6261
+ continue;
6262
+ }
6263
+ const { end } = findTagEnd(input, index + 1);
6264
+ if (end < 0) {
6265
+ result.push(input.slice(index));
6266
+ break;
6267
+ }
6268
+ let cursor = index + 1;
6269
+ if (input[cursor] === "!") {
6270
+ result.push(input.slice(start, end + 1));
6271
+ index = end + 1;
6272
+ continue;
6273
+ }
6274
+ const closing = input[cursor] === "/";
6275
+ if (closing) cursor++;
6276
+ if (cursor >= end || !isNameStart(input[cursor])) {
6277
+ result.push(input[index++]);
6278
+ continue;
6279
+ }
6280
+ const nameStart = cursor++;
6281
+ while (cursor < end && isNameChar(input[cursor])) cursor++;
6282
+ const name = input.slice(nameStart, cursor);
6283
+ const attributes = [];
6284
+ let quote = null;
6285
+ let inSpace = false;
6286
+ for (let offset = cursor; offset < end; offset++) {
6287
+ const character = input[offset];
6288
+ if (quote !== null) {
6289
+ attributes.push(character);
6290
+ if (character === quote) quote = null;
6291
+ continue;
6292
+ }
6293
+ if (isSourceSpace(character)) {
6294
+ if (!inSpace) attributes.push(" ");
6295
+ inSpace = true;
6296
+ } else {
6297
+ inSpace = false;
6298
+ attributes.push(character);
6299
+ if (character === '"' || character === "'") quote = character;
6300
+ }
6301
+ }
6302
+ let attrs = attributes.join("").replace(/ +$/, "");
6303
+ if (!closing && VOID_HTML_ELEMENTS.has(name.toLowerCase())) {
6304
+ if (attrs.endsWith("/") && !slashBelongsToUnquotedValue(attrs)) {
6305
+ attrs = attrs.slice(0, -1).replace(/ +$/, "");
6306
+ }
6307
+ result.push(`<${name.toLowerCase()}${attrs} />`);
6308
+ } else {
6309
+ result.push(input.slice(start, cursor), attrs, ">");
6310
+ }
6311
+ index = end + 1;
6312
+ }
6313
+ return result.join("");
6247
6314
  }
6248
- function processBlockElement(node) {
6315
+ function removeEmptyWrappers(node) {
6249
6316
  for (const child of [...node.childNodes]) {
6250
- if (child.nodeType !== 3) continue;
6251
- const normalized = trimWhitespace(child.rawText);
6252
- if (normalized) child.rawText = normalized;
6253
- else child.remove();
6317
+ if (child.nodeType === 8) {
6318
+ node.removeChild(child);
6319
+ continue;
6320
+ }
6321
+ if (child.nodeType !== 1) continue;
6322
+ removeEmptyWrappers(child);
6323
+ const hasId = Object.keys(child.rawAttributes).some((name) => name.toLowerCase() === "id");
6324
+ if (EMPTY_TEXT_WRAPPERS.has(child.rawTagName.toLowerCase()) && !hasId && child.childNodes.every((item) => item.nodeType === 3 && isWhitespaceOnly(item.rawText))) {
6325
+ const replacement = new TextNode(child.childNodes.some((item) => item.rawText.length > 0) ? " " : "", node);
6326
+ node.exchangeChild(child, replacement);
6327
+ }
6254
6328
  }
6329
+ let previous = null;
6330
+ for (const child of [...node.childNodes]) {
6331
+ if (child.nodeType === 3) {
6332
+ if (previous !== null) {
6333
+ previous.rawText += child.rawText;
6334
+ node.removeChild(child);
6335
+ } else previous = child;
6336
+ } else previous = null;
6337
+ }
6338
+ }
6339
+ function processBlockElement(node) {
6340
+ node.childNodes = node.childNodes.filter((child) => {
6341
+ if (child.nodeType !== 3) return true;
6342
+ const normalized = trimWhitespace(child.rawText);
6343
+ if (normalized) {
6344
+ child.rawText = normalized;
6345
+ return true;
6346
+ }
6347
+ child.parentNode = null;
6348
+ return false;
6349
+ });
6255
6350
  for (const child of [...node.childNodes]) {
6256
6351
  if (child.nodeType !== 1) continue;
6257
6352
  const name = child.rawTagName.toLowerCase();
@@ -6261,15 +6356,15 @@ var require_wemlContentNormalizeV2 = __commonJS({
6261
6356
  }
6262
6357
  }
6263
6358
  function processInlineContainer(node) {
6264
- if (hasDirectSentChildren(node)) processSentContainer(node);
6359
+ if (hasDirectSentChildren(node)) processSentContainer(node, true);
6265
6360
  else processInlineContent(node, true);
6266
6361
  }
6267
- function processSentContainer(node) {
6362
+ function processSentContainer(node, trimEdges) {
6268
6363
  for (const child of [...node.childNodes]) {
6269
6364
  if (child.nodeType !== 1) continue;
6270
6365
  const name = child.rawTagName.toLowerCase();
6271
6366
  if (isInlineTextElement(child)) {
6272
- if (hasDirectSentChildren(child)) processSentContainer(child);
6367
+ if (hasDirectSentChildren(child)) processSentContainer(child, false);
6273
6368
  else processInlineContent(child, false);
6274
6369
  } else if (BLOCK_ELEMENTS.has(name)) {
6275
6370
  processBlockElement(child);
@@ -6293,7 +6388,7 @@ var require_wemlContentNormalizeV2 = __commonJS({
6293
6388
  if (next && next.nodeType === 3) next.rawText = trimStartWhitespace(next.rawText);
6294
6389
  }
6295
6390
  }
6296
- trimContainerEdges(node);
6391
+ if (trimEdges) trimContainerEdges(node);
6297
6392
  for (const child of [...node.childNodes]) {
6298
6393
  if (child.nodeType === 3 && child.rawText === "") child.remove();
6299
6394
  }
@@ -6315,7 +6410,7 @@ var require_wemlContentNormalizeV2 = __commonJS({
6315
6410
  if (child.nodeType !== 1) continue;
6316
6411
  const name = child.rawTagName.toLowerCase();
6317
6412
  if (isInlineTextElement(child)) {
6318
- if (hasDirectSentChildren(child)) processSentContainer(child);
6413
+ if (hasDirectSentChildren(child)) processSentContainer(child, false);
6319
6414
  else processInlineContent(child, false);
6320
6415
  } else if (BLOCK_ELEMENTS.has(name)) {
6321
6416
  processBlockElement(child);
@@ -6506,7 +6601,7 @@ var require_wemlContentNormalizeV2 = __commonJS({
6506
6601
  }
6507
6602
  canonical.set(
6508
6603
  name,
6509
- SPACE_SEPARATED_ATTRIBUTES.has(name) ? normalizeTokenList(value, entities2, marker) : value
6604
+ SPACE_SEPARATED_ATTRIBUTES.has(name) ? normalizeTokenList(value, entities2, marker) : trimWhitespace(value)
6510
6605
  );
6511
6606
  }
6512
6607
  return [...canonical.entries()].sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([name, value]) => ` ${name}="${encodeAttr(String(value))}"`).join("");
@@ -6736,7 +6831,7 @@ var require_wemlContentNormalizeV2 = __commonJS({
6736
6831
  return isNameStart(character) || character >= "0" && character <= "9" || character === "-" || character === "_" || character === ":" || character === ".";
6737
6832
  }
6738
6833
  function isSourceSpace(character) {
6739
- return character === " " || character === " " || character === "\n" || character === "\r" || character === "\f" || character === "\v";
6834
+ return isNormalizableWhitespace(character);
6740
6835
  }
6741
6836
  function withoutWhiteSpace(text) {
6742
6837
  return Array.from(text, (character) => WHITE_SPACE.has(character.codePointAt(0)) ? "" : character).join("");
@@ -6767,13 +6862,6 @@ var require_wemlContentNormalizeV2 = __commonJS({
6767
6862
  function trimWhitespace(text) {
6768
6863
  return collapseWhitespace(text).replace(/^ +| +$/g, "");
6769
6864
  }
6770
- function trimRawEndWhitespace(text) {
6771
- const characters = Array.from(text);
6772
- while (characters.length > 0 && isNormalizableWhitespace(characters.at(-1))) {
6773
- characters.pop();
6774
- }
6775
- return characters.join("");
6776
- }
6777
6865
  function isWhitespaceOnly(text) {
6778
6866
  return Array.from(text).every(isNormalizableWhitespace);
6779
6867
  }
@@ -30842,24 +30930,22 @@ function getCompletionContext(text, offset, nodeStart) {
30842
30930
  switch (token) {
30843
30931
  case TokenType.StartTagOpen:
30844
30932
  if (scanner.getTokenEnd() === offset) {
30845
- const end = scanNextEnd(scanner, offset, TokenType.StartTag);
30846
- return { kind: "tag", start: offset - 1, end, includesBracket: true };
30933
+ return { kind: "tag", start: offset - 1, end: offset, includesBracket: true };
30847
30934
  }
30848
30935
  break;
30849
30936
  case TokenType.EndTagOpen:
30850
30937
  if (scanner.getTokenEnd() === offset) {
30851
- const end = scanNextEnd(scanner, offset, TokenType.EndTag);
30852
- return { kind: "end-tag", start: offset, end };
30938
+ return { kind: "end-tag", start: offset, end: offset };
30853
30939
  }
30854
30940
  break;
30855
30941
  case TokenType.EndTag:
30856
30942
  if (scanner.getTokenOffset() <= offset && offset <= scanner.getTokenEnd()) {
30857
- return { kind: "end-tag", start: scanner.getTokenOffset(), end: scanner.getTokenEnd() };
30943
+ return { kind: "end-tag", start: scanner.getTokenOffset(), end: offset };
30858
30944
  }
30859
30945
  break;
30860
30946
  case TokenType.StartTag:
30861
30947
  if (scanner.getTokenOffset() <= offset && offset <= scanner.getTokenEnd()) {
30862
- return { kind: "tag", start: scanner.getTokenOffset(), end: scanner.getTokenEnd(), includesBracket: false };
30948
+ return { kind: "tag", start: scanner.getTokenOffset(), end: offset, includesBracket: false };
30863
30949
  }
30864
30950
  currentTag = scanner.getTokenText();
30865
30951
  break;
@@ -30897,8 +30983,7 @@ function getCompletionContext(text, offset, nodeStart) {
30897
30983
  switch (scanner.getScannerState()) {
30898
30984
  case ScannerState.AfterOpeningStartTag: {
30899
30985
  const start = scanner.getTokenOffset();
30900
- const end = scanNextEnd(scanner, offset, TokenType.StartTag);
30901
- return { kind: "tag", start, end, includesBracket: false };
30986
+ return { kind: "tag", start, end: offset, includesBracket: false };
30902
30987
  }
30903
30988
  case ScannerState.WithinTag:
30904
30989
  case ScannerState.AfterAttributeName: