@doccov/sdk 0.19.0 → 0.20.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 +9 -10
- package/dist/index.js +175 -152
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -114,21 +114,19 @@ interface DetectedSchemaEntry {
|
|
|
114
114
|
schema: Record<string, unknown>;
|
|
115
115
|
vendor: string;
|
|
116
116
|
}
|
|
117
|
-
/**
|
|
118
|
-
* Runtime Schema Detection (Stubbed)
|
|
119
|
-
*
|
|
120
|
-
* Standard Schema extraction has been removed. This module provides
|
|
121
|
-
* empty stubs to maintain API compatibility.
|
|
122
|
-
*/
|
|
123
117
|
interface SchemaDetectionContext {
|
|
124
118
|
baseDir: string;
|
|
125
119
|
entryFile: string;
|
|
126
120
|
}
|
|
121
|
+
interface DetectedSchema {
|
|
122
|
+
schema: Record<string, unknown>;
|
|
123
|
+
vendor: string;
|
|
124
|
+
}
|
|
127
125
|
interface SchemaDetectionResult {
|
|
128
|
-
schemas: Map<string,
|
|
126
|
+
schemas: Map<string, DetectedSchema>;
|
|
129
127
|
errors: string[];
|
|
130
128
|
}
|
|
131
|
-
declare function detectRuntimeSchemas(
|
|
129
|
+
declare function detectRuntimeSchemas(context: SchemaDetectionContext): Promise<SchemaDetectionResult>;
|
|
132
130
|
declare function clearSchemaCache(): void;
|
|
133
131
|
import * as TS from "typescript";
|
|
134
132
|
/**
|
|
@@ -2298,8 +2296,9 @@ declare class DocCov {
|
|
|
2298
2296
|
*/
|
|
2299
2297
|
private findPackageJson;
|
|
2300
2298
|
/**
|
|
2301
|
-
*
|
|
2302
|
-
*
|
|
2299
|
+
* Detect Standard Schema exports from compiled modules.
|
|
2300
|
+
* Only runs when schemaExtraction is 'runtime' or 'hybrid'.
|
|
2301
|
+
* Returns undefined if detection is disabled, fails, or no schemas found.
|
|
2303
2302
|
*/
|
|
2304
2303
|
private detectSchemas;
|
|
2305
2304
|
private normalizeDiagnostic;
|
package/dist/index.js
CHANGED
|
@@ -17,12 +17,180 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
17
17
|
};
|
|
18
18
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
19
|
|
|
20
|
-
// src/
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
// src/extract/schema/standard-schema.ts
|
|
21
|
+
import { spawn } from "node:child_process";
|
|
22
|
+
import * as fs from "node:fs";
|
|
23
|
+
import * as path from "node:path";
|
|
24
|
+
function isStandardJSONSchema(obj) {
|
|
25
|
+
if (typeof obj !== "object" || obj === null)
|
|
26
|
+
return false;
|
|
27
|
+
const std = obj["~standard"];
|
|
28
|
+
if (typeof std !== "object" || std === null)
|
|
29
|
+
return false;
|
|
30
|
+
const stdObj = std;
|
|
31
|
+
if (typeof stdObj.version !== "number")
|
|
32
|
+
return false;
|
|
33
|
+
if (typeof stdObj.vendor !== "string")
|
|
34
|
+
return false;
|
|
35
|
+
const jsonSchema = stdObj.jsonSchema;
|
|
36
|
+
if (typeof jsonSchema !== "object" || jsonSchema === null)
|
|
37
|
+
return false;
|
|
38
|
+
const jsObj = jsonSchema;
|
|
39
|
+
return typeof jsObj.output === "function";
|
|
40
|
+
}
|
|
41
|
+
var WORKER_SCRIPT = `
|
|
42
|
+
const path = require('path');
|
|
43
|
+
const { pathToFileURL } = require('url');
|
|
44
|
+
|
|
45
|
+
async function extract() {
|
|
46
|
+
// With node -e, argv is: [node, arg1, arg2, ...]
|
|
47
|
+
// (the -e script is NOT in argv)
|
|
48
|
+
const [modulePath, target] = process.argv.slice(1);
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
// Import the module using dynamic import (works with ESM and CJS)
|
|
52
|
+
const absPath = path.resolve(modulePath);
|
|
53
|
+
const mod = await import(pathToFileURL(absPath).href);
|
|
54
|
+
const results = [];
|
|
55
|
+
|
|
56
|
+
// Check each export
|
|
57
|
+
for (const [name, value] of Object.entries(mod)) {
|
|
58
|
+
if (name.startsWith('_')) continue;
|
|
59
|
+
if (typeof value !== 'object' || value === null) continue;
|
|
60
|
+
|
|
61
|
+
const std = value['~standard'];
|
|
62
|
+
if (!std || typeof std !== 'object') continue;
|
|
63
|
+
if (typeof std.version !== 'number') continue;
|
|
64
|
+
if (typeof std.vendor !== 'string') continue;
|
|
65
|
+
if (!std.jsonSchema || typeof std.jsonSchema.output !== 'function') continue;
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const outputSchema = std.jsonSchema.output(target);
|
|
69
|
+
const inputSchema = std.jsonSchema.input ? std.jsonSchema.input(target) : undefined;
|
|
70
|
+
|
|
71
|
+
results.push({
|
|
72
|
+
exportName: name,
|
|
73
|
+
vendor: std.vendor,
|
|
74
|
+
outputSchema,
|
|
75
|
+
inputSchema
|
|
76
|
+
});
|
|
77
|
+
} catch (e) {
|
|
78
|
+
// Skip schemas that fail to extract
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log(JSON.stringify({ success: true, results }));
|
|
83
|
+
} catch (e) {
|
|
84
|
+
console.log(JSON.stringify({ success: false, error: e.message }));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
extract();
|
|
89
|
+
`;
|
|
90
|
+
function resolveCompiledPath(tsPath, baseDir) {
|
|
91
|
+
const relativePath = path.relative(baseDir, tsPath);
|
|
92
|
+
const withoutExt = relativePath.replace(/\.tsx?$/, "");
|
|
93
|
+
const candidates = [
|
|
94
|
+
path.join(baseDir, `${withoutExt}.js`),
|
|
95
|
+
path.join(baseDir, "dist", `${withoutExt.replace(/^src\//, "")}.js`),
|
|
96
|
+
path.join(baseDir, "build", `${withoutExt.replace(/^src\//, "")}.js`),
|
|
97
|
+
path.join(baseDir, "lib", `${withoutExt.replace(/^src\//, "")}.js`)
|
|
98
|
+
];
|
|
99
|
+
for (const candidate of candidates) {
|
|
100
|
+
if (fs.existsSync(candidate)) {
|
|
101
|
+
return candidate;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
async function extractStandardSchemas(compiledJsPath, options = {}) {
|
|
107
|
+
const { timeout = 1e4, target = "draft-2020-12" } = options;
|
|
108
|
+
const result = {
|
|
23
109
|
schemas: new Map,
|
|
24
110
|
errors: []
|
|
25
111
|
};
|
|
112
|
+
if (!fs.existsSync(compiledJsPath)) {
|
|
113
|
+
result.errors.push(`Compiled JS not found: ${compiledJsPath}`);
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
return new Promise((resolve) => {
|
|
117
|
+
const child = spawn("node", ["-e", WORKER_SCRIPT, compiledJsPath, target], {
|
|
118
|
+
timeout,
|
|
119
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
120
|
+
});
|
|
121
|
+
let stdout = "";
|
|
122
|
+
let stderr = "";
|
|
123
|
+
child.stdout.on("data", (data) => {
|
|
124
|
+
stdout += data.toString();
|
|
125
|
+
});
|
|
126
|
+
child.stderr.on("data", (data) => {
|
|
127
|
+
stderr += data.toString();
|
|
128
|
+
});
|
|
129
|
+
child.on("close", (code) => {
|
|
130
|
+
if (code !== 0) {
|
|
131
|
+
result.errors.push(`Extraction process failed: ${stderr || `exit code ${code}`}`);
|
|
132
|
+
resolve(result);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
const parsed = JSON.parse(stdout);
|
|
137
|
+
if (!parsed.success) {
|
|
138
|
+
result.errors.push(`Extraction failed: ${parsed.error}`);
|
|
139
|
+
resolve(result);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
for (const item of parsed.results) {
|
|
143
|
+
result.schemas.set(item.exportName, {
|
|
144
|
+
exportName: item.exportName,
|
|
145
|
+
vendor: item.vendor,
|
|
146
|
+
outputSchema: item.outputSchema,
|
|
147
|
+
inputSchema: item.inputSchema
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
} catch (e) {
|
|
151
|
+
result.errors.push(`Failed to parse extraction output: ${e}`);
|
|
152
|
+
}
|
|
153
|
+
resolve(result);
|
|
154
|
+
});
|
|
155
|
+
child.on("error", (err) => {
|
|
156
|
+
result.errors.push(`Subprocess error: ${err.message}`);
|
|
157
|
+
resolve(result);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
async function extractStandardSchemasFromProject(entryFile, baseDir, options = {}) {
|
|
162
|
+
const compiledPath = resolveCompiledPath(entryFile, baseDir);
|
|
163
|
+
if (!compiledPath) {
|
|
164
|
+
return {
|
|
165
|
+
schemas: new Map,
|
|
166
|
+
errors: [`Could not find compiled JS for ${entryFile}. Build the project first.`]
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return extractStandardSchemas(compiledPath, options);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// src/analysis/schema-detection.ts
|
|
173
|
+
async function detectRuntimeSchemas(context) {
|
|
174
|
+
const { baseDir, entryFile } = context;
|
|
175
|
+
const compiledPath = resolveCompiledPath(entryFile, baseDir);
|
|
176
|
+
if (!compiledPath) {
|
|
177
|
+
return {
|
|
178
|
+
schemas: new Map,
|
|
179
|
+
errors: []
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const extraction = await extractStandardSchemasFromProject(entryFile, baseDir);
|
|
183
|
+
const schemas = new Map;
|
|
184
|
+
for (const [name, result] of extraction.schemas) {
|
|
185
|
+
schemas.set(name, {
|
|
186
|
+
schema: result.outputSchema,
|
|
187
|
+
vendor: result.vendor
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
schemas,
|
|
192
|
+
errors: extraction.errors
|
|
193
|
+
};
|
|
26
194
|
}
|
|
27
195
|
function clearSchemaCache() {}
|
|
28
196
|
// src/extract/schema/types.ts
|
|
@@ -209,155 +377,6 @@ function getRegisteredAdapters() {
|
|
|
209
377
|
function getSupportedLibraries() {
|
|
210
378
|
return adapters.flatMap((a) => a.packages);
|
|
211
379
|
}
|
|
212
|
-
// src/extract/schema/standard-schema.ts
|
|
213
|
-
import { spawn } from "node:child_process";
|
|
214
|
-
import * as fs from "node:fs";
|
|
215
|
-
import * as path from "node:path";
|
|
216
|
-
function isStandardJSONSchema(obj) {
|
|
217
|
-
if (typeof obj !== "object" || obj === null)
|
|
218
|
-
return false;
|
|
219
|
-
const std = obj["~standard"];
|
|
220
|
-
if (typeof std !== "object" || std === null)
|
|
221
|
-
return false;
|
|
222
|
-
const stdObj = std;
|
|
223
|
-
if (typeof stdObj.version !== "number")
|
|
224
|
-
return false;
|
|
225
|
-
if (typeof stdObj.vendor !== "string")
|
|
226
|
-
return false;
|
|
227
|
-
const jsonSchema = stdObj.jsonSchema;
|
|
228
|
-
if (typeof jsonSchema !== "object" || jsonSchema === null)
|
|
229
|
-
return false;
|
|
230
|
-
const jsObj = jsonSchema;
|
|
231
|
-
return typeof jsObj.output === "function";
|
|
232
|
-
}
|
|
233
|
-
var WORKER_SCRIPT = `
|
|
234
|
-
const path = require('path');
|
|
235
|
-
|
|
236
|
-
async function extract() {
|
|
237
|
-
// With node -e, argv is: [node, arg1, arg2, ...]
|
|
238
|
-
// (the -e script is NOT in argv)
|
|
239
|
-
const [modulePath, target] = process.argv.slice(1);
|
|
240
|
-
|
|
241
|
-
try {
|
|
242
|
-
// Import the module
|
|
243
|
-
const mod = require(path.resolve(modulePath));
|
|
244
|
-
const results = [];
|
|
245
|
-
|
|
246
|
-
// Check each export
|
|
247
|
-
for (const [name, value] of Object.entries(mod)) {
|
|
248
|
-
if (name.startsWith('_')) continue;
|
|
249
|
-
if (typeof value !== 'object' || value === null) continue;
|
|
250
|
-
|
|
251
|
-
const std = value['~standard'];
|
|
252
|
-
if (!std || typeof std !== 'object') continue;
|
|
253
|
-
if (typeof std.version !== 'number') continue;
|
|
254
|
-
if (typeof std.vendor !== 'string') continue;
|
|
255
|
-
if (!std.jsonSchema || typeof std.jsonSchema.output !== 'function') continue;
|
|
256
|
-
|
|
257
|
-
try {
|
|
258
|
-
const outputSchema = std.jsonSchema.output(target);
|
|
259
|
-
const inputSchema = std.jsonSchema.input ? std.jsonSchema.input(target) : undefined;
|
|
260
|
-
|
|
261
|
-
results.push({
|
|
262
|
-
exportName: name,
|
|
263
|
-
vendor: std.vendor,
|
|
264
|
-
outputSchema,
|
|
265
|
-
inputSchema
|
|
266
|
-
});
|
|
267
|
-
} catch (e) {
|
|
268
|
-
// Skip schemas that fail to extract
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
console.log(JSON.stringify({ success: true, results }));
|
|
273
|
-
} catch (e) {
|
|
274
|
-
console.log(JSON.stringify({ success: false, error: e.message }));
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
extract();
|
|
279
|
-
`;
|
|
280
|
-
function resolveCompiledPath(tsPath, baseDir) {
|
|
281
|
-
const relativePath = path.relative(baseDir, tsPath);
|
|
282
|
-
const withoutExt = relativePath.replace(/\.tsx?$/, "");
|
|
283
|
-
const candidates = [
|
|
284
|
-
path.join(baseDir, `${withoutExt}.js`),
|
|
285
|
-
path.join(baseDir, "dist", `${withoutExt.replace(/^src\//, "")}.js`),
|
|
286
|
-
path.join(baseDir, "build", `${withoutExt.replace(/^src\//, "")}.js`),
|
|
287
|
-
path.join(baseDir, "lib", `${withoutExt.replace(/^src\//, "")}.js`)
|
|
288
|
-
];
|
|
289
|
-
for (const candidate of candidates) {
|
|
290
|
-
if (fs.existsSync(candidate)) {
|
|
291
|
-
return candidate;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
return null;
|
|
295
|
-
}
|
|
296
|
-
async function extractStandardSchemas(compiledJsPath, options = {}) {
|
|
297
|
-
const { timeout = 1e4, target = "draft-2020-12" } = options;
|
|
298
|
-
const result = {
|
|
299
|
-
schemas: new Map,
|
|
300
|
-
errors: []
|
|
301
|
-
};
|
|
302
|
-
if (!fs.existsSync(compiledJsPath)) {
|
|
303
|
-
result.errors.push(`Compiled JS not found: ${compiledJsPath}`);
|
|
304
|
-
return result;
|
|
305
|
-
}
|
|
306
|
-
return new Promise((resolve) => {
|
|
307
|
-
const child = spawn("node", ["-e", WORKER_SCRIPT, compiledJsPath, target], {
|
|
308
|
-
timeout,
|
|
309
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
310
|
-
});
|
|
311
|
-
let stdout = "";
|
|
312
|
-
let stderr = "";
|
|
313
|
-
child.stdout.on("data", (data) => {
|
|
314
|
-
stdout += data.toString();
|
|
315
|
-
});
|
|
316
|
-
child.stderr.on("data", (data) => {
|
|
317
|
-
stderr += data.toString();
|
|
318
|
-
});
|
|
319
|
-
child.on("close", (code) => {
|
|
320
|
-
if (code !== 0) {
|
|
321
|
-
result.errors.push(`Extraction process failed: ${stderr || `exit code ${code}`}`);
|
|
322
|
-
resolve(result);
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
try {
|
|
326
|
-
const parsed = JSON.parse(stdout);
|
|
327
|
-
if (!parsed.success) {
|
|
328
|
-
result.errors.push(`Extraction failed: ${parsed.error}`);
|
|
329
|
-
resolve(result);
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
for (const item of parsed.results) {
|
|
333
|
-
result.schemas.set(item.exportName, {
|
|
334
|
-
exportName: item.exportName,
|
|
335
|
-
vendor: item.vendor,
|
|
336
|
-
outputSchema: item.outputSchema,
|
|
337
|
-
inputSchema: item.inputSchema
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
} catch (e) {
|
|
341
|
-
result.errors.push(`Failed to parse extraction output: ${e}`);
|
|
342
|
-
}
|
|
343
|
-
resolve(result);
|
|
344
|
-
});
|
|
345
|
-
child.on("error", (err) => {
|
|
346
|
-
result.errors.push(`Subprocess error: ${err.message}`);
|
|
347
|
-
resolve(result);
|
|
348
|
-
});
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
async function extractStandardSchemasFromProject(entryFile, baseDir, options = {}) {
|
|
352
|
-
const compiledPath = resolveCompiledPath(entryFile, baseDir);
|
|
353
|
-
if (!compiledPath) {
|
|
354
|
-
return {
|
|
355
|
-
schemas: new Map,
|
|
356
|
-
errors: [`Could not find compiled JS for ${entryFile}. Build the project first.`]
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
return extractStandardSchemas(compiledPath, options);
|
|
360
|
-
}
|
|
361
380
|
// src/analysis/docs-coverage.ts
|
|
362
381
|
import {
|
|
363
382
|
DRIFT_CATEGORIES
|
|
@@ -8978,6 +8997,10 @@ class DocCov {
|
|
|
8978
8997
|
}
|
|
8979
8998
|
}
|
|
8980
8999
|
async detectSchemas(entryFile, packageDir) {
|
|
9000
|
+
const mode = this.options.schemaExtraction ?? "static";
|
|
9001
|
+
if (mode === "static") {
|
|
9002
|
+
return;
|
|
9003
|
+
}
|
|
8981
9004
|
try {
|
|
8982
9005
|
const result = await detectRuntimeSchemas({
|
|
8983
9006
|
baseDir: packageDir,
|