tcdona_unilib 1.0.10 → 1.0.12

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.
Files changed (71) hide show
  1. package/.prettierrc.json +6 -0
  2. package/animejs.ts +13 -1
  3. package/ast-grep.ts +42 -0
  4. package/big.ts +2 -2
  5. package/clipboardy.ts +1 -1
  6. package/dayjs.ts +2 -2
  7. package/dotenvx.ts +15 -2
  8. package/eff/eff.delay.ts +21 -0
  9. package/eff/eff.ts +226 -0
  10. package/eff/effcan.ts +286 -0
  11. package/eff/throwable.ts +11 -0
  12. package/effector.ts +33 -2
  13. package/es-toolkit.ts +1 -7
  14. package/exome.ts +10 -2
  15. package/hono.ts +18 -2
  16. package/hotkeys-js.ts +3 -2
  17. package/idmeta.json +42 -0
  18. package/inquirer.ts +1 -1
  19. package/koka/async.ts +4 -0
  20. package/koka/ctx.ts +4 -0
  21. package/koka/err.ts +4 -0
  22. package/koka/gen.ts +4 -0
  23. package/koka/index.ts +2 -0
  24. package/koka/opt.ts +4 -0
  25. package/koka/result.ts +10 -0
  26. package/koka/task.ts +4 -0
  27. package/koka-domain.ts +18 -0
  28. package/koka.ts +34 -0
  29. package/magic-regexp.ts +28 -2
  30. package/marked.ts +28 -2
  31. package/nanoid.ts +7 -1
  32. package/nanostores.ts +31 -2
  33. package/neverthrow.ts +2 -2
  34. package/package.json +15 -15
  35. package/pathe.ts +16 -1
  36. package/pinyin-pro.ts +16 -2
  37. package/prettier.ts +20 -2
  38. package/staticMeta/enum.api.ts +111 -82
  39. package/staticMeta/err.ts +64 -0
  40. package/staticMeta/file.yml.ts +12 -12
  41. package/staticMeta/md.html2md.ts +38 -0
  42. package/staticMeta/md.md2html.ts +203 -0
  43. package/staticMeta/path.init.ts +12 -12
  44. package/staticMeta/string.nanoid.ts +7 -7
  45. package/staticMeta/url.ts +57 -54
  46. package/tinypool.ts +29 -2
  47. package/turndown.ts +1 -1
  48. package/vite.ts +2 -2
  49. package/viteplugin/md.plugin.dist.d.ts +18 -0
  50. package/viteplugin/md.plugin.dist.js +1133 -0
  51. package/viteplugin/md.plugin.ts +22 -0
  52. package/viteplugin/vite-env.d.ts +6 -0
  53. package/viteplugin/vite.config.ts +62 -0
  54. package/vue.ts +2 -12
  55. package/zod.ts +19 -2
  56. package/zx.ts +25 -1
  57. package/@ast-grep.ts +0 -18
  58. package/comctx.ts +0 -2
  59. package/hono/cors.ts +0 -1
  60. package/hono/logger.ts +0 -1
  61. package/hono/timeout.ts +0 -1
  62. package/staticMeta/ast.scan.ts +0 -131
  63. package/staticMeta/ast.ts +0 -259
  64. package/staticMeta/eff.delay.ts +0 -17
  65. package/staticMeta/eff.ts +0 -203
  66. package/staticMeta/iduniq.ts +0 -320
  67. package/staticMeta/idupdate.ts +0 -374
  68. package/staticMeta/pkg.json.ts +0 -138
  69. package/staticMeta/project.ts +0 -98
  70. package/staticMeta/sync.ts +0 -296
  71. package/tcproject.ts +0 -60
@@ -2,37 +2,45 @@
2
2
  * 日志和错误处理 API:基于文件路径和事件 ID 生成统一的日志前缀
3
3
  */
4
4
 
5
+ // ==================== 类型扩展 ====================
6
+
7
+ declare global {
8
+ interface ErrorConstructor {
9
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void
10
+ }
11
+ }
12
+
5
13
  // ==================== 日志配置 ====================
6
14
 
7
- const cons = console;
15
+ const cons = console
8
16
 
