lake-html 1.0.0 → 2.1.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/README.md CHANGED
@@ -52,19 +52,19 @@ console.log(html);
52
52
 
53
53
  ## Customization
54
54
 
55
- You can customize how specific boxes are rendered or add support for new box types by passing a `rules` object as the second argument.
55
+ You can customize how specific boxes are rendered or add support for new box types by passing a `renderers` object as the second argument.
56
56
 
57
57
  ### Overriding an existing renderer
58
58
 
59
59
  For example, if you want to wrap all images in a `<figure>` tag:
60
60
 
61
61
  ```js
62
- import { toHTML, getDefaultBoxRenderers } from 'lake-html';
62
+ import { toHTML, getBoxRenderers } from 'lake-html';
63
63
 
64
- const rules = getDefaultBoxRenderers();
64
+ const renderers = getBoxRenderers();
65
65
 
66
66
  // Override the 'image' renderer
67
- rules.image = (boxValue, encode) => {
67
+ renderers.image = (boxValue, encode) => {
68
68
  return {
69
69
  tagName: 'figure',
70
70
  attributes: { class: 'custom-image' },
@@ -72,38 +72,38 @@ rules.image = (boxValue, encode) => {
72
72
  };
73
73
  };
74
74
 
75
- const html = toHTML(content, rules);
75
+ const html = toHTML(content, renderers);
76
76
  ```
77
77
 
78
78
  ### Adding a new box type
79
79
 
80
80
  ```js
81
- import { toHTML, getDefaultBoxRenderers } from 'lake-html';
81
+ import { toHTML, getBoxRenderers } from 'lake-html';
82
82
 
83
- const rules = getDefaultBoxRenderers();
83
+ const renderers = getBoxRenderers();
84
84
 
85
85
  // Add a custom 'card' box
86
- rules.card = (boxValue, encode) => {
86
+ renderers.card = (boxValue, encode) => {
87
87
  return `<div class="card">
88
88
  <h3>${encode(boxValue.title)}</h3>
89
89
  <p>${encode(boxValue.summary)}</p>
90
90
  </div>`;
91
91
  };
92
92
 
93
- const html = toHTML(content, rules);
93
+ const html = toHTML(content, renderers);
94
94
  ```
95
95
 
96
96
  ## API Reference
97
97
 
98
- ### toHTML(value: string, rules?: BoxRenderers): string
98
+ ### toHTML(value: string, renderers?: BoxRenderers): string
99
99
 
100
100
  The main conversion function.
101
101
 
102
102
  * `value`: The input LML string.
103
103
 
104
- * `rules`: (Optional) An object to override default renderers.
104
+ * `renderers`: (Optional) An object to override default renderers.
105
105
 
106
- ### getDefaultBoxRenderers()
106
+ ### getBoxRenderers()
107
107
 
108
108
  Returns the default map of box renderers. Useful when you want to extend the defaults rather than replace them entirely.
109
109
 
package/dist/index.d.mts CHANGED
@@ -1,21 +1,21 @@
1
1
  type AttributeMap = Record<string, string>;
