Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 0 additions & 78 deletions src/convert.test.ts

This file was deleted.

106 changes: 8 additions & 98 deletions src/convert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ type FieldReturn = {

const withNamedFieldType = (namedTypeNode: NamedTypeNode): FieldReturn => {
const name = namedTypeNode.name.value as TypeName;
const output = `${getArbitraryName(name)}()` as Generated;
const output = `(limit > 0) ? ${getArbitraryName(
name
)}(limit - 1) : fc.constant(null)` as Generated;
return { output, deps: [name] };
};

Expand Down Expand Up @@ -193,107 +195,15 @@ const removeKind = (k: Kind) => (a: Output) => a.kind !== k;

const render = (val: Output) => {
const { name, output } = val;
const recurseLimit = 10;
return `export const ${getArbitraryName(
name
)} = (): fc.Arbitrary<any> => ${output}`;
)} = (limit = ${recurseLimit}): fc.Arbitrary<any> => ${output}`;
};

export const getSchemaDeclarations = (schema: GraphQLSchema): string =>
sortASTs2(getNamedTypes(schema).map(withNamedType).filter(notNull))
getNamedTypes(schema)
.map(withNamedType)
.filter(notNull)
.map(render)
.join("\n\n");

const sortASTs2 = <A>(a: A): A => a;

const filterSplit = <A>(
as: A[],
f: (a: A) => boolean
): { yes: A[]; no: A[] } => ({
yes: as.filter(f),
no: as.filter(a => !f(a))
});

export const sortASTs = (as: Output[]): Output[] => {
const limit = 10000;
return caseEither(magicSort(as, limit), {
onRight: payload => payload,
onLeft: err => {
throw err;
return [];
}
});
};

const showProgress = (used: Output[], remaining: Output[]): void => {
const unresolved = [
...new Set(remaining.map(a => a.deps).reduce((as, a) => as.concat(a), []))
];
const resolved = used.map(a => a.name);
console.log("RESOLVED", resolved);
console.log("UNRESOLVED", unresolved);
};

export const magicSort = (
as: Output[],
startingLimit: number
): Either<string, Output[]> => {
let limit = startingLimit;
let newRemaining = as;
let newUsed: Output[] = [];
let error = `Could not resolve ordering within ${startingLimit} tries`;
while (newRemaining.length > 0 && limit > 0) {
const succeeded = caseEither(moveASTs(newUsed, newRemaining), {
onRight: payload => {
newUsed = payload.used;
newRemaining = payload.remaining;
limit = limit - 1;
return true;
},
onLeft: err => {
error = err;
return false;
}
});
// showProgress(newUsed, newRemaining);
if (!succeeded) {
break;
}
}
if (newRemaining.length > 0) {
return left(error);
}
return right(newUsed);
};

type ASTReturn = Either<
string,
{
used: Output[];
remaining: Output[];
}
>;

export const moveASTs = (used: Output[], remaining: Output[]): ASTReturn => {
// remove everything in used from deps list
const usedDeps = used.map(a => a.name);

const remainingFiltered = remaining.map(a => ({
...a,
deps: a.deps.filter(dep => !usedDeps.includes(dep))
}));

// move everything with empty deps list left
const { yes: moved, no: keep } = filterSplit(
remainingFiltered,
a => a.deps.length === 0
);

// done
const newUsed = [...used, ...moved];
if (newUsed.length === used.length) {
return left(
`No changes made, unresolvable. ${newUsed.length} moved, ${keep.length} remaining to move.`
);
}
return right({ used: newUsed, remaining: keep });
};
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getSchemaDeclarations } from "./convert";
module.exports = {
plugin: (schema: GraphQLSchema, documents: any, config: any) => {
const declarations = getSchemaDeclarations(schema);
const output = `import * as fc from 'fast-check'\n${declarations}`;
const output = `import * as fc from 'fast-check'\nconst RECURSE_LIMIT=10\n${declarations}`;
return format(output, {
parser: "typescript"
});
Expand Down
44 changes: 30 additions & 14 deletions test/test-output.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,32 @@
import * as generated from "../output/twitter/output";
import * as twitter from "../output/twitter/output";
import * as github from "../output/github/output";
import * as fc from "fast-check";

const items: any = { ...generated };

Object.keys(items).forEach((key: string) => {
const func = items[key];
console.log(`---------------${key}-----------------`);
const arb = (func as any)();
fc.assert(
fc.property(arb, a => {
console.log(a);
return true;
})
);
});
const twitterItems: any = { ...twitter };

Object.keys(twitterItems)
.map((key: string) => {
const func = twitterItems[key];
const arb = (func as any)();
return [key, fc.sample(arb, 1)[0]];
})
.map(console.log);

const githubItems: any = { ...github };

console.log("github has ", Object.keys(githubItems).length, " items");

const someKeys = Object.keys(githubItems); // .slice(0, 110);

console.log("lets try out ", someKeys.length, " first");

// we can override this for fucking huge things that blow the stack
const recurseLimit = 4;

someKeys
.map((key: string) => {
const func = githubItems[key];
const arb = (func as any)(recurseLimit);
return [key, fc.sample(arb, 1)[0]];
})
.map(console.log);