@airalogy/aimd-renderer 2.4.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/README.md +117 -0
- package/README.zh-CN.md +101 -0
- package/dist/aimd-renderer.css +1 -0
- package/dist/html.js +11 -0
- package/dist/index.js +439 -0
- package/dist/processor-Cv8E7QsA.js +11539 -0
- package/dist/vue.js +17 -0
- package/package.json +84 -0
- package/src/__tests__/renderer.test.ts +388 -0
- package/src/common/annotateStepReferences.ts +110 -0
- package/src/common/assignerHighlighting.ts +159 -0
- package/src/common/assignerVisibility.ts +289 -0
- package/src/common/eventKeys.ts +10 -0
- package/src/common/figureNumbering.ts +126 -0
- package/src/common/processor.ts +1554 -0
- package/src/common/quiz-preview.ts +22 -0
- package/src/common/unified-token-renderer.ts +810 -0
- package/src/css.d.ts +1 -0
- package/src/html/index.ts +33 -0
- package/src/index.ts +114 -0
- package/src/locales.ts +256 -0
- package/src/styles/katex.css +2 -0
- package/src/vue/index.ts +47 -0
- package/src/vue/vue-renderer.ts +1449 -0
package/src/css.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
declare module "*.css" {}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML rendering exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
createCustomElementAimdRenderer,
|
|
7
|
+
createHtmlProcessor,
|
|
8
|
+
renderToHtml,
|
|
9
|
+
renderToHtmlSync,
|
|
10
|
+
parseAndExtract,
|
|
11
|
+
} from '../common/processor'
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
createAimdRendererMessages,
|
|
15
|
+
DEFAULT_AIMD_RENDERER_LOCALE,
|
|
16
|
+
resolveAimdRendererLocale,
|
|
17
|
+
} from '../locales'
|
|
18
|
+
|
|
19
|
+
export type { ProcessorOptions } from '@airalogy/aimd-core/types'
|
|
20
|
+
export type {
|
|
21
|
+
AimdAssignerVisibility,
|
|
22
|
+
AimdHtmlNodeRenderer,
|
|
23
|
+
AimdHtmlRendererContext,
|
|
24
|
+
CustomElementAimdRendererOptions,
|
|
25
|
+
AimdRendererOptions,
|
|
26
|
+
RenderResult,
|
|
27
|
+
} from '../common/processor'
|
|
28
|
+
export type {
|
|
29
|
+
AimdRendererI18nOptions,
|
|
30
|
+
AimdRendererLocale,
|
|
31
|
+
AimdRendererMessages,
|
|
32
|
+
AimdRendererMessagesInput,
|
|
33
|
+
} from '../locales'
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @airalogy/aimd-renderer
|
|
3
|
+
*
|
|
4
|
+
* AIMD rendering engines for HTML and Vue
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Common exports
|
|
8
|
+
export {
|
|
9
|
+
createCustomElementAimdRenderer,
|
|
10
|
+
createHtmlProcessor,
|
|
11
|
+
createRenderer,
|
|
12
|
+
defaultRenderer,
|
|
13
|
+
parseAndExtract,
|
|
14
|
+
renderToHtml,
|
|
15
|
+
renderToHtmlSync,
|
|
16
|
+
renderToVue,
|
|
17
|
+
} from './common/processor'
|
|
18
|
+
|
|
19
|
+
export {
|
|
20
|
+
createAimdRendererMessages,
|
|
21
|
+
DEFAULT_AIMD_RENDERER_LOCALE,
|
|
22
|
+
getAimdRendererQuizTypeLabel,
|
|
23
|
+
resolveAimdRendererLocale,
|
|
24
|
+
} from './locales'
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
bubbleMenuEventKey,
|
|
28
|
+
draftEventKey,
|
|
29
|
+
fieldEventKey,
|
|
30
|
+
protocolKey,
|
|
31
|
+
reportEventKey,
|
|
32
|
+
} from './common/eventKeys'
|
|
33
|
+
|
|
34
|
+
export {
|
|
35
|
+
type AssetResponse,
|
|
36
|
+
createUnifiedTokenRenderer,
|
|
37
|
+
type TokenLike,
|
|
38
|
+
type TokenProps,
|
|
39
|
+
type UnifiedRendererContext,
|
|
40
|
+
type UnifiedTokenRendererOptions,
|
|
41
|
+
} from './common/unified-token-renderer'
|
|
42
|
+
|
|
43
|
+
// Vue renderer exports
|
|
44
|
+
export {
|
|
45
|
+
type AimdComponentRenderer,
|
|
46
|
+
type AimdRendererContext,
|
|
47
|
+
type AssetResolver,
|
|
48
|
+
createAssetRenderer,
|
|
49
|
+
createCodeBlockRenderer,
|
|
50
|
+
createComponentRenderer,
|
|
51
|
+
createEmbeddedRenderer,
|
|
52
|
+
createMermaidRenderer,
|
|
53
|
+
createStepCardRenderer,
|
|
54
|
+
type ElementRenderer,
|
|
55
|
+
hastToVue,
|
|
56
|
+
renderToVNodes,
|
|
57
|
+
type AimdStepCardRendererOptions,
|
|
58
|
+
type ShikiHighlighter,
|
|
59
|
+
type VueRendererOptions,
|
|
60
|
+
} from './vue/vue-renderer'
|
|
61
|
+
|
|
62
|
+
// Re-export types from aimd-core
|
|
63
|
+
export type {
|
|
64
|
+
ProcessorOptions,
|
|
65
|
+
RenderContext,
|
|
66
|
+
RenderMode,
|
|
67
|
+
RenderNode,
|
|
68
|
+
TokenRenderRule,
|
|
69
|
+
} from '@airalogy/aimd-core/types'
|
|
70
|
+
|
|
71
|
+
// Re-export RenderResult from processor
|
|
72
|
+
export type {
|
|
73
|
+
AimdAssignerVisibility,
|
|
74
|
+
AimdHtmlNodeRenderer,
|
|
75
|
+
AimdHtmlRendererContext,
|
|
76
|
+
CustomElementAimdRendererOptions,
|
|
77
|
+
AimdRendererOptions,
|
|
78
|
+
RenderResult,
|
|
79
|
+
} from './common/processor'
|
|
80
|
+
export type {
|
|
81
|
+
AimdRendererI18nOptions,
|
|
82
|
+
AimdRendererLocale,
|
|
83
|
+
AimdRendererMessages,
|
|
84
|
+
AimdRendererMessagesInput,
|
|
85
|
+
} from './locales'
|
|
86
|
+
|
|
87
|
+
// Helper function
|
|
88
|
+
export function getFinalIndent(item: { parent?: any, sequence: number, level: number }): string {
|
|
89
|
+
const { parent, sequence, level } = item
|
|
90
|
+
let indent = String(sequence + 1)
|
|
91
|
+
|
|
92
|
+
if (level === 1) {
|
|
93
|
+
return indent
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let parentNode = parent
|
|
97
|
+
|
|
98
|
+
while (parentNode) {
|
|
99
|
+
indent = `${parentNode.sequence + 1}.${indent}`
|
|
100
|
+
parentNode = parentNode.parent
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return indent
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function parseFieldTag(template: string): { type: string, name: string }[] {
|
|
107
|
+
const isTable = template.startsWith("var_table")
|
|
108
|
+
if (isTable) {
|
|
109
|
+
const [type, _, group, ...rest] = template.split(/(\\)?\|/g)
|
|
110
|
+
return [{ type, name: `${group}|${rest.filter(Boolean).join(",")}` }]
|
|
111
|
+
}
|
|
112
|
+
const [type, _, name] = template.split(/(\\)?\|/)
|
|
113
|
+
return [{ type, name }]
|
|
114
|
+
}
|
package/src/locales.ts
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
export type AimdRendererLocale = "en-US" | "zh-CN"
|
|
2
|
+
|
|
3
|
+
export const DEFAULT_AIMD_RENDERER_LOCALE: AimdRendererLocale = "en-US"
|
|
4
|
+
|
|
5
|
+
type DeepPartial<T> = {
|
|
6
|
+
[K in keyof T]?: T[K] extends (...args: any[]) => any
|
|
7
|
+
? T[K]
|
|
8
|
+
: T[K] extends Array<infer U>
|
|
9
|
+
? Array<DeepPartial<U>>
|
|
10
|
+
: T[K] extends object
|
|
11
|
+
? DeepPartial<T[K]>
|
|
12
|
+
: T[K]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface AimdRendererMessages {
|
|
16
|
+
scope: {
|
|
17
|
+
var: string
|
|
18
|
+
quiz: string
|
|
19
|
+
step: string
|
|
20
|
+
check: string
|
|
21
|
+
table: string
|
|
22
|
+
figure: string
|
|
23
|
+
}
|
|
24
|
+
quiz: {
|
|
25
|
+
types: {
|
|
26
|
+
choice: string
|
|
27
|
+
singleChoice: string
|
|
28
|
+
multipleChoice: string
|
|
29
|
+
blank: string
|
|
30
|
+
open: string
|
|
31
|
+
scale: string
|
|
32
|
+
}
|
|
33
|
+
score: (score: string | number) => string
|
|
34
|
+
answer: (value: string) => string
|
|
35
|
+
rubric: (value: string) => string
|
|
36
|
+
}
|
|
37
|
+
step: {
|
|
38
|
+
sequence: (step: string | number) => string
|
|
39
|
+
reference: (step: string | number) => string
|
|
40
|
+
}
|
|
41
|
+
figure: {
|
|
42
|
+
reference: (value: string | number) => string
|
|
43
|
+
captionTitle: (sequence: number, title?: string) => string
|
|
44
|
+
}
|
|
45
|
+
assigner: {
|
|
46
|
+
clientSummary: string
|
|
47
|
+
serverSummary: string
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type AimdRendererMessagesInput = DeepPartial<AimdRendererMessages>
|
|
52
|
+
|
|
53
|
+
export interface AimdRendererI18nOptions {
|
|
54
|
+
locale?: AimdRendererLocale | string
|
|
55
|
+
messages?: AimdRendererMessagesInput
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function detectRuntimeLocale(): string | undefined {
|
|
59
|
+
if (typeof document !== "undefined") {
|
|
60
|
+
const htmlLang = document.documentElement?.lang?.trim()
|
|
61
|
+
if (htmlLang)
|
|
62
|
+
return htmlLang
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (typeof navigator !== "undefined") {
|
|
66
|
+
if (navigator.language)
|
|
67
|
+
return navigator.language
|
|
68
|
+
if (Array.isArray(navigator.languages) && navigator.languages.length > 0)
|
|
69
|
+
return navigator.languages[0]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return undefined
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const EN_US_MESSAGES: AimdRendererMessages = {
|
|
76
|
+
scope: {
|
|
77
|
+
var: "var",
|
|
78
|
+
quiz: "quiz",
|
|
79
|
+
step: "step",
|
|
80
|
+
check: "check",
|
|
81
|
+
table: "table",
|
|
82
|
+
figure: "figure",
|
|
83
|
+
},
|
|
84
|
+
quiz: {
|
|
85
|
+
types: {
|
|
86
|
+
choice: "choice",
|
|
87
|
+
singleChoice: "Single choice",
|
|
88
|
+
multipleChoice: "Multiple choice",
|
|
89
|
+
blank: "blank",
|
|
90
|
+
open: "open",
|
|
91
|
+
scale: "scale",
|
|
92
|
+
},
|
|
93
|
+
score: score => `${score} pt`,
|
|
94
|
+
answer: value => `Answer: ${value}`,
|
|
95
|
+
rubric: value => `Rubric: ${value}`,
|
|
96
|
+
},
|
|
97
|
+
step: {
|
|
98
|
+
sequence: step => `Step ${step} :`,
|
|
99
|
+
reference: step => `Step ${step}`,
|
|
100
|
+
},
|
|
101
|
+
figure: {
|
|
102
|
+
reference: value => `figure ${value}`,
|
|
103
|
+
captionTitle: (sequence, title) => title ? `figure ${sequence}: ${title}` : `figure ${sequence}`,
|
|
104
|
+
},
|
|
105
|
+
assigner: {
|
|
106
|
+
clientSummary: "Client assigner",
|
|
107
|
+
serverSummary: "Server assigner",
|
|
108
|
+
},
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const ZH_CN_MESSAGES: AimdRendererMessages = {
|
|
112
|
+
scope: {
|
|
113
|
+
var: "变量",
|
|
114
|
+
quiz: "题目",
|
|
115
|
+
step: "步骤",
|
|
116
|
+
check: "检查点",
|
|
117
|
+
table: "表格",
|
|
118
|
+
figure: "图",
|
|
119
|
+
},
|
|
120
|
+
quiz: {
|
|
121
|
+
types: {
|
|
122
|
+
choice: "选择",
|
|
123
|
+
singleChoice: "单选",
|
|
124
|
+
multipleChoice: "多选",
|
|
125
|
+
blank: "填空",
|
|
126
|
+
open: "开放",
|
|
127
|
+
scale: "量表",
|
|
128
|
+
},
|
|
129
|
+
score: score => `${score} 分`,
|
|
130
|
+
answer: value => `答案:${value}`,
|
|
131
|
+
rubric: value => `评分标准:${value}`,
|
|
132
|
+
},
|
|
133
|
+
step: {
|
|
134
|
+
sequence: step => `步骤 ${step}:`,
|
|
135
|
+
reference: step => `步骤${step}`,
|
|
136
|
+
},
|
|
137
|
+
figure: {
|
|
138
|
+
reference: value => `图 ${value}`,
|
|
139
|
+
captionTitle: (sequence, title) => title ? `图 ${sequence}:${title}` : `图 ${sequence}`,
|
|
140
|
+
},
|
|
141
|
+
assigner: {
|
|
142
|
+
clientSummary: "前端 assigner",
|
|
143
|
+
serverSummary: "服务端 assigner",
|
|
144
|
+
},
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const BASE_MESSAGES: Record<AimdRendererLocale, AimdRendererMessages> = {
|
|
148
|
+
"en-US": EN_US_MESSAGES,
|
|
149
|
+
"zh-CN": ZH_CN_MESSAGES,
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
153
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function deepMerge<T>(base: T, override?: DeepPartial<T>): T {
|
|
157
|
+
if (!override)
|
|
158
|
+
return base
|
|
159
|
+
|
|
160
|
+
const result: Record<string, unknown> = { ...(base as Record<string, unknown>) }
|
|
161
|
+
|
|
162
|
+
for (const key of Object.keys(override) as Array<keyof T>) {
|
|
163
|
+
const overrideValue = override[key]
|
|
164
|
+
if (overrideValue === undefined)
|
|
165
|
+
continue
|
|
166
|
+
|
|
167
|
+
const baseValue = base[key]
|
|
168
|
+
if (isPlainObject(baseValue) && isPlainObject(overrideValue)) {
|
|
169
|
+
result[key as string] = deepMerge(baseValue, overrideValue as any)
|
|
170
|
+
continue
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
result[key as string] = overrideValue as T[keyof T]
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return result as T
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function resolveAimdRendererLocale(locale?: string): AimdRendererLocale {
|
|
180
|
+
const runtimeLocale = locale || detectRuntimeLocale()
|
|
181
|
+
|
|
182
|
+
if (runtimeLocale?.toLowerCase().startsWith("zh")) {
|
|
183
|
+
return "zh-CN"
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return DEFAULT_AIMD_RENDERER_LOCALE
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export function createAimdRendererMessages(
|
|
190
|
+
locale: string | undefined,
|
|
191
|
+
overrides?: AimdRendererMessagesInput,
|
|
192
|
+
): AimdRendererMessages {
|
|
193
|
+
const resolvedLocale = resolveAimdRendererLocale(locale)
|
|
194
|
+
const merged = deepMerge(BASE_MESSAGES[resolvedLocale], overrides)
|
|
195
|
+
const choiceOverride = overrides?.quiz?.types?.choice
|
|
196
|
+
const hasSingleChoiceOverride = overrides?.quiz?.types?.singleChoice !== undefined
|
|
197
|
+
const hasMultipleChoiceOverride = overrides?.quiz?.types?.multipleChoice !== undefined
|
|
198
|
+
|
|
199
|
+
if (typeof choiceOverride === "string") {
|
|
200
|
+
if (!hasSingleChoiceOverride) {
|
|
201
|
+
merged.quiz.types.singleChoice = choiceOverride
|
|
202
|
+
}
|
|
203
|
+
if (!hasMultipleChoiceOverride) {
|
|
204
|
+
merged.quiz.types.multipleChoice = choiceOverride
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return merged
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function getAimdRendererScopeLabel(
|
|
212
|
+
scope: string,
|
|
213
|
+
messages: Pick<AimdRendererMessages, "scope">,
|
|
214
|
+
): string {
|
|
215
|
+
switch (scope) {
|
|
216
|
+
case "var":
|
|
217
|
+
return messages.scope.var
|
|
218
|
+
case "quiz":
|
|
219
|
+
return messages.scope.quiz
|
|
220
|
+
case "step":
|
|
221
|
+
return messages.scope.step
|
|
222
|
+
case "check":
|
|
223
|
+
return messages.scope.check
|
|
224
|
+
case "var_table":
|
|
225
|
+
return messages.scope.table
|
|
226
|
+
case "figure":
|
|
227
|
+
return messages.scope.figure
|
|
228
|
+
default:
|
|
229
|
+
return scope
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function getAimdRendererQuizTypeLabel(
|
|
234
|
+
quizType: string | undefined,
|
|
235
|
+
quizMode: string | undefined,
|
|
236
|
+
messages: Pick<AimdRendererMessages, "quiz">,
|
|
237
|
+
): string {
|
|
238
|
+
switch (quizType) {
|
|
239
|
+
case "choice":
|
|
240
|
+
if (quizMode === "single") {
|
|
241
|
+
return messages.quiz.types.singleChoice
|
|
242
|
+
}
|
|
243
|
+
if (quizMode === "multiple") {
|
|
244
|
+
return messages.quiz.types.multipleChoice
|
|
245
|
+
}
|
|
246
|
+
return messages.quiz.types.choice
|
|
247
|
+
case "blank":
|
|
248
|
+
return messages.quiz.types.blank
|
|
249
|
+
case "open":
|
|
250
|
+
return messages.quiz.types.open
|
|
251
|
+
case "scale":
|
|
252
|
+
return messages.quiz.types.scale
|
|
253
|
+
default:
|
|
254
|
+
return quizType || messages.quiz.types.open
|
|
255
|
+
}
|
|
256
|
+
}
|
package/src/vue/index.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vue rendering exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
type AimdComponentRenderer,
|
|
7
|
+
type AimdRendererContext,
|
|
8
|
+
type AssetResolver,
|
|
9
|
+
createAssetRenderer,
|
|
10
|
+
createCodeBlockRenderer,
|
|
11
|
+
createComponentRenderer,
|
|
12
|
+
createEmbeddedRenderer,
|
|
13
|
+
createMermaidRenderer,
|
|
14
|
+
createStepCardRenderer,
|
|
15
|
+
type ElementRenderer,
|
|
16
|
+
hastToVue,
|
|
17
|
+
renderToVNodes,
|
|
18
|
+
type AimdStepCardRendererOptions,
|
|
19
|
+
type ShikiHighlighter,
|
|
20
|
+
type VueRendererOptions,
|
|
21
|
+
} from './vue-renderer'
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
renderToVue,
|
|
25
|
+
createRenderer,
|
|
26
|
+
defaultRenderer,
|
|
27
|
+
} from '../common/processor'
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
createAimdRendererMessages,
|
|
31
|
+
DEFAULT_AIMD_RENDERER_LOCALE,
|
|
32
|
+
resolveAimdRendererLocale,
|
|
33
|
+
} from '../locales'
|
|
34
|
+
|
|
35
|
+
export type {
|
|
36
|
+
RenderContext,
|
|
37
|
+
RenderMode,
|
|
38
|
+
ProcessorOptions,
|
|
39
|
+
} from '@airalogy/aimd-core/types'
|
|
40
|
+
|
|
41
|
+
export type { AimdAssignerVisibility, AimdRendererOptions, RenderResult } from '../common/processor'
|
|
42
|
+
export type {
|
|
43
|
+
AimdRendererI18nOptions,
|
|
44
|
+
AimdRendererLocale,
|
|
45
|
+
AimdRendererMessages,
|
|
46
|
+
AimdRendererMessagesInput,
|
|
47
|
+
} from '../locales'
|