@bfra.me/doc-sync 0.1.0 → 0.1.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/lib/chunk-45NROJIG.js +327 -0
- package/lib/chunk-DRBRT57F.js +1 -0
- package/lib/chunk-GZ2MP3VN.js +261 -0
- package/lib/{chunk-G5KKGJYO.js → chunk-LOB73H77.js} +18 -260
- package/lib/{chunk-DR6UG237.js → chunk-NC7YTZAL.js} +20 -334
- package/lib/chunk-SQSYXPIF.js +1 -0
- package/lib/cli/index.js +4 -2
- package/lib/generators/index.d.ts +1 -3
- package/lib/generators/index.js +2 -1
- package/lib/index.d.ts +7 -139
- package/lib/index.js +146 -13
- package/lib/orchestrator/index.d.ts +82 -0
- package/lib/orchestrator/index.js +27 -0
- package/lib/utils/index.d.ts +140 -0
- package/lib/utils/index.js +24 -0
- package/lib/watcher/index.d.ts +62 -0
- package/lib/watcher/index.js +25 -0
- package/package.json +17 -2
- package/src/generators/mdx-generator.ts +18 -17
- package/src/index.ts +82 -0
- package/src/utils/safe-patterns.ts +6 -2
|
@@ -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-
|
|
5
|
+
} from "./chunk-LOB73H77.js";
|
|
10
6
|
import {
|
|
11
7
|
analyzePublicAPI,
|
|
12
8
|
parsePackageComplete,
|
|
13
9
|
parseReadmeFile
|
|
14
10
|
} from "./chunk-6NKAJT2M.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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1003
|
-
const resolvedRoot =
|
|
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-
|
|
713
|
+
//# sourceMappingURL=chunk-NC7YTZAL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=chunk-SQSYXPIF.js.map
|
package/lib/cli/index.js
CHANGED
|
@@ -3,15 +3,17 @@ import {
|
|
|
3
3
|
createPackageScanner,
|
|
4
4
|
createSyncOrchestrator,
|
|
5
5
|
createValidationPipeline
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-NC7YTZAL.js";
|
|
7
7
|
import {
|
|
8
8
|
generateMDXDocument,
|
|
9
9
|
mergeContent
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-LOB73H77.js";
|
|
11
11
|
import "../chunk-ROLA7SBB.js";
|
|
12
12
|
import {
|
|
13
13
|
getUnscopedName
|
|
14
14
|
} from "../chunk-6NKAJT2M.js";
|
|
15
|
+
import "../chunk-GZ2MP3VN.js";
|
|
16
|
+
import "../chunk-45NROJIG.js";
|
|
15
17
|
|
|
16
18
|
// src/cli/index.ts
|
|
17
19
|
import process4 from "process";
|
|
@@ -160,9 +160,7 @@ declare function generateMDXDocument(packageInfo: PackageInfo, readme: ReadmeCon
|
|
|
160
160
|
declare function sanitizeContent(content: string): string;
|
|
161
161
|
/**
|
|
162
162
|
* Sanitizes content within MDX while preserving JSX components
|
|
163
|
-
*
|
|
164
|
-
* Now includes sanitization of JSX component attributes to prevent XSS
|
|
165
|
-
* Uses safe, non-backtracking parsing to prevent ReDoS
|
|
163
|
+
* Sanitizes JSX component attributes to prevent XSS while leaving closing tags unchanged
|
|
166
164
|
*/
|
|
167
165
|
declare function sanitizeTextContent(content: string): string;
|
|
168
166
|
declare function validateMDXSyntax(mdx: string): Result<true, SyncError>;
|
package/lib/generators/index.js
CHANGED
|
@@ -34,8 +34,9 @@ import {
|
|
|
34
34
|
validateMarkerPairing,
|
|
35
35
|
wrapAutoSection,
|
|
36
36
|
wrapManualSection
|
|
37
|
-
} from "../chunk-
|
|
37
|
+
} from "../chunk-LOB73H77.js";
|
|
38
38
|
import "../chunk-ROLA7SBB.js";
|
|
39
|
+
import "../chunk-GZ2MP3VN.js";
|
|
39
40
|
export {
|
|
40
41
|
cleanCodeExample,
|
|
41
42
|
createBadge,
|
package/lib/index.d.ts
CHANGED
|
@@ -1,141 +1,9 @@
|
|
|
1
1
|
export { CodeExampleOptions, ComponentMapperConfig, ContentSection, MDXGeneratorOptions, MergeOptions, MergeResult, SectionMapper, cleanCodeExample, createBadge, createCard, createCardGrid, createDiffSummary, createTabs, detectLanguage, extractAutoSections, extractManualSections, formatCodeBlock, formatCodeExamples, formatFunctionExamples, formatGroupedExamples, formatTypeExamples, formatUsageExample, generateAPICompact, generateAPIReference, generateCategoryReference, generateFrontmatter, generateInstallTabs, generateMDXDocument, groupExamplesByCategory, hasAutoContent, hasManualContent, mapToStarlightComponents, mergeContent, parseFrontmatter, sanitizeContent, sanitizeTextContent, stringifyFrontmatter, stripSentinelMarkers, validateMDXSyntax, validateMarkerPairing, wrapAutoSection, wrapManualSection } from './generators/index.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export { CLIOptions, DocConfigSource, ExportedFunction, ExportedType, FunctionParameter, InferSchema, JSDocInfo, JSDocParam, JSDocTag, MDXFrontmatter, ParseError, ParseErrorCode, ParseResult, ReExport, ReadmeSection, SENTINEL_MARKERS, SyncErrorCode, SyncInfo, SyncResult } from './types.js';
|
|
2
|
+
export { PackageScannerOptions, ScanResult, ScannedPackage, SyncOrchestrator, SyncOrchestratorOptions, ValidationError, ValidationPipelineOptions, ValidationResult, ValidationWarning, createPackageScanner, createSyncOrchestrator, createValidationPipeline, filterPackagesByPattern, groupPackagesByScope, isValidFilePath, validateContentString, validateDocument } from './orchestrator/index.js';
|
|
3
|
+
export { ExportAnalyzerOptions, JSDocableDeclaration, PackageInfoOptions, PackageJsonSchema, PublicAPIAnalysis, ReadmeParserOptions, ResolvedExport, TypeScriptParserOptions, analyzePublicAPI, analyzeTypeScriptContent, analyzeTypeScriptFile, assertPackageAPI, assertPackageInfo, assertParseError, buildDocSlug, createProject, extractDocsConfig, extractExportedFunctions, extractExportedTypes, extractJSDocInfo, extractPackageAPI, extractReExports, findEntryPoint, findExportedSymbols, findReadmePath, findSection, flattenSections, getExportedSymbolInfo, getExportsByKind, getPackageScope, getSectionsByLevel, getTableOfContents, getUnscopedName, hasJSDoc, isDocConfigSource, isExportedFunction, isExportedType, isJSDocInfo, isJSDocParam, isJSDocTag, isMDXFrontmatter, isPackageAPI, isPackageInfo, isParseError, isReExport, isReadmeContent, isReadmeSection, isSafeContent, isSafeFilePath, isSymbolExported, isSyncError, isValidHeadingLevel, isValidPackageName, isValidSemver, parseJSDoc, parsePackageComplete, parsePackageJson, parsePackageJsonContent, parseReadme, parseReadmeFile, parseSourceContent, parseSourceFile } from './parsers/index.js';
|
|
4
|
+
export { CLIOptions, DocConfig, DocConfigSource, ExportedFunction, ExportedType, FileChangeEvent, FunctionParameter, InferSchema, JSDocInfo, JSDocParam, JSDocTag, MDXDocument, MDXFrontmatter, PackageAPI, PackageInfo, ParseError, ParseErrorCode, ParseResult, ReExport, ReadmeContent, ReadmeSection, SENTINEL_MARKERS, SyncError, SyncErrorCode, SyncInfo, SyncResult, SyncSummary } from './types.js';
|
|
5
|
+
export { createHeadingPattern, extractCodeBlocks, findEmptyMarkdownLinks, hasComponent, parseJSXAttributes, parseJSXTags, sanitizeAttribute, sanitizeForMDX, sanitizeJSXTag } from './utils/index.js';
|
|
6
|
+
export { BatchChangeHandler, DocChangeDetector, DocChangeDetectorOptions, DocChangeHandler, DocDebouncer, DocDebouncerOptions, DocFileWatcher, DocWatcherOptions, FileCategory, PackageChangeAnalysis, RegenerationScope, categorizeFile, consolidateEvents, createDocChangeDetector, createDocDebouncer, createDocWatcher, deduplicateEvents, determineRegenerationScope, filterDocumentationChanges, groupChangesByPackage, hasAnyFileChanged } from './watcher/index.js';
|
|
7
|
+
import '@bfra.me/es/result';
|
|
8
|
+
import 'ts-morph';
|
|
5
9
|
import 'zod';
|
|
6
|
-
|
|
7
|
-
interface PackageScannerOptions {
|
|
8
|
-
readonly rootDir: string;
|
|
9
|
-
readonly includePatterns?: readonly string[];
|
|
10
|
-
readonly excludePackages?: readonly string[];
|
|
11
|
-
readonly parseSourceFiles?: boolean;
|
|
12
|
-
readonly parseReadme?: boolean;
|
|
13
|
-
}
|
|
14
|
-
interface ScannedPackage {
|
|
15
|
-
readonly info: PackageInfo;
|
|
16
|
-
readonly readme?: ReadmeContent;
|
|
17
|
-
readonly api?: PackageAPI;
|
|
18
|
-
readonly sourceFiles: readonly string[];
|
|
19
|
-
readonly needsDocumentation: boolean;
|
|
20
|
-
readonly existingDocPath?: string;
|
|
21
|
-
}
|
|
22
|
-
interface ScanResult {
|
|
23
|
-
readonly packages: readonly ScannedPackage[];
|
|
24
|
-
readonly packagesNeedingDocs: readonly ScannedPackage[];
|
|
25
|
-
readonly errors: readonly SyncError[];
|
|
26
|
-
readonly durationMs: number;
|
|
27
|
-
}
|
|
28
|
-
declare function createPackageScanner(options: PackageScannerOptions): {
|
|
29
|
-
readonly scan: () => Promise<ScanResult>;
|
|
30
|
-
readonly scanPackage: (packagePath: string) => Promise<Result<ScannedPackage, SyncError>>;
|
|
31
|
-
};
|
|
32
|
-
declare function filterPackagesByPattern(packages: readonly ScannedPackage[], pattern: string): ScannedPackage[];
|
|
33
|
-
declare function groupPackagesByScope(packages: readonly ScannedPackage[]): Map<string, ScannedPackage[]>;
|
|
34
|
-
|
|
35
|
-
interface DocWatcherOptions {
|
|
36
|
-
readonly rootDir?: string;
|
|
37
|
-
readonly debounceMs?: number;
|
|
38
|
-
readonly additionalIgnore?: readonly string[];
|
|
39
|
-
readonly usePolling?: boolean;
|
|
40
|
-
}
|
|
41
|
-
type DocChangeHandler = (events: readonly FileChangeEvent[]) => void | Promise<void>;
|
|
42
|
-
interface DocFileWatcher {
|
|
43
|
-
readonly start: () => Promise<void>;
|
|
44
|
-
readonly close: () => Promise<void>;
|
|
45
|
-
readonly onChanges: (handler: DocChangeHandler) => () => void;
|
|
46
|
-
readonly getWatchedPaths: () => readonly string[];
|
|
47
|
-
}
|
|
48
|
-
declare function createDocWatcher(options?: DocWatcherOptions): DocFileWatcher;
|
|
49
|
-
type FileCategory = 'readme' | 'source' | 'package-json' | 'unknown';
|
|
50
|
-
declare function categorizeFile(filePath: string): FileCategory;
|
|
51
|
-
declare function groupChangesByPackage(events: readonly FileChangeEvent[]): Map<string, FileChangeEvent[]>;
|
|
52
|
-
declare function filterDocumentationChanges(events: readonly FileChangeEvent[]): FileChangeEvent[];
|
|
53
|
-
|
|
54
|
-
interface DocChangeDetectorOptions {
|
|
55
|
-
readonly algorithm?: 'sha256' | 'md5';
|
|
56
|
-
}
|
|
57
|
-
interface PackageChangeAnalysis {
|
|
58
|
-
readonly packageName: string;
|
|
59
|
-
readonly needsRegeneration: boolean;
|
|
60
|
-
readonly changedCategories: readonly FileCategory[];
|
|
61
|
-
readonly changedFiles: readonly string[];
|
|
62
|
-
}
|
|
63
|
-
interface DocChangeDetector {
|
|
64
|
-
readonly hasChanged: (filePath: string) => Promise<boolean>;
|
|
65
|
-
readonly record: (filePath: string) => Promise<void>;
|
|
66
|
-
readonly recordPackage: (pkg: PackageInfo, files: readonly string[]) => Promise<void>;
|
|
67
|
-
readonly clear: (filePath: string) => void;
|
|
68
|
-
readonly clearAll: () => void;
|
|
69
|
-
readonly analyzeChanges: (events: readonly FileChangeEvent[]) => Promise<PackageChangeAnalysis[]>;
|
|
70
|
-
}
|
|
71
|
-
declare function createDocChangeDetector(options?: DocChangeDetectorOptions): DocChangeDetector;
|
|
72
|
-
type RegenerationScope = 'full' | 'api-only' | 'readme-only' | 'metadata-only' | 'none';
|
|
73
|
-
declare function determineRegenerationScope(changedCategories: readonly FileCategory[]): RegenerationScope;
|
|
74
|
-
declare function hasAnyFileChanged(detector: DocChangeDetector, files: readonly string[]): Promise<boolean>;
|
|
75
|
-
|
|
76
|
-
interface DocDebouncerOptions {
|
|
77
|
-
readonly debounceMs?: number;
|
|
78
|
-
readonly maxWaitMs?: number;
|
|
79
|
-
}
|
|
80
|
-
type BatchChangeHandler = (events: readonly FileChangeEvent[]) => void | Promise<void>;
|
|
81
|
-
interface DocDebouncer {
|
|
82
|
-
readonly add: (event: FileChangeEvent) => void;
|
|
83
|
-
readonly addAll: (events: readonly FileChangeEvent[]) => void;
|
|
84
|
-
readonly flush: () => void;
|
|
85
|
-
readonly cancel: () => void;
|
|
86
|
-
readonly getPendingCount: () => number;
|
|
87
|
-
}
|
|
88
|
-
declare function createDocDebouncer(handler: BatchChangeHandler, options?: DocDebouncerOptions): DocDebouncer;
|
|
89
|
-
declare function deduplicateEvents(events: readonly FileChangeEvent[]): FileChangeEvent[];
|
|
90
|
-
declare function consolidateEvents(events: readonly FileChangeEvent[]): FileChangeEvent[];
|
|
91
|
-
|
|
92
|
-
interface SyncOrchestratorOptions {
|
|
93
|
-
readonly config: DocConfig;
|
|
94
|
-
readonly dryRun?: boolean;
|
|
95
|
-
readonly verbose?: boolean;
|
|
96
|
-
readonly onProgress?: (message: string) => void;
|
|
97
|
-
readonly onError?: (error: SyncError) => void;
|
|
98
|
-
}
|
|
99
|
-
interface SyncOrchestrator {
|
|
100
|
-
readonly syncAll: () => Promise<SyncSummary>;
|
|
101
|
-
readonly syncPackages: (packageNames: readonly string[]) => Promise<SyncSummary>;
|
|
102
|
-
readonly handleChanges: (events: readonly FileChangeEvent[]) => Promise<SyncSummary>;
|
|
103
|
-
readonly startWatching: () => Promise<void>;
|
|
104
|
-
readonly stopWatching: () => Promise<void>;
|
|
105
|
-
readonly isWatching: () => boolean;
|
|
106
|
-
}
|
|
107
|
-
declare function createSyncOrchestrator(options: SyncOrchestratorOptions): SyncOrchestrator;
|
|
108
|
-
/** Prevents directory traversal attacks (SEC-002) */
|
|
109
|
-
declare function isValidFilePath(filePath: string, rootDir: string): boolean;
|
|
110
|
-
|
|
111
|
-
interface ValidationResult {
|
|
112
|
-
readonly valid: boolean;
|
|
113
|
-
readonly errors: readonly ValidationError[];
|
|
114
|
-
readonly warnings: readonly ValidationWarning[];
|
|
115
|
-
}
|
|
116
|
-
interface ValidationError {
|
|
117
|
-
readonly type: 'syntax' | 'frontmatter' | 'component' | 'content';
|
|
118
|
-
readonly message: string;
|
|
119
|
-
readonly line?: number;
|
|
120
|
-
readonly column?: number;
|
|
121
|
-
}
|
|
122
|
-
interface ValidationWarning {
|
|
123
|
-
readonly type: 'deprecation' | 'recommendation' | 'compatibility';
|
|
124
|
-
readonly message: string;
|
|
125
|
-
readonly line?: number;
|
|
126
|
-
}
|
|
127
|
-
interface ValidationPipelineOptions {
|
|
128
|
-
readonly validateFrontmatter?: boolean;
|
|
129
|
-
readonly validateComponents?: boolean;
|
|
130
|
-
readonly validateContent?: boolean;
|
|
131
|
-
readonly strict?: boolean;
|
|
132
|
-
}
|
|
133
|
-
declare function createValidationPipeline(options?: ValidationPipelineOptions): {
|
|
134
|
-
readonly validate: (doc: MDXDocument) => ValidationResult;
|
|
135
|
-
readonly validateContent: (content: string) => ValidationResult;
|
|
136
|
-
readonly validateMultiple: (docs: readonly MDXDocument[]) => Result<Map<string, ValidationResult>, SyncError>;
|
|
137
|
-
};
|
|
138
|
-
declare function validateDocument(doc: MDXDocument, options?: ValidationPipelineOptions): Result<MDXDocument, SyncError>;
|
|
139
|
-
declare function validateContentString(content: string, options?: ValidationPipelineOptions): Result<string, SyncError>;
|
|
140
|
-
|
|
141
|
-
export { type BatchChangeHandler, type DocChangeDetector, type DocChangeDetectorOptions, type DocChangeHandler, DocConfig, type DocDebouncer, type DocDebouncerOptions, type DocFileWatcher, type DocWatcherOptions, type FileCategory, FileChangeEvent, MDXDocument, PackageAPI, type PackageChangeAnalysis, PackageInfo, type PackageScannerOptions, ReadmeContent, type RegenerationScope, type ScanResult, type ScannedPackage, SyncError, type SyncOrchestrator, type SyncOrchestratorOptions, SyncSummary, type ValidationError, type ValidationPipelineOptions, type ValidationResult, type ValidationWarning, categorizeFile, consolidateEvents, createDocChangeDetector, createDocDebouncer, createDocWatcher, createPackageScanner, createSyncOrchestrator, createValidationPipeline, deduplicateEvents, determineRegenerationScope, filterDocumentationChanges, filterPackagesByPattern, groupChangesByPackage, groupPackagesByScope, hasAnyFileChanged, isValidFilePath, validateContentString, validateDocument };
|