@doccov/sdk 0.6.0 → 0.8.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/dist/index.d.ts +633 -8
- package/dist/index.js +705 -50
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = createRequire(import.meta.url);
|
|
19
|
+
|
|
1
20
|
// src/analysis/docs-coverage.ts
|
|
2
21
|
import ts from "typescript";
|
|
3
22
|
|
|
@@ -2042,7 +2061,36 @@ function createAnalysisContext({
|
|
|
2042
2061
|
// src/analysis/spec-builder.ts
|
|
2043
2062
|
import * as fs2 from "node:fs";
|
|
2044
2063
|
import * as path3 from "node:path";
|
|
2045
|
-
import { SCHEMA_URL } from "@openpkg-ts/spec";
|
|
2064
|
+
import { SCHEMA_URL, SCHEMA_VERSION } from "@openpkg-ts/spec";
|
|
2065
|
+
|
|
2066
|
+
// src/analysis/decorator-utils.ts
|
|
2067
|
+
function extractDecorators(node) {
|
|
2068
|
+
if (!ts2.canHaveDecorators(node)) {
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
2071
|
+
const decorators = ts2.getDecorators(node);
|
|
2072
|
+
if (!decorators || decorators.length === 0) {
|
|
2073
|
+
return;
|
|
2074
|
+
}
|
|
2075
|
+
return decorators.map((decorator) => {
|
|
2076
|
+
const expression = decorator.expression;
|
|
2077
|
+
if (ts2.isIdentifier(expression)) {
|
|
2078
|
+
return { name: expression.text };
|
|
2079
|
+
}
|
|
2080
|
+
if (ts2.isCallExpression(expression)) {
|
|
2081
|
+
const name = ts2.isIdentifier(expression.expression) ? expression.expression.text : expression.expression.getText();
|
|
2082
|
+
const argumentsText = expression.arguments.map((arg) => arg.getText());
|
|
2083
|
+
return { name, argumentsText };
|
|
2084
|
+
}
|
|
2085
|
+
if (ts2.isPropertyAccessExpression(expression)) {
|
|
2086
|
+
return { name: expression.getText() };
|
|
2087
|
+
}
|
|
2088
|
+
return { name: expression.getText() };
|
|
2089
|
+
});
|
|
2090
|
+
}
|
|
2091
|
+
function extractParameterDecorators(param) {
|
|
2092
|
+
return extractDecorators(param);
|
|
2093
|
+
}
|
|
2046
2094
|
|
|
2047
2095
|
// src/utils/parameter-utils.ts
|
|
2048
2096
|
var BUILTIN_TYPE_SCHEMAS = {
|
|
@@ -2972,6 +3020,10 @@ function structureParameter(param, paramDecl, paramType, typeChecker, typeRefs,
|
|
|
2972
3020
|
if (paramDecl.dotDotDotToken) {
|
|
2973
3021
|
out.rest = true;
|
|
2974
3022
|
}
|
|
3023
|
+
const decorators = extractParameterDecorators(paramDecl);
|
|
3024
|
+
if (decorators) {
|
|
3025
|
+
out.decorators = decorators;
|
|
3026
|
+
}
|
|
2975
3027
|
return out;
|
|
2976
3028
|
}
|
|
2977
3029
|
|
|
@@ -2980,6 +3032,7 @@ function parseJSDocBlock(commentText) {
|
|
|
2980
3032
|
const result = {
|
|
2981
3033
|
description: "",
|
|
2982
3034
|
params: [],
|
|
3035
|
+
throws: [],
|
|
2983
3036
|
examples: [],
|
|
2984
3037
|
tags: [],
|
|
2985
3038
|
rawParamNames: []
|
|
@@ -3085,6 +3138,22 @@ function parseReturnContent(content) {
|
|
|
3085
3138
|
description: processInlineLinks(remaining)
|
|
3086
3139
|
};
|
|
3087
3140
|
}
|
|
3141
|
+
function parseThrowsContent(content) {
|
|
3142
|
+
const trimmed = content.trim();
|
|
3143
|
+
let remaining = trimmed;
|
|
3144
|
+
let type;
|
|
3145
|
+
if (remaining.startsWith("{")) {
|
|
3146
|
+
const typeEnd = findMatchingBrace(remaining, 0);
|
|
3147
|
+
if (typeEnd > 0) {
|
|
3148
|
+
type = remaining.slice(1, typeEnd).trim();
|
|
3149
|
+
remaining = remaining.slice(typeEnd + 1).trim();
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3152
|
+
return {
|
|
3153
|
+
type,
|
|
3154
|
+
description: processInlineLinks(remaining)
|
|
3155
|
+
};
|
|
3156
|
+
}
|
|
3088
3157
|
function findMatchingBrace(text, startIndex) {
|
|
3089
3158
|
if (text[startIndex] !== "{")
|
|
3090
3159
|
return -1;
|
|
@@ -3141,14 +3210,35 @@ function processTagContent(result, tag, content) {
|
|
|
3141
3210
|
result.rawParamNames.push(parsed.name);
|
|
3142
3211
|
result.params.push(parsed);
|
|
3143
3212
|
}
|
|
3144
|
-
result.tags.push({
|
|
3213
|
+
result.tags.push({
|
|
3214
|
+
name: "param",
|
|
3215
|
+
text: trimmedContent,
|
|
3216
|
+
paramName: parsed?.name,
|
|
3217
|
+
typeAnnotation: parsed?.type
|
|
3218
|
+
});
|
|
3145
3219
|
break;
|
|
3146
3220
|
}
|
|
3147
3221
|
case "returns":
|
|
3148
3222
|
case "return": {
|
|
3149
3223
|
const parsed = parseReturnContent(trimmedContent);
|
|
3150
3224
|
result.returns = parsed;
|
|
3151
|
-
result.tags.push({
|
|
3225
|
+
result.tags.push({
|
|
3226
|
+
name: "returns",
|
|
3227
|
+
text: trimmedContent,
|
|
3228
|
+
typeAnnotation: parsed.type
|
|
3229
|
+
});
|
|
3230
|
+
break;
|
|
3231
|
+
}
|
|
3232
|
+
case "throws":
|
|
3233
|
+
case "throw":
|
|
3234
|
+
case "exception": {
|
|
3235
|
+
const parsed = parseThrowsContent(trimmedContent);
|
|
3236
|
+
result.throws.push(parsed);
|
|
3237
|
+
result.tags.push({
|
|
3238
|
+
name: "throws",
|
|
3239
|
+
text: trimmedContent,
|
|
3240
|
+
typeAnnotation: parsed.type
|
|
3241
|
+
});
|
|
3152
3242
|
break;
|
|
3153
3243
|
}
|
|
3154
3244
|
case "example": {
|
|
@@ -3156,26 +3246,70 @@ function processTagContent(result, tag, content) {
|
|
|
3156
3246
|
if (example) {
|
|
3157
3247
|
result.examples.push(example);
|
|
3158
3248
|
}
|
|
3249
|
+
const langMatch = trimmedContent.match(/^```(\w+)/);
|
|
3250
|
+
result.tags.push({
|
|
3251
|
+
name: "example",
|
|
3252
|
+
text: example,
|
|
3253
|
+
language: langMatch?.[1]
|
|
3254
|
+
});
|
|
3159
3255
|
break;
|
|
3160
3256
|
}
|
|
3161
3257
|
case "see": {
|
|
3162
3258
|
const linkTargets = extractAllLinkTargets(trimmedContent);
|
|
3163
3259
|
for (const target of linkTargets) {
|
|
3164
|
-
result.tags.push({ name: "link", text: target });
|
|
3165
|
-
result.tags.push({ name: "see", text: target });
|
|
3260
|
+
result.tags.push({ name: "link", text: target, reference: target });
|
|
3261
|
+
result.tags.push({ name: "see", text: target, reference: target });
|
|
3166
3262
|
}
|
|
3167
3263
|
if (linkTargets.length === 0) {
|
|
3168
|
-
result.tags.push({ name: "see", text: trimmedContent });
|
|
3264
|
+
result.tags.push({ name: "see", text: trimmedContent, reference: trimmedContent });
|
|
3169
3265
|
}
|
|
3170
3266
|
break;
|
|
3171
3267
|
}
|
|
3172
3268
|
case "link": {
|
|
3173
3269
|
const target = extractLinkTarget(trimmedContent);
|
|
3174
3270
|
if (target) {
|
|
3175
|
-
result.tags.push({ name: "link", text: target });
|
|
3271
|
+
result.tags.push({ name: "link", text: target, reference: target });
|
|
3176
3272
|
}
|
|
3177
3273
|
break;
|
|
3178
3274
|
}
|
|
3275
|
+
case "since": {
|
|
3276
|
+
result.tags.push({ name: "since", text: trimmedContent, version: trimmedContent });
|
|
3277
|
+
break;
|
|
3278
|
+
}
|
|
3279
|
+
case "deprecated": {
|
|
3280
|
+
const versionMatch = trimmedContent.match(/^(\d+\.\d+(?:\.\d+)?)\s*(.*)?$/);
|
|
3281
|
+
if (versionMatch) {
|
|
3282
|
+
result.tags.push({
|
|
3283
|
+
name: "deprecated",
|
|
3284
|
+
text: trimmedContent,
|
|
3285
|
+
version: versionMatch[1],
|
|
3286
|
+
reason: versionMatch[2]?.trim() || undefined
|
|
3287
|
+
});
|
|
3288
|
+
} else {
|
|
3289
|
+
result.tags.push({
|
|
3290
|
+
name: "deprecated",
|
|
3291
|
+
text: trimmedContent,
|
|
3292
|
+
reason: trimmedContent || undefined
|
|
3293
|
+
});
|
|
3294
|
+
}
|
|
3295
|
+
break;
|
|
3296
|
+
}
|
|
3297
|
+
case "type":
|
|
3298
|
+
case "typedef": {
|
|
3299
|
+
let typeAnnotation;
|
|
3300
|
+
if (trimmedContent.startsWith("{")) {
|
|
3301
|
+
const typeEnd = findMatchingBrace(trimmedContent, 0);
|
|
3302
|
+
if (typeEnd > 0) {
|
|
3303
|
+
typeAnnotation = trimmedContent.slice(1, typeEnd).trim();
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3306
|
+
result.tags.push({
|
|
3307
|
+
name: tag,
|
|
3308
|
+
text: trimmedContent,
|
|
3309
|
+
typeAnnotation
|
|
3310
|
+
});
|
|
3311
|
+
break;
|
|
3312
|
+
}
|
|
3179
3313
|
case "inheritdoc": {
|
|
3180
3314
|
result.tags.push({ name: "inheritDoc", text: trimmedContent });
|
|
3181
3315
|
break;
|
|
@@ -3262,6 +3396,9 @@ function parseJSDocText(commentText) {
|
|
|
3262
3396
|
result.returns = parsed.returns.description;
|
|
3263
3397
|
result.returnsType = parsed.returns.type;
|
|
3264
3398
|
}
|
|
3399
|
+
if (parsed.throws.length > 0) {
|
|
3400
|
+
result.throws = parsed.throws;
|
|
3401
|
+
}
|
|
3265
3402
|
return result;
|
|
3266
3403
|
}
|
|
3267
3404
|
function extractDestructuredParams(parsedDoc, paramName) {
|
|
@@ -3401,6 +3538,7 @@ function serializeClass(declaration, symbol, context) {
|
|
|
3401
3538
|
const parsedDoc = parseJSDocComment(symbol, context.checker);
|
|
3402
3539
|
const description = parsedDoc?.description ?? getJSDocComment(symbol, context.checker);
|
|
3403
3540
|
const metadata = extractPresentationMetadata(parsedDoc);
|
|
3541
|
+
const decorators = extractDecorators(declaration);
|
|
3404
3542
|
const exportEntry = {
|
|
3405
3543
|
id: symbol.getName(),
|
|
3406
3544
|
name: symbol.getName(),
|
|
@@ -3414,7 +3552,8 @@ function serializeClass(declaration, symbol, context) {
|
|
|
3414
3552
|
...heritage.extends ? { extends: heritage.extends } : {},
|
|
3415
3553
|
...heritage.implements && heritage.implements.length > 0 ? { implements: heritage.implements } : {},
|
|
3416
3554
|
tags: parsedDoc?.tags,
|
|
3417
|
-
examples: parsedDoc?.examples
|
|
3555
|
+
examples: parsedDoc?.examples,
|
|
3556
|
+
decorators
|
|
3418
3557
|
};
|
|
3419
3558
|
const typeDefinition = {
|
|
3420
3559
|
id: symbol.getName(),
|
|
@@ -3507,7 +3646,8 @@ function serializeClassMembers(declaration, checker, typeRefs, referencedTypes)
|
|
|
3507
3646
|
schema,
|
|
3508
3647
|
description: memberDoc?.description ?? (memberSymbol ? getJSDocComment(memberSymbol, checker) : undefined),
|
|
3509
3648
|
flags: Object.keys(flags).length > 0 ? flags : undefined,
|
|
3510
|
-
tags: memberDoc?.tags
|
|
3649
|
+
tags: memberDoc?.tags,
|
|
3650
|
+
decorators: extractDecorators(member)
|
|
3511
3651
|
});
|
|
3512
3652
|
continue;
|
|
3513
3653
|
}
|
|
@@ -3515,10 +3655,12 @@ function serializeClassMembers(declaration, checker, typeRefs, referencedTypes)
|
|
|
3515
3655
|
const memberName = member.name?.getText() ?? "method";
|
|
3516
3656
|
const memberSymbol = member.name ? checker.getSymbolAtLocation(member.name) : undefined;
|
|
3517
3657
|
const methodDoc = memberSymbol ? parseJSDocComment(memberSymbol, checker) : null;
|
|
3518
|
-
const
|
|
3519
|
-
const
|
|
3520
|
-
|
|
3521
|
-
|
|
3658
|
+
const methodType = memberSymbol ? checker.getTypeOfSymbolAtLocation(memberSymbol, member) : checker.getTypeAtLocation(member);
|
|
3659
|
+
const callSignatures = methodType.getCallSignatures();
|
|
3660
|
+
const signatures = callSignatures.length > 0 ? callSignatures.map((sig, index) => ({
|
|
3661
|
+
...serializeSignature(sig, checker, typeRefs, referencedTypes, methodDoc, memberSymbol),
|
|
3662
|
+
overloadIndex: callSignatures.length > 1 ? index : undefined
|
|
3663
|
+
})) : undefined;
|
|
3522
3664
|
members.push({
|
|
3523
3665
|
id: memberName,
|
|
3524
3666
|
name: memberName,
|
|
@@ -3527,15 +3669,20 @@ function serializeClassMembers(declaration, checker, typeRefs, referencedTypes)
|
|
|
3527
3669
|
signatures,
|
|
3528
3670
|
description: methodDoc?.description ?? (memberSymbol ? getJSDocComment(memberSymbol, checker) : undefined),
|
|
3529
3671
|
flags: getMethodFlags(member),
|
|
3530
|
-
tags: methodDoc?.tags
|
|
3672
|
+
tags: methodDoc?.tags,
|
|
3673
|
+
decorators: extractDecorators(member)
|
|
3531
3674
|
});
|
|
3532
3675
|
continue;
|
|
3533
3676
|
}
|
|
3534
3677
|
if (ts2.isConstructorDeclaration(member)) {
|
|
3535
3678
|
const ctorSymbol = checker.getSymbolAtLocation(member);
|
|
3536
3679
|
const ctorDoc = ctorSymbol ? parseJSDocComment(ctorSymbol, checker) : null;
|
|
3537
|
-
const
|
|
3538
|
-
const
|
|
3680
|
+
const classType = checker.getTypeAtLocation(declaration);
|
|
3681
|
+
const constructSignatures = classType.getConstructSignatures();
|
|
3682
|
+
const signatures = constructSignatures.length > 0 ? constructSignatures.map((sig, index) => ({
|
|
3683
|
+
...serializeSignature(sig, checker, typeRefs, referencedTypes, ctorDoc, ctorSymbol),
|
|
3684
|
+
overloadIndex: constructSignatures.length > 1 ? index : undefined
|
|
3685
|
+
})) : undefined;
|
|
3539
3686
|
members.push({
|
|
3540
3687
|
id: "constructor",
|
|
3541
3688
|
name: "constructor",
|
|
@@ -3543,7 +3690,8 @@ function serializeClassMembers(declaration, checker, typeRefs, referencedTypes)
|
|
|
3543
3690
|
visibility: getMemberVisibility(member.modifiers),
|
|
3544
3691
|
signatures,
|
|
3545
3692
|
description: ctorDoc?.description ?? (ctorSymbol ? getJSDocComment(ctorSymbol, checker) : undefined),
|
|
3546
|
-
tags: ctorDoc?.tags
|
|
3693
|
+
tags: ctorDoc?.tags,
|
|
3694
|
+
decorators: extractDecorators(member)
|
|
3547
3695
|
});
|
|
3548
3696
|
continue;
|
|
3549
3697
|
}
|
|
@@ -3576,7 +3724,8 @@ function serializeClassMembers(declaration, checker, typeRefs, referencedTypes)
|
|
|
3576
3724
|
schema,
|
|
3577
3725
|
description: memberDoc?.description ?? (memberSymbol ? getJSDocComment(memberSymbol, checker) : undefined),
|
|
3578
3726
|
flags: Object.keys(flags).length > 0 ? flags : undefined,
|
|
3579
|
-
tags: memberDoc?.tags
|
|
3727
|
+
tags: memberDoc?.tags,
|
|
3728
|
+
decorators: extractDecorators(primaryMember)
|
|
3580
3729
|
});
|
|
3581
3730
|
}
|
|
3582
3731
|
}
|
|
@@ -3584,6 +3733,10 @@ function serializeClassMembers(declaration, checker, typeRefs, referencedTypes)
|
|
|
3584
3733
|
}
|
|
3585
3734
|
function serializeSignature(signature, checker, typeRefs, referencedTypes, doc, symbol) {
|
|
3586
3735
|
const typeParameters = serializeTypeParameterDeclarations(signature.declaration?.typeParameters, checker, referencedTypes);
|
|
3736
|
+
const throws = doc?.throws?.map((t) => ({
|
|
3737
|
+
type: t.type,
|
|
3738
|
+
description: t.description
|
|
3739
|
+
}));
|
|
3587
3740
|
return {
|
|
3588
3741
|
parameters: signature.getParameters().map((param) => {
|
|
3589
3742
|
const paramDecl = param.valueDeclaration;
|
|
@@ -3597,7 +3750,8 @@ function serializeSignature(signature, checker, typeRefs, referencedTypes, doc,
|
|
|
3597
3750
|
description: doc?.returns || ""
|
|
3598
3751
|
},
|
|
3599
3752
|
description: doc?.description || (symbol ? getJSDocComment(symbol, checker) : undefined),
|
|
3600
|
-
typeParameters
|
|
3753
|
+
typeParameters,
|
|
3754
|
+
throws: throws && throws.length > 0 ? throws : undefined
|
|
3601
3755
|
};
|
|
3602
3756
|
}
|
|
3603
3757
|
function getMemberVisibility(modifiers) {
|
|
@@ -3677,7 +3831,7 @@ function serializeCallSignatures(signatures, symbol, context, parsedDoc) {
|
|
|
3677
3831
|
const typeRefs = typeRegistry.getTypeRefs();
|
|
3678
3832
|
const referencedTypes = typeRegistry.getReferencedTypes();
|
|
3679
3833
|
const functionDoc = parsedDoc ?? (symbol ? parseJSDocComment(symbol, checker) : null);
|
|
3680
|
-
return signatures.map((signature) => {
|
|
3834
|
+
return signatures.map((signature, index) => {
|
|
3681
3835
|
const parameters = signature.getParameters().map((param) => {
|
|
3682
3836
|
const paramDecl = param.declarations?.find(ts2.isParameter);
|
|
3683
3837
|
const location = symbol?.declarations?.[0] ?? signature.declaration ?? param.declarations?.[0] ?? param.valueDeclaration;
|
|
@@ -3715,6 +3869,10 @@ function serializeCallSignatures(signatures, symbol, context, parsedDoc) {
|
|
|
3715
3869
|
...isAsserts ? { asserts: true } : {}
|
|
3716
3870
|
};
|
|
3717
3871
|
}
|
|
3872
|
+
const throws = functionDoc?.throws?.map((t) => ({
|
|
3873
|
+
type: t.type,
|
|
3874
|
+
description: t.description
|
|
3875
|
+
}));
|
|
3718
3876
|
return {
|
|
3719
3877
|
parameters,
|
|
3720
3878
|
returns: {
|
|
@@ -3724,7 +3882,9 @@ function serializeCallSignatures(signatures, symbol, context, parsedDoc) {
|
|
|
3724
3882
|
...typePredicateInfo ? { typePredicate: typePredicateInfo } : {}
|
|
3725
3883
|
},
|
|
3726
3884
|
description: functionDoc?.description || undefined,
|
|
3727
|
-
typeParameters
|
|
3885
|
+
typeParameters,
|
|
3886
|
+
overloadIndex: signatures.length > 1 ? index : undefined,
|
|
3887
|
+
throws: throws && throws.length > 0 ? throws : undefined
|
|
3728
3888
|
};
|
|
3729
3889
|
});
|
|
3730
3890
|
}
|
|
@@ -3785,26 +3945,37 @@ function serializeInterfaceMembers(declaration, checker, typeRefs, referencedTyp
|
|
|
3785
3945
|
continue;
|
|
3786
3946
|
const memberSymbol = member.name ? checker.getSymbolAtLocation(member.name) : undefined;
|
|
3787
3947
|
const methodDoc = memberSymbol ? parseJSDocComment(memberSymbol, checker) : null;
|
|
3788
|
-
const
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
const
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3948
|
+
const methodType = memberSymbol ? checker.getTypeOfSymbolAtLocation(memberSymbol, member) : checker.getTypeAtLocation(member);
|
|
3949
|
+
const callSignatures = methodType.getCallSignatures();
|
|
3950
|
+
if (callSignatures.length > 0) {
|
|
3951
|
+
const signatures = callSignatures.map((signature, index) => {
|
|
3952
|
+
const parameters = signature.getParameters().map((param) => {
|
|
3953
|
+
const paramDecl = param.declarations?.find(ts2.isParameter);
|
|
3954
|
+
const paramType = paramDecl ? checker.getTypeAtLocation(paramDecl) : checker.getTypeOfSymbolAtLocation(param, member);
|
|
3955
|
+
collectReferencedTypes(paramType, checker, referencedTypes);
|
|
3956
|
+
if (paramDecl) {
|
|
3957
|
+
const paramDoc = getParameterDocumentation(param, paramDecl, checker);
|
|
3958
|
+
return structureParameter(param, paramDecl, paramType, checker, typeRefs, null, paramDoc, referencedTypes);
|
|
3959
|
+
}
|
|
3960
|
+
return {
|
|
3961
|
+
name: param.getName(),
|
|
3962
|
+
required: !(param.flags & ts2.SymbolFlags.Optional),
|
|
3963
|
+
schema: formatTypeReference(paramType, checker, typeRefs, referencedTypes)
|
|
3964
|
+
};
|
|
3965
|
+
});
|
|
3966
|
+
const returnType = signature.getReturnType();
|
|
3967
|
+
if (returnType) {
|
|
3968
|
+
collectReferencedTypes(returnType, checker, referencedTypes);
|
|
3797
3969
|
}
|
|
3798
3970
|
return {
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3971
|
+
parameters,
|
|
3972
|
+
returns: {
|
|
3973
|
+
schema: returnType ? formatTypeReference(returnType, checker, typeRefs, referencedTypes) : { type: "void" }
|
|
3974
|
+
},
|
|
3975
|
+
description: methodDoc?.description,
|
|
3976
|
+
overloadIndex: callSignatures.length > 1 ? index : undefined
|
|
3802
3977
|
};
|
|
3803
3978
|
});
|
|
3804
|
-
const returnType = signature.getReturnType();
|
|
3805
|
-
if (returnType) {
|
|
3806
|
-
collectReferencedTypes(returnType, checker, referencedTypes);
|
|
3807
|
-
}
|
|
3808
3979
|
const flags = {};
|
|
3809
3980
|
if (member.questionToken) {
|
|
3810
3981
|
flags.optional = true;
|
|
@@ -3813,15 +3984,7 @@ function serializeInterfaceMembers(declaration, checker, typeRefs, referencedTyp
|
|
|
3813
3984
|
id: methodName,
|
|
3814
3985
|
name: methodName,
|
|
3815
3986
|
kind: "method",
|
|
3816
|
-
signatures
|
|
3817
|
-
{
|
|
3818
|
-
parameters,
|
|
3819
|
-
returns: {
|
|
3820
|
-
schema: returnType ? formatTypeReference(returnType, checker, typeRefs, referencedTypes) : { type: "void" }
|
|
3821
|
-
},
|
|
3822
|
-
description: methodDoc?.description
|
|
3823
|
-
}
|
|
3824
|
-
],
|
|
3987
|
+
signatures,
|
|
3825
3988
|
description: methodDoc?.description ?? (memberSymbol ? getJSDocComment(memberSymbol, checker) : undefined),
|
|
3826
3989
|
flags: Object.keys(flags).length > 0 ? flags : undefined,
|
|
3827
3990
|
tags: methodDoc?.tags
|
|
@@ -4013,6 +4176,8 @@ function serializeNamespace(declaration, symbol, context) {
|
|
|
4013
4176
|
const description = parsedDoc?.description ?? getJSDocComment(symbol, checker);
|
|
4014
4177
|
const metadata = extractPresentationMetadata(parsedDoc);
|
|
4015
4178
|
const members = extractNamespaceMembers(declaration, checker);
|
|
4179
|
+
const isAugmentation = ts2.isStringLiteral(declaration.name);
|
|
4180
|
+
const augmentedModule = isAugmentation ? declaration.name.text : undefined;
|
|
4016
4181
|
return {
|
|
4017
4182
|
id: symbol.getName(),
|
|
4018
4183
|
name: symbol.getName(),
|
|
@@ -4023,7 +4188,9 @@ function serializeNamespace(declaration, symbol, context) {
|
|
|
4023
4188
|
source: getSourceLocation(declaration),
|
|
4024
4189
|
members: members.length > 0 ? members : undefined,
|
|
4025
4190
|
tags: parsedDoc?.tags,
|
|
4026
|
-
examples: parsedDoc?.examples
|
|
4191
|
+
examples: parsedDoc?.examples,
|
|
4192
|
+
isAugmentation: isAugmentation || undefined,
|
|
4193
|
+
augmentedModule
|
|
4027
4194
|
};
|
|
4028
4195
|
}
|
|
4029
4196
|
function extractNamespaceMembers(declaration, checker) {
|
|
@@ -4115,6 +4282,46 @@ function extractNamespaceMembers(declaration, checker) {
|
|
|
4115
4282
|
}
|
|
4116
4283
|
|
|
4117
4284
|
// src/analysis/serializers/type-aliases.ts
|
|
4285
|
+
function analyzeTypeAliasKind(typeNode) {
|
|
4286
|
+
if (ts2.isConditionalTypeNode(typeNode)) {
|
|
4287
|
+
return {
|
|
4288
|
+
typeAliasKind: "conditional",
|
|
4289
|
+
conditionalType: {
|
|
4290
|
+
checkType: typeNode.checkType.getText(),
|
|
4291
|
+
extendsType: typeNode.extendsType.getText(),
|
|
4292
|
+
trueType: typeNode.trueType.getText(),
|
|
4293
|
+
falseType: typeNode.falseType.getText()
|
|
4294
|
+
}
|
|
4295
|
+
};
|
|
4296
|
+
}
|
|
4297
|
+
if (ts2.isMappedTypeNode(typeNode)) {
|
|
4298
|
+
const readonlyToken = typeNode.readonlyToken;
|
|
4299
|
+
const questionToken = typeNode.questionToken;
|
|
4300
|
+
return {
|
|
4301
|
+
typeAliasKind: "mapped",
|
|
4302
|
+
mappedType: {
|
|
4303
|
+
typeParameter: typeNode.typeParameter.getText(),
|
|
4304
|
+
nameType: typeNode.nameType?.getText(),
|
|
4305
|
+
valueType: typeNode.type?.getText(),
|
|
4306
|
+
readonly: readonlyToken ? readonlyToken.kind === ts2.SyntaxKind.MinusToken ? "-" : readonlyToken.kind === ts2.SyntaxKind.PlusToken ? "+" : true : undefined,
|
|
4307
|
+
optional: questionToken ? questionToken.kind === ts2.SyntaxKind.MinusToken ? "-" : questionToken.kind === ts2.SyntaxKind.PlusToken ? "+" : true : undefined
|
|
4308
|
+
}
|
|
4309
|
+
};
|
|
4310
|
+
}
|
|
4311
|
+
if (ts2.isTemplateLiteralTypeNode(typeNode)) {
|
|
4312
|
+
return { typeAliasKind: "template-literal" };
|
|
4313
|
+
}
|
|
4314
|
+
if (containsInferType(typeNode)) {
|
|
4315
|
+
return { typeAliasKind: "infer" };
|
|
4316
|
+
}
|
|
4317
|
+
return { typeAliasKind: "alias" };
|
|
4318
|
+
}
|
|
4319
|
+
function containsInferType(node) {
|
|
4320
|
+
if (ts2.isInferTypeNode(node)) {
|
|
4321
|
+
return true;
|
|
4322
|
+
}
|
|
4323
|
+
return ts2.forEachChild(node, containsInferType) ?? false;
|
|
4324
|
+
}
|
|
4118
4325
|
function serializeTypeAlias(declaration, symbol, context) {
|
|
4119
4326
|
const { checker, typeRegistry } = context;
|
|
4120
4327
|
const typeRefs = typeRegistry.getTypeRefs();
|
|
@@ -4123,6 +4330,7 @@ function serializeTypeAlias(declaration, symbol, context) {
|
|
|
4123
4330
|
const description = parsedDoc?.description ?? getJSDocComment(symbol, checker);
|
|
4124
4331
|
const metadata = extractPresentationMetadata(parsedDoc);
|
|
4125
4332
|
const typeParameters = serializeTypeParameterDeclarations(declaration.typeParameters, checker, referencedTypes);
|
|
4333
|
+
const typeAnalysis = analyzeTypeAliasKind(declaration.type);
|
|
4126
4334
|
const exportEntry = {
|
|
4127
4335
|
id: symbol.getName(),
|
|
4128
4336
|
name: symbol.getName(),
|
|
@@ -4134,7 +4342,10 @@ function serializeTypeAlias(declaration, symbol, context) {
|
|
|
4134
4342
|
source: getSourceLocation(declaration),
|
|
4135
4343
|
typeParameters,
|
|
4136
4344
|
tags: parsedDoc?.tags,
|
|
4137
|
-
examples: parsedDoc?.examples
|
|
4345
|
+
examples: parsedDoc?.examples,
|
|
4346
|
+
typeAliasKind: typeAnalysis.typeAliasKind !== "alias" ? typeAnalysis.typeAliasKind : undefined,
|
|
4347
|
+
conditionalType: typeAnalysis.conditionalType,
|
|
4348
|
+
mappedType: typeAnalysis.mappedType
|
|
4138
4349
|
};
|
|
4139
4350
|
const aliasType = checker.getTypeAtLocation(declaration.type);
|
|
4140
4351
|
const aliasName = symbol.getName();
|
|
@@ -4153,7 +4364,10 @@ function serializeTypeAlias(declaration, symbol, context) {
|
|
|
4153
4364
|
kind: "type",
|
|
4154
4365
|
description,
|
|
4155
4366
|
source: getSourceLocation(declaration),
|
|
4156
|
-
tags: parsedDoc?.tags
|
|
4367
|
+
tags: parsedDoc?.tags,
|
|
4368
|
+
typeAliasKind: typeAnalysis.typeAliasKind !== "alias" ? typeAnalysis.typeAliasKind : undefined,
|
|
4369
|
+
conditionalType: typeAnalysis.conditionalType,
|
|
4370
|
+
mappedType: typeAnalysis.mappedType
|
|
4157
4371
|
};
|
|
4158
4372
|
if (typeof aliasSchema === "string") {
|
|
4159
4373
|
typeDefinition.type = aliasSchema;
|
|
@@ -4270,7 +4484,7 @@ function buildOpenPkgSpec(context, resolveExternalTypes) {
|
|
|
4270
4484
|
const packageJson = fs2.existsSync(packageJsonPath) ? JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8")) : {};
|
|
4271
4485
|
const spec = {
|
|
4272
4486
|
$schema: SCHEMA_URL,
|
|
4273
|
-
openpkg:
|
|
4487
|
+
openpkg: SCHEMA_VERSION,
|
|
4274
4488
|
meta: {
|
|
4275
4489
|
name: packageJson.name || "unknown",
|
|
4276
4490
|
version: packageJson.version || "1.0.0",
|
|
@@ -4666,6 +4880,48 @@ async function extractPackageSpec(entryFile, packageDir, content, options) {
|
|
|
4666
4880
|
});
|
|
4667
4881
|
return result.spec;
|
|
4668
4882
|
}
|
|
4883
|
+
// src/filtering/merge.ts
|
|
4884
|
+
function unique(values) {
|
|
4885
|
+
return Array.from(new Set(values));
|
|
4886
|
+
}
|
|
4887
|
+
function parseListFlag(value) {
|
|
4888
|
+
if (!value) {
|
|
4889
|
+
return;
|
|
4890
|
+
}
|
|
4891
|
+
const rawItems = Array.isArray(value) ? value : [value];
|
|
4892
|
+
const normalized = rawItems.flatMap((item) => String(item).split(",")).map((item) => item.trim()).filter(Boolean);
|
|
4893
|
+
return normalized.length > 0 ? unique(normalized) : undefined;
|
|
4894
|
+
}
|
|
4895
|
+
function mergeFilters(config, overrides) {
|
|
4896
|
+
const configInclude = config?.include;
|
|
4897
|
+
const configExclude = config?.exclude;
|
|
4898
|
+
const overrideInclude = overrides.include;
|
|
4899
|
+
const overrideExclude = overrides.exclude;
|
|
4900
|
+
let include = configInclude;
|
|
4901
|
+
let exclude = configExclude;
|
|
4902
|
+
let source = include || exclude ? "config" : undefined;
|
|
4903
|
+
const fromConfig = !!(configInclude || configExclude);
|
|
4904
|
+
let fromOverride = false;
|
|
4905
|
+
if (overrideInclude) {
|
|
4906
|
+
include = include ? include.filter((item) => overrideInclude.includes(item)) : overrideInclude;
|
|
4907
|
+
source = source ? "combined" : "override";
|
|
4908
|
+
fromOverride = true;
|
|
4909
|
+
}
|
|
4910
|
+
if (overrideExclude) {
|
|
4911
|
+
exclude = exclude ? unique([...exclude, ...overrideExclude]) : overrideExclude;
|
|
4912
|
+
source = source ? "combined" : "override";
|
|
4913
|
+
fromOverride = true;
|
|
4914
|
+
}
|
|
4915
|
+
include = include ? unique(include) : undefined;
|
|
4916
|
+
exclude = exclude ? unique(exclude) : undefined;
|
|
4917
|
+
return {
|
|
4918
|
+
include,
|
|
4919
|
+
exclude,
|
|
4920
|
+
source,
|
|
4921
|
+
fromConfig,
|
|
4922
|
+
fromOverride
|
|
4923
|
+
};
|
|
4924
|
+
}
|
|
4669
4925
|
// src/fix/deterministic-fixes.ts
|
|
4670
4926
|
var FIXABLE_DRIFT_TYPES = new Set([
|
|
4671
4927
|
"param-mismatch",
|
|
@@ -7056,6 +7312,390 @@ async function runExamplesWithPackage(examples, options) {
|
|
|
7056
7312
|
} catch {}
|
|
7057
7313
|
}
|
|
7058
7314
|
}
|
|
7315
|
+
// src/scan/summary.ts
|
|
7316
|
+
function extractSpecSummary(spec) {
|
|
7317
|
+
const exports = spec.exports ?? [];
|
|
7318
|
+
const undocumented = [];
|
|
7319
|
+
const drift = [];
|
|
7320
|
+
for (const exp of exports) {
|
|
7321
|
+
const docs = exp.docs;
|
|
7322
|
+
if (!docs)
|
|
7323
|
+
continue;
|
|
7324
|
+
const hasMissing = (docs.missing?.length ?? 0) > 0;
|
|
7325
|
+
const isPartial = (docs.coverageScore ?? 0) < 100;
|
|
7326
|
+
if (hasMissing || isPartial) {
|
|
7327
|
+
undocumented.push(exp.name);
|
|
7328
|
+
}
|
|
7329
|
+
for (const d of docs.drift ?? []) {
|
|
7330
|
+
drift.push({
|
|
7331
|
+
export: exp.name,
|
|
7332
|
+
type: d.type,
|
|
7333
|
+
issue: d.issue,
|
|
7334
|
+
suggestion: d.suggestion
|
|
7335
|
+
});
|
|
7336
|
+
}
|
|
7337
|
+
}
|
|
7338
|
+
return {
|
|
7339
|
+
coverage: spec.docs?.coverageScore ?? 0,
|
|
7340
|
+
exportCount: exports.length,
|
|
7341
|
+
typeCount: spec.types?.length ?? 0,
|
|
7342
|
+
driftCount: drift.length,
|
|
7343
|
+
undocumented,
|
|
7344
|
+
drift
|
|
7345
|
+
};
|
|
7346
|
+
}
|
|
7347
|
+
// src/install/index.ts
|
|
7348
|
+
var DEFAULT_FALLBACK_ORDER = ["bun", "npm"];
|
|
7349
|
+
async function installDependencies(fs8, cwd, runCommand2, options = {}) {
|
|
7350
|
+
const {
|
|
7351
|
+
timeout = 180000,
|
|
7352
|
+
fallbackOrder = DEFAULT_FALLBACK_ORDER,
|
|
7353
|
+
onProgress
|
|
7354
|
+
} = options;
|
|
7355
|
+
const errors = [];
|
|
7356
|
+
onProgress?.({ stage: "installing", message: "Detecting package manager..." });
|
|
7357
|
+
const pmInfo = await detectPackageManager(fs8);
|
|
7358
|
+
if (pmInfo.lockfile) {
|
|
7359
|
+
onProgress?.({
|
|
7360
|
+
stage: "installing",
|
|
7361
|
+
message: `Installing with ${pmInfo.name}...`,
|
|
7362
|
+
progress: 25
|
|
7363
|
+
});
|
|
7364
|
+
const installCmd = getInstallCommand(pmInfo);
|
|
7365
|
+
const result = await runCommand2(installCmd[0], installCmd.slice(1), { cwd, timeout });
|
|
7366
|
+
if (result.exitCode === 0) {
|
|
7367
|
+
onProgress?.({ stage: "installing", message: "Dependencies installed", progress: 100 });
|
|
7368
|
+
return {
|
|
7369
|
+
success: true,
|
|
7370
|
+
packageManager: pmInfo.name
|
|
7371
|
+
};
|
|
7372
|
+
}
|
|
7373
|
+
const errorMsg = result.stderr.slice(0, 150) || `Exit code ${result.exitCode}`;
|
|
7374
|
+
errors.push(`[${installCmd.join(" ")}] ${errorMsg}`);
|
|
7375
|
+
if (result.stderr.includes("workspace:") || result.stderr.includes("EUNSUPPORTEDPROTOCOL")) {
|
|
7376
|
+
onProgress?.({
|
|
7377
|
+
stage: "installing",
|
|
7378
|
+
message: "Workspace protocol detected, trying bun...",
|
|
7379
|
+
progress: 35
|
|
7380
|
+
});
|
|
7381
|
+
}
|
|
7382
|
+
}
|
|
7383
|
+
for (const fallbackPm of fallbackOrder) {
|
|
7384
|
+
if (pmInfo.lockfile && fallbackPm === pmInfo.name)
|
|
7385
|
+
continue;
|
|
7386
|
+
onProgress?.({
|
|
7387
|
+
stage: "installing",
|
|
7388
|
+
message: `Trying ${fallbackPm} fallback...`,
|
|
7389
|
+
progress: 50
|
|
7390
|
+
});
|
|
7391
|
+
const fallbackCmd = getFallbackInstallCommand(fallbackPm);
|
|
7392
|
+
const result = await runCommand2(fallbackCmd[0], fallbackCmd.slice(1), { cwd, timeout });
|
|
7393
|
+
if (result.exitCode === 0) {
|
|
7394
|
+
onProgress?.({ stage: "installing", message: "Dependencies installed", progress: 100 });
|
|
7395
|
+
return {
|
|
7396
|
+
success: true,
|
|
7397
|
+
packageManager: fallbackPm,
|
|
7398
|
+
fallbackUsed: fallbackPm
|
|
7399
|
+
};
|
|
7400
|
+
}
|
|
7401
|
+
const errorMsg = result.stderr.slice(0, 150) || `Exit code ${result.exitCode}`;
|
|
7402
|
+
errors.push(`[${fallbackCmd.join(" ")}] ${errorMsg}`);
|
|
7403
|
+
}
|
|
7404
|
+
onProgress?.({
|
|
7405
|
+
stage: "installing",
|
|
7406
|
+
message: "Could not install dependencies",
|
|
7407
|
+
progress: 100
|
|
7408
|
+
});
|
|
7409
|
+
return {
|
|
7410
|
+
success: false,
|
|
7411
|
+
packageManager: pmInfo.name,
|
|
7412
|
+
error: "All installation attempts failed",
|
|
7413
|
+
errors
|
|
7414
|
+
};
|
|
7415
|
+
}
|
|
7416
|
+
function getFallbackInstallCommand(pm) {
|
|
7417
|
+
switch (pm) {
|
|
7418
|
+
case "npm":
|
|
7419
|
+
return ["npm", "install", "--legacy-peer-deps", "--ignore-scripts"];
|
|
7420
|
+
case "bun":
|
|
7421
|
+
return ["bun", "install"];
|
|
7422
|
+
case "yarn":
|
|
7423
|
+
return ["yarn", "install"];
|
|
7424
|
+
case "pnpm":
|
|
7425
|
+
return ["pnpm", "install"];
|
|
7426
|
+
default:
|
|
7427
|
+
return ["npm", "install"];
|
|
7428
|
+
}
|
|
7429
|
+
}
|
|
7430
|
+
function createNodeCommandRunner() {
|
|
7431
|
+
return async (cmd, args, options) => {
|
|
7432
|
+
const { execSync } = await import("node:child_process");
|
|
7433
|
+
const fullCmd = [cmd, ...args].join(" ");
|
|
7434
|
+
try {
|
|
7435
|
+
const stdout = execSync(fullCmd, {
|
|
7436
|
+
cwd: options.cwd,
|
|
7437
|
+
stdio: "pipe",
|
|
7438
|
+
timeout: options.timeout ?? 180000
|
|
7439
|
+
});
|
|
7440
|
+
return {
|
|
7441
|
+
exitCode: 0,
|
|
7442
|
+
stdout: stdout?.toString() ?? "",
|
|
7443
|
+
stderr: ""
|
|
7444
|
+
};
|
|
7445
|
+
} catch (error) {
|
|
7446
|
+
const err = error;
|
|
7447
|
+
return {
|
|
7448
|
+
exitCode: err.status ?? 1,
|
|
7449
|
+
stdout: err.stdout?.toString() ?? "",
|
|
7450
|
+
stderr: err.stderr?.toString() ?? err.message ?? "Unknown error"
|
|
7451
|
+
};
|
|
7452
|
+
}
|
|
7453
|
+
};
|
|
7454
|
+
}
|
|
7455
|
+
|
|
7456
|
+
// src/github/index.ts
|
|
7457
|
+
function parseGitHubUrl(input, defaultRef = "main") {
|
|
7458
|
+
const trimmed = input.trim();
|
|
7459
|
+
if (!trimmed) {
|
|
7460
|
+
throw new Error("GitHub URL cannot be empty");
|
|
7461
|
+
}
|
|
7462
|
+
let normalized = trimmed.replace(/^https?:\/\//, "").replace(/^git@github\.com:/, "").replace(/\.git$/, "");
|
|
7463
|
+
normalized = normalized.replace(/^github\.com\//, "");
|
|
7464
|
+
const parts = normalized.split("/").filter(Boolean);
|
|
7465
|
+
if (parts.length < 2) {
|
|
7466
|
+
throw new Error(`Invalid GitHub URL format: "${input}". Expected owner/repo or https://github.com/owner/repo`);
|
|
7467
|
+
}
|
|
7468
|
+
const owner = parts[0];
|
|
7469
|
+
const repo = parts[1];
|
|
7470
|
+
let ref = defaultRef;
|
|
7471
|
+
if (parts.length >= 4 && (parts[2] === "tree" || parts[2] === "blob")) {
|
|
7472
|
+
ref = parts.slice(3).join("/");
|
|
7473
|
+
}
|
|
7474
|
+
if (!owner || !repo) {
|
|
7475
|
+
throw new Error(`Could not parse owner/repo from: "${input}"`);
|
|
7476
|
+
}
|
|
7477
|
+
return { owner, repo, ref };
|
|
7478
|
+
}
|
|
7479
|
+
function buildCloneUrl(parsed) {
|
|
7480
|
+
return `https://github.com/${parsed.owner}/${parsed.repo}.git`;
|
|
7481
|
+
}
|
|
7482
|
+
function buildDisplayUrl(parsed) {
|
|
7483
|
+
return `github.com/${parsed.owner}/${parsed.repo}`;
|
|
7484
|
+
}
|
|
7485
|
+
function buildRawUrl(parsed, filePath) {
|
|
7486
|
+
return `https://raw.githubusercontent.com/${parsed.owner}/${parsed.repo}/${parsed.ref}/${filePath}`;
|
|
7487
|
+
}
|
|
7488
|
+
async function fetchSpecFromGitHub(parsed) {
|
|
7489
|
+
const urls = [
|
|
7490
|
+
buildRawUrl(parsed, "openpkg.json"),
|
|
7491
|
+
`https://raw.githubusercontent.com/${parsed.owner}/${parsed.repo}/master/openpkg.json`
|
|
7492
|
+
];
|
|
7493
|
+
for (const url of urls) {
|
|
7494
|
+
try {
|
|
7495
|
+
const response = await fetch(url);
|
|
7496
|
+
if (response.ok) {
|
|
7497
|
+
return await response.json();
|
|
7498
|
+
}
|
|
7499
|
+
} catch {}
|
|
7500
|
+
}
|
|
7501
|
+
return null;
|
|
7502
|
+
}
|
|
7503
|
+
async function fetchSpec(owner, repo, branch = "main") {
|
|
7504
|
+
return fetchSpecFromGitHub({ owner, repo, ref: branch });
|
|
7505
|
+
}
|
|
7506
|
+
|
|
7507
|
+
// src/scan/orchestrator.ts
|
|
7508
|
+
class ScanOrchestrator {
|
|
7509
|
+
fs;
|
|
7510
|
+
options;
|
|
7511
|
+
constructor(fs8, options = {}) {
|
|
7512
|
+
this.fs = fs8;
|
|
7513
|
+
this.options = options;
|
|
7514
|
+
}
|
|
7515
|
+
emit(event) {
|
|
7516
|
+
this.options.onProgress?.(event);
|
|
7517
|
+
}
|
|
7518
|
+
async detectPackage(packageName) {
|
|
7519
|
+
this.emit({ stage: "detecting", message: "Detecting project structure...", progress: 10 });
|
|
7520
|
+
const mono = await detectMonorepo(this.fs);
|
|
7521
|
+
if (mono.isMonorepo) {
|
|
7522
|
+
if (!packageName) {
|
|
7523
|
+
const publicPackages = mono.packages.filter((p) => !p.private);
|
|
7524
|
+
throw new MonorepoRequiresPackageError(publicPackages.map((p) => p.name));
|
|
7525
|
+
}
|
|
7526
|
+
const pkg = findPackageByName(mono.packages, packageName);
|
|
7527
|
+
if (!pkg) {
|
|
7528
|
+
throw new Error(`Package "${packageName}" not found. Available: ${mono.packages.map((p) => p.name).join(", ")}`);
|
|
7529
|
+
}
|
|
7530
|
+
this.emit({ stage: "detecting", message: `Found package: ${pkg.name}`, progress: 15 });
|
|
7531
|
+
return { targetPath: pkg.path, resolvedPackage: pkg.name };
|
|
7532
|
+
}
|
|
7533
|
+
return { targetPath: "." };
|
|
7534
|
+
}
|
|
7535
|
+
async detectEntry(targetPath) {
|
|
7536
|
+
this.emit({ stage: "detecting", message: "Detecting entry point...", progress: 18 });
|
|
7537
|
+
const entry = await detectEntryPoint(this.fs, targetPath);
|
|
7538
|
+
const entryFile = targetPath === "." ? entry.path : `${targetPath}/${entry.path}`;
|
|
7539
|
+
this.emit({
|
|
7540
|
+
stage: "detecting",
|
|
7541
|
+
message: `Entry point: ${entry.path} (from ${entry.source})`,
|
|
7542
|
+
progress: 20
|
|
7543
|
+
});
|
|
7544
|
+
return entryFile;
|
|
7545
|
+
}
|
|
7546
|
+
async install(workDir) {
|
|
7547
|
+
if (!this.options.commandRunner) {
|
|
7548
|
+
return {
|
|
7549
|
+
success: false,
|
|
7550
|
+
packageManager: "npm",
|
|
7551
|
+
error: "No command runner provided"
|
|
7552
|
+
};
|
|
7553
|
+
}
|
|
7554
|
+
this.emit({ stage: "installing", message: "Installing dependencies...", progress: 25 });
|
|
7555
|
+
const result = await installDependencies(this.fs, workDir, this.options.commandRunner, {
|
|
7556
|
+
onProgress: this.options.onProgress
|
|
7557
|
+
});
|
|
7558
|
+
if (result.success) {
|
|
7559
|
+
this.emit({ stage: "installing", message: "Dependencies installed", progress: 45 });
|
|
7560
|
+
} else {
|
|
7561
|
+
this.emit({
|
|
7562
|
+
stage: "installing",
|
|
7563
|
+
message: "Install failed (continuing with limited analysis)",
|
|
7564
|
+
progress: 45
|
|
7565
|
+
});
|
|
7566
|
+
}
|
|
7567
|
+
return result;
|
|
7568
|
+
}
|
|
7569
|
+
async build(workDir, targetPath) {
|
|
7570
|
+
if (!this.options.commandRunner)
|
|
7571
|
+
return;
|
|
7572
|
+
const buildInfo = await detectBuildInfo(this.fs, targetPath);
|
|
7573
|
+
const buildScript = getPrimaryBuildScript(buildInfo);
|
|
7574
|
+
if (!buildScript)
|
|
7575
|
+
return;
|
|
7576
|
+
this.emit({ stage: "building", message: "Running build...", progress: 50 });
|
|
7577
|
+
const result = await this.options.commandRunner("npm", ["run", buildScript], {
|
|
7578
|
+
cwd: workDir,
|
|
7579
|
+
timeout: 300000
|
|
7580
|
+
});
|
|
7581
|
+
const buildMessage = result.exitCode === 0 ? "Build complete" : "Build failed (continuing)";
|
|
7582
|
+
this.emit({ stage: "building", message: buildMessage, progress: 60 });
|
|
7583
|
+
}
|
|
7584
|
+
async analyze(entryFile) {
|
|
7585
|
+
this.emit({ stage: "analyzing", message: "Analyzing documentation...", progress: 65 });
|
|
7586
|
+
const doccov = new DocCov({ resolveExternalTypes: !this.options.skipResolve });
|
|
7587
|
+
const result = await doccov.analyzeFileWithDiagnostics(entryFile);
|
|
7588
|
+
this.emit({ stage: "analyzing", message: "Analysis complete", progress: 90 });
|
|
7589
|
+
return result.spec;
|
|
7590
|
+
}
|
|
7591
|
+
async scan(options) {
|
|
7592
|
+
const parsed = parseGitHubUrl(options.url, options.ref ?? "main");
|
|
7593
|
+
this.emit({
|
|
7594
|
+
stage: "detecting",
|
|
7595
|
+
message: `Scanning ${parsed.owner}/${parsed.repo}...`,
|
|
7596
|
+
progress: 5
|
|
7597
|
+
});
|
|
7598
|
+
const { targetPath, resolvedPackage } = await this.detectPackage(options.package);
|
|
7599
|
+
const entryFile = await this.detectEntry(targetPath);
|
|
7600
|
+
if (!options.skipInstall && this.options.commandRunner) {
|
|
7601
|
+
await this.install(".");
|
|
7602
|
+
await this.build(".", targetPath);
|
|
7603
|
+
}
|
|
7604
|
+
const spec = await this.analyze(entryFile);
|
|
7605
|
+
this.emit({ stage: "complete", message: "Extracting results...", progress: 95 });
|
|
7606
|
+
const summary = extractSpecSummary(spec);
|
|
7607
|
+
this.emit({ stage: "complete", message: "Scan complete", progress: 100 });
|
|
7608
|
+
return {
|
|
7609
|
+
owner: parsed.owner,
|
|
7610
|
+
repo: parsed.repo,
|
|
7611
|
+
ref: parsed.ref,
|
|
7612
|
+
packageName: resolvedPackage ?? options.package,
|
|
7613
|
+
coverage: summary.coverage,
|
|
7614
|
+
exportCount: summary.exportCount,
|
|
7615
|
+
typeCount: summary.typeCount,
|
|
7616
|
+
driftCount: summary.driftCount,
|
|
7617
|
+
undocumented: summary.undocumented,
|
|
7618
|
+
drift: summary.drift
|
|
7619
|
+
};
|
|
7620
|
+
}
|
|
7621
|
+
}
|
|
7622
|
+
|
|
7623
|
+
class MonorepoRequiresPackageError extends Error {
|
|
7624
|
+
availablePackages;
|
|
7625
|
+
constructor(availablePackages) {
|
|
7626
|
+
super(`Monorepo detected with ${availablePackages.length} packages. ` + `Specify target with --package. Available: ${availablePackages.join(", ")}`);
|
|
7627
|
+
this.name = "MonorepoRequiresPackageError";
|
|
7628
|
+
this.availablePackages = availablePackages;
|
|
7629
|
+
}
|
|
7630
|
+
}
|
|
7631
|
+
// src/resolve/index.ts
|
|
7632
|
+
import * as path9 from "node:path";
|
|
7633
|
+
async function resolveTarget(fs8, options) {
|
|
7634
|
+
let targetDir = options.cwd;
|
|
7635
|
+
let packageInfo;
|
|
7636
|
+
if (options.package) {
|
|
7637
|
+
const mono = await detectMonorepo(fs8);
|
|
7638
|
+
if (!mono.isMonorepo) {
|
|
7639
|
+
throw new Error("Not a monorepo. Remove --package flag for single-package repos.");
|
|
7640
|
+
}
|
|
7641
|
+
const pkg = findPackageByName(mono.packages, options.package);
|
|
7642
|
+
if (!pkg) {
|
|
7643
|
+
const available = mono.packages.map((p) => p.name).join(", ");
|
|
7644
|
+
throw new Error(`Package "${options.package}" not found. Available: ${available}`);
|
|
7645
|
+
}
|
|
7646
|
+
targetDir = path9.join(options.cwd, pkg.path);
|
|
7647
|
+
packageInfo = pkg;
|
|
7648
|
+
}
|
|
7649
|
+
let entryFile;
|
|
7650
|
+
let entryPointInfo;
|
|
7651
|
+
if (!options.entry) {
|
|
7652
|
+
entryPointInfo = await detectEntryPoint(fs8, getRelativePath(options.cwd, targetDir));
|
|
7653
|
+
entryFile = path9.join(targetDir, entryPointInfo.path);
|
|
7654
|
+
} else {
|
|
7655
|
+
const explicitPath = path9.resolve(targetDir, options.entry);
|
|
7656
|
+
const isDirectory = await isDir(fs8, getRelativePath(options.cwd, explicitPath));
|
|
7657
|
+
if (isDirectory) {
|
|
7658
|
+
targetDir = explicitPath;
|
|
7659
|
+
entryPointInfo = await detectEntryPoint(fs8, getRelativePath(options.cwd, explicitPath));
|
|
7660
|
+
entryFile = path9.join(explicitPath, entryPointInfo.path);
|
|
7661
|
+
} else {
|
|
7662
|
+
entryFile = explicitPath;
|
|
7663
|
+
entryPointInfo = {
|
|
7664
|
+
path: options.entry,
|
|
7665
|
+
source: "explicit",
|
|
7666
|
+
isDeclarationOnly: options.entry.endsWith(".d.ts")
|
|
7667
|
+
};
|
|
7668
|
+
}
|
|
7669
|
+
}
|
|
7670
|
+
return {
|
|
7671
|
+
targetDir,
|
|
7672
|
+
entryFile,
|
|
7673
|
+
packageInfo,
|
|
7674
|
+
entryPointInfo
|
|
7675
|
+
};
|
|
7676
|
+
}
|
|
7677
|
+
function getRelativePath(base, target) {
|
|
7678
|
+
if (base === target)
|
|
7679
|
+
return ".";
|
|
7680
|
+
const rel = path9.relative(base, target);
|
|
7681
|
+
return rel || ".";
|
|
7682
|
+
}
|
|
7683
|
+
async function isDir(fs8, relativePath) {
|
|
7684
|
+
const hasPackageJson = await fs8.exists(path9.join(relativePath, "package.json"));
|
|
7685
|
+
if (hasPackageJson)
|
|
7686
|
+
return true;
|
|
7687
|
+
const commonEntryFiles = ["index.ts", "index.tsx", "src/index.ts", "main.ts"];
|
|
7688
|
+
for (const entry of commonEntryFiles) {
|
|
7689
|
+
if (await fs8.exists(path9.join(relativePath, entry))) {
|
|
7690
|
+
return true;
|
|
7691
|
+
}
|
|
7692
|
+
}
|
|
7693
|
+
return !path9.extname(relativePath);
|
|
7694
|
+
}
|
|
7695
|
+
// src/config/types.ts
|
|
7696
|
+
function defineConfig(config) {
|
|
7697
|
+
return config;
|
|
7698
|
+
}
|
|
7059
7699
|
export {
|
|
7060
7700
|
typecheckExamples,
|
|
7061
7701
|
typecheckExample,
|
|
@@ -7064,20 +7704,25 @@ export {
|
|
|
7064
7704
|
runExamplesWithPackage,
|
|
7065
7705
|
runExamples,
|
|
7066
7706
|
runExample,
|
|
7707
|
+
resolveTarget,
|
|
7067
7708
|
requireExample,
|
|
7068
7709
|
requireDescription,
|
|
7069
7710
|
readPackageJson,
|
|
7070
7711
|
parseMarkdownFiles,
|
|
7071
7712
|
parseMarkdownFile,
|
|
7713
|
+
parseListFlag,
|
|
7072
7714
|
parseJSDocToPatch,
|
|
7715
|
+
parseGitHubUrl,
|
|
7073
7716
|
parseAssertions,
|
|
7074
7717
|
noEmptyReturns,
|
|
7075
7718
|
mergeFixes,
|
|
7719
|
+
mergeFilters,
|
|
7076
7720
|
mergeConfig,
|
|
7077
7721
|
lintExports,
|
|
7078
7722
|
lintExport,
|
|
7079
7723
|
isFixableDrift,
|
|
7080
7724
|
isExecutableLang,
|
|
7725
|
+
installDependencies,
|
|
7081
7726
|
hasNonAssertionComments,
|
|
7082
7727
|
hasDocsImpact,
|
|
7083
7728
|
hasDocsForExport,
|
|
@@ -7097,6 +7742,9 @@ export {
|
|
|
7097
7742
|
findJSDocLocation,
|
|
7098
7743
|
findExportReferences,
|
|
7099
7744
|
findDeprecatedReferences,
|
|
7745
|
+
fetchSpecFromGitHub,
|
|
7746
|
+
fetchSpec,
|
|
7747
|
+
extractSpecSummary,
|
|
7100
7748
|
extractPackageSpec,
|
|
7101
7749
|
extractImports,
|
|
7102
7750
|
extractFunctionCalls,
|
|
@@ -7107,9 +7755,14 @@ export {
|
|
|
7107
7755
|
detectExampleAssertionFailures,
|
|
7108
7756
|
detectEntryPoint,
|
|
7109
7757
|
detectBuildInfo,
|
|
7758
|
+
defineConfig,
|
|
7110
7759
|
createSourceFile,
|
|
7760
|
+
createNodeCommandRunner,
|
|
7111
7761
|
consistentParamStyle,
|
|
7112
7762
|
categorizeDrifts,
|
|
7763
|
+
buildRawUrl,
|
|
7764
|
+
buildDisplayUrl,
|
|
7765
|
+
buildCloneUrl,
|
|
7113
7766
|
blockReferencesExport,
|
|
7114
7767
|
applyPatchToJSDoc,
|
|
7115
7768
|
applyEdits,
|
|
@@ -7118,8 +7771,10 @@ export {
|
|
|
7118
7771
|
analyzeDocsImpact,
|
|
7119
7772
|
analyze,
|
|
7120
7773
|
allRules,
|
|
7774
|
+
ScanOrchestrator,
|
|
7121
7775
|
SandboxFileSystem,
|
|
7122
7776
|
OpenPkg,
|
|
7123
7777
|
NodeFileSystem,
|
|
7778
|
+
MonorepoRequiresPackageError,
|
|
7124
7779
|
DocCov
|
|
7125
7780
|
};
|