@incremark/shared 0.2.6 → 0.3.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/index.d.ts +53 -1
- package/dist/index.js +42 -1
- package/dist/index.js.map +1 -1
- package/package.json +8 -4
package/dist/index.d.ts
CHANGED
|
@@ -60,4 +60,56 @@ declare function hasChunks(node: PhrasingContent): node is TextNodeWithChunks;
|
|
|
60
60
|
*/
|
|
61
61
|
declare function getStableText(node: TextNodeWithChunks): string;
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
/**
|
|
64
|
+
* 环境检测工具函数
|
|
65
|
+
*
|
|
66
|
+
* 用于 SSR 兼容性检测
|
|
67
|
+
*/
|
|
68
|
+
/**
|
|
69
|
+
* 检测是否在浏览器环境中
|
|
70
|
+
*/
|
|
71
|
+
declare function isBrowser(): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* 检测是否在服务器环境中 (SSR)
|
|
74
|
+
*/
|
|
75
|
+
declare function isServer(): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* 检测 Clipboard API 是否可用
|
|
78
|
+
*/
|
|
79
|
+
declare function isClipboardAvailable(): boolean;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Incremark 国际化类型定义
|
|
83
|
+
*/
|
|
84
|
+
interface IncremarkLocale {
|
|
85
|
+
/** 代码块相关翻译 */
|
|
86
|
+
code: {
|
|
87
|
+
/** 复制代码按钮文本 */
|
|
88
|
+
copy: string;
|
|
89
|
+
/** 复制成功后的提示文本 */
|
|
90
|
+
copied: string;
|
|
91
|
+
};
|
|
92
|
+
/** Mermaid 图表相关翻译 */
|
|
93
|
+
mermaid: {
|
|
94
|
+
/** 复制代码按钮文本 */
|
|
95
|
+
copy: string;
|
|
96
|
+
/** 复制成功后的提示文本 */
|
|
97
|
+
copied: string;
|
|
98
|
+
/** 查看源代码按钮文本 */
|
|
99
|
+
viewSource: string;
|
|
100
|
+
/** 预览图表按钮文本 */
|
|
101
|
+
preview: string;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 英文 locale
|
|
107
|
+
*/
|
|
108
|
+
declare const en: IncremarkLocale;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 简体中文 locale
|
|
112
|
+
*/
|
|
113
|
+
declare const zhCN: IncremarkLocale;
|
|
114
|
+
|
|
115
|
+
export { type HtmlTagInfo, type HtmlWrapperNode, type IncremarkLocale, type TextNodeWithChunks, en, extractTagName, getStableText, hasChunks, isBrowser, isClipboardAvailable, isHtmlNode, isHtmlWrapperNode, isServer, processHtmlNodes, zhCN };
|
package/dist/index.js
CHANGED
|
@@ -114,6 +114,47 @@ function getStableText(node) {
|
|
|
114
114
|
return node.value.slice(0, node.stableLength ?? 0);
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
// src/env.ts
|
|
118
|
+
function isBrowser() {
|
|
119
|
+
return typeof window !== "undefined";
|
|
120
|
+
}
|
|
121
|
+
function isServer() {
|
|
122
|
+
return typeof window === "undefined";
|
|
123
|
+
}
|
|
124
|
+
function isClipboardAvailable() {
|
|
125
|
+
return typeof navigator !== "undefined" && !!navigator.clipboard;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/locales/en.ts
|
|
129
|
+
var en = {
|
|
130
|
+
code: {
|
|
131
|
+
copy: "Copy code",
|
|
132
|
+
copied: "Code copied"
|
|
133
|
+
},
|
|
134
|
+
mermaid: {
|
|
135
|
+
copy: "Copy code",
|
|
136
|
+
copied: "Code copied",
|
|
137
|
+
viewSource: "View source code",
|
|
138
|
+
preview: "Preview diagram"
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
var en_default = en;
|
|
142
|
+
|
|
143
|
+
// src/locales/zh-cn.ts
|
|
144
|
+
var zhCN = {
|
|
145
|
+
code: {
|
|
146
|
+
copy: "\u590D\u5236\u4EE3\u7801",
|
|
147
|
+
copied: "\u4EE3\u7801\u5DF2\u590D\u5236"
|
|
148
|
+
},
|
|
149
|
+
mermaid: {
|
|
150
|
+
copy: "\u590D\u5236\u4EE3\u7801",
|
|
151
|
+
copied: "\u4EE3\u7801\u5DF2\u590D\u5236",
|
|
152
|
+
viewSource: "\u67E5\u770B\u6E90\u4EE3\u7801",
|
|
153
|
+
preview: "\u9884\u89C8\u56FE\u8868"
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
var zh_cn_default = zhCN;
|
|
157
|
+
|
|
158
|
+
export { en_default as en, extractTagName, getStableText, hasChunks, isBrowser, isClipboardAvailable, isHtmlNode, isHtmlWrapperNode, isServer, processHtmlNodes, zh_cn_default as zhCN };
|
|
118
159
|
//# sourceMappingURL=index.js.map
|
|
119
160
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/html.ts","../src/text.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { PhrasingContent, HTML } from 'mdast'\n\n/**\n * HTML 标签信息\n */\nexport interface HtmlTagInfo {\n tagName: string\n isClosing: boolean\n isSelfClosing: boolean\n}\n\n/**\n * 提取 HTML 标签名(支持自闭合标签)\n */\nexport function extractTagName(html: string): HtmlTagInfo | null {\n const match = html.match(/^<\\/?([a-zA-Z][a-zA-Z0-9-]*)\\s*\\/?>?/)\n if (!match) return null\n \n const isClosing = html.startsWith('</')\n const isSelfClosing = html.endsWith('/>') || !!html.match(/^<[^>]+\\/>$/)\n return {\n tagName: match[1].toLowerCase(),\n isClosing,\n isSelfClosing\n }\n}\n\n/**\n * 类型守卫:检查是否是 HTML 节点\n */\nexport function isHtmlNode(node: PhrasingContent): node is HTML {\n return node.type === 'html'\n}\n\n/**\n * HTML 包装节点:包含开始标签、内容节点、结束标签\n * 这样可以在渲染时一起处理,避免空标签\n */\nexport interface HtmlWrapperNode {\n type: 'html-wrapper'\n startTag: string\n content: PhrasingContent[]\n endTag: string\n tagName: string\n}\n\n/**\n * 类型守卫:检查是否是 HTML 包装节点\n */\nexport function isHtmlWrapperNode(node: PhrasingContent | HtmlWrapperNode): node is HtmlWrapperNode {\n return (node as HtmlWrapperNode).type === 'html-wrapper'\n}\n\n/**\n * 处理 HTML 节点数组,将开始标签、中间内容、结束标签包装在一起\n * 这样渲染时可以一起处理,避免空标签\n */\nexport function processHtmlNodes(nodes: PhrasingContent[]): (PhrasingContent | HtmlWrapperNode)[] {\n const result: (PhrasingContent | HtmlWrapperNode)[] = []\n let i = 0\n \n while (i < nodes.length) {\n const node = nodes[i]\n \n if (isHtmlNode(node)) {\n const tagInfo = extractTagName(node.value)\n \n if (tagInfo) {\n if (tagInfo.isSelfClosing) {\n // 自闭合标签,直接添加\n result.push(node)\n i++\n } else if (tagInfo.isClosing) {\n // 结束标签,如果前面没有匹配的开始标签,跳过(可能是之前补上的)\n // 否则应该已经被包装处理了,这里不应该单独出现\n i++\n continue\n } else {\n // 开始标签:收集后续内容直到找到对应的结束标签\n const startTag = node.value\n const tagName = tagInfo.tagName\n const contentNodes: PhrasingContent[] = []\n let foundClosing = false\n let j = i + 1\n let depth = 1 // 嵌套深度\n \n // 收集开始标签和结束标签之间的所有节点\n while (j < nodes.length && depth > 0) {\n const nextNode = nodes[j]\n \n if (isHtmlNode(nextNode)) {\n const nextTagInfo = extractTagName(nextNode.value)\n if (nextTagInfo) {\n if (nextTagInfo.isClosing && nextTagInfo.tagName === tagName) {\n // 找到匹配的结束标签\n depth--\n if (depth === 0) {\n foundClosing = true\n const endTag = nextNode.value\n \n // 创建包装节点\n const wrapperNode: HtmlWrapperNode = {\n type: 'html-wrapper',\n startTag,\n content: contentNodes,\n endTag,\n tagName\n }\n \n result.push(wrapperNode)\n i = j + 1 // 跳过已处理的所有节点\n break\n } else {\n // 嵌套的结束标签,收集到内容中\n contentNodes.push(nextNode)\n j++\n }\n } else if (!nextTagInfo.isClosing && nextTagInfo.tagName === tagName) {\n // 嵌套的同名开始标签\n depth++\n contentNodes.push(nextNode)\n j++\n } else {\n // 其他 HTML 节点,收集到内容中\n contentNodes.push(nextNode)\n j++\n }\n } else {\n // 无法解析的 HTML,收集到内容中\n contentNodes.push(nextNode)\n j++\n }\n } else {\n // 非 HTML 节点(文本等),收集到内容中\n contentNodes.push(nextNode)\n j++\n }\n }\n \n if (!foundClosing) {\n // 没有找到结束标签,补上一个\n const endTag = `</${tagName}>`\n \n const wrapperNode: HtmlWrapperNode = {\n type: 'html-wrapper',\n startTag,\n content: contentNodes,\n endTag,\n tagName\n }\n \n result.push(wrapperNode)\n i = j // 跳过已处理的所有节点\n }\n }\n } else {\n // 无法解析的 HTML,直接添加\n result.push(node)\n i++\n }\n } else {\n // 非 HTML 节点,直接添加\n result.push(node)\n i++\n }\n }\n \n return result\n}\n\n","import type { PhrasingContent, Text } from 'mdast'\nimport type { TextNodeWithChunks } from './types'\n\n/**\n * 类型守卫:检查是否是带 chunks 的文本节点\n */\nexport function hasChunks(node: PhrasingContent): node is TextNodeWithChunks {\n return node.type === 'text' && 'chunks' in node && Array.isArray((node as TextNodeWithChunks).chunks)\n}\n\n/**\n * 获取文本节点的稳定部分(不需要动画)\n */\nexport function getStableText(node: TextNodeWithChunks): string {\n if (!node.chunks || node.chunks.length === 0) {\n return (node as Text).value\n }\n return (node as Text).value.slice(0, node.stableLength ?? 0)\n}\n\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/html.ts","../src/text.ts","../src/env.ts","../src/locales/en.ts","../src/locales/zh-cn.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { PhrasingContent, HTML } from 'mdast'\n\n/**\n * HTML 标签信息\n */\nexport interface HtmlTagInfo {\n tagName: string\n isClosing: boolean\n isSelfClosing: boolean\n}\n\n/**\n * 提取 HTML 标签名(支持自闭合标签)\n */\nexport function extractTagName(html: string): HtmlTagInfo | null {\n const match = html.match(/^<\\/?([a-zA-Z][a-zA-Z0-9-]*)\\s*\\/?>?/)\n if (!match) return null\n \n const isClosing = html.startsWith('</')\n const isSelfClosing = html.endsWith('/>') || !!html.match(/^<[^>]+\\/>$/)\n return {\n tagName: match[1].toLowerCase(),\n isClosing,\n isSelfClosing\n }\n}\n\n/**\n * 类型守卫:检查是否是 HTML 节点\n */\nexport function isHtmlNode(node: PhrasingContent): node is HTML {\n return node.type === 'html'\n}\n\n/**\n * HTML 包装节点:包含开始标签、内容节点、结束标签\n * 这样可以在渲染时一起处理,避免空标签\n */\nexport interface HtmlWrapperNode {\n type: 'html-wrapper'\n startTag: string\n content: PhrasingContent[]\n endTag: string\n tagName: string\n}\n\n/**\n * 类型守卫:检查是否是 HTML 包装节点\n */\nexport function isHtmlWrapperNode(node: PhrasingContent | HtmlWrapperNode): node is HtmlWrapperNode {\n return (node as HtmlWrapperNode).type === 'html-wrapper'\n}\n\n/**\n * 处理 HTML 节点数组,将开始标签、中间内容、结束标签包装在一起\n * 这样渲染时可以一起处理,避免空标签\n */\nexport function processHtmlNodes(nodes: PhrasingContent[]): (PhrasingContent | HtmlWrapperNode)[] {\n const result: (PhrasingContent | HtmlWrapperNode)[] = []\n let i = 0\n \n while (i < nodes.length) {\n const node = nodes[i]\n \n if (isHtmlNode(node)) {\n const tagInfo = extractTagName(node.value)\n \n if (tagInfo) {\n if (tagInfo.isSelfClosing) {\n // 自闭合标签,直接添加\n result.push(node)\n i++\n } else if (tagInfo.isClosing) {\n // 结束标签,如果前面没有匹配的开始标签,跳过(可能是之前补上的)\n // 否则应该已经被包装处理了,这里不应该单独出现\n i++\n continue\n } else {\n // 开始标签:收集后续内容直到找到对应的结束标签\n const startTag = node.value\n const tagName = tagInfo.tagName\n const contentNodes: PhrasingContent[] = []\n let foundClosing = false\n let j = i + 1\n let depth = 1 // 嵌套深度\n \n // 收集开始标签和结束标签之间的所有节点\n while (j < nodes.length && depth > 0) {\n const nextNode = nodes[j]\n \n if (isHtmlNode(nextNode)) {\n const nextTagInfo = extractTagName(nextNode.value)\n if (nextTagInfo) {\n if (nextTagInfo.isClosing && nextTagInfo.tagName === tagName) {\n // 找到匹配的结束标签\n depth--\n if (depth === 0) {\n foundClosing = true\n const endTag = nextNode.value\n \n // 创建包装节点\n const wrapperNode: HtmlWrapperNode = {\n type: 'html-wrapper',\n startTag,\n content: contentNodes,\n endTag,\n tagName\n }\n \n result.push(wrapperNode)\n i = j + 1 // 跳过已处理的所有节点\n break\n } else {\n // 嵌套的结束标签,收集到内容中\n contentNodes.push(nextNode)\n j++\n }\n } else if (!nextTagInfo.isClosing && nextTagInfo.tagName === tagName) {\n // 嵌套的同名开始标签\n depth++\n contentNodes.push(nextNode)\n j++\n } else {\n // 其他 HTML 节点,收集到内容中\n contentNodes.push(nextNode)\n j++\n }\n } else {\n // 无法解析的 HTML,收集到内容中\n contentNodes.push(nextNode)\n j++\n }\n } else {\n // 非 HTML 节点(文本等),收集到内容中\n contentNodes.push(nextNode)\n j++\n }\n }\n \n if (!foundClosing) {\n // 没有找到结束标签,补上一个\n const endTag = `</${tagName}>`\n \n const wrapperNode: HtmlWrapperNode = {\n type: 'html-wrapper',\n startTag,\n content: contentNodes,\n endTag,\n tagName\n }\n \n result.push(wrapperNode)\n i = j // 跳过已处理的所有节点\n }\n }\n } else {\n // 无法解析的 HTML,直接添加\n result.push(node)\n i++\n }\n } else {\n // 非 HTML 节点,直接添加\n result.push(node)\n i++\n }\n }\n \n return result\n}\n\n","import type { PhrasingContent, Text } from 'mdast'\nimport type { TextNodeWithChunks } from './types'\n\n/**\n * 类型守卫:检查是否是带 chunks 的文本节点\n */\nexport function hasChunks(node: PhrasingContent): node is TextNodeWithChunks {\n return node.type === 'text' && 'chunks' in node && Array.isArray((node as TextNodeWithChunks).chunks)\n}\n\n/**\n * 获取文本节点的稳定部分(不需要动画)\n */\nexport function getStableText(node: TextNodeWithChunks): string {\n if (!node.chunks || node.chunks.length === 0) {\n return (node as Text).value\n }\n return (node as Text).value.slice(0, node.stableLength ?? 0)\n}\n\n","/**\n * 环境检测工具函数\n *\n * 用于 SSR 兼容性检测\n */\n\n/**\n * 检测是否在浏览器环境中\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined'\n}\n\n/**\n * 检测是否在服务器环境中 (SSR)\n */\nexport function isServer(): boolean {\n return typeof window === 'undefined'\n}\n\n/**\n * 检测 Clipboard API 是否可用\n */\nexport function isClipboardAvailable(): boolean {\n return typeof navigator !== 'undefined' && !!navigator.clipboard\n}\n","import type { IncremarkLocale } from './types'\n\n/**\n * 英文 locale\n */\nconst en: IncremarkLocale = {\n code: {\n copy: 'Copy code',\n copied: 'Code copied'\n },\n mermaid: {\n copy: 'Copy code',\n copied: 'Code copied',\n viewSource: 'View source code',\n preview: 'Preview diagram'\n }\n}\n\nexport default en\n","import type { IncremarkLocale } from './types'\n\n/**\n * 简体中文 locale\n */\nconst zhCN: IncremarkLocale = {\n code: {\n copy: '复制代码',\n copied: '代码已复制'\n },\n mermaid: {\n copy: '复制代码',\n copied: '代码已复制',\n viewSource: '查看源代码',\n preview: '预览图表'\n }\n}\n\nexport default zhCN\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@incremark/shared",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Incremark
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Incremark shared utilities - Common logic and i18n support for Vue, React, and Svelte.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -22,12 +22,16 @@
|
|
|
22
22
|
"typescript": "^5.3.0"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
|
-
"@incremark/core": "0.
|
|
25
|
+
"@incremark/core": "0.3.0"
|
|
26
26
|
},
|
|
27
27
|
"keywords": [
|
|
28
28
|
"incremark",
|
|
29
29
|
"shared",
|
|
30
|
-
"utils"
|
|
30
|
+
"utils",
|
|
31
|
+
"i18n",
|
|
32
|
+
"locales",
|
|
33
|
+
"markdown",
|
|
34
|
+
"streaming"
|
|
31
35
|
],
|
|
32
36
|
"license": "MIT",
|
|
33
37
|
"repository": {
|