9
17
  export enum LogLevel {
10
- DEBUG = 0,
11
- INFO = 1,
12
- WARN = 2,
13
- ERROR = 3,
14
- FATAL = 4,
18
+ DEBUG = 0,
19
+ INFO = 1,
20
+ WARN = 2,
21
+ ERROR = 3,
22
+ FATAL = 4,
15
23
  }
16
24
 
17
- const logLevelUsed = LogLevel.INFO;
25
+ const logLevelUsed = LogLevel.INFO
18
26
 
19
27
  const logFnMap: Record<LogLevel, (...args: unknown[]) => void> = {
20
- [LogLevel.DEBUG]: cons.debug,
21
- [LogLevel.INFO]: cons.log,
22
- [LogLevel.WARN]: cons.warn,
23
- [LogLevel.ERROR]: cons.error,
24
- [LogLevel.FATAL]: cons.error,
25
- };
28
+ [LogLevel.DEBUG]: cons.debug,
29
+ [LogLevel.INFO]: cons.log,
30
+ [LogLevel.WARN]: cons.warn,
31
+ [LogLevel.ERROR]: cons.error,
32
+ [LogLevel.FATAL]: cons.error,
33
+ }
26
34
 
27
35
  // ==================== 日志链类型 ====================
28
36
 
29
37
  export interface TcLog {
30
- debug: (...args: unknown[]) => void;
31
- info: (...args: unknown[]) => void;
32
- log: (...args: unknown[]) => void;
33
- warn: (...args: unknown[]) => void;
34
- error: (...args: unknown[]) => void;
35
- fatal: (...args: unknown[]) => void;
38
+ debug: (...args: unknown[]) => void
39
+ info: (...args: unknown[]) => void
40
+ log: (...args: unknown[]) => void
41
+ warn: (...args: unknown[]) => void
42
+ error: (...args: unknown[]) => void
43
+ fatal: (...args: unknown[]) => void
36
44
  }
37
45
 
38
46
  // ==================== 新的 fileId 配置类型 ====================
@@ -41,102 +49,123 @@ export interface TcLog {
41
49
  * fileId 的配置对象:包含事件 ID、源文件、标签
42
50
  */
43
51
  export interface FileIdConf {
44
- id: string; // 事件标识 key
45
- srcFile: string; // 源文件路径
46
- tag: string[]; // 标签数组(必须)
52
+ id: string // 事件标识 key
53
+ srcFile: string // 源文件路径
54
+ tag: string[] // 标签数组(必须)
47
55
  }
48
56
 
49
57
  /**
50
58
  * fileId:包含配置和日志方法(info, warn, error, debug)
51
59
  */
52
60
  export interface FileId {
53
- readonly conf: FileIdConf;
61
+ readonly conf: FileIdConf
54
62
 
55
- // 日志方法
56
- info: (...args: unknown[]) => void;
57
- warn: (...args: unknown[]) => void;
58
- error: (...args: unknown[]) => void;
59
- debug: (...args: unknown[]) => void;
63
+ // 日志方法
64
+ info: (...args: unknown[]) => void
65
+ warn: (...args: unknown[]) => void
66
+ error: (...args: unknown[]) => void
67
+ debug: (...args: unknown[]) => void
60
68
  }
61
69
 
62
70
  /**
63
71
  * 生成格式为 YYMMDD-HHmmss 的时间戳
64
72
  */
65
73
  const getTimestamp = (): string => {
66
- const now = new Date();
67
- const yy = String(now.getFullYear()).slice(-2).padStart(2, '0');
68
- const mm = String(now.getMonth() + 1).padStart(2, '0');
69
- const dd = String(now.getDate()).padStart(2, '0');
70
- const hh = String(now.getHours()).padStart(2, '0');
71
- const min = String(now.getMinutes()).padStart(2, '0');
72
- const ss = String(now.getSeconds()).padStart(2, '0');
73
- return `${yy}${mm}${dd}-${hh}${min}${ss}`;
74
- };
74
+ const now = new Date()
75
+ const yy = String(now.getFullYear()).slice(-2).padStart(2, '0')
76
+ const mm = String(now.getMonth() + 1).padStart(2, '0')
77
+ const dd = String(now.getDate()).padStart(2, '0')
78
+ const hh = String(now.getHours()).padStart(2, '0')
79
+ const min = String(now.getMinutes()).padStart(2, '0')
80
+ const ss = String(now.getSeconds()).padStart(2, '0')
81
+ return `${yy}${mm}${dd}-${hh}${min}${ss}`
82
+ }
75
83
 
