-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmutation.js
More file actions
88 lines (75 loc) · 2.88 KB
/
Copy pathmutation.js
File metadata and controls
88 lines (75 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
const fs = require("fs");
const path = require("path");
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generator = require("@babel/generator").default;
const JSON_DIR = "./json_corpus";
const EXPRESSION_TYPES = new Set([
"AssignmentExpression", "BinaryExpression", "LogicalExpression",
"UnaryExpression", "CallExpression", "MemberExpression",
"ConditionalExpression", "NewExpression", "ArrayExpression",
"ObjectExpression", "SequenceExpression", "UpdateExpression",
"ThisExpression", "SuperExpression", "TaggedTemplateExpression",
"TemplateLiteral", "AwaitExpression", "YieldExpression",
"ArrowFunctionExpression", "FunctionExpression", "ClassExpression",
"ParenthesizedExpression", "ExpressionStatement",
]);
const FILE_PATH = process.argv[2];
if (!FILE_PATH) {
console.error("Usage: node mutation.js <path>");
process.exit(1);
}
function loadRandomJson(directory) {
const files = fs.readdirSync(directory).filter(f => f.endsWith(".json"));
if (files.length === 0) {
console.error(`No JSON files in: ${directory}`);
process.exit(1);
}
const selected = files[Math.floor(Math.random() * files.length)];
return JSON.parse(fs.readFileSync(path.join(directory, selected), "utf-8"));
}
const code = fs.readFileSync(FILE_PATH, "utf-8");
const ast = parser.parse(code, {
sourceType: "module",
errorRecovery: true,
plugins: [
"jsx", "typescript", "classProperties",
"optionalChaining", "nullishCoalescingOperator", "dynamicImport",
],
});
const blockStatements = [];
const expressions = [];
traverse(ast, {
enter(path) {
if (path.node.type === "BlockStatement") {
blockStatements.push(path);
}
if (EXPRESSION_TYPES.has(path.node.type)) {
expressions.push(path);
}
},
});
const operations = [];
if (blockStatements.length > 0) operations.push("insertExpressionStatement");
if (expressions.length > 0) operations.push("subtreeChange");
if (operations.length === 0) {
process.exit(0);
}
const selectedOp = operations[Math.floor(Math.random() * operations.length)];
switch (selectedOp) {
case "insertExpressionStatement": {
const block = blockStatements[Math.floor(Math.random() * blockStatements.length)];
const insertIndex = Math.floor(Math.random() * (block.node.body.length + 1));
const newStatement = loadRandomJson(`${JSON_DIR}/ExpressionStatement`);
block.node.body.splice(insertIndex, 0, newStatement);
break;
}
case "subtreeChange": {
const target = expressions[Math.floor(Math.random() * expressions.length)];
const typeDir = path.join(JSON_DIR, target.node.type);
const replacement = loadRandomJson(typeDir);
target.replaceWith(replacement);
break;
}
}
console.log(generator(ast, { compact: false }).code);