@doccov/sdk 0.3.6 → 0.5.6
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 +39 -6
- package/dist/index.js +473 -125
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -116,7 +116,11 @@ interface ExportReference {
|
|
|
116
116
|
/**
|
|
117
117
|
* Change type for an impacted reference
|
|
118
118
|
*/
|
|
119
|
-
type DocsChangeType = "signature-changed" | "removed" | "deprecated";
|
|
119
|
+
type DocsChangeType = "signature-changed" | "removed" | "deprecated" | "method-removed" | "method-changed" | "method-deprecated";
|
|
120
|
+
/**
|
|
121
|
+
* Member-level change type
|
|
122
|
+
*/
|
|
123
|
+
type MemberChangeType = "added" | "removed" | "signature-changed";
|
|
120
124
|
/**
|
|
121
125
|
* An impacted reference in a documentation file
|
|
122
126
|
*/
|
|
@@ -131,6 +135,14 @@ interface DocsImpactReference {
|
|
|
131
135
|
suggestion?: string;
|
|
132
136
|
/** Context around the reference */
|
|
133
137
|
context?: string;
|
|
138
|
+
/** Member/method name if this is a member-level change */
|
|
139
|
+
memberName?: string;
|
|
140
|
+
/** Type of member change (added, removed, signature-changed) */
|
|
141
|
+
memberChangeType?: MemberChangeType;
|
|
142
|
+
/** Suggested replacement for removed/changed members */
|
|
143
|
+
replacementSuggestion?: string;
|
|
144
|
+
/** True if this is just a class instantiation (new ClassName()) */
|
|
145
|
+
isInstantiation?: boolean;
|
|
134
146
|
}
|
|
135
147
|
/**
|
|
136
148
|
* Documentation file impact summary
|
|
@@ -198,14 +210,32 @@ declare function findExportReferences(files: MarkdownDocFile[], exportNames: str
|
|
|
198
210
|
*/
|
|
199
211
|
declare function blockReferencesExport(block: MarkdownCodeBlock, exportName: string): boolean;
|
|
200
212
|
import { SpecDiff } from "@openpkg-ts/spec";
|
|
213
|
+
type MemberChangeType2 = "added" | "removed" | "signature-changed";
|
|
214
|
+
interface MemberChange {
|
|
215
|
+
/** The class this member belongs to */
|
|
216
|
+
className: string;
|
|
217
|
+
/** The member name (e.g., "evaluateChainhook") */
|
|
218
|
+
memberName: string;
|
|
219
|
+
/** Kind of member */
|
|
220
|
+
memberKind: "method" | "property" | "accessor" | "constructor";
|
|
221
|
+
/** Type of change */
|
|
222
|
+
changeType: MemberChangeType2;
|
|
223
|
+
/** Old signature string (for signature changes) */
|
|
224
|
+
oldSignature?: string;
|
|
225
|
+
/** New signature string (for signature changes) */
|
|
226
|
+
newSignature?: string;
|
|
227
|
+
/** Suggested replacement (e.g., "Use replayChainhook instead") */
|
|
228
|
+
suggestion?: string;
|
|
229
|
+
}
|
|
201
230
|
/**
|
|
202
231
|
* Analyze docs impact from a spec diff
|
|
203
232
|
*
|
|
204
233
|
* @param diff - The spec diff result
|
|
205
234
|
* @param markdownFiles - Parsed markdown files
|
|
206
235
|
* @param newExportNames - All names in the new spec (for missing docs detection)
|
|
236
|
+
* @param memberChanges - Optional member-level changes for granular detection
|
|
207
237
|
*/
|
|
208
|
-
declare function analyzeDocsImpact(diff: SpecDiff, markdownFiles: MarkdownDocFile[], newExportNames?: string[]): DocsImpactResult;
|
|
238
|
+
declare function analyzeDocsImpact(diff: SpecDiff, markdownFiles: MarkdownDocFile[], newExportNames?: string[], memberChanges?: MemberChange[]): DocsImpactResult;
|
|
209
239
|
/**
|
|
210
240
|
* Find references to deprecated exports
|
|
211
241
|
*/
|
|
@@ -225,13 +255,15 @@ declare function getDocumentedExports(markdownFiles: MarkdownDocFile[], exportNa
|
|
|
225
255
|
* Get all exports that lack documentation
|
|
226
256
|
*/
|
|
227
257
|
declare function getUndocumentedExports(markdownFiles: MarkdownDocFile[], exportNames: string[]): string[];
|
|
228
|
-
import { OpenPkg as
|
|
258
|
+
import { OpenPkg as OpenPkg3, SpecDiff as SpecDiff2 } from "@openpkg-ts/spec";
|
|
229
259
|
/**
|
|
230
260
|
* Extended spec diff result with docs impact
|
|
231
261
|
*/
|
|
232
262
|
interface SpecDiffWithDocs extends SpecDiff2 {
|
|
233
263
|
/** Docs impact analysis (only present if markdown files provided) */
|
|
234
264
|
docsImpact?: DocsImpactResult;
|
|
265
|
+
/** Member-level changes for classes (methods added/removed/changed) */
|
|
266
|
+
memberChanges?: MemberChange[];
|
|
235
267
|
}
|
|
236
268
|
/**
|
|
237
269
|
* Options for diffSpecWithDocs
|
|
@@ -263,7 +295,7 @@ interface DiffWithDocsOptions {
|
|
|
263
295
|
* }
|
|
264
296
|
* ```
|
|
265
297
|
*/
|
|
266
|
-
declare function diffSpecWithDocs(oldSpec:
|
|
298
|
+
declare function diffSpecWithDocs(oldSpec: OpenPkg3, newSpec: OpenPkg3, options?: DiffWithDocsOptions): SpecDiffWithDocs;
|
|
267
299
|
/**
|
|
268
300
|
* Check if a diff has any docs impact
|
|
269
301
|
*/
|
|
@@ -276,6 +308,7 @@ declare function getDocsImpactSummary(diff: SpecDiffWithDocs): {
|
|
|
276
308
|
impactedReferenceCount: number;
|
|
277
309
|
missingDocsCount: number;
|
|
278
310
|
totalIssues: number;
|
|
311
|
+
memberChangesCount: number;
|
|
279
312
|
};
|
|
280
313
|
interface DocCovOptions {
|
|
281
314
|
includePrivate?: boolean;
|
|
@@ -466,7 +499,7 @@ declare class DocCov {
|
|
|
466
499
|
declare function analyze(code: string, options?: AnalyzeOptions): Promise<OpenPkgSpec>;
|
|
467
500
|
declare function analyzeFile(filePath: string, options?: AnalyzeOptions): Promise<OpenPkgSpec>;
|
|
468
501
|
/** @deprecated Use DocCov instead */
|
|
469
|
-
declare const
|
|
502
|
+
declare const OpenPkg4: typeof DocCov;
|
|
470
503
|
/**
|
|
471
504
|
* Project detection types for I/O-agnostic project analysis.
|
|
472
505
|
* Used by both CLI (NodeFileSystem) and API (SandboxFileSystem).
|
|
@@ -723,4 +756,4 @@ declare function readPackageJson(fs: FileSystem, dir: string): Promise<PackageJs
|
|
|
723
756
|
* ```
|
|
724
757
|
*/
|
|
725
758
|
declare function analyzeProject2(fs: FileSystem, options?: AnalyzeProjectOptions): Promise<ProjectInfo>;
|
|
726
|
-
export { serializeJSDoc, safeParseJson, runExamplesWithPackage, runExamples, runExample, readPackageJson, parseMarkdownFiles, parseMarkdownFile, parseJSDocToPatch, parseAssertions, mergeFixes, isFixableDrift, isExecutableLang, hasNonAssertionComments, hasDocsImpact, hasDocsForExport, getUndocumentedExports, getRunCommand, getPrimaryBuildScript, getInstallCommand, getDocumentedExports, getDocsImpactSummary, generateFixesForExport, generateFix, formatPackageList, findRemovedReferences, findPackageByName, findJSDocLocation, findExportReferences, findDeprecatedReferences, extractPackageSpec, extractImports, extractFunctionCalls, diffSpecWithDocs, detectPackageManager, detectMonorepo, detectExampleRuntimeErrors, detectExampleAssertionFailures, detectEntryPoint, detectBuildInfo, createSourceFile, categorizeDrifts, blockReferencesExport, applyPatchToJSDoc, applyEdits, analyzeProject2 as analyzeProject, analyzeFile, analyzeDocsImpact, analyze, WorkspacePackage, SpecDiffWithDocs, SandboxFileSystem, RunExamplesWithPackageResult, RunExamplesWithPackageOptions, RunExampleOptions, ProjectInfo, PackageManagerInfo, PackageManager, PackageJson, PackageExports, OpenPkgSpec, OpenPkgOptions,
|
|
759
|
+
export { serializeJSDoc, safeParseJson, runExamplesWithPackage, runExamples, runExample, readPackageJson, parseMarkdownFiles, parseMarkdownFile, parseJSDocToPatch, parseAssertions, mergeFixes, isFixableDrift, isExecutableLang, hasNonAssertionComments, hasDocsImpact, hasDocsForExport, getUndocumentedExports, getRunCommand, getPrimaryBuildScript, getInstallCommand, getDocumentedExports, getDocsImpactSummary, generateFixesForExport, generateFix, formatPackageList, findRemovedReferences, findPackageByName, findJSDocLocation, findExportReferences, findDeprecatedReferences, extractPackageSpec, extractImports, extractFunctionCalls, diffSpecWithDocs, detectPackageManager, detectMonorepo, detectExampleRuntimeErrors, detectExampleAssertionFailures, detectEntryPoint, detectBuildInfo, createSourceFile, categorizeDrifts, blockReferencesExport, applyPatchToJSDoc, applyEdits, analyzeProject2 as analyzeProject, analyzeFile, analyzeDocsImpact, analyze, WorkspacePackage, SpecDiffWithDocs, SandboxFileSystem, RunExamplesWithPackageResult, RunExamplesWithPackageOptions, RunExampleOptions, ProjectInfo, PackageManagerInfo, PackageManager, PackageJson, PackageExports, OpenPkgSpec, OpenPkgOptions, OpenPkg4 as OpenPkg, NodeFileSystem, MonorepoType, MonorepoInfo, MarkdownDocFile, MarkdownCodeBlock, JSDocTag, JSDocReturn, JSDocPatch, JSDocParam, JSDocEdit, FixType, FixSuggestion, FilterOptions, FileSystem, ExportReference, ExampleRunResult, EntryPointSource, EntryPointInfo, DocsImpactResult, DocsImpactReference, DocsImpact, DocsChangeType, DocCovOptions, DocCov, DiffWithDocsOptions, Diagnostic, BuildInfo, ApplyEditsResult, AnalyzeProjectOptions, AnalyzeOptions, AnalysisResult };
|
package/dist/index.js
CHANGED
|
@@ -1107,6 +1107,39 @@ function extractFunctionCalls(code) {
|
|
|
1107
1107
|
}
|
|
1108
1108
|
return Array.from(calls);
|
|
1109
1109
|
}
|
|
1110
|
+
function extractMethodCalls(code) {
|
|
1111
|
+
const calls = [];
|
|
1112
|
+
const lines = code.split(`
|
|
1113
|
+
`);
|
|
1114
|
+
const methodCallRegex = /\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\.\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/g;
|
|
1115
|
+
const skipObjects = new Set(["console", "Math", "JSON", "Object", "Array", "String", "Number"]);
|
|
1116
|
+
for (let lineIndex = 0;lineIndex < lines.length; lineIndex++) {
|
|
1117
|
+
const line = lines[lineIndex];
|
|
1118
|
+
let match;
|
|
1119
|
+
methodCallRegex.lastIndex = 0;
|
|
1120
|
+
while ((match = methodCallRegex.exec(line)) !== null) {
|
|
1121
|
+
const objectName = match[1];
|
|
1122
|
+
const methodName = match[2];
|
|
1123
|
+
if (skipObjects.has(objectName)) {
|
|
1124
|
+
continue;
|
|
1125
|
+
}
|
|
1126
|
+
calls.push({
|
|
1127
|
+
objectName,
|
|
1128
|
+
methodName,
|
|
1129
|
+
line: lineIndex,
|
|
1130
|
+
context: line.trim()
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
return calls;
|
|
1135
|
+
}
|
|
1136
|
+
function hasInstantiation(code, className) {
|
|
1137
|
+
const regex = new RegExp(`\\bnew\\s+${escapeRegex(className)}\\s*\\(`, "g");
|
|
1138
|
+
return regex.test(code);
|
|
1139
|
+
}
|
|
1140
|
+
function escapeRegex(str) {
|
|
1141
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1142
|
+
}
|
|
1110
1143
|
function findExportReferences(files, exportNames) {
|
|
1111
1144
|
const references = [];
|
|
1112
1145
|
const exportSet = new Set(exportNames);
|
|
@@ -1174,27 +1207,99 @@ function getChangeType(exportName, diff) {
|
|
|
1174
1207
|
}
|
|
1175
1208
|
return null;
|
|
1176
1209
|
}
|
|
1177
|
-
function
|
|
1210
|
+
function mapMemberChangeType(memberChangeType) {
|
|
1211
|
+
switch (memberChangeType) {
|
|
1212
|
+
case "removed":
|
|
1213
|
+
return "method-removed";
|
|
1214
|
+
case "signature-changed":
|
|
1215
|
+
return "method-changed";
|
|
1216
|
+
default:
|
|
1217
|
+
return "signature-changed";
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
function analyzeDocsImpact(diff, markdownFiles, newExportNames = [], memberChanges) {
|
|
1178
1221
|
const changedExports = [
|
|
1179
1222
|
...diff.breaking
|
|
1180
1223
|
];
|
|
1181
|
-
const
|
|
1224
|
+
const memberChangesByMethod = new Map;
|
|
1225
|
+
if (memberChanges) {
|
|
1226
|
+
for (const mc of memberChanges) {
|
|
1227
|
+
memberChangesByMethod.set(mc.memberName, mc);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
const classesWithMemberChanges = new Set(memberChanges?.map((mc) => mc.className) ?? []);
|
|
1182
1231
|
const impactByFile = new Map;
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
if (!changeType)
|
|
1186
|
-
continue;
|
|
1187
|
-
let impact = impactByFile.get(ref.file);
|
|
1232
|
+
const addReference = (file, ref) => {
|
|
1233
|
+
let impact = impactByFile.get(file);
|
|
1188
1234
|
if (!impact) {
|
|
1189
|
-
impact = { file
|
|
1190
|
-
impactByFile.set(
|
|
1191
|
-
}
|
|
1192
|
-
impact.references.push(
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1235
|
+
impact = { file, references: [] };
|
|
1236
|
+
impactByFile.set(file, impact);
|
|
1237
|
+
}
|
|
1238
|
+
impact.references.push(ref);
|
|
1239
|
+
};
|
|
1240
|
+
for (const mdFile of markdownFiles) {
|
|
1241
|
+
for (const block of mdFile.codeBlocks) {
|
|
1242
|
+
const reportedRefs = new Set;
|
|
1243
|
+
if (memberChanges && memberChanges.length > 0) {
|
|
1244
|
+
const methodCalls = extractMethodCalls(block.code);
|
|
1245
|
+
for (const call of methodCalls) {
|
|
1246
|
+
const memberChange = memberChangesByMethod.get(call.methodName);
|
|
1247
|
+
if (memberChange) {
|
|
1248
|
+
const refKey = `${mdFile.path}:${block.lineStart + call.line}:${call.methodName}`;
|
|
1249
|
+
if (!reportedRefs.has(refKey)) {
|
|
1250
|
+
reportedRefs.add(refKey);
|
|
1251
|
+
addReference(mdFile.path, {
|
|
1252
|
+
exportName: memberChange.className,
|
|
1253
|
+
memberName: call.methodName,
|
|
1254
|
+
memberChangeType: memberChange.changeType,
|
|
1255
|
+
changeType: mapMemberChangeType(memberChange.changeType),
|
|
1256
|
+
replacementSuggestion: memberChange.suggestion,
|
|
1257
|
+
line: block.lineStart + call.line,
|
|
1258
|
+
context: call.context,
|
|
1259
|
+
isInstantiation: false
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
for (const className of classesWithMemberChanges) {
|
|
1265
|
+
if (hasInstantiation(block.code, className)) {
|
|
1266
|
+
const refKey = `${mdFile.path}:${block.lineStart}:new ${className}`;
|
|
1267
|
+
if (!reportedRefs.has(refKey)) {
|
|
1268
|
+
const hasMethodRefs = Array.from(reportedRefs).some((key) => key.startsWith(`${mdFile.path}:`) && memberChanges.some((mc) => mc.className === className && key.includes(mc.memberName)));
|
|
1269
|
+
if (!hasMethodRefs) {
|
|
1270
|
+
reportedRefs.add(refKey);
|
|
1271
|
+
addReference(mdFile.path, {
|
|
1272
|
+
exportName: className,
|
|
1273
|
+
line: block.lineStart,
|
|
1274
|
+
changeType: "signature-changed",
|
|
1275
|
+
context: `new ${className}(...)`,
|
|
1276
|
+
isInstantiation: true
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
const exportsWithoutMemberChanges = changedExports.filter((name) => !classesWithMemberChanges.has(name));
|
|
1284
|
+
if (exportsWithoutMemberChanges.length > 0) {
|
|
1285
|
+
const refs = findExportReferences([{ ...mdFile, codeBlocks: [block] }], exportsWithoutMemberChanges);
|
|
1286
|
+
for (const ref of refs) {
|
|
1287
|
+
const changeType = getChangeType(ref.exportName, diff);
|
|
1288
|
+
if (!changeType)
|
|
1289
|
+
continue;
|
|
1290
|
+
const refKey = `${ref.file}:${ref.line}:${ref.exportName}`;
|
|
1291
|
+
if (!reportedRefs.has(refKey)) {
|
|
1292
|
+
reportedRefs.add(refKey);
|
|
1293
|
+
addReference(ref.file, {
|
|
1294
|
+
exportName: ref.exportName,
|
|
1295
|
+
line: ref.line,
|
|
1296
|
+
changeType,
|
|
1297
|
+
context: ref.context
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1198
1303
|
}
|
|
1199
1304
|
const documentedExports = new Set;
|
|
1200
1305
|
for (const file of markdownFiles) {
|
|
@@ -1208,10 +1313,11 @@ function analyzeDocsImpact(diff, markdownFiles, newExportNames = []) {
|
|
|
1208
1313
|
}
|
|
1209
1314
|
const missingDocs = diff.nonBreaking.filter((name) => !documentedExports.has(name));
|
|
1210
1315
|
const totalCodeBlocks = markdownFiles.reduce((sum, f) => sum + f.codeBlocks.length, 0);
|
|
1211
|
-
const allReferences = findExportReferences(markdownFiles, [
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1316
|
+
const allReferences = findExportReferences(markdownFiles, [...changedExports, ...diff.nonBreaking]);
|
|
1317
|
+
let impactedReferences = 0;
|
|
1318
|
+
for (const impact of impactByFile.values()) {
|
|
1319
|
+
impactedReferences += impact.references.length;
|
|
1320
|
+
}
|
|
1215
1321
|
return {
|
|
1216
1322
|
impactedFiles: Array.from(impactByFile.values()),
|
|
1217
1323
|
missingDocs,
|
|
@@ -1219,7 +1325,7 @@ function analyzeDocsImpact(diff, markdownFiles, newExportNames = []) {
|
|
|
1219
1325
|
filesScanned: markdownFiles.length,
|
|
1220
1326
|
codeBlocksFound: totalCodeBlocks,
|
|
1221
1327
|
referencesFound: allReferences.length,
|
|
1222
|
-
impactedReferences
|
|
1328
|
+
impactedReferences
|
|
1223
1329
|
}
|
|
1224
1330
|
};
|
|
1225
1331
|
}
|
|
@@ -1246,18 +1352,213 @@ function getUndocumentedExports(markdownFiles, exportNames) {
|
|
|
1246
1352
|
const documented = new Set(getDocumentedExports(markdownFiles, exportNames));
|
|
1247
1353
|
return exportNames.filter((name) => !documented.has(name));
|
|
1248
1354
|
}
|
|
1355
|
+
// src/markdown/member-diff.ts
|
|
1356
|
+
function diffMemberChanges(oldSpec, newSpec, changedClassNames) {
|
|
1357
|
+
const changes = [];
|
|
1358
|
+
const oldExportMap = toExportMap(oldSpec.exports ?? []);
|
|
1359
|
+
const newExportMap = toExportMap(newSpec.exports ?? []);
|
|
1360
|
+
for (const className of changedClassNames) {
|
|
1361
|
+
const oldExport = oldExportMap.get(className);
|
|
1362
|
+
const newExport = newExportMap.get(className);
|
|
1363
|
+
if (!oldExport?.members && !newExport?.members) {
|
|
1364
|
+
continue;
|
|
1365
|
+
}
|
|
1366
|
+
const oldMembers = toMemberMap(oldExport?.members ?? []);
|
|
1367
|
+
const newMembers = toMemberMap(newExport?.members ?? []);
|
|
1368
|
+
const addedMemberNames = [];
|
|
1369
|
+
for (const [memberName, newMember] of newMembers) {
|
|
1370
|
+
if (!oldMembers.has(memberName)) {
|
|
1371
|
+
addedMemberNames.push(memberName);
|
|
1372
|
+
changes.push({
|
|
1373
|
+
className,
|
|
1374
|
+
memberName,
|
|
1375
|
+
memberKind: getMemberKind(newMember),
|
|
1376
|
+
changeType: "added",
|
|
1377
|
+
newSignature: formatSignature(newMember)
|
|
1378
|
+
});
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
for (const [memberName, oldMember] of oldMembers) {
|
|
1382
|
+
if (!newMembers.has(memberName)) {
|
|
1383
|
+
const suggestion = findSimilarMember(memberName, newMembers, addedMemberNames);
|
|
1384
|
+
changes.push({
|
|
1385
|
+
className,
|
|
1386
|
+
memberName,
|
|
1387
|
+
memberKind: getMemberKind(oldMember),
|
|
1388
|
+
changeType: "removed",
|
|
1389
|
+
oldSignature: formatSignature(oldMember),
|
|
1390
|
+
suggestion
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
for (const [memberName, oldMember] of oldMembers) {
|
|
1395
|
+
const newMember = newMembers.get(memberName);
|
|
1396
|
+
if (newMember && hasSignatureChanged(oldMember, newMember)) {
|
|
1397
|
+
changes.push({
|
|
1398
|
+
className,
|
|
1399
|
+
memberName,
|
|
1400
|
+
memberKind: getMemberKind(newMember),
|
|
1401
|
+
changeType: "signature-changed",
|
|
1402
|
+
oldSignature: formatSignature(oldMember),
|
|
1403
|
+
newSignature: formatSignature(newMember)
|
|
1404
|
+
});
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
return changes;
|
|
1409
|
+
}
|
|
1410
|
+
function toExportMap(exports) {
|
|
1411
|
+
const map = new Map;
|
|
1412
|
+
for (const exp of exports) {
|
|
1413
|
+
if (exp?.name) {
|
|
1414
|
+
map.set(exp.name, exp);
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
return map;
|
|
1418
|
+
}
|
|
1419
|
+
function toMemberMap(members) {
|
|
1420
|
+
const map = new Map;
|
|
1421
|
+
for (const member of members) {
|
|
1422
|
+
if (member?.name) {
|
|
1423
|
+
map.set(member.name, member);
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
return map;
|
|
1427
|
+
}
|
|
1428
|
+
function getMemberKind(member) {
|
|
1429
|
+
switch (member.kind) {
|
|
1430
|
+
case "method":
|
|
1431
|
+
return "method";
|
|
1432
|
+
case "property":
|
|
1433
|
+
return "property";
|
|
1434
|
+
case "accessor":
|
|
1435
|
+
return "accessor";
|
|
1436
|
+
case "constructor":
|
|
1437
|
+
return "constructor";
|
|
1438
|
+
default:
|
|
1439
|
+
return "method";
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
function formatSignature(member) {
|
|
1443
|
+
if (!member.signatures?.length) {
|
|
1444
|
+
return member.name ?? "";
|
|
1445
|
+
}
|
|
1446
|
+
const sig = member.signatures[0];
|
|
1447
|
+
const params = sig.parameters?.map((p) => {
|
|
1448
|
+
const optional = p.required === false ? "?" : "";
|
|
1449
|
+
return `${p.name}${optional}`;
|
|
1450
|
+
}) ?? [];
|
|
1451
|
+
return `${member.name}(${params.join(", ")})`;
|
|
1452
|
+
}
|
|
1453
|
+
function hasSignatureChanged(oldMember, newMember) {
|
|
1454
|
+
const oldSigs = oldMember.signatures ?? [];
|
|
1455
|
+
const newSigs = newMember.signatures ?? [];
|
|
1456
|
+
if (oldSigs.length !== newSigs.length) {
|
|
1457
|
+
return true;
|
|
1458
|
+
}
|
|
1459
|
+
for (let i = 0;i < oldSigs.length; i++) {
|
|
1460
|
+
if (!signaturesEqual(oldSigs[i], newSigs[i])) {
|
|
1461
|
+
return true;
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
return false;
|
|
1465
|
+
}
|
|
1466
|
+
function signaturesEqual(a, b) {
|
|
1467
|
+
const aParams = a.parameters ?? [];
|
|
1468
|
+
const bParams = b.parameters ?? [];
|
|
1469
|
+
if (aParams.length !== bParams.length) {
|
|
1470
|
+
return false;
|
|
1471
|
+
}
|
|
1472
|
+
for (let i = 0;i < aParams.length; i++) {
|
|
1473
|
+
const ap = aParams[i];
|
|
1474
|
+
const bp = bParams[i];
|
|
1475
|
+
if (ap.name !== bp.name)
|
|
1476
|
+
return false;
|
|
1477
|
+
if (ap.required !== bp.required)
|
|
1478
|
+
return false;
|
|
1479
|
+
if (JSON.stringify(ap.schema) !== JSON.stringify(bp.schema))
|
|
1480
|
+
return false;
|
|
1481
|
+
}
|
|
1482
|
+
if (JSON.stringify(a.returns) !== JSON.stringify(b.returns)) {
|
|
1483
|
+
return false;
|
|
1484
|
+
}
|
|
1485
|
+
return true;
|
|
1486
|
+
}
|
|
1487
|
+
function findSimilarMember(removedName, newMembers, addedMembers) {
|
|
1488
|
+
const candidates = addedMembers.length > 0 ? addedMembers : Array.from(newMembers.keys());
|
|
1489
|
+
let bestMatch;
|
|
1490
|
+
let bestScore = 0;
|
|
1491
|
+
for (const name of candidates) {
|
|
1492
|
+
if (name === removedName)
|
|
1493
|
+
continue;
|
|
1494
|
+
const removedWords = splitCamelCase(removedName);
|
|
1495
|
+
const newWords = splitCamelCase(name);
|
|
1496
|
+
let matchingWords = 0;
|
|
1497
|
+
let suffixMatch = false;
|
|
1498
|
+
if (removedWords.length > 0 && newWords.length > 0) {
|
|
1499
|
+
const removedSuffix = removedWords[removedWords.length - 1];
|
|
1500
|
+
const newSuffix = newWords[newWords.length - 1];
|
|
1501
|
+
if (removedSuffix === newSuffix) {
|
|
1502
|
+
suffixMatch = true;
|
|
1503
|
+
matchingWords += 2;
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
for (const word of removedWords) {
|
|
1507
|
+
if (newWords.includes(word)) {
|
|
1508
|
+
matchingWords++;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
const wordScore = matchingWords / Math.max(removedWords.length, newWords.length);
|
|
1512
|
+
const editDistance = levenshteinDistance(removedName.toLowerCase(), name.toLowerCase());
|
|
1513
|
+
const maxLen = Math.max(removedName.length, name.length);
|
|
1514
|
+
const levenScore = 1 - editDistance / maxLen;
|
|
1515
|
+
const totalScore = suffixMatch ? wordScore * 1.5 + levenScore : wordScore + levenScore * 0.5;
|
|
1516
|
+
if (totalScore > bestScore && totalScore >= 0.5) {
|
|
1517
|
+
bestScore = totalScore;
|
|
1518
|
+
bestMatch = name;
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
return bestMatch ? `Use ${bestMatch} instead` : undefined;
|
|
1522
|
+
}
|
|
1523
|
+
function levenshteinDistance(a, b) {
|
|
1524
|
+
const matrix = [];
|
|
1525
|
+
for (let i = 0;i <= b.length; i++) {
|
|
1526
|
+
matrix[i] = [i];
|
|
1527
|
+
}
|
|
1528
|
+
for (let j = 0;j <= a.length; j++) {
|
|
1529
|
+
matrix[0][j] = j;
|
|
1530
|
+
}
|
|
1531
|
+
for (let i = 1;i <= b.length; i++) {
|
|
1532
|
+
for (let j = 1;j <= a.length; j++) {
|
|
1533
|
+
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
1534
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
1535
|
+
} else {
|
|
1536
|
+
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1);
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
return matrix[b.length][a.length];
|
|
1541
|
+
}
|
|
1542
|
+
function splitCamelCase(str) {
|
|
1543
|
+
return str.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().split(" ");
|
|
1544
|
+
}
|
|
1249
1545
|
// src/markdown/diff-with-docs.ts
|
|
1250
1546
|
import { diffSpec } from "@openpkg-ts/spec";
|
|
1251
1547
|
function diffSpecWithDocs(oldSpec, newSpec, options = {}) {
|
|
1252
1548
|
const baseDiff = diffSpec(oldSpec, newSpec);
|
|
1549
|
+
const memberChanges = diffMemberChanges(oldSpec, newSpec, baseDiff.breaking);
|
|
1253
1550
|
if (!options.markdownFiles?.length) {
|
|
1254
|
-
return
|
|
1551
|
+
return {
|
|
1552
|
+
...baseDiff,
|
|
1553
|
+
memberChanges: memberChanges.length > 0 ? memberChanges : undefined
|
|
1554
|
+
};
|
|
1255
1555
|
}
|
|
1256
1556
|
const newExportNames = newSpec.exports?.map((e) => e.name) ?? [];
|
|
1257
|
-
const docsImpact = analyzeDocsImpact(baseDiff, options.markdownFiles, newExportNames);
|
|
1557
|
+
const docsImpact = analyzeDocsImpact(baseDiff, options.markdownFiles, newExportNames, memberChanges);
|
|
1258
1558
|
return {
|
|
1259
1559
|
...baseDiff,
|
|
1260
|
-
docsImpact
|
|
1560
|
+
docsImpact,
|
|
1561
|
+
memberChanges: memberChanges.length > 0 ? memberChanges : undefined
|
|
1261
1562
|
};
|
|
1262
1563
|
}
|
|
1263
1564
|
function hasDocsImpact(diff) {
|
|
@@ -1271,7 +1572,8 @@ function getDocsImpactSummary(diff) {
|
|
|
1271
1572
|
impactedFileCount: 0,
|
|
1272
1573
|
impactedReferenceCount: 0,
|
|
1273
1574
|
missingDocsCount: 0,
|
|
1274
|
-
totalIssues: 0
|
|
1575
|
+
totalIssues: 0,
|
|
1576
|
+
memberChangesCount: diff.memberChanges?.length ?? 0
|
|
1275
1577
|
};
|
|
1276
1578
|
}
|
|
1277
1579
|
const impactedFileCount = diff.docsImpact.impactedFiles.length;
|
|
@@ -1281,7 +1583,8 @@ function getDocsImpactSummary(diff) {
|
|
|
1281
1583
|
impactedFileCount,
|
|
1282
1584
|
impactedReferenceCount,
|
|
1283
1585
|
missingDocsCount,
|
|
1284
|
-
totalIssues: impactedReferenceCount + missingDocsCount
|
|
1586
|
+
totalIssues: impactedReferenceCount + missingDocsCount,
|
|
1587
|
+
memberChangesCount: diff.memberChanges?.length ?? 0
|
|
1285
1588
|
};
|
|
1286
1589
|
}
|
|
1287
1590
|
// src/analysis/run-analysis.ts
|
|
@@ -1299,101 +1602,6 @@ var resolvedTypeScriptModule = (() => {
|
|
|
1299
1602
|
})();
|
|
1300
1603
|
var ts2 = resolvedTypeScriptModule;
|
|
1301
1604
|
|
|
1302
|
-
// src/analysis/context.ts
|
|
1303
|
-
import * as path2 from "node:path";
|
|
1304
|
-
|
|
1305
|
-
// src/options.ts
|
|
1306
|
-
var DEFAULT_OPTIONS = {
|
|
1307
|
-
includePrivate: false,
|
|
1308
|
-
followImports: true
|
|
1309
|
-
};
|
|
1310
|
-
function normalizeDocCovOptions(options = {}) {
|
|
1311
|
-
return {
|
|
1312
|
-
...DEFAULT_OPTIONS,
|
|
1313
|
-
...options
|
|
1314
|
-
};
|
|
1315
|
-
}
|
|
1316
|
-
var normalizeOpenPkgOptions = normalizeDocCovOptions;
|
|
1317
|
-
|
|
1318
|
-
// src/analysis/program.ts
|
|
1319
|
-
import * as path from "node:path";
|
|
1320
|
-
var DEFAULT_COMPILER_OPTIONS = {
|
|
1321
|
-
target: ts2.ScriptTarget.Latest,
|
|
1322
|
-
module: ts2.ModuleKind.CommonJS,
|
|
1323
|
-
lib: ["lib.es2021.d.ts"],
|
|
1324
|
-
declaration: true,
|
|
1325
|
-
moduleResolution: ts2.ModuleResolutionKind.NodeJs
|
|
1326
|
-
};
|
|
1327
|
-
function createProgram({
|
|
1328
|
-
entryFile,
|
|
1329
|
-
baseDir = path.dirname(entryFile),
|
|
1330
|
-
content
|
|
1331
|
-
}) {
|
|
1332
|
-
const configPath = ts2.findConfigFile(baseDir, ts2.sys.fileExists, "tsconfig.json");
|
|
1333
|
-
let compilerOptions = { ...DEFAULT_COMPILER_OPTIONS };
|
|
1334
|
-
if (configPath) {
|
|
1335
|
-
const configFile = ts2.readConfigFile(configPath, ts2.sys.readFile);
|
|
1336
|
-
const parsedConfig = ts2.parseJsonConfigFileContent(configFile.config, ts2.sys, path.dirname(configPath));
|
|
1337
|
-
compilerOptions = { ...compilerOptions, ...parsedConfig.options };
|
|
1338
|
-
}
|
|
1339
|
-
const allowJsVal = compilerOptions.allowJs;
|
|
1340
|
-
if (typeof allowJsVal === "boolean" && allowJsVal) {
|
|
1341
|
-
compilerOptions = { ...compilerOptions, allowJs: false, checkJs: false };
|
|
1342
|
-
}
|
|
1343
|
-
const compilerHost = ts2.createCompilerHost(compilerOptions, true);
|
|
1344
|
-
let inMemorySource;
|
|
1345
|
-
if (content !== undefined) {
|
|
1346
|
-
inMemorySource = ts2.createSourceFile(entryFile, content, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TS);
|
|
1347
|
-
const originalGetSourceFile = compilerHost.getSourceFile.bind(compilerHost);
|
|
1348
|
-
compilerHost.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
1349
|
-
if (fileName === entryFile) {
|
|
1350
|
-
return inMemorySource;
|
|
1351
|
-
}
|
|
1352
|
-
return originalGetSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile);
|
|
1353
|
-
};
|
|
1354
|
-
}
|
|
1355
|
-
const program = ts2.createProgram([entryFile], compilerOptions, compilerHost);
|
|
1356
|
-
const sourceFile = inMemorySource ?? program.getSourceFile(entryFile);
|
|
1357
|
-
return {
|
|
1358
|
-
program,
|
|
1359
|
-
compilerHost,
|
|
1360
|
-
compilerOptions,
|
|
1361
|
-
sourceFile,
|
|
1362
|
-
configPath
|
|
1363
|
-
};
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
// src/analysis/context.ts
|
|
1367
|
-
function createAnalysisContext({
|
|
1368
|
-
entryFile,
|
|
1369
|
-
packageDir,
|
|
1370
|
-
content,
|
|
1371
|
-
options
|
|
1372
|
-
}) {
|
|
1373
|
-
const baseDir = packageDir ?? path2.dirname(entryFile);
|
|
1374
|
-
const normalizedOptions = normalizeOpenPkgOptions(options);
|
|
1375
|
-
const programResult = createProgram({ entryFile, baseDir, content });
|
|
1376
|
-
if (!programResult.sourceFile) {
|
|
1377
|
-
throw new Error(`Could not load ${entryFile}`);
|
|
1378
|
-
}
|
|
1379
|
-
return {
|
|
1380
|
-
entryFile,
|
|
1381
|
-
baseDir,
|
|
1382
|
-
program: programResult.program,
|
|
1383
|
-
checker: programResult.program.getTypeChecker(),
|
|
1384
|
-
sourceFile: programResult.sourceFile,
|
|
1385
|
-
compilerOptions: programResult.compilerOptions,
|
|
1386
|
-
compilerHost: programResult.compilerHost,
|
|
1387
|
-
options: normalizedOptions,
|
|
1388
|
-
configPath: programResult.configPath
|
|
1389
|
-
};
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
|
-
// src/analysis/spec-builder.ts
|
|
1393
|
-
import * as fs from "node:fs";
|
|
1394
|
-
import * as path3 from "node:path";
|
|
1395
|
-
import { SCHEMA_URL } from "@openpkg-ts/spec";
|
|
1396
|
-
|
|
1397
1605
|
// src/utils/type-utils.ts
|
|
1398
1606
|
function getTypeId(type, typeChecker) {
|
|
1399
1607
|
const internalId = type.id;
|
|
@@ -1515,6 +1723,30 @@ function collectReferencedTypesFromNode(node, typeChecker, referencedTypes) {
|
|
|
1515
1723
|
});
|
|
1516
1724
|
}
|
|
1517
1725
|
function isBuiltInType(name) {
|
|
1726
|
+
if (name.length === 1 && /^[A-Z]$/.test(name)) {
|
|
1727
|
+
return true;
|
|
1728
|
+
}
|
|
1729
|
+
if (/^T[A-Z][a-zA-Z]*$/.test(name)) {
|
|
1730
|
+
return true;
|
|
1731
|
+
}
|
|
1732
|
+
const libraryInternals = [
|
|
1733
|
+
"UnionStatic",
|
|
1734
|
+
"IntersectStatic",
|
|
1735
|
+
"ObjectStatic",
|
|
1736
|
+
"ArrayStatic",
|
|
1737
|
+
"StaticDecode",
|
|
1738
|
+
"StaticEncode",
|
|
1739
|
+
"ZodType",
|
|
1740
|
+
"ZodObject",
|
|
1741
|
+
"ZodString",
|
|
1742
|
+
"ZodNumber",
|
|
1743
|
+
"ZodArray",
|
|
1744
|
+
"ZodUnion",
|
|
1745
|
+
"ZodIntersection"
|
|
1746
|
+
];
|
|
1747
|
+
if (libraryInternals.includes(name)) {
|
|
1748
|
+
return true;
|
|
1749
|
+
}
|
|
1518
1750
|
const builtIns = [
|
|
1519
1751
|
"string",
|
|
1520
1752
|
"number",
|
|
@@ -1523,6 +1755,8 @@ function isBuiltInType(name) {
|
|
|
1523
1755
|
"symbol",
|
|
1524
1756
|
"undefined",
|
|
1525
1757
|
"null",
|
|
1758
|
+
"true",
|
|
1759
|
+
"false",
|
|
1526
1760
|
"any",
|
|
1527
1761
|
"unknown",
|
|
1528
1762
|
"never",
|
|
@@ -1566,11 +1800,125 @@ function isBuiltInType(name) {
|
|
|
1566
1800
|
"Proxy",
|
|
1567
1801
|
"Intl",
|
|
1568
1802
|
"globalThis",
|
|
1803
|
+
"Record",
|
|
1804
|
+
"Partial",
|
|
1805
|
+
"Required",
|
|
1806
|
+
"Readonly",
|
|
1807
|
+
"Pick",
|
|
1808
|
+
"Omit",
|
|
1809
|
+
"Exclude",
|
|
1810
|
+
"Extract",
|
|
1811
|
+
"NonNullable",
|
|
1812
|
+
"ReturnType",
|
|
1813
|
+
"Parameters",
|
|
1814
|
+
"InstanceType",
|
|
1815
|
+
"ConstructorParameters",
|
|
1816
|
+
"Awaited",
|
|
1817
|
+
"ThisType",
|
|
1818
|
+
"Uppercase",
|
|
1819
|
+
"Lowercase",
|
|
1820
|
+
"Capitalize",
|
|
1821
|
+
"Uncapitalize",
|
|
1569
1822
|
"__type"
|
|
1570
1823
|
];
|
|
1571
1824
|
return builtIns.includes(name);
|
|
1572
1825
|
}
|
|
1573
1826
|
|
|
1827
|
+
// src/analysis/context.ts
|
|
1828
|
+
import * as path2 from "node:path";
|
|
1829
|
+
|
|
1830
|
+
// src/options.ts
|
|
1831
|
+
var DEFAULT_OPTIONS = {
|
|
1832
|
+
includePrivate: false,
|
|
1833
|
+
followImports: true
|
|
1834
|
+
};
|
|
1835
|
+
function normalizeDocCovOptions(options = {}) {
|
|
1836
|
+
return {
|
|
1837
|
+
...DEFAULT_OPTIONS,
|
|
1838
|
+
...options
|
|
1839
|
+
};
|
|
1840
|
+
}
|
|
1841
|
+
var normalizeOpenPkgOptions = normalizeDocCovOptions;
|
|
1842
|
+
|
|
1843
|
+
// src/analysis/program.ts
|
|
1844
|
+
import * as path from "node:path";
|
|
1845
|
+
var DEFAULT_COMPILER_OPTIONS = {
|
|
1846
|
+
target: ts2.ScriptTarget.Latest,
|
|
1847
|
+
module: ts2.ModuleKind.CommonJS,
|
|
1848
|
+
lib: ["lib.es2021.d.ts"],
|
|
1849
|
+
declaration: true,
|
|
1850
|
+
moduleResolution: ts2.ModuleResolutionKind.NodeJs
|
|
1851
|
+
};
|
|
1852
|
+
function createProgram({
|
|
1853
|
+
entryFile,
|
|
1854
|
+
baseDir = path.dirname(entryFile),
|
|
1855
|
+
content
|
|
1856
|
+
}) {
|
|
1857
|
+
const configPath = ts2.findConfigFile(baseDir, ts2.sys.fileExists, "tsconfig.json");
|
|
1858
|
+
let compilerOptions = { ...DEFAULT_COMPILER_OPTIONS };
|
|
1859
|
+
if (configPath) {
|
|
1860
|
+
const configFile = ts2.readConfigFile(configPath, ts2.sys.readFile);
|
|
1861
|
+
const parsedConfig = ts2.parseJsonConfigFileContent(configFile.config, ts2.sys, path.dirname(configPath));
|
|
1862
|
+
compilerOptions = { ...compilerOptions, ...parsedConfig.options };
|
|
1863
|
+
}
|
|
1864
|
+
const allowJsVal = compilerOptions.allowJs;
|
|
1865
|
+
if (typeof allowJsVal === "boolean" && allowJsVal) {
|
|
1866
|
+
compilerOptions = { ...compilerOptions, allowJs: false, checkJs: false };
|
|
1867
|
+
}
|
|
1868
|
+
const compilerHost = ts2.createCompilerHost(compilerOptions, true);
|
|
1869
|
+
let inMemorySource;
|
|
1870
|
+
if (content !== undefined) {
|
|
1871
|
+
inMemorySource = ts2.createSourceFile(entryFile, content, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TS);
|
|
1872
|
+
const originalGetSourceFile = compilerHost.getSourceFile.bind(compilerHost);
|
|
1873
|
+
compilerHost.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
1874
|
+
if (fileName === entryFile) {
|
|
1875
|
+
return inMemorySource;
|
|
1876
|
+
}
|
|
1877
|
+
return originalGetSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile);
|
|
1878
|
+
};
|
|
1879
|
+
}
|
|
1880
|
+
const program = ts2.createProgram([entryFile], compilerOptions, compilerHost);
|
|
1881
|
+
const sourceFile = inMemorySource ?? program.getSourceFile(entryFile);
|
|
1882
|
+
return {
|
|
1883
|
+
program,
|
|
1884
|
+
compilerHost,
|
|
1885
|
+
compilerOptions,
|
|
1886
|
+
sourceFile,
|
|
1887
|
+
configPath
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
// src/analysis/context.ts
|
|
1892
|
+
function createAnalysisContext({
|
|
1893
|
+
entryFile,
|
|
1894
|
+
packageDir,
|
|
1895
|
+
content,
|
|
1896
|
+
options
|
|
1897
|
+
}) {
|
|
1898
|
+
const baseDir = packageDir ?? path2.dirname(entryFile);
|
|
1899
|
+
const normalizedOptions = normalizeOpenPkgOptions(options);
|
|
1900
|
+
const programResult = createProgram({ entryFile, baseDir, content });
|
|
1901
|
+
if (!programResult.sourceFile) {
|
|
1902
|
+
throw new Error(`Could not load ${entryFile}`);
|
|
1903
|
+
}
|
|
1904
|
+
return {
|
|
1905
|
+
entryFile,
|
|
1906
|
+
baseDir,
|
|
1907
|
+
program: programResult.program,
|
|
1908
|
+
checker: programResult.program.getTypeChecker(),
|
|
1909
|
+
sourceFile: programResult.sourceFile,
|
|
1910
|
+
compilerOptions: programResult.compilerOptions,
|
|
1911
|
+
compilerHost: programResult.compilerHost,
|
|
1912
|
+
options: normalizedOptions,
|
|
1913
|
+
configPath: programResult.configPath
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
// src/analysis/spec-builder.ts
|
|
1918
|
+
import * as fs from "node:fs";
|
|
1919
|
+
import * as path3 from "node:path";
|
|
1920
|
+
import { SCHEMA_URL } from "@openpkg-ts/spec";
|
|
1921
|
+
|
|
1574
1922
|
// src/utils/parameter-utils.ts
|
|
1575
1923
|
var BUILTIN_TYPE_SCHEMAS = {
|
|
1576
1924
|
Date: { type: "string", format: "date-time" },
|
|
@@ -3705,10 +4053,10 @@ function collectDanglingRefs(spec) {
|
|
|
3705
4053
|
const referencedTypes = new Set;
|
|
3706
4054
|
collectAllRefs(spec.exports, referencedTypes);
|
|
3707
4055
|
collectAllRefs(spec.types, referencedTypes);
|
|
3708
|
-
return Array.from(referencedTypes).filter((ref) => !definedTypes.has(ref));
|
|
4056
|
+
return Array.from(referencedTypes).filter((ref) => !definedTypes.has(ref) && !isBuiltInType(ref));
|
|
3709
4057
|
}
|
|
3710
4058
|
function collectExternalTypes(spec) {
|
|
3711
|
-
return (spec.types ?? []).filter((t) => t.kind === "external").map((t) => t.id);
|
|
4059
|
+
return (spec.types ?? []).filter((t) => t.kind === "external").map((t) => t.id).filter((id) => !isBuiltInType(id));
|
|
3712
4060
|
}
|
|
3713
4061
|
function hasExternalImports(sourceFile) {
|
|
3714
4062
|
let found = false;
|
|
@@ -4077,7 +4425,7 @@ function generateAssertionFix(drift, exportEntry) {
|
|
|
4077
4425
|
const oldValue = oldValueMatch?.[1];
|
|
4078
4426
|
if (!oldValue)
|
|
4079
4427
|
return null;
|
|
4080
|
-
const updatedExample = oldExample.replace(new RegExp(`//\\s*=>\\s*${
|
|
4428
|
+
const updatedExample = oldExample.replace(new RegExp(`//\\s*=>\\s*${escapeRegex2(oldValue)}`, "g"), `// => ${newValue}`);
|
|
4081
4429
|
const updatedExamples = [...examples];
|
|
4082
4430
|
updatedExamples[exampleIndex] = updatedExample;
|
|
4083
4431
|
return {
|
|
@@ -4195,7 +4543,7 @@ function stringifySchema(schema) {
|
|
|
4195
4543
|
}
|
|
4196
4544
|
return "unknown";
|
|
4197
4545
|
}
|
|
4198
|
-
function
|
|
4546
|
+
function escapeRegex2(str) {
|
|
4199
4547
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4200
4548
|
}
|
|
4201
4549
|
function categorizeDrifts(drifts) {
|