76
84
  export class TcErr extends Error {
77
- public fildId: FileId;
78
- public ctx: Record<string, unknown>;
79
- public cause?: Error; // 显式声明 cause 属性
80
-
81
- constructor(
82
- ctx: { fildId: FileId; cause?: unknown } & Record<string, unknown>,
83
- ) {
84
- const { fildId, cause, ...rest } = ctx;
85
- super(fildId.conf?.id ?? 'TcErrId');
86
- Object.setPrototypeOf(this, new.target.prototype);
87
- this.name = 'TcErr';
88
- this.fildId = fildId;
89
- if (cause) {
90
- this.cause = cause as Error;
91
- }
92
- this.ctx = rest;
93
- if (Error.captureStackTrace) {
94
- Error.captureStackTrace(this, TcErr);
95
- }
96
-
97
- cons.error(getTimestamp(), fildId, cause, rest);
85
+ public fileId: FileId
86
+ public ctx: Record<string, unknown>
87
+ public cause?: Error // 显式声明 cause 属性
88
+
89
+ constructor(
90
+ ctx: { fileId: FileId; cause?: unknown } & Record<string, unknown>,
91
+ ) {
92
+ const { fileId, cause, ...rest } = ctx
93
+ super(fileId.conf?.id ?? 'TcErrId')
94
+ Object.setPrototypeOf(this, new.target.prototype)
95
+ this.name = 'TcErr'
96
+ this.fileId = fileId
97
+ if (cause) {
98
+ this.cause = cause as Error
98
99
  }
100
+ this.ctx = rest
101
+ if (Error.captureStackTrace) {
102
+ Error.captureStackTrace(this, TcErr)
103
+ }
104
+
105
+ cons.error(
106
+ getTimestamp(),
107
+ `[${fileId.conf.srcFile}:${fileId.conf.id}]${fileId.conf.tag.length > 0 ? `[${fileId.conf.tag.join(', ')}]` : ''}`,
108
+ cause,
109
+ rest,
110
+ )
111
+ }
112
+ }
113
+
114
+ export type TcErrObj = Record<string, unknown> & {
115
+ fileId: FileId
116
+ cause?: Error | unknown
117
+ }
118
+
119
+ export const tcerrobj = (errObj: TcErrObj): TcErrObj => {
120
+ const { fileId, cause, ...ctx } = errObj
121
+ // 将 Error 对象传递给 cons.error,Node.js 会自动格式化堆栈信息
122
+ cons.error(
123
+ `${getTimestamp()} [${fileId.conf.srcFile}:${fileId.conf.id}]${fileId.conf.tag.length > 0 ? `[${fileId.conf.tag.join(', ')}]` : ''}`,
124
+ { cause, ...ctx },
125
+ )
126
+
127
+ return errObj
99
128
  }
100
129
 
101
130
  // ==================== 内部日志函数工厂 ====================
102
131
 
103
132
  const createLogFn = (
104
- level: LogLevel,
105
- prefix: string,
133
+ level: LogLevel,
134
+ prefix: string,
106
135
  ): ((...args: unknown[]) => void) => {
107
- if (level < logLevelUsed) return () => { };
136
+ if (level < logLevelUsed) return () => {}
108
137
 
109
- const logFn = logFnMap[level] ?? (() => { });
110
- return logFn.bind(null, `${getTimestamp()} ${prefix}`);
111
- };
138
+ const logFn = logFnMap[level] ?? (() => {})
139
+ return logFn.bind(null, `${getTimestamp()} ${prefix}`)
140
+ }
112
141
 
113
142
  // ==================== 新的 fileInit API ====================
114
143
 
115
144
  /**
116
145
  * 工厂函数类型:接收事件 ID 和可选标签,返回 FileId
117
146
  */
118
- export type fileIdFactory = (id: string, ...tag: string[]) => FileId;
147
+ export type fileIdFactory = (id: string, ...tag: string[]) => FileId
119
148
 
