@bfra.me/doc-sync 0.1.0 → 0.1.2

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.
@@ -1,17 +1,25 @@
1
1
  import {
2
- createHeadingPattern,
3
- extractCodeBlocks,
4
- findEmptyMarkdownLinks,
5
2
  generateMDXDocument,
6
- hasComponent,
7
3
  mergeContent,
8
4
  validateMDXSyntax
9
- } from "./chunk-G5KKGJYO.js";
5
+ } from "./chunk-CUBMCGAY.js";
10
6
  import {
11
7
  analyzePublicAPI,
12
8
  parsePackageComplete,
13
9
  parseReadmeFile
14
- } from "./chunk-6NKAJT2M.js";
10
+ } from "./chunk-VHUUC45J.js";
11
+ import {
12
+ createHeadingPattern,
13
+ extractCodeBlocks,
14
+ findEmptyMarkdownLinks,
15
+ hasComponent
16
+ } from "./chunk-GZ2MP3VN.js";
17
+ import {
18
+ createDocDebouncer,
19
+ createDocWatcher,
20
+ determineRegenerationScope,
21
+ groupChangesByPackage
22
+ } from "./chunk-45NROJIG.js";
15
23
 
16
24
  // src/orchestrator/package-scanner.ts
17
25
  import fs from "fs/promises";
@@ -197,318 +205,6 @@ function getPackageScope(packageName) {
197
205
  return void 0;
198
206
  }
199
207
 
