@incremark/shared 0.3.9 → 0.4.0-alpha.1
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 +85 -1
- package/dist/index.js +90 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -123,4 +123,88 @@ declare const en: IncremarkLocale;
|
|
|
123
123
|
*/
|
|
124
124
|
declare const zhCN: IncremarkLocale;
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
/**
|
|
127
|
+
* format.ts
|
|
128
|
+
*
|
|
129
|
+
* 格式化工具函数
|
|
130
|
+
*/
|
|
131
|
+
/**
|
|
132
|
+
* 格式化时长(毫秒)为人类可读格式
|
|
133
|
+
* 支持国际化
|
|
134
|
+
*
|
|
135
|
+
* @param ms - 时长(毫秒)
|
|
136
|
+
* @param locale - 语言环境,默认 'en'
|
|
137
|
+
* @returns 格式化后的时长字符串
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* formatDuration(500, 'en') // '1s'
|
|
141
|
+
* formatDuration(1500, 'en') // '2s'
|
|
142
|
+
* formatDuration(65000, 'en') // '1m 5s'
|
|
143
|
+
* formatDuration(125000, 'en') // '2m 5s'
|
|
144
|
+
* formatDuration(125000, 'zh') // '2分5秒'
|
|
145
|
+
* formatDuration(3600000, 'en') // '1h'
|
|
146
|
+
* formatDuration(3665000, 'en') // '1h 1m'
|
|
147
|
+
*/
|
|
148
|
+
declare function formatDuration(ms: number, locale?: string): string;
|
|
149
|
+
/**
|
|
150
|
+
* 格式化文件大小为人类可读格式
|
|
151
|
+
*
|
|
152
|
+
* @param bytes - 文件大小(字节)
|
|
153
|
+
* @param decimals - 小数位数,默认 1
|
|
154
|
+
* @returns 格式化后的文件大小字符串
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* formatFileSize(0) // '0 B'
|
|
158
|
+
* formatFileSize(1024) // '1 KB'
|
|
159
|
+
* formatFileSize(1536) // '1.5 KB'
|
|
160
|
+
* formatFileSize(1048576) // '1 MB'
|
|
161
|
+
* formatFileSize(1073741824) // '1 GB'
|
|
162
|
+
*/
|
|
163
|
+
declare function formatFileSize(bytes?: number, decimals?: number): string;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* bem.ts
|
|
167
|
+
*
|
|
168
|
+
* BEM 命名工具函数
|
|
169
|
+
* 简单的 BEM 命名生成器,不依赖第三方库
|
|
170
|
+
*/
|
|
171
|
+
/**
|
|
172
|
+
* BEM 类名生成器
|
|
173
|
+
*
|
|
174
|
+
* @param block - Block 名称
|
|
175
|
+
* @param namespace - 命名空间前缀(可选)
|
|
176
|
+
* @returns BEM 命名函数
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* // 默认配置
|
|
180
|
+
* const b = createBem('button');
|
|
181
|
+
* b(); // 'button'
|
|
182
|
+
* b({ active: true }); // 'button button--active'
|
|
183
|
+
* b('icon'); // 'button__icon'
|
|
184
|
+
* b('icon', { large: true }); // 'button__icon button__icon--large'
|
|
185
|
+
*
|
|
186
|
+
* // 带命名空间
|
|
187
|
+
* const b = createBem('button', 'im-');
|
|
188
|
+
* b(); // 'im-button'
|
|
189
|
+
* b({ active: true }); // 'im-button im-button--active'
|
|
190
|
+
* b('icon'); // 'im-button__icon'
|
|
191
|
+
* b('icon', { large: true }); // 'im-button__icon im-button__icon--large'
|
|
192
|
+
*/
|
|
193
|
+
declare function createBem(block: string, namespace?: string): (element?: string, modifiers?: Record<string, boolean | string | number> | string) => string;
|
|
194
|
+
/**
|
|
195
|
+
* 创建带命名空间的 BEM 生成器
|
|
196
|
+
* 专用于 Incremark Chat UI 组件(im- 前缀)
|
|
197
|
+
*
|
|
198
|
+
* @param block - Block 名称(会自动添加 im- 前缀)
|
|
199
|
+
* @returns BEM 命名函数
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* const b = createImBem('cot');
|
|
203
|
+
* b(); // 'im-cot'
|
|
204
|
+
* b({ expanded: true }); // 'im-cot im-cot--expanded'
|
|
205
|
+
* b('header'); // 'im-cot__header'
|
|
206
|
+
* b('icon', 'loading'); // 'im-cot__icon im-cot__icon--loading'
|
|
207
|
+
*/
|
|
208
|
+
declare function createImBem(block: string): (element?: string, modifiers?: Record<string, boolean | string | number> | string) => string;
|
|
209
|
+
|
|
210
|
+
export { type HtmlTagInfo, type HtmlWrapperNode, type IncremarkLocale, type TextChunk, type TextNodeWithChunks, createBem, createImBem, en, extractTagName, formatDuration, formatFileSize, generateParserId, getStableText, hasChunks, isBrowser, isClipboardAvailable, isHtmlNode, isHtmlWrapperNode, isServer, processHtmlNodes, zhCN };
|
package/dist/index.js
CHANGED
|
@@ -160,6 +160,95 @@ var zhCN = {
|
|
|
160
160
|
};
|
|
161
161
|
var zh_cn_default = zhCN;
|
|
162
162
|
|
|
163
|
-
|
|
163
|
+
// src/format.ts
|
|
164
|
+
var DURATION_UNITS = {
|
|
165
|
+
en: { s: "s", m: "m", h: "h" },
|
|
166
|
+
zh: { s: "\u79D2", m: "\u5206\u949F", h: "\u5C0F\u65F6" },
|
|
167
|
+
ja: { s: "\u79D2", m: "\u5206", h: "\u6642\u9593" },
|
|
168
|
+
ko: { s: "\uCD08", m: "\uBD84", h: "\uC2DC\uAC04" },
|
|
169
|
+
de: { s: "s", m: "Min", h: "Std" },
|
|
170
|
+
fr: { s: "s", m: "min", h: "h" },
|
|
171
|
+
es: { s: "s", m: "min", h: "h" }
|
|
172
|
+
};
|
|
173
|
+
function formatDuration(ms, locale = "en") {
|
|
174
|
+
const units = DURATION_UNITS[locale] || DURATION_UNITS.en;
|
|
175
|
+
if (ms < 1e3) {
|
|
176
|
+
return `1${units.s}`;
|
|
177
|
+
}
|
|
178
|
+
if (ms < 6e4) {
|
|
179
|
+
const seconds = Math.ceil(ms / 1e3);
|
|
180
|
+
return `${seconds}${units.s}`;
|
|
181
|
+
}
|
|
182
|
+
if (ms < 36e5) {
|
|
183
|
+
const minutes2 = Math.floor(ms / 6e4);
|
|
184
|
+
const seconds = Math.ceil(ms % 6e4 / 1e3);
|
|
185
|
+
if (seconds === 60) {
|
|
186
|
+
return `${minutes2 + 1}${units.m}`;
|
|
187
|
+
}
|
|
188
|
+
if (seconds === 0) {
|
|
189
|
+
return `${minutes2}${units.m}`;
|
|
190
|
+
}
|
|
191
|
+
if (locale === "zh" || locale === "ja" || locale === "ko") {
|
|
192
|
+
return `${minutes2}${units.m}${seconds}${units.s}`;
|
|
193
|
+
}
|
|
194
|
+
return `${minutes2}${units.m} ${seconds}${units.s}`;
|
|
195
|
+
}
|
|
196
|
+
const hours = Math.floor(ms / 36e5);
|
|
197
|
+
const minutes = Math.ceil(ms % 36e5 / 6e4);
|
|
198
|
+
if (minutes === 60) {
|
|
199
|
+
return `${hours + 1}${units.h}`;
|
|
200
|
+
}
|
|
201
|
+
if (minutes === 0) {
|
|
202
|
+
return `${hours}${units.h}`;
|
|
203
|
+
}
|
|
204
|
+
if (locale === "zh" || locale === "ja" || locale === "ko") {
|
|
205
|
+
return `${hours}${units.h}${minutes}${units.m}`;
|
|
206
|
+
}
|
|
207
|
+
return `${hours}${units.h} ${minutes}${units.m}`;
|
|
208
|
+
}
|
|
209
|
+
var FILE_SIZE_UNITS = ["B", "KB", "MB", "GB", "TB"];
|
|
210
|
+
function formatFileSize(bytes, decimals = 1) {
|
|
211
|
+
if (bytes === void 0 || bytes === null) return "";
|
|
212
|
+
if (bytes === 0) return "0 B";
|
|
213
|
+
const k = 1024;
|
|
214
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
215
|
+
const size = bytes / Math.pow(k, i);
|
|
216
|
+
if (size % 1 === 0) {
|
|
217
|
+
return `${size} ${FILE_SIZE_UNITS[i]}`;
|
|
218
|
+
}
|
|
219
|
+
return `${size.toFixed(decimals)} ${FILE_SIZE_UNITS[i]}`;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/bem.ts
|
|
223
|
+
function createBem(block, namespace = "") {
|
|
224
|
+
const ns = namespace;
|
|
225
|
+
const blockName = ns ? `${ns}${block}` : block;
|
|
226
|
+
return function bem(element, modifiers) {
|
|
227
|
+
const classes = [];
|
|
228
|
+
if (element) {
|
|
229
|
+
classes.push(`${blockName}__${element}`);
|
|
230
|
+
} else {
|
|
231
|
+
classes.push(blockName);
|
|
232
|
+
}
|
|
233
|
+
if (modifiers) {
|
|
234
|
+
if (typeof modifiers === "string") {
|
|
235
|
+
classes.push(`${blockName}${element ? `__${element}` : ""}--${modifiers}`);
|
|
236
|
+
} else {
|
|
237
|
+
for (const [key, value] of Object.entries(modifiers)) {
|
|
238
|
+
if (value) {
|
|
239
|
+
const modValue = value === true ? "" : `-${value}`;
|
|
240
|
+
classes.push(`${blockName}${element ? `__${element}` : ""}--${key}${modValue}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return classes.join(" ");
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function createImBem(block) {
|
|
249
|
+
return createBem(block, "im-");
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export { createBem, createImBem, en_default as en, extractTagName, formatDuration, formatFileSize, generateParserId, getStableText, hasChunks, isBrowser, isClipboardAvailable, isHtmlNode, isHtmlWrapperNode, isServer, processHtmlNodes, zh_cn_default as zhCN };
|
|
164
253
|
//# sourceMappingURL=index.js.map
|
|
165
254
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/html.ts","../src/text.ts","../src/env.ts","../src/id.ts","../src/locales/en.ts","../src/locales/zh-cn.ts"],"names":[],"mappings":";AAcO,SAAS,eAAe,IAAA,EAAkC;AAC/D,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,sCAAsC,CAAA;AAC/D,EAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AAEnB,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,UAAA,CAAW,IAAI,CAAA;AACtC,EAAA,MAAM,aAAA,GAAgB,KAAK,QAAA,CAAS,IAAI,KAAK,CAAC,CAAC,IAAA,CAAK,KAAA,CAAM,aAAa,CAAA;AACvE,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,KAAA,CAAM,CAAC,CAAA,CAAE,WAAA,EAAY;AAAA,IAC9B,SAAA;AAAA,IACA;AAAA,GACF;AACF;AAKO,SAAS,WAAW,IAAA,EAAqC;AAC9D,EAAA,OAAO,KAAK,IAAA,KAAS,MAAA;AACvB;AAiBO,SAAS,kBAAkB,IAAA,EAAkE;AAClG,EAAA,OAAQ,KAAyB,IAAA,KAAS,cAAA;AAC5C;AAMO,SAAS,iBAAiB,KAAA,EAAiE;AAChG,EAAA,MAAM,SAAgD,EAAC;AACvD,EAAA,IAAI,CAAA,GAAI,CAAA;AAER,EAAA,OAAO,CAAA,GAAI,MAAM,MAAA,EAAQ;AACvB,IAAA,MAAM,IAAA,GAAO,MAAM,CAAC,CAAA;AAEpB,IAAA,IAAI,UAAA,CAAW,IAAI,CAAA,EAAG;AACpB,MAAA,MAAM,OAAA,GAAU,cAAA,CAAe,IAAA,CAAK,KAAK,CAAA;AAEzC,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,IAAI,QAAQ,aAAA,EAAe;AAEzB,UAAA,MAAA,CAAO,KAAK,IAAI,CAAA;AAChB,UAAA,CAAA,EAAA;AAAA,QACF,CAAA,MAAA,IAAW,QAAQ,SAAA,EAAW;AAG5B,UAAA,CAAA,EAAA;AACA,UAAA;AAAA,QACF,CAAA,MAAO;AAEL,UAAA,MAAM,WAAW,IAAA,CAAK,KAAA;AACtB,UAAA,MAAM,UAAU,OAAA,CAAQ,OAAA;AACxB,UAAA,MAAM,eAAkC,EAAC;AACzC,UAAA,IAAI,YAAA,GAAe,KAAA;AACnB,UAAA,IAAI,IAAI,CAAA,GAAI,CAAA;AACZ,UAAA,IAAI,KAAA,GAAQ,CAAA;AAGZ,UAAA,OAAO,CAAA,GAAI,KAAA,CAAM,MAAA,IAAU,KAAA,GAAQ,CAAA,EAAG;AACpC,YAAA,MAAM,QAAA,GAAW,MAAM,CAAC,CAAA;AAExB,YAAA,IAAI,UAAA,CAAW,QAAQ,CAAA,EAAG;AACxB,cAAA,MAAM,WAAA,GAAc,cAAA,CAAe,QAAA,CAAS,KAAK,CAAA;AACjD,cAAA,IAAI,WAAA,EAAa;AACf,gBAAA,IAAI,WAAA,CAAY,SAAA,IAAa,WAAA,CAAY,OAAA,KAAY,OAAA,EAAS;AAE5D,kBAAA,KAAA,EAAA;AACA,kBAAA,IAAI,UAAU,CAAA,EAAG;AACf,oBAAA,YAAA,GAAe,IAAA;AACf,oBAAA,MAAM,SAAS,QAAA,CAAS,KAAA;AAGxB,oBAAA,MAAM,WAAA,GAA+B;AAAA,sBACnC,IAAA,EAAM,cAAA;AAAA,sBACN,QAAA;AAAA,sBACA,OAAA,EAAS,YAAA;AAAA,sBACT,MAAA;AAAA,sBACA;AAAA,qBACF;AAEA,oBAAA,MAAA,CAAO,KAAK,WAAW,CAAA;AACvB,oBAAA,CAAA,GAAI,CAAA,GAAI,CAAA;AACR,oBAAA;AAAA,kBACF,CAAA,MAAO;AAEL,oBAAA,YAAA,CAAa,KAAK,QAAQ,CAAA;AAC1B,oBAAA,CAAA,EAAA;AAAA,kBACF;AAAA,gBACF,WAAW,CAAC,WAAA,CAAY,SAAA,IAAa,WAAA,CAAY,YAAY,OAAA,EAAS;AAEpE,kBAAA,KAAA,EAAA;AACA,kBAAA,YAAA,CAAa,KAAK,QAAQ,CAAA;AAC1B,kBAAA,CAAA,EAAA;AAAA,gBACF,CAAA,MAAO;AAEL,kBAAA,YAAA,CAAa,KAAK,QAAQ,CAAA;AAC1B,kBAAA,CAAA,EAAA;AAAA,gBACF;AAAA,cACF,CAAA,MAAO;AAEL,gBAAA,YAAA,CAAa,KAAK,QAAQ,CAAA;AAC1B,gBAAA,CAAA,EAAA;AAAA,cACF;AAAA,YACF,CAAA,MAAO;AAEL,cAAA,YAAA,CAAa,KAAK,QAAQ,CAAA;AAC1B,cAAA,CAAA,EAAA;AAAA,YACF;AAAA,UACF;AAEA,UAAA,IAAI,CAAC,YAAA,EAAc;AAEjB,YAAA,MAAM,MAAA,GAAS,KAAK,OAAO,CAAA,CAAA,CAAA;AAE3B,YAAA,MAAM,WAAA,GAA+B;AAAA,cACnC,IAAA,EAAM,cAAA;AAAA,cACN,QAAA;AAAA,cACA,OAAA,EAAS,YAAA;AAAA,cACT,MAAA;AAAA,cACA;AAAA,aACF;AAEA,YAAA,MAAA,CAAO,KAAK,WAAW,CAAA;AACvB,YAAA,CAAA,GAAI,CAAA;AAAA,UACN;AAAA,QACF;AAAA,MACF,CAAA,MAAO;AAEL,QAAA,MAAA,CAAO,KAAK,IAAI,CAAA;AAChB,QAAA,CAAA,EAAA;AAAA,MACF;AAAA,IACF,CAAA,MAAO;AAEL,MAAA,MAAA,CAAO,KAAK,IAAI,CAAA;AAChB,MAAA,CAAA,EAAA;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;;;AClKO,SAAS,UAAU,IAAA,EAAmD;AAC3E,EAAA,OAAO,IAAA,CAAK,SAAS,MAAA,IAAU,QAAA,IAAY,QAAQ,KAAA,CAAM,OAAA,CAAS,KAA4B,MAAM,CAAA;AACtG;AAKO,SAAS,cAAc,IAAA,EAAkC;AAC9D,EAAA,IAAI,CAAC,IAAA,CAAK,MAAA,IAAU,IAAA,CAAK,MAAA,CAAO,WAAW,CAAA,EAAG;AAC5C,IAAA,OAAQ,IAAA,CAAc,KAAA;AAAA,EACxB;AACA,EAAA,OAAQ,KAAc,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,IAAA,CAAK,gBAAgB,CAAC,CAAA;AAC7D;;;ACTO,SAAS,SAAA,GAAqB;AACnC,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAC3B;AAKO,SAAS,QAAA,GAAoB;AAClC,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAC3B;AAKO,SAAS,oBAAA,GAAgC;AAC9C,EAAA,OAAO,OAAO,SAAA,KAAc,WAAA,IAAe,CAAC,CAAC,SAAA,CAAU,SAAA;AACzD;;;ACfO,SAAS,gBAAA,CAAiB,SAAS,QAAA,EAAkB;AAC1D,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,IAAA,CAAK,KAAK,CAAA,CAAA,EAAI,IAAA,CAAK,MAAA,GAAS,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA;AACvE;;;ACPA,IAAM,EAAA,GAAsB;AAAA,EAC1B,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,WAAA;AAAA,IACN,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,WAAA;AAAA,IACN,MAAA,EAAQ,aAAA;AAAA,IACR,UAAA,EAAY,kBAAA;AAAA,IACZ,OAAA,EAAS;AAAA;AAEb,CAAA;AAEA,IAAO,UAAA,GAAQ;;;ACbf,IAAM,IAAA,GAAwB;AAAA,EAC5B,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,0BAAA;AAAA,IACN,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,0BAAA;AAAA,IACN,MAAA,EAAQ,gCAAA;AAAA,IACR,UAAA,EAAY,gCAAA;AAAA,IACZ,OAAA,EAAS;AAAA;AAEb,CAAA;AAEA,IAAO,aAAA,GAAQ","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","/**\n * @file id.ts - ID 生成工具\n * @description 提供各种 ID 生成函数\n */\n\n/**\n * 生成唯一的 parser ID\n * @param prefix - ID 前缀,默认为 'parser'\n * @returns 唯一的 parser ID\n */\nexport function generateParserId(prefix = 'parser'): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}`\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/html.ts","../src/text.ts","../src/env.ts","../src/id.ts","../src/locales/en.ts","../src/locales/zh-cn.ts","../src/format.ts","../src/bem.ts"],"names":["minutes"],"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","/**\n * @file id.ts - ID 生成工具\n * @description 提供各种 ID 生成函数\n */\n\n/**\n * 生成唯一的 parser ID\n * @param prefix - ID 前缀,默认为 'parser'\n * @returns 唯一的 parser ID\n */\nexport function generateParserId(prefix = 'parser'): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}`\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","/**\n * format.ts\n *\n * 格式化工具函数\n */\n\n/**\n * 时长单位标签(国际化)\n */\nconst DURATION_UNITS: Record<string, { s: string; m: string; h: string }> = {\n en: { s: 's', m: 'm', h: 'h' },\n zh: { s: '秒', m: '分钟', h: '小时' },\n ja: { s: '秒', m: '分', h: '時間' },\n ko: { s: '초', m: '분', h: '시간' },\n de: { s: 's', m: 'Min', h: 'Std' },\n fr: { s: 's', m: 'min', h: 'h' },\n es: { s: 's', m: 'min', h: 'h' },\n};\n\n/**\n * 格式化时长(毫秒)为人类可读格式\n * 支持国际化\n *\n * @param ms - 时长(毫秒)\n * @param locale - 语言环境,默认 'en'\n * @returns 格式化后的时长字符串\n *\n * @example\n * formatDuration(500, 'en') // '1s'\n * formatDuration(1500, 'en') // '2s'\n * formatDuration(65000, 'en') // '1m 5s'\n * formatDuration(125000, 'en') // '2m 5s'\n * formatDuration(125000, 'zh') // '2分5秒'\n * formatDuration(3600000, 'en') // '1h'\n * formatDuration(3665000, 'en') // '1h 1m'\n */\nexport function formatDuration(ms: number, locale: string = 'en'): string {\n // 获取单位标签,回退到英文\n const units = DURATION_UNITS[locale] || DURATION_UNITS.en;\n\n // 小于 1 秒,向上取整显示为 1 秒\n if (ms < 1000) {\n return `1${units.s}`;\n }\n\n // 小于 1 分钟,显示秒(向上取整)\n if (ms < 60000) {\n const seconds = Math.ceil(ms / 1000);\n return `${seconds}${units.s}`;\n }\n\n // 小于 1 小时,显示分钟和秒\n if (ms < 3600000) {\n const minutes = Math.floor(ms / 60000);\n const seconds = Math.ceil((ms % 60000) / 1000);\n\n if (seconds === 60) {\n return `${minutes + 1}${units.m}`;\n }\n\n if (seconds === 0) {\n return `${minutes}${units.m}`;\n }\n\n // 中文、日文、韩文使用紧凑格式:2分5秒\n if (locale === 'zh' || locale === 'ja' || locale === 'ko') {\n return `${minutes}${units.m}${seconds}${units.s}`;\n }\n\n // 英文等使用空格分隔:2m 5s\n return `${minutes}${units.m} ${seconds}${units.s}`;\n }\n\n // 大于 1 小时,显示小时和分钟\n const hours = Math.floor(ms / 3600000);\n const minutes = Math.ceil((ms % 3600000) / 60000);\n\n if (minutes === 60) {\n return `${hours + 1}${units.h}`;\n }\n\n if (minutes === 0) {\n return `${hours}${units.h}`;\n }\n\n // 中文、日文、韩文使用紧凑格式:1小时5分钟\n if (locale === 'zh' || locale === 'ja' || locale === 'ko') {\n return `${hours}${units.h}${minutes}${units.m}`;\n }\n\n // 英文等使用空格分隔:1h 5m\n return `${hours}${units.h} ${minutes}${units.m}`;\n}\n\n/**\n * 文件大小单位\n */\nconst FILE_SIZE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB'];\n\n/**\n * 格式化文件大小为人类可读格式\n *\n * @param bytes - 文件大小(字节)\n * @param decimals - 小数位数,默认 1\n * @returns 格式化后的文件大小字符串\n *\n * @example\n * formatFileSize(0) // '0 B'\n * formatFileSize(1024) // '1 KB'\n * formatFileSize(1536) // '1.5 KB'\n * formatFileSize(1048576) // '1 MB'\n * formatFileSize(1073741824) // '1 GB'\n */\nexport function formatFileSize(bytes?: number, decimals: number = 1): string {\n if (bytes === undefined || bytes === null) return '';\n if (bytes === 0) return '0 B';\n\n const k = 1024;\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n const size = bytes / Math.pow(k, i);\n\n // 如果是整数,不显示小数\n if (size % 1 === 0) {\n return `${size} ${FILE_SIZE_UNITS[i]}`;\n }\n\n return `${size.toFixed(decimals)} ${FILE_SIZE_UNITS[i]}`;\n}\n","/**\n * bem.ts\n *\n * BEM 命名工具函数\n * 简单的 BEM 命名生成器,不依赖第三方库\n */\n\n/**\n * BEM 类名生成器\n *\n * @param block - Block 名称\n * @param namespace - 命名空间前缀(可选)\n * @returns BEM 命名函数\n *\n * @example\n * // 默认配置\n * const b = createBem('button');\n * b(); // 'button'\n * b({ active: true }); // 'button button--active'\n * b('icon'); // 'button__icon'\n * b('icon', { large: true }); // 'button__icon button__icon--large'\n *\n * // 带命名空间\n * const b = createBem('button', 'im-');\n * b(); // 'im-button'\n * b({ active: true }); // 'im-button im-button--active'\n * b('icon'); // 'im-button__icon'\n * b('icon', { large: true }); // 'im-button__icon im-button__icon--large'\n */\nexport function createBem(block: string, namespace: string = '') {\n const ns = namespace;\n const blockName = ns ? `${ns}${block}` : block;\n\n /**\n * 生成 BEM 类名\n *\n * @param element - 元素名称(可选)\n * @param modifiers - 修饰符对象或字符串\n * @returns 类名字符串\n */\n return function bem(\n element?: string,\n modifiers?: Record<string, boolean | string | number> | string\n ): string {\n const classes: string[] = [];\n\n // Block 或 Block__Element\n if (element) {\n classes.push(`${blockName}__${element}`);\n } else {\n classes.push(blockName);\n }\n\n // Modifiers\n if (modifiers) {\n if (typeof modifiers === 'string') {\n // 字符串修饰符:'loading' => 'block--loading'\n classes.push(`${blockName}${element ? `__${element}` : ''}--${modifiers}`);\n } else {\n // 对象修饰符:{ active: true, size: 'large' }\n for (const [key, value] of Object.entries(modifiers)) {\n if (value) {\n const modValue = value === true ? '' : `-${value}`;\n classes.push(`${blockName}${element ? `__${element}` : ''}--${key}${modValue}`);\n }\n }\n }\n }\n\n return classes.join(' ');\n };\n}\n\n/**\n * 创建带命名空间的 BEM 生成器\n * 专用于 Incremark Chat UI 组件(im- 前缀)\n *\n * @param block - Block 名称(会自动添加 im- 前缀)\n * @returns BEM 命名函数\n *\n * @example\n * const b = createImBem('cot');\n * b(); // 'im-cot'\n * b({ expanded: true }); // 'im-cot im-cot--expanded'\n * b('header'); // 'im-cot__header'\n * b('icon', 'loading'); // 'im-cot__icon im-cot__icon--loading'\n */\nexport function createImBem(block: string) {\n return createBem(block, 'im-');\n}\n\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@incremark/shared",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-alpha.1",
|
|
4
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",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"typescript": "^5.9.3"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
|
-
"@incremark/core": "0.
|
|
25
|
+
"@incremark/core": "0.4.0-alpha.1"
|
|
26
26
|
},
|
|
27
27
|
"keywords": [
|
|
28
28
|
"incremark",
|