120
149
  /**
121
150
  * 为模块创建 fileId 工厂函数
122
151
  * @param modulePath 模块路径(相对路径字符串)
123
152
  */
124
153
  export function fileInit(modulePath: string): fileIdFactory {
125
- return (id: string, ...tag: string[]): FileId => {
126
- const prefix = `[${modulePath}:${id}]${tag.length > 0 ? `[${tag.join(', ')}]` : ''}`;
127
-
128
- const conf: FileIdConf = {
129
- id,
130
- srcFile: modulePath,
131
- tag,
132
- };
133
-
134
- return {
135
- conf,
136
- info: createLogFn(LogLevel.INFO, prefix),
137
- warn: createLogFn(LogLevel.WARN, prefix),
138
- error: createLogFn(LogLevel.ERROR, prefix),
139
- debug: createLogFn(LogLevel.DEBUG, prefix),
140
- };
141
- };
154
+ return (id: string, ...tag: string[]): FileId => {
155
+ const prefix = `[${modulePath}:${id}]${tag.length > 0 ? `[${tag.join(', ')}]` : ''}`
156
+
157
+ const conf: FileIdConf = {
158
+ id,
159
+ srcFile: modulePath,
160
+ tag,
161
+ }
162
+
163
+ return {
164
+ conf,
165
+ info: createLogFn(LogLevel.INFO, prefix),
166
+ warn: createLogFn(LogLevel.WARN, prefix),
167
+ error: createLogFn(LogLevel.ERROR, prefix),
168
+ debug: createLogFn(LogLevel.DEBUG, prefix),
169
+ }
170
+ }
142
171
  }
@@ -0,0 +1,64 @@
1
+ import { z } from 'zod'
2
+ import { Result, ok, err } from 'neverthrow'
3
+ import { jsonParse } from '../eff/throwable'
4
+ import { fileInit, TcErrObj, tcerrobj } from './enum.api'
5
+
6
+ const fileId = fileInit('src/staticMeta/err.ts')
7
+
8
+ /**
9
+ * Zod 错误消息解析后的格式
10
+ */
11
+ export type ZodErrorMessage = {
12
+ code: string
13
+ message: string
14
+ path: string[]
15
+ value: string
16
+ }[]
17
+
18
+ /**
19
+ * Zod 解析错误类型(JSON 解析成功的情况)
20
+ */
21
+ export type ZodParseError = TcErrObj & {
22
+ zodErrors: ZodErrorMessage
23
+ }
24
+
25
+ /**
26
+ * Zod 验证并返回 Result<T, ZodParseError>
27
+ *
28
+ * 验证成功时返回 ok(data),失败时返回 err(ZodParseError),
29
+ * 并自动将 Zod 的 validated.error 作为 TcErr 的 cause。
30
+ * 同时给 fileId 添加 tag "zodParseError" 标记。
31
+ *
32
+ * 返回的错误类型有两种情况:
33
+ * - ZodParseErrorJson: 当 error.message 可以解析为 JSON 时,包含 zodErrors 属性
34
+ * - ZodParseErrorString: 当 error.message 无法解析为 JSON 时,包含 message 属性
35
+ */
36
+ export const zodParse = <T extends z.ZodType>(
37
+ schema: T,
38
+ data: unknown,
39
+ context: Record<string, unknown>,
40
+ ): Result<z.infer<T>, ZodParseError> => {
41
+ const validated = schema.safeParse(data)
42
+
43
+ if (validated.success) {
44
+ return ok(validated.data)
45
+ }
46
+
47
+ return err(
48
+ jsonParse(validated.error.message).match(
49
+ (message: ZodErrorMessage): ZodParseError =>
50
+ tcerrobj({
51
+ fileId: fileId('schemaValidationFailed', 'zodParseError-json'),
52
+ ...message,
53
+ schema,
54
+ data,
55
+ ...context,
56
+ }) as ZodParseError,
57
+ () =>
58
+ fileId('schemaValidationFailed', 'zodParseError-string').error(
59
+ validated.error.message,
60
+ context,
61
+ ) as unknown as ZodParseError,
62
+ ),
63
+ )
64
+ }
@@ -1,18 +1,18 @@
1
- import { fs, YAML } from 'zx';
1
+ import { fs, YAML } from 'zx'
2
2
 
