tcdona_unilib 1.0.11 → 1.0.14
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/.prettierrc.json +6 -0
- package/animejs.ts +13 -1
- package/ast-grep.ts +42 -0
- package/big.ts +2 -2
- package/clipboardy.ts +1 -1
- package/dayjs.ts +2 -2
- package/dotenvx.ts +15 -2
- package/eff/aff.ts +161 -0
- package/eff/aff.util.ts +218 -0
- package/eff/eff.delay.ts +21 -0
- package/eff/eff.ts +225 -0
- package/eff/effcan.ts +286 -0
- package/eff/throwable.ts +11 -0
- package/effector.ts +33 -2
- package/es-toolkit.ts +1 -7
- package/exome.ts +10 -2
- package/hono.ts +18 -2
- package/hotkeys-js.ts +3 -2
- package/idmeta.json +42 -0
- package/inquirer.ts +1 -1
- package/koka/async.ts +2 -7
- package/koka/ctx.ts +2 -9
- package/koka/err.ts +2 -9
- package/koka/gen.ts +2 -9
- package/koka/index.ts +1 -1
- package/koka/opt.ts +2 -7
- package/koka/result.ts +6 -9
- package/koka/task.ts +2 -8
- package/koka-domain.ts +13 -16
- package/koka.ts +29 -34
- package/magic-regexp.ts +28 -2
- package/marked.ts +28 -2
- package/nanoid.ts +7 -1
- package/nanostores.ts +31 -2
- package/neverthrow.ts +2 -2
- package/package.json +24 -33
- package/pathe.ts +16 -1
- package/pinyin-pro.ts +16 -2
- package/prettier.ts +20 -2
- package/staticMeta/enum.api.ts +111 -82
- package/staticMeta/err.ts +64 -0
- package/staticMeta/file.yml.ts +22 -13
- package/staticMeta/md.html2md.ts +38 -0
- package/staticMeta/md.md2html.ts +203 -0
- package/staticMeta/path.init.ts +12 -12
- package/staticMeta/string.nanoid.ts +7 -7
- package/staticMeta/url.ts +57 -54
- package/tinypool.ts +29 -2
- package/turndown.ts +1 -1
- package/vite.ts +2 -2
- package/viteplugin/md.plugin.dist.d.ts +18 -0
- package/viteplugin/md.plugin.dist.js +1133 -0
- package/viteplugin/md.plugin.ts +22 -0
- package/viteplugin/vite-env.d.ts +6 -0
- package/viteplugin/vite.config.ts +62 -0
- package/vue.ts +2 -12
- package/zod.ts +19 -2
- package/zx.ts +25 -1
- package/@ast-grep.ts +0 -18
- package/comctx.ts +0 -2
- package/hono/cors.ts +0 -1
- package/hono/logger.ts +0 -1
- package/hono/timeout.ts +0 -1
- package/staticMeta/ast.scan.ts +0 -131
- package/staticMeta/ast.ts +0 -259
- package/staticMeta/eff.delay.ts +0 -17
- package/staticMeta/eff.ts +0 -203
- package/staticMeta/iduniq.ts +0 -320
- package/staticMeta/idupdate.ts +0 -374
- package/staticMeta/pkg.json.ts +0 -138
- package/staticMeta/project.ts +0 -98
- package/staticMeta/sync.ts +0 -296
package/staticMeta/enum.api.ts
CHANGED
|
@@ -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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
61
|
+
readonly conf: FileIdConf
|
|
54
62
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
+
rest,
|
|
109
|
+
)
|
|
110
|
+
cons.log(cause)
|
|
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
|
-
|
|
105
|
-
|
|
133
|
+
level: LogLevel,
|
|
134
|
+
prefix: string,
|
|
106
135
|
): ((...args: unknown[]) => void) => {
|
|
107
|
-
|
|
136
|
+
if (level < logLevelUsed) return () => {}
|
|
108
137
|
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
+
}
|
package/staticMeta/file.yml.ts
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
|
-
import { fs, YAML } from 'zx'
|
|
2
|
-
|
|
1
|
+
import { fs, YAML } from 'zx'
|
|
3
2
|
/**
|
|
4
3
|
* YAML 文件读写:无 data 参数时读取,有 data 参数时写入
|
|
5
4
|
*/
|
|
6
5
|
export function yml(path: string, data?: unknown): unknown {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
if (typeof data !== 'undefined') {
|
|
7
|
+
fs.writeFileSync(
|
|
8
|
+
path,
|
|
9
|
+
// @ts-expect-error YAML.stringify 类型定义有误
|
|
10
|
+
YAML.stringify(data, { singleQuote: true }),
|
|
11
|
+
'utf-8',
|
|
12
|
+
)
|
|
13
|
+
} else {
|
|
14
|
+
const ymlContent = fs.readFileSync(path, 'utf-8')
|
|
15
|
+
return YAML.parse(ymlContent)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
import { default as jsYAML } from 'js-yaml'
|
|
20
|
+
export const yml2 = (path: string, data?: unknown): unknown => {
|
|
21
|
+
if (typeof data !== 'undefined') {
|
|
22
|
+
fs.writeFileSync(path, jsYAML.dump(data, { sortKeys: true }), 'utf-8')
|
|
23
|
+
} else {
|
|
24
|
+
const ymlContent = fs.readFileSync(path, 'utf-8')
|
|
25
|
+
return jsYAML.load(ymlContent)
|
|
26
|
+
}
|
|
18
27
|
}
|
|
@@ -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, '&')
|
|
19
|
+
.replace(/</g, '<')
|
|
20
|
+
.replace(/>/g, '>')
|
|
21
|
+
.replace(/"/g, '"')
|
|
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
|
+
}
|
package/staticMeta/path.init.ts
CHANGED
|
@@ -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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const __filename = fileURLToPath(metaUrl)
|
|
11
|
+
const __dirname = dirname(__filename)
|
|
12
|
+
const __rootname = resolve(__dirname, root)
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
)
|
|
7
|
+
'useandom26T198340PX75pxJACKVERYMINDBUSHWOLFGQZbfghjklqvwyzrict',
|
|
8
|
+
18,
|
|
9
|
+
)
|
|
10
10
|
|
|
11
11
|
export const lowerNanoid = customAlphabet(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
)
|
|
12
|
+
'useandom2619834075pxbfghjklqvwyzrict',
|
|
13
|
+
18,
|
|
14
|
+
)
|