2
- interface BoxNode {
2
+ interface BoxHTMLNode {
3
3
  tagName: string;
4
4
  attributes?: AttributeMap;
5
5
  isVoid?: boolean;
6
6
  innerHTML?: string;
7
7
  }
8
- type EntityEncoder = (value: string) => string;
9
- type BoxRenderer = (boxValue: AttributeMap, encode: EntityEncoder) => BoxNode | string;
10
- type BoxRenderers = Record<string, BoxRenderer>;
8
+ type EncodeHTMLEntities = (value: string) => string;
9
+ type RenderBox = (boxValue: AttributeMap, encode: EncodeHTMLEntities) => BoxHTMLNode;
10
+ type BoxRenderers = Record<string, RenderBox>;
11
11
  /**
12
12
  * Returns the default configuration for rendering various Lake attributes.
13
13
  */
14
- declare function getDefaultBoxRenderers(): BoxRenderers;
14
+ declare function getBoxRenderers(): BoxRenderers;
15
15
  /**
16
16
  * Main function to convert Lake Markup Language (LML) to standard HTML.
17
17
  * It processes custom <lake-box> tags and removes internal anchors.
18
18
  */
19
- declare function toHTML(value: string, rules?: BoxRenderers): string;
19
+ declare function toHTML(value: string, renderers?: BoxRenderers): string;
20
20
 
21
- export { getDefaultBoxRenderers, toHTML };
21
+ export { getBoxRenderers, toHTML };
package/dist/index.d.ts CHANGED
@@ -1,21 +1,21 @@
1
1
  type AttributeMap = Record<string, string>;
2
- interface BoxNode {
2
+ interface BoxHTMLNode {
3
3
  tagName: string;
4
4
  attributes?: AttributeMap;
5
5
  isVoid?: boolean;
6
6
  innerHTML?: string;
7
7
  }
8
- type EntityEncoder = (value: string) => string;
9
- type BoxRenderer = (boxValue: AttributeMap, encode: EntityEncoder) => BoxNode | string;
10
- type BoxRenderers = Record<string, BoxRenderer>;
8
+ type EncodeHTMLEntities = (value: string) => string;
9
+ type RenderBox = (boxValue: AttributeMap, encode: EncodeHTMLEntities) => BoxHTMLNode;
10
+ type BoxRenderers = Record<string, RenderBox>;
11
11
  /**
12
12
  * Returns the default configuration for rendering various Lake attributes.
13
13
  */
14
- declare function getDefaultBoxRenderers(): BoxRenderers;
14
+ declare function getBoxRenderers(): BoxRenderers;
15
15
  /**
16
16
  * Main function to convert Lake Markup Language (LML) to standard HTML.
17
17
  * It processes custom <lake-box> tags and removes internal anchors.
18
18
  */
19
- declare function toHTML(value: string, rules?: BoxRenderers): string;
19
+ declare function toHTML(value: string, renderers?: BoxRenderers): string;
20
20
 
21
- export { getDefaultBoxRenderers, toHTML };
21
+ export { getBoxRenderers, toHTML };
package/dist/index.js CHANGED
@@ -37,7 +37,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
37
37
  // src/index.ts
38
38
  var index_exports = {};
39
39
  __export(index_exports, {
40
- getDefaultBoxRenderers: () => getDefaultBoxRenderers,
40
+ getBoxRenderers: () => getBoxRenderers,
41
41
  toHTML: () => toHTML
42
42
  });
43
43
  module.exports = __toCommonJS(index_exports);
@@ -45,9 +45,15 @@ function extractIdFromUrl(url) {
45
45
  const result = /[\w\-]+$/.exec(url);
46
46
  return result ? result[0] : "";
47
47
  }
48
- function getDefaultBoxRenderers() {
48
+ function getBoxRenderers() {
49
49
  return {
50
- hr: () => '<div class="lake-box-block lake-hr"><hr /></div>',
50
+ hr: () => ({
51
+ tagName: "div",
52
+ attributes: {
53
+ class: "lake-box-block lake-hr"
54
+ },
55
+ innerHTML: "<hr />"
56
+ }),
51
57
  image: (boxValue) => ({
52
58
  tagName: "img",
53
59
  attributes: __spreadProps(__spreadValues(__spreadValues(__spreadValues({
@@ -57,6 +63,14 @@ function getDefaultBoxRenderers() {
57
63
  }),
58
64
  isVoid: true
59
65
  }),
66
+ media: (boxValue) => ({
67
+ tagName: "video",
68
+ attributes: __spreadProps(__spreadValues(__spreadValues({
69
+ src: boxValue.url
70
+ }, boxValue.width && { width: boxValue.width.replace(/px$/i, "") }), boxValue.height && { height: boxValue.height.replace(/px$/i, "") }), {
71
+ controls: "true"
72
+ })
73
+ }),
60
74
  file: (boxValue, encode) => ({
61
75
  tagName: "a",
62
76
  attributes: {
@@ -86,15 +100,27 @@ function getDefaultBoxRenderers() {
86
100
  tagName: "code",
87
101
  innerHTML: boxValue.code
88
102
  }),
103
+ mention: (boxValue, encode) => {
104
+ var _a;
105
+ return {
106
+ tagName: "a",
107
+ attributes: {
108
+ href: `/${boxValue.name}`,
109
+ target: "_blank"
110
+ },
111
+ innerHTML: encode((_a = boxValue.nickname) != null ? _a : boxValue.name)
112
+ };
113
+ },
89
114
  video: (boxValue) => ({
90
115
  tagName: "iframe",
91
116
  attributes: __spreadProps(__spreadValues({}, boxValue.url && { src: `https://www.youtube.com/embed/${extractIdFromUrl(boxValue.url)}` }), {
117
+ width: boxValue.width ? boxValue.width.replace(/px$/i, "") : "560",
118
+ height: boxValue.height ? boxValue.height.replace(/px$/i, "") : "315",
92
119
  title: "YouTube video player",
93
120
  frameborder: "0",
94
121
  allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",
95
122
  referrerpolicy: "strict-origin-when-cross-origin",
96
- allowfullscreen: "true",
97
- style: "width: 560px; height: 315px;"
123
+ allowfullscreen: "true"
98
124
  })
99
125
  }),
100
126
  twitter: (boxValue) => ({
@@ -148,31 +174,31 @@ function serializeAttributes(attrs) {
148
174
  }
149
175
  return result.join(" ");
150
176
  }
151
- function toHTML(value, rules) {
152
- const config = rules != null ? rules : getDefaultBoxRenderers();
177
+ function toBoxHTML(node) {
178
+ var _a;
179
+ let result = `<${node.tagName}`;
180
+ if (node.attributes) {
181
+ result += ` ${serializeAttributes(node.attributes)}`;
182
+ }
183
+ if (node.isVoid === true) {
184
+ result += " />";
185
+ } else {
186
+ result += `>${(_a = node.innerHTML) != null ? _a : ""}</${node.tagName}>`;
187
+ }
188
+ return result;
189
+ }
190
+ function toHTML(value, renderers) {
191
+ renderers = renderers != null ? renderers : getBoxRenderers();
153
192
  const combinedRegex = /(<lake-box[^>]+>)[\s\S]*?(?:<\/lake-box>|$)|(<anchor\s*\/>)|(<focus\s*\/>)/gi;
154
193
  return value.replace(combinedRegex, (match, boxOpen) => {
155
- var _a;
156
194
  if (boxOpen) {
157
195
  const attributes = parseAttributes(boxOpen);
158
- const render = config[attributes.name];
196
+ const render = renderers[attributes.name];
159
197
  if (render) {
160
198
  try {
161
- const decodedValue = attributes.value ? JSON.parse(decodeBase64(attributes.value)) : {};
162
- const result = render(decodedValue, encodeHTMLEntities);
163
- if (typeof result === "string") {
164
- return result;
165
- }
166
- let html = `<${result.tagName}`;
167
- if (result.attributes) {
168
- html += ` ${serializeAttributes(result.attributes)}`;
169
- }
170
- if (result.isVoid === true) {
171
- html += " />";
172
- } else {
173
- html += `>${(_a = result.innerHTML) != null ? _a : ""}</${result.tagName}>`;
174
- }
175
- return html;
199
+ const boxValue = attributes.value ? JSON.parse(decodeBase64(attributes.value)) : {};
200
+ const node = render(boxValue, encodeHTMLEntities);
201
+ return toBoxHTML(node);
176
202
  } catch (e) {
177
203
  console.error("Failed to parse lake-box value:", e);
178
204
  }
@@ -183,7 +209,7 @@ function toHTML(value, rules) {
183
209
  }
184
210
  // Annotate the CommonJS export names for ESM import in node:
185
211
  0 && (module.exports = {
186
- getDefaultBoxRenderers,
212
+ getBoxRenderers,
187
213
  toHTML
188
214
  });
189
215
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Define a generic type for HTML attributes (key-value pairs)\ntype AttributeMap = Record<string, string>;\n\n// Structure representing the output HTML node\ninterface BoxNode {\n tagName: string;\n attributes?: AttributeMap;\n isVoid?: boolean; // True for self-closing tags like <img />, <hr />\n innerHTML?: string;\n}\n\n// Function signature for encoding HTML entities\ntype EntityEncoder = (value: string) => string;\n\n// Function signature for encoding HTML entities\ntype BoxRenderer = (boxValue: AttributeMap, encode: EntityEncoder) => BoxNode | string;\n\n// Registry of renderers for different box types\ntype BoxRenderers = Record<string, BoxRenderer>;\n\n/**\n * Extracts the ID from a URL.\n * Useful for extracting YouTube or Twitter IDs from clean URLs.\n */\nfunction extractIdFromUrl(url: string): string {\n const result = /[\\w\\-]+$/.exec(url);\n return result ? result[0] : '';\n}\n\n/**\n * Returns the default configuration for rendering various Lake attributes.\n */\nexport function getDefaultBoxRenderers(): BoxRenderers {\n return {\n hr: () => '<div class=\"lake-box-block lake-hr\"><hr /></div>',\n\n image: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n ...(boxValue.width && { width: boxValue.width }),\n ...(boxValue.height && { height: boxValue.height }),\n ...(boxValue.caption && { alt: boxValue.caption }),\n border: '0',\n },\n isVoid: true,\n }),\n\n file: (boxValue, encode) => ({\n tagName: 'a',\n attributes: {\n href: boxValue.url,\n target: '_blank',\n },\n innerHTML: encode(boxValue.name),\n }),\n\n codeBlock: (boxValue, encode) => ({\n tagName: 'pre',\n attributes: {\n class: `lang-${boxValue.lang}`,\n },\n innerHTML: `<code>${encode(boxValue.code)}</code>`,\n }),\n\n emoji: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n width: '32',\n height: '32',\n border: '0',\n },\n isVoid: true,\n }),\n\n equation: boxValue => ({\n tagName: 'code',\n innerHTML: boxValue.code,\n }),\n\n video: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://www.youtube.com/embed/${extractIdFromUrl(boxValue.url)}` }),\n title: 'YouTube video player',\n frameborder: '0',\n allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',\n referrerpolicy: 'strict-origin-when-cross-origin',\n allowfullscreen: 'true',\n style: 'width: 560px; height: 315px;',\n },\n }),\n\n twitter: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://platform.twitter.com/embed/Tweet.html?id=${extractIdFromUrl(boxValue.url)}` }),\n title: 'Twitter tweet',\n scrolling: 'no',\n frameborder: '0',\n allowtransparency: 'true',\n allowfullscreen: 'true',\n style: 'width: 550px; height: 300px;',\n },\n }),\n };\n}\n\n// Map for reserved HTML characters\nconst htmlEntityMap = new Map([\n ['&', '&amp;'],\n ['<', '&lt;'],\n ['>', '&gt;'],\n ['\"', '&quot;'],\n ['\\xA0', '&nbsp;'],\n]);\n\n/**\n * Escapes reserved HTML characters to prevent XSS and rendering issues.\n */\nfunction encodeHTMLEntities(value: string): string {\n return value.replace(/[&<>\"\\xA0]/g, match => htmlEntityMap.get(match)!);\n}\n\n/**\n * Decodes a Base64 encoded string with UTF-8 support.\n */\nfunction decodeBase64(value: string): string {\n const binaryString = atob(value);\n const byteArray = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n byteArray[i] = binaryString.charCodeAt(i);\n }\n const decoder = new TextDecoder();\n return decoder.decode(byteArray);\n}\n\n/**\n * Parses HTML tag attributes from a string into a key-value object.\n */\nfunction parseAttributes(tag: string): AttributeMap {\n const attributes: AttributeMap = {};\n // Regex breakdown:\n // Group 1/2: Key=Value (unquoted)\n // Group 3/4: Key=\"Value\" (double quoted)\n // Group 5/6: Key='Value' (single quoted)\n const reg = /\\s+(?:([\\w\\-:]+)=([^\\s\"'<>]+)|([\\w\\-:\"]+)=\"([^\"]*)\"|([\\w\\-:\"]+)='([^']*)')(?=[\\s/>])/g;\n let match: RegExpExecArray | null;\n while ((match = reg.exec(tag))) {\n const key = (match[1] || match[3] || match[5]).toLowerCase();\n const value = match[1] ? match[2] : (match[3] ? match[4] : match[6]);\n attributes[key] = value;\n }\n return attributes;\n}\n\n/**\n * Serializes an attribute map into an HTML attribute string.\n */\nfunction serializeAttributes(attrs: AttributeMap): string {\n const result: string[] = [];\n for (const key of Object.keys(attrs)) {\n const value = String(attrs[key]);\n result.push(`${key}=\"${encodeHTMLEntities(value)}\"`);\n }\n return result.join(' ');\n}\n\n/**\n * Main function to convert Lake Markup Language (LML) to standard HTML.\n * It processes custom <lake-box> tags and removes internal anchors.\n */\nexport function toHTML(value: string, rules?: BoxRenderers): string {\n const config = rules ?? getDefaultBoxRenderers();\n // Regex to match <lake-box>, <anchor>, and <focus> tags\n const combinedRegex = /(<lake-box[^>]+>)[\\s\\S]*?(?:<\\/lake-box>|$)|(<anchor\\s*\\/>)|(<focus\\s*\\/>)/gi;\n return value.replace(combinedRegex, (match, boxOpen) => {\n // Handle lake-box conversion\n if (boxOpen) {\n const attributes = parseAttributes(boxOpen);\n const render = config[attributes.name];\n if (render) {\n try {\n const decodedValue = attributes.value ? JSON.parse(decodeBase64(attributes.value)) : {};\n const result = render(decodedValue, encodeHTMLEntities);\n // If renderer returns a raw string, return it directly\n if (typeof result === 'string') {\n return result;\n }\n // Otherwise, build the HTML tag from BoxNode\n let html = `<${result.tagName}`;\n if (result.attributes) {\n html += ` ${serializeAttributes(result.attributes)}`;\n }\n if (result.isVoid === true) {\n html += ' />';\n } else {\n html += `>${result.innerHTML ?? ''}</${result.tagName}>`;\n }\n return html;\n } catch (e) {\n console.error('Failed to parse lake-box value:', e);\n }\n }\n }\n // Remove internal selection markers (<anchor /> and <focus />)\n return '';\n });\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Define a generic type for HTML attributes (key-value pairs)\ntype AttributeMap = Record<string, string>;\n\n// Structure representing the output HTML node\ninterface BoxHTMLNode {\n tagName: string;\n attributes?: AttributeMap;\n isVoid?: boolean; // True for self-closing tags like <img />, <hr />\n innerHTML?: string;\n}\n\n// Function signature for encoding HTML entities\ntype EncodeHTMLEntities = (value: string) => string;\n\n// Function signature for encoding HTML entities\ntype RenderBox = (boxValue: AttributeMap, encode: EncodeHTMLEntities) => BoxHTMLNode;\n\n// Registry of renderers for different box types\ntype BoxRenderers = Record<string, RenderBox>;\n\n/**\n * Extracts the ID from a URL.\n * Useful for extracting YouTube or Twitter IDs from clean URLs.\n */\nfunction extractIdFromUrl(url: string): string {\n const result = /[\\w\\-]+$/.exec(url);\n return result ? result[0] : '';\n}\n\n/**\n * Returns the default configuration for rendering various Lake attributes.\n */\nexport function getBoxRenderers(): BoxRenderers {\n return {\n hr: () => ({\n tagName: 'div',\n attributes: {\n class: 'lake-box-block lake-hr',\n },\n innerHTML: '<hr />',\n }),\n\n image: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n ...(boxValue.width && { width: boxValue.width }),\n ...(boxValue.height && { height: boxValue.height }),\n ...(boxValue.caption && { alt: boxValue.caption }),\n border: '0',\n },\n isVoid: true,\n }),\n\n media: boxValue => ({\n tagName: 'video',\n attributes: {\n src: boxValue.url,\n ...(boxValue.width && { width: boxValue.width.replace(/px$/i, '') }),\n ...(boxValue.height && { height: boxValue.height.replace(/px$/i, '') }),\n controls: 'true',\n },\n }),\n\n file: (boxValue, encode) => ({\n tagName: 'a',\n attributes: {\n href: boxValue.url,\n target: '_blank',\n },\n innerHTML: encode(boxValue.name),\n }),\n\n codeBlock: (boxValue, encode) => ({\n tagName: 'pre',\n attributes: {\n class: `lang-${boxValue.lang}`,\n },\n innerHTML: `<code>${encode(boxValue.code)}</code>`,\n }),\n\n emoji: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n width: '32',\n height: '32',\n border: '0',\n },\n isVoid: true,\n }),\n\n equation: boxValue => ({\n tagName: 'code',\n innerHTML: boxValue.code,\n }),\n\n mention: (boxValue, encode) => ({\n tagName: 'a',\n attributes: {\n href: `/${boxValue.name}`,\n target: '_blank',\n },\n innerHTML: encode(boxValue.nickname ?? boxValue.name),\n }),\n\n video: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://www.youtube.com/embed/${extractIdFromUrl(boxValue.url)}` }),\n width: boxValue.width ? boxValue.width.replace(/px$/i, '') : '560',\n height: boxValue.height ? boxValue.height.replace(/px$/i, '') : '315',\n title: 'YouTube video player',\n frameborder: '0',\n allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',\n referrerpolicy: 'strict-origin-when-cross-origin',\n allowfullscreen: 'true',\n },\n }),\n\n twitter: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://platform.twitter.com/embed/Tweet.html?id=${extractIdFromUrl(boxValue.url)}` }),\n title: 'Twitter tweet',\n scrolling: 'no',\n frameborder: '0',\n allowtransparency: 'true',\n allowfullscreen: 'true',\n style: 'width: 550px; height: 300px;',\n },\n }),\n };\n}\n\n// Map for reserved HTML characters\nconst htmlEntityMap = new Map([\n ['&', '&amp;'],\n ['<', '&lt;'],\n ['>', '&gt;'],\n ['\"', '&quot;'],\n ['\\xA0', '&nbsp;'],\n]);\n\n/**\n * Escapes reserved HTML characters to prevent XSS and rendering issues.\n */\nfunction encodeHTMLEntities(value: string): string {\n return value.replace(/[&<>\"\\xA0]/g, match => htmlEntityMap.get(match)!);\n}\n\n/**\n * Decodes a Base64 encoded string with UTF-8 support.\n */\nfunction decodeBase64(value: string): string {\n const binaryString = atob(value);\n const byteArray = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n byteArray[i] = binaryString.charCodeAt(i);\n }\n const decoder = new TextDecoder();\n return decoder.decode(byteArray);\n}\n\n/**\n * Parses HTML tag attributes from a string into a key-value object.\n */\nfunction parseAttributes(tag: string): AttributeMap {\n const attributes: AttributeMap = {};\n // Regex breakdown:\n // Group 1/2: Key=Value (unquoted)\n // Group 3/4: Key=\"Value\" (double quoted)\n // Group 5/6: Key='Value' (single quoted)\n const reg = /\\s+(?:([\\w\\-:]+)=([^\\s\"'<>]+)|([\\w\\-:\"]+)=\"([^\"]*)\"|([\\w\\-:\"]+)='([^']*)')(?=[\\s/>])/g;\n let match: RegExpExecArray | null;\n while ((match = reg.exec(tag))) {\n const key = (match[1] || match[3] || match[5]).toLowerCase();\n const value = match[1] ? match[2] : (match[3] ? match[4] : match[6]);\n attributes[key] = value;\n }\n return attributes;\n}\n\n/**\n * Serializes an attribute map into an HTML attribute string.\n */\nfunction serializeAttributes(attrs: AttributeMap): string {\n const result: string[] = [];\n for (const key of Object.keys(attrs)) {\n const value = String(attrs[key]);\n result.push(`${key}=\"${encodeHTMLEntities(value)}\"`);\n }\n return result.join(' ');\n}\n\n/**\n * Serializes a BoxHTMLNode object into a standard HTML string.\n */\nfunction toBoxHTML(node: BoxHTMLNode): string {\n let result = `<${node.tagName}`;\n if (node.attributes) {\n result += ` ${serializeAttributes(node.attributes)}`;\n }\n if (node.isVoid === true) {\n result += ' />';\n } else {\n result += `>${node.innerHTML ?? ''}</${node.tagName}>`;\n }\n return result;\n}\n\n/**\n * Main function to convert Lake Markup Language (LML) to standard HTML.\n * It processes custom <lake-box> tags and removes internal anchors.\n */\nexport function toHTML(value: string, renderers?: BoxRenderers): string {\n renderers = renderers ?? getBoxRenderers();\n // Regex to match <lake-box>, <anchor>, and <focus> tags\n const combinedRegex = /(<lake-box[^>]+>)[\\s\\S]*?(?:<\\/lake-box>|$)|(<anchor\\s*\\/>)|(<focus\\s*\\/>)/gi;\n return value.replace(combinedRegex, (match, boxOpen) => {\n // Handle lake-box conversion\n if (boxOpen) {\n const attributes = parseAttributes(boxOpen);\n const render = renderers[attributes.name];\n if (render) {\n try {\n const boxValue = attributes.value ? JSON.parse(decodeBase64(attributes.value)) : {};\n const node = render(boxValue, encodeHTMLEntities);\n return toBoxHTML(node);\n } catch (e) {\n console.error('Failed to parse lake-box value:', e);\n }\n }\n }\n // Remove internal selection markers (<anchor /> and <focus />)\n return '';\n });\n}\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -23,9 +23,15 @@ function extractIdFromUrl(url) {
23
23
  const result = /[\w\-]+$/.exec(url);
24
24
  return result ? result[0] : "";
25
25
  }
26
- function getDefaultBoxRenderers() {
26
+ function getBoxRenderers() {
27
27
  return {
28
- hr: () => '<div class="lake-box-block lake-hr"><hr /></div>',
28
+ hr: () => ({
29
+ tagName: "div",
30
+ attributes: {
31
+ class: "lake-box-block lake-hr"
32
+ },
33
+ innerHTML: "<hr />"
34
+ }),
29
35
  image: (boxValue) => ({
30
36
  tagName: "img",
31
37
  attributes: __spreadProps(__spreadValues(__spreadValues(__spreadValues({
@@ -35,6 +41,14 @@ function getDefaultBoxRenderers() {
35
41
  }),
36
42
  isVoid: true
37
43
  }),
44
+ media: (boxValue) => ({
45
+ tagName: "video",
46
+ attributes: __spreadProps(__spreadValues(__spreadValues({
47
+ src: boxValue.url
48
+ }, boxValue.width && { width: boxValue.width.replace(/px$/i, "") }), boxValue.height && { height: boxValue.height.replace(/px$/i, "") }), {
49
+ controls: "true"
50
+ })
51
+ }),
38
52
  file: (boxValue, encode) => ({
39
53
  tagName: "a",
40
54
  attributes: {
@@ -64,15 +78,27 @@ function getDefaultBoxRenderers() {
64
78
  tagName: "code",
65
79
  innerHTML: boxValue.code
66
80
  }),
81
+ mention: (boxValue, encode) => {
82
+ var _a;
83
+ return {
84
+ tagName: "a",
85
+ attributes: {
86
+ href: `/${boxValue.name}`,
87
+ target: "_blank"
88
+ },
89
+ innerHTML: encode((_a = boxValue.nickname) != null ? _a : boxValue.name)
90
+ };
91
+ },
67
92
  video: (boxValue) => ({
68
93
  tagName: "iframe",
69
94
  attributes: __spreadProps(__spreadValues({}, boxValue.url && { src: `https://www.youtube.com/embed/${extractIdFromUrl(boxValue.url)}` }), {
95
+ width: boxValue.width ? boxValue.width.replace(/px$/i, "") : "560",
96
+ height: boxValue.height ? boxValue.height.replace(/px$/i, "") : "315",
70
97
  title: "YouTube video player",
71
98
  frameborder: "0",
72
99
  allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",
73
100
  referrerpolicy: "strict-origin-when-cross-origin",
74
- allowfullscreen: "true",
75
- style: "width: 560px; height: 315px;"
101
+ allowfullscreen: "true"
76
102
  })
77
103
  }),
78
104
  twitter: (boxValue) => ({
@@ -126,31 +152,31 @@ function serializeAttributes(attrs) {
126
152
  }
127
153
  return result.join(" ");
128
154
  }
129
- function toHTML(value, rules) {
130
- const config = rules != null ? rules : getDefaultBoxRenderers();
155
+ function toBoxHTML(node) {
156
+ var _a;
157
+ let result = `<${node.tagName}`;
158
+ if (node.attributes) {
159
+ result += ` ${serializeAttributes(node.attributes)}`;
160
+ }
161
+ if (node.isVoid === true) {
162
+ result += " />";
163
+ } else {
164
+ result += `>${(_a = node.innerHTML) != null ? _a : ""}</${node.tagName}>`;
165
+ }
166
+ return result;
167
+ }
168
+ function toHTML(value, renderers) {
169
+ renderers = renderers != null ? renderers : getBoxRenderers();
131
170
  const combinedRegex = /(<lake-box[^>]+>)[\s\S]*?(?:<\/lake-box>|$)|(<anchor\s*\/>)|(<focus\s*\/>)/gi;
132
171
  return value.replace(combinedRegex, (match, boxOpen) => {
133
- var _a;
134
172
  if (boxOpen) {
135
173
  const attributes = parseAttributes(boxOpen);
136
- const render = config[attributes.name];
174
+ const render = renderers[attributes.name];
137
175
  if (render) {
138
176
  try {
139
- const decodedValue = attributes.value ? JSON.parse(decodeBase64(attributes.value)) : {};
140
- const result = render(decodedValue, encodeHTMLEntities);
141
- if (typeof result === "string") {
142
- return result;
143
- }
144
- let html = `<${result.tagName}`;
145
- if (result.attributes) {
146
- html += ` ${serializeAttributes(result.attributes)}`;
147
- }
148
- if (result.isVoid === true) {
149
- html += " />";
150
- } else {
151
- html += `>${(_a = result.innerHTML) != null ? _a : ""}</${result.tagName}>`;
152
- }
153
- return html;
177
+ const boxValue = attributes.value ? JSON.parse(decodeBase64(attributes.value)) : {};
178
+ const node = render(boxValue, encodeHTMLEntities);
179
+ return toBoxHTML(node);
154
180
  } catch (e) {
155
181
  console.error("Failed to parse lake-box value:", e);
156
182
  }
@@ -160,7 +186,7 @@ function toHTML(value, rules) {
160
186
  });
161
187
  }
162
188
  export {
163
- getDefaultBoxRenderers,
189
+ getBoxRenderers,
164
190
  toHTML
165
191
  };
166
192
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Define a generic type for HTML attributes (key-value pairs)\ntype AttributeMap = Record<string, string>;\n\n// Structure representing the output HTML node\ninterface BoxNode {\n tagName: string;\n attributes?: AttributeMap;\n isVoid?: boolean; // True for self-closing tags like <img />, <hr />\n innerHTML?: string;\n}\n\n// Function signature for encoding HTML entities\ntype EntityEncoder = (value: string) => string;\n\n// Function signature for encoding HTML entities\ntype BoxRenderer = (boxValue: AttributeMap, encode: EntityEncoder) => BoxNode | string;\n\n// Registry of renderers for different box types\ntype BoxRenderers = Record<string, BoxRenderer>;\n\n/**\n * Extracts the ID from a URL.\n * Useful for extracting YouTube or Twitter IDs from clean URLs.\n */\nfunction extractIdFromUrl(url: string): string {\n const result = /[\\w\\-]+$/.exec(url);\n return result ? result[0] : '';\n}\n\n/**\n * Returns the default configuration for rendering various Lake attributes.\n */\nexport function getDefaultBoxRenderers(): BoxRenderers {\n return {\n hr: () => '<div class=\"lake-box-block lake-hr\"><hr /></div>',\n\n image: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n ...(boxValue.width && { width: boxValue.width }),\n ...(boxValue.height && { height: boxValue.height }),\n ...(boxValue.caption && { alt: boxValue.caption }),\n border: '0',\n },\n isVoid: true,\n }),\n\n file: (boxValue, encode) => ({\n tagName: 'a',\n attributes: {\n href: boxValue.url,\n target: '_blank',\n },\n innerHTML: encode(boxValue.name),\n }),\n\n codeBlock: (boxValue, encode) => ({\n tagName: 'pre',\n attributes: {\n class: `lang-${boxValue.lang}`,\n },\n innerHTML: `<code>${encode(boxValue.code)}</code>`,\n }),\n\n emoji: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n width: '32',\n height: '32',\n border: '0',\n },\n isVoid: true,\n }),\n\n equation: boxValue => ({\n tagName: 'code',\n innerHTML: boxValue.code,\n }),\n\n video: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://www.youtube.com/embed/${extractIdFromUrl(boxValue.url)}` }),\n title: 'YouTube video player',\n frameborder: '0',\n allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',\n referrerpolicy: 'strict-origin-when-cross-origin',\n allowfullscreen: 'true',\n style: 'width: 560px; height: 315px;',\n },\n }),\n\n twitter: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://platform.twitter.com/embed/Tweet.html?id=${extractIdFromUrl(boxValue.url)}` }),\n title: 'Twitter tweet',\n scrolling: 'no',\n frameborder: '0',\n allowtransparency: 'true',\n allowfullscreen: 'true',\n style: 'width: 550px; height: 300px;',\n },\n }),\n };\n}\n\n// Map for reserved HTML characters\nconst htmlEntityMap = new Map([\n ['&', '&amp;'],\n ['<', '&lt;'],\n ['>', '&gt;'],\n ['\"', '&quot;'],\n ['\\xA0', '&nbsp;'],\n]);\n\n/**\n * Escapes reserved HTML characters to prevent XSS and rendering issues.\n */\nfunction encodeHTMLEntities(value: string): string {\n return value.replace(/[&<>\"\\xA0]/g, match => htmlEntityMap.get(match)!);\n}\n\n/**\n * Decodes a Base64 encoded string with UTF-8 support.\n */\nfunction decodeBase64(value: string): string {\n const binaryString = atob(value);\n const byteArray = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n byteArray[i] = binaryString.charCodeAt(i);\n }\n const decoder = new TextDecoder();\n return decoder.decode(byteArray);\n}\n\n/**\n * Parses HTML tag attributes from a string into a key-value object.\n */\nfunction parseAttributes(tag: string): AttributeMap {\n const attributes: AttributeMap = {};\n // Regex breakdown:\n // Group 1/2: Key=Value (unquoted)\n // Group 3/4: Key=\"Value\" (double quoted)\n // Group 5/6: Key='Value' (single quoted)\n const reg = /\\s+(?:([\\w\\-:]+)=([^\\s\"'<>]+)|([\\w\\-:\"]+)=\"([^\"]*)\"|([\\w\\-:\"]+)='([^']*)')(?=[\\s/>])/g;\n let match: RegExpExecArray | null;\n while ((match = reg.exec(tag))) {\n const key = (match[1] || match[3] || match[5]).toLowerCase();\n const value = match[1] ? match[2] : (match[3] ? match[4] : match[6]);\n attributes[key] = value;\n }\n return attributes;\n}\n\n/**\n * Serializes an attribute map into an HTML attribute string.\n */\nfunction serializeAttributes(attrs: AttributeMap): string {\n const result: string[] = [];\n for (const key of Object.keys(attrs)) {\n const value = String(attrs[key]);\n result.push(`${key}=\"${encodeHTMLEntities(value)}\"`);\n }\n return result.join(' ');\n}\n\n/**\n * Main function to convert Lake Markup Language (LML) to standard HTML.\n * It processes custom <lake-box> tags and removes internal anchors.\n */\nexport function toHTML(value: string, rules?: BoxRenderers): string {\n const config = rules ?? getDefaultBoxRenderers();\n // Regex to match <lake-box>, <anchor>, and <focus> tags\n const combinedRegex = /(<lake-box[^>]+>)[\\s\\S]*?(?:<\\/lake-box>|$)|(<anchor\\s*\\/>)|(<focus\\s*\\/>)/gi;\n return value.replace(combinedRegex, (match, boxOpen) => {\n // Handle lake-box conversion\n if (boxOpen) {\n const attributes = parseAttributes(boxOpen);\n const render = config[attributes.name];\n if (render) {\n try {\n const decodedValue = attributes.value ? JSON.parse(decodeBase64(attributes.value)) : {};\n const result = render(decodedValue, encodeHTMLEntities);\n // If renderer returns a raw string, return it directly\n if (typeof result === 'string') {\n return result;\n }\n // Otherwise, build the HTML tag from BoxNode\n let html = `<${result.tagName}`;\n if (result.attributes) {\n html += ` ${serializeAttributes(result.attributes)}`;\n }\n if (result.isVoid === true) {\n html += ' />';\n } else {\n html += `>${result.innerHTML ?? ''}</${result.tagName}>`;\n }\n return html;\n } catch (e) {\n console.error('Failed to parse lake-box value:', e);\n }\n }\n }\n // Remove internal selection markers (<anchor /> and <focus />)\n return '';\n });\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Define a generic type for HTML attributes (key-value pairs)\ntype AttributeMap = Record<string, string>;\n\n// Structure representing the output HTML node\ninterface BoxHTMLNode {\n tagName: string;\n attributes?: AttributeMap;\n isVoid?: boolean; // True for self-closing tags like <img />, <hr />\n innerHTML?: string;\n}\n\n// Function signature for encoding HTML entities\ntype EncodeHTMLEntities = (value: string) => string;\n\n// Function signature for encoding HTML entities\ntype RenderBox = (boxValue: AttributeMap, encode: EncodeHTMLEntities) => BoxHTMLNode;\n\n// Registry of renderers for different box types\ntype BoxRenderers = Record<string, RenderBox>;\n\n/**\n * Extracts the ID from a URL.\n * Useful for extracting YouTube or Twitter IDs from clean URLs.\n */\nfunction extractIdFromUrl(url: string): string {\n const result = /[\\w\\-]+$/.exec(url);\n return result ? result[0] : '';\n}\n\n/**\n * Returns the default configuration for rendering various Lake attributes.\n */\nexport function getBoxRenderers(): BoxRenderers {\n return {\n hr: () => ({\n tagName: 'div',\n attributes: {\n class: 'lake-box-block lake-hr',\n },\n innerHTML: '<hr />',\n }),\n\n image: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n ...(boxValue.width && { width: boxValue.width }),\n ...(boxValue.height && { height: boxValue.height }),\n ...(boxValue.caption && { alt: boxValue.caption }),\n border: '0',\n },\n isVoid: true,\n }),\n\n media: boxValue => ({\n tagName: 'video',\n attributes: {\n src: boxValue.url,\n ...(boxValue.width && { width: boxValue.width.replace(/px$/i, '') }),\n ...(boxValue.height && { height: boxValue.height.replace(/px$/i, '') }),\n controls: 'true',\n },\n }),\n\n file: (boxValue, encode) => ({\n tagName: 'a',\n attributes: {\n href: boxValue.url,\n target: '_blank',\n },\n innerHTML: encode(boxValue.name),\n }),\n\n codeBlock: (boxValue, encode) => ({\n tagName: 'pre',\n attributes: {\n class: `lang-${boxValue.lang}`,\n },\n innerHTML: `<code>${encode(boxValue.code)}</code>`,\n }),\n\n emoji: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n width: '32',\n height: '32',\n border: '0',\n },\n isVoid: true,\n }),\n\n equation: boxValue => ({\n tagName: 'code',\n innerHTML: boxValue.code,\n }),\n\n mention: (boxValue, encode) => ({\n tagName: 'a',\n attributes: {\n href: `/${boxValue.name}`,\n target: '_blank',\n },\n innerHTML: encode(boxValue.nickname ?? boxValue.name),\n }),\n\n video: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://www.youtube.com/embed/${extractIdFromUrl(boxValue.url)}` }),\n width: boxValue.width ? boxValue.width.replace(/px$/i, '') : '560',\n height: boxValue.height ? boxValue.height.replace(/px$/i, '') : '315',\n title: 'YouTube video player',\n frameborder: '0',\n allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',\n referrerpolicy: 'strict-origin-when-cross-origin',\n allowfullscreen: 'true',\n },\n }),\n\n twitter: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://platform.twitter.com/embed/Tweet.html?id=${extractIdFromUrl(boxValue.url)}` }),\n title: 'Twitter tweet',\n scrolling: 'no',\n frameborder: '0',\n allowtransparency: 'true',\n allowfullscreen: 'true',\n style: 'width: 550px; height: 300px;',\n },\n }),\n };\n}\n\n// Map for reserved HTML characters\nconst htmlEntityMap = new Map([\n ['&', '&amp;'],\n ['<', '&lt;'],\n ['>', '&gt;'],\n ['\"', '&quot;'],\n ['\\xA0', '&nbsp;'],\n]);\n\n/**\n * Escapes reserved HTML characters to prevent XSS and rendering issues.\n */\nfunction encodeHTMLEntities(value: string): string {\n return value.replace(/[&<>\"\\xA0]/g, match => htmlEntityMap.get(match)!);\n}\n\n/**\n * Decodes a Base64 encoded string with UTF-8 support.\n */\nfunction decodeBase64(value: string): string {\n const binaryString = atob(value);\n const byteArray = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n byteArray[i] = binaryString.charCodeAt(i);\n }\n const decoder = new TextDecoder();\n return decoder.decode(byteArray);\n}\n\n/**\n * Parses HTML tag attributes from a string into a key-value object.\n */\nfunction parseAttributes(tag: string): AttributeMap {\n const attributes: AttributeMap = {};\n // Regex breakdown:\n // Group 1/2: Key=Value (unquoted)\n // Group 3/4: Key=\"Value\" (double quoted)\n // Group 5/6: Key='Value' (single quoted)\n const reg = /\\s+(?:([\\w\\-:]+)=([^\\s\"'<>]+)|([\\w\\-:\"]+)=\"([^\"]*)\"|([\\w\\-:\"]+)='([^']*)')(?=[\\s/>])/g;\n let match: RegExpExecArray | null;\n while ((match = reg.exec(tag))) {\n const key = (match[1] || match[3] || match[5]).toLowerCase();\n const value = match[1] ? match[2] : (match[3] ? match[4] : match[6]);\n attributes[key] = value;\n }\n return attributes;\n}\n\n/**\n * Serializes an attribute map into an HTML attribute string.\n */\nfunction serializeAttributes(attrs: AttributeMap): string {\n const result: string[] = [];\n for (const key of Object.keys(attrs)) {\n const value = String(attrs[key]);\n result.push(`${key}=\"${encodeHTMLEntities(value)}\"`);\n }\n return result.join(' ');\n}\n\n/**\n * Serializes a BoxHTMLNode object into a standard HTML string.\n */\nfunction toBoxHTML(node: BoxHTMLNode): string {\n let result = `<${node.tagName}`;\n if (node.attributes) {\n result += ` ${serializeAttributes(node.attributes)}`;\n }\n if (node.isVoid === true) {\n result += ' />';\n } else {\n result += `>${node.innerHTML ?? ''}</${node.tagName}>`;\n }\n return result;\n}\n\n/**\n * Main function to convert Lake Markup Language (LML) to standard HTML.\n * It processes custom <lake-box> tags and removes internal anchors.\n */\nexport function toHTML(value: string, renderers?: BoxRenderers): string {\n renderers = renderers ?? getBoxRenderers();\n // Regex to match <lake-box>, <anchor>, and <focus> tags\n const combinedRegex = /(<lake-box[^>]+>)[\\s\\S]*?(?:<\\/lake-box>|$)|(<anchor\\s*\\/>)|(<focus\\s*\\/>)/gi;\n return value.replace(combinedRegex, (match, boxOpen) => {\n // Handle lake-box conversion\n if (boxOpen) {\n const attributes = parseAttributes(boxOpen);\n const render = renderers[attributes.name];\n if (render) {\n try {\n const boxValue = attributes.value ? JSON.parse(decodeBase64(attributes.value)) : {};\n const node = render(boxValue, encodeHTMLEntities);\n return toBoxHTML(node);\n } catch (e) {\n console.error('Failed to parse lake-box value:', e);\n }\n }\n }\n // Remove internal selection markers (<anchor /> and <focus />)\n return '';\n });\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lake-html",
3
- "version": "1.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "A lightweight utility to convert Lake Markup Language (LML) to HTML",
5
5
  "author": "Luo Longhao <luolonghao@gmail.com>",
6
6
  "license": "MIT",
@@ -32,7 +32,7 @@
32
32
  ],
33
33
  "devDependencies": {
34
34
  "@antfu/eslint-config": "^7.2.0",
35
- "@vitest/coverage-v8": "4.0.17",
35
+ "@vitest/coverage-v8": "^4.0.18",
36
36
  "conventional-changelog-cli": "^5.0.0",
37
37
  "eslint": "^9.39.2",
38
38
  "execa": "^9.6.1",