@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,6 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SENTINEL_MARKERS
|
|
3
3
|
} from "./chunk-ROLA7SBB.js";
|
|
4
|
+
import {
|
|
5
|
+
extractCodeBlocks,
|
|
6
|
+
parseJSXTags,
|
|
7
|
+
sanitizeAttribute,
|
|
8
|
+
sanitizeForMDX,
|
|
9
|
+
sanitizeJSXTag
|
|
10
|
+
} from "./chunk-GZ2MP3VN.js";
|
|
4
11
|
|
|
5
12
|
// src/generators/api-reference-generator.ts
|
|
6
13
|
function generateAPIReference(api) {
|
|
@@ -435,80 +442,6 @@ function formatGroupedExamples(api, options = {}) {
|
|
|
435
442
|
return sections.join("\n").trim();
|
|
436
443
|
}
|
|
437
444
|
|
|
438
|
-
// src/utils/sanitization.ts
|
|
439
|
-
import { sanitizeInput } from "@bfra.me/es/validation";
|
|
440
|
-
import escapeHtml from "escape-html";
|
|
441
|
-
function sanitizeForMDX(content) {
|
|
442
|
-
const escaped = sanitizeInput(content, { trim: false });
|
|
443
|
-
return escaped.replaceAll("{", "{").replaceAll("}", "}");
|
|
444
|
-
}
|
|
445
|
-
function sanitizeAttribute(value) {
|
|
446
|
-
return escapeHtml(value);
|
|
447
|
-
}
|
|
448
|
-
function parseJSXAttributes(tag) {
|
|
449
|
-
const attrs = [];
|
|
450
|
-
const spaceIndex = tag.indexOf(" ");
|
|
451
|
-
if (spaceIndex === -1) return attrs;
|
|
452
|
-
const closeIndex = tag.lastIndexOf(">");
|
|
453
|
-
if (closeIndex === -1) return attrs;
|
|
454
|
-
const attrRegion = tag.slice(spaceIndex + 1, closeIndex).trim();
|
|
455
|
-
let i = 0;
|
|
456
|
-
while (i < attrRegion.length) {
|
|
457
|
-
while (i < attrRegion.length && /\s/.test(attrRegion.charAt(i))) i++;
|
|
458
|
-
if (i >= attrRegion.length) break;
|
|
459
|
-
let name = "";
|
|
460
|
-
while (i < attrRegion.length && /[\w-]/.test(attrRegion.charAt(i))) {
|
|
461
|
-
name += attrRegion[i];
|
|
462
|
-
i++;
|
|
463
|
-
}
|
|
464
|
-
if (!name) break;
|
|
465
|
-
while (i < attrRegion.length && /\s/.test(attrRegion.charAt(i))) i++;
|
|
466
|
-
if (i >= attrRegion.length || attrRegion[i] !== "=") {
|
|
467
|
-
attrs.push({ name, value: null });
|
|
468
|
-
continue;
|
|
469
|
-
}
|
|
470
|
-
i++;
|
|
471
|
-
while (i < attrRegion.length && /\s/.test(attrRegion.charAt(i))) i++;
|
|
472
|
-
if (i >= attrRegion.length) {
|
|
473
|
-
attrs.push({ name, value: "" });
|
|
474
|
-
break;
|
|
475
|
-
}
|
|
476
|
-
let value = "";
|
|
477
|
-
const quote = attrRegion[i];
|
|
478
|
-
if (quote === '"' || quote === "'") {
|
|
479
|
-
i++;
|
|
480
|
-
while (i < attrRegion.length && attrRegion[i] !== quote) {
|
|
481
|
-
value += attrRegion[i];
|
|
482
|
-
i++;
|
|
483
|
-
}
|
|
484
|
-
if (i < attrRegion.length) i++;
|
|
485
|
-
} else {
|
|
486
|
-
while (i < attrRegion.length && !/[\s/>]/.test(attrRegion.charAt(i))) {
|
|
487
|
-
value += attrRegion[i];
|
|
488
|
-
i++;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
attrs.push({ name, value });
|
|
492
|
-
}
|
|
493
|
-
return attrs;
|
|
494
|
-
}
|
|
495
|
-
function sanitizeJSXTag(tag) {
|
|
496
|
-
const tagMatch = tag.match(/^<([A-Z][a-zA-Z0-9]*)/);
|
|
497
|
-
if (!tagMatch || typeof tagMatch[1] !== "string" || tagMatch[1].length === 0) {
|
|
498
|
-
return escapeHtml(tag);
|
|
499
|
-
}
|
|
500
|
-
const tagName = tagMatch[1];
|
|
501
|
-
const selfClosing = tag.endsWith("/>");
|
|
502
|
-
const attributes = parseJSXAttributes(tag);
|
|
503
|
-
const sanitizedAttrs = attributes.map(({ name, value }) => {
|
|
504
|
-
if (value === null) return name;
|
|
505
|
-
const escaped = escapeHtml(value);
|
|
506
|
-
return `${name}="${escaped}"`;
|
|
507
|
-
});
|
|
508
|
-
const attrString = sanitizedAttrs.length > 0 ? ` ${sanitizedAttrs.join(" ")}` : "";
|
|
509
|
-
return `<${tagName}${attrString}${selfClosing ? " />" : ">"}`;
|
|
510
|
-
}
|
|
511
|
-
|
|
512
445
|
// src/generators/component-mapper.ts
|
|
513
446
|
var DEFAULT_CONFIG = {
|
|
514
447
|
featureSections: ["features", "highlights", "key features"],
|
|
@@ -1167,179 +1100,6 @@ function stripQuotes(value) {
|
|
|
1167
1100
|
|
|
1168
1101
|
// src/generators/mdx-generator.ts
|
|
1169
1102
|
import { err as err2, ok as ok2 } from "@bfra.me/es/result";
|
|
1170
|
-
|
|
1171
|
-
// src/utils/safe-patterns.ts
|
|
1172
|
-
import remarkParse from "remark-parse";
|
|
1173
|
-
import { unified } from "unified";
|
|
1174
|
-
function createHeadingPattern(level) {
|
|
1175
|
-
if (level < 1 || level > 6) {
|
|
1176
|
-
throw new Error("Heading level must be between 1 and 6");
|
|
1177
|
-
}
|
|
1178
|
-
const hashes = "#".repeat(level);
|
|
1179
|
-
return new RegExp(`^${hashes} ([^\r
|
|
1180
|
-
]+)$`, "gm");
|
|
1181
|
-
}
|
|
1182
|
-
function hasComponent(content, componentName) {
|
|
1183
|
-
const escaped = componentName.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
|
|
1184
|
-
const pattern = new RegExp(String.raw`<${escaped}(?:\s[^>]*)?(?:>|\/>)`);
|
|
1185
|
-
return pattern.test(content);
|
|
1186
|
-
}
|
|
1187
|
-
function extractCodeBlocks(content) {
|
|
1188
|
-
const processor = unified().use(remarkParse);
|
|
1189
|
-
let tree;
|
|
1190
|
-
try {
|
|
1191
|
-
tree = processor.parse(content);
|
|
1192
|
-
} catch {
|
|
1193
|
-
return [];
|
|
1194
|
-
}
|
|
1195
|
-
const blocks = [];
|
|
1196
|
-
function visit(node) {
|
|
1197
|
-
if (node.type === "code") {
|
|
1198
|
-
const lang = node.lang ?? "";
|
|
1199
|
-
const value = node.value ?? "";
|
|
1200
|
-
blocks.push(`\`\`\`${lang}
|
|
1201
|
-
${value}
|
|
1202
|
-
\`\`\``);
|
|
1203
|
-
}
|
|
1204
|
-
if (Array.isArray(node.children)) {
|
|
1205
|
-
for (const child of node.children) {
|
|
1206
|
-
visit(child);
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
visit(tree);
|
|
1211
|
-
return blocks;
|
|
1212
|
-
}
|
|
1213
|
-
function parseJSXTags(content) {
|
|
1214
|
-
const results = [];
|
|
1215
|
-
let i = 0;
|
|
1216
|
-
while (i < content.length) {
|
|
1217
|
-
if (content[i] !== "<") {
|
|
1218
|
-
i++;
|
|
1219
|
-
continue;
|
|
1220
|
-
}
|
|
1221
|
-
const startIndex = i;
|
|
1222
|
-
i++;
|
|
1223
|
-
if (i >= content.length) break;
|
|
1224
|
-
const isClosing = content[i] === "/";
|
|
1225
|
-
if (isClosing) {
|
|
1226
|
-
i++;
|
|
1227
|
-
if (i >= content.length) break;
|
|
1228
|
-
}
|
|
1229
|
-
if (!/^[A-Z]/.test(content[i] ?? "")) {
|
|
1230
|
-
continue;
|
|
1231
|
-
}
|
|
1232
|
-
let tagName = "";
|
|
1233
|
-
while (i < content.length && /^[a-z0-9]/i.test(content[i] ?? "")) {
|
|
1234
|
-
tagName += content[i];
|
|
1235
|
-
i++;
|
|
1236
|
-
}
|
|
1237
|
-
if (tagName.length === 0) {
|
|
1238
|
-
continue;
|
|
1239
|
-
}
|
|
1240
|
-
if (isClosing) {
|
|
1241
|
-
if (i < content.length && content[i] === ">") {
|
|
1242
|
-
results.push({
|
|
1243
|
-
tag: `</${tagName}>`,
|
|
1244
|
-
index: startIndex,
|
|
1245
|
-
isClosing: true,
|
|
1246
|
-
isSelfClosing: false
|
|
1247
|
-
});
|
|
1248
|
-
i++;
|
|
1249
|
-
}
|
|
1250
|
-
continue;
|
|
1251
|
-
}
|
|
1252
|
-
let depth = 0;
|
|
1253
|
-
let foundEnd = false;
|
|
1254
|
-
let isSelfClosing = false;
|
|
1255
|
-
while (i < content.length && !foundEnd) {
|
|
1256
|
-
const char = content[i];
|
|
1257
|
-
if ((char === '"' || char === "'") && depth === 0) {
|
|
1258
|
-
const quote = char;
|
|
1259
|
-
i++;
|
|
1260
|
-
while (i < content.length && content[i] !== quote) {
|
|
1261
|
-
if (content[i] === "\\" && i + 1 < content.length) {
|
|
1262
|
-
i += 2;
|
|
1263
|
-
} else {
|
|
1264
|
-
i++;
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1267
|
-
if (i < content.length) i++;
|
|
1268
|
-
continue;
|
|
1269
|
-
}
|
|
1270
|
-
if (char === "{") {
|
|
1271
|
-
depth++;
|
|
1272
|
-
i++;
|
|
1273
|
-
continue;
|
|
1274
|
-
}
|
|
1275
|
-
if (char === "}") {
|
|
1276
|
-
depth = Math.max(0, depth - 1);
|
|
1277
|
-
i++;
|
|
1278
|
-
continue;
|
|
1279
|
-
}
|
|
1280
|
-
if (depth === 0) {
|
|
1281
|
-
if (char === "/" && i + 1 < content.length && content[i + 1] === ">") {
|
|
1282
|
-
isSelfClosing = true;
|
|
1283
|
-
foundEnd = true;
|
|
1284
|
-
i += 2;
|
|
1285
|
-
continue;
|
|
1286
|
-
}
|
|
1287
|
-
if (char === ">") {
|
|
1288
|
-
foundEnd = true;
|
|
1289
|
-
i++;
|
|
1290
|
-
continue;
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
i++;
|
|
1294
|
-
}
|
|
1295
|
-
if (foundEnd) {
|
|
1296
|
-
const fullTag = content.slice(startIndex, i);
|
|
1297
|
-
results.push({ tag: fullTag, index: startIndex, isClosing: false, isSelfClosing });
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
return results;
|
|
1301
|
-
}
|
|
1302
|
-
function findEmptyMarkdownLinks(content) {
|
|
1303
|
-
const positions = [];
|
|
1304
|
-
let pos = 0;
|
|
1305
|
-
while (pos < content.length) {
|
|
1306
|
-
const openBracket = content.indexOf("[", pos);
|
|
1307
|
-
if (openBracket === -1) break;
|
|
1308
|
-
let bracketDepth = 1;
|
|
1309
|
-
let closeBracket = openBracket + 1;
|
|
1310
|
-
while (closeBracket < content.length && bracketDepth > 0) {
|
|
1311
|
-
if (content[closeBracket] === "[") {
|
|
1312
|
-
bracketDepth++;
|
|
1313
|
-
} else if (content[closeBracket] === "]") {
|
|
1314
|
-
bracketDepth--;
|
|
1315
|
-
}
|
|
1316
|
-
closeBracket++;
|
|
1317
|
-
}
|
|
1318
|
-
if (bracketDepth !== 0) {
|
|
1319
|
-
pos = openBracket + 1;
|
|
1320
|
-
continue;
|
|
1321
|
-
}
|
|
1322
|
-
closeBracket--;
|
|
1323
|
-
if (closeBracket + 1 < content.length && content[closeBracket + 1] === "(") {
|
|
1324
|
-
let parenPos = closeBracket + 2;
|
|
1325
|
-
let isEmptyOrWhitespace = true;
|
|
1326
|
-
while (parenPos < content.length && content[parenPos] !== ")") {
|
|
1327
|
-
if (!/^\s/.test(content[parenPos] ?? "")) {
|
|
1328
|
-
isEmptyOrWhitespace = false;
|
|
1329
|
-
break;
|
|
1330
|
-
}
|
|
1331
|
-
parenPos++;
|
|
1332
|
-
}
|
|
1333
|
-
if (isEmptyOrWhitespace && parenPos < content.length && content[parenPos] === ")") {
|
|
1334
|
-
positions.push(openBracket);
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
pos = closeBracket + 1;
|
|
1338
|
-
}
|
|
1339
|
-
return positions;
|
|
1340
|
-
}
|
|
1341
|
-
|
|
1342
|
-
// src/generators/mdx-generator.ts
|
|
1343
1103
|
var DEFAULT_OPTIONS2 = {
|
|
1344
1104
|
includeAPI: true,
|
|
1345
1105
|
includeExamples: true,
|
|
@@ -1442,11 +1202,7 @@ function sanitizeTextContent(content) {
|
|
|
1442
1202
|
if (index > lastIndex) {
|
|
1443
1203
|
parts.push(sanitizeContent(content.slice(lastIndex, index)));
|
|
1444
1204
|
}
|
|
1445
|
-
|
|
1446
|
-
parts.push(tag);
|
|
1447
|
-
} else {
|
|
1448
|
-
parts.push(sanitizeJSXTag(tag));
|
|
1449
|
-
}
|
|
1205
|
+
parts.push(isClosing ? tag : sanitizeJSXTag(tag));
|
|
1450
1206
|
lastIndex = index + tag.length;
|
|
1451
1207
|
}
|
|
1452
1208
|
if (lastIndex < content.length) {
|
|
@@ -1471,17 +1227,23 @@ function validateMDXSyntax(mdx) {
|
|
|
1471
1227
|
}
|
|
1472
1228
|
return ok2(true);
|
|
1473
1229
|
}
|
|
1230
|
+
function isTypeScriptGeneric(tag) {
|
|
1231
|
+
const tagNameMatch = tag.match(/<\/?([A-Z][a-zA-Z0-9]*)/);
|
|
1232
|
+
const tagName = tagNameMatch?.[1];
|
|
1233
|
+
return tagName !== void 0 && tagName.length === 1;
|
|
1234
|
+
}
|
|
1474
1235
|
function checkForUnclosedTags(mdx) {
|
|
1475
1236
|
const unclosed = [];
|
|
1476
1237
|
const tagStack = [];
|
|
1477
1238
|
const codeBlocks = extractCodeBlocks(mdx);
|
|
1478
|
-
let
|
|
1239
|
+
let contentWithoutCode = mdx;
|
|
1479
1240
|
for (const block of codeBlocks) {
|
|
1480
1241
|
const lineCount = block.split("\n").length;
|
|
1481
1242
|
const placeholder = "\n".repeat(lineCount);
|
|
1482
|
-
|
|
1243
|
+
contentWithoutCode = contentWithoutCode.replace(block, placeholder);
|
|
1483
1244
|
}
|
|
1484
|
-
const
|
|
1245
|
+
const allJSXTags = parseJSXTags(contentWithoutCode);
|
|
1246
|
+
const jsxTags = allJSXTags.filter(({ tag }) => !isTypeScriptGeneric(tag));
|
|
1485
1247
|
for (const { tag, isClosing, isSelfClosing } of jsxTags) {
|
|
1486
1248
|
const tagNameMatch = isClosing ? tag.match(/^<\/([A-Z][a-zA-Z0-9]*)>$/) : tag.match(/^<([A-Z][a-zA-Z0-9]*)/);
|
|
1487
1249
|
const tagName = tagNameMatch?.[1];
|
|
@@ -1548,13 +1310,9 @@ export {
|
|
|
1548
1310
|
generateFrontmatter,
|
|
1549
1311
|
stringifyFrontmatter,
|
|
1550
1312
|
parseFrontmatter,
|
|
1551
|
-
createHeadingPattern,
|
|
1552
|
-
hasComponent,
|
|
1553
|
-
extractCodeBlocks,
|
|
1554
|
-
findEmptyMarkdownLinks,
|
|
1555
1313
|
generateMDXDocument,
|
|
1556
1314
|
sanitizeContent,
|
|
1557
1315
|
sanitizeTextContent,
|
|
1558
1316
|
validateMDXSyntax
|
|
1559
1317
|
};
|
|
1560
|
-
//# sourceMappingURL=chunk-
|
|
1318
|
+
//# sourceMappingURL=chunk-LOB73H77.js.map
|