3
3
  /**
4
4
  * YAML 文件读写:无 data 参数时读取,有 data 参数时写入
5
5
  */
6
6
  export function yml(path: string, data?: unknown): unknown {
7
- if (typeof data !== 'undefined') {
8
- fs.writeFileSync(
9
- path,
10
- // @ts-expect-error YAML.stringify 类型定义有误
11
- YAML.stringify(data, { singleQuote: true, sortKeys: true }),
12
- 'utf-8',
13
- );
14
- } else {
15
- const ymlContent = fs.readFileSync(path, 'utf-8');
16
- return YAML.parse(ymlContent);
17
- }
7
+ if (typeof data !== 'undefined') {
8
+ fs.writeFileSync(
9
+ path,
10
+ // @ts-expect-error YAML.stringify 类型定义有误
11
+ YAML.stringify(data, { singleQuote: true, sortKeys: true }),
12
+ 'utf-8',
13
+ )
14
+ } else {
15
+ const ymlContent = fs.readFileSync(path, 'utf-8')
16
+ return YAML.parse(ymlContent)
17
+ }
18
18
  }
@@ -0,0 +1,38 @@
1
+ import { type MdMapping } from './md.md2html.js'
2
+
3
+ const ELEMENT_NODE = 1
4
+ const TEXT_NODE = 3
5
+
6
+ export const reconstructMarkdown = (
7
+ container: HTMLElement,
8
+ idMap: Record<string, MdMapping>,
9
+ ): string => {
10
+ const parts: string[] = []
11
+
12
+ const walk = (node: Node): void => {
13
+ if (node.nodeType === ELEMENT_NODE) {
14
+ const el = node as HTMLElement
15
+ const mdId = el.getAttribute('data-md-id')
16
+
17
+ if (mdId && idMap[mdId]) {
18
+ parts.push(idMap[mdId].originalMd)
19
+ return
20
+ }
21
+ }
22
+
23
+ if (node.nodeType === TEXT_NODE) {
24
+ const text = node.textContent || ''
25
+ if (text.trim()) {
26
+ parts.push(text)
27
+ }
28
+ return
29
+ }
30
+
31
+ for (const child of Array.from(node.childNodes)) {
32
+ walk(child)
33
+ }
34
+ }
35
+
36
+ walk(container)
37
+ return parts.join('')
38
+ }
@@ -0,0 +1,203 @@
1
+ import { Lexer, type Token, type Tokens } from 'marked'
2
+
3
+ export interface MdMapping {
4
+ originalMd: string
5
+ }
6
+
7
+ export interface ParseResult {
8
+ html: string
9
+ idMap: Record<string, MdMapping>
10
+ }
11
+
12
+ // const resetIdCounter = (): void => {
13
+ // idCounter = 0
14
+ // }
15
+
16
+ const escapeHtml = (text: string): string => {
17
+ return text
18
+ .replace(/&/g, '&amp;')
19
+ .replace(/</g, '&lt;')
20
+ .replace(/>/g, '&gt;')
21
+ .replace(/"/g, '&quot;')
22
+ }
23
+
24
+ export const parseMarkdownWithIds = (markdown: string): ParseResult => {
25
+ let idCounter = 0
26
+ const generateId = (prefix: string): string => `${prefix}-${idCounter++}`
27
+ // resetIdCounter()
28
+ const idMap: Record<string, MdMapping> = {}
29
+ const tokens = Lexer.lex(markdown)
30
+
31
+ const processToken = (token: Token): string => {
32
+ switch (token.type) {
33
+ case 'heading': {
34
+ const t = token as Tokens.Heading
35
+ const id = generateId('h')
36
+ idMap[id] = { originalMd: t.raw }
37
+ const content = t.tokens ? t.tokens.map(processToken).join('') : t.text
38
+ return `<h${t.depth} data-md-id="${id}">${content}</h${t.depth}>\n`
39
+ }
40
+
41
+ case 'paragraph': {
42
+ const t = token as Tokens.Paragraph
43
+ const id = generateId('p')
44
+ idMap[id] = { originalMd: t.raw }
45
+ const content = t.tokens ? t.tokens.map(processToken).join('') : t.text
46
+ return `<p data-md-id="${id}">${content}</p>\n`
47
+ }
48
+
49
+ case 'code': {
50
+ const t = token as Tokens.Code
51
+ const id = generateId('pre')
52
+ idMap[id] = { originalMd: t.raw }
53
+ const langClass = t.lang
54
+ ? ` class="language-${escapeHtml(t.lang)}"`
55
+ : ''
56
+ return `<pre data-md-id="${id}"><code${langClass}>${escapeHtml(t.text)}</code></pre>\n`
57
+ }
58
+
59
+ case 'codespan': {
60
+ const t = token as Tokens.Codespan
61
+ const id = generateId('code')
62
+ idMap[id] = { originalMd: t.raw }
63
+ return `<code data-md-id="${id}">${escapeHtml(t.text)}</code>`
64
+ }
65
+
66
+ case 'blockquote': {
67
+ const t = token as Tokens.Blockquote
68
+ const id = generateId('blockquote')
69
+ idMap[id] = { originalMd: t.raw }
70
+ const content = t.tokens ? t.tokens.map(processToken).join('') : t.text
71
+ return `<blockquote data-md-id="${id}">\n${content}</blockquote>\n`
72
+ }
73
+
74
+ case 'list': {
75
+ const t = token as Tokens.List
76
+ const id = generateId('list')
77
+ idMap[id] = { originalMd: t.raw }
78
+ const tag = t.ordered ? 'ol' : 'ul'
79
+ const items = t.items.map((item) => processToken(item)).join('')
80
+ return `<${tag} data-md-id="${id}">\n${items}</${tag}>\n`
81
+ }
82
+
83
+ case 'list_item': {
84
+ const t = token as Tokens.ListItem
85
+ const id = generateId('li')
86
+ idMap[id] = { originalMd: t.raw }
87
+ const content = t.tokens ? t.tokens.map(processToken).join('') : t.text
88
+ return `<li data-md-id="${id}">${content}</li>\n`
89
+ }
90
+
91
+ case 'strong': {
92
+ const t = token as Tokens.Strong
93
+ const id = generateId('strong')
94
+ idMap[id] = { originalMd: t.raw }
95
+ const content = t.tokens ? t.tokens.map(processToken).join('') : t.text
96
+ return `<strong data-md-id="${id}">${content}</strong>`
97
+ }
98
+
99
+ case 'em': {
100
+ const t = token as Tokens.Em
101
+ const id = generateId('em')
102
+ idMap[id] = { originalMd: t.raw }
103
+ const content = t.tokens ? t.tokens.map(processToken).join('') : t.text
104
+ return `<em data-md-id="${id}">${content}</em>`
105
+ }
106
+
107
+ case 'link': {
108
+ const t = token as Tokens.Link
109
+ const id = generateId('a')
110
+ idMap[id] = { originalMd: t.raw }
111
+ const content = t.tokens ? t.tokens.map(processToken).join('') : t.text
112
+ const title = t.title ? ` title="${escapeHtml(t.title)}"` : ''
113
+ return `<a data-md-id="${id}" href="${escapeHtml(t.href)}"${title}>${content}</a>`
114
+ }
115
+
116
+ case 'image': {
117
+ const t = token as Tokens.Image
118
+ const id = generateId('img')
119
+ idMap[id] = { originalMd: t.raw }
120
+ const title = t.title ? ` title="${escapeHtml(t.title)}"` : ''
121
+ return `<img data-md-id="${id}" src="${escapeHtml(t.href)}" alt="${escapeHtml(t.text)}"${title}>`
122
+ }
123
+
124
+ case 'text': {
125
+ const t = token as Tokens.Text
126
+ if ('tokens' in t && t.tokens) {
127
+ return t.tokens.map(processToken).join('')
128
+ }
129
+ return t.text
130
+ }
131
+
132
+ case 'space':
133
+ return '\n'
134
+
135
+ case 'hr': {
136
+ const t = token as Tokens.Hr
137
+ const id = generateId('hr')
138
+ idMap[id] = { originalMd: t.raw }
139
+ return `<hr data-md-id="${id}">\n`
140
+ }
141
+
142
+ case 'br':
143
+ return '<br>'
144
+
145
+ case 'del': {
146
+ const t = token as Tokens.Del
147
+ const id = generateId('del')
148
+ idMap[id] = { originalMd: t.raw }
149
+ const content = t.tokens ? t.tokens.map(processToken).join('') : t.text
150
+ return `<del data-md-id="${id}">${content}</del>`
151
+ }
152
+
153
+ case 'html': {
154
+ const t = token as Tokens.HTML
155
+ return t.raw
156
+ }
157
+
158
+ case 'table': {
159
+ const t = token as Tokens.Table
160
+ const id = generateId('table')
161
+ idMap[id] = { originalMd: t.raw }
162
+
163
+ const headerCells = t.header
164
+ .map((cell, i) => {
165
+ const align = t.align[i] ? ` style="text-align:${t.align[i]}"` : ''
166
+ const content = cell.tokens
167
+ ? cell.tokens.map(processToken).join('')
168
+ : cell.text
169
+ return `<th${align}>${content}</th>`
170
+ })
171
+ .join('')
172
+
173
+ const bodyRows = t.rows
174
+ .map((row) => {
175
+ const cells = row
176
+ .map((cell, i) => {
177
+ const align = t.align[i]
178
+ ? ` style="text-align:${t.align[i]}"`
179
+ : ''
180
+ const content = cell.tokens
181
+ ? cell.tokens.map(processToken).join('')
182
+ : cell.text
183
+ return `<td${align}>${content}</td>`
184
+ })
185
+ .join('')
186
+ return `<tr>${cells}</tr>`
187
+ })
188
+ .join('\n')
189
+
190
+ return `<table data-md-id="${id}">
191
+ <thead><tr>${headerCells}</tr></thead>
192
+ <tbody>${bodyRows}</tbody>
193
+ </table>\n`
194
+ }
195
+
196
+ default:
197
+ return ''
198
+ }
199
+ }
200
+
201
+ const html = tokens.map(processToken).join('')
202
+ return { html, idMap }
203
+ }
@@ -1,5 +1,5 @@
1
- import { dirname, relative, resolve } from 'node:path';
2
- import { fileURLToPath } from 'node:url';
1
+ import { dirname, relative, resolve } from 'node:path'
2
+ import { fileURLToPath } from 'node:url'
3
3
 
4
4
  /**
5
5
  * 初始化模块的路径元信息(__filename, __dirname, __relative, resolve)
@@ -7,15 +7,15 @@ import { fileURLToPath } from 'node:url';
7
7
  * @param root 根目录路径
8
8
  */
9
9
  export function pathMeta(metaUrl: string, root: string) {
10
- const __filename = fileURLToPath(metaUrl);
11
- const __dirname = dirname(__filename);
12
- const __rootname = resolve(root);
10
+ const __filename = fileURLToPath(metaUrl)
11
+ const __dirname = dirname(__filename)
12
+ const __rootname = resolve(__dirname, root)
13
13
 
14
- return {
15
- __rootname,
16
- __dirname,
17
- __filename,
18
- resolve: resolve.bind(null, __dirname),
19
- __relative: relative(__rootname, __filename),
20
- } as const;
14
+ return {
15
+ __rootname,
16
+ __dirname,
17
+ __filename,
18
+ resolve: resolve.bind(null, __dirname),
19
+ __relative: relative(__rootname, __filename),
20
+ } as const
21
21
  }
@@ -1,14 +1,14 @@
1
- import { customAlphabet } from 'nanoid';
1
+ import { customAlphabet } from 'nanoid'
2
2
 
3
3
  /**
4
4
  * 生成 18 字符的唯一 ID(使用自定义字符集,排除易混淆字符)
5
5
  */
6
6
  export const tcNanoid = customAlphabet(
7
- 'useandom26T198340PX75pxJACKVERYMINDBUSHWOLFGQZbfghjklqvwyzrict',
8
- 18,
9
- );
7
+ 'useandom26T198340PX75pxJACKVERYMINDBUSHWOLFGQZbfghjklqvwyzrict',
8
+ 18,
9
+ )
10
10
 
11
11
  export const lowerNanoid = customAlphabet(
12
- 'useandom2619834075pxbfghjklqvwyzrict',
13
- 18,
14
- );
12
+ 'useandom2619834075pxbfghjklqvwyzrict',
13
+ 18,
14
+ )