@xyd-js/content 0.1.0-xyd.8 → 0.1.0-xyd.97
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/CHANGELOG.md +1157 -0
- package/ISSUES.md +1 -0
- package/LICENSE +21 -0
- package/TODO.md +2 -0
- package/dist/index.d.ts +24 -5
- package/dist/index.js +212 -566
- package/dist/index.js.map +1 -1
- package/dist/md.d.ts +69 -0
- package/dist/md.js +23396 -0
- package/dist/md.js.map +1 -0
- package/dist/mdToc-NBBxMJ4l.d.ts +12 -0
- package/dist/vite.d.ts +103 -9
- package/dist/vite.js +19992 -170
- package/dist/vite.js.map +1 -1
- package/package.json +26 -7
- package/packages/md/index.ts +17 -8
- package/packages/md/plugins/component-directives/index.ts +3 -0
- package/packages/md/plugins/component-directives/mdComponentDirective.ts +524 -0
- package/packages/md/plugins/component-directives/types.ts +1 -0
- package/packages/md/plugins/component-directives/utils.ts +27 -0
- package/packages/md/plugins/composer/__fixtures__/1.single-example/input.md +7 -0
- package/packages/md/plugins/composer/__fixtures__/1.single-example/output.json +63 -0
- package/packages/md/plugins/composer/__fixtures__/2.single-example-with-name/input.md +7 -0
- package/packages/md/plugins/composer/__fixtures__/2.single-example-with-name/output.json +63 -0
- package/packages/md/plugins/composer/__fixtures__/3.multiple-examples/input.md +15 -0
- package/packages/md/plugins/composer/__fixtures__/3.multiple-examples/output.json +122 -0
- package/packages/md/plugins/composer/__fixtures__/4.example-groups/input.md +23 -0
- package/packages/md/plugins/composer/__fixtures__/4.example-groups/output.json +184 -0
- package/packages/md/plugins/composer/__tests__/mdComposer.test.ts +41 -0
- package/packages/md/plugins/composer/__tests__/testHelpers.ts +48 -0
- package/packages/md/plugins/composer/index.ts +1 -0
- package/packages/md/plugins/composer/mdComposer.ts +146 -0
- package/packages/md/plugins/developer-writing/index.ts +3 -0
- package/packages/md/plugins/developer-writing/mdCodeRehype.ts +78 -0
- package/packages/md/plugins/functions/__fixtures__/external.ts +4 -0
- package/packages/md/plugins/functions/__fixtures__/test.js +11 -0
- package/packages/md/plugins/functions/__fixtures__/test.py +9 -0
- package/packages/md/plugins/functions/__fixtures__/test.ts +18 -0
- package/packages/md/plugins/functions/__tests__/mdFunctionImportCode.test.ts +295 -0
- package/packages/md/plugins/functions/__tests__/parseFunctionCall.test.ts +47 -0
- package/packages/md/plugins/functions/__tests__/testHelpers.ts +71 -0
- package/packages/md/plugins/functions/index.ts +11 -0
- package/packages/md/plugins/functions/mdFunctionChangelog.ts +124 -0
- package/packages/md/plugins/functions/mdFunctionImportCode.ts +83 -0
- package/packages/md/plugins/functions/mdFunctionUniform.ts +79 -0
- package/packages/md/plugins/functions/types.ts +6 -0
- package/packages/md/plugins/functions/uniformProcessor.ts +349 -0
- package/packages/md/plugins/functions/utils.ts +423 -0
- package/packages/md/plugins/index.ts +56 -9
- package/packages/md/plugins/mdCode.ts +67 -0
- package/packages/md/plugins/mdHeadingId.ts +47 -0
- package/packages/md/plugins/mdPage.ts +35 -0
- package/packages/md/plugins/{md-themeSettings.ts → mdThemeSettings.ts} +8 -0
- package/packages/md/plugins/mdToc.ts +224 -0
- package/packages/md/plugins/meta/index.ts +1 -0
- package/packages/md/plugins/meta/mdMeta.ts +189 -0
- package/packages/md/plugins/output-variables/__fixtures__/1.simple/input.md +22 -0
- package/packages/md/plugins/output-variables/__fixtures__/1.simple/output.json +191 -0
- package/packages/md/plugins/output-variables/__fixtures__/2.multiple-vars/input.md +21 -0
- package/packages/md/plugins/output-variables/__fixtures__/2.multiple-vars/output.json +127 -0
- package/packages/md/plugins/output-variables/__tests__/index.test.ts +28 -0
- package/packages/md/plugins/output-variables/__tests__/testHelpers.ts +36 -0
- package/packages/md/plugins/output-variables/index.ts +1 -0
- package/packages/md/plugins/output-variables/lib/const.ts +4 -0
- package/packages/md/plugins/output-variables/lib/factoryAttributes.ts +350 -0
- package/packages/md/plugins/output-variables/lib/factoryLabel.ts +135 -0
- package/packages/md/plugins/output-variables/lib/factoryName.ts +59 -0
- package/packages/md/plugins/output-variables/lib/index.ts +21 -0
- package/packages/md/plugins/output-variables/lib/outputVarsContainer.ts +328 -0
- package/packages/md/plugins/output-variables/lib/util.ts +494 -0
- package/packages/md/plugins/output-variables/remarkOutputVars.ts +22 -0
- package/packages/md/plugins/rehypeHeading.ts +50 -0
- package/packages/md/plugins/types.ts +15 -0
- package/packages/md/plugins/utils/componentLike.ts +72 -0
- package/packages/md/plugins/utils/index.ts +2 -0
- package/packages/md/plugins/utils/mdParameters.test.ts +114 -0
- package/packages/md/plugins/utils/mdParameters.ts +249 -0
- package/packages/md/plugins/utils/mdastTypes.ts +42 -0
- package/packages/md/search/index.ts +251 -0
- package/packages/md/search/types.ts +36 -0
- package/packages/vite/index.ts +8 -2
- package/src/fs.ts +51 -36
- package/src/index.ts +4 -4
- package/src/navigation.ts +50 -38
- package/src/types.ts +8 -0
- package/tsconfig.json +31 -8
- package/tsup.config.ts +2 -0
- package/vitest.config.ts +17 -0
- package/packages/md/plugins/md-code.ts +0 -15
- package/packages/md/plugins/md-codegroup.ts +0 -36
- package/packages/md/plugins/md-page.ts +0 -22
- package/packages/md/plugins/md-toc.ts +0 -133
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import {Directives, LeafDirective, TextDirective, ToMarkdownOptions} from 'mdast-util-directive'
|
|
3
|
+
* @import {
|
|
4
|
+
* CompileContext,
|
|
5
|
+
* Extension as FromMarkdownExtension,
|
|
6
|
+
* Handle as FromMarkdownHandle,
|
|
7
|
+
* Token
|
|
8
|
+
* } from 'mdast-util-from-markdown'
|
|
9
|
+
* @import {
|
|
10
|
+
* ConstructName,
|
|
11
|
+
* Handle as ToMarkdownHandle,
|
|
12
|
+
* Options as ToMarkdownExtension,
|
|
13
|
+
* State
|
|
14
|
+
* } from 'mdast-util-to-markdown'
|
|
15
|
+
* @import {Nodes, Paragraph} from 'mdast'
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { ccount } from 'ccount'
|
|
19
|
+
import { ok as assert } from 'devlop'
|
|
20
|
+
import { parseEntities } from 'parse-entities'
|
|
21
|
+
import { stringifyEntitiesLight } from 'stringify-entities'
|
|
22
|
+
import { visitParents } from 'unist-util-visit-parents'
|
|
23
|
+
import { PRIMARY_SYMBOL_STR } from './const'
|
|
24
|
+
|
|
25
|
+
const own = {}.hasOwnProperty
|
|
26
|
+
|
|
27
|
+
/** @type {Readonly<ToMarkdownOptions>} */
|
|
28
|
+
const emptyOptions = {}
|
|
29
|
+
|
|
30
|
+
const shortcut = /^[^\t\n\r "#'.<=>`}]+$/
|
|
31
|
+
const unquoted = /^[^\t\n\r "'<=>`}]+$/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create an extension for `mdast-util-from-markdown` to enable directives in
|
|
35
|
+
* markdown.
|
|
36
|
+
*
|
|
37
|
+
* @returns {FromMarkdownExtension}
|
|
38
|
+
* Extension for `mdast-util-from-markdown` to enable directives.
|
|
39
|
+
*/
|
|
40
|
+
export function outputVarsFromMarkdown() {
|
|
41
|
+
return {
|
|
42
|
+
canContainEols: ['textDirective'],
|
|
43
|
+
enter: {
|
|
44
|
+
outputVarContainer: enterContainer,
|
|
45
|
+
outputVarContainerAttributes: enterAttributes,
|
|
46
|
+
outputVarContainerLabel: enterContainerLabel,
|
|
47
|
+
},
|
|
48
|
+
exit: {
|
|
49
|
+
outputVarContainer: exit,
|
|
50
|
+
outputVarContainerAttributeClassValue: exitAttributeClassValue,
|
|
51
|
+
outputVarContainerAttributeIdValue: exitAttributeIdValue,
|
|
52
|
+
outputVarContainerAttributeName: exitAttributeName,
|
|
53
|
+
outputVarContainerAttributeValue: exitAttributeValue,
|
|
54
|
+
outputVarContainerAttributes: exitAttributes,
|
|
55
|
+
outputVarContainerLabel: exitContainerLabel,
|
|
56
|
+
outputVarContainerName: exitName,
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Create an extension for `mdast-util-to-markdown` to enable directives in
|
|
63
|
+
* markdown.
|
|
64
|
+
*
|
|
65
|
+
* @param {Readonly<ToMarkdownOptions> | null | undefined} [options]
|
|
66
|
+
* Configuration (optional).
|
|
67
|
+
* @returns {ToMarkdownExtension}
|
|
68
|
+
* Extension for `mdast-util-to-markdown` to enable directives.
|
|
69
|
+
*/
|
|
70
|
+
export function outputVarsToMarkdown(options?: any) {
|
|
71
|
+
const settings = options || emptyOptions
|
|
72
|
+
|
|
73
|
+
if (
|
|
74
|
+
settings.quote !== '"' &&
|
|
75
|
+
settings.quote !== "'" &&
|
|
76
|
+
settings.quote !== null &&
|
|
77
|
+
settings.quote !== undefined
|
|
78
|
+
) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
'Invalid quote `' + settings.quote + '`, expected `\'` or `"`'
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
handleOutputVars.peek = peekDirective
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
handlers: {
|
|
88
|
+
outputVars: handleOutputVars,
|
|
89
|
+
},
|
|
90
|
+
unsafe: [
|
|
91
|
+
{
|
|
92
|
+
character: '\r',
|
|
93
|
+
inConstruct: ['leafDirectiveLabel', 'outputVarsLabel']
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
character: '\n',
|
|
97
|
+
inConstruct: ['leafDirectiveLabel', 'outputVarsLabel']
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
before: '[^>]',
|
|
101
|
+
character: '>',
|
|
102
|
+
after: '[A-Za-z]',
|
|
103
|
+
inConstruct: ['phrasing']
|
|
104
|
+
},
|
|
105
|
+
{ atBreak: true, character: '>', after: '>' }
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @type {ToMarkdownHandle}
|
|
111
|
+
* @param {Directives} node
|
|
112
|
+
*/
|
|
113
|
+
function handleOutputVars(node, _, state, info) {
|
|
114
|
+
const tracker = state.createTracker(info)
|
|
115
|
+
const sequence = fence(node)
|
|
116
|
+
const exit = state.enter(node.type)
|
|
117
|
+
let value = tracker.move(sequence + (node.name || ''))
|
|
118
|
+
/** @type {LeafDirective | Paragraph | TextDirective | undefined} */
|
|
119
|
+
let label
|
|
120
|
+
|
|
121
|
+
if (node.type === 'outputVars') {
|
|
122
|
+
const head = (node.children || [])[0]
|
|
123
|
+
label = inlineDirectiveLabel(head) ? head : undefined
|
|
124
|
+
} else {
|
|
125
|
+
label = node
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (label && label.children && label.children.length > 0) {
|
|
129
|
+
const exit = state.enter('label')
|
|
130
|
+
/** @type {ConstructName} */
|
|
131
|
+
const labelType = `${node.type}Label`
|
|
132
|
+
const subexit = state.enter(labelType)
|
|
133
|
+
value += tracker.move('[')
|
|
134
|
+
value += tracker.move(
|
|
135
|
+
state.containerPhrasing(label, {
|
|
136
|
+
...tracker.current(),
|
|
137
|
+
before: value,
|
|
138
|
+
after: ']'
|
|
139
|
+
})
|
|
140
|
+
)
|
|
141
|
+
value += tracker.move(']')
|
|
142
|
+
subexit()
|
|
143
|
+
exit()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
value += tracker.move(attributes(node, state))
|
|
147
|
+
|
|
148
|
+
if (node.type === 'outputVars') {
|
|
149
|
+
const head = (node.children || [])[0]
|
|
150
|
+
let shallow = node
|
|
151
|
+
|
|
152
|
+
if (inlineDirectiveLabel(head)) {
|
|
153
|
+
shallow = Object.assign({}, node, { children: node.children.slice(1) })
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (shallow && shallow.children && shallow.children.length > 0) {
|
|
157
|
+
value += tracker.move('\n')
|
|
158
|
+
value += tracker.move(state.containerFlow(shallow, tracker.current()))
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
value += tracker.move('\n' + sequence)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
exit()
|
|
165
|
+
return value
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @param {Directives} node
|
|
170
|
+
* @param {State} state
|
|
171
|
+
* @returns {string}
|
|
172
|
+
*/
|
|
173
|
+
function attributes(node, state) {
|
|
174
|
+
const attributes = node.attributes || {}
|
|
175
|
+
/** @type {Array<string>} */
|
|
176
|
+
const values = []
|
|
177
|
+
/** @type {string | undefined} */
|
|
178
|
+
let classesFull
|
|
179
|
+
/** @type {string | undefined} */
|
|
180
|
+
let classes
|
|
181
|
+
/** @type {string | undefined} */
|
|
182
|
+
let id
|
|
183
|
+
/** @type {string} */
|
|
184
|
+
let key
|
|
185
|
+
|
|
186
|
+
for (key in attributes) {
|
|
187
|
+
if (
|
|
188
|
+
own.call(attributes, key) &&
|
|
189
|
+
attributes[key] !== undefined &&
|
|
190
|
+
attributes[key] !== null
|
|
191
|
+
) {
|
|
192
|
+
const value = String(attributes[key])
|
|
193
|
+
|
|
194
|
+
// To do: next major:
|
|
195
|
+
// Do not reorder `id` and `class` attributes when they do not turn into
|
|
196
|
+
// shortcuts.
|
|
197
|
+
// Additionally, join shortcuts: `#a .b.c d="e"` -> `#a.b.c d="e"`
|
|
198
|
+
if (key === 'id') {
|
|
199
|
+
id =
|
|
200
|
+
settings.preferShortcut !== false && shortcut.test(value)
|
|
201
|
+
? '#' + value
|
|
202
|
+
: quoted('id', value, node, state)
|
|
203
|
+
} else if (key === 'class') {
|
|
204
|
+
const list = value.split(/[\t\n\r ]+/g)
|
|
205
|
+
/** @type {Array<string>} */
|
|
206
|
+
const classesFullList = []
|
|
207
|
+
/** @type {Array<string>} */
|
|
208
|
+
const classesList = []
|
|
209
|
+
let index = -1
|
|
210
|
+
|
|
211
|
+
while (++index < list.length) {
|
|
212
|
+
; (settings.preferShortcut !== false && shortcut.test(list[index])
|
|
213
|
+
? classesList
|
|
214
|
+
: classesFullList
|
|
215
|
+
).push(list[index])
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
classesFull =
|
|
219
|
+
classesFullList.length > 0
|
|
220
|
+
? quoted('class', classesFullList.join(' '), node, state)
|
|
221
|
+
: ''
|
|
222
|
+
classes = classesList.length > 0 ? '.' + classesList.join('.') : ''
|
|
223
|
+
} else {
|
|
224
|
+
values.push(quoted(key, value, node, state))
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (classesFull) {
|
|
230
|
+
values.unshift(classesFull)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (classes) {
|
|
234
|
+
values.unshift(classes)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (id) {
|
|
238
|
+
values.unshift(id)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return values.length > 0 ? '{' + values.join(' ') + '}' : ''
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @param {string} key
|
|
246
|
+
* @param {string} value
|
|
247
|
+
* @param {Directives} node
|
|
248
|
+
* @param {State} state
|
|
249
|
+
* @returns {string}
|
|
250
|
+
*/
|
|
251
|
+
function quoted(key, value, node, state) {
|
|
252
|
+
if (settings.collapseEmptyAttributes !== false && !value) return key
|
|
253
|
+
|
|
254
|
+
if (settings.preferUnquoted && unquoted.test(value)) {
|
|
255
|
+
return key + '=' + value
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// If the alternative is less common than `quote`, switch.
|
|
259
|
+
const preferred = settings.quote || state.options.quote || '"'
|
|
260
|
+
const alternative = preferred === '"' ? "'" : '"'
|
|
261
|
+
// If the alternative is less common than `quote`, switch.
|
|
262
|
+
const appliedQuote =
|
|
263
|
+
settings.quoteSmart &&
|
|
264
|
+
ccount(value, preferred) > ccount(value, alternative)
|
|
265
|
+
? alternative
|
|
266
|
+
: preferred
|
|
267
|
+
const subset =
|
|
268
|
+
node.type === 'textDirective'
|
|
269
|
+
? [appliedQuote]
|
|
270
|
+
: [appliedQuote, '\n', '\r']
|
|
271
|
+
|
|
272
|
+
return (
|
|
273
|
+
key +
|
|
274
|
+
'=' +
|
|
275
|
+
appliedQuote +
|
|
276
|
+
stringifyEntitiesLight(value, { subset }) +
|
|
277
|
+
appliedQuote
|
|
278
|
+
)
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* @this {CompileContext}
|
|
284
|
+
* @type {FromMarkdownHandle}
|
|
285
|
+
*/
|
|
286
|
+
function enterContainer(token) {
|
|
287
|
+
enter.call(this, 'outputVars', token)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* @this {CompileContext}
|
|
292
|
+
* @type {FromMarkdownHandle}
|
|
293
|
+
*/
|
|
294
|
+
function enterLeaf(token) {
|
|
295
|
+
enter.call(this, 'leafDirective', token)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* @this {CompileContext}
|
|
300
|
+
* @type {FromMarkdownHandle}
|
|
301
|
+
*/
|
|
302
|
+
function enterText(token) {
|
|
303
|
+
enter.call(this, 'textDirective', token)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* @this {CompileContext}
|
|
308
|
+
* @param {Directives['type']} type
|
|
309
|
+
* @param {Token} token
|
|
310
|
+
*/
|
|
311
|
+
function enter(type, token) {
|
|
312
|
+
this.enter({ type, name: '', attributes: {}, children: [] }, token)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* @this {CompileContext}
|
|
317
|
+
* @param {Token} token
|
|
318
|
+
*/
|
|
319
|
+
function exitName(token) {
|
|
320
|
+
const node = this.stack[this.stack.length - 1]
|
|
321
|
+
assert(
|
|
322
|
+
node.type === 'outputVars' ||
|
|
323
|
+
node.type === 'leafDirective' ||
|
|
324
|
+
node.type === 'textDirective'
|
|
325
|
+
)
|
|
326
|
+
node.name = this.sliceSerialize(token)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* @this {CompileContext}
|
|
331
|
+
* @type {FromMarkdownHandle}
|
|
332
|
+
*/
|
|
333
|
+
function enterContainerLabel(token) {
|
|
334
|
+
this.enter(
|
|
335
|
+
{ type: 'paragraph', data: { directiveLabel: true }, children: [] },
|
|
336
|
+
token
|
|
337
|
+
)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* @this {CompileContext}
|
|
342
|
+
* @type {FromMarkdownHandle}
|
|
343
|
+
*/
|
|
344
|
+
function exitContainerLabel(token) {
|
|
345
|
+
this.exit(token)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* @this {CompileContext}
|
|
350
|
+
* @type {FromMarkdownHandle}
|
|
351
|
+
*/
|
|
352
|
+
function enterAttributes() {
|
|
353
|
+
this.data.directiveAttributes = []
|
|
354
|
+
this.buffer() // Capture EOLs
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* @this {CompileContext}
|
|
359
|
+
* @type {FromMarkdownHandle}
|
|
360
|
+
*/
|
|
361
|
+
function exitAttributeIdValue(token) {
|
|
362
|
+
const list = this.data.directiveAttributes
|
|
363
|
+
assert(list, 'expected `directiveAttributes`')
|
|
364
|
+
list.push([
|
|
365
|
+
'id',
|
|
366
|
+
parseEntities(this.sliceSerialize(token), { attribute: true })
|
|
367
|
+
])
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* @this {CompileContext}
|
|
372
|
+
* @type {FromMarkdownHandle}
|
|
373
|
+
*/
|
|
374
|
+
function exitAttributeClassValue(token) {
|
|
375
|
+
const list = this.data.directiveAttributes
|
|
376
|
+
assert(list, 'expected `directiveAttributes`')
|
|
377
|
+
list.push([
|
|
378
|
+
'class',
|
|
379
|
+
parseEntities(this.sliceSerialize(token), { attribute: true })
|
|
380
|
+
])
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* @this {CompileContext}
|
|
385
|
+
* @type {FromMarkdownHandle}
|
|
386
|
+
*/
|
|
387
|
+
function exitAttributeValue(token) {
|
|
388
|
+
const list = this.data.directiveAttributes
|
|
389
|
+
assert(list, 'expected `directiveAttributes`')
|
|
390
|
+
list[list.length - 1][1] = parseEntities(this.sliceSerialize(token), {
|
|
391
|
+
attribute: true
|
|
392
|
+
})
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* @this {CompileContext}
|
|
397
|
+
* @type {FromMarkdownHandle}
|
|
398
|
+
*/
|
|
399
|
+
function exitAttributeName(token) {
|
|
400
|
+
const list = this.data.directiveAttributes
|
|
401
|
+
assert(list, 'expected `directiveAttributes`')
|
|
402
|
+
|
|
403
|
+
// Attribute names in CommonMark are significantly limited, so character
|
|
404
|
+
// references can't exist.
|
|
405
|
+
list.push([this.sliceSerialize(token), ''])
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* @this {CompileContext}
|
|
410
|
+
* @type {FromMarkdownHandle}
|
|
411
|
+
*/
|
|
412
|
+
function exitAttributes() {
|
|
413
|
+
const list = this.data.directiveAttributes
|
|
414
|
+
assert(list, 'expected `directiveAttributes`')
|
|
415
|
+
/** @type {Record<string, string>} */
|
|
416
|
+
const cleaned = {}
|
|
417
|
+
let index = -1
|
|
418
|
+
|
|
419
|
+
while (++index < list.length) {
|
|
420
|
+
const attribute = list[index]
|
|
421
|
+
|
|
422
|
+
if (attribute[0] === 'class' && cleaned.class) {
|
|
423
|
+
cleaned.class += ' ' + attribute[1]
|
|
424
|
+
} else {
|
|
425
|
+
cleaned[attribute[0]] = attribute[1]
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
this.data.directiveAttributes = undefined
|
|
430
|
+
this.resume() // Drop EOLs
|
|
431
|
+
const node = this.stack[this.stack.length - 1]
|
|
432
|
+
assert(
|
|
433
|
+
node.type === 'outputVars' ||
|
|
434
|
+
node.type === 'leafDirective' ||
|
|
435
|
+
node.type === 'textDirective'
|
|
436
|
+
)
|
|
437
|
+
node.attributes = cleaned
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* @this {CompileContext}
|
|
442
|
+
* @type {FromMarkdownHandle}
|
|
443
|
+
*/
|
|
444
|
+
function exit(token) {
|
|
445
|
+
this.exit(token)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/** @type {ToMarkdownHandle} */
|
|
449
|
+
function peekDirective() {
|
|
450
|
+
return ':'
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* @param {Nodes} node
|
|
455
|
+
* @returns {node is Paragraph & {data: {directiveLabel: true}}}
|
|
456
|
+
*/
|
|
457
|
+
function inlineDirectiveLabel(node) {
|
|
458
|
+
return Boolean(
|
|
459
|
+
node && node.type === 'paragraph' && node.data && node.data.directiveLabel
|
|
460
|
+
)
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* @param {Directives} node
|
|
465
|
+
* @returns {string}
|
|
466
|
+
*/
|
|
467
|
+
function fence(node) {
|
|
468
|
+
let size = 0
|
|
469
|
+
|
|
470
|
+
if (node.type === 'outputVars') {
|
|
471
|
+
visitParents(node, function (node, parents) {
|
|
472
|
+
if (node.type === 'outputVars') {
|
|
473
|
+
let index = parents.length
|
|
474
|
+
let nesting = 0
|
|
475
|
+
|
|
476
|
+
while (index--) {
|
|
477
|
+
if (parents[index].type === 'outputVars') {
|
|
478
|
+
nesting++
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (nesting > size) size = nesting
|
|
483
|
+
}
|
|
484
|
+
})
|
|
485
|
+
size += 3
|
|
486
|
+
return `${PRIMARY_SYMBOL_STR}`.repeat(size)
|
|
487
|
+
} else if (node.type === 'leafDirective') {
|
|
488
|
+
size = 2
|
|
489
|
+
return `${PRIMARY_SYMBOL_STR}`.repeat(size)
|
|
490
|
+
} else {
|
|
491
|
+
size = 1
|
|
492
|
+
return `${PRIMARY_SYMBOL_STR}`.repeat(size)
|
|
493
|
+
}
|
|
494
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { outputVars } from './lib'
|
|
2
|
+
import { outputVarsFromMarkdown, outputVarsToMarkdown } from './lib/util'
|
|
3
|
+
|
|
4
|
+
export function remarkOutputVars() {
|
|
5
|
+
console.time('plugin:remarkOutputVars');
|
|
6
|
+
const data = this.data()
|
|
7
|
+
|
|
8
|
+
const micromarkExtensions =
|
|
9
|
+
data.micromarkExtensions || (data.micromarkExtensions = [])
|
|
10
|
+
const fromMarkdownExtensions =
|
|
11
|
+
data.fromMarkdownExtensions || (data.fromMarkdownExtensions = [])
|
|
12
|
+
const toMarkdownExtensions =
|
|
13
|
+
data.toMarkdownExtensions || (data.toMarkdownExtensions = [])
|
|
14
|
+
|
|
15
|
+
micromarkExtensions.push(outputVars())
|
|
16
|
+
fromMarkdownExtensions.push(outputVarsFromMarkdown())
|
|
17
|
+
toMarkdownExtensions.push(outputVarsToMarkdown())
|
|
18
|
+
|
|
19
|
+
console.timeEnd('plugin:remarkOutputVars');
|
|
20
|
+
return function () { }
|
|
21
|
+
}
|
|
22
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { visit } from 'unist-util-visit';
|
|
2
|
+
import type { Plugin } from 'unified';
|
|
3
|
+
import type { Root } from 'hast';
|
|
4
|
+
|
|
5
|
+
import { mdParameters } from './utils/mdParameters';
|
|
6
|
+
|
|
7
|
+
export const rehypeHeading: Plugin<[], Root> = () => {
|
|
8
|
+
return (tree) => {
|
|
9
|
+
visit(tree, 'element', (node) => {
|
|
10
|
+
if (!node.tagName?.match(/^h[1-6]$/)) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Get the heading text
|
|
15
|
+
const text = node.children
|
|
16
|
+
.map((child) => ('value' in child ? child.value : ''))
|
|
17
|
+
.join('');
|
|
18
|
+
|
|
19
|
+
// Parse props using curly braces
|
|
20
|
+
const { props } = mdParameters(text);
|
|
21
|
+
|
|
22
|
+
if (node.properties?.hideHeading) {
|
|
23
|
+
const existingStyle = node.properties?.style || '';
|
|
24
|
+
node.properties = {
|
|
25
|
+
...node.properties,
|
|
26
|
+
style: `${existingStyle} visibility: hidden; display: block`.trim()
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (const child of node.children) {
|
|
31
|
+
if (!('value' in child)) {
|
|
32
|
+
continue
|
|
33
|
+
}
|
|
34
|
+
const { sanitizedText } = mdParameters(child.value);
|
|
35
|
+
|
|
36
|
+
child.value = sanitizedText;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// If no props were found, return
|
|
40
|
+
if (Object.keys(props).length === 0) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
node.properties = {
|
|
45
|
+
...node.properties,
|
|
46
|
+
...props,
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { VFile } from "vfile";
|
|
2
|
+
|
|
3
|
+
// Define the structure of outputVars with support for multiple types
|
|
4
|
+
export type OutputVars<T extends Record<string, any>> = {
|
|
5
|
+
[K in keyof T]: T[K];
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// Define a custom VFile type that includes outputVars
|
|
9
|
+
export interface SymbolxVfile<T extends Record<string, any>> extends VFile {
|
|
10
|
+
data: {
|
|
11
|
+
outputVars?: OutputVars<T>;
|
|
12
|
+
[key: string]: any;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import { mdxJsxFromMarkdown } from 'mdast-util-mdx-jsx';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import acornJsx from 'acorn-jsx';
|
|
5
|
+
import { fromMarkdown } from 'mdast-util-from-markdown'
|
|
6
|
+
import { mdxJsx } from 'micromark-extension-mdx-jsx'
|
|
7
|
+
import * as acorn from 'acorn';
|
|
8
|
+
import reactElementToJSXString from 'react-element-to-jsx-string';
|
|
9
|
+
|
|
10
|
+
const acornWithJsx = acorn.Parser.extend(acornJsx());
|
|
11
|
+
|
|
12
|
+
export function componentLike(
|
|
13
|
+
componentName: string,
|
|
14
|
+
props: Record<string, any>,
|
|
15
|
+
children: any[]
|
|
16
|
+
) {
|
|
17
|
+
console.time('componentLike:total');
|
|
18
|
+
|
|
19
|
+
console.time('componentLike:createElement');
|
|
20
|
+
// Ensure proper escaping in props and children before creating the React element
|
|
21
|
+
const escapedProps = ensureProperEscaping(props);
|
|
22
|
+
const escapedChildren = ensureProperEscaping(children);
|
|
23
|
+
const reactElement = React.createElement(componentName, escapedProps, ...escapedChildren);
|
|
24
|
+
console.timeEnd('componentLike:createElement');
|
|
25
|
+
|
|
26
|
+
// Convert the React element to a JSX string
|
|
27
|
+
console.time('componentLike:toJSXString');
|
|
28
|
+
// @ts-ignore - The default property exists at runtime
|
|
29
|
+
const mdxString = reactElementToJSXString.default(reactElement);
|
|
30
|
+
console.timeEnd('componentLike:toJSXString');
|
|
31
|
+
|
|
32
|
+
// Parse the JSX string to get proper MDX attributes
|
|
33
|
+
console.time('componentLike:fromMarkdown');
|
|
34
|
+
|
|
35
|
+
const ast = fromMarkdown(mdxString, {
|
|
36
|
+
extensions: [mdxJsx({
|
|
37
|
+
acorn: acornWithJsx,
|
|
38
|
+
addResult: true
|
|
39
|
+
})],
|
|
40
|
+
mdastExtensions: [mdxJsxFromMarkdown()]
|
|
41
|
+
});
|
|
42
|
+
console.timeEnd('componentLike:fromMarkdown');
|
|
43
|
+
|
|
44
|
+
console.timeEnd('componentLike:total');
|
|
45
|
+
return ast
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Recursively ensures proper backslash escaping in string values.
|
|
51
|
+
* Fixes backslashes like `curl --request POST \` into double `\\` to fix JSON format
|
|
52
|
+
*/
|
|
53
|
+
function ensureProperEscaping(obj: any): any {
|
|
54
|
+
if (typeof obj === 'string') {
|
|
55
|
+
// Replace any single backslashes that aren't already part of an escape sequence
|
|
56
|
+
return obj.replace(/(?<!\\)\\(?!\\)/g, '\\\\');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (Array.isArray(obj)) {
|
|
60
|
+
return obj.map(item => ensureProperEscaping(item));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (obj && typeof obj === 'object') {
|
|
64
|
+
const result = { ...obj };
|
|
65
|
+
for (const key in result) {
|
|
66
|
+
result[key] = ensureProperEscaping(result[key]);
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return obj;
|
|
72
|
+
}
|