@jxsuite/parser 1.4.0 → 1.5.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/dist/markdown.js CHANGED
@@ -865,6 +865,22 @@ function isJsonObject(value) {
865
865
  function isRef(value) {
866
866
  return isJsonObject(value) && typeof value.$ref === "string";
867
867
  }
868
+ function isTagExpression(tagName) {
869
+ return isJsonObject(tagName) && isJsonObject(tagName.$expression);
870
+ }
871
+ function tagNameCandidates(tagName) {
872
+ if (typeof tagName === "string") {
873
+ return [tagName];
874
+ }
875
+ if (!isTagExpression(tagName)) {
876
+ return [];
877
+ }
878
+ const expression = tagName.$expression;
879
+ if (expression.operator === "?:") {
880
+ return [...new Set([expression.value, expression.initial])];
881
+ }
882
+ return [...new Set([...Object.values(expression.cases), expression.default])];
883
+ }
868
884
  var SCHEMA_KEYWORDS;
869
885
  var init_guards = __esm(() => {
870
886
  SCHEMA_KEYWORDS = new Set([
@@ -41982,7 +41998,7 @@ function transpileJxMarkdown(source) {
41982
41998
  return doc;
41983
41999
  }
41984
42000
  function slugifyHeading(text5) {
41985
- return text5.toLowerCase().replaceAll(/[^\w\s-]/g, "").replaceAll(/\s+/g, "-").replaceAll(/-+/g, "-").replaceAll(/^-|-$/g, "");
42001
+ return text5.normalize("NFC").toLowerCase().replaceAll(/[^\p{L}\p{N}_\s-]/gu, "").replaceAll(/\s+/gu, "-").replaceAll(/-+/g, "-").replaceAll(/^-|-$/g, "");
41986
42002
  }
41987
42003
  function jxNodeText(node2) {
41988
42004
  if (typeof node2 === "string") {
@@ -42004,7 +42020,7 @@ function assignHeadingIds(children) {
42004
42020
  if (typeof node2 !== "object" || node2 === null) {
42005
42021
  continue;
42006
42022
  }
42007
- const tag = node2.tagName;
42023
+ const tag = typeof node2.tagName === "string" ? node2.tagName : "";
42008
42024
  if (tag && HEADING_TAGS.has(tag)) {
42009
42025
  const text5 = jxNodeText(node2).trim();
42010
42026
  let id = typeof node2.id === "string" && node2.id.length > 0 ? node2.id : "";
@@ -42313,7 +42329,7 @@ function convertJxNode(el, isBlock, allowlist) {
42313
42329
  if (!el || typeof el !== "object") {
42314
42330
  return null;
42315
42331
  }
42316
- const tag = el.tagName ?? "div";
42332
+ const tag = serializableTag(el.tagName) || "div";
42317
42333
  if (!allowlist.has(tag) || hasJxProps(el)) {
42318
42334
  return convertToDirective(el, isBlock, allowlist);
42319
42335
  }
@@ -42442,6 +42458,15 @@ function convertJxNode(el, isBlock, allowlist) {
42442
42458
  }
42443
42459
  return null;
42444
42460
  }
42461
+ function serializableTag(tagName) {
42462
+ if (typeof tagName === "string") {
42463
+ return tagName;
42464
+ }
42465
+ if (tagName == null) {
42466
+ return "";
42467
+ }
42468
+ throw new Error(`Markdown cannot express a tag chosen at creation (candidates: ` + `${tagNameCandidates(tagName).join(", ")}). Keep this element in a JSON component.`);
42469
+ }
42445
42470
  function collectDirectiveAttrs(el) {
42446
42471
  const propsObj = {};
42447
42472
  for (const [key2, value2] of Object.entries(el)) {
@@ -42574,7 +42599,7 @@ function nodeToMdast(node2, ctx, scope) {
42574
42599
  if (node2.$prototype === "Array") {
42575
42600
  return expandArray(node2, ctx, scope);
42576
42601
  }
42577
- const tag = node2.tagName ?? "div";
42602
+ const tag = serializableTag(node2.tagName) || "div";
42578
42603
  const text5 = resolveText(node2.textContent, ctx, scope);
42579
42604
  if (typeof node2.innerHTML === "string" && node2.innerHTML.trim()) {
42580
42605
  const htmlNodes = htmlToMdast(node2.innerHTML);
@@ -43373,6 +43398,63 @@ var init_serialize = __esm(() => {
43373
43398
  JX_ANNOTATION_KEYS2 = new Set(["$title", "$description"]);
43374
43399
  });
43375
43400
 
43401
+ // ../../packages/schema/src/intl.ts
43402
+ var DEFAULT_FORMAT_LOCALE = "en-US", INTL_HELPERS, INTL_HELPER_PATHS, INTL_LOCALE_PARAM;
43403
+ var init_intl = __esm(() => {
43404
+ INTL_HELPERS = [
43405
+ {
43406
+ api: "Intl.NumberFormat",
43407
+ params: ["value", "locale", "options"],
43408
+ path: "Intl/formatNumber",
43409
+ summary: "Format a number for a locale — grouping, decimals, currency, percent, units."
43410
+ },
43411
+ {
43412
+ api: "Intl.DateTimeFormat",
43413
+ params: ["value", "locale", "options"],
43414
+ path: "Intl/formatDate",
43415
+ summary: "Format a date or timestamp for a locale. Pass `timeZone` in options."
43416
+ },
43417
+ {
43418
+ api: "Intl.RelativeTimeFormat",
43419
+ params: ["value", "unit", "locale", "options"],
43420
+ path: "Intl/formatRelativeTime",
43421
+ summary: 'Format a relative time — `-3, "day"` becomes "3 days ago".'
43422
+ },
43423
+ {
43424
+ api: "Intl.ListFormat",
43425
+ params: ["values", "locale", "options"],
43426
+ path: "Intl/formatList",
43427
+ summary: 'Join a list the way a locale does — "a, b, and c", not a hand-written comma join.'
43428
+ },
43429
+ {
43430
+ api: "Intl.PluralRules",
43431
+ params: ["value", "locale", "options"],
43432
+ path: "Intl/plural",
43433
+ summary: 'Which plural category a number falls in ("one", "few", "other") — many languages have ' + "more than two, so a ternary on `n === 1` is wrong outside English."
43434
+ },
43435
+ {
43436
+ api: "Intl.Collator",
43437
+ params: ["a", "b", "locale", "options"],
43438
+ path: "Intl/compare",
43439
+ summary: "Compare two strings for sorting. `<` and `sort()` order by UTF-16 code unit, which puts " + '"Zebra" before "apple" and sorts every accented word into the wrong place.'
43440
+ },
43441
+ {
43442
+ api: "Intl.DisplayNames",
43443
+ params: ["code", "type", "locale", "options"],
43444
+ path: "Intl/displayName",
43445
+ summary: 'The name of a language, region, script or currency in a locale — "de" as "German" or ' + '"Deutsch", from CLDR rather than a hand-kept table.'
43446
+ },
43447
+ {
43448
+ api: "Intl.Segmenter",
43449
+ params: ["value", "granularity", "locale"],
43450
+ path: "Intl/segment",
43451
+ summary: "Split text into graphemes, words or sentences (UAX #29). `[...str]` splits code points, " + "so it cuts an emoji with a skin-tone modifier in half."
43452
+ }
43453
+ ];
43454
+ INTL_HELPER_PATHS = INTL_HELPERS.map((helper) => helper.path);
43455
+ INTL_LOCALE_PARAM = Object.fromEntries(INTL_HELPERS.map((helper) => [helper.path, helper.params.indexOf("locale")]));
43456
+ });
43457
+
43376
43458
  // ../../node_modules/glob/dist/esm/index.min.js
43377
43459
  import { fileURLToPath as Wi } from "node:url";
43378
43460
  import { posix as mi, win32 as re2 } from "node:path";
@@ -51707,15 +51789,34 @@ function splitToken(token, offsets) {
51707
51789
  });
51708
51790
  return tokens;
51709
51791
  }
51792
+ function findFirstBreakpointAfter(breakpoints, offset) {
51793
+ let start = 0;
51794
+ let end = breakpoints.length;
51795
+ while (start < end) {
51796
+ const middle = start + (end - start >> 1);
51797
+ if (breakpoints[middle] <= offset)
51798
+ start = middle + 1;
51799
+ else
51800
+ end = middle;
51801
+ }
51802
+ return start;
51803
+ }
51710
51804
  function splitTokens(tokens, breakpoints) {
51711
51805
  const sorted = [...breakpoints instanceof Set ? breakpoints : new Set(breakpoints)].sort((a, b) => a - b);
51712
51806
  if (!sorted.length)
51713
51807
  return tokens;
51714
51808
  return tokens.map((line) => {
51715
51809
  return line.flatMap((token) => {
51716
- const breakpointsInToken = sorted.filter((i) => token.offset < i && i < token.offset + token.content.length).map((i) => i - token.offset).sort((a, b) => a - b);
51717
- if (!breakpointsInToken.length)
51810
+ const tokenEnd = token.offset + token.content.length;
51811
+ const start = findFirstBreakpointAfter(sorted, token.offset);
51812
+ let end = start;
51813
+ while (end < sorted.length && sorted[end] < tokenEnd)
51814
+ end++;
51815
+ if (start === end)
51718
51816
  return token;
51817
+ const breakpointsInToken = sorted.slice(start, end);
51818
+ for (let index2 = 0;index2 < breakpointsInToken.length; index2++)
51819
+ breakpointsInToken[index2] -= token.offset;
51719
51820
  return splitToken(token, breakpointsInToken);
51720
51821
  });
51721
51822
  });
@@ -51742,7 +51843,9 @@ function flatTokenVariants(merged, variantsOrder, cssVariablePrefix, defaultColo
51742
51843
  const darkIndex = variantsOrder.findIndex((t) => t === "dark");
51743
51844
  if (lightIndex === -1 || darkIndex === -1)
51744
51845
  throw new ShikiError('When using `defaultColor: "light-dark()"`, you must provide both `light` and `dark` themes');
51745
- mergedStyles[key2] = `light-dark(${styles[lightIndex][key2] || "inherit"}, ${styles[darkIndex][key2] || "inherit"})`;
51846
+ const lightValue = styles[lightIndex][key2] || "inherit";
51847
+ const darkValue = styles[darkIndex][key2] || "inherit";
51848
+ mergedStyles[key2] = `light-dark(${lightValue}, ${darkValue})`;
51746
51849
  if (colorsRendering === "css-vars")
51747
51850
  mergedStyles[varKey(idx, key2)] = value2;
51748
51851
  } else
@@ -56080,9 +56183,17 @@ function mdastToString(node2) {
56080
56183
  }
56081
56184
  return "";
56082
56185
  }
56186
+ function countWords(text6) {
56187
+ let words = 0;
56188
+ for (const { segment } of WORD_SEGMENTER.segment(text6)) {
56189
+ if (WORD_LIKE.test(segment)) {
56190
+ words += 1;
56191
+ }
56192
+ }
56193
+ return words;
56194
+ }
56083
56195
  function readingTime(text6) {
56084
- const words = text6.split(/\s+/).filter(Boolean).length;
56085
- return Math.max(1, Math.ceil(words / 200));
56196
+ return Math.max(1, Math.ceil(countWords(text6) / WORDS_PER_MINUTE));
56086
56197
  }
56087
56198
  function extractExcerpt(tree) {
56088
56199
  let firstParagraph = null;
@@ -56132,7 +56243,7 @@ function processMarkdown(source, filePath, config = {}) {
56132
56243
  $excerpt: excerpt,
56133
56244
  $readingTime: readingTime(plainText),
56134
56245
  $toc: toc,
56135
- $wordCount: plainText.split(/\s+/).filter(Boolean).length,
56246
+ $wordCount: countWords(plainText),
56136
56247
  frontmatter: frontmatter2,
56137
56248
  path: filePath,
56138
56249
  slug
@@ -56191,19 +56302,22 @@ class MarkdownCollection {
56191
56302
  return filtered;
56192
56303
  }
56193
56304
  }
56194
- var import_remark_parse_frontmatter2;
56305
+ var import_remark_parse_frontmatter2, WORDS_PER_MINUTE = 200, WORD_SEGMENTER, WORD_LIKE;
56195
56306
  var init_md = __esm(() => {
56196
56307
  init_unified();
56197
56308
  init_remark_parse();
56198
56309
  init_remark_frontmatter();
56199
56310
  init_remark_gfm();
56200
56311
  init_remark_directive();
56312
+ init_intl();
56201
56313
  init_index_min();
56202
56314
  init_transpile();
56203
56315
  init_highlight();
56204
56316
  init_markdown2();
56205
56317
  init_transpile();
56206
56318
  import_remark_parse_frontmatter2 = __toESM(require_dist2(), 1);
56319
+ WORD_SEGMENTER = new Intl.Segmenter(DEFAULT_FORMAT_LOCALE, { granularity: "word" });
56320
+ WORD_LIKE = /[\p{L}\p{N}]/u;
56207
56321
  });
56208
56322
 
56209
56323
  // src/markdown.ts
@@ -56233,7 +56347,7 @@ class Markdown {
56233
56347
  }
56234
56348
  static async load(path2, options = {}) {
56235
56349
  const { processMarkdown: processMarkdown2 } = await Promise.resolve().then(() => (init_md(), exports_md));
56236
- const { readFileSync: readFileSync2 } = await import("node:fs");
56350
+ const { readFileSync: readFileSync2, statSync } = await import("node:fs");
56237
56351
  const source = readFileSync2(path2, "utf8");
56238
56352
  const result = processMarkdown2(source, path2, {
56239
56353
  ...options.directives !== undefined && { directives: options.directives },
@@ -56243,6 +56357,9 @@ class Markdown {
56243
56357
  ...options.sourceRoot !== undefined && { sourceRoot: options.sourceRoot }
56244
56358
  });
56245
56359
  const _meta = {};
56360
+ try {
56361
+ _meta.mtime = statSync(path2).mtime.toISOString().replace(/\.\d{3}Z$/, "Z");
56362
+ } catch {}
56246
56363
  if (result.$excerpt != null) {
56247
56364
  _meta.excerpt = result.$excerpt;
56248
56365
  }
package/dist/serialize.js CHANGED
@@ -865,6 +865,22 @@ function isJsonObject(value) {
865
865
  function isRef(value) {
866
866
  return isJsonObject(value) && typeof value.$ref === "string";
867
867
  }
868
+ function isTagExpression(tagName) {
869
+ return isJsonObject(tagName) && isJsonObject(tagName.$expression);
870
+ }
871
+ function tagNameCandidates(tagName) {
872
+ if (typeof tagName === "string") {
873
+ return [tagName];
874
+ }
875
+ if (!isTagExpression(tagName)) {
876
+ return [];
877
+ }
878
+ const expression = tagName.$expression;
879
+ if (expression.operator === "?:") {
880
+ return [...new Set([expression.value, expression.initial])];
881
+ }
882
+ return [...new Set([...Object.values(expression.cases), expression.default])];
883
+ }
868
884
  var SCHEMA_KEYWORDS;
869
885
  var init_guards = __esm(() => {
870
886
  SCHEMA_KEYWORDS = new Set([
@@ -41982,7 +41998,7 @@ function transpileJxMarkdown(source) {
41982
41998
  return doc;
41983
41999
  }
41984
42000
  function slugifyHeading(text5) {
41985
- return text5.toLowerCase().replaceAll(/[^\w\s-]/g, "").replaceAll(/\s+/g, "-").replaceAll(/-+/g, "-").replaceAll(/^-|-$/g, "");
42001
+ return text5.normalize("NFC").toLowerCase().replaceAll(/[^\p{L}\p{N}_\s-]/gu, "").replaceAll(/\s+/gu, "-").replaceAll(/-+/g, "-").replaceAll(/^-|-$/g, "");
41986
42002
  }
41987
42003
  function jxNodeText(node2) {
41988
42004
  if (typeof node2 === "string") {
@@ -42004,7 +42020,7 @@ function assignHeadingIds(children) {
42004
42020
  if (typeof node2 !== "object" || node2 === null) {
42005
42021
  continue;
42006
42022
  }
42007
- const tag = node2.tagName;
42023
+ const tag = typeof node2.tagName === "string" ? node2.tagName : "";
42008
42024
  if (tag && HEADING_TAGS.has(tag)) {
42009
42025
  const text5 = jxNodeText(node2).trim();
42010
42026
  let id = typeof node2.id === "string" && node2.id.length > 0 ? node2.id : "";
@@ -42313,7 +42329,7 @@ function convertJxNode(el, isBlock, allowlist) {
42313
42329
  if (!el || typeof el !== "object") {
42314
42330
  return null;
42315
42331
  }
42316
- const tag = el.tagName ?? "div";
42332
+ const tag = serializableTag(el.tagName) || "div";
42317
42333
  if (!allowlist.has(tag) || hasJxProps(el)) {
42318
42334
  return convertToDirective(el, isBlock, allowlist);
42319
42335
  }
@@ -42442,6 +42458,15 @@ function convertJxNode(el, isBlock, allowlist) {
42442
42458
  }
42443
42459
  return null;
42444
42460
  }
42461
+ function serializableTag(tagName) {
42462
+ if (typeof tagName === "string") {
42463
+ return tagName;
42464
+ }
42465
+ if (tagName == null) {
42466
+ return "";
42467
+ }
42468
+ throw new Error(`Markdown cannot express a tag chosen at creation (candidates: ` + `${tagNameCandidates(tagName).join(", ")}). Keep this element in a JSON component.`);
42469
+ }
42445
42470
  function collectDirectiveAttrs(el) {
42446
42471
  const propsObj = {};
42447
42472
  for (const [key2, value2] of Object.entries(el)) {
@@ -42574,7 +42599,7 @@ function nodeToMdast(node2, ctx, scope) {
42574
42599
  if (node2.$prototype === "Array") {
42575
42600
  return expandArray(node2, ctx, scope);
42576
42601
  }
42577
- const tag = node2.tagName ?? "div";
42602
+ const tag = serializableTag(node2.tagName) || "div";
42578
42603
  const text5 = resolveText(node2.textContent, ctx, scope);
42579
42604
  if (typeof node2.innerHTML === "string" && node2.innerHTML.trim()) {
42580
42605
  const htmlNodes = htmlToMdast(node2.innerHTML);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jxsuite/parser",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Jx markdown parser and external class integration",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -48,10 +48,10 @@
48
48
  "upgrade": "bunx npm-check-updates -u && bun install"
49
49
  },
50
50
  "dependencies": {
51
- "@jxsuite/markup": "^0.4.1",
52
- "@jxsuite/schema": "^1.4.0",
53
- "@shikijs/langs": "^4.3.1",
54
- "@shikijs/themes": "^4.3.1",
51
+ "@jxsuite/markup": "^0.4.3",
52
+ "@jxsuite/schema": "^1.6.0",
53
+ "@shikijs/langs": "^4.4.3",
54
+ "@shikijs/themes": "^4.4.3",
55
55
  "glob": "^13.0.6",
56
56
  "mdast-util-to-string": "^4.0.0",
57
57
  "remark-directive": "^4.0.0",
@@ -60,14 +60,14 @@
60
60
  "remark-parse": "^11.0.0",
61
61
  "remark-parse-frontmatter": "^1.0.3",
62
62
  "remark-stringify": "^11.0.0",
63
- "shiki": "^4.3.1",
63
+ "shiki": "^4.4.3",
64
64
  "unified": "^11.0.5",
65
65
  "unist-util-visit": "^5.1.0",
66
66
  "yaml": "^2.9.0"
67
67
  },
68
68
  "devDependencies": {
69
- "@happy-dom/global-registrator": "^20.11.1",
70
- "@jxsuite/runtime": "^1.3.1",
69
+ "@happy-dom/global-registrator": "^20.11.2",
70
+ "@jxsuite/runtime": "^2.0.0",
71
71
  "@types/mdast": "^4.0.4",
72
72
  "ajv": "^8.20.0"
73
73
  },
@@ -9,7 +9,7 @@
9
9
 
10
10
  "format": {
11
11
  "extensions": [".md"],
12
- "mediaType": "text/markdown",
12
+ "mediaType": "text/markdown; variant=GFM",
13
13
  "documentKinds": ["page", "component", "content"],
14
14
  "exportTarget": true,
15
15
  "remote": false