200
- // src/watcher/file-watcher.ts
201
- import path2 from "path";
202
- import process from "process";
203
- import { createFileWatcher as createBaseWatcher } from "@bfra.me/es/watcher";
204
- var DEFAULT_WATCH_PATTERNS = [
205
- "packages/*/README.md",
206
- "packages/*/readme.md",
207
- "packages/*/package.json",
208
- "packages/*/src/**/*.ts",
209
- "packages/*/src/**/*.tsx"
210
- ];
211
- var DEFAULT_IGNORE_PATTERNS = [
212
- "**/node_modules/**",
213
- "**/lib/**",
214
- "**/dist/**",
215
- "**/.git/**",
216
- "**/coverage/**",
217
- "**/*.test.ts",
218
- "**/*.spec.ts",
219
- "**/__tests__/**",
220
- "**/__mocks__/**"
221
- ];
222
- function extractPackageName(filePath, root) {
223
- const relativePath = path2.relative(root, filePath);
224
- const parts = relativePath.split(path2.sep);
225
- if (parts[0] === "packages" && parts.length > 1) {
226
- return parts[1];
227
- }
228
- return void 0;
229
- }
230
- function createDocWatcher(options = {}) {
231
- const {
232
- rootDir = process.cwd(),
233
- debounceMs = 300,
234
- additionalIgnore = [],
235
- usePolling = false
236
- } = options;
237
- const watchPaths = DEFAULT_WATCH_PATTERNS.map((pattern) => path2.join(rootDir, pattern));
238
- const ignoredPatterns = [...DEFAULT_IGNORE_PATTERNS, ...additionalIgnore];
239
- const watcherOptions = {
240
- debounceMs,
241
- ignored: ignoredPatterns,
242
- usePolling
243
- };
244
- const baseWatcher = createBaseWatcher(watchPaths, watcherOptions);
245
- const handlers = /* @__PURE__ */ new Set();
246
- function transformToDocEvents(changes) {
247
- return changes.map((change) => ({
248
- type: change.type,
249
- path: change.path,
250
- packageName: extractPackageName(change.path, rootDir),
251
- timestamp: new Date(change.timestamp)
252
- }));
253
- }
254
- return {
255
- async start() {
256
- baseWatcher.on("change", (event) => {
257
- const docEvents = transformToDocEvents(event.changes);
258
- for (const handler of handlers) {
259
- Promise.resolve(handler(docEvents)).catch((error) => {
260
- console.error("[doc-sync] Error in change handler:", error);
261
- });
262
- }
263
- });
264
- await baseWatcher.start();
265
- },
266
- async close() {
267
- await baseWatcher.close();
268
- handlers.clear();
269
- },
270
- onChanges(handler) {
271
- handlers.add(handler);
272
- return () => {
273
- handlers.delete(handler);
274
- };
275
- },
276
- getWatchedPaths() {
277
- return watchPaths;
278
- }
279
- };
280
- }
281
- function categorizeFile(filePath) {
282
- const basename = path2.basename(filePath).toLowerCase();
283
- if (basename === "readme.md" || basename === "readme") {
284
- return "readme";
285
- }
286
- if (basename === "package.json") {
287
- return "package-json";
288
- }
289
- const ext = path2.extname(filePath).toLowerCase();
290
- if (ext === ".ts" || ext === ".tsx") {
291
- return "source";
292
- }
293
- return "unknown";
294
- }
295
- function groupChangesByPackage(events) {
296
- const grouped = /* @__PURE__ */ new Map();
297
- for (const event of events) {
298
- const pkg = event.packageName ?? "__unknown__";
299
- const existing = grouped.get(pkg);
300
- if (existing === void 0) {
301
- grouped.set(pkg, [event]);
302
- } else {
303
- existing.push(event);
304
- }
305
- }
306
- return grouped;
307
- }
308
- function filterDocumentationChanges(events) {
309
- return events.filter((event) => {
310
- const category = categorizeFile(event.path);
311
- return category !== "unknown";
312
- });
313
- }
314
-
315
- // src/watcher/change-detector.ts
316
- import { createChangeDetector as createBaseDetector } from "@bfra.me/es/watcher";
317
- function createDocChangeDetector(options = {}) {
318
- const baseDetector = createBaseDetector({ algorithm: options.algorithm });
319
- const packageFiles = /* @__PURE__ */ new Map();
320
- return {
321
- async hasChanged(filePath) {
322
- return baseDetector.hasChanged(filePath);
323
- },
324
- async record(filePath) {
325
- await baseDetector.record(filePath);
326
- },
327
- async recordPackage(pkg, files) {
328
- const fileSet = new Set(files);
329
- packageFiles.set(pkg.name, fileSet);
330
- await Promise.all(files.map(async (file) => baseDetector.record(file)));
331
- },
332
- clear(filePath) {
333
- baseDetector.clear(filePath);
334
- for (const fileSet of packageFiles.values()) {
335
- fileSet.delete(filePath);
336
- }
337
- },
338
- clearAll() {
339
- baseDetector.clearAll();
340
- packageFiles.clear();
341
- },
342
- async analyzeChanges(events) {
343
- const packageChanges = /* @__PURE__ */ new Map();
344
- for (const event of events) {
345
- const packageName = event.packageName ?? "__unknown__";
346
- const category = categorizeFile(event.path);
347
- let analysis = packageChanges.get(packageName);
348
- if (analysis === void 0) {
349
- analysis = { categories: /* @__PURE__ */ new Set(), files: [] };
350
- packageChanges.set(packageName, analysis);
351
- }
352
- if (category !== "unknown") {
353
- analysis.categories.add(category);
354
- }
355
- analysis.files.push(event.path);
356
- }
357
- const results = [];
358
- for (const [packageName, analysis] of packageChanges) {
359
- const changedCategories = [...analysis.categories];
360
- const needsRegeneration = changedCategories.includes("readme") || changedCategories.includes("package-json") || changedCategories.includes("source");
361
- results.push({
362
- packageName,
363
- needsRegeneration,
364
- changedCategories,
365
- changedFiles: analysis.files
366
- });
367
- }
368
- return results;
369
- }
370
- };
371
- }
372
- function determineRegenerationScope(changedCategories) {
373
- const hasReadme = changedCategories.includes("readme");
374
- const hasSource = changedCategories.includes("source");
375
- const hasPackageJson = changedCategories.includes("package-json");
376
- if (hasReadme && hasSource) {
377
- return "full";
378
- }
379
- if (hasSource) {
380
- return "api-only";
381
- }
382
- if (hasReadme) {
383
- return "readme-only";
384
- }
385
- if (hasPackageJson) {
386
- return "metadata-only";
387
- }
388
- return "none";
389
- }
390
- async function hasAnyFileChanged(detector, files) {
391
- const results = await Promise.all(files.map(async (file) => detector.hasChanged(file)));
392
- return results.some((changed) => changed);
393
- }
394
-
395
- // src/watcher/debouncer.ts
396
- import { createDebouncer as createBaseDebouncer } from "@bfra.me/es/watcher";
397
- function createDocDebouncer(handler, options = {}) {
398
- const { debounceMs = 300, maxWaitMs = 5e3 } = options;
399
- let pendingEvents = [];
400
- let maxWaitTimeout;
401
- function processEvents(events) {
402
- if (maxWaitTimeout !== void 0) {
403
- clearTimeout(maxWaitTimeout);
404
- maxWaitTimeout = void 0;
405
- }
406
- const deduplicated = deduplicateEvents(events);
407
- if (deduplicated.length > 0) {
408
- Promise.resolve(handler(deduplicated)).catch((error) => {
409
- console.error("[doc-sync] Error in batch handler:", error);
410
- });
411
- }
412
- }
413
- const baseDebouncer = createBaseDebouncer((events) => {
414
- processEvents(events);
415
- pendingEvents = [];
416
- }, debounceMs);
417
- function startMaxWaitTimer() {
418
- if (maxWaitTimeout === void 0) {
419
- maxWaitTimeout = setTimeout(() => {
420
- baseDebouncer.flush();
421
- }, maxWaitMs);
422
- }
423
- }
424
- return {
425
- add(event) {
426
- pendingEvents.push(event);
427
- startMaxWaitTimer();
428
- baseDebouncer.add(event);
429
- },
430
- addAll(events) {
431
- for (const event of events) {
432
- pendingEvents.push(event);
433
- baseDebouncer.add(event);
434
- }
435
- if (events.length > 0) {
436
- startMaxWaitTimer();
437
- }
438
- },
439
- flush() {
440
- if (maxWaitTimeout !== void 0) {
441
- clearTimeout(maxWaitTimeout);
442
- maxWaitTimeout = void 0;
443
- }
444
- baseDebouncer.flush();
445
- },
446
- cancel() {
447
- if (maxWaitTimeout !== void 0) {
448
- clearTimeout(maxWaitTimeout);
449
- maxWaitTimeout = void 0;
450
- }
451
- pendingEvents = [];
452
- baseDebouncer.cancel();
453
- },
454
- getPendingCount() {
455
- return pendingEvents.length;
456
- }
457
- };
458
- }
459
- function deduplicateEvents(events) {
460
- const latestByPath = /* @__PURE__ */ new Map();
461
- for (const event of events) {
462
- const existing = latestByPath.get(event.path);
463
- if (existing === void 0 || event.timestamp > existing.timestamp) {
464
- latestByPath.set(event.path, event);
465
- }
466
- }
467
- return [...latestByPath.values()];
468
- }
469
- function consolidateEvents(events) {
470
- const byPath = /* @__PURE__ */ new Map();
471
- for (const event of events) {
472
- const existing = byPath.get(event.path);
473
- if (existing === void 0) {
474
- byPath.set(event.path, [event]);
475
- } else {
476
- existing.push(event);
477
- }
478
- }
479
- const consolidated = [];
480
- for (const [, pathEvents] of byPath) {
481
- const firstEvent = pathEvents[0];
482
- if (firstEvent === void 0) {
483
- continue;
484
- }
485
- if (pathEvents.length === 1) {
486
- consolidated.push(firstEvent);
487
- continue;
488
- }
489
- pathEvents.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
490
- const first = pathEvents[0];
491
- const last = pathEvents.at(-1);
492
- if (first === void 0 || last === void 0) {
493
- continue;
494
- }
495
- if (first.type === "add" && last.type === "unlink") {
496
- continue;
497
- }
498
- if (first.type === "unlink" && last.type === "add") {
499
- consolidated.push({
500
- type: "change",
501
- path: last.path,
502
- packageName: last.packageName,
503
- timestamp: last.timestamp
504
- });
505
- continue;
506
- }
507
- consolidated.push(last);
508
- }
509
- return consolidated;
510
- }
511
-
512
208
  // src/orchestrator/validation-pipeline.ts
