@jxsuite/markup 0.4.11 → 0.4.13

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) 2026 Kevin Shenk
3
+ Copyright (c) 2026 Avunu LLC and Jx Suite contributors
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jxsuite/markup",
3
- "version": "0.4.11",
3
+ "version": "0.4.13",
4
4
  "description": "Browser-safe markup conversion: HTML → Jx nodes, markdown → sanitized HTML",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -26,7 +26,7 @@
26
26
  "upgrade": "bun update --latest && bun install"
27
27
  },
28
28
  "dependencies": {
29
- "@jxsuite/schema": "^2.3.0",
29
+ "@jxsuite/schema": "^4.0.0",
30
30
  "hast-util-from-html": "^2.0.3",
31
31
  "hast-util-whitespace": "^3.0.0",
32
32
  "property-information": "^7.2.0",
package/src/html-to-jx.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { fromHtml } from "hast-util-from-html";
2
2
  import { whitespace } from "hast-util-whitespace";
3
- import { find, html as htmlInfo } from "property-information";
3
+ import { find, html } from "property-information";
4
+ import { isString } from "@jxsuite/schema/guards";
4
5
 
5
- import type { Nodes as HastNode } from "hast";
6
+ import type { Properties, RootContent } from "hast";
6
7
  import type { JxElement } from "@jxsuite/schema/types";
7
8
 
8
9
  /**
@@ -13,14 +14,14 @@ import type { JxElement } from "@jxsuite/schema/types";
13
14
  */
14
15
  export function htmlToJx(htmlString: string) {
15
16
  const hast = fromHtml(htmlString, { fragment: true });
16
- return convertHastChildren(hast.children as HastNode[]);
17
+ return convertHastChildren(hast.children);
17
18
  }
18
19
 
19
20
  /**
20
- * @param {HastNode[]} children
21
+ * @param {RootContent[]} children
21
22
  * @returns {(JxElement | string)[]}
22
23
  */
23
- function convertHastChildren(children: HastNode[]) {
24
+ function convertHastChildren(children: RootContent[]) {
24
25
  const result: (JxElement | string)[] = [];
25
26
  for (const child of children) {
26
27
  const converted = convertHastNode(child);
@@ -32,21 +33,21 @@ function convertHastChildren(children: HastNode[]) {
32
33
  }
33
34
 
34
35
  /**
35
- * @param {HastNode} node
36
+ * @param {RootContent} node
36
37
  * @returns {JxElement | string | null}
37
38
  */
38
- function convertHastNode(node: HastNode) {
39
+ function convertHastNode(node: RootContent) {
39
40
  if (node.type === "text") {
40
- if (whitespace(node as Parameters<typeof whitespace>[0])) {
41
+ if (whitespace(node)) {
41
42
  return null;
42
43
  }
43
- return node.value ?? null;
44
+ return node.value;
44
45
  }
45
46
 
46
47
  if (node.type === "element") {
47
48
  const el: JxElement = { tagName: node.tagName };
48
49
 
49
- if (node.properties && Object.keys(node.properties).length > 0) {
50
+ if (Object.keys(node.properties).length > 0) {
50
51
  const { style, attrs } = hastPropsToJx(node.properties);
51
52
  if (Object.keys(attrs).length > 0) {
52
53
  el.attributes = attrs;
@@ -56,12 +57,12 @@ function convertHastNode(node: HastNode) {
56
57
  }
57
58
  }
58
59
 
59
- const kids = node.children ? convertHastChildren(node.children) : [];
60
+ const kids = convertHastChildren(node.children);
60
61
 
61
- if (kids.length === 1 && typeof kids[0] === "string") {
62
+ if (kids.length === 1 && isString(kids[0])) {
62
63
  [el.textContent] = kids;
63
64
  } else if (kids.length > 0) {
64
- el.children = kids as JxElement[];
65
+ el.children = kids;
65
66
  }
66
67
 
67
68
  return el;
@@ -71,10 +72,10 @@ function convertHastNode(node: HastNode) {
71
72
  }
72
73
 
73
74
  /**
74
- * @param {Record<string, unknown>} properties
75
+ * @param {Properties} properties
75
76
  * @returns {{ style: Record<string, string>; attrs: Record<string, string> }}
76
77
  */
77
- function hastPropsToJx(properties: Record<string, unknown>) {
78
+ function hastPropsToJx(properties: Properties) {
78
79
  const attrs: Record<string, string> = {};
79
80
  const style: Record<string, string> = {};
80
81
 
@@ -83,10 +84,10 @@ function hastPropsToJx(properties: Record<string, unknown>) {
83
84
  continue;
84
85
  }
85
86
 
86
- const info = find(htmlInfo, key);
87
+ const info = find(html, key);
87
88
  const name = info.attribute;
88
89
 
89
- if (name === "style" && typeof value === "string") {
90
+ if (name === "style" && isString(value)) {
90
91
  parseInlineStyle(value, style);
91
92
  continue;
92
93
  }
package/src/md-html.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Md-html — browser-safe markdown → sanitized HTML string
3
3
  *
4
- * Small display pipeline for rendering untrusted markdown (e.g. LLM chat output) as
5
- * HTML: remark-parse + remark-gfm → remark-rehype (raw HTML disabled) → rehype-sanitize
6
- * (default schema: strips scripts, event handlers, javascript:/data: URLs) → stringify.
4
+ * Small display pipeline for rendering untrusted markdown (e.g. LLM chat output) as HTML:
5
+ * remark-parse + remark-gfm → remark-rehype (raw HTML disabled) → rehype-sanitize (default schema:
6
+ * strips scripts, event handlers, javascript:/data: URLs) → stringify.
7
7
  *
8
- * Like everything in @jxsuite/markup this module has no node-only imports, so it is safe
9
- * for the studio bundle. It intentionally produces an HTML *string*, not Jx nodes — use
8
+ * Like everything in @jxsuite/markup this module has no node-only imports, so it is safe for the
9
+ * studio bundle. It intentionally produces an HTML _string_, not Jx nodes — use
10
10
  * `@jxsuite/parser/markdown` for markdown → Jx document transpilation.
11
11
  *
12
12
  * @module @jxsuite/markup/md-html
@@ -20,22 +20,35 @@ import remarkParse from "remark-parse";
20
20
  import remarkRehype from "remark-rehype";
21
21
  import { unified } from "unified";
22
22
 
23
+ /**
24
+ * A unified attacher: called with `this` bound to the processor and the plugin's optional settings.
25
+ * Its result (a parser, compiler or transformer) is consumed by unified, never by us.
26
+ */
27
+ type UnifiedPlugin = (...settings: never[]) => void;
28
+
23
29
  /**
24
30
  * Minimal structural surface of the unified processor used here — same rationale as
25
31
  * `UnifiedProcessor` in @jxsuite/parser's types (oxlint sees the ESM-only unified types as `any`),
26
32
  * plus `processSync` which that shared type doesn't carry.
27
33
  */
28
34
  interface MdHtmlProcessor {
29
- use: (plugin: unknown, ...options: unknown[]) => MdHtmlProcessor;
35
+ use: (plugin: UnifiedPlugin) => MdHtmlProcessor;
30
36
  processSync: (source: string) => { toString: () => string };
31
37
  }
32
38
 
33
- const processor = (unified as unknown as () => MdHtmlProcessor)()
34
- .use(remarkParse)
39
+ /* SAFETY: `unified`, `remark-parse`, `remark-rehype` and `rehype-stringify` are shorthand
40
+ `declare module` entries in the root types.d.ts, so their imports are `any` here. unified@11
41
+ exports `unified` as a callable Processor whose call returns a fresh Processor; that Processor's
42
+ `use(plugin)` returns itself and `processSync(string)` returns a VFile whose toString() yields
43
+ the compiled HTML, which is exactly the MdHtmlProcessor surface. Each of the three plugin
44
+ packages default-exports a unified attacher function taking optional settings, which is the
45
+ UnifiedPlugin shape. */
46
+ const processor = (unified as () => MdHtmlProcessor)()
47
+ .use(remarkParse as UnifiedPlugin)
35
48
  .use(remarkGfm)
36
- .use(remarkRehype)
49
+ .use(remarkRehype as UnifiedPlugin)
37
50
  .use(rehypeSanitize)
38
- .use(rehypeStringify);
51
+ .use(rehypeStringify as UnifiedPlugin);
39
52
 
40
53
  /**
41
54
  * Convert markdown source to a sanitized HTML string (GFM tables/strikethrough/task lists