@bfra.me/doc-sync 0.1.0
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/README.md +288 -0
- package/lib/chunk-6NKAJT2M.js +1233 -0
- package/lib/chunk-DR6UG237.js +1027 -0
- package/lib/chunk-G5KKGJYO.js +1560 -0
- package/lib/chunk-ROLA7SBB.js +12 -0
- package/lib/cli/index.d.ts +1 -0
- package/lib/cli/index.js +397 -0
- package/lib/generators/index.d.ts +170 -0
- package/lib/generators/index.js +76 -0
- package/lib/index.d.ts +141 -0
- package/lib/index.js +118 -0
- package/lib/parsers/index.d.ts +264 -0
- package/lib/parsers/index.js +113 -0
- package/lib/types.d.ts +388 -0
- package/lib/types.js +7 -0
- package/package.json +99 -0
- package/src/cli/commands/index.ts +3 -0
- package/src/cli/commands/sync.ts +146 -0
- package/src/cli/commands/validate.ts +151 -0
- package/src/cli/commands/watch.ts +74 -0
- package/src/cli/index.ts +71 -0
- package/src/cli/types.ts +19 -0
- package/src/cli/ui.ts +123 -0
- package/src/generators/api-reference-generator.ts +268 -0
- package/src/generators/code-example-formatter.ts +313 -0
- package/src/generators/component-mapper.ts +383 -0
- package/src/generators/content-merger.ts +295 -0
- package/src/generators/frontmatter-generator.ts +277 -0
- package/src/generators/index.ts +56 -0
- package/src/generators/mdx-generator.ts +289 -0
- package/src/index.ts +131 -0
- package/src/orchestrator/index.ts +21 -0
- package/src/orchestrator/package-scanner.ts +276 -0
- package/src/orchestrator/sync-orchestrator.ts +382 -0
- package/src/orchestrator/validation-pipeline.ts +328 -0
- package/src/parsers/export-analyzer.ts +335 -0
- package/src/parsers/guards.ts +350 -0
- package/src/parsers/index.ts +82 -0
- package/src/parsers/jsdoc-extractor.ts +313 -0
- package/src/parsers/package-info.ts +267 -0
- package/src/parsers/readme-parser.ts +334 -0
- package/src/parsers/typescript-parser.ts +299 -0
- package/src/types.ts +423 -0
- package/src/utils/index.ts +13 -0
- package/src/utils/safe-patterns.ts +280 -0
- package/src/utils/sanitization.ts +164 -0
- package/src/watcher/change-detector.ts +138 -0
- package/src/watcher/debouncer.ts +168 -0
- package/src/watcher/file-watcher.ts +164 -0
- package/src/watcher/index.ts +27 -0
|
@@ -0,0 +1,1233 @@
|
|
|
1
|
+
// src/parsers/export-analyzer.ts
|
|
2
|
+
import { ok as ok2 } from "@bfra.me/es/result";
|
|
3
|
+
|
|
4
|
+
// src/parsers/typescript-parser.ts
|
|
5
|
+
import { err, ok } from "@bfra.me/es/result";
|
|
6
|
+
import { Project } from "ts-morph";
|
|
7
|
+
|
|
8
|
+
// src/parsers/jsdoc-extractor.ts
|
|
9
|
+
function hasJSDoc(node) {
|
|
10
|
+
return "getJsDocs" in node && typeof node.getJsDocs === "function";
|
|
11
|
+
}
|
|
12
|
+
function extractJSDocInfo(node) {
|
|
13
|
+
if (!hasJSDoc(node)) {
|
|
14
|
+
return void 0;
|
|
15
|
+
}
|
|
16
|
+
const jsDocs = node.getJsDocs();
|
|
17
|
+
if (jsDocs.length === 0) {
|
|
18
|
+
return void 0;
|
|
19
|
+
}
|
|
20
|
+
const jsDoc = jsDocs[0];
|
|
21
|
+
if (jsDoc === void 0) {
|
|
22
|
+
return void 0;
|
|
23
|
+
}
|
|
24
|
+
return parseJSDoc(jsDoc);
|
|
25
|
+
}
|
|
26
|
+
function parseJSDoc(jsDoc) {
|
|
27
|
+
const description = jsDoc.getDescription().trim() || void 0;
|
|
28
|
+
const tags = jsDoc.getTags();
|
|
29
|
+
const params = extractParams(tags);
|
|
30
|
+
const returns = extractReturns(tags);
|
|
31
|
+
const examples = extractExamples(tags);
|
|
32
|
+
const deprecated = extractDeprecated(tags);
|
|
33
|
+
const since = extractSince(tags);
|
|
34
|
+
const see = extractSee(tags);
|
|
35
|
+
const customTags = extractCustomTags(tags);
|
|
36
|
+
return {
|
|
37
|
+
...description !== void 0 && { description },
|
|
38
|
+
...params.length > 0 && { params },
|
|
39
|
+
...returns !== void 0 && { returns },
|
|
40
|
+
...examples.length > 0 && { examples },
|
|
41
|
+
...deprecated !== void 0 && { deprecated },
|
|
42
|
+
...since !== void 0 && { since },
|
|
43
|
+
...see.length > 0 && { see },
|
|
44
|
+
...customTags.length > 0 && { customTags }
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function extractParams(tags) {
|
|
48
|
+
const params = [];
|
|
49
|
+
for (const tag of tags) {
|
|
50
|
+
const tagName = tag.getTagName();
|
|
51
|
+
if (tagName !== "param") continue;
|
|
52
|
+
const text = getTagText(tag);
|
|
53
|
+
if (text === void 0) continue;
|
|
54
|
+
const parsed = parseParamText(text);
|
|
55
|
+
if (parsed !== void 0) {
|
|
56
|
+
params.push(parsed);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return params;
|
|
60
|
+
}
|
|
61
|
+
function parseParamText(text) {
|
|
62
|
+
const trimmed = text.trim();
|
|
63
|
+
if (trimmed.length === 0) {
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
let type;
|
|
67
|
+
let remaining = trimmed;
|
|
68
|
+
if (remaining.startsWith("{")) {
|
|
69
|
+
const typeEnd = remaining.indexOf("}");
|
|
70
|
+
if (typeEnd > 0) {
|
|
71
|
+
type = remaining.slice(1, typeEnd);
|
|
72
|
+
remaining = remaining.slice(typeEnd + 1).trim();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const dashIndex = remaining.indexOf(" - ");
|
|
76
|
+
const spaceIndex = remaining.indexOf(" ");
|
|
77
|
+
let name;
|
|
78
|
+
let description;
|
|
79
|
+
if (dashIndex > 0) {
|
|
80
|
+
name = remaining.slice(0, dashIndex).trim();
|
|
81
|
+
description = remaining.slice(dashIndex + 3).trim() || void 0;
|
|
82
|
+
} else if (spaceIndex > 0) {
|
|
83
|
+
name = remaining.slice(0, spaceIndex).trim();
|
|
84
|
+
description = remaining.slice(spaceIndex + 1).trim() || void 0;
|
|
85
|
+
} else {
|
|
86
|
+
name = remaining;
|
|
87
|
+
}
|
|
88
|
+
let optional = false;
|
|
89
|
+
if (name.startsWith("[") && name.endsWith("]")) {
|
|
90
|
+
optional = true;
|
|
91
|
+
name = name.slice(1, -1);
|
|
92
|
+
}
|
|
93
|
+
let defaultValue;
|
|
94
|
+
const defaultIndex = name.indexOf("=");
|
|
95
|
+
if (defaultIndex > 0) {
|
|
96
|
+
defaultValue = name.slice(defaultIndex + 1);
|
|
97
|
+
name = name.slice(0, defaultIndex);
|
|
98
|
+
optional = true;
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
name,
|
|
102
|
+
...type !== void 0 && { type },
|
|
103
|
+
...description !== void 0 && { description },
|
|
104
|
+
...optional && { optional },
|
|
105
|
+
...defaultValue !== void 0 && { defaultValue }
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function extractReturns(tags) {
|
|
109
|
+
for (const tag of tags) {
|
|
110
|
+
const tagName = tag.getTagName();
|
|
111
|
+
if (tagName !== "returns" && tagName !== "return") continue;
|
|
112
|
+
const text = getTagText(tag);
|
|
113
|
+
if (text !== void 0 && text.trim().length > 0) {
|
|
114
|
+
let result = text.trim();
|
|
115
|
+
if (result.startsWith("{")) {
|
|
116
|
+
const typeEnd = result.indexOf("}");
|
|
117
|
+
if (typeEnd > 0) {
|
|
118
|
+
result = result.slice(typeEnd + 1).trim();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return result.length > 0 ? result : void 0;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return void 0;
|
|
125
|
+
}
|
|
126
|
+
function extractExamples(tags) {
|
|
127
|
+
const examples = [];
|
|
128
|
+
for (const tag of tags) {
|
|
129
|
+
const tagName = tag.getTagName();
|
|
130
|
+
if (tagName !== "example") continue;
|
|
131
|
+
const text = getTagText(tag);
|
|
132
|
+
if (text !== void 0 && text.trim().length > 0) {
|
|
133
|
+
examples.push(text.trim());
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return examples;
|
|
137
|
+
}
|
|
138
|
+
function extractDeprecated(tags) {
|
|
139
|
+
for (const tag of tags) {
|
|
140
|
+
const tagName = tag.getTagName();
|
|
141
|
+
if (tagName !== "deprecated") continue;
|
|
142
|
+
const text = getTagText(tag);
|
|
143
|
+
return text?.trim() ?? "";
|
|
144
|
+
}
|
|
145
|
+
return void 0;
|
|
146
|
+
}
|
|
147
|
+
function extractSince(tags) {
|
|
148
|
+
for (const tag of tags) {
|
|
149
|
+
const tagName = tag.getTagName();
|
|
150
|
+
if (tagName !== "since") continue;
|
|
151
|
+
const text = getTagText(tag);
|
|
152
|
+
if (text !== void 0 && text.trim().length > 0) {
|
|
153
|
+
return text.trim();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return void 0;
|
|
157
|
+
}
|
|
158
|
+
function extractSee(tags) {
|
|
159
|
+
const see = [];
|
|
160
|
+
for (const tag of tags) {
|
|
161
|
+
const tagName = tag.getTagName();
|
|
162
|
+
if (tagName !== "see") continue;
|
|
163
|
+
const text = getTagText(tag);
|
|
164
|
+
if (text !== void 0 && text.trim().length > 0) {
|
|
165
|
+
see.push(text.trim());
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return see;
|
|
169
|
+
}
|
|
170
|
+
var STANDARD_TAGS = /* @__PURE__ */ new Set([
|
|
171
|
+
"param",
|
|
172
|
+
"returns",
|
|
173
|
+
"return",
|
|
174
|
+
"example",
|
|
175
|
+
"deprecated",
|
|
176
|
+
"since",
|
|
177
|
+
"see",
|
|
178
|
+
"type",
|
|
179
|
+
"typedef",
|
|
180
|
+
"callback",
|
|
181
|
+
"template",
|
|
182
|
+
"throws",
|
|
183
|
+
"async",
|
|
184
|
+
"generator",
|
|
185
|
+
"override",
|
|
186
|
+
"readonly",
|
|
187
|
+
"private",
|
|
188
|
+
"protected",
|
|
189
|
+
"public",
|
|
190
|
+
"module",
|
|
191
|
+
"exports",
|
|
192
|
+
"interface",
|
|
193
|
+
"enum",
|
|
194
|
+
"class",
|
|
195
|
+
"constructor",
|
|
196
|
+
"function",
|
|
197
|
+
"method",
|
|
198
|
+
"property",
|
|
199
|
+
"member",
|
|
200
|
+
"implements",
|
|
201
|
+
"extends",
|
|
202
|
+
"augments"
|
|
203
|
+
]);
|
|
204
|
+
function extractCustomTags(tags) {
|
|
205
|
+
const customTags = [];
|
|
206
|
+
for (const tag of tags) {
|
|
207
|
+
const tagName = tag.getTagName();
|
|
208
|
+
if (STANDARD_TAGS.has(tagName)) continue;
|
|
209
|
+
const text = getTagText(tag);
|
|
210
|
+
const value = text !== void 0 && text.trim().length > 0 ? text.trim() : void 0;
|
|
211
|
+
customTags.push({
|
|
212
|
+
name: tagName,
|
|
213
|
+
...value !== void 0 && { value }
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return customTags;
|
|
217
|
+
}
|
|
218
|
+
function getTagText(tag) {
|
|
219
|
+
const fullText = tag.getText();
|
|
220
|
+
const tagName = tag.getTagName();
|
|
221
|
+
const prefix = `@${tagName}`;
|
|
222
|
+
if (fullText.startsWith(prefix)) {
|
|
223
|
+
const text = fullText.slice(prefix.length).trim();
|
|
224
|
+
return text.length > 0 ? text : void 0;
|
|
225
|
+
}
|
|
226
|
+
return void 0;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// src/parsers/typescript-parser.ts
|
|
230
|
+
function createProject(options) {
|
|
231
|
+
return new Project({
|
|
232
|
+
tsConfigFilePath: options?.tsConfigPath,
|
|
233
|
+
compilerOptions: {
|
|
234
|
+
declaration: true,
|
|
235
|
+
...options?.compilerOptions
|
|
236
|
+
},
|
|
237
|
+
skipAddingFilesFromTsConfig: true
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
function parseSourceFile(project, filePath) {
|
|
241
|
+
try {
|
|
242
|
+
const sourceFile = project.addSourceFileAtPath(filePath);
|
|
243
|
+
return ok(sourceFile);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
return err({
|
|
246
|
+
code: "FILE_NOT_FOUND",
|
|
247
|
+
message: `Failed to parse source file: ${filePath}`,
|
|
248
|
+
filePath,
|
|
249
|
+
cause: error
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function parseSourceContent(project, content, virtualPath = "virtual.ts") {
|
|
254
|
+
try {
|
|
255
|
+
const sourceFile = project.createSourceFile(virtualPath, content, {
|
|
256
|
+
overwrite: true
|
|
257
|
+
});
|
|
258
|
+
return ok(sourceFile);
|
|
259
|
+
} catch (error) {
|
|
260
|
+
return err({
|
|
261
|
+
code: "INVALID_SYNTAX",
|
|
262
|
+
message: "Failed to parse TypeScript content",
|
|
263
|
+
filePath: virtualPath,
|
|
264
|
+
cause: error
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function extractExportedFunctions(sourceFile) {
|
|
269
|
+
const functions = [];
|
|
270
|
+
for (const func of sourceFile.getFunctions()) {
|
|
271
|
+
if (!func.isExported()) continue;
|
|
272
|
+
const name = func.getName() ?? "default";
|
|
273
|
+
const parameters = extractFunctionParameters(func);
|
|
274
|
+
const returnType = func.getReturnType().getText();
|
|
275
|
+
const jsdoc = extractJSDocInfo(func);
|
|
276
|
+
functions.push({
|
|
277
|
+
name,
|
|
278
|
+
jsdoc,
|
|
279
|
+
signature: func.getSignature()?.getDeclaration().getText() ?? func.getText(),
|
|
280
|
+
isAsync: func.isAsync(),
|
|
281
|
+
isGenerator: func.isGenerator(),
|
|
282
|
+
parameters,
|
|
283
|
+
returnType,
|
|
284
|
+
isDefault: func.isDefaultExport()
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
return functions;
|
|
288
|
+
}
|
|
289
|
+
function extractFunctionParameters(func) {
|
|
290
|
+
return func.getParameters().map((param) => ({
|
|
291
|
+
name: param.getName(),
|
|
292
|
+
type: param.getType().getText(),
|
|
293
|
+
optional: param.isOptional(),
|
|
294
|
+
defaultValue: param.getInitializer()?.getText()
|
|
295
|
+
}));
|
|
296
|
+
}
|
|
297
|
+
function extractExportedTypes(sourceFile) {
|
|
298
|
+
const types = [];
|
|
299
|
+
for (const iface of sourceFile.getInterfaces()) {
|
|
300
|
+
if (!iface.isExported()) continue;
|
|
301
|
+
const jsdoc = extractJSDocInfo(iface);
|
|
302
|
+
const typeParams = iface.getTypeParameters().map((tp) => tp.getText());
|
|
303
|
+
types.push({
|
|
304
|
+
name: iface.getName(),
|
|
305
|
+
jsdoc,
|
|
306
|
+
definition: iface.getText(),
|
|
307
|
+
kind: "interface",
|
|
308
|
+
isDefault: iface.isDefaultExport(),
|
|
309
|
+
typeParameters: typeParams.length > 0 ? typeParams : void 0
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
for (const typeAlias of sourceFile.getTypeAliases()) {
|
|
313
|
+
if (!typeAlias.isExported()) continue;
|
|
314
|
+
const jsdoc = extractJSDocInfo(typeAlias);
|
|
315
|
+
const typeParams = typeAlias.getTypeParameters().map((tp) => tp.getText());
|
|
316
|
+
types.push({
|
|
317
|
+
name: typeAlias.getName(),
|
|
318
|
+
jsdoc,
|
|
319
|
+
definition: typeAlias.getText(),
|
|
320
|
+
kind: "type",
|
|
321
|
+
isDefault: typeAlias.isDefaultExport(),
|
|
322
|
+
typeParameters: typeParams.length > 0 ? typeParams : void 0
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
for (const enumDecl of sourceFile.getEnums()) {
|
|
326
|
+
if (!enumDecl.isExported()) continue;
|
|
327
|
+
const jsdoc = extractJSDocInfo(enumDecl);
|
|
328
|
+
types.push({
|
|
329
|
+
name: enumDecl.getName(),
|
|
330
|
+
jsdoc,
|
|
331
|
+
definition: enumDecl.getText(),
|
|
332
|
+
kind: "enum",
|
|
333
|
+
isDefault: enumDecl.isDefaultExport()
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
for (const classDecl of sourceFile.getClasses()) {
|
|
337
|
+
if (!classDecl.isExported()) continue;
|
|
338
|
+
const name = classDecl.getName();
|
|
339
|
+
if (name === void 0) continue;
|
|
340
|
+
const jsdoc = extractJSDocInfo(classDecl);
|
|
341
|
+
const typeParams = classDecl.getTypeParameters().map((tp) => tp.getText());
|
|
342
|
+
types.push({
|
|
343
|
+
name,
|
|
344
|
+
jsdoc,
|
|
345
|
+
definition: classDecl.getText(),
|
|
346
|
+
kind: "class",
|
|
347
|
+
isDefault: classDecl.isDefaultExport(),
|
|
348
|
+
typeParameters: typeParams.length > 0 ? typeParams : void 0
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
return types;
|
|
352
|
+
}
|
|
353
|
+
function extractReExports(sourceFile) {
|
|
354
|
+
const reExports = [];
|
|
355
|
+
for (const exportDecl of sourceFile.getExportDeclarations()) {
|
|
356
|
+
const moduleSpecifier = exportDecl.getModuleSpecifierValue();
|
|
357
|
+
if (moduleSpecifier === void 0 || moduleSpecifier.length === 0) continue;
|
|
358
|
+
if (exportDecl.isNamespaceExport()) {
|
|
359
|
+
const namespaceExport = exportDecl.getNamespaceExport();
|
|
360
|
+
reExports.push({
|
|
361
|
+
from: moduleSpecifier,
|
|
362
|
+
exports: "*",
|
|
363
|
+
alias: namespaceExport?.getName()
|
|
364
|
+
});
|
|
365
|
+
} else {
|
|
366
|
+
const namedExports = exportDecl.getNamedExports().map((ne) => {
|
|
367
|
+
const aliasNode = ne.getAliasNode();
|
|
368
|
+
const alias = aliasNode === void 0 ? void 0 : aliasNode.getText();
|
|
369
|
+
const name = ne.getName();
|
|
370
|
+
return alias === void 0 ? name : `${name} as ${alias}`;
|
|
371
|
+
});
|
|
372
|
+
if (namedExports.length > 0) {
|
|
373
|
+
reExports.push({
|
|
374
|
+
from: moduleSpecifier,
|
|
375
|
+
exports: namedExports
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return reExports;
|
|
381
|
+
}
|
|
382
|
+
function extractPackageAPI(sourceFile) {
|
|
383
|
+
return {
|
|
384
|
+
functions: extractExportedFunctions(sourceFile),
|
|
385
|
+
types: extractExportedTypes(sourceFile),
|
|
386
|
+
reExports: extractReExports(sourceFile)
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
function analyzeTypeScriptFile(filePath, options) {
|
|
390
|
+
const project = createProject(options);
|
|
391
|
+
const sourceFileResult = parseSourceFile(project, filePath);
|
|
392
|
+
if (!sourceFileResult.success) {
|
|
393
|
+
return sourceFileResult;
|
|
394
|
+
}
|
|
395
|
+
try {
|
|
396
|
+
const api = extractPackageAPI(sourceFileResult.data);
|
|
397
|
+
return ok(api);
|
|
398
|
+
} catch (error) {
|
|
399
|
+
return err({
|
|
400
|
+
code: "INVALID_SYNTAX",
|
|
401
|
+
message: `Failed to analyze TypeScript file: ${filePath}`,
|
|
402
|
+
filePath,
|
|
403
|
+
cause: error
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function analyzeTypeScriptContent(content, options) {
|
|
408
|
+
const project = createProject(options);
|
|
409
|
+
const sourceFileResult = parseSourceContent(project, content);
|
|
410
|
+
if (!sourceFileResult.success) {
|
|
411
|
+
return sourceFileResult;
|
|
412
|
+
}
|
|
413
|
+
try {
|
|
414
|
+
const api = extractPackageAPI(sourceFileResult.data);
|
|
415
|
+
return ok(api);
|
|
416
|
+
} catch (error) {
|
|
417
|
+
return err({
|
|
418
|
+
code: "INVALID_SYNTAX",
|
|
419
|
+
message: "Failed to analyze TypeScript content",
|
|
420
|
+
cause: error
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// src/parsers/export-analyzer.ts
|
|
426
|
+
function analyzePublicAPI(entryPointPath, options) {
|
|
427
|
+
const project = createProject({ tsConfigPath: options?.tsConfigPath });
|
|
428
|
+
const sourceFileResult = parseSourceFile(project, entryPointPath);
|
|
429
|
+
if (!sourceFileResult.success) {
|
|
430
|
+
return sourceFileResult;
|
|
431
|
+
}
|
|
432
|
+
const sourceFile = sourceFileResult.data;
|
|
433
|
+
const api = extractPackageAPI(sourceFile);
|
|
434
|
+
const resolvedExports = resolveAllExports(sourceFile, api, project, options);
|
|
435
|
+
return ok2({
|
|
436
|
+
packagePath: sourceFile.getDirectoryPath(),
|
|
437
|
+
entryPoint: entryPointPath,
|
|
438
|
+
api,
|
|
439
|
+
resolvedExports
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
function resolveAllExports(sourceFile, api, project, options) {
|
|
443
|
+
const exports = [];
|
|
444
|
+
const filePath = sourceFile.getFilePath();
|
|
445
|
+
for (const func of api.functions) {
|
|
446
|
+
exports.push({
|
|
447
|
+
name: func.name,
|
|
448
|
+
kind: "function",
|
|
449
|
+
source: filePath,
|
|
450
|
+
isDefault: func.isDefault
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
for (const type of api.types) {
|
|
454
|
+
exports.push({
|
|
455
|
+
name: type.name,
|
|
456
|
+
kind: type.kind,
|
|
457
|
+
source: filePath,
|
|
458
|
+
isDefault: type.isDefault
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
if (options?.followReExports !== false) {
|
|
462
|
+
const maxDepth = options?.maxDepth ?? 5;
|
|
463
|
+
const reExportedItems = resolveReExports(
|
|
464
|
+
sourceFile,
|
|
465
|
+
api.reExports,
|
|
466
|
+
project,
|
|
467
|
+
maxDepth,
|
|
468
|
+
/* @__PURE__ */ new Set()
|
|
469
|
+
);
|
|
470
|
+
exports.push(...reExportedItems);
|
|
471
|
+
}
|
|
472
|
+
return exports;
|
|
473
|
+
}
|
|
474
|
+
function resolveReExports(sourceFile, reExports, project, remainingDepth, visited) {
|
|
475
|
+
if (remainingDepth <= 0 || reExports.length === 0) {
|
|
476
|
+
return [];
|
|
477
|
+
}
|
|
478
|
+
const exports = [];
|
|
479
|
+
for (const reExport of reExports) {
|
|
480
|
+
const resolvedPath = resolveModulePath(sourceFile, reExport.from);
|
|
481
|
+
if (resolvedPath === void 0 || visited.has(resolvedPath)) {
|
|
482
|
+
if (reExport.exports === "*") {
|
|
483
|
+
exports.push({
|
|
484
|
+
name: reExport.alias ?? "*",
|
|
485
|
+
kind: "re-export",
|
|
486
|
+
source: reExport.from,
|
|
487
|
+
isDefault: false
|
|
488
|
+
});
|
|
489
|
+
} else {
|
|
490
|
+
for (const name of reExport.exports) {
|
|
491
|
+
exports.push({
|
|
492
|
+
name,
|
|
493
|
+
kind: "re-export",
|
|
494
|
+
source: reExport.from,
|
|
495
|
+
isDefault: false
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
visited.add(resolvedPath);
|
|
502
|
+
try {
|
|
503
|
+
const reExportedFile = getOrAddSourceFile(project, resolvedPath);
|
|
504
|
+
if (reExportedFile === void 0) continue;
|
|
505
|
+
const reExportedAPI = extractPackageAPI(reExportedFile);
|
|
506
|
+
if (reExport.exports === "*") {
|
|
507
|
+
for (const func of reExportedAPI.functions) {
|
|
508
|
+
exports.push({
|
|
509
|
+
name: func.name,
|
|
510
|
+
kind: "function",
|
|
511
|
+
source: resolvedPath,
|
|
512
|
+
isDefault: func.isDefault
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
for (const type of reExportedAPI.types) {
|
|
516
|
+
exports.push({
|
|
517
|
+
name: type.name,
|
|
518
|
+
kind: type.kind,
|
|
519
|
+
source: resolvedPath,
|
|
520
|
+
isDefault: type.isDefault
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
const nestedExports = resolveReExports(
|
|
524
|
+
reExportedFile,
|
|
525
|
+
reExportedAPI.reExports,
|
|
526
|
+
project,
|
|
527
|
+
remainingDepth - 1,
|
|
528
|
+
visited
|
|
529
|
+
);
|
|
530
|
+
exports.push(...nestedExports);
|
|
531
|
+
} else {
|
|
532
|
+
for (const exportName of reExport.exports) {
|
|
533
|
+
const [originalName, alias] = parseExportName(exportName);
|
|
534
|
+
const func = reExportedAPI.functions.find((f) => f.name === originalName);
|
|
535
|
+
if (func !== void 0) {
|
|
536
|
+
exports.push({
|
|
537
|
+
name: alias ?? originalName,
|
|
538
|
+
kind: "function",
|
|
539
|
+
source: resolvedPath,
|
|
540
|
+
isDefault: func.isDefault
|
|
541
|
+
});
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
const type = reExportedAPI.types.find((t) => t.name === originalName);
|
|
545
|
+
if (type !== void 0) {
|
|
546
|
+
exports.push({
|
|
547
|
+
name: alias ?? originalName,
|
|
548
|
+
kind: type.kind,
|
|
549
|
+
source: resolvedPath,
|
|
550
|
+
isDefault: type.isDefault
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
} catch {
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return exports;
|
|
559
|
+
}
|
|
560
|
+
function parseExportName(exportName) {
|
|
561
|
+
const asIndex = exportName.indexOf(" as ");
|
|
562
|
+
if (asIndex > 0) {
|
|
563
|
+
return [exportName.slice(0, asIndex), exportName.slice(asIndex + 4)];
|
|
564
|
+
}
|
|
565
|
+
return [exportName, void 0];
|
|
566
|
+
}
|
|
567
|
+
function resolveModulePath(sourceFile, modulePath) {
|
|
568
|
+
if (!modulePath.startsWith(".")) {
|
|
569
|
+
return void 0;
|
|
570
|
+
}
|
|
571
|
+
try {
|
|
572
|
+
const directory = sourceFile.getDirectory();
|
|
573
|
+
const extensions = [".ts", ".tsx", "/index.ts", "/index.tsx", ".js", ".jsx"];
|
|
574
|
+
for (const ext of extensions) {
|
|
575
|
+
const candidate = directory.getSourceFile(modulePath + ext);
|
|
576
|
+
if (candidate !== void 0) {
|
|
577
|
+
return candidate.getFilePath();
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
const direct = directory.getSourceFile(modulePath);
|
|
581
|
+
return direct?.getFilePath();
|
|
582
|
+
} catch {
|
|
583
|
+
return void 0;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
function getOrAddSourceFile(project, filePath) {
|
|
587
|
+
try {
|
|
588
|
+
return project.getSourceFile(filePath) ?? project.addSourceFileAtPath(filePath);
|
|
589
|
+
} catch {
|
|
590
|
+
return void 0;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
function findExportedSymbols(entryPointPath, options) {
|
|
594
|
+
const analysisResult = analyzePublicAPI(entryPointPath, options);
|
|
595
|
+
if (!analysisResult.success) {
|
|
596
|
+
return analysisResult;
|
|
597
|
+
}
|
|
598
|
+
const symbols = analysisResult.data.resolvedExports.map((exp) => exp.name);
|
|
599
|
+
return ok2([...new Set(symbols)]);
|
|
600
|
+
}
|
|
601
|
+
function isSymbolExported(entryPointPath, symbolName, options) {
|
|
602
|
+
const analysisResult = analyzePublicAPI(entryPointPath, options);
|
|
603
|
+
if (!analysisResult.success) {
|
|
604
|
+
return analysisResult;
|
|
605
|
+
}
|
|
606
|
+
const isExported = analysisResult.data.resolvedExports.some((exp) => exp.name === symbolName);
|
|
607
|
+
return ok2(isExported);
|
|
608
|
+
}
|
|
609
|
+
function getExportedSymbolInfo(entryPointPath, symbolName, options) {
|
|
610
|
+
const analysisResult = analyzePublicAPI(entryPointPath, options);
|
|
611
|
+
if (!analysisResult.success) {
|
|
612
|
+
return analysisResult;
|
|
613
|
+
}
|
|
614
|
+
const exported = analysisResult.data.resolvedExports.find((exp) => exp.name === symbolName);
|
|
615
|
+
return ok2(exported);
|
|
616
|
+
}
|
|
617
|
+
function getExportsByKind(entryPointPath, kind, options) {
|
|
618
|
+
const analysisResult = analyzePublicAPI(entryPointPath, options);
|
|
619
|
+
if (!analysisResult.success) {
|
|
620
|
+
return analysisResult;
|
|
621
|
+
}
|
|
622
|
+
const filtered = analysisResult.data.resolvedExports.filter((exp) => exp.kind === kind);
|
|
623
|
+
return ok2(filtered);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// src/parsers/guards.ts
|
|
627
|
+
function isParseError(value) {
|
|
628
|
+
if (typeof value !== "object" || value === null) {
|
|
629
|
+
return false;
|
|
630
|
+
}
|
|
631
|
+
const obj = value;
|
|
632
|
+
return typeof obj.code === "string" && typeof obj.message === "string" && [
|
|
633
|
+
"INVALID_SYNTAX",
|
|
634
|
+
"FILE_NOT_FOUND",
|
|
635
|
+
"READ_ERROR",
|
|
636
|
+
"MALFORMED_JSON",
|
|
637
|
+
"UNSUPPORTED_FORMAT"
|
|
638
|
+
].includes(obj.code);
|
|
639
|
+
}
|
|
640
|
+
function isSyncError(value) {
|
|
641
|
+
if (typeof value !== "object" || value === null) {
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
const obj = value;
|
|
645
|
+
return typeof obj.code === "string" && typeof obj.message === "string" && [
|
|
646
|
+
"WRITE_ERROR",
|
|
647
|
+
"VALIDATION_ERROR",
|
|
648
|
+
"GENERATION_ERROR",
|
|
649
|
+
"PACKAGE_NOT_FOUND",
|
|
650
|
+
"CONFIG_ERROR"
|
|
651
|
+
].includes(obj.code);
|
|
652
|
+
}
|
|
653
|
+
function isJSDocParam(value) {
|
|
654
|
+
if (typeof value !== "object" || value === null) {
|
|
655
|
+
return false;
|
|
656
|
+
}
|
|
657
|
+
const obj = value;
|
|
658
|
+
return typeof obj.name === "string" && (obj.type === void 0 || typeof obj.type === "string") && (obj.description === void 0 || typeof obj.description === "string") && (obj.optional === void 0 || typeof obj.optional === "boolean") && (obj.defaultValue === void 0 || typeof obj.defaultValue === "string");
|
|
659
|
+
}
|
|
660
|
+
function isJSDocTag(value) {
|
|
661
|
+
if (typeof value !== "object" || value === null) {
|
|
662
|
+
return false;
|
|
663
|
+
}
|
|
664
|
+
const obj = value;
|
|
665
|
+
return typeof obj.name === "string" && (obj.value === void 0 || typeof obj.value === "string");
|
|
666
|
+
}
|
|
667
|
+
function isJSDocInfo(value) {
|
|
668
|
+
if (typeof value !== "object" || value === null) {
|
|
669
|
+
return false;
|
|
670
|
+
}
|
|
671
|
+
const obj = value;
|
|
672
|
+
return (obj.description === void 0 || typeof obj.description === "string") && (obj.params === void 0 || Array.isArray(obj.params) && obj.params.every(isJSDocParam)) && (obj.returns === void 0 || typeof obj.returns === "string") && (obj.examples === void 0 || Array.isArray(obj.examples) && obj.examples.every((e) => typeof e === "string")) && (obj.deprecated === void 0 || typeof obj.deprecated === "string") && (obj.since === void 0 || typeof obj.since === "string") && (obj.see === void 0 || Array.isArray(obj.see) && obj.see.every((s) => typeof s === "string")) && (obj.customTags === void 0 || Array.isArray(obj.customTags) && obj.customTags.every(isJSDocTag));
|
|
673
|
+
}
|
|
674
|
+
function isExportedFunction(value) {
|
|
675
|
+
if (typeof value !== "object" || value === null) {
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
const obj = value;
|
|
679
|
+
return typeof obj.name === "string" && typeof obj.signature === "string" && typeof obj.isAsync === "boolean" && typeof obj.isGenerator === "boolean" && Array.isArray(obj.parameters) && typeof obj.returnType === "string" && typeof obj.isDefault === "boolean";
|
|
680
|
+
}
|
|
681
|
+
function isExportedType(value) {
|
|
682
|
+
if (typeof value !== "object" || value === null) {
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
const obj = value;
|
|
686
|
+
return typeof obj.name === "string" && typeof obj.definition === "string" && typeof obj.kind === "string" && ["interface", "type", "enum", "class"].includes(obj.kind) && typeof obj.isDefault === "boolean";
|
|
687
|
+
}
|
|
688
|
+
function isReExport(value) {
|
|
689
|
+
if (typeof value !== "object" || value === null) {
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
692
|
+
const obj = value;
|
|
693
|
+
return typeof obj.from === "string" && (obj.exports === "*" || Array.isArray(obj.exports) && obj.exports.every((e) => typeof e === "string"));
|
|
694
|
+
}
|
|
695
|
+
function isPackageAPI(value) {
|
|
696
|
+
if (typeof value !== "object" || value === null) {
|
|
697
|
+
return false;
|
|
698
|
+
}
|
|
699
|
+
const obj = value;
|
|
700
|
+
return Array.isArray(obj.functions) && obj.functions.every(isExportedFunction) && Array.isArray(obj.types) && obj.types.every(isExportedType) && Array.isArray(obj.reExports) && obj.reExports.every(isReExport);
|
|
701
|
+
}
|
|
702
|
+
function isDocConfigSource(value) {
|
|
703
|
+
if (typeof value !== "object" || value === null) {
|
|
704
|
+
return false;
|
|
705
|
+
}
|
|
706
|
+
const obj = value;
|
|
707
|
+
return (obj.title === void 0 || typeof obj.title === "string") && (obj.description === void 0 || typeof obj.description === "string") && (obj.sidebar === void 0 || typeof obj.sidebar === "object") && (obj.excludeSections === void 0 || Array.isArray(obj.excludeSections) && obj.excludeSections.every((s) => typeof s === "string")) && (obj.frontmatter === void 0 || typeof obj.frontmatter === "object");
|
|
708
|
+
}
|
|
709
|
+
function isPackageInfo(value) {
|
|
710
|
+
if (typeof value !== "object" || value === null) {
|
|
711
|
+
return false;
|
|
712
|
+
}
|
|
713
|
+
const obj = value;
|
|
714
|
+
return typeof obj.name === "string" && typeof obj.version === "string" && typeof obj.packagePath === "string" && typeof obj.srcPath === "string" && (obj.description === void 0 || typeof obj.description === "string") && (obj.keywords === void 0 || Array.isArray(obj.keywords) && obj.keywords.every((k) => typeof k === "string")) && (obj.readmePath === void 0 || typeof obj.readmePath === "string") && (obj.docsConfig === void 0 || isDocConfigSource(obj.docsConfig));
|
|
715
|
+
}
|
|
716
|
+
function isReadmeSection(value) {
|
|
717
|
+
if (typeof value !== "object" || value === null) {
|
|
718
|
+
return false;
|
|
719
|
+
}
|
|
720
|
+
const obj = value;
|
|
721
|
+
return typeof obj.heading === "string" && typeof obj.level === "number" && obj.level >= 1 && obj.level <= 6 && typeof obj.content === "string" && Array.isArray(obj.children) && obj.children.every(isReadmeSection);
|
|
722
|
+
}
|
|
723
|
+
function isReadmeContent(value) {
|
|
724
|
+
if (typeof value !== "object" || value === null) {
|
|
725
|
+
return false;
|
|
726
|
+
}
|
|
727
|
+
const obj = value;
|
|
728
|
+
return (obj.title === void 0 || typeof obj.title === "string") && (obj.preamble === void 0 || typeof obj.preamble === "string") && Array.isArray(obj.sections) && obj.sections.every(isReadmeSection) && typeof obj.raw === "string";
|
|
729
|
+
}
|
|
730
|
+
function isMDXFrontmatter(value) {
|
|
731
|
+
if (typeof value !== "object" || value === null) {
|
|
732
|
+
return false;
|
|
733
|
+
}
|
|
734
|
+
const obj = value;
|
|
735
|
+
return typeof obj.title === "string" && (obj.description === void 0 || typeof obj.description === "string") && (obj.sidebar === void 0 || typeof obj.sidebar === "object") && (obj.tableOfContents === void 0 || typeof obj.tableOfContents === "boolean" || typeof obj.tableOfContents === "object") && (obj.template === void 0 || obj.template === "doc" || obj.template === "splash");
|
|
736
|
+
}
|
|
737
|
+
function isValidPackageName(name) {
|
|
738
|
+
if (name.length === 0) {
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
741
|
+
if (name.startsWith(".") || name.startsWith("_")) {
|
|
742
|
+
return false;
|
|
743
|
+
}
|
|
744
|
+
if (name.startsWith("@")) {
|
|
745
|
+
const slashIndex = name.indexOf("/");
|
|
746
|
+
if (slashIndex <= 1 || slashIndex === name.length - 1) {
|
|
747
|
+
return false;
|
|
748
|
+
}
|
|
749
|
+
const scope = name.slice(1, slashIndex);
|
|
750
|
+
const pkg = name.slice(slashIndex + 1);
|
|
751
|
+
return isValidUnscopedPackageName(scope) && isValidUnscopedPackageName(pkg);
|
|
752
|
+
}
|
|
753
|
+
return isValidUnscopedPackageName(name);
|
|
754
|
+
}
|
|
755
|
+
function isValidUnscopedPackageName(name) {
|
|
756
|
+
return /^\w[\w.-]*$/.test(name);
|
|
757
|
+
}
|
|
758
|
+
function isValidSemver(version) {
|
|
759
|
+
return /^\d+\.\d+\.\d+(?:-[\w.-]+)?(?:\+[\w.-]+)?$/.test(version);
|
|
760
|
+
}
|
|
761
|
+
function isValidHeadingLevel(level) {
|
|
762
|
+
return Number.isInteger(level) && level >= 1 && level <= 6;
|
|
763
|
+
}
|
|
764
|
+
function isSafeContent(content) {
|
|
765
|
+
const dangerousPatterns = [/<script\b/i, /javascript:/i, /on\w+\s*=/i, /data:/i, /vbscript:/i];
|
|
766
|
+
return !dangerousPatterns.some((pattern) => pattern.test(content));
|
|
767
|
+
}
|
|
768
|
+
function isSafeFilePath(filePath) {
|
|
769
|
+
const normalizedPath = filePath.replaceAll("\\", "/").replaceAll(/\/+/g, "/").replaceAll("/./", "/");
|
|
770
|
+
if (normalizedPath.includes("../") || normalizedPath.includes("..\\")) {
|
|
771
|
+
return false;
|
|
772
|
+
}
|
|
773
|
+
if (normalizedPath.startsWith("/") && !filePath.startsWith("/")) {
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
return true;
|
|
777
|
+
}
|
|
778
|
+
function assertParseError(value) {
|
|
779
|
+
if (!isParseError(value)) {
|
|
780
|
+
throw new TypeError("Expected ParseError");
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
function assertPackageInfo(value) {
|
|
784
|
+
if (!isPackageInfo(value)) {
|
|
785
|
+
throw new TypeError("Expected PackageInfo");
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
function assertPackageAPI(value) {
|
|
789
|
+
if (!isPackageAPI(value)) {
|
|
790
|
+
throw new TypeError("Expected PackageAPI");
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// src/parsers/package-info.ts
|
|
795
|
+
import path from "path";
|
|
796
|
+
import { err as err2, ok as ok3 } from "@bfra.me/es/result";
|
|
797
|
+
async function parsePackageJson(packagePath, options) {
|
|
798
|
+
const packageJsonPath = packagePath.endsWith("package.json") ? packagePath : path.join(packagePath, "package.json");
|
|
799
|
+
try {
|
|
800
|
+
const fs = await import("fs/promises");
|
|
801
|
+
const content = await fs.readFile(packageJsonPath, "utf-8");
|
|
802
|
+
return parsePackageJsonContent(content, packageJsonPath, options);
|
|
803
|
+
} catch (error) {
|
|
804
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
805
|
+
return err2({
|
|
806
|
+
code: "FILE_NOT_FOUND",
|
|
807
|
+
message: `package.json not found: ${packageJsonPath}`,
|
|
808
|
+
filePath: packageJsonPath,
|
|
809
|
+
cause: error
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
return err2({
|
|
813
|
+
code: "READ_ERROR",
|
|
814
|
+
message: `Failed to read package.json: ${packageJsonPath}`,
|
|
815
|
+
filePath: packageJsonPath,
|
|
816
|
+
cause: error
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
function parsePackageJsonContent(content, filePath, options) {
|
|
821
|
+
let parsed;
|
|
822
|
+
try {
|
|
823
|
+
parsed = JSON.parse(content);
|
|
824
|
+
} catch (error) {
|
|
825
|
+
return err2({
|
|
826
|
+
code: "MALFORMED_JSON",
|
|
827
|
+
message: `Invalid JSON in package.json: ${filePath}`,
|
|
828
|
+
filePath,
|
|
829
|
+
cause: error
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
if (!isPackageJson(parsed)) {
|
|
833
|
+
return err2({
|
|
834
|
+
code: "INVALID_SYNTAX",
|
|
835
|
+
message: "package.json is missing required fields (name, version)",
|
|
836
|
+
filePath
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
const packageDir = path.dirname(filePath);
|
|
840
|
+
return ok3({
|
|
841
|
+
name: parsed.name,
|
|
842
|
+
version: parsed.version,
|
|
843
|
+
...parsed.description !== void 0 && { description: parsed.description },
|
|
844
|
+
...parsed.keywords !== void 0 && { keywords: parsed.keywords },
|
|
845
|
+
packagePath: packageDir,
|
|
846
|
+
srcPath: path.join(packageDir, "src"),
|
|
847
|
+
...options?.extractDocsConfig !== false && parsed.docs !== void 0 && { docsConfig: parsed.docs }
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
function isPackageJson(value) {
|
|
851
|
+
if (typeof value !== "object" || value === null) {
|
|
852
|
+
return false;
|
|
853
|
+
}
|
|
854
|
+
const obj = value;
|
|
855
|
+
if (typeof obj.name !== "string" || obj.name.length === 0) {
|
|
856
|
+
return false;
|
|
857
|
+
}
|
|
858
|
+
if (typeof obj.version !== "string" || obj.version.length === 0) {
|
|
859
|
+
return false;
|
|
860
|
+
}
|
|
861
|
+
return true;
|
|
862
|
+
}
|
|
863
|
+
function extractDocsConfig(pkg) {
|
|
864
|
+
return pkg.docsConfig;
|
|
865
|
+
}
|
|
866
|
+
async function findReadmePath(packagePath) {
|
|
867
|
+
const fs = await import("fs/promises");
|
|
868
|
+
const candidates = ["README.md", "readme.md", "Readme.md", "README.MD", "README"];
|
|
869
|
+
for (const candidate of candidates) {
|
|
870
|
+
const readmePath = path.join(packagePath, candidate);
|
|
871
|
+
try {
|
|
872
|
+
await fs.access(readmePath);
|
|
873
|
+
return readmePath;
|
|
874
|
+
} catch {
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
return void 0;
|
|
878
|
+
}
|
|
879
|
+
function findEntryPoint(pkg, content) {
|
|
880
|
+
try {
|
|
881
|
+
const parsed = JSON.parse(content);
|
|
882
|
+
if (parsed.exports !== void 0) {
|
|
883
|
+
const mainExport = parsed.exports["."];
|
|
884
|
+
if (mainExport !== void 0 && typeof mainExport === "object") {
|
|
885
|
+
const exportObj = mainExport;
|
|
886
|
+
if (typeof exportObj.source === "string") {
|
|
887
|
+
return path.join(pkg.packagePath, exportObj.source);
|
|
888
|
+
}
|
|
889
|
+
if (typeof exportObj.import === "string") {
|
|
890
|
+
const importPath = exportObj.import;
|
|
891
|
+
if (importPath.includes("/lib/")) {
|
|
892
|
+
return path.join(
|
|
893
|
+
pkg.packagePath,
|
|
894
|
+
importPath.replace("/lib/", "/src/").replace(".js", ".ts")
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
return path.join(pkg.packagePath, importPath);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
if (typeof mainExport === "string") {
|
|
901
|
+
return path.join(pkg.packagePath, mainExport);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
if (typeof parsed.types === "string") {
|
|
905
|
+
const typesPath = parsed.types.replace("/lib/", "/src/").replace(".d.ts", ".ts");
|
|
906
|
+
return path.join(pkg.packagePath, typesPath);
|
|
907
|
+
}
|
|
908
|
+
if (typeof parsed.main === "string") {
|
|
909
|
+
const mainPath = parsed.main.replace("/lib/", "/src/").replace(".js", ".ts");
|
|
910
|
+
return path.join(pkg.packagePath, mainPath);
|
|
911
|
+
}
|
|
912
|
+
} catch {
|
|
913
|
+
}
|
|
914
|
+
return path.join(pkg.srcPath, "index.ts");
|
|
915
|
+
}
|
|
916
|
+
async function parsePackageComplete(packagePath, options) {
|
|
917
|
+
const packageInfoResult = await parsePackageJson(packagePath, options);
|
|
918
|
+
if (!packageInfoResult.success) {
|
|
919
|
+
return packageInfoResult;
|
|
920
|
+
}
|
|
921
|
+
const readmePath = await findReadmePath(packageInfoResult.data.packagePath);
|
|
922
|
+
return ok3({
|
|
923
|
+
...packageInfoResult.data,
|
|
924
|
+
...readmePath !== void 0 && { readmePath }
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
function getPackageScope(packageName) {
|
|
928
|
+
if (packageName.startsWith("@")) {
|
|
929
|
+
const slashIndex = packageName.indexOf("/");
|
|
930
|
+
if (slashIndex > 0) {
|
|
931
|
+
return packageName.slice(0, slashIndex);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
return void 0;
|
|
935
|
+
}
|
|
936
|
+
function getUnscopedName(packageName) {
|
|
937
|
+
if (packageName.startsWith("@")) {
|
|
938
|
+
const slashIndex = packageName.indexOf("/");
|
|
939
|
+
if (slashIndex > 0) {
|
|
940
|
+
return packageName.slice(slashIndex + 1);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
return packageName;
|
|
944
|
+
}
|
|
945
|
+
function buildDocSlug(packageName) {
|
|
946
|
+
return getUnscopedName(packageName).toLowerCase().replaceAll(/[^a-z0-9-]/g, "-");
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
// src/parsers/readme-parser.ts
|
|
950
|
+
import { err as err3, ok as ok4 } from "@bfra.me/es/result";
|
|
951
|
+
import remarkParse from "remark-parse";
|
|
952
|
+
import { unified } from "unified";
|
|
953
|
+
function parseReadme(content, options) {
|
|
954
|
+
try {
|
|
955
|
+
const processor = unified().use(remarkParse);
|
|
956
|
+
const tree = processor.parse(content);
|
|
957
|
+
const title = extractTitle(tree);
|
|
958
|
+
const preamble = extractPreamble(tree);
|
|
959
|
+
const sections = options?.extractSections === false ? [] : extractSections(tree);
|
|
960
|
+
return ok4({
|
|
961
|
+
...title !== void 0 && { title },
|
|
962
|
+
...preamble !== void 0 && { preamble },
|
|
963
|
+
sections,
|
|
964
|
+
raw: options?.preserveRaw === false ? "" : content
|
|
965
|
+
});
|
|
966
|
+
} catch (error) {
|
|
967
|
+
return err3({
|
|
968
|
+
code: "INVALID_SYNTAX",
|
|
969
|
+
message: "Failed to parse README content",
|
|
970
|
+
cause: error
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
async function parseReadmeFile(filePath, options) {
|
|
975
|
+
try {
|
|
976
|
+
const fs = await import("fs/promises");
|
|
977
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
978
|
+
return parseReadme(content, options);
|
|
979
|
+
} catch (error) {
|
|
980
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
981
|
+
return err3({
|
|
982
|
+
code: "FILE_NOT_FOUND",
|
|
983
|
+
message: `README file not found: ${filePath}`,
|
|
984
|
+
filePath,
|
|
985
|
+
cause: error
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
return err3({
|
|
989
|
+
code: "READ_ERROR",
|
|
990
|
+
message: `Failed to read README file: ${filePath}`,
|
|
991
|
+
filePath,
|
|
992
|
+
cause: error
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
function extractTitle(tree) {
|
|
997
|
+
for (const node of tree.children) {
|
|
998
|
+
if (node.type === "heading" && node.depth === 1) {
|
|
999
|
+
return extractTextFromNode(node);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
return void 0;
|
|
1003
|
+
}
|
|
1004
|
+
function extractPreamble(tree) {
|
|
1005
|
+
const preambleNodes = [];
|
|
1006
|
+
for (const node of tree.children) {
|
|
1007
|
+
if (node.type === "heading") {
|
|
1008
|
+
break;
|
|
1009
|
+
}
|
|
1010
|
+
preambleNodes.push(node);
|
|
1011
|
+
}
|
|
1012
|
+
if (preambleNodes.length === 0) {
|
|
1013
|
+
return void 0;
|
|
1014
|
+
}
|
|
1015
|
+
const text = preambleNodes.map(extractTextFromNode).join("\n\n").trim();
|
|
1016
|
+
return text.length > 0 ? text : void 0;
|
|
1017
|
+
}
|
|
1018
|
+
function extractSections(tree) {
|
|
1019
|
+
const sections = [];
|
|
1020
|
+
const stack = [];
|
|
1021
|
+
for (let i = 0; i < tree.children.length; i++) {
|
|
1022
|
+
const node = tree.children[i];
|
|
1023
|
+
if (node !== void 0 && node.type === "heading") {
|
|
1024
|
+
const heading = extractTextFromNode(node);
|
|
1025
|
+
const level = node.depth;
|
|
1026
|
+
const content = extractSectionContent(tree, i + 1);
|
|
1027
|
+
const newSection = {
|
|
1028
|
+
heading,
|
|
1029
|
+
level,
|
|
1030
|
+
content,
|
|
1031
|
+
children: []
|
|
1032
|
+
};
|
|
1033
|
+
while (stack.length > 0 && (stack.at(-1)?.level ?? 0) >= level) {
|
|
1034
|
+
stack.pop();
|
|
1035
|
+
}
|
|
1036
|
+
if (stack.length === 0) {
|
|
1037
|
+
sections.push(newSection);
|
|
1038
|
+
} else {
|
|
1039
|
+
const parent = stack.at(-1);
|
|
1040
|
+
parent?.section.children.push(newSection);
|
|
1041
|
+
}
|
|
1042
|
+
stack.push({ level, section: newSection });
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
return freezeSections(sections);
|
|
1046
|
+
}
|
|
1047
|
+
function freezeSections(sections) {
|
|
1048
|
+
return sections.map((s) => ({
|
|
1049
|
+
heading: s.heading,
|
|
1050
|
+
level: s.level,
|
|
1051
|
+
content: s.content,
|
|
1052
|
+
children: freezeSections([...s.children])
|
|
1053
|
+
}));
|
|
1054
|
+
}
|
|
1055
|
+
function extractSectionContent(tree, startIndex) {
|
|
1056
|
+
const contentNodes = [];
|
|
1057
|
+
for (let i = startIndex; i < tree.children.length; i++) {
|
|
1058
|
+
const node = tree.children[i];
|
|
1059
|
+
if (node === void 0 || node.type === "heading") {
|
|
1060
|
+
break;
|
|
1061
|
+
}
|
|
1062
|
+
contentNodes.push(node);
|
|
1063
|
+
}
|
|
1064
|
+
return contentNodes.map(serializeNode).join("\n\n").trim();
|
|
1065
|
+
}
|
|
1066
|
+
function extractTextFromNode(node) {
|
|
1067
|
+
if ("value" in node && typeof node.value === "string") {
|
|
1068
|
+
return node.value;
|
|
1069
|
+
}
|
|
1070
|
+
if ("children" in node && Array.isArray(node.children)) {
|
|
1071
|
+
return node.children.map(extractTextFromNode).join("");
|
|
1072
|
+
}
|
|
1073
|
+
return "";
|
|
1074
|
+
}
|
|
1075
|
+
function serializeNode(node) {
|
|
1076
|
+
if (node.type === "paragraph") {
|
|
1077
|
+
return extractTextFromNode(node);
|
|
1078
|
+
}
|
|
1079
|
+
if (node.type === "heading") {
|
|
1080
|
+
const prefix = "#".repeat(node.depth);
|
|
1081
|
+
return `${prefix} ${extractTextFromNode(node)}`;
|
|
1082
|
+
}
|
|
1083
|
+
if (node.type === "code") {
|
|
1084
|
+
return `\`\`\`${node.lang ?? ""}
|
|
1085
|
+
${node.value}
|
|
1086
|
+
\`\`\``;
|
|
1087
|
+
}
|
|
1088
|
+
if (node.type === "blockquote") {
|
|
1089
|
+
return node.children.map((c) => `> ${serializeNode(c)}`).join("\n");
|
|
1090
|
+
}
|
|
1091
|
+
if (node.type === "list") {
|
|
1092
|
+
const items = node.children.map((item, index) => {
|
|
1093
|
+
if (item.type !== "listItem") return "";
|
|
1094
|
+
const prefix = node.ordered === true ? `${index + 1}. ` : "- ";
|
|
1095
|
+
const content = item.children.map(serializeNode).join("\n");
|
|
1096
|
+
return `${prefix}${content}`;
|
|
1097
|
+
}).filter((s) => s.length > 0);
|
|
1098
|
+
return items.join("\n");
|
|
1099
|
+
}
|
|
1100
|
+
if (node.type === "thematicBreak") {
|
|
1101
|
+
return "---";
|
|
1102
|
+
}
|
|
1103
|
+
if (node.type === "html") {
|
|
1104
|
+
return node.value;
|
|
1105
|
+
}
|
|
1106
|
+
if (node.type === "table") {
|
|
1107
|
+
return serializeTable(node);
|
|
1108
|
+
}
|
|
1109
|
+
return extractTextFromNode(node);
|
|
1110
|
+
}
|
|
1111
|
+
function serializeTable(node) {
|
|
1112
|
+
if (node.type !== "table" || !("children" in node)) {
|
|
1113
|
+
return "";
|
|
1114
|
+
}
|
|
1115
|
+
const rows = node.children.filter((row) => row.type === "tableRow").map((row) => {
|
|
1116
|
+
const cells = row.children.filter((cell) => cell.type === "tableCell").map((cell) => extractTextFromNode(cell));
|
|
1117
|
+
return `| ${cells.join(" | ")} |`;
|
|
1118
|
+
});
|
|
1119
|
+
if (rows.length === 0) {
|
|
1120
|
+
return "";
|
|
1121
|
+
}
|
|
1122
|
+
const headerRow = rows[0];
|
|
1123
|
+
if (headerRow !== void 0) {
|
|
1124
|
+
const columnCount = (headerRow.match(/\|/g)?.length ?? 2) - 1;
|
|
1125
|
+
const separator = `|${" --- |".repeat(columnCount)}`;
|
|
1126
|
+
rows.splice(1, 0, separator);
|
|
1127
|
+
}
|
|
1128
|
+
return rows.join("\n");
|
|
1129
|
+
}
|
|
1130
|
+
function findSection(content, headingText) {
|
|
1131
|
+
const normalizedSearch = headingText.toLowerCase();
|
|
1132
|
+
function searchInSections(sections) {
|
|
1133
|
+
for (const section of sections) {
|
|
1134
|
+
if (section.heading.toLowerCase() === normalizedSearch) {
|
|
1135
|
+
return section;
|
|
1136
|
+
}
|
|
1137
|
+
const found = searchInSections(section.children);
|
|
1138
|
+
if (found !== void 0) {
|
|
1139
|
+
return found;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
return void 0;
|
|
1143
|
+
}
|
|
1144
|
+
return searchInSections(content.sections);
|
|
1145
|
+
}
|
|
1146
|
+
function getSectionsByLevel(content, level) {
|
|
1147
|
+
const result = [];
|
|
1148
|
+
function collectAtLevel(sections) {
|
|
1149
|
+
for (const section of sections) {
|
|
1150
|
+
if (section.level === level) {
|
|
1151
|
+
result.push(section);
|
|
1152
|
+
}
|
|
1153
|
+
collectAtLevel(section.children);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
collectAtLevel(content.sections);
|
|
1157
|
+
return result;
|
|
1158
|
+
}
|
|
1159
|
+
function flattenSections(content) {
|
|
1160
|
+
const result = [];
|
|
1161
|
+
function collect(sections) {
|
|
1162
|
+
for (const section of sections) {
|
|
1163
|
+
result.push(section);
|
|
1164
|
+
collect(section.children);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
collect(content.sections);
|
|
1168
|
+
return result;
|
|
1169
|
+
}
|
|
1170
|
+
function getTableOfContents(content) {
|
|
1171
|
+
return flattenSections(content).map((s) => ({
|
|
1172
|
+
heading: s.heading,
|
|
1173
|
+
level: s.level
|
|
1174
|
+
}));
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
export {
|
|
1178
|
+
hasJSDoc,
|
|
1179
|
+
extractJSDocInfo,
|
|
1180
|
+
parseJSDoc,
|
|
1181
|
+
createProject,
|
|
1182
|
+
parseSourceFile,
|
|
1183
|
+
parseSourceContent,
|
|
1184
|
+
extractExportedFunctions,
|
|
1185
|
+
extractExportedTypes,
|
|
1186
|
+
extractReExports,
|
|
1187
|
+
extractPackageAPI,
|
|
1188
|
+
analyzeTypeScriptFile,
|
|
1189
|
+
analyzeTypeScriptContent,
|
|
1190
|
+
analyzePublicAPI,
|
|
1191
|
+
findExportedSymbols,
|
|
1192
|
+
isSymbolExported,
|
|
1193
|
+
getExportedSymbolInfo,
|
|
1194
|
+
getExportsByKind,
|
|
1195
|
+
isParseError,
|
|
1196
|
+
isSyncError,
|
|
1197
|
+
isJSDocParam,
|
|
1198
|
+
isJSDocTag,
|
|
1199
|
+
isJSDocInfo,
|
|
1200
|
+
isExportedFunction,
|
|
1201
|
+
isExportedType,
|
|
1202
|
+
isReExport,
|
|
1203
|
+
isPackageAPI,
|
|
1204
|
+
isDocConfigSource,
|
|
1205
|
+
isPackageInfo,
|
|
1206
|
+
isReadmeSection,
|
|
1207
|
+
isReadmeContent,
|
|
1208
|
+
isMDXFrontmatter,
|
|
1209
|
+
isValidPackageName,
|
|
1210
|
+
isValidSemver,
|
|
1211
|
+
isValidHeadingLevel,
|
|
1212
|
+
isSafeContent,
|
|
1213
|
+
isSafeFilePath,
|
|
1214
|
+
assertParseError,
|
|
1215
|
+
assertPackageInfo,
|
|
1216
|
+
assertPackageAPI,
|
|
1217
|
+
parsePackageJson,
|
|
1218
|
+
parsePackageJsonContent,
|
|
1219
|
+
extractDocsConfig,
|
|
1220
|
+
findReadmePath,
|
|
1221
|
+
findEntryPoint,
|
|
1222
|
+
parsePackageComplete,
|
|
1223
|
+
getPackageScope,
|
|
1224
|
+
getUnscopedName,
|
|
1225
|
+
buildDocSlug,
|
|
1226
|
+
parseReadme,
|
|
1227
|
+
parseReadmeFile,
|
|
1228
|
+
findSection,
|
|
1229
|
+
getSectionsByLevel,
|
|
1230
|
+
flattenSections,
|
|
1231
|
+
getTableOfContents
|
|
1232
|
+
};
|
|
1233
|
+
//# sourceMappingURL=chunk-6NKAJT2M.js.map
|