513
209
  import { err as err2, ok as ok2 } from "@bfra.me/es/result";
514
210
  var DEFAULT_OPTIONS2 = {
@@ -722,7 +418,7 @@ function validateContentString(content, options) {
722
418
 
723
419
  // src/orchestrator/sync-orchestrator.ts
724
420
  import fs2 from "fs/promises";
725
- import path3 from "path";
421
+ import path2 from "path";
726
422
  import { err as err3, ok as ok3 } from "@bfra.me/es/result";
727
423
  function createSyncOrchestrator(options) {
728
424
  const { config, dryRun = false, verbose = false, onProgress, onError } = options;
@@ -943,7 +639,7 @@ function createSyncOrchestrator(options) {
943
639
  }
944
640
  function getOutputPath(packageName, outputDir) {
945
641
  const slug = createSlug(getUnscopedName2(packageName));
946
- return path3.join(outputDir, `${slug}.mdx`);
642
+ return path2.join(outputDir, `${slug}.mdx`);
947
643
  }
948
644
  function createSlug(name) {
949
645
  return name.toLowerCase().replaceAll(/[^a-z0-9-]/g, "-");
@@ -958,7 +654,7 @@ function getUnscopedName2(packageName) {
958
654
  return packageName;
959
655
  }
960
656
  async function writeFile(filePath, content) {
961
- const dir = path3.dirname(filePath);
657
+ const dir = path2.dirname(filePath);
962
658
  await fs2.mkdir(dir, { recursive: true });
963
659
  await fs2.writeFile(filePath, content, "utf-8");
964
660
  }
@@ -992,15 +688,15 @@ function isNodeError(error) {
992
688
  return error instanceof Error && "code" in error;
993
689
  }
994
690
  function categorizeFileChange(filePath) {
995
- const basename = path3.basename(filePath).toLowerCase();
691
+ const basename = path2.basename(filePath).toLowerCase();
996
692
  if (basename === "readme.md" || basename === "readme") return "readme";
997
693
  if (basename === "package.json") return "package-json";
998
694
  if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) return "source";
999
695
  return "unknown";
1000
696
  }
1001
697
  function isValidFilePath(filePath, rootDir) {
1002
- const resolvedPath = path3.resolve(filePath);
1003
- const resolvedRoot = path3.resolve(rootDir);
698
+ const resolvedPath = path2.resolve(filePath);
699
+ const resolvedRoot = path2.resolve(rootDir);
1004
700
  return resolvedPath.startsWith(resolvedRoot);
1005
701
  }
1006
702
 
@@ -1008,20 +704,10 @@ export {
1008
704
  createPackageScanner,
1009
705
  filterPackagesByPattern,
1010
706
  groupPackagesByScope,
1011
- createDocWatcher,
1012
- categorizeFile,
1013
- groupChangesByPackage,
1014
- filterDocumentationChanges,
1015
- createDocChangeDetector,
1016
- determineRegenerationScope,
1017
- hasAnyFileChanged,
1018
- createDocDebouncer,
1019
- deduplicateEvents,
1020
- consolidateEvents,
1021
707
  createValidationPipeline,
1022
708
  validateDocument,
1023
709
  validateContentString,
1024
710
  createSyncOrchestrator,
1025
711
  isValidFilePath
1026
712
  };
1027
- //# sourceMappingURL=chunk-DR6UG237.js.map
713
+ //# sourceMappingURL=chunk-DTXB5PMR.js.map
@@ -0,0 +1,261 @@
1
+ // src/utils/sanitization.ts
2
+ import { sanitizeInput } from "@bfra.me/es/validation";
3
+ import escapeHtml from "escape-html";
4
+ function sanitizeForMDX(content) {
5
+ const escaped = sanitizeInput(content, { trim: false });
6
+ return escaped.replaceAll("{", "{").replaceAll("}", "}");
7
+ }
8
+ function sanitizeAttribute(value) {
9
+ return escapeHtml(value);
10
+ }
11
+ function parseJSXAttributes(tag) {
12
+ const attrs = [];
13
+ const spaceIndex = tag.indexOf(" ");
14
+ if (spaceIndex === -1) return attrs;
15
+ const closeIndex = tag.lastIndexOf(">");
16
+ if (closeIndex === -1) return attrs;
17
+ const attrRegion = tag.slice(spaceIndex + 1, closeIndex).trim();
18
+ let i = 0;
19
+ while (i < attrRegion.length) {
20
+ while (i < attrRegion.length && /\s/.test(attrRegion.charAt(i))) i++;
21
+ if (i >= attrRegion.length) break;
22
+ let name = "";
23
+ while (i < attrRegion.length && /[\w-]/.test(attrRegion.charAt(i))) {
24
+ name += attrRegion[i];
25
+ i++;
26
+ }
27
+ if (!name) break;
28
+ while (i < attrRegion.length && /\s/.test(attrRegion.charAt(i))) i++;
29
+ if (i >= attrRegion.length || attrRegion[i] !== "=") {
30
+ attrs.push({ name, value: null });
31
+ continue;
32
+ }
33
+ i++;
34
+ while (i < attrRegion.length && /\s/.test(attrRegion.charAt(i))) i++;
35
+ if (i >= attrRegion.length) {
36
+ attrs.push({ name, value: "" });
37
+ break;
38
+ }
39
+ let value = "";
40
+ const quote = attrRegion[i];
41
+ if (quote === '"' || quote === "'") {
42
+ i++;
43
+ while (i < attrRegion.length && attrRegion[i] !== quote) {
44
+ value += attrRegion[i];
45
+ i++;
46
+ }
47
+ if (i < attrRegion.length) i++;
48
+ } else {
49
+ while (i < attrRegion.length && !/[\s/>]/.test(attrRegion.charAt(i))) {
50
+ value += attrRegion[i];
51
+ i++;
52
+ }
53
+ }
54
+ attrs.push({ name, value });
55
+ }
56
+ return attrs;
57
+ }
58
+ function sanitizeJSXTag(tag) {
59
+ const tagMatch = tag.match(/^<([A-Z][a-zA-Z0-9]*)/);
60
+ if (!tagMatch || typeof tagMatch[1] !== "string" || tagMatch[1].length === 0) {
61
+ return escapeHtml(tag);
62
+ }
63
+ const tagName = tagMatch[1];
64
+ const selfClosing = tag.endsWith("/>");
65
+ const attributes = parseJSXAttributes(tag);
66
+ const sanitizedAttrs = attributes.map(({ name, value }) => {
67
+ if (value === null) return name;
68
+ const escaped = escapeHtml(value);
69
+ return `${name}="${escaped}"`;
70
+ });
71
+ const attrString = sanitizedAttrs.length > 0 ? ` ${sanitizedAttrs.join(" ")}` : "";
72
+ return `<${tagName}${attrString}${selfClosing ? " />" : ">"}`;
73
+ }
74
+
75
+ // src/utils/safe-patterns.ts
76
+ import remarkParse from "remark-parse";
77
+ import { unified } from "unified";
78
+ function createHeadingPattern(level) {
79
+ if (level < 1 || level > 6) {
80
+ throw new Error("Heading level must be between 1 and 6");
81
+ }
82
+ const hashes = "#".repeat(level);
83
+ return new RegExp(`^${hashes} ([^\r
84
+ ]+)$`, "gm");
85
+ }
86
+ function hasComponent(content, componentName) {
87
+ const escaped = componentName.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
88
+ const pattern = new RegExp(String.raw`<${escaped}(?:\s[^>]*)?(?:>|\/>)`);
89
+ return pattern.test(content);
90
+ }
91
+ function extractCodeBlocks(content) {
92
+ const processor = unified().use(remarkParse);
93
+ let tree;
94
+ try {
95
+ tree = processor.parse(content);
96
+ } catch {
97
+ return [];
98
+ }
99
+ const blocks = [];
100
+ function visit(node) {
101
+ if (node.type === "code") {
102
+ const lang = node.lang ?? "";
103
+ const value = node.value ?? "";
104
+ blocks.push(`\`\`\`${lang}
105
+ ${value}
106
+ \`\`\``);
107
+ }
108
+ if (node.type === "inlineCode") {
109
+ const value = node.value ?? "";
110
+ blocks.push(`\`${value}\``);
111
+ }
112
+ if (Array.isArray(node.children)) {
113
+ for (const child of node.children) {
114
+ visit(child);
115
+ }
116
+ }
117
+ }
118
+ visit(tree);
119
+ return blocks;
120
+ }
121
+ function parseJSXTags(content) {
122
+ const results = [];
123
+ let i = 0;
124
+ while (i < content.length) {
125
+ if (content[i] !== "<") {
126
+ i++;
127
+ continue;
128
+ }
129
+ const startIndex = i;
130
+ i++;
131
+ if (i >= content.length) break;
132
+ const isClosing = content[i] === "/";
133
+ if (isClosing) {
134
+ i++;
135
+ if (i >= content.length) break;
136
+ }
137
+ if (!/^[A-Z]/.test(content[i] ?? "")) {
138
+ continue;
139
+ }
140
+ let tagName = "";
141
+ while (i < content.length && /^[a-z0-9]/i.test(content[i] ?? "")) {
142
+ tagName += content[i];
143
+ i++;
144
+ }
145
+ if (tagName.length === 0) {
146
+ continue;
147
+ }
148
+ if (isClosing) {
149
+ if (i < content.length && content[i] === ">") {
150
+ results.push({
151
+ tag: `</${tagName}>`,
152
+ index: startIndex,
153
+ isClosing: true,
154
+ isSelfClosing: false
155
+ });
156
+ i++;
157
+ }
158
+ continue;
159
+ }
160
+ let depth = 0;
161
+ let foundEnd = false;
162
+ let isSelfClosing = false;
163
+ while (i < content.length && !foundEnd) {
164
+ const char = content[i];
165
+ if ((char === '"' || char === "'") && depth === 0) {
166
+ const quote = char;
167
+ i++;
168
+ while (i < content.length && content[i] !== quote) {
169
+ if (content[i] === "\\" && i + 1 < content.length) {
170
+ i += 2;
171
+ } else {
172
+ i++;
173
+ }
174
+ }
175
+ if (i < content.length) i++;
176
+ continue;
177
+ }
178
+ if (char === "{") {
179
+ depth++;
180
+ i++;
181
+ continue;
182
+ }
183
+ if (char === "}") {
184
+ depth = Math.max(0, depth - 1);
185
+ i++;
186
+ continue;
187
+ }
188
+ if (depth === 0) {
189
+ if (char === "/" && i + 1 < content.length && content[i + 1] === ">") {
190
+ isSelfClosing = true;
191
+ foundEnd = true;
192
+ i += 2;
193
+ continue;
194
+ }
195
+ if (char === ">") {
196
+ foundEnd = true;
197
+ i++;
198
+ continue;
199
+ }
200
+ }
201
+ i++;
202
+ }
203
+ if (foundEnd) {
204
+ const fullTag = content.slice(startIndex, i);
205
+ results.push({ tag: fullTag, index: startIndex, isClosing: false, isSelfClosing });
206
+ }
207
+ }
208
+ return results;
209
+ }
210
+ function findEmptyMarkdownLinks(content) {
211
+ const positions = [];
212
+ let pos = 0;
213
+ while (pos < content.length) {
214
+ const openBracket = content.indexOf("[", pos);
215
+ if (openBracket === -1) break;
216
+ let bracketDepth = 1;
217
+ let closeBracket = openBracket + 1;
218
+ while (closeBracket < content.length && bracketDepth > 0) {
219
+ if (content[closeBracket] === "[") {
220
+ bracketDepth++;
221
+ } else if (content[closeBracket] === "]") {
222
+ bracketDepth--;
223
+ }
224
+ closeBracket++;
225
+ }
226
+ if (bracketDepth !== 0) {
227
+ pos = openBracket + 1;
228
+ continue;
229
+ }
230
+ closeBracket--;
231
+ if (closeBracket + 1 < content.length && content[closeBracket + 1] === "(") {
232
+ let parenPos = closeBracket + 2;
233
+ let isEmptyOrWhitespace = true;
234
+ while (parenPos < content.length && content[parenPos] !== ")") {
235
+ if (!/^\s/.test(content[parenPos] ?? "")) {
236
+ isEmptyOrWhitespace = false;
237
+ break;
238
+ }
239
+ parenPos++;
240
+ }
241
+ if (isEmptyOrWhitespace && parenPos < content.length && content[parenPos] === ")") {
242
+ positions.push(openBracket);
243
+ }
244
+ }
245
+ pos = closeBracket + 1;
246
+ }
247
+ return positions;
248
+ }
249
+
250
+ export {
251
+ sanitizeForMDX,
252
+ sanitizeAttribute,
253
+ parseJSXAttributes,
254
+ sanitizeJSXTag,
255
+ createHeadingPattern,
256
+ hasComponent,
257
+ extractCodeBlocks,
258
+ parseJSXTags,
259
+ findEmptyMarkdownLinks
260
+ };
261
+ //# sourceMappingURL=chunk-GZ2MP3VN.js.map
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=chunk-SQSYXPIF.js.map