@mintlify/common 1.0.413 → 1.0.414
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/mdx/plugins/rehype/index.d.ts +1 -1
- package/dist/mdx/plugins/rehype/index.js +1 -1
- package/dist/mdx/plugins/rehype/rehypeCodeBlocks/buildMetaAttributes.d.ts +3 -0
- package/dist/mdx/plugins/rehype/rehypeCodeBlocks/buildMetaAttributes.js +16 -0
- package/dist/mdx/plugins/rehype/{rehypeCodeBlocks.d.ts → rehypeCodeBlocks/index.d.ts} +2 -0
- package/dist/mdx/plugins/rehype/rehypeCodeBlocks/index.js +124 -0
- package/dist/mdx/plugins/rehype/rehypeCodeBlocks/metaOptions.d.ts +123 -0
- package/dist/mdx/plugins/rehype/rehypeCodeBlocks/metaOptions.js +429 -0
- package/dist/mdx/plugins/rehype/rehypeCodeBlocks/parseMetaString.d.ts +20 -0
- package/dist/mdx/plugins/rehype/rehypeCodeBlocks/parseMetaString.js +69 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/dist/mdx/plugins/rehype/rehypeCodeBlocks.js +0 -59
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
export class MetaOptions {
|
|
2
|
+
constructor(input, reservedKeys = []) {
|
|
3
|
+
const { options, errors, remainingText } = parseOptions(input, reservedKeys);
|
|
4
|
+
this.parsedOptions = options;
|
|
5
|
+
this.errors = errors.length ? errors : undefined;
|
|
6
|
+
this.remainingText = remainingText;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A list of error messages that occurred when parsing the meta string,
|
|
10
|
+
* or `undefined` if no errors occurred.
|
|
11
|
+
*/
|
|
12
|
+
get getErrors() {
|
|
13
|
+
return this.errors;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Returns the remaining text after all parsed options are removed.
|
|
17
|
+
* This is useful for extracting filename from meta strings.
|
|
18
|
+
*/
|
|
19
|
+
getRemainingText() {
|
|
20
|
+
return this.remainingText;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Returns a list of meta options, optionally filtered by their key and/or {@link MetaOptionKind}.
|
|
24
|
+
*
|
|
25
|
+
* @param keyOrKeys
|
|
26
|
+
* Allows to filter the options by key. An empty string will return options without a key.
|
|
27
|
+
* A non-empty string will return options with a matching key (case-insensitive).
|
|
28
|
+
* An array of strings will return options with any of the matching keys.
|
|
29
|
+
* If omitted, no key-based filtering will be applied.
|
|
30
|
+
*
|
|
31
|
+
* @param kind
|
|
32
|
+
* Allows to filter the options by {@link MetaOptionKind}.
|
|
33
|
+
* If omitted, no kind-based filtering will be applied.
|
|
34
|
+
*/
|
|
35
|
+
list(keyOrKeys, kind) {
|
|
36
|
+
const filtered = this.parsedOptions.filter((option) => {
|
|
37
|
+
if (kind !== undefined && option.kind !== kind)
|
|
38
|
+
return false;
|
|
39
|
+
if (keyOrKeys === undefined)
|
|
40
|
+
return true;
|
|
41
|
+
const keys = Array.isArray(keyOrKeys) ? keyOrKeys : [keyOrKeys];
|
|
42
|
+
return keys.some((key) => { var _a; return (key === '' && !option.key) || ((_a = option.key) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === key.toLowerCase(); });
|
|
43
|
+
});
|
|
44
|
+
return filtered;
|
|
45
|
+
}
|
|
46
|
+
value(key, kind) {
|
|
47
|
+
var _a;
|
|
48
|
+
if (!key)
|
|
49
|
+
throw new Error('You must specify a non-empty key when using getString, getRange, getRegExp or getBoolean.');
|
|
50
|
+
return (_a = this.list(key, kind).pop()) === null || _a === void 0 ? void 0 : _a.value;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Returns the last string value with the given key (case-insensitive),
|
|
54
|
+
* or without a key by passing an empty string.
|
|
55
|
+
*/
|
|
56
|
+
getString(key) {
|
|
57
|
+
return this.value(key, 'string');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Returns an array of all string values with the given keys (case-insensitive),
|
|
61
|
+
* or without a key by passing an empty string.
|
|
62
|
+
*/
|
|
63
|
+
getStrings(keyOrKeys) {
|
|
64
|
+
return this.list(keyOrKeys, 'string').map((option) => option.value);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Returns the last range value (`{value}`) with the given key (case-insensitive),
|
|
68
|
+
* or without a key by passing an empty string.
|
|
69
|
+
*/
|
|
70
|
+
getRange(key) {
|
|
71
|
+
return this.value(key, 'range');
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Returns an array of all range values (`{value}`) with the given keys (case-insensitive),
|
|
75
|
+
* or without a key by passing an empty string.
|
|
76
|
+
*/
|
|
77
|
+
getRanges(keyOrKeys) {
|
|
78
|
+
return this.list(keyOrKeys, 'range').map((option) => option.value);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Returns the last integer value with the given key (case-insensitive),
|
|
82
|
+
* or without a key by passing an empty string.
|
|
83
|
+
*/
|
|
84
|
+
getInteger(key) {
|
|
85
|
+
return this.getIntegers(key).pop();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Returns an array of all integer values with the given keys (case-insensitive),
|
|
89
|
+
* or without a key by passing an empty string.
|
|
90
|
+
*/
|
|
91
|
+
getIntegers(keyOrKeys) {
|
|
92
|
+
return this.list(keyOrKeys)
|
|
93
|
+
.map((option) => {
|
|
94
|
+
// Skip values that are neither strings nor ranges
|
|
95
|
+
if (option.kind !== 'string' && option.kind !== 'range')
|
|
96
|
+
return NaN;
|
|
97
|
+
// Skip values that don't look like valid numbers
|
|
98
|
+
if (!/^-?\d+$/.test(option.value.trim()))
|
|
99
|
+
return NaN;
|
|
100
|
+
// Try to parse the value as an integer and return it
|
|
101
|
+
return parseInt(option.value, 10);
|
|
102
|
+
})
|
|
103
|
+
.filter((value) => !isNaN(value));
|
|
104
|
+
}
|
|
105
|
+
getStringsWithInteger(keyOrKeys) {
|
|
106
|
+
var _a, _b, _c, _d;
|
|
107
|
+
const strings = this.getStrings(keyOrKeys);
|
|
108
|
+
const integers = [];
|
|
109
|
+
for (const string of strings) {
|
|
110
|
+
const parts = string.split(',');
|
|
111
|
+
for (const part of parts) {
|
|
112
|
+
const trimmed = part.trim();
|
|
113
|
+
if (trimmed.includes('-')) {
|
|
114
|
+
const rangeParts = trimmed.split('-');
|
|
115
|
+
if (rangeParts.length === 2) {
|
|
116
|
+
const start = parseInt((_b = (_a = rangeParts[0]) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : '', 10);
|
|
117
|
+
const end = parseInt((_d = (_c = rangeParts[1]) === null || _c === void 0 ? void 0 : _c.trim()) !== null && _d !== void 0 ? _d : '', 10);
|
|
118
|
+
if (!isNaN(start) && !isNaN(end)) {
|
|
119
|
+
for (let i = start; i <= end; i++) {
|
|
120
|
+
integers.push(i);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
// Handle single number
|
|
127
|
+
const num = parseInt(trimmed, 10);
|
|
128
|
+
if (!isNaN(num)) {
|
|
129
|
+
integers.push(num);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return integers;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Returns an array of all integers from range values with the given keys (case-insensitive),
|
|
138
|
+
* parsing ranges like "1,3-5" to return [1,3,4,5].
|
|
139
|
+
* Works with range values (`{value}`) that contain comma-separated integers and ranges.
|
|
140
|
+
*/
|
|
141
|
+
getRangesWithInteger(keyOrKeys) {
|
|
142
|
+
var _a, _b, _c, _d;
|
|
143
|
+
const ranges = this.getRanges(keyOrKeys);
|
|
144
|
+
const integers = [];
|
|
145
|
+
for (const range of ranges) {
|
|
146
|
+
const parts = range.split(',');
|
|
147
|
+
for (const part of parts) {
|
|
148
|
+
const trimmed = part.trim();
|
|
149
|
+
if (trimmed.includes('-')) {
|
|
150
|
+
const rangeParts = trimmed.split('-');
|
|
151
|
+
if (rangeParts.length === 2) {
|
|
152
|
+
const start = parseInt((_b = (_a = rangeParts[0]) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : '', 10);
|
|
153
|
+
const end = parseInt((_d = (_c = rangeParts[1]) === null || _c === void 0 ? void 0 : _c.trim()) !== null && _d !== void 0 ? _d : '', 10);
|
|
154
|
+
if (!isNaN(start) && !isNaN(end)) {
|
|
155
|
+
for (let i = start; i <= end; i++) {
|
|
156
|
+
integers.push(i);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
// Handle single number
|
|
163
|
+
const num = parseInt(trimmed, 10);
|
|
164
|
+
if (!isNaN(num)) {
|
|
165
|
+
integers.push(num);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return integers;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Returns the last RegExp value (`/value/`) with the given key (case-insensitive),
|
|
174
|
+
* or without a key by passing an empty string.
|
|
175
|
+
*/
|
|
176
|
+
getRegExp(key) {
|
|
177
|
+
return this.value(key, 'regexp');
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Returns an array of all RegExp values (`/value/`) with the given keys (case-insensitive),
|
|
181
|
+
* or without a key by passing an empty string.
|
|
182
|
+
*/
|
|
183
|
+
getRegExps(keyOrKeys) {
|
|
184
|
+
return this.list(keyOrKeys, 'regexp').map((option) => option.value);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Returns the last boolean value with the given key (case-insensitive).
|
|
188
|
+
*/
|
|
189
|
+
getBoolean(key) {
|
|
190
|
+
// First try to get a boolean option
|
|
191
|
+
const booleanValue = this.value(key, 'boolean');
|
|
192
|
+
if (booleanValue !== undefined) {
|
|
193
|
+
return booleanValue;
|
|
194
|
+
}
|
|
195
|
+
// Fall back to checking string values for boolean-like content
|
|
196
|
+
const stringValue = this.value(key, 'string');
|
|
197
|
+
if (stringValue !== undefined) {
|
|
198
|
+
const lowerValue = stringValue.toLowerCase();
|
|
199
|
+
if (lowerValue === 'true')
|
|
200
|
+
return true;
|
|
201
|
+
if (lowerValue === 'false')
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function parseOptions(input, reservedKeys = [], syntax = {
|
|
208
|
+
valueDelimiters: ["'", '"', '/', '{...}'],
|
|
209
|
+
keyValueSeparator: '=',
|
|
210
|
+
}) {
|
|
211
|
+
const options = [];
|
|
212
|
+
const errors = [];
|
|
213
|
+
// Parse delimited values first and remove them from the input string
|
|
214
|
+
const delimitedValues = parseDelimitedValues(input, syntax);
|
|
215
|
+
let inputWithoutDelimited = input;
|
|
216
|
+
delimitedValues.forEach(({ index, fullMatch: raw, key, value, valueStartDelimiter, valueEndDelimiter }) => {
|
|
217
|
+
inputWithoutDelimited =
|
|
218
|
+
inputWithoutDelimited.slice(0, index) +
|
|
219
|
+
' '.repeat(raw.length) +
|
|
220
|
+
inputWithoutDelimited.slice(index + raw.length);
|
|
221
|
+
// Handle regular expressions
|
|
222
|
+
if (valueStartDelimiter === '/') {
|
|
223
|
+
let regExp;
|
|
224
|
+
try {
|
|
225
|
+
// Try to use regular expressions with capture group indices
|
|
226
|
+
regExp = new RegExp(value, 'gd');
|
|
227
|
+
}
|
|
228
|
+
catch (_error) {
|
|
229
|
+
try {
|
|
230
|
+
// Use fallback if unsupported
|
|
231
|
+
regExp = new RegExp(value, 'g');
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
/* c8 ignore next */
|
|
235
|
+
const msg = error instanceof Error ? error.message : error;
|
|
236
|
+
errors.push(`Failed to parse option \`${raw.trim()}\`: ${msg}`);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
options.push({
|
|
241
|
+
index,
|
|
242
|
+
raw,
|
|
243
|
+
kind: 'regexp',
|
|
244
|
+
key,
|
|
245
|
+
value: regExp,
|
|
246
|
+
valueStartDelimiter,
|
|
247
|
+
valueEndDelimiter,
|
|
248
|
+
});
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
// Handle ranges
|
|
252
|
+
if (valueStartDelimiter === '{') {
|
|
253
|
+
options.push({
|
|
254
|
+
index,
|
|
255
|
+
raw,
|
|
256
|
+
kind: 'range',
|
|
257
|
+
key,
|
|
258
|
+
value,
|
|
259
|
+
valueStartDelimiter,
|
|
260
|
+
valueEndDelimiter,
|
|
261
|
+
});
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
// Handle quoted boolean values
|
|
265
|
+
if (value.toLowerCase() === 'true' || value.toLowerCase() === 'false') {
|
|
266
|
+
options.push({
|
|
267
|
+
index,
|
|
268
|
+
raw,
|
|
269
|
+
kind: 'boolean',
|
|
270
|
+
key,
|
|
271
|
+
value: value.toLowerCase() === 'true',
|
|
272
|
+
valueStartDelimiter,
|
|
273
|
+
valueEndDelimiter,
|
|
274
|
+
});
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
// Treat all other options as strings
|
|
278
|
+
options.push({
|
|
279
|
+
index,
|
|
280
|
+
raw,
|
|
281
|
+
kind: 'string',
|
|
282
|
+
key,
|
|
283
|
+
value,
|
|
284
|
+
valueStartDelimiter,
|
|
285
|
+
valueEndDelimiter,
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
// Now parse all remaining options
|
|
289
|
+
const escapedSeparator = escapeRegExp(syntax.keyValueSeparator).replace(/-/g, '\\-');
|
|
290
|
+
const regExp = new RegExp(`([^\\s${escapedSeparator}]+)(?:\\s*${escapedSeparator}\\s*(\\S+))?`, 'g');
|
|
291
|
+
const simpleOptions = [...inputWithoutDelimited.matchAll(regExp)];
|
|
292
|
+
let remainingText = inputWithoutDelimited;
|
|
293
|
+
simpleOptions.forEach((match) => {
|
|
294
|
+
const index = match.index;
|
|
295
|
+
const [raw, key, value] = match;
|
|
296
|
+
let option;
|
|
297
|
+
if (value === 'true' || value === 'false' || value === undefined) {
|
|
298
|
+
// Handle booleans
|
|
299
|
+
option = {
|
|
300
|
+
index,
|
|
301
|
+
raw,
|
|
302
|
+
kind: 'boolean',
|
|
303
|
+
key,
|
|
304
|
+
value: value !== 'false',
|
|
305
|
+
valueStartDelimiter: '',
|
|
306
|
+
valueEndDelimiter: '',
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
// Treat all other options as strings
|
|
311
|
+
option = {
|
|
312
|
+
index,
|
|
313
|
+
raw,
|
|
314
|
+
kind: 'string',
|
|
315
|
+
key,
|
|
316
|
+
value,
|
|
317
|
+
valueStartDelimiter: '',
|
|
318
|
+
valueEndDelimiter: '',
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
options.push(option);
|
|
322
|
+
if (option.key && reservedKeys.includes(option.key)) {
|
|
323
|
+
remainingText =
|
|
324
|
+
remainingText.slice(0, index) +
|
|
325
|
+
' '.repeat(raw.length) +
|
|
326
|
+
remainingText.slice(index + raw.length);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
// Sort options by their index in the input string
|
|
330
|
+
options.sort((a, b) => a.index - b.index);
|
|
331
|
+
return {
|
|
332
|
+
options,
|
|
333
|
+
errors,
|
|
334
|
+
remainingText: remainingText.trim(),
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
function parseDelimitedValues(input, syntax) {
|
|
338
|
+
const valueDelimiterPairs = syntax.valueDelimiters.map((valueDelimiter) => {
|
|
339
|
+
const parts = valueDelimiter.split('...');
|
|
340
|
+
const isPair = parts.length === 2;
|
|
341
|
+
return {
|
|
342
|
+
valueStartDelimiter: isPair ? parts[0] : valueDelimiter,
|
|
343
|
+
valueEndDelimiter: isPair ? parts[1] : valueDelimiter,
|
|
344
|
+
};
|
|
345
|
+
});
|
|
346
|
+
const singleCharValueDelimiters = valueDelimiterPairs
|
|
347
|
+
.map((pair) => pair.valueStartDelimiter)
|
|
348
|
+
.filter((delimiter) => delimiter != null && delimiter.length === 1)
|
|
349
|
+
.join('');
|
|
350
|
+
// Build a regular expression that contains alternatives for all value delimiters
|
|
351
|
+
const regExpParts = valueDelimiterPairs
|
|
352
|
+
.filter((pair) => pair.valueStartDelimiter && pair.valueEndDelimiter)
|
|
353
|
+
.map(({ valueStartDelimiter, valueEndDelimiter }) => {
|
|
354
|
+
const part = [
|
|
355
|
+
// Whitespace or start of string
|
|
356
|
+
`(?:\\s|^)`,
|
|
357
|
+
// Optional group for key name and key/value separator
|
|
358
|
+
[
|
|
359
|
+
// Start of non-capturing optional group
|
|
360
|
+
`(?:`,
|
|
361
|
+
// Key name (captured)
|
|
362
|
+
`([^\\s${escapeRegExp((singleCharValueDelimiters + syntax.keyValueSeparator).replace(/-/g, '\\-'))}]+)`,
|
|
363
|
+
// Optional whitespace
|
|
364
|
+
`\\s*`,
|
|
365
|
+
// Key/value separator (e.g. `=`)
|
|
366
|
+
escapeRegExp(syntax.keyValueSeparator),
|
|
367
|
+
// Optional whitespace
|
|
368
|
+
`\\s*`,
|
|
369
|
+
// End of non-capturing optional group
|
|
370
|
+
`)?`,
|
|
371
|
+
],
|
|
372
|
+
// Value start delimiter
|
|
373
|
+
escapeRegExp(valueStartDelimiter),
|
|
374
|
+
// Value string (captured, can be an empty string),
|
|
375
|
+
// consisting of any of the following parts:
|
|
376
|
+
// - any character that is not a backslash
|
|
377
|
+
// - a backslash followed by any character
|
|
378
|
+
`((?:[^\\\\]|\\\\.)*?)`,
|
|
379
|
+
// Value end delimiter that is not escaped by a preceding `\`
|
|
380
|
+
`${escapeRegExp(valueEndDelimiter)}`,
|
|
381
|
+
// Whitespace or end of string
|
|
382
|
+
`(?=\\s|$)`,
|
|
383
|
+
];
|
|
384
|
+
return part.flat().join('');
|
|
385
|
+
});
|
|
386
|
+
if (regExpParts.length === 0) {
|
|
387
|
+
return [];
|
|
388
|
+
}
|
|
389
|
+
const regExp = new RegExp(regExpParts.join('|'), 'g');
|
|
390
|
+
// Now use the regular expression to find all matches
|
|
391
|
+
const matches = [...input.matchAll(regExp)];
|
|
392
|
+
return matches.map((match) => {
|
|
393
|
+
const [fullMatch, ...keyValuePairs] = match;
|
|
394
|
+
// Determine which value delimiter pair was used for this match
|
|
395
|
+
// by looking for the first defined value in the capture group array
|
|
396
|
+
// (matches can have no key, so the found capture group can either be a key or a value,
|
|
397
|
+
// but as they come in pairs, a division by 2 will give us the delimiter pair index)
|
|
398
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
399
|
+
const firstCaptureGroupIndex = keyValuePairs.findIndex((value) => value !== undefined);
|
|
400
|
+
const delimiterPairIdx = Math.floor(firstCaptureGroupIndex / 2);
|
|
401
|
+
const delimiterPair = valueDelimiterPairs[delimiterPairIdx];
|
|
402
|
+
if (!delimiterPair) {
|
|
403
|
+
throw new Error(`Unable to find delimiter pair at index ${delimiterPairIdx}`);
|
|
404
|
+
}
|
|
405
|
+
const { valueStartDelimiter, valueEndDelimiter } = delimiterPair;
|
|
406
|
+
// Also retrieve the actual matched key and value
|
|
407
|
+
const [key, escapedValue] = keyValuePairs.slice(delimiterPairIdx * 2, delimiterPairIdx * 2 + 2);
|
|
408
|
+
// Unescape value by removing any backslash that escapes any of the following:
|
|
409
|
+
// - another backslash (e.g. `\\` becomes `\`)
|
|
410
|
+
// - the value end delimiter (e.g. `\"` becomes `"`)
|
|
411
|
+
// Any other backslashes are kept because users may not know
|
|
412
|
+
// that they need to be escaped in the first place.
|
|
413
|
+
const escapedBackslashOrValueEndDelimiter = new RegExp(`\\\\(\\\\|${escapeRegExp(valueEndDelimiter)})`, 'g');
|
|
414
|
+
const value = escapedValue
|
|
415
|
+
? escapedValue.replace(escapedBackslashOrValueEndDelimiter, '$1')
|
|
416
|
+
: '';
|
|
417
|
+
return {
|
|
418
|
+
index: match.index || 0,
|
|
419
|
+
fullMatch,
|
|
420
|
+
key: key || '',
|
|
421
|
+
value,
|
|
422
|
+
valueStartDelimiter: valueStartDelimiter,
|
|
423
|
+
valueEndDelimiter: valueEndDelimiter,
|
|
424
|
+
};
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
function escapeRegExp(input) {
|
|
428
|
+
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
429
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { MetaOptions } from './metaOptions.js';
|
|
2
|
+
export type Meta = {
|
|
3
|
+
filename?: string;
|
|
4
|
+
icon?: string;
|
|
5
|
+
lang?: string;
|
|
6
|
+
lines?: boolean;
|
|
7
|
+
wrap?: boolean;
|
|
8
|
+
expandable?: boolean;
|
|
9
|
+
highlight?: number[];
|
|
10
|
+
focus?: number[];
|
|
11
|
+
};
|
|
12
|
+
export type MetaParserConfig = {
|
|
13
|
+
[K in keyof Meta]: {
|
|
14
|
+
keys: string[];
|
|
15
|
+
parser: (metaOptions: MetaOptions) => Meta[K];
|
|
16
|
+
defaultValue?: Meta[K];
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export declare const META_PARSER_CONFIG: MetaParserConfig;
|
|
20
|
+
export declare function parseMetaString(input: string): Meta;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { MetaOptions } from './metaOptions.js';
|
|
2
|
+
export const META_PARSER_CONFIG = {
|
|
3
|
+
filename: {
|
|
4
|
+
keys: ['title'],
|
|
5
|
+
parser: (metaOptions) => {
|
|
6
|
+
const title = metaOptions.getString('title');
|
|
7
|
+
return title || metaOptions.getRemainingText() || '';
|
|
8
|
+
},
|
|
9
|
+
defaultValue: '',
|
|
10
|
+
},
|
|
11
|
+
icon: {
|
|
12
|
+
keys: ['icon'],
|
|
13
|
+
parser: (metaOptions) => metaOptions.getString('icon'),
|
|
14
|
+
},
|
|
15
|
+
lang: {
|
|
16
|
+
keys: ['lang'],
|
|
17
|
+
parser: (metaOptions) => metaOptions.getString('lang'),
|
|
18
|
+
},
|
|
19
|
+
lines: {
|
|
20
|
+
keys: ['lines'],
|
|
21
|
+
parser: (metaOptions) => metaOptions.getBoolean('lines'),
|
|
22
|
+
},
|
|
23
|
+
wrap: {
|
|
24
|
+
keys: ['wrap'],
|
|
25
|
+
parser: (metaOptions) => metaOptions.getBoolean('wrap'),
|
|
26
|
+
},
|
|
27
|
+
expandable: {
|
|
28
|
+
keys: ['expandable', '[expandable]'],
|
|
29
|
+
parser: (metaOptions) => metaOptions.getBoolean('[expandable]') || metaOptions.getBoolean('expandable'),
|
|
30
|
+
},
|
|
31
|
+
highlight: {
|
|
32
|
+
keys: ['highlight'],
|
|
33
|
+
parser: (metaOptions) => {
|
|
34
|
+
const highlightWithString = metaOptions.getStringsWithInteger('highlight');
|
|
35
|
+
const highlightWithInteger = metaOptions.getRangesWithInteger('highlight');
|
|
36
|
+
const highlightWithStringWithoutKey = metaOptions.getRangesWithInteger('');
|
|
37
|
+
const result = [
|
|
38
|
+
...highlightWithString,
|
|
39
|
+
...highlightWithInteger,
|
|
40
|
+
...highlightWithStringWithoutKey,
|
|
41
|
+
];
|
|
42
|
+
return result.length ? Array.from(new Set(result)) : undefined;
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
focus: {
|
|
46
|
+
keys: ['focus'],
|
|
47
|
+
parser: (metaOptions) => {
|
|
48
|
+
const focusWithString = metaOptions.getStringsWithInteger('focus');
|
|
49
|
+
const focusWithInteger = metaOptions.getRangesWithInteger('focus');
|
|
50
|
+
const result = [...focusWithString, ...focusWithInteger];
|
|
51
|
+
return result.length ? Array.from(new Set(result)) : undefined;
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
export function parseMetaString(input) {
|
|
56
|
+
const reservedKeys = Object.values(META_PARSER_CONFIG).flatMap((config) => config.keys);
|
|
57
|
+
const metaOptions = new MetaOptions(input, reservedKeys);
|
|
58
|
+
const result = {};
|
|
59
|
+
for (const [key, config] of Object.entries(META_PARSER_CONFIG)) {
|
|
60
|
+
const parsedValue = config === null || config === void 0 ? void 0 : config.parser(metaOptions);
|
|
61
|
+
if (parsedValue !== undefined) {
|
|
62
|
+
result[key] = parsedValue;
|
|
63
|
+
}
|
|
64
|
+
else if ((config === null || config === void 0 ? void 0 : config.defaultValue) !== undefined) {
|
|
65
|
+
result[key] = config.defaultValue;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|