diffgenome 0.1.0__py3-none-any.whl
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.
- diffgenome/__init__.py +7 -0
- diffgenome/__main__.py +240 -0
- diffgenome/_collectors/go/dg/dg.go +623 -0
- diffgenome/_collectors/go/go.mod +3 -0
- diffgenome/_collectors/go/instrument/facts.go +346 -0
- diffgenome/_collectors/go/instrument/main.go +484 -0
- diffgenome/_collectors/node/instrument.js +289 -0
- diffgenome/_collectors/node/jest-setup.js +40 -0
- diffgenome/_collectors/node/package-lock.json +35 -0
- diffgenome/_collectors/node/package.json +11 -0
- diffgenome/_collectors/node/runtime.js +426 -0
- diffgenome/ambiguity.py +122 -0
- diffgenome/api.py +67 -0
- diffgenome/change.py +86 -0
- diffgenome/change_artifact.py +310 -0
- diffgenome/collect/__init__.py +2 -0
- diffgenome/collect/go_test.py +271 -0
- diffgenome/collect/node_jest.py +319 -0
- diffgenome/collect/py_monitoring.py +985 -0
- diffgenome/collect/py_runtime.py +116 -0
- diffgenome/collect/py_symbols.py +238 -0
- diffgenome/collect/pytest_plugin.py +130 -0
- diffgenome/compose.py +469 -0
- diffgenome/dependence.py +264 -0
- diffgenome/evaluate.py +669 -0
- diffgenome/frontends/__init__.py +0 -0
- diffgenome/frontends/python_ir.py +335 -0
- diffgenome/genome.py +1016 -0
- diffgenome/genome_pipeline.py +674 -0
- diffgenome/genome_prompt.py +33 -0
- diffgenome/genome_state.py +2118 -0
- diffgenome/graph.py +426 -0
- diffgenome/llm.py +189 -0
- diffgenome/model.py +364 -0
- diffgenome/mvp.py +398 -0
- diffgenome/probe.py +509 -0
- diffgenome/projection.py +308 -0
- diffgenome/py.typed +0 -0
- diffgenome/render.py +118 -0
- diffgenome/report.py +363 -0
- diffgenome/resolve.py +37 -0
- diffgenome/runtime.py +74 -0
- diffgenome/runtime_evidence.py +261 -0
- diffgenome/sandbox.py +166 -0
- diffgenome/serialize.py +96 -0
- diffgenome/sites.py +19 -0
- diffgenome/static_types.py +69 -0
- diffgenome/structure.py +462 -0
- diffgenome-0.1.0.dist-info/METADATA +139 -0
- diffgenome-0.1.0.dist-info/RECORD +53 -0
- diffgenome-0.1.0.dist-info/WHEEL +4 -0
- diffgenome-0.1.0.dist-info/entry_points.txt +2 -0
- diffgenome-0.1.0.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/*
|
|
4
|
+
* diffgenome Node source instrumenter.
|
|
5
|
+
*
|
|
6
|
+
* node instrument.js --root <repo copy> --src <dir> [--src ...] --tests <dir> [--tests ...]
|
|
7
|
+
* --runtime <abs path to runtime.js> --index <out.json> [--dry]
|
|
8
|
+
*
|
|
9
|
+
* Rewrites every .ts/.js/.tsx/.jsx file under the roots IN PLACE (the copy is disposable)
|
|
10
|
+
* so that each function reports entry, return/throw and call sites to the runtime, and
|
|
11
|
+
* writes a symbol index (definitions with line spans) that the Python side uses to map
|
|
12
|
+
* diff lines to symbols and to extract source for probe context. Symbol naming:
|
|
13
|
+
* js:<path relative to root, no extension>.<qualified name>
|
|
14
|
+
* where anonymous functions are named <anon>@<line>, the same rule the Python collector
|
|
15
|
+
* uses for lambdas.
|
|
16
|
+
*
|
|
17
|
+
* Sync functions get try/catch/finally around the body (keeps `this`/`arguments`);
|
|
18
|
+
* async functions and generators get their body moved into a callback run under the
|
|
19
|
+
* runtime's AsyncLocalStorage scope, which is what makes attribution across `await`
|
|
20
|
+
* correct.
|
|
21
|
+
*/
|
|
22
|
+
const fs = require("fs");
|
|
23
|
+
const path = require("path");
|
|
24
|
+
const ts = require("typescript");
|
|
25
|
+
|
|
26
|
+
function parseArgs(argv) {
|
|
27
|
+
const out = { src: [], tests: [], dry: false };
|
|
28
|
+
for (let i = 0; i < argv.length; i++) {
|
|
29
|
+
const a = argv[i];
|
|
30
|
+
if (a === "--root") out.root = argv[++i];
|
|
31
|
+
else if (a === "--src") out.src.push(argv[++i]);
|
|
32
|
+
else if (a === "--tests") out.tests.push(argv[++i]);
|
|
33
|
+
else if (a === "--runtime") out.runtime = argv[++i];
|
|
34
|
+
else if (a === "--index") out.index = argv[++i];
|
|
35
|
+
else if (a === "--dry") out.dry = true;
|
|
36
|
+
}
|
|
37
|
+
if (!out.root || !out.runtime) throw new Error("--root and --runtime are required");
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const EXCLUDED = new Set(["node_modules", "dist", "build", "coverage", "__pycache__"]);
|
|
42
|
+
const EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
43
|
+
|
|
44
|
+
function* walk(dir) {
|
|
45
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
46
|
+
if (entry.name.startsWith(".") || EXCLUDED.has(entry.name)) continue;
|
|
47
|
+
const full = path.join(dir, entry.name);
|
|
48
|
+
if (entry.isDirectory()) yield* walk(full);
|
|
49
|
+
else if (entry.isFile() && EXTS.has(path.extname(entry.name)) && !entry.name.endsWith(".d.ts")) yield full;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function moduleName(root, file) {
|
|
54
|
+
const rel = path.relative(root, file).split(path.sep).join("/");
|
|
55
|
+
return rel.replace(/\.(tsx?|jsx?|mjs|cjs)$/, "");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ----------------------------------------------------------------------------- naming
|
|
59
|
+
|
|
60
|
+
function isFunctionLike(node) {
|
|
61
|
+
return (
|
|
62
|
+
ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) ||
|
|
63
|
+
ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node) ||
|
|
64
|
+
ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node)
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function nameOf(node, sf) {
|
|
69
|
+
const line = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
70
|
+
if (ts.isConstructorDeclaration(node)) return "constructor";
|
|
71
|
+
if ((ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node) || ts.isFunctionExpression(node) ||
|
|
72
|
+
ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node)) && node.name) {
|
|
73
|
+
return node.name.getText(sf);
|
|
74
|
+
}
|
|
75
|
+
const p = node.parent;
|
|
76
|
+
if (p && ts.isVariableDeclaration(p) && ts.isIdentifier(p.name)) return p.name.text;
|
|
77
|
+
if (p && ts.isPropertyAssignment(p) && p.name) return p.name.getText(sf);
|
|
78
|
+
if (p && ts.isPropertyDeclaration(p) && p.name) return p.name.getText(sf);
|
|
79
|
+
return `<anon>@${line}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function qualname(node, sf) {
|
|
83
|
+
const parts = [];
|
|
84
|
+
let cur = node;
|
|
85
|
+
while (cur && !ts.isSourceFile(cur)) {
|
|
86
|
+
if (isFunctionLike(cur)) parts.unshift(nameOf(cur, sf));
|
|
87
|
+
else if (ts.isClassDeclaration(cur) || ts.isClassExpression(cur)) parts.unshift(cur.name ? cur.name.text : `<class>@${sf.getLineAndCharacterOfPosition(cur.getStart(sf)).line + 1}`);
|
|
88
|
+
cur = cur.parent;
|
|
89
|
+
}
|
|
90
|
+
return parts.join(".");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function paramNames(node) {
|
|
94
|
+
return node.parameters.map((p) => (ts.isIdentifier(p.name) ? p.name.text : "<pattern>"));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function paramIdentifiers(node) {
|
|
98
|
+
return node.parameters.filter((p) => ts.isIdentifier(p.name)).map((p) => p.name.text);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ----------------------------------------------------------------------------- transform
|
|
102
|
+
|
|
103
|
+
function instrumentFile(file, ctxInfo, index) {
|
|
104
|
+
const text = fs.readFileSync(file, "utf8");
|
|
105
|
+
const sf = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true, file.endsWith("x") ? ts.ScriptKind.TSX : undefined);
|
|
106
|
+
const mod = moduleName(ctxInfo.root, file);
|
|
107
|
+
const rel = path.relative(ctxInfo.root, file).split(path.sep).join("/");
|
|
108
|
+
const f = ts.factory;
|
|
109
|
+
const DG = f.createIdentifier("__dg");
|
|
110
|
+
let changed = false;
|
|
111
|
+
|
|
112
|
+
// Index definitions (functions and classes) from the original tree.
|
|
113
|
+
function indexNode(node) {
|
|
114
|
+
if (isFunctionLike(node) && node.body) {
|
|
115
|
+
const start = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
116
|
+
const end = sf.getLineAndCharacterOfPosition(node.getEnd()).line + 1;
|
|
117
|
+
index.push({ symbol: `js:${mod}.${qualname(node, sf)}`, path: rel, start, end, kind: "function", is_async: !!(node.modifiers && node.modifiers.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword)) });
|
|
118
|
+
} else if (ts.isClassDeclaration(node) && node.name) {
|
|
119
|
+
const start = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
120
|
+
const end = sf.getLineAndCharacterOfPosition(node.getEnd()).line + 1;
|
|
121
|
+
index.push({ symbol: `js:${mod}.${qualname(node, sf)}`, path: rel, start, end, kind: "class", is_async: false });
|
|
122
|
+
}
|
|
123
|
+
ts.forEachChild(node, indexNode);
|
|
124
|
+
}
|
|
125
|
+
indexNode(sf);
|
|
126
|
+
|
|
127
|
+
const transformer = (context) => {
|
|
128
|
+
const ctxStack = []; // the __dgc identifier for the innermost instrumented function
|
|
129
|
+
function visit(node) {
|
|
130
|
+
// ---- call sites: obj.m(args) -> __dg.callm(obj, "m", [args]); f(args) -> __dg.callf(f, [args])
|
|
131
|
+
if (ts.isCallExpression(node) && ctxStack.length > 0 && !node.questionDotToken) {
|
|
132
|
+
const callee = node.expression;
|
|
133
|
+
const args = node.arguments.map((a) => ts.visitNode(a, visit));
|
|
134
|
+
const skip =
|
|
135
|
+
callee.kind === ts.SyntaxKind.SuperKeyword || callee.kind === ts.SyntaxKind.ImportKeyword ||
|
|
136
|
+
(ts.isIdentifier(callee) && (callee.text === "require" || callee.text === "__dg")) ||
|
|
137
|
+
(ts.isPropertyAccessExpression(callee) && (callee.questionDotToken || (ts.isIdentifier(callee.expression) && callee.expression.text === "__dg"))) ||
|
|
138
|
+
(ts.isPropertyAccessExpression(callee) && callee.expression.kind === ts.SyntaxKind.SuperKeyword) ||
|
|
139
|
+
node.typeArguments;
|
|
140
|
+
if (!skip) {
|
|
141
|
+
const arr = f.createArrayLiteralExpression(args, false);
|
|
142
|
+
if (ts.isPropertyAccessExpression(callee)) {
|
|
143
|
+
const obj = ts.visitNode(callee.expression, visit);
|
|
144
|
+
changed = true;
|
|
145
|
+
return f.createCallExpression(f.createPropertyAccessExpression(DG, "callm"), undefined, [obj, f.createStringLiteral(callee.name.text), arr]);
|
|
146
|
+
}
|
|
147
|
+
if (ts.isElementAccessExpression(callee) && !callee.questionDotToken) {
|
|
148
|
+
const obj = ts.visitNode(callee.expression, visit);
|
|
149
|
+
const key = ts.visitNode(callee.argumentExpression, visit);
|
|
150
|
+
changed = true;
|
|
151
|
+
return f.createCallExpression(f.createPropertyAccessExpression(DG, "callm"), undefined, [obj, key, arr]);
|
|
152
|
+
}
|
|
153
|
+
if (ts.isIdentifier(callee) || ts.isParenthesizedExpression(callee)) {
|
|
154
|
+
const fn = ts.visitNode(callee, visit);
|
|
155
|
+
changed = true;
|
|
156
|
+
return f.createCallExpression(f.createPropertyAccessExpression(DG, "callf"), undefined, [fn, arr]);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// ---- returns inside an instrumented function (not inside a nested function)
|
|
161
|
+
if (ts.isReturnStatement(node) && ctxStack.length > 0) {
|
|
162
|
+
const c = ctxStack[ctxStack.length - 1];
|
|
163
|
+
const expr = node.expression ? ts.visitNode(node.expression, visit) : f.createIdentifier("undefined");
|
|
164
|
+
changed = true;
|
|
165
|
+
return f.updateReturnStatement(node, f.createCallExpression(f.createPropertyAccessExpression(DG, "ret"), undefined, [c, expr]));
|
|
166
|
+
}
|
|
167
|
+
// ---- function bodies
|
|
168
|
+
if (isFunctionLike(node) && node.body) {
|
|
169
|
+
const isAccessor = ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node);
|
|
170
|
+
const isAsync = !!(node.modifiers && node.modifiers.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword));
|
|
171
|
+
const isGen = !!node.asteriskToken;
|
|
172
|
+
const isCtor = ts.isConstructorDeclaration(node);
|
|
173
|
+
const useRun = (isAsync || isGen) && !isCtor;
|
|
174
|
+
const sym = `js:${mod}.${qualname(node, sf)}`;
|
|
175
|
+
const line = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
176
|
+
const c = f.createUniqueName("__dgc");
|
|
177
|
+
ctxStack.push(c);
|
|
178
|
+
// visit the body with the new context
|
|
179
|
+
let body = node.body;
|
|
180
|
+
if (!ts.isBlock(body)) body = f.createBlock([f.createReturnStatement(body)], true);
|
|
181
|
+
const visitedBody = ts.visitEachChild(body, visit, context);
|
|
182
|
+
ctxStack.pop();
|
|
183
|
+
const meta = f.createObjectLiteralExpression([
|
|
184
|
+
f.createPropertyAssignment("sym", f.createStringLiteral(sym)),
|
|
185
|
+
f.createPropertyAssignment("origin", f.createStringLiteral(ctxInfo.origin)),
|
|
186
|
+
f.createPropertyAssignment("file", f.createStringLiteral(rel)),
|
|
187
|
+
f.createPropertyAssignment("line", f.createNumericLiteral(String(line))),
|
|
188
|
+
f.createPropertyAssignment("params", f.createArrayLiteralExpression(paramNames(node).map((n) => f.createStringLiteral(n)))),
|
|
189
|
+
]);
|
|
190
|
+
const values = f.createArrayLiteralExpression(paramIdentifiers(node).map((n) => f.createIdentifier(n)));
|
|
191
|
+
let newBody;
|
|
192
|
+
if (useRun) {
|
|
193
|
+
// return __dg.run(meta, [args], this, async/function* (c) { body }) (yield* for generators)
|
|
194
|
+
const inner = isGen
|
|
195
|
+
? f.createFunctionExpression(isAsync ? [f.createModifier(ts.SyntaxKind.AsyncKeyword)] : undefined, f.createToken(ts.SyntaxKind.AsteriskToken), undefined, undefined, [f.createParameterDeclaration(undefined, undefined, c)], undefined, visitedBody)
|
|
196
|
+
: f.createArrowFunction([f.createModifier(ts.SyntaxKind.AsyncKeyword)], undefined, [f.createParameterDeclaration(undefined, undefined, c)], undefined, undefined, visitedBody);
|
|
197
|
+
const thisArg = ts.isArrowFunction(node) ? f.createIdentifier("undefined") : f.createThis();
|
|
198
|
+
const call = f.createCallExpression(f.createPropertyAccessExpression(DG, "run"), undefined, [meta, values, thisArg, inner]);
|
|
199
|
+
const stmt = isGen
|
|
200
|
+
? f.createReturnStatement(f.createYieldExpression(f.createToken(ts.SyntaxKind.AsteriskToken), call))
|
|
201
|
+
: f.createReturnStatement(call);
|
|
202
|
+
newBody = f.createBlock([stmt], true);
|
|
203
|
+
} else {
|
|
204
|
+
// const c = __dg.enter(meta, [args]); try { body } catch (e) { __dg.throwed(c, e); throw e } finally { __dg.exit(c) }
|
|
205
|
+
const e = f.createUniqueName("__dge");
|
|
206
|
+
const decl = f.createVariableStatement(undefined, f.createVariableDeclarationList([
|
|
207
|
+
f.createVariableDeclaration(c, undefined, undefined, f.createCallExpression(f.createPropertyAccessExpression(DG, "enter"), undefined, [meta, values, (ts.isArrowFunction(node) || isCtor) ? f.createIdentifier("undefined") : f.createThis()])),
|
|
208
|
+
], ts.NodeFlags.Const));
|
|
209
|
+
const tryStmt = f.createTryStatement(
|
|
210
|
+
visitedBody,
|
|
211
|
+
f.createCatchClause(f.createVariableDeclaration(e), f.createBlock([
|
|
212
|
+
f.createExpressionStatement(f.createCallExpression(f.createPropertyAccessExpression(DG, "throwed"), undefined, [c, e])),
|
|
213
|
+
f.createThrowStatement(e),
|
|
214
|
+
], true)),
|
|
215
|
+
f.createBlock([f.createExpressionStatement(f.createCallExpression(f.createPropertyAccessExpression(DG, "exit"), undefined, [c]))], true),
|
|
216
|
+
);
|
|
217
|
+
newBody = f.createBlock([decl, tryStmt], true);
|
|
218
|
+
}
|
|
219
|
+
changed = true;
|
|
220
|
+
if (ts.isFunctionDeclaration(node)) return f.updateFunctionDeclaration(node, node.modifiers, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, newBody);
|
|
221
|
+
if (ts.isFunctionExpression(node)) return f.updateFunctionExpression(node, node.modifiers, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, newBody);
|
|
222
|
+
if (ts.isArrowFunction(node)) return f.updateArrowFunction(node, node.modifiers, node.typeParameters, node.parameters, node.type, node.equalsGreaterThanToken, newBody);
|
|
223
|
+
if (ts.isMethodDeclaration(node)) return f.updateMethodDeclaration(node, node.modifiers, node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters, node.type, newBody);
|
|
224
|
+
if (ts.isConstructorDeclaration(node)) return f.updateConstructorDeclaration(node, node.modifiers, node.parameters, newBody);
|
|
225
|
+
if (isAccessor) {
|
|
226
|
+
if (ts.isGetAccessorDeclaration(node)) return f.updateGetAccessorDeclaration(node, node.modifiers, node.name, node.parameters, node.type, newBody);
|
|
227
|
+
return f.updateSetAccessorDeclaration(node, node.modifiers, node.name, node.parameters, newBody);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return ts.visitEachChild(node, visit, context);
|
|
231
|
+
}
|
|
232
|
+
return (root) => {
|
|
233
|
+
const visited = ts.visitNode(root, visit);
|
|
234
|
+
// Register named top-level classes so the runtime can claim overriding fakes by
|
|
235
|
+
// prototype identity: __dg.registerClass(Name, "js:<module>.Name").
|
|
236
|
+
const extra = [];
|
|
237
|
+
for (const stmt of visited.statements) {
|
|
238
|
+
if (ts.isClassDeclaration(stmt) && stmt.name) {
|
|
239
|
+
const sym = `js:${mod}.${stmt.name.text}`;
|
|
240
|
+
extra.push({ after: stmt, stmt: f.createExpressionStatement(f.createCallExpression(f.createPropertyAccessExpression(DG, "registerClass"), undefined, [f.createIdentifier(stmt.name.text), f.createStringLiteral(sym), f.createStringLiteral(ctxInfo.origin)])) });
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (extra.length === 0) return visited;
|
|
244
|
+
const statements = [];
|
|
245
|
+
for (const stmt of visited.statements) {
|
|
246
|
+
statements.push(stmt);
|
|
247
|
+
for (const e of extra) if (e.after === stmt) { statements.push(e.stmt); changed = true; }
|
|
248
|
+
}
|
|
249
|
+
return f.updateSourceFile(visited, statements);
|
|
250
|
+
};
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const result = ts.transform(sf, [transformer]);
|
|
254
|
+
const out = result.transformed[0];
|
|
255
|
+
if (!changed) return false;
|
|
256
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed, removeComments: false });
|
|
257
|
+
let printed = printer.printFile(out);
|
|
258
|
+
const header = `const __dg = require(${JSON.stringify(ctxInfo.runtime)});\n`;
|
|
259
|
+
// Keep a leading shebang / 'use strict' / reflect-metadata import order intact enough:
|
|
260
|
+
// our require is side-effect free, so putting it first is safe.
|
|
261
|
+
printed = header + printed;
|
|
262
|
+
if (!ctxInfo.dry) fs.writeFileSync(file, printed);
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function main() {
|
|
267
|
+
const args = parseArgs(process.argv.slice(2));
|
|
268
|
+
const root = path.resolve(args.root);
|
|
269
|
+
const index = [];
|
|
270
|
+
let count = 0;
|
|
271
|
+
const seen = new Set();
|
|
272
|
+
const roots = [...args.tests.map((d) => ({ dir: path.resolve(root, d), origin: "test" })), ...args.src.map((d) => ({ dir: path.resolve(root, d), origin: "repo" }))];
|
|
273
|
+
for (const r of roots) {
|
|
274
|
+
if (!fs.existsSync(r.dir)) continue;
|
|
275
|
+
for (const file of walk(r.dir)) {
|
|
276
|
+
if (seen.has(file)) continue;
|
|
277
|
+
seen.add(file);
|
|
278
|
+
try {
|
|
279
|
+
if (instrumentFile(file, { root, origin: r.origin, runtime: path.resolve(args.runtime), dry: args.dry }, index)) count++;
|
|
280
|
+
} catch (e) {
|
|
281
|
+
process.stderr.write(`diffgenome: failed to instrument ${file}: ${e.message}\n`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (args.index) fs.writeFileSync(args.index, JSON.stringify({ root: root, definitions: index }, null, 1) + "\n");
|
|
286
|
+
process.stdout.write(`instrumented ${count} files, indexed ${index.length} definitions\n`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
main();
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Jest integration: marks each test as a stimulus and writes its Execution when it ends.
|
|
4
|
+
* Loaded through the workspace Jest config (setupFilesAfterEnv, or setupTestFrameworkScriptFile
|
|
5
|
+
* on Jest < 24) with DIFFGENOME_RUNTIME pointing at runtime.js. Works with the jasmine2
|
|
6
|
+
* runner (reporter API) and with jest-circus (beforeEach/afterEach + expect state).
|
|
7
|
+
*/
|
|
8
|
+
const runtime = require(process.env.DIFFGENOME_RUNTIME);
|
|
9
|
+
if (process.env.DIFFGENOME_CHAIN_SETUP) require(process.env.DIFFGENOME_CHAIN_SETUP);
|
|
10
|
+
|
|
11
|
+
function refFor(fullName) {
|
|
12
|
+
const state = typeof expect !== "undefined" && expect.getState ? expect.getState() : {};
|
|
13
|
+
const file = state.testPath ? require("path").relative(process.cwd(), state.testPath) : "";
|
|
14
|
+
return file ? `${file}::${fullName}` : fullName;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (typeof jasmine !== "undefined" && jasmine.getEnv) {
|
|
18
|
+
jasmine.getEnv().addReporter({
|
|
19
|
+
specStarted(result) {
|
|
20
|
+
runtime.begin(refFor(result.fullName));
|
|
21
|
+
},
|
|
22
|
+
specDone(result) {
|
|
23
|
+
runtime.end(result.status === "passed" ? "passed" : result.status === "pending" ? "skipped" : "failed");
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
} else {
|
|
27
|
+
let failedBefore = 0;
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
const s = expect.getState();
|
|
30
|
+
failedBefore = s.assertionCalls;
|
|
31
|
+
runtime.begin(refFor(s.currentTestName || "unknown"));
|
|
32
|
+
});
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
const s = expect.getState();
|
|
35
|
+
// jest-circus does not expose the status in afterEach; a failed expectation leaves
|
|
36
|
+
// suppressedErrors, an uncaught throw skips afterEach entirely.
|
|
37
|
+
const failed = s.suppressedErrors && s.suppressedErrors.length > 0;
|
|
38
|
+
runtime.end(failed ? "failed" : "passed");
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "diffgenome-node-collector",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"lockfileVersion": 3,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"": {
|
|
8
|
+
"name": "diffgenome-node-collector",
|
|
9
|
+
"version": "0.0.1",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"bcryptjs": "^2.4.3",
|
|
12
|
+
"typescript": "5.9.3"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"node_modules/bcryptjs": {
|
|
16
|
+
"version": "2.4.3",
|
|
17
|
+
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
|
|
18
|
+
"integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==",
|
|
19
|
+
"license": "MIT"
|
|
20
|
+
},
|
|
21
|
+
"node_modules/typescript": {
|
|
22
|
+
"version": "5.9.3",
|
|
23
|
+
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
|
24
|
+
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
|
25
|
+
"license": "Apache-2.0",
|
|
26
|
+
"bin": {
|
|
27
|
+
"tsc": "bin/tsc",
|
|
28
|
+
"tsserver": "bin/tsserver"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=14.17"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "diffgenome-node-collector",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"description": "Source-instrumentation collector for Node/TypeScript targets; emits the diffgenome event protocol.",
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"bcryptjs": "^2.4.3",
|
|
9
|
+
"typescript": "5.9.3"
|
|
10
|
+
}
|
|
11
|
+
}
|