@doccov/sdk 0.21.0 → 0.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +24 -3
- package/dist/index.js +137 -59
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -125,6 +125,8 @@ interface DetectedSchema {
|
|
|
125
125
|
interface SchemaDetectionResult {
|
|
126
126
|
schemas: Map<string, DetectedSchema>;
|
|
127
127
|
errors: string[];
|
|
128
|
+
/** Warning when runtime was requested but compiled JS not found */
|
|
129
|
+
noCompiledJsWarning?: boolean;
|
|
128
130
|
}
|
|
129
131
|
declare function detectRuntimeSchemas(context: SchemaDetectionContext): Promise<SchemaDetectionResult>;
|
|
130
132
|
declare function clearSchemaCache(): void;
|
|
@@ -329,9 +331,28 @@ type DriftResult = {
|
|
|
329
331
|
exports: Map<string, SpecDocDrift[]>;
|
|
330
332
|
};
|
|
331
333
|
/**
|
|
334
|
+
* Information about an for context-aware suggestions.
|
|
335
|
+
*/
|
|
336
|
+
interface ExportInfo {
|
|
337
|
+
name: string;
|
|
338
|
+
kind: string;
|
|
339
|
+
isCallable: boolean;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Registry of exports and types for cross-reference validation.
|
|
343
|
+
*/
|
|
344
|
+
interface ExportRegistry {
|
|
345
|
+
/** Map of names to their info (for context-aware suggestions) */
|
|
346
|
+
exports: Map<string, ExportInfo>;
|
|
347
|
+
/** Set of type names (interfaces, type aliases, etc.) */
|
|
348
|
+
types: Set<string>;
|
|
349
|
+
/** Combined set of all names (for backward compatibility) */
|
|
350
|
+
all: Set<string>;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
332
353
|
* Build a registry of all export/type names for cross-reference validation.
|
|
333
354
|
*/
|
|
334
|
-
declare function buildExportRegistry(spec: OpenPkgSpec):
|
|
355
|
+
declare function buildExportRegistry(spec: OpenPkgSpec): ExportRegistry;
|
|
335
356
|
/**
|
|
336
357
|
* Compute drift for all exports in a spec.
|
|
337
358
|
*
|
|
@@ -342,10 +363,10 @@ declare function computeDrift(spec: OpenPkgSpec): DriftResult;
|
|
|
342
363
|
* Compute drift for a single export.
|
|
343
364
|
*
|
|
344
365
|
* @param entry - The to analyze
|
|
345
|
-
* @param
|
|
366
|
+
* @param registry - Registry of known exports and types for validation
|
|
346
367
|
* @returns Array of drift issues detected
|
|
347
368
|
*/
|
|
348
|
-
declare function computeExportDrift(entry: SpecExport,
|
|
369
|
+
declare function computeExportDrift(entry: SpecExport, registry?: ExportRegistry): SpecDocDrift[];
|
|
349
370
|
/**
|
|
350
371
|
* Detect runtime errors in @example blocks.
|
|
351
372
|
* Results are provided externally after running examples via runExamples().
|
package/dist/index.js
CHANGED
|
@@ -204,7 +204,8 @@ async function detectRuntimeSchemas(context) {
|
|
|
204
204
|
if (!compiledPath) {
|
|
205
205
|
return {
|
|
206
206
|
schemas: new Map,
|
|
207
|
-
errors: []
|
|
207
|
+
errors: [],
|
|
208
|
+
noCompiledJsWarning: true
|
|
208
209
|
};
|
|
209
210
|
}
|
|
210
211
|
const extraction = await extractStandardSchemasFromProject(entryFile, baseDir);
|
|
@@ -646,7 +647,7 @@ function generateReturnTypeFix(drift, exportEntry, existingPatch) {
|
|
|
646
647
|
const actualReturn = signature?.returns;
|
|
647
648
|
if (!actualReturn)
|
|
648
649
|
return null;
|
|
649
|
-
const correctType =
|
|
650
|
+
const correctType = stringifySchema(actualReturn.schema);
|
|
650
651
|
const updatedReturn = {
|
|
651
652
|
...existingPatch?.returns,
|
|
652
653
|
type: correctType
|
|
@@ -1394,27 +1395,42 @@ var LIBRARY_INTERNAL_PATTERNS = [
|
|
|
1394
1395
|
|
|
1395
1396
|
// src/analysis/docs-coverage.ts
|
|
1396
1397
|
function buildExportRegistry(spec) {
|
|
1397
|
-
const
|
|
1398
|
+
const exports = new Map;
|
|
1399
|
+
const types = new Set;
|
|
1400
|
+
const all = new Set;
|
|
1398
1401
|
for (const entry of spec.exports ?? []) {
|
|
1399
|
-
|
|
1400
|
-
|
|
1402
|
+
const info = {
|
|
1403
|
+
name: entry.name,
|
|
1404
|
+
kind: entry.kind ?? "unknown",
|
|
1405
|
+
isCallable: ["function", "class"].includes(entry.kind ?? "")
|
|
1406
|
+
};
|
|
1407
|
+
exports.set(entry.name, info);
|
|
1408
|
+
if (entry.id)
|
|
1409
|
+
exports.set(entry.id, info);
|
|
1410
|
+
all.add(entry.name);
|
|
1411
|
+
if (entry.id)
|
|
1412
|
+
all.add(entry.id);
|
|
1401
1413
|
}
|
|
1402
1414
|
for (const type of spec.types ?? []) {
|
|
1403
|
-
|
|
1404
|
-
|
|
1415
|
+
types.add(type.name);
|
|
1416
|
+
if (type.id)
|
|
1417
|
+
types.add(type.id);
|
|
1418
|
+
all.add(type.name);
|
|
1419
|
+
if (type.id)
|
|
1420
|
+
all.add(type.id);
|
|
1405
1421
|
}
|
|
1406
|
-
return
|
|
1422
|
+
return { exports, types, all };
|
|
1407
1423
|
}
|
|
1408
1424
|
function computeDrift(spec) {
|
|
1409
|
-
const
|
|
1425
|
+
const registry = buildExportRegistry(spec);
|
|
1410
1426
|
const exports = new Map;
|
|
1411
1427
|
for (const entry of spec.exports ?? []) {
|
|
1412
|
-
const drift = computeExportDrift(entry,
|
|
1428
|
+
const drift = computeExportDrift(entry, registry);
|
|
1413
1429
|
exports.set(entry.id ?? entry.name, drift);
|
|
1414
1430
|
}
|
|
1415
1431
|
return { exports };
|
|
1416
1432
|
}
|
|
1417
|
-
function computeExportDrift(entry,
|
|
1433
|
+
function computeExportDrift(entry, registry) {
|
|
1418
1434
|
return [
|
|
1419
1435
|
...detectParamDrift(entry),
|
|
1420
1436
|
...detectOptionalityDrift(entry),
|
|
@@ -1423,8 +1439,8 @@ function computeExportDrift(entry, exportRegistry) {
|
|
|
1423
1439
|
...detectGenericConstraintDrift(entry),
|
|
1424
1440
|
...detectDeprecatedDrift(entry),
|
|
1425
1441
|
...detectVisibilityDrift(entry),
|
|
1426
|
-
...detectExampleDrift(entry,
|
|
1427
|
-
...detectBrokenLinks(entry,
|
|
1442
|
+
...detectExampleDrift(entry, registry),
|
|
1443
|
+
...detectBrokenLinks(entry, registry),
|
|
1428
1444
|
...detectExampleSyntaxErrors(entry),
|
|
1429
1445
|
...detectAsyncMismatch(entry),
|
|
1430
1446
|
...detectPropertyTypeDrift(entry)
|
|
@@ -1471,24 +1487,39 @@ function detectParamDrift(entry) {
|
|
|
1471
1487
|
if (properties.has(firstProperty)) {
|
|
1472
1488
|
continue;
|
|
1473
1489
|
}
|
|
1474
|
-
const
|
|
1490
|
+
const propsArray = Array.from(properties);
|
|
1491
|
+
const suggestion2 = findClosestMatch(firstProperty, propsArray);
|
|
1492
|
+
let suggestionText2;
|
|
1493
|
+
if (suggestion2) {
|
|
1494
|
+
suggestionText2 = `Did you mean "${prefix}.${suggestion2.value}"?`;
|
|
1495
|
+
} else if (propsArray.length > 0 && propsArray.length <= 8) {
|
|
1496
|
+
const propsList = propsArray.slice(0, 5).map((p) => `${prefix}.${p}`);
|
|
1497
|
+
suggestionText2 = propsArray.length > 5 ? `Available: ${propsList.join(", ")}... (${propsArray.length} total)` : `Available: ${propsList.join(", ")}`;
|
|
1498
|
+
}
|
|
1475
1499
|
drifts.push({
|
|
1476
1500
|
type: "param-mismatch",
|
|
1477
1501
|
target: documentedName,
|
|
1478
1502
|
issue: `JSDoc documents property "${propertyPath}" on parameter "${prefix}" which does not exist.`,
|
|
1479
|
-
suggestion:
|
|
1503
|
+
suggestion: suggestionText2
|
|
1480
1504
|
});
|
|
1481
1505
|
continue;
|
|
1482
1506
|
}
|
|
1483
1507
|
continue;
|
|
1484
1508
|
}
|
|
1485
1509
|
}
|
|
1486
|
-
const
|
|
1510
|
+
const paramsArray = Array.from(actualParamNames);
|
|
1511
|
+
const suggestion = findClosestMatch(documentedName, paramsArray);
|
|
1512
|
+
let suggestionText;
|
|
1513
|
+
if (suggestion) {
|
|
1514
|
+
suggestionText = `Did you mean "${suggestion.value}"?`;
|
|
1515
|
+
} else if (paramsArray.length > 0 && paramsArray.length <= 6) {
|
|
1516
|
+
suggestionText = `Available parameters: ${paramsArray.join(", ")}`;
|
|
1517
|
+
}
|
|
1487
1518
|
drifts.push({
|
|
1488
1519
|
type: "param-mismatch",
|
|
1489
1520
|
target: documentedName,
|
|
1490
1521
|
issue: `JSDoc documents parameter "${documentedName}" which is not present in the signature.`,
|
|
1491
|
-
suggestion:
|
|
1522
|
+
suggestion: suggestionText
|
|
1492
1523
|
});
|
|
1493
1524
|
}
|
|
1494
1525
|
return drifts;
|
|
@@ -1596,7 +1627,7 @@ function detectReturnTypeDrift(entry) {
|
|
|
1596
1627
|
if (!signatureReturn) {
|
|
1597
1628
|
return [];
|
|
1598
1629
|
}
|
|
1599
|
-
const declaredRaw =
|
|
1630
|
+
const declaredRaw = extractTypeFromSchema(signatureReturn.schema);
|
|
1600
1631
|
const declaredType = normalizeType(declaredRaw) ?? undefined;
|
|
1601
1632
|
if (!declaredType) {
|
|
1602
1633
|
return [];
|
|
@@ -1959,26 +1990,53 @@ function buildGenericConstraintSuggestion(templateName, actualConstraint) {
|
|
|
1959
1990
|
}
|
|
1960
1991
|
return `Remove the constraint from @template ${templateName} to match the declaration.`;
|
|
1961
1992
|
}
|
|
1993
|
+
function splitCamelCase(str) {
|
|
1994
|
+
return str.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").toLowerCase().split(/[\s_-]+/).filter(Boolean);
|
|
1995
|
+
}
|
|
1962
1996
|
function findClosestMatch(source, candidates) {
|
|
1963
1997
|
if (candidates.length === 0) {
|
|
1964
1998
|
return;
|
|
1965
1999
|
}
|
|
1966
|
-
const
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
return normalizedCandidate.includes(normalizedSource) || normalizedSource.includes(normalizedCandidate);
|
|
1970
|
-
});
|
|
1971
|
-
if (substringCandidate && substringCandidate !== source) {
|
|
1972
|
-
return { value: substringCandidate, distance: 0 };
|
|
1973
|
-
}
|
|
1974
|
-
let best;
|
|
2000
|
+
const sourceWords = splitCamelCase(source);
|
|
2001
|
+
let bestMatch;
|
|
2002
|
+
let bestScore = 0;
|
|
1975
2003
|
for (const candidate of candidates) {
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
2004
|
+
if (candidate === source)
|
|
2005
|
+
continue;
|
|
2006
|
+
const candidateWords = splitCamelCase(candidate);
|
|
2007
|
+
let matchingWords = 0;
|
|
2008
|
+
let suffixMatch = false;
|
|
2009
|
+
if (sourceWords.length > 0 && candidateWords.length > 0) {
|
|
2010
|
+
const sourceSuffix = sourceWords[sourceWords.length - 1];
|
|
2011
|
+
const candidateSuffix = candidateWords[candidateWords.length - 1];
|
|
2012
|
+
if (sourceSuffix === candidateSuffix) {
|
|
2013
|
+
suffixMatch = true;
|
|
2014
|
+
matchingWords += 1.5;
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
const suffixWord = suffixMatch ? sourceWords[sourceWords.length - 1] : null;
|
|
2018
|
+
for (const word of sourceWords) {
|
|
2019
|
+
if (word !== suffixWord && candidateWords.includes(word)) {
|
|
2020
|
+
matchingWords++;
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
if (matchingWords < 2)
|
|
2024
|
+
continue;
|
|
2025
|
+
const wordScore = matchingWords / Math.max(sourceWords.length, candidateWords.length);
|
|
2026
|
+
const editDistance = levenshtein(source.toLowerCase(), candidate.toLowerCase());
|
|
2027
|
+
const maxLen = Math.max(source.length, candidate.length);
|
|
2028
|
+
const levScore = 1 - editDistance / maxLen;
|
|
2029
|
+
const totalScore = suffixMatch ? wordScore * 1.5 + levScore : wordScore + levScore * 0.5;
|
|
2030
|
+
if (totalScore > bestScore && totalScore >= 0.5) {
|
|
2031
|
+
bestScore = totalScore;
|
|
2032
|
+
bestMatch = candidate;
|
|
1979
2033
|
}
|
|
1980
2034
|
}
|
|
1981
|
-
|
|
2035
|
+
if (!bestMatch) {
|
|
2036
|
+
return;
|
|
2037
|
+
}
|
|
2038
|
+
const distance = Math.round((1 - bestScore) * 10);
|
|
2039
|
+
return { value: bestMatch, distance };
|
|
1982
2040
|
}
|
|
1983
2041
|
function levenshtein(a, b) {
|
|
1984
2042
|
if (a === b) {
|
|
@@ -2008,8 +2066,22 @@ function levenshtein(a, b) {
|
|
|
2008
2066
|
}
|
|
2009
2067
|
return matrix[b.length][a.length];
|
|
2010
2068
|
}
|
|
2011
|
-
function
|
|
2012
|
-
|
|
2069
|
+
function getIdentifierContext(node) {
|
|
2070
|
+
const parent = node.parent;
|
|
2071
|
+
if (!parent)
|
|
2072
|
+
return "value";
|
|
2073
|
+
if (ts2.isCallExpression(parent) && parent.expression === node)
|
|
2074
|
+
return "call";
|
|
2075
|
+
if (ts2.isNewExpression(parent) && parent.expression === node)
|
|
2076
|
+
return "call";
|
|
2077
|
+
if (ts2.isTypeReferenceNode(parent))
|
|
2078
|
+
return "type";
|
|
2079
|
+
if (ts2.isExpressionWithTypeArguments(parent))
|
|
2080
|
+
return "type";
|
|
2081
|
+
return "value";
|
|
2082
|
+
}
|
|
2083
|
+
function detectExampleDrift(entry, registry) {
|
|
2084
|
+
if (!registry || !entry.examples?.length)
|
|
2013
2085
|
return [];
|
|
2014
2086
|
const drifts = [];
|
|
2015
2087
|
for (const example of entry.examples) {
|
|
@@ -2023,7 +2095,11 @@ function detectExampleDrift(entry, exportRegistry) {
|
|
|
2023
2095
|
if (isLocalDeclaration(node)) {
|
|
2024
2096
|
localDeclarations.add(text);
|
|
2025
2097
|
} else if (isIdentifierReference(node) && !isBuiltInIdentifier(text)) {
|
|
2026
|
-
|
|
2098
|
+
const context = getIdentifierContext(node);
|
|
2099
|
+
const existing = referencedIdentifiers.get(text);
|
|
2100
|
+
if (!existing || context === "call") {
|
|
2101
|
+
referencedIdentifiers.set(text, context);
|
|
2102
|
+
}
|
|
2027
2103
|
}
|
|
2028
2104
|
}
|
|
2029
2105
|
ts2.forEachChild(node, visit);
|
|
@@ -2035,16 +2111,27 @@ function detectExampleDrift(entry, exportRegistry) {
|
|
|
2035
2111
|
continue;
|
|
2036
2112
|
const sourceFile = ts2.createSourceFile("example.ts", codeContent, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TS);
|
|
2037
2113
|
const localDeclarations = new Set;
|
|
2038
|
-
const referencedIdentifiers = new
|
|
2114
|
+
const referencedIdentifiers = new Map;
|
|
2039
2115
|
visit(sourceFile);
|
|
2040
2116
|
for (const local of localDeclarations) {
|
|
2041
2117
|
referencedIdentifiers.delete(local);
|
|
2042
2118
|
}
|
|
2043
|
-
for (const identifier of referencedIdentifiers) {
|
|
2044
|
-
if (!
|
|
2045
|
-
|
|
2119
|
+
for (const [identifier, context] of referencedIdentifiers) {
|
|
2120
|
+
if (!registry.all.has(identifier)) {
|
|
2121
|
+
let candidates;
|
|
2122
|
+
if (context === "call") {
|
|
2123
|
+
candidates = Array.from(registry.exports.values()).filter((e) => e.isCallable).map((e) => e.name);
|
|
2124
|
+
} else if (context === "type") {
|
|
2125
|
+
candidates = [
|
|
2126
|
+
...Array.from(registry.types),
|
|
2127
|
+
...Array.from(registry.exports.values()).filter((e) => ["class", "interface", "type", "enum"].includes(e.kind)).map((e) => e.name)
|
|
2128
|
+
];
|
|
2129
|
+
} else {
|
|
2130
|
+
candidates = Array.from(registry.exports.keys());
|
|
2131
|
+
}
|
|
2132
|
+
const suggestion = findClosestMatch(identifier, candidates);
|
|
2046
2133
|
const isPascal = /^[A-Z]/.test(identifier);
|
|
2047
|
-
const hasCloseMatch = suggestion && suggestion.distance <=
|
|
2134
|
+
const hasCloseMatch = suggestion && suggestion.distance <= 5;
|
|
2048
2135
|
if (hasCloseMatch || isPascal) {
|
|
2049
2136
|
drifts.push({
|
|
2050
2137
|
type: "example-drift",
|
|
@@ -2086,8 +2173,8 @@ function isIdentifierReference(node) {
|
|
|
2086
2173
|
return false;
|
|
2087
2174
|
return true;
|
|
2088
2175
|
}
|
|
2089
|
-
function detectBrokenLinks(entry,
|
|
2090
|
-
if (!
|
|
2176
|
+
function detectBrokenLinks(entry, registry) {
|
|
2177
|
+
if (!registry) {
|
|
2091
2178
|
return [];
|
|
2092
2179
|
}
|
|
2093
2180
|
const drifts = [];
|
|
@@ -2114,13 +2201,13 @@ function detectBrokenLinks(entry, exportRegistry) {
|
|
|
2114
2201
|
if (target.includes("/") || target.includes("@")) {
|
|
2115
2202
|
continue;
|
|
2116
2203
|
}
|
|
2117
|
-
if (!
|
|
2118
|
-
const suggestion = findClosestMatch(rootName, Array.from(
|
|
2204
|
+
if (!registry.all.has(rootName) && !registry.all.has(target)) {
|
|
2205
|
+
const suggestion = findClosestMatch(rootName, Array.from(registry.all));
|
|
2119
2206
|
drifts.push({
|
|
2120
2207
|
type: "broken-link",
|
|
2121
2208
|
target,
|
|
2122
2209
|
issue: `{${type} ${target}} references a symbol that does not exist.`,
|
|
2123
|
-
suggestion: suggestion
|
|
2210
|
+
suggestion: suggestion ? `Did you mean "${suggestion.value}"?` : undefined
|
|
2124
2211
|
});
|
|
2125
2212
|
}
|
|
2126
2213
|
}
|
|
@@ -2198,7 +2285,7 @@ function detectAsyncMismatch(entry) {
|
|
|
2198
2285
|
}
|
|
2199
2286
|
const drifts = [];
|
|
2200
2287
|
const returnsPromise = signatures.some((sig) => {
|
|
2201
|
-
const returnType =
|
|
2288
|
+
const returnType = extractTypeFromSchema(sig.returns?.schema) ?? "";
|
|
2202
2289
|
return returnType.startsWith("Promise<") || returnType === "Promise";
|
|
2203
2290
|
});
|
|
2204
2291
|
const returnsTag = entry.tags?.find((tag) => tag.name === "returns" || tag.name === "return");
|
|
@@ -5161,11 +5248,11 @@ function formatTypeReference(type, typeChecker, typeRefs, referencedTypes, visit
|
|
|
5161
5248
|
if (type.getFlags() & ts.TypeFlags.Object) {
|
|
5162
5249
|
const objectType = type;
|
|
5163
5250
|
if (objectType.objectFlags & ts.ObjectFlags.Mapped) {
|
|
5164
|
-
return { type: "object"
|
|
5251
|
+
return { type: "object" };
|
|
5165
5252
|
}
|
|
5166
5253
|
}
|
|
5167
5254
|
if (type.flags & ts.TypeFlags.Conditional) {
|
|
5168
|
-
return { type: "object"
|
|
5255
|
+
return { type: "object" };
|
|
5169
5256
|
}
|
|
5170
5257
|
if (type.isUnion()) {
|
|
5171
5258
|
const unionType = type;
|
|
@@ -6419,7 +6506,6 @@ function serializeCallSignatures(signatures, symbol, context, parsedDoc) {
|
|
|
6419
6506
|
};
|
|
6420
6507
|
});
|
|
6421
6508
|
const returnType = signature.getReturnType();
|
|
6422
|
-
const returnTypeText = returnType ? checker.typeToString(returnType) : undefined;
|
|
6423
6509
|
if (returnType) {
|
|
6424
6510
|
collectReferencedTypes(returnType, checker, referencedTypes);
|
|
6425
6511
|
}
|
|
@@ -6445,7 +6531,6 @@ function serializeCallSignatures(signatures, symbol, context, parsedDoc) {
|
|
|
6445
6531
|
returns: {
|
|
6446
6532
|
schema: returnType ? formatTypeReference(returnType, checker, typeRefs, referencedTypes) : { type: "void" },
|
|
6447
6533
|
description: functionDoc?.returns || "",
|
|
6448
|
-
tsType: returnTypeText,
|
|
6449
6534
|
...typePredicateInfo ? { typePredicate: typePredicateInfo } : {}
|
|
6450
6535
|
},
|
|
6451
6536
|
description: functionDoc?.description || undefined,
|
|
@@ -8490,13 +8575,6 @@ function extractTypeName(schema) {
|
|
|
8490
8575
|
if (typeof s.type === "string") {
|
|
8491
8576
|
return s.type;
|
|
8492
8577
|
}
|
|
8493
|
-
if (typeof s.tsType === "string") {
|
|
8494
|
-
const tsType = s.tsType;
|
|
8495
|
-
if (tsType.length > 30) {
|
|
8496
|
-
return `${tsType.slice(0, 27)}...`;
|
|
8497
|
-
}
|
|
8498
|
-
return tsType;
|
|
8499
|
-
}
|
|
8500
8578
|
return;
|
|
8501
8579
|
}
|
|
8502
8580
|
function hasSignatureChanged(oldMember, newMember) {
|
|
@@ -8540,8 +8618,8 @@ function findSimilarMember(removedName, newMembers, addedMembers) {
|
|
|
8540
8618
|
for (const name of candidates) {
|
|
8541
8619
|
if (name === removedName)
|
|
8542
8620
|
continue;
|
|
8543
|
-
const removedWords =
|
|
8544
|
-
const newWords =
|
|
8621
|
+
const removedWords = splitCamelCase2(removedName);
|
|
8622
|
+
const newWords = splitCamelCase2(name);
|
|
8545
8623
|
let matchingWords = 0;
|
|
8546
8624
|
let suffixMatch = false;
|
|
8547
8625
|
if (removedWords.length > 0 && newWords.length > 0) {
|
|
@@ -8588,7 +8666,7 @@ function levenshteinDistance(a, b) {
|
|
|
8588
8666
|
}
|
|
8589
8667
|
return matrix[b.length][a.length];
|
|
8590
8668
|
}
|
|
8591
|
-
function
|
|
8669
|
+
function splitCamelCase2(str) {
|
|
8592
8670
|
return str.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().split(" ");
|
|
8593
8671
|
}
|
|
8594
8672
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doccov/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.1",
|
|
4
4
|
"description": "DocCov SDK - Documentation coverage and drift detection for TypeScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dist"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@openpkg-ts/spec": "^0.
|
|
42
|
+
"@openpkg-ts/spec": "^0.11.0",
|
|
43
43
|
"@vercel/sandbox": "^1.0.3",
|
|
44
44
|
"mdast": "^3.0.0",
|
|
45
45
|
"minimatch": "^10.1.1",
|