@doccov/sdk 0.12.0 → 0.15.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 +240 -212
- package/dist/index.js +335 -192
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3501,7 +3501,6 @@ function normalizeDocCovOptions(options = {}) {
|
|
|
3501
3501
|
cwd: options.cwd ?? process.cwd()
|
|
3502
3502
|
};
|
|
3503
3503
|
}
|
|
3504
|
-
var normalizeOpenPkgOptions = normalizeDocCovOptions;
|
|
3505
3504
|
|
|
3506
3505
|
// src/analysis/program.ts
|
|
3507
3506
|
import * as path7 from "node:path";
|
|
@@ -3559,7 +3558,7 @@ function createAnalysisContext({
|
|
|
3559
3558
|
options
|
|
3560
3559
|
}) {
|
|
3561
3560
|
const baseDir = packageDir ?? path8.dirname(entryFile);
|
|
3562
|
-
const normalizedOptions =
|
|
3561
|
+
const normalizedOptions = normalizeDocCovOptions(options);
|
|
3563
3562
|
const programResult = createProgram({ entryFile, baseDir, content });
|
|
3564
3563
|
if (!programResult.sourceFile) {
|
|
3565
3564
|
throw new Error(`Could not load ${entryFile}`);
|
|
@@ -3611,39 +3610,7 @@ function extractParameterDecorators(param) {
|
|
|
3611
3610
|
return extractDecorators(param);
|
|
3612
3611
|
}
|
|
3613
3612
|
|
|
3614
|
-
// src/utils/
|
|
3615
|
-
var MAX_TYPE_DEPTH = DEFAULT_MAX_TYPE_DEPTH;
|
|
3616
|
-
function safeTypeToString(typeChecker, type) {
|
|
3617
|
-
try {
|
|
3618
|
-
return typeChecker.typeToString(type);
|
|
3619
|
-
} catch {
|
|
3620
|
-
return "unknown";
|
|
3621
|
-
}
|
|
3622
|
-
}
|
|
3623
|
-
var BUILTIN_TYPE_SCHEMAS = {
|
|
3624
|
-
Date: { type: "string", format: "date-time" },
|
|
3625
|
-
RegExp: { type: "object", description: "RegExp" },
|
|
3626
|
-
Error: { type: "object" },
|
|
3627
|
-
Promise: { type: "object" },
|
|
3628
|
-
Map: { type: "object" },
|
|
3629
|
-
Set: { type: "object" },
|
|
3630
|
-
WeakMap: { type: "object" },
|
|
3631
|
-
WeakSet: { type: "object" },
|
|
3632
|
-
Function: { type: "object" },
|
|
3633
|
-
ArrayBuffer: { type: "string", format: "binary" },
|
|
3634
|
-
ArrayBufferLike: { type: "string", format: "binary" },
|
|
3635
|
-
DataView: { type: "string", format: "binary" },
|
|
3636
|
-
Uint8Array: { type: "string", format: "byte" },
|
|
3637
|
-
Uint16Array: { type: "string", format: "byte" },
|
|
3638
|
-
Uint32Array: { type: "string", format: "byte" },
|
|
3639
|
-
Int8Array: { type: "string", format: "byte" },
|
|
3640
|
-
Int16Array: { type: "string", format: "byte" },
|
|
3641
|
-
Int32Array: { type: "string", format: "byte" },
|
|
3642
|
-
Float32Array: { type: "string", format: "byte" },
|
|
3643
|
-
Float64Array: { type: "string", format: "byte" },
|
|
3644
|
-
BigInt64Array: { type: "string", format: "byte" },
|
|
3645
|
-
BigUint64Array: { type: "string", format: "byte" }
|
|
3646
|
-
};
|
|
3613
|
+
// src/utils/typebox-handler.ts
|
|
3647
3614
|
var TYPEBOX_PRIMITIVE_MAP = {
|
|
3648
3615
|
TString: { type: "string" },
|
|
3649
3616
|
TNumber: { type: "number" },
|
|
@@ -3677,7 +3644,31 @@ function unwrapTypeBoxOptional(type) {
|
|
|
3677
3644
|
const hadMarker = filtered.length < intersectionType.types.length;
|
|
3678
3645
|
return { innerTypes: filtered, isOptional: hadMarker };
|
|
3679
3646
|
}
|
|
3680
|
-
function
|
|
3647
|
+
function getPropertyType(prop, parentType, typeChecker) {
|
|
3648
|
+
if (prop.valueDeclaration) {
|
|
3649
|
+
return typeChecker.getTypeOfSymbolAtLocation(prop, prop.valueDeclaration);
|
|
3650
|
+
}
|
|
3651
|
+
const propType = typeChecker.getTypeOfPropertyOfType(parentType, prop.getName());
|
|
3652
|
+
if (propType) {
|
|
3653
|
+
return propType;
|
|
3654
|
+
}
|
|
3655
|
+
const decl = prop.declarations?.[0];
|
|
3656
|
+
if (decl) {
|
|
3657
|
+
return typeChecker.getTypeOfSymbolAtLocation(prop, decl);
|
|
3658
|
+
}
|
|
3659
|
+
return typeChecker.getAnyType();
|
|
3660
|
+
}
|
|
3661
|
+
var _formatTypeReference = null;
|
|
3662
|
+
function setFormatTypeReference(fn) {
|
|
3663
|
+
_formatTypeReference = fn;
|
|
3664
|
+
}
|
|
3665
|
+
function formatTypeReferenceInternal(type, typeChecker, typeRefs, referencedTypes, visited, depth, maxDepth, typeIds) {
|
|
3666
|
+
if (_formatTypeReference) {
|
|
3667
|
+
return _formatTypeReference(type, typeChecker, typeRefs, referencedTypes, visited, depth, maxDepth, typeIds);
|
|
3668
|
+
}
|
|
3669
|
+
return { type: "object" };
|
|
3670
|
+
}
|
|
3671
|
+
function formatTypeBoxSchema(type, typeChecker, typeRefs, referencedTypes, visited, depth = 0, maxDepth = DEFAULT_MAX_TYPE_DEPTH, typeIds) {
|
|
3681
3672
|
if (depth > maxDepth) {
|
|
3682
3673
|
return { type: "unknown" };
|
|
3683
3674
|
}
|
|
@@ -3716,7 +3707,7 @@ function formatTypeBoxSchema(type, typeChecker, typeRefs, referencedTypes, visit
|
|
|
3716
3707
|
const nested = formatTypeBoxSchema(propType, typeChecker, typeRefs, referencedTypes, visited, depth + 1, maxDepth, typeIds);
|
|
3717
3708
|
properties[propName] = nested ?? { type: "object" };
|
|
3718
3709
|
} else {
|
|
3719
|
-
properties[propName] =
|
|
3710
|
+
properties[propName] = formatTypeReferenceInternal(propType, typeChecker, typeRefs, referencedTypes, visited, depth + 1, maxDepth, typeIds);
|
|
3720
3711
|
}
|
|
3721
3712
|
const { isOptional } = unwrapTypeBoxOptional(propType);
|
|
3722
3713
|
if (propSymbolName !== "TOptional" && !isOptional) {
|
|
@@ -3744,7 +3735,7 @@ function formatTypeBoxSchema(type, typeChecker, typeRefs, referencedTypes, visit
|
|
|
3744
3735
|
type: "object"
|
|
3745
3736
|
};
|
|
3746
3737
|
} else {
|
|
3747
|
-
items =
|
|
3738
|
+
items = formatTypeReferenceInternal(itemType, typeChecker, typeRefs, referencedTypes, visited, depth + 1, maxDepth, typeIds);
|
|
3748
3739
|
}
|
|
3749
3740
|
return { type: "array", items };
|
|
3750
3741
|
}
|
|
@@ -3765,7 +3756,7 @@ function formatTypeBoxSchema(type, typeChecker, typeRefs, referencedTypes, visit
|
|
|
3765
3756
|
type: "object"
|
|
3766
3757
|
});
|
|
3767
3758
|
} else {
|
|
3768
|
-
members.push(
|
|
3759
|
+
members.push(formatTypeReferenceInternal(memberType, typeChecker, typeRefs, referencedTypes, visited, depth + 1, maxDepth, typeIds));
|
|
3769
3760
|
}
|
|
3770
3761
|
}
|
|
3771
3762
|
} else if (tupleType.typeArguments) {
|
|
@@ -3779,7 +3770,7 @@ function formatTypeBoxSchema(type, typeChecker, typeRefs, referencedTypes, visit
|
|
|
3779
3770
|
type: "object"
|
|
3780
3771
|
});
|
|
3781
3772
|
} else {
|
|
3782
|
-
members.push(
|
|
3773
|
+
members.push(formatTypeReferenceInternal(memberType, typeChecker, typeRefs, referencedTypes, visited, depth + 1, maxDepth, typeIds));
|
|
3783
3774
|
}
|
|
3784
3775
|
}
|
|
3785
3776
|
}
|
|
@@ -3802,7 +3793,7 @@ function formatTypeBoxSchema(type, typeChecker, typeRefs, referencedTypes, visit
|
|
|
3802
3793
|
type: "object"
|
|
3803
3794
|
});
|
|
3804
3795
|
} else {
|
|
3805
|
-
members.push(
|
|
3796
|
+
members.push(formatTypeReferenceInternal(memberType, typeChecker, typeRefs, referencedTypes, visited, depth + 1, maxDepth, typeIds));
|
|
3806
3797
|
}
|
|
3807
3798
|
}
|
|
3808
3799
|
}
|
|
@@ -3822,7 +3813,7 @@ function formatTypeBoxSchema(type, typeChecker, typeRefs, referencedTypes, visit
|
|
|
3822
3813
|
type: "object"
|
|
3823
3814
|
};
|
|
3824
3815
|
}
|
|
3825
|
-
return
|
|
3816
|
+
return formatTypeReferenceInternal(innerType, typeChecker, typeRefs, referencedTypes, visited, depth + 1, maxDepth, typeIds);
|
|
3826
3817
|
}
|
|
3827
3818
|
case "TLiteral": {
|
|
3828
3819
|
if (!typeArgs || typeArgs.length === 0) {
|
|
@@ -3852,7 +3843,7 @@ function formatTypeBoxSchema(type, typeChecker, typeRefs, referencedTypes, visit
|
|
|
3852
3843
|
} else if (valueSymbolName && isTypeBoxSchemaType(valueSymbolName)) {
|
|
3853
3844
|
additionalProperties = formatTypeBoxSchema(valueType, typeChecker, typeRefs, referencedTypes, visited, depth + 1, maxDepth, typeIds) ?? true;
|
|
3854
3845
|
} else {
|
|
3855
|
-
additionalProperties =
|
|
3846
|
+
additionalProperties = formatTypeReferenceInternal(valueType, typeChecker, typeRefs, referencedTypes, visited, depth + 1, maxDepth, typeIds);
|
|
3856
3847
|
}
|
|
3857
3848
|
return { type: "object", additionalProperties };
|
|
3858
3849
|
}
|
|
@@ -3872,6 +3863,32 @@ function formatTypeBoxSchema(type, typeChecker, typeRefs, referencedTypes, visit
|
|
|
3872
3863
|
return null;
|
|
3873
3864
|
}
|
|
3874
3865
|
}
|
|
3866
|
+
|
|
3867
|
+
// src/utils/schema-builder.ts
|
|
3868
|
+
var BUILTIN_TYPE_SCHEMAS = {
|
|
3869
|
+
Date: { type: "string", format: "date-time" },
|
|
3870
|
+
RegExp: { type: "object", description: "RegExp" },
|
|
3871
|
+
Error: { type: "object" },
|
|
3872
|
+
Promise: { type: "object" },
|
|
3873
|
+
Map: { type: "object" },
|
|
3874
|
+
Set: { type: "object" },
|
|
3875
|
+
WeakMap: { type: "object" },
|
|
3876
|
+
WeakSet: { type: "object" },
|
|
3877
|
+
Function: { type: "object" },
|
|
3878
|
+
ArrayBuffer: { type: "string", format: "binary" },
|
|
3879
|
+
ArrayBufferLike: { type: "string", format: "binary" },
|
|
3880
|
+
DataView: { type: "string", format: "binary" },
|
|
3881
|
+
Uint8Array: { type: "string", format: "byte" },
|
|
3882
|
+
Uint16Array: { type: "string", format: "byte" },
|
|
3883
|
+
Uint32Array: { type: "string", format: "byte" },
|
|
3884
|
+
Int8Array: { type: "string", format: "byte" },
|
|
3885
|
+
Int16Array: { type: "string", format: "byte" },
|
|
3886
|
+
Int32Array: { type: "string", format: "byte" },
|
|
3887
|
+
Float32Array: { type: "string", format: "byte" },
|
|
3888
|
+
Float64Array: { type: "string", format: "byte" },
|
|
3889
|
+
BigInt64Array: { type: "string", format: "byte" },
|
|
3890
|
+
BigUint64Array: { type: "string", format: "byte" }
|
|
3891
|
+
};
|
|
3875
3892
|
function isObjectLiteralType(type) {
|
|
3876
3893
|
if (!(type.getFlags() & ts2.TypeFlags.Object)) {
|
|
3877
3894
|
return false;
|
|
@@ -3894,20 +3911,6 @@ function withDescription(schema, description) {
|
|
|
3894
3911
|
description
|
|
3895
3912
|
};
|
|
3896
3913
|
}
|
|
3897
|
-
function getPropertyType(prop, parentType, typeChecker) {
|
|
3898
|
-
if (prop.valueDeclaration) {
|
|
3899
|
-
return typeChecker.getTypeOfSymbolAtLocation(prop, prop.valueDeclaration);
|
|
3900
|
-
}
|
|
3901
|
-
const propType = typeChecker.getTypeOfPropertyOfType(parentType, prop.getName());
|
|
3902
|
-
if (propType) {
|
|
3903
|
-
return propType;
|
|
3904
|
-
}
|
|
3905
|
-
const decl = prop.declarations?.[0];
|
|
3906
|
-
if (decl) {
|
|
3907
|
-
return typeChecker.getTypeOfSymbolAtLocation(prop, decl);
|
|
3908
|
-
}
|
|
3909
|
-
return typeChecker.getAnyType();
|
|
3910
|
-
}
|
|
3911
3914
|
function propertiesToSchema(properties, description) {
|
|
3912
3915
|
const schema = {
|
|
3913
3916
|
type: "object",
|
|
@@ -3944,6 +3947,10 @@ function propertiesToSchema(properties, description) {
|
|
|
3944
3947
|
}
|
|
3945
3948
|
return schema;
|
|
3946
3949
|
}
|
|
3950
|
+
var _formatTypeReference2 = null;
|
|
3951
|
+
function setSchemaBuilderFormatTypeReference(fn) {
|
|
3952
|
+
_formatTypeReference2 = fn;
|
|
3953
|
+
}
|
|
3947
3954
|
function buildSchemaFromTypeNode(node, typeChecker, typeRefs, referencedTypes, functionDoc, parentParamName) {
|
|
3948
3955
|
if (ts2.isParenthesizedTypeNode(node)) {
|
|
3949
3956
|
return buildSchemaFromTypeNode(node.type, typeChecker, typeRefs, referencedTypes, functionDoc ?? null, parentParamName);
|
|
@@ -3973,7 +3980,7 @@ function buildSchemaFromTypeNode(node, typeChecker, typeRefs, referencedTypes, f
|
|
|
3973
3980
|
let schema2 = "any";
|
|
3974
3981
|
if (member.type) {
|
|
3975
3982
|
const memberType = typeChecker.getTypeFromTypeNode(member.type);
|
|
3976
|
-
const formatted =
|
|
3983
|
+
const formatted = _formatTypeReference2 ? _formatTypeReference2(memberType, typeChecker, typeRefs, referencedTypes) : { type: "any" };
|
|
3977
3984
|
if (typeof formatted === "string") {
|
|
3978
3985
|
if (formatted === "any") {
|
|
3979
3986
|
schema2 = buildSchemaFromTypeNode(member.type, typeChecker, typeRefs, referencedTypes, functionDoc, parentParamName);
|
|
@@ -4154,7 +4161,16 @@ function deduplicateSchemas(schemas) {
|
|
|
4154
4161
|
}
|
|
4155
4162
|
return result;
|
|
4156
4163
|
}
|
|
4157
|
-
|
|
4164
|
+
|
|
4165
|
+
// src/utils/type-formatter.ts
|
|
4166
|
+
function safeTypeToString(typeChecker, type) {
|
|
4167
|
+
try {
|
|
4168
|
+
return typeChecker.typeToString(type);
|
|
4169
|
+
} catch {
|
|
4170
|
+
return "unknown";
|
|
4171
|
+
}
|
|
4172
|
+
}
|
|
4173
|
+
function formatTypeReference(type, typeChecker, typeRefs, referencedTypes, visitedAliases, depth = 0, maxDepth = DEFAULT_MAX_TYPE_DEPTH, visitedTypeIds) {
|
|
4158
4174
|
if (depth > maxDepth) {
|
|
4159
4175
|
return { type: "unknown" };
|
|
4160
4176
|
}
|
|
@@ -4351,6 +4367,9 @@ function formatTypeReference(type, typeChecker, typeRefs, referencedTypes, visit
|
|
|
4351
4367
|
}
|
|
4352
4368
|
}
|
|
4353
4369
|
}
|
|
4370
|
+
setFormatTypeReference(formatTypeReference);
|
|
4371
|
+
setSchemaBuilderFormatTypeReference(formatTypeReference);
|
|
4372
|
+
// src/utils/parameter-utils.ts
|
|
4354
4373
|
function structureParameter(param, paramDecl, paramType, typeChecker, typeRefs, functionDoc, paramDoc, referencedTypes) {
|
|
4355
4374
|
const paramName = param.getName();
|
|
4356
4375
|
const isDestructured = paramName === "__0" || ts2.isObjectBindingPattern(paramDecl.name) || ts2.isArrayBindingPattern(paramDecl.name);
|
|
@@ -6147,10 +6166,30 @@ class TypeRegistry {
|
|
|
6147
6166
|
}
|
|
6148
6167
|
|
|
6149
6168
|
// src/analysis/spec-builder.ts
|
|
6150
|
-
function
|
|
6151
|
-
|
|
6169
|
+
function createDefaultGenerationInfo(entryFile) {
|
|
6170
|
+
return {
|
|
6171
|
+
timestamp: new Date().toISOString(),
|
|
6172
|
+
generator: {
|
|
6173
|
+
name: "@doccov/sdk",
|
|
6174
|
+
version: "0.0.0"
|
|
6175
|
+
},
|
|
6176
|
+
analysis: {
|
|
6177
|
+
entryPoint: entryFile,
|
|
6178
|
+
entryPointSource: "explicit",
|
|
6179
|
+
isDeclarationOnly: entryFile.endsWith(".d.ts"),
|
|
6180
|
+
resolvedExternalTypes: false
|
|
6181
|
+
},
|
|
6182
|
+
environment: {
|
|
6183
|
+
hasNodeModules: false
|
|
6184
|
+
},
|
|
6185
|
+
issues: []
|
|
6186
|
+
};
|
|
6187
|
+
}
|
|
6188
|
+
function buildOpenPkgSpec(context, resolveExternalTypes, generation) {
|
|
6189
|
+
const { baseDir, checker: typeChecker, sourceFile, program, entryFile } = context;
|
|
6152
6190
|
const packageJsonPath = path9.join(baseDir, "package.json");
|
|
6153
6191
|
const packageJson = fs8.existsSync(packageJsonPath) ? JSON.parse(fs8.readFileSync(packageJsonPath, "utf-8")) : {};
|
|
6192
|
+
const generationInfo = generation ?? createDefaultGenerationInfo(path9.relative(baseDir, entryFile));
|
|
6154
6193
|
const spec = {
|
|
6155
6194
|
$schema: SCHEMA_URL,
|
|
6156
6195
|
openpkg: SCHEMA_VERSION,
|
|
@@ -6163,7 +6202,8 @@ function buildOpenPkgSpec(context, resolveExternalTypes) {
|
|
|
6163
6202
|
ecosystem: "js/ts"
|
|
6164
6203
|
},
|
|
6165
6204
|
exports: [],
|
|
6166
|
-
types: []
|
|
6205
|
+
types: [],
|
|
6206
|
+
generation: generationInfo
|
|
6167
6207
|
};
|
|
6168
6208
|
const typeRegistry = new TypeRegistry;
|
|
6169
6209
|
const serializerContext = {
|
|
@@ -6480,7 +6520,7 @@ function hasExternalImports(sourceFile) {
|
|
|
6480
6520
|
});
|
|
6481
6521
|
return found;
|
|
6482
6522
|
}
|
|
6483
|
-
function runAnalysis(input) {
|
|
6523
|
+
function runAnalysis(input, generationInput) {
|
|
6484
6524
|
const context = createAnalysisContext(input);
|
|
6485
6525
|
const { baseDir, options, program } = context;
|
|
6486
6526
|
const packageJsonPath = findNearestPackageJson(baseDir);
|
|
@@ -6493,30 +6533,65 @@ function runAnalysis(input) {
|
|
|
6493
6533
|
`);
|
|
6494
6534
|
return !/allowJs/i.test(msg);
|
|
6495
6535
|
});
|
|
6496
|
-
const spec = buildOpenPkgSpec(context, resolveExternalTypes);
|
|
6497
6536
|
const specDiagnostics = [];
|
|
6537
|
+
const generationIssues = [];
|
|
6498
6538
|
if (!hasNodeModules && hasExternalImports(context.sourceFile)) {
|
|
6499
|
-
|
|
6539
|
+
const issue = {
|
|
6540
|
+
code: "NO_NODE_MODULES",
|
|
6500
6541
|
message: "External imports detected but node_modules not found.",
|
|
6501
6542
|
severity: "info",
|
|
6502
6543
|
suggestion: "Run npm install or bun install for complete type resolution."
|
|
6503
|
-
}
|
|
6504
|
-
|
|
6544
|
+
};
|
|
6545
|
+
specDiagnostics.push(issue);
|
|
6546
|
+
generationIssues.push(issue);
|
|
6547
|
+
}
|
|
6548
|
+
const generation = generationInput ? {
|
|
6549
|
+
timestamp: new Date().toISOString(),
|
|
6550
|
+
generator: {
|
|
6551
|
+
name: generationInput.generatorName,
|
|
6552
|
+
version: generationInput.generatorVersion
|
|
6553
|
+
},
|
|
6554
|
+
analysis: {
|
|
6555
|
+
entryPoint: generationInput.entryPoint,
|
|
6556
|
+
entryPointSource: generationInput.entryPointSource,
|
|
6557
|
+
isDeclarationOnly: generationInput.isDeclarationOnly ?? false,
|
|
6558
|
+
resolvedExternalTypes: resolveExternalTypes,
|
|
6559
|
+
maxTypeDepth: options.maxDepth
|
|
6560
|
+
},
|
|
6561
|
+
environment: {
|
|
6562
|
+
packageManager: generationInput.packageManager,
|
|
6563
|
+
hasNodeModules,
|
|
6564
|
+
isMonorepo: generationInput.isMonorepo,
|
|
6565
|
+
targetPackage: generationInput.targetPackage
|
|
6566
|
+
},
|
|
6567
|
+
issues: generationIssues
|
|
6568
|
+
} : undefined;
|
|
6569
|
+
const spec = buildOpenPkgSpec(context, resolveExternalTypes, generation);
|
|
6505
6570
|
const danglingRefs = collectDanglingRefs(spec);
|
|
6506
6571
|
for (const ref of danglingRefs) {
|
|
6507
|
-
|
|
6572
|
+
const issue = {
|
|
6573
|
+
code: "DANGLING_REF",
|
|
6508
6574
|
message: `Type '${ref}' is referenced but not defined in types[].`,
|
|
6509
6575
|
severity: "warning",
|
|
6510
6576
|
suggestion: hasNodeModules ? "The type may be from an external package. Check import paths." : "Run npm/bun install to resolve external types."
|
|
6511
|
-
}
|
|
6577
|
+
};
|
|
6578
|
+
specDiagnostics.push(issue);
|
|
6579
|
+
if (generation) {
|
|
6580
|
+
generation.issues.push(issue);
|
|
6581
|
+
}
|
|
6512
6582
|
}
|
|
6513
6583
|
const externalTypes = collectExternalTypes(spec);
|
|
6514
6584
|
if (externalTypes.length > 0) {
|
|
6515
|
-
|
|
6585
|
+
const issue = {
|
|
6586
|
+
code: "EXTERNAL_TYPE_STUBS",
|
|
6516
6587
|
message: `${externalTypes.length} external type(s) could not be fully resolved: ${externalTypes.slice(0, 5).join(", ")}${externalTypes.length > 5 ? "..." : ""}`,
|
|
6517
6588
|
severity: "warning",
|
|
6518
6589
|
suggestion: hasNodeModules ? "Types are from external packages. Full resolution requires type declarations." : "Run npm/bun install to resolve external type definitions."
|
|
6519
|
-
}
|
|
6590
|
+
};
|
|
6591
|
+
specDiagnostics.push(issue);
|
|
6592
|
+
if (generation) {
|
|
6593
|
+
generation.issues.push(issue);
|
|
6594
|
+
}
|
|
6520
6595
|
}
|
|
6521
6596
|
const sourceFiles = program.getSourceFiles().filter((sf) => !sf.isDeclarationFile && sf.fileName.startsWith(baseDir)).map((sf) => sf.fileName);
|
|
6522
6597
|
return {
|
|
@@ -8176,7 +8251,7 @@ class DocCov {
|
|
|
8176
8251
|
packageDir,
|
|
8177
8252
|
content: code,
|
|
8178
8253
|
options: this.options
|
|
8179
|
-
});
|
|
8254
|
+
}, analyzeOptions.generationInput);
|
|
8180
8255
|
const filterOutcome = this.applySpecFilters(analysis.spec, analyzeOptions.filters);
|
|
8181
8256
|
return {
|
|
8182
8257
|
spec: filterOutcome.spec,
|
|
@@ -8211,7 +8286,7 @@ class DocCov {
|
|
|
8211
8286
|
packageDir,
|
|
8212
8287
|
content,
|
|
8213
8288
|
options: this.options
|
|
8214
|
-
});
|
|
8289
|
+
}, analyzeOptions.generationInput);
|
|
8215
8290
|
const filterOutcome = this.applySpecFilters(analysis.spec, analyzeOptions.filters);
|
|
8216
8291
|
const metadata = this.normalizeMetadata(analysis.metadata);
|
|
8217
8292
|
const result = {
|
|
@@ -8374,7 +8449,6 @@ async function analyze(code, options = {}) {
|
|
|
8374
8449
|
async function analyzeFile(filePath, options = {}) {
|
|
8375
8450
|
return new DocCov().analyzeFile(filePath, options);
|
|
8376
8451
|
}
|
|
8377
|
-
var OpenPkg = DocCov;
|
|
8378
8452
|
function resolvePackageDir(entryFile) {
|
|
8379
8453
|
const fallbackDir = path11.dirname(entryFile);
|
|
8380
8454
|
let currentDir = fallbackDir;
|
|
@@ -8486,130 +8560,199 @@ function extractSpecSummary(spec) {
|
|
|
8486
8560
|
drift
|
|
8487
8561
|
};
|
|
8488
8562
|
}
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
this.options = options;
|
|
8497
|
-
}
|
|
8498
|
-
emit(event) {
|
|
8499
|
-
this.options.onProgress?.(event);
|
|
8500
|
-
}
|
|
8501
|
-
async detectPackage(packageName) {
|
|
8502
|
-
this.emit({ stage: "detecting", message: "Detecting project structure...", progress: 10 });
|
|
8503
|
-
const mono = await detectMonorepo(this.fs);
|
|
8504
|
-
if (mono.isMonorepo) {
|
|
8505
|
-
if (!packageName) {
|
|
8506
|
-
const publicPackages = mono.packages.filter((p) => !p.private);
|
|
8507
|
-
throw new MonorepoRequiresPackageError(publicPackages.map((p) => p.name));
|
|
8508
|
-
}
|
|
8509
|
-
const pkg = findPackageByName(mono.packages, packageName);
|
|
8510
|
-
if (!pkg) {
|
|
8511
|
-
throw new Error(`Package "${packageName}" not found. Available: ${mono.packages.map((p) => p.name).join(", ")}`);
|
|
8512
|
-
}
|
|
8513
|
-
this.emit({ stage: "detecting", message: `Found package: ${pkg.name}`, progress: 15 });
|
|
8514
|
-
return { targetPath: pkg.path, resolvedPackage: pkg.name };
|
|
8515
|
-
}
|
|
8516
|
-
return { targetPath: "." };
|
|
8517
|
-
}
|
|
8518
|
-
async detectEntry(targetPath) {
|
|
8519
|
-
this.emit({ stage: "detecting", message: "Detecting entry point...", progress: 18 });
|
|
8520
|
-
const entry = await detectEntryPoint(this.fs, targetPath);
|
|
8521
|
-
const entryFile = targetPath === "." ? entry.path : `${targetPath}/${entry.path}`;
|
|
8522
|
-
this.emit({
|
|
8523
|
-
stage: "detecting",
|
|
8524
|
-
message: `Entry point: ${entry.path} (from ${entry.source})`,
|
|
8525
|
-
progress: 20
|
|
8526
|
-
});
|
|
8527
|
-
return entryFile;
|
|
8563
|
+
// src/scan/github-context.ts
|
|
8564
|
+
function parseGitHubUrl2(url) {
|
|
8565
|
+
try {
|
|
8566
|
+
const { owner, repo } = parseGitHubUrl(url);
|
|
8567
|
+
return { owner, repo };
|
|
8568
|
+
} catch {
|
|
8569
|
+
return null;
|
|
8528
8570
|
}
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8571
|
+
}
|
|
8572
|
+
async function fetchRawFile(owner, repo, ref, path13) {
|
|
8573
|
+
const url = `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${path13}`;
|
|
8574
|
+
try {
|
|
8575
|
+
const response = await fetch(url);
|
|
8576
|
+
if (response.ok) {
|
|
8577
|
+
return await response.text();
|
|
8536
8578
|
}
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
|
|
8541
|
-
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
|
|
8548
|
-
});
|
|
8579
|
+
return null;
|
|
8580
|
+
} catch {
|
|
8581
|
+
return null;
|
|
8582
|
+
}
|
|
8583
|
+
}
|
|
8584
|
+
async function fetchRepoMetadata(owner, repo) {
|
|
8585
|
+
const url = `https://api.github.com/repos/${owner}/${repo}`;
|
|
8586
|
+
const response = await fetch(url, {
|
|
8587
|
+
headers: {
|
|
8588
|
+
Accept: "application/vnd.github.v3+json",
|
|
8589
|
+
"User-Agent": "DocCov-Scanner"
|
|
8549
8590
|
}
|
|
8550
|
-
|
|
8591
|
+
});
|
|
8592
|
+
if (!response.ok) {
|
|
8593
|
+
throw new Error(`Failed to fetch repository: ${response.status} ${response.statusText}`);
|
|
8551
8594
|
}
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
|
|
8580
|
-
|
|
8581
|
-
const
|
|
8582
|
-
const
|
|
8583
|
-
|
|
8584
|
-
await this.install(".");
|
|
8585
|
-
await this.build(".", targetPath);
|
|
8586
|
-
}
|
|
8587
|
-
const spec = await this.analyze(entryFile);
|
|
8588
|
-
this.emit({ stage: "complete", message: "Extracting results...", progress: 95 });
|
|
8589
|
-
const summary = extractSpecSummary(spec);
|
|
8590
|
-
this.emit({ stage: "complete", message: "Scan complete", progress: 100 });
|
|
8595
|
+
const data = await response.json();
|
|
8596
|
+
return {
|
|
8597
|
+
owner,
|
|
8598
|
+
repo,
|
|
8599
|
+
defaultBranch: data.default_branch,
|
|
8600
|
+
description: data.description,
|
|
8601
|
+
language: data.language,
|
|
8602
|
+
topics: data.topics ?? [],
|
|
8603
|
+
isPrivate: data.private
|
|
8604
|
+
};
|
|
8605
|
+
}
|
|
8606
|
+
async function detectPackageManager3(owner, repo, ref) {
|
|
8607
|
+
const lockfiles = [
|
|
8608
|
+
{ name: "bun.lockb", manager: "bun" },
|
|
8609
|
+
{ name: "pnpm-lock.yaml", manager: "pnpm" },
|
|
8610
|
+
{ name: "yarn.lock", manager: "yarn" },
|
|
8611
|
+
{ name: "package-lock.json", manager: "npm" }
|
|
8612
|
+
];
|
|
8613
|
+
for (const { name, manager } of lockfiles) {
|
|
8614
|
+
const content = await fetchRawFile(owner, repo, ref, name);
|
|
8615
|
+
if (content !== null) {
|
|
8616
|
+
return { manager, lockfile: { name, content: content.slice(0, 1e4) } };
|
|
8617
|
+
}
|
|
8618
|
+
}
|
|
8619
|
+
return { manager: "unknown" };
|
|
8620
|
+
}
|
|
8621
|
+
async function detectWorkspace(packageJson, owner, repo, ref) {
|
|
8622
|
+
const pnpmWorkspace = await fetchRawFile(owner, repo, ref, "pnpm-workspace.yaml");
|
|
8623
|
+
if (pnpmWorkspace) {
|
|
8624
|
+
const packagesMatch = pnpmWorkspace.match(/packages:\s*\n((?:\s+-\s+['"]?[^\n]+['"]?\n?)+)/);
|
|
8625
|
+
const packages = packagesMatch ? packagesMatch[1].split(`
|
|
8626
|
+
`).map((line) => line.replace(/^\s+-\s+['"]?/, "").replace(/['"]?\s*$/, "")).filter(Boolean) : undefined;
|
|
8591
8627
|
return {
|
|
8592
|
-
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
packageName: resolvedPackage ?? options.package,
|
|
8596
|
-
coverage: summary.coverage,
|
|
8597
|
-
exportCount: summary.exportCount,
|
|
8598
|
-
typeCount: summary.typeCount,
|
|
8599
|
-
driftCount: summary.driftCount,
|
|
8600
|
-
undocumented: summary.undocumented,
|
|
8601
|
-
drift: summary.drift
|
|
8628
|
+
isMonorepo: true,
|
|
8629
|
+
tool: "pnpm",
|
|
8630
|
+
packages
|
|
8602
8631
|
};
|
|
8603
8632
|
}
|
|
8633
|
+
const lernaJson = await fetchRawFile(owner, repo, ref, "lerna.json");
|
|
8634
|
+
if (lernaJson) {
|
|
8635
|
+
return { isMonorepo: true, tool: "lerna" };
|
|
8636
|
+
}
|
|
8637
|
+
if (packageJson && typeof packageJson === "object") {
|
|
8638
|
+
const pkg = packageJson;
|
|
8639
|
+
if (pkg.workspaces) {
|
|
8640
|
+
const workspaces = pkg.workspaces;
|
|
8641
|
+
const packages = Array.isArray(workspaces) ? workspaces : workspaces.packages;
|
|
8642
|
+
return {
|
|
8643
|
+
isMonorepo: true,
|
|
8644
|
+
tool: "npm",
|
|
8645
|
+
packages: packages?.filter((p) => typeof p === "string")
|
|
8646
|
+
};
|
|
8647
|
+
}
|
|
8648
|
+
}
|
|
8649
|
+
return { isMonorepo: false };
|
|
8604
8650
|
}
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8651
|
+
function detectBuildHints(packageJson, tsconfigJson) {
|
|
8652
|
+
const hints = {
|
|
8653
|
+
hasTypeScript: false,
|
|
8654
|
+
hasWasm: false,
|
|
8655
|
+
hasNativeModules: false,
|
|
8656
|
+
hasBuildScript: false,
|
|
8657
|
+
frameworks: []
|
|
8658
|
+
};
|
|
8659
|
+
if (!packageJson || typeof packageJson !== "object") {
|
|
8660
|
+
return hints;
|
|
8661
|
+
}
|
|
8662
|
+
const pkg = packageJson;
|
|
8663
|
+
const deps = {
|
|
8664
|
+
...typeof pkg.dependencies === "object" ? pkg.dependencies : {},
|
|
8665
|
+
...typeof pkg.devDependencies === "object" ? pkg.devDependencies : {}
|
|
8666
|
+
};
|
|
8667
|
+
hints.hasTypeScript = "typescript" in deps || tsconfigJson !== null;
|
|
8668
|
+
hints.hasWasm = "wasm-pack" in deps || "@aspect-build/rules_esbuild" in deps;
|
|
8669
|
+
hints.hasNativeModules = "node-gyp" in deps || "prebuild" in deps || "napi-rs" in deps;
|
|
8670
|
+
const scripts = typeof pkg.scripts === "object" ? pkg.scripts : {};
|
|
8671
|
+
if (scripts.build) {
|
|
8672
|
+
hints.hasBuildScript = true;
|
|
8673
|
+
hints.buildScript = scripts.build;
|
|
8674
|
+
}
|
|
8675
|
+
const frameworkDeps = [
|
|
8676
|
+
{ dep: "react", name: "React" },
|
|
8677
|
+
{ dep: "vue", name: "Vue" },
|
|
8678
|
+
{ dep: "svelte", name: "Svelte" },
|
|
8679
|
+
{ dep: "next", name: "Next.js" },
|
|
8680
|
+
{ dep: "nuxt", name: "Nuxt" },
|
|
8681
|
+
{ dep: "astro", name: "Astro" },
|
|
8682
|
+
{ dep: "express", name: "Express" },
|
|
8683
|
+
{ dep: "fastify", name: "Fastify" },
|
|
8684
|
+
{ dep: "hono", name: "Hono" }
|
|
8685
|
+
];
|
|
8686
|
+
for (const { dep, name } of frameworkDeps) {
|
|
8687
|
+
if (dep in deps) {
|
|
8688
|
+
hints.frameworks.push(name);
|
|
8689
|
+
}
|
|
8690
|
+
}
|
|
8691
|
+
return hints;
|
|
8692
|
+
}
|
|
8693
|
+
async function fetchGitHubContext(repoUrl, ref) {
|
|
8694
|
+
const parsed = parseGitHubUrl2(repoUrl);
|
|
8695
|
+
if (!parsed) {
|
|
8696
|
+
throw new Error(`Invalid GitHub URL: ${repoUrl}`);
|
|
8697
|
+
}
|
|
8698
|
+
const { owner, repo } = parsed;
|
|
8699
|
+
const metadata = await fetchRepoMetadata(owner, repo);
|
|
8700
|
+
const targetRef = ref ?? metadata.defaultBranch;
|
|
8701
|
+
const [packageJsonRaw, tsconfigJsonRaw, pmResult] = await Promise.all([
|
|
8702
|
+
fetchRawFile(owner, repo, targetRef, "package.json"),
|
|
8703
|
+
fetchRawFile(owner, repo, targetRef, "tsconfig.json"),
|
|
8704
|
+
detectPackageManager3(owner, repo, targetRef)
|
|
8705
|
+
]);
|
|
8706
|
+
let packageJson = null;
|
|
8707
|
+
let tsconfigJson = null;
|
|
8708
|
+
if (packageJsonRaw) {
|
|
8709
|
+
try {
|
|
8710
|
+
packageJson = JSON.parse(packageJsonRaw);
|
|
8711
|
+
} catch {}
|
|
8712
|
+
}
|
|
8713
|
+
if (tsconfigJsonRaw) {
|
|
8714
|
+
try {
|
|
8715
|
+
tsconfigJson = JSON.parse(tsconfigJsonRaw);
|
|
8716
|
+
} catch {}
|
|
8717
|
+
}
|
|
8718
|
+
const workspace = await detectWorkspace(packageJson, owner, repo, targetRef);
|
|
8719
|
+
const buildHints = detectBuildHints(packageJson, tsconfigJson);
|
|
8720
|
+
return {
|
|
8721
|
+
metadata,
|
|
8722
|
+
ref: targetRef,
|
|
8723
|
+
packageManager: pmResult.manager,
|
|
8724
|
+
workspace,
|
|
8725
|
+
buildHints,
|
|
8726
|
+
files: {
|
|
8727
|
+
packageJson: packageJsonRaw ?? undefined,
|
|
8728
|
+
tsconfigJson: tsconfigJsonRaw ?? undefined,
|
|
8729
|
+
lockfile: pmResult.lockfile
|
|
8730
|
+
}
|
|
8731
|
+
};
|
|
8732
|
+
}
|
|
8733
|
+
async function listWorkspacePackages(owner, repo, ref, patterns) {
|
|
8734
|
+
const packages = [];
|
|
8735
|
+
for (const pattern of patterns) {
|
|
8736
|
+
const baseDir = pattern.replace(/\/\*.*$/, "");
|
|
8737
|
+
try {
|
|
8738
|
+
const url = `https://api.github.com/repos/${owner}/${repo}/contents/${baseDir}?ref=${ref}`;
|
|
8739
|
+
const response = await fetch(url, {
|
|
8740
|
+
headers: {
|
|
8741
|
+
Accept: "application/vnd.github.v3+json",
|
|
8742
|
+
"User-Agent": "DocCov-Scanner"
|
|
8743
|
+
}
|
|
8744
|
+
});
|
|
8745
|
+
if (response.ok) {
|
|
8746
|
+
const contents = await response.json();
|
|
8747
|
+
for (const item of contents) {
|
|
8748
|
+
if (item.type === "dir") {
|
|
8749
|
+
packages.push(`${baseDir}/${item.name}`);
|
|
8750
|
+
}
|
|
8751
|
+
}
|
|
8752
|
+
}
|
|
8753
|
+
} catch {}
|
|
8612
8754
|
}
|
|
8755
|
+
return packages;
|
|
8613
8756
|
}
|
|
8614
8757
|
export {
|
|
8615
8758
|
validateSpecCache,
|
|
@@ -8626,6 +8769,7 @@ export {
|
|
|
8626
8769
|
runExample,
|
|
8627
8770
|
resolveTarget,
|
|
8628
8771
|
readPackageJson,
|
|
8772
|
+
parseGitHubUrl2 as parseScanGitHubUrl,
|
|
8629
8773
|
parseMarkdownFiles,
|
|
8630
8774
|
parseMarkdownFile,
|
|
8631
8775
|
parseListFlag,
|
|
@@ -8638,6 +8782,7 @@ export {
|
|
|
8638
8782
|
mergeConfig,
|
|
8639
8783
|
loadSpecCache,
|
|
8640
8784
|
loadCachedReport,
|
|
8785
|
+
listWorkspacePackages,
|
|
8641
8786
|
isFixableDrift,
|
|
8642
8787
|
isExecutableLang,
|
|
8643
8788
|
isCachedReportValid,
|
|
@@ -8676,6 +8821,7 @@ export {
|
|
|
8676
8821
|
findDeprecatedReferences,
|
|
8677
8822
|
fetchSpecFromGitHub,
|
|
8678
8823
|
fetchSpec,
|
|
8824
|
+
fetchGitHubContext,
|
|
8679
8825
|
extractSpecSummary,
|
|
8680
8826
|
extractPackageSpec,
|
|
8681
8827
|
extractImports,
|
|
@@ -8713,15 +8859,12 @@ export {
|
|
|
8713
8859
|
analyzeDocsImpact,
|
|
8714
8860
|
analyze,
|
|
8715
8861
|
VALIDATION_INFO,
|
|
8716
|
-
ScanOrchestrator,
|
|
8717
8862
|
SandboxFileSystem,
|
|
8718
8863
|
STYLE_RULES,
|
|
8719
8864
|
SPEC_CACHE_FILE,
|
|
8720
8865
|
REPORT_VERSION,
|
|
8721
8866
|
REPORT_EXTENSIONS,
|
|
8722
|
-
OpenPkg,
|
|
8723
8867
|
NodeFileSystem,
|
|
8724
|
-
MonorepoRequiresPackageError,
|
|
8725
8868
|
DocCov,
|
|
8726
8869
|
DEFAULT_REPORT_PATH,
|
|
8727
8870
|
DEFAULT_REPORT_DIR,
|