Summary:
This PR adds the fuzzer I’ve been working on to the Prepack codebase so other people can contribute, provide feedback, and run it against their changes. The new commands added are:

- `yarn fuzz`: Starts generating tests in the foreground and logs progress. If it finds an error it will try and shrink it before returning the shrunken program to you with the invalid results.
- `yarn fuzz-sample`: See a selection of the programs generated by the fuzzer.
- `yarn fuzz-overnight`: Spin up a worker for each CPU and try to find failing test cases. Your computer will be basically unusable while you run this, so leave it running overnight. Failed test cases will be saved in `fuzzer/overnight.sqlite` so in the morning you can use `sqlite3` to inspect the errors the fuzzer found.

The fuzzer generates programs with an optimized function and executes them twice:

1. In Node.js
2. In Node.js after running Prepack

Then compares the results. If the results are different then the fuzzer will attempt to shrink the program to something easier to debug and return this to you. See [this gist for a sample of generated programs](https://gist.github.com/calebmer/6a727c1f4aa8c08d51940e60d29d336a). Here’s an example of a function you might see:

```js
function f3(a1, a2, a3, a4, a5, a6) {
  2;
  var x2;

  if (0) {
    return a1 ? false : a2;
  } else {
    var x1 = a3;
    x2 = x1;
  }

  var x6;

  if (x2) {
    var x3;

    if (x2) {
      x3 = x2;
    } else {
      x3 = a4;
    }

    var x4 = x3;
    x6 = x4;
  } else {
    var x5;

    if (a5) {
      x5 = x2;
    } else {
      x5 = a6;
    }

    x6 = f2(x5);
  }

  return x6;
}
```

So far I’ve reported four bugs reduced from test cases found by this version of the fuzzer. I’ve reported a couple more from old fuzzers I used, but these four from the current version. The shrinking process is not that good and it takes a while as the generated program can get large, so you’ll usually have to do some manual shrinking to get good bug reports. I only ran `yarn fuzz-overnight` for about an hour. It found 28 failures and I reduced those down to these 4.

- #2354
- #2355
- #2361
- #2363

I expect I’ll find more bugs as these get fixed and I add more JavaScript features to the fuzzer. The features I currently have are:

- Scalar primitives (number, string, boolean, null/undefined)
- Functions
- Conditional expressions
- If statements
- Variable declarations

Not too many features, but enough to catch a handful of bugs.

> **Note:** If this PR is too much to review, I’ve created [`calebmer/prepack-fuzzer`](https://github.com/calebmer/prepack-fuzzer) in which my work is broken up into commits as I made them. I then copied these files over to the Prepack repo.

The fuzzer in this PR is a rewrite from the [fuzzer I started with](https://gist.github.com/calebmer/75dd75ebe556681d3a628e75eaffc403). The main lessons I learned from that one are that I should start with a general JS fuzzer instead of a React fuzzer (since adding JS features after the fact to fuzzer designed for React is difficult) and that all nested structures need to be generated with one recursive generator from the generator library I’m using.

To generate programs I use [`leebyron/testcheck`](https://github.com/leebyron/testcheck-js) which is actually a JS compiled version of the official Clojure library [`clojure/test.check`](https://github.com/clojure/test.check). `testcheck` is designed for generative property testing at a much smaller scale then program fuzzing. So I am abusing the library a bit to use it as a fuzzer. My reasoning is that I wanted to write the fuzzer in JS (to have access to the Babel AST) and I didn’t want to write my own case generating framework. If we outgrow `testcheck` then we can keep the DSL, but rewrite the generation/shrinking logic. Although its been working fine for me so far. (Yet I am using a forked version which simply uses some unpublished features in the `testcheck` repo.)

The generator code in `fuzzer/src/gen.js` may look odd to you. It uses immutable.js and a **state monad** implemented with a JS generator so the code looks imperative. I need state since generating various program components depends on things like “what variables are declared at a given point in time,” but because I’m limited to only using a single recursive generator (based on performance lessons I learned from my first fuzzer) I can’t pass around state at the generator level and must instead maintain state at the result level. At first I tried hacking together some imperative state, but when shrinking programs `testcheck` replays some generators to get new programs. So what do you do when you need a stateful process that needs to be replayed? You use a monad.

I could try to fix the bugs I found, but I’d like to find more bugs. I need to add back support for React components and I need to add more language features.

_Which JS language features are the most interesting to fuzz?_

I ranked all the kinds of AST nodes in our internal React bundle [and got this](https://gist.github.com/calebmer/be5e2bad4b12af683522096544fc9568). I’ll be starting with that, but the Prepack team has a better intuition around what’s good for fuzzing. I know there’s been a discussion around temporals recently that I haven’t really been following. What would be good ways to trigger this behavior?
Pull Request resolved: https://github.com/facebook/prepack/pull/2374

Differential Revision: D9180836

Pulled By: calebmer

fbshipit-source-id: 59d3fb59ecc1026a865672e2833f7482ed72139a
This commit is contained in:
Caleb Meredith 2018-08-09 10:35:07 -07:00 committed by Facebook Github Bot
parent efc807f5f4
commit 4319298f88
12 changed files with 1610 additions and 1 deletions

8
fuzzer/.eslintrc Normal file
View File

@ -0,0 +1,8 @@
{
"env": {
"node": true
},
"rules": {
"flow-header/flow-header": "off"
}
}

4
fuzzer/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
node_modules
.DS_Store
yarn-error.log
overnight.sqlite

20
fuzzer/package.json Normal file
View File

@ -0,0 +1,20 @@
{
"private": true,
"name": "prepack-fuzzer",
"version": "0.0.0-unversioned",
"license": "UNLICENSED",
"scripts": {
"sample": "node src/sample.js",
"test": "node src/test.js",
"overnight": "node src/overnight.js"
},
"dependencies": {
"@babel/generator": "^7.0.0-beta.55",
"@babel/types": "^7.0.0-beta.55",
"chalk": "^2.4.1",
"immutable": "^3.8.2",
"pretty-ms": "^3.2.0",
"sqlite3": "^4.0.2",
"testcheck": "npm:@calebmer/testcheck@1.0.0-rc.5"
}
}

76
fuzzer/src/execute.js Normal file
View File

@ -0,0 +1,76 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
const vm = require("vm");
const { prepackSources } = require("../../lib/prepack-node.js");
function executeNormal(code) {
const context = createVmContext();
vm.runInContext(code, context);
const inspect = context.module.exports;
try {
const value = inspect();
return { error: false, value };
} catch (error) {
return { error: true, value: error };
}
}
function executePrepack(code) {
let prepackedCode;
try {
prepackedCode = prepackSources([{ fileContents: code, filePath: "test.js" }], prepackOptions).code;
} catch (error) {
return { error: true, value: error };
}
const context = createVmContext();
vm.runInContext(prepackedCode, context);
const inspect = context.module.exports;
try {
const value = inspect();
return { error: false, value };
} catch (error) {
return { error: true, value: error };
}
}
function createVmContext() {
const sandbox = {
module: { exports: {} },
};
sandbox.global = sandbox;
return vm.createContext(sandbox);
}
const prepackOptions = {
errorHandler: diag => {
if (diag.severity === "Information") return "Recover";
if (diag.errorCode === "PP0025") return "Recover";
if (diag.severity !== "Warning") return "Fail";
return "Recover";
},
compatibility: "fb-www",
internalDebug: true,
serialize: true,
uniqueSuffix: "",
maxStackDepth: 100,
instantRender: false,
reactEnabled: true,
reactOutput: "create-element",
reactVerbose: true,
reactOptimizeNestedFunctions: false,
inlineExpressions: true,
invariantLevel: 3,
abstractValueImpliesMax: 1000,
};
module.exports = {
executeNormal,
executePrepack,
};

452
fuzzer/src/gen.js Normal file
View File

@ -0,0 +1,452 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
const t = require("@babel/types");
const Immutable = require("immutable");
const { gen } = require("testcheck");
const ScopeRecord = Immutable.Record({
variables: Immutable.List(),
functions: Immutable.List(),
});
const StateRecord = Immutable.Record({
declarations: Immutable.List(),
scopes: Immutable.List([ScopeRecord()]),
nextVariableId: 1,
nextFunctionId: 1,
nextArgumentId: 1,
});
const genString = gen.array(gen.asciiChar, { maxSize: 20 }).then(chars => chars.join(""));
const genValueLiteral = gen.oneOfWeighted([
// null / undefined
[1, gen.oneOf([gen.return(t.nullLiteral()), gen.return(t.identifier("undefined"))])],
// number
[1, gen.number.then(n => gen.return(t.numericLiteral(n)))],
// string
[1, genString.then(s => gen.return(t.stringLiteral(s)))],
// boolean
[7, gen.oneOf([gen.return(t.booleanLiteral(true)), gen.return(t.booleanLiteral(false))])],
]);
function createGenComputation() {
const _getStateSymbol = Symbol("getState");
function* getState() {
return yield _getStateSymbol;
}
function* putState(nextState) {
yield nextState;
}
function* replaceState(f) {
yield f(yield _getStateSymbol);
}
function* newVariable() {
let state = yield* getState();
const name = `x${state.nextVariableId}`;
state = state.update("nextVariableId", x => x + 1).updateIn(["scopes", -1, "variables"], vs => vs.push({ name }));
yield* putState(state);
return name;
}
function* newFunction(arity) {
let state = yield* getState();
const name = `f${state.nextFunctionId}`;
state = state
.update("nextFunctionId", x => x + 1)
.updateIn(["scopes", -1, "functions"], fs => fs.push({ name, arity }));
yield* putState(state);
return name;
}
function* newArgument() {
let state = yield* getState();
const name = `a${state.nextArgumentId}`;
state = state.update("nextArgumentId", x => x + 1).updateIn(["scopes", -1, "variables"], vs => vs.push({ name }));
yield* putState(state);
return name;
}
const genScalarComputation = gen.oneOfWeighted([
[
1,
genValueLiteral.then(expression => {
const result = {
statements: Immutable.List(),
expression,
};
return {
args: 0,
*computation() {
return result;
},
};
}),
],
// Reuse variable
[
2,
gen.posInt.then(n => ({
args: 0,
*computation() {
const state = yield* getState();
const variables = Immutable.List().concat(...state.scopes.map(scope => scope.variables));
if (variables.isEmpty()) {
// If we have no variables to reuse then return something else.
return {
statements: Immutable.List(),
expression: t.numericLiteral(n),
};
} else {
const variable = variables.get(n % variables.size);
return {
statements: Immutable.List(),
expression: t.identifier(variable.name),
};
}
},
})),
],
// Argument
[
4,
gen.return({
args: 1,
*computation() {
const expression = t.identifier(yield* newArgument());
return {
statements: Immutable.List(),
expression,
};
},
}),
],
// // Intentional failure. Uncomment this to test if everything is working.
// [
// 1,
// gen.return({
// args: 0,
// *computation() {
// const expression = t.conditionalExpression(
// t.memberExpression(
// t.identifier('global'),
// t.identifier('__optimize')
// ),
// t.booleanLiteral(true),
// t.booleanLiteral(false)
// );
// return {statements: Immutable.List(), expression};
// },
// }),
// ],
]);
function* conditional(computation) {
yield* replaceState(state => state.update("scopes", scopes => scopes.push(ScopeRecord())));
const result = yield* computation();
yield* replaceState(state => state.update("scopes", scope => scope.pop()));
return result;
}
const genNestedComputation = genComputation =>
gen.oneOfWeighted([
// condition ? consequent : alternate
[
5,
gen([genComputation, genComputation, genComputation]).then(([c, tr, fa]) => ({
args: c.args + tr.args + fa.args,
*computation() {
const condition = yield* c.computation();
let statements = condition.statements;
// Conditionally generate consequent and alternate.
const consequent = yield* conditional(tr.computation);
const alternate = yield* conditional(fa.computation);
// If our consequent and/or alternate have statements then we need
// to hoist these statements to an if-statement.
const conditionReuse =
(!consequent.statements.isEmpty() || !alternate.statements.isEmpty()) &&
t.identifier(yield* newVariable());
if (conditionReuse) {
statements = statements.push(
t.variableDeclaration("var", [t.variableDeclarator(conditionReuse, condition.expression)])
);
if (consequent.statements.isEmpty() && !alternate.statements.isEmpty()) {
statements = statements.push(
t.ifStatement(
t.unaryExpression("!", conditionReuse),
t.blockStatement(alternate.statements.toArray())
)
);
} else {
statements = statements.push(
t.ifStatement(
conditionReuse,
t.blockStatement(consequent.statements.toArray()),
alternate.statements.size === 0 ? undefined : t.blockStatement(alternate.statements.toArray())
)
);
}
}
return {
statements,
expression: t.conditionalExpression(
conditionReuse || condition.expression,
consequent.expression,
alternate.expression
),
};
},
})),
],
// if (condition) { consequent } else { alternate }
[
10,
gen([
genComputation,
genComputation,
genComputation,
gen.oneOfWeighted([[1, gen.return(true)], [5, gen.return(false)]]),
gen.oneOfWeighted([[1, gen.return(true)], [5, gen.return(false)]]),
]).then(([c, tr, fa, returnConsequent, returnAlternate]) => ({
args: c.args + tr.args + fa.args,
*computation() {
const condition = yield* c.computation();
const consequent = yield* conditional(tr.computation);
const alternate = yield* conditional(fa.computation);
const variable = yield* newVariable();
let { statements } = condition;
let consequentStatements = consequent.statements;
let alternateStatements = alternate.statements;
statements = statements.push(t.variableDeclaration("var", [t.variableDeclarator(t.identifier(variable))]));
if (returnConsequent) {
consequentStatements = consequentStatements.push(t.returnStatement(consequent.expression));
} else {
consequentStatements = consequentStatements.push(
t.expressionStatement(t.assignmentExpression("=", t.identifier(variable), consequent.expression))
);
}
if (returnAlternate) {
alternateStatements = alternateStatements.push(t.returnStatement(alternate.expression));
} else {
alternateStatements = alternateStatements.push(
t.expressionStatement(t.assignmentExpression("=", t.identifier(variable), alternate.expression))
);
}
statements = statements.push(
t.ifStatement(
condition.expression,
t.blockStatement(consequentStatements.toArray()),
t.blockStatement(alternateStatements.toArray())
)
);
return {
statements,
expression: t.identifier(variable),
};
},
})),
],
// var id = init;
[
20,
genComputation.then(({ args, computation }) => ({
args,
*computation() {
const { statements, expression } = yield* computation();
const variable = yield* newVariable();
return {
statements: statements.push(
t.variableDeclaration("var", [t.variableDeclarator(t.identifier(variable), expression)])
),
expression: t.identifier(variable),
};
},
})),
],
// function f(...args) { body }
[
15,
genComputation
.then(({ args, computation }) => ({
computation,
argComputations: Array(args).fill(genComputation),
}))
.then(({ computation, argComputations }) => ({
args: argComputations.reduce((acc, c) => acc + c.args, 0),
*computation() {
// Generate our computation in a new state with new scopes. Then
// restore the old state.
const prevState = yield* getState();
const prevNextVariableId = prevState.get("nextVariableId");
const prevNextArgumentId = prevState.get("nextArgumentId");
const prevScopes = prevState.get("scopes");
yield* replaceState(state =>
state
.set("nextVariableId", 1)
.set("nextArgumentId", 1)
.set("scopes", Immutable.List([ScopeRecord()]))
);
const fn = yield* computation();
yield* replaceState(state =>
state
.set("nextVariableId", prevNextVariableId)
.set("nextArgumentId", prevNextArgumentId)
.set("scopes", prevScopes)
);
// Create the function declaration.
const functionStatements = fn.statements.push(t.returnStatement(fn.expression));
const functionName = yield* newFunction(argComputations.length);
const functionDeclaration = t.functionDeclaration(
t.identifier(functionName),
argComputations.map((_, i) => t.identifier(`a${i + 1}`)),
t.blockStatement(functionStatements.toArray())
);
yield* replaceState(state =>
state.update("declarations", declarations => declarations.push(functionDeclaration))
);
// Compute the arguments.
let statements = Immutable.List();
const args = [];
for (const { computation: argComputation } of argComputations) {
const arg = yield* argComputation();
statements = statements.concat(arg.statements);
args.push(arg.expression);
}
return {
statements,
expression: t.callExpression(t.identifier(functionName), args),
};
},
})),
],
// ignored; computation
[
1,
gen([genComputation, genComputation]).then(
([{ args: ignoredArgs, computation: ignoredComputation }, { args, computation }]) => ({
args: ignoredArgs + args,
*computation() {
const { statements: ignoredStatements, expression: ignoredExpression } = yield* ignoredComputation();
const { statements, expression } = yield* computation();
return {
statements: ignoredStatements.push(t.expressionStatement(ignoredExpression)).concat(statements),
expression,
};
},
})
),
],
]);
// Wrap for at least one level of nesting.
const genComputation = genNestedComputation(gen.nested(genNestedComputation, genScalarComputation));
// Runer for the state monad we use for computations. We want to use some
// state in our computations. This is why we use a monad.
return genComputation.then(({ args, computation }) => {
const generator = computation();
let state = StateRecord();
let step = generator.next();
while (!step.done) {
if (step.value === _getStateSymbol) {
step = generator.next(state);
} else {
state = step.value;
step = generator.next();
}
}
return gen.return({
args,
computation: step.value,
declarations: state.declarations,
});
});
}
const genProgramStatements = createGenComputation()
.then(({ args, computation, declarations }) => ({
args: gen.array(genValueLiteral, { size: args }),
computation: gen.return(computation),
declarations: gen.return(declarations),
}))
.then(({ args, computation: { statements: mainStatements, expression: mainExpression }, declarations }) => {
mainStatements = mainStatements.push(t.returnStatement(mainExpression));
const statements = [];
statements.push(t.expressionStatement(t.stringLiteral("use strict")));
declarations.forEach(declaration => {
statements.push(declaration);
});
statements.push(
t.functionDeclaration(
t.identifier("main"),
args.map((arg, i) => t.identifier(`a${i + 1}`)),
t.blockStatement(mainStatements.toArray())
)
);
statements.push(
t.ifStatement(
t.memberExpression(t.identifier("global"), t.identifier("__optimize")),
t.expressionStatement(t.callExpression(t.identifier("__optimize"), [t.identifier("main")]))
)
);
statements.push(
t.expressionStatement(
t.assignmentExpression(
"=",
t.memberExpression(t.identifier("module"), t.identifier("exports")),
t.functionExpression(
t.identifier("inspect"),
[],
t.blockStatement([t.returnStatement(t.callExpression(t.identifier("main"), args))])
)
)
)
);
return gen.return(statements);
});
const genProgram = genProgramStatements.then(statements => gen.return(t.program(statements)));
const genPrgramWrappedInIife = genProgramStatements.then(statements =>
gen.return(
t.program([
t.expressionStatement(t.callExpression(t.functionExpression(null, [], t.blockStatement(statements)), [])),
])
)
);
module.exports = {
genProgram,
genPrgramWrappedInIife,
};

123
fuzzer/src/overnight.js Normal file
View File

@ -0,0 +1,123 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
const path = require("path");
const cluster = require("cluster");
const os = require("os");
const chalk = require("chalk");
const sqlite3 = require("sqlite3");
const db = new sqlite3.Database(path.resolve(__dirname, "..", "overnight.sqlite"));
if (cluster.isMaster) {
console.log(`Master ${chalk.cyan(process.pid)} started`);
db.run(
`create table fuzz_error (
seed text,
code text,
expected_error bool,
expected text,
actual_error bool,
actual text
)`,
error => {
if (error) throw error;
db.close();
masterMain();
}
);
function masterMain() {
const aliveWorkers = new Map();
// Fork workers.
const cpus = os.cpus().length;
for (let i = 0; i < cpus; i++) {
forkWorker();
}
// Restart workers when they die.
cluster.on("exit", (worker, code, signal) => {
const pid = chalk.cyan(worker.process.pid);
const error = chalk.red(signal || code);
console.log(`Worker ${pid} died (${error}). Restarting...`);
forkWorker();
});
// Creates a new worker
function forkWorker() {
const worker = cluster.fork();
markWorkerAlive(worker);
worker.on("message", message => {
if (worker.isDead()) return;
if (message === "ping") markWorkerAlive(worker);
});
}
// Marks a worker as alive. We kill workers after 10 minutes of inactivity
// since the worker might be stuck in an infinite loop. Or might be trying
// to shrink a really large test case.
function markWorkerAlive(worker) {
// Clear the old timeout
if (aliveWorkers.has(worker)) {
clearTimeout(aliveWorkers.get(worker));
}
// Create a new timeout
const timeoutId = setTimeout(() => {
const pid = chalk.cyan(worker.process.pid);
console.log(`Havent heard from worker ${pid} in 10 minutes. Killing...`);
// Hard kill since we suspect the process is in an infinite loop so the
// process cant receive an IPC message.
process.kill(worker.process.pid, "SIGKILL");
aliveWorkers.delete(worker);
}, 1000 * 60 * 10);
aliveWorkers.set(worker, timeoutId);
}
}
} else {
console.log(`Worker ${chalk.cyan(process.pid)} started`);
// Make the reporter a noop.
require("./report").reportTestFinish = () => {};
const { check } = require("testcheck");
const { executeNormal, executePrepack } = require("./execute");
const { prepackWorks } = require("./property");
const insert = db.prepare(`insert into fuzz_error values (?, ?, ?, ?, ?, ?)`);
loop();
function loop() {
process.send("ping");
const test = check(prepackWorks, { numTests: Infinity, maxSize: 200 });
process.send("ping");
console.log(`Worker ${chalk.cyan(process.pid)} found a failing test case`);
// Add all the failing test cases to the database.
test.shrunk.smallest.forEach((code, i) => {
const expected = executeNormal(code);
const actual = executePrepack(code);
insert.run(
test.seed.toString(),
code,
expected.error,
expected.error ? expected.value.stack : JSON.stringify(expected.value),
actual.error,
actual.error ? actual.value.stack : JSON.stringify(actual.value),
error => {
if (error) throw error;
loop();
}
);
});
}
}

47
fuzzer/src/property.js Normal file
View File

@ -0,0 +1,47 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
const generate = require("@babel/generator").default;
const { gen, property } = require("testcheck");
const { executeNormal, executePrepack } = require("./execute");
const { genPrgramWrappedInIife } = require("./gen");
const { ReportStatus, reportTestFinish } = require("./report");
/**
* Tests if the output of a Prepacked program is the same as the output of the
* un-Prepacked program.
*/
const prepackWorks = property(genPrgramWrappedInIife.then(program => gen.return(generate(program).code)), code => {
const start = Date.now();
try {
const expected = executeNormal(code);
const actual = executePrepack(code);
const ok = expected.error ? actual.error : expected.value === actual.value;
const end = Date.now();
const time = end - start;
reportTestFinish(time, ok ? ReportStatus.pass : ReportStatus.fail);
return ok;
} catch (error) {
const end = Date.now();
const time = end - start;
if (error.message.includes("timed out")) {
// Ignore programs which time out.
reportTestFinish(time, ReportStatus.skip);
return true;
} else {
reportTestFinish(time, ReportStatus.fail);
return false;
}
}
});
module.exports = {
prepackWorks,
};

45
fuzzer/src/report.js Normal file
View File

@ -0,0 +1,45 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
const chalk = require("chalk");
const prettyMs = require("pretty-ms");
const ReportStatus = {
pass: "pass",
fail: "fail",
skip: "timeout",
};
const statusIcon = {
pass: chalk.green("✔"),
fail: chalk.red("✘"),
skip: chalk.yellow("!"),
};
const statusVerb = {
pass: "passed",
fail: "failed",
skip: "skipped",
};
const divider = chalk.dim("┈".repeat(process.stdout.columns));
function reportTestFinish(time, status) {
const icon = statusIcon[status];
const verb = statusVerb[status];
console.log(`${icon} Test ${verb} in ${prettyMs(time)}`);
}
module.exports = {
ReportStatus,
passIcon: statusIcon.pass,
failIcon: statusIcon.fail,
divider,
reportTestFinish,
};

24
fuzzer/src/sample.js Normal file
View File

@ -0,0 +1,24 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
const generate = require("@babel/generator").default;
const { sample } = require("testcheck");
const { genProgram } = require("./gen");
const { divider } = require("./report");
Error.stackTraceLimit = Infinity;
const genCode = genProgram.then(program => generate(program).code);
const samples = sample(genCode);
console.log(divider);
samples.forEach(e => {
console.log(e);
console.log(divider);
});

49
fuzzer/src/test.js Normal file
View File

@ -0,0 +1,49 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
const util = require("util");
const chalk = require("chalk");
const { check } = require("testcheck");
const { executeNormal, executePrepack } = require("./execute");
const { prepackWorks } = require("./property");
const { passIcon, failIcon, divider } = require("./report");
console.log(divider);
const test = check(prepackWorks, { numTests: 1000, maxSize: 200 });
console.log(divider);
const { seed, numTests } = test;
const plural = numTests === 1 ? "" : "s";
if (test.result === true) {
// Yay! No failures.
console.log(`${passIcon} Passed after running ${numTests} test${plural} ` + `with seed ${seed}`);
} else {
// Uh, oh. A failure!
console.error(`${failIcon} Failed after running ${numTests} test${plural} ` + `with seed ${seed}`);
if (test.result !== false) {
console.error(chalk.red(test.result.stack));
}
// Log the shrunk failure case and the args which caused it to fail.
test.shrunk.smallest.forEach((code, i) => {
console.error(divider);
console.error(code);
console.error(divider);
const expected = executeNormal(code);
const actual = executePrepack(code);
console.error(`${chalk.dim("Expected:")} ${inspect(expected.value)}`);
console.error(` ${chalk.dim("Actual:")} ${inspect(actual.value)}`);
});
console.error(divider);
}
function inspect(value) {
return util.inspect(value, { colors: true });
}

758
fuzzer/yarn.lock Normal file
View File

@ -0,0 +1,758 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@babel/generator@^7.0.0-beta.55":
version "7.0.0-beta.55"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.55.tgz#8ec11152dcc398bae35dd181122704415c383a01"
dependencies:
"@babel/types" "7.0.0-beta.55"
jsesc "^2.5.1"
lodash "^4.17.10"
source-map "^0.5.0"
trim-right "^1.0.1"
"@babel/types@7.0.0-beta.55", "@babel/types@^7.0.0-beta.55":
version "7.0.0-beta.55"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.55.tgz#7755c9d2e58315a64f05d8cf3322379be16d9199"
dependencies:
esutils "^2.0.2"
lodash "^4.17.10"
to-fast-properties "^2.0.0"
abbrev@1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
ajv@^5.1.0:
version "5.5.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
dependencies:
co "^4.6.0"
fast-deep-equal "^1.0.0"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.3.0"
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
ansi-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
dependencies:
color-convert "^1.9.0"
aproba@^1.0.3:
version "1.2.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
are-we-there-yet@~1.1.2:
version "1.1.5"
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
dependencies:
delegates "^1.0.0"
readable-stream "^2.0.6"
asn1@~0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
dependencies:
safer-buffer "~2.1.0"
assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
aws4@^1.6.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289"
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
bcrypt-pbkdf@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
dependencies:
tweetnacl "^0.14.3"
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
chalk@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chownr@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181"
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
color-convert@^1.9.0:
version "1.9.2"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147"
dependencies:
color-name "1.1.1"
color-name@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689"
combined-stream@1.0.6, combined-stream@~1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
dependencies:
delayed-stream "~1.0.0"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
console-control-strings@^1.0.0, console-control-strings@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
dependencies:
assert-plus "^1.0.0"
debug@^2.1.2:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
dependencies:
ms "2.0.0"
deep-extend@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
detect-libc@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
ecc-jsbn@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
dependencies:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
extend@~3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
extsprintf@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
fast-deep-equal@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
fast-json-stable-stringify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
form-data@~2.3.1:
version "2.3.2"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099"
dependencies:
asynckit "^0.4.0"
combined-stream "1.0.6"
mime-types "^2.1.12"
fs-minipass@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
dependencies:
minipass "^2.2.1"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
gauge@~2.7.3:
version "2.7.4"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
dependencies:
aproba "^1.0.3"
console-control-strings "^1.0.0"
has-unicode "^2.0.0"
object-assign "^4.1.0"
signal-exit "^3.0.0"
string-width "^1.0.1"
strip-ansi "^3.0.1"
wide-align "^1.1.0"
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
dependencies:
assert-plus "^1.0.0"
glob@^7.0.5:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
har-validator@~5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd"
dependencies:
ajv "^5.1.0"
har-schema "^2.0.0"
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
has-unicode@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
dependencies:
assert-plus "^1.0.0"
jsprim "^1.2.2"
sshpk "^1.7.0"
iconv-lite@^0.4.4:
version "0.4.23"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
dependencies:
safer-buffer ">= 2.1.2 < 3"
ignore-walk@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
dependencies:
minimatch "^3.0.4"
immutable@^3.8.2:
version "3.8.2"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
ini@~1.3.0:
version "1.3.5"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
is-fullwidth-code-point@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
dependencies:
number-is-nan "^1.0.0"
is-fullwidth-code-point@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
jsesc@^2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe"
json-schema-traverse@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
dependencies:
assert-plus "1.0.0"
extsprintf "1.3.0"
json-schema "0.2.3"
verror "1.10.0"
lodash@^4.17.10:
version "4.17.10"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
mime-db@~1.35.0:
version "1.35.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47"
mime-types@^2.1.12, mime-types@~2.1.17:
version "2.1.19"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0"
dependencies:
mime-db "~1.35.0"
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
brace-expansion "^1.1.7"
minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
minipass@^2.2.1, minipass@^2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233"
dependencies:
safe-buffer "^5.1.2"
yallist "^3.0.0"
minizlib@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb"
dependencies:
minipass "^2.2.1"
mkdirp@^0.5.0, mkdirp@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
dependencies:
minimist "0.0.8"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
nan@~2.10.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f"
needle@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d"
dependencies:
debug "^2.1.2"
iconv-lite "^0.4.4"
sax "^1.2.4"
node-pre-gyp@^0.10.3:
version "0.10.3"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc"
dependencies:
detect-libc "^1.0.2"
mkdirp "^0.5.1"
needle "^2.2.1"
nopt "^4.0.1"
npm-packlist "^1.1.6"
npmlog "^4.0.2"
rc "^1.2.7"
rimraf "^2.6.1"
semver "^5.3.0"
tar "^4"
nopt@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
dependencies:
abbrev "1"
osenv "^0.1.4"
npm-bundled@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308"
npm-packlist@^1.1.6:
version "1.1.11"
resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de"
dependencies:
ignore-walk "^3.0.1"
npm-bundled "^1.0.1"
npmlog@^4.0.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
dependencies:
are-we-there-yet "~1.1.2"
console-control-strings "~1.1.0"
gauge "~2.7.3"
set-blocking "~2.0.0"
number-is-nan@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
oauth-sign@~0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
object-assign@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
dependencies:
wrappy "1"
os-homedir@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
os-tmpdir@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
osenv@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
dependencies:
os-homedir "^1.0.0"
os-tmpdir "^1.0.0"
parse-ms@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d"
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
performance-now@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
pretty-ms@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-3.2.0.tgz#87a8feaf27fc18414d75441467d411d6e6098a25"
dependencies:
parse-ms "^1.0.0"
process-nextick-args@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
qs@~6.5.1:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
rc@^1.2.7:
version "1.2.8"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
dependencies:
deep-extend "^0.6.0"
ini "~1.3.0"
minimist "^1.2.0"
strip-json-comments "~2.0.1"
readable-stream@^2.0.6:
version "2.3.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~2.0.0"
safe-buffer "~5.1.1"
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
request@^2.87.0:
version "2.87.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e"
dependencies:
aws-sign2 "~0.7.0"
aws4 "^1.6.0"
caseless "~0.12.0"
combined-stream "~1.0.5"
extend "~3.0.1"
forever-agent "~0.6.1"
form-data "~2.3.1"
har-validator "~5.0.3"
http-signature "~1.2.0"
is-typedarray "~1.0.0"
isstream "~0.1.2"
json-stringify-safe "~5.0.1"
mime-types "~2.1.17"
oauth-sign "~0.8.2"
performance-now "^2.1.0"
qs "~6.5.1"
safe-buffer "^5.1.1"
tough-cookie "~2.3.3"
tunnel-agent "^0.6.0"
uuid "^3.1.0"
rimraf@^2.6.1:
version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
dependencies:
glob "^7.0.5"
safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
sax@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
semver@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
set-blocking@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
signal-exit@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
source-map@^0.5.0:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
sqlite3@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-4.0.2.tgz#1bbeb68b03ead5d499e42a3a1b140064791c5a64"
dependencies:
nan "~2.10.0"
node-pre-gyp "^0.10.3"
request "^2.87.0"
sshpk@^1.7.0:
version "1.14.2"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98"
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
dashdash "^1.12.0"
getpass "^0.1.1"
safer-buffer "^2.0.2"
optionalDependencies:
bcrypt-pbkdf "^1.0.0"
ecc-jsbn "~0.1.1"
jsbn "~0.1.0"
tweetnacl "~0.14.0"
string-width@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
dependencies:
code-point-at "^1.0.0"
is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0"
"string-width@^1.0.2 || 2":
version "2.1.1"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
dependencies:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
dependencies:
safe-buffer "~5.1.0"
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
dependencies:
ansi-regex "^2.0.0"
strip-ansi@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
dependencies:
ansi-regex "^3.0.0"
strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
supports-color@^5.3.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
dependencies:
has-flag "^3.0.0"
tar@^4:
version "4.4.6"
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b"
dependencies:
chownr "^1.0.1"
fs-minipass "^1.2.5"
minipass "^2.3.3"
minizlib "^1.1.0"
mkdirp "^0.5.0"
safe-buffer "^5.1.2"
yallist "^3.0.2"
"testcheck@npm:@calebmer/testcheck@1.0.0-rc.5":
version "1.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@calebmer/testcheck/-/testcheck-1.0.0-rc.5.tgz#f194b5cb1c37d09df47a75dd7857147b0f09b73c"
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
tough-cookie@~2.3.3:
version "2.3.4"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"
dependencies:
punycode "^1.4.1"
trim-right@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
dependencies:
safe-buffer "^5.0.1"
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
uuid@^3.1.0:
version "3.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
verror@1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
dependencies:
assert-plus "^1.0.0"
core-util-is "1.0.2"
extsprintf "^1.2.0"
wide-align@^1.1.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
dependencies:
string-width "^1.0.2 || 2"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
yallist@^3.0.0, yallist@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9"

View File

@ -59,7 +59,10 @@
"prettier": "node ./scripts/prettier.js write-changed",
"prettier-all": "node ./scripts/prettier.js write",
"prettier-ci": "node ./scripts/prettier.js",
"debug-fb-www": "node --stack_trace_limit=200 --stack_size=10000 --max_old_space_size=16384 ./scripts/debug-fb-www.js"
"debug-fb-www": "node --stack_trace_limit=200 --stack_size=10000 --max_old_space_size=16384 ./scripts/debug-fb-www.js",
"fuzz": "cd fuzzer && yarn && yarn test",
"fuzz-sample": "cd fuzzer && yarn && yarn sample",
"fuzz-overnight": "cd fuzzer && yarn && yarn overnight"
},
"dependencies": {
"@babel/core": "^7.0.0-beta.53",