Merge pull request #179 from quicktype/typescript-refinements

TypeScript refinements for `test/`
This commit is contained in:
David Siegel 2017-09-10 22:24:25 -07:00 коммит произвёл GitHub
Родитель cf444e3f88 51a98e649a
Коммит fbbe99a624
9 изменённых файлов: 885 добавлений и 586 удалений

11
.vscode/extensions.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1,11 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
"nwolverson.language-purescript",
"nwolverson.ide-purescript",
"esbenp.prettier-vscode",
"eg2.tslint"
]
}

1
.vscode/settings.json поставляемый
Просмотреть файл

@ -1,6 +1,7 @@
// Place your settings in this file to overwrite default and user settings.
{
"purescript.addNpmPath": true,
"editor.formatOnSave": true,
"search.exclude": {
"**/.git": true,
"**/node_modules": true,

Просмотреть файл

@ -14,12 +14,13 @@ $ npm run build
## Edit
Install [Visual Studio Code](https://code.visualstudio.com/), open this workspace,
and install the recommended extensions.
```shell
$ code . # open in VSCode
```
Install the `purescript-ide` extension in VSCode, then use the command pallete to start the `psc-ide` server for code completion, etc.
### Live-reloading for quick feedback
If you're working on a renderer, you'll likely want quick feedback on renderer output as you edit.

83
package-lock.json сгенерированный
Просмотреть файл

@ -226,6 +226,44 @@
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
"dev": true
},
"babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
"dev": true,
"requires": {
"chalk": "1.1.3",
"esutils": "2.0.2",
"js-tokens": "3.0.2"
},
"dependencies": {
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
"ansi-styles": "2.2.1",
"escape-string-regexp": "1.0.5",
"has-ansi": "2.0.0",
"strip-ansi": "3.0.1",
"supports-color": "2.0.0"
}
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
}
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@ -1451,6 +1489,12 @@
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"esutils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
"dev": true
},
"events": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
@ -3473,6 +3517,12 @@
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
"dev": true
},
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
"dev": true
},
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
@ -5488,6 +5538,39 @@
}
}
},
"tslib": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.7.1.tgz",
"integrity": "sha1-vIAEFkaRkjp5/oN4u+s9ogF1OOw=",
"dev": true
},
"tslint": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.7.0.tgz",
"integrity": "sha1-wl4NDJL6EgHCvDDoROCOaCtPNVI=",
"dev": true,
"requires": {
"babel-code-frame": "6.26.0",
"colors": "1.1.2",
"commander": "2.11.0",
"diff": "3.3.0",
"glob": "7.1.2",
"minimatch": "3.0.4",
"resolve": "1.4.0",
"semver": "5.4.1",
"tslib": "1.7.1",
"tsutils": "2.8.2"
}
},
"tsutils": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.8.2.tgz",
"integrity": "sha1-LBSGukMSYIRbCsb5Aq/Z1wio6mo=",
"dev": true,
"requires": {
"tslib": "1.7.1"
}
},
"tty-browserify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",

Просмотреть файл

@ -34,6 +34,7 @@
"purescript-psa": "^0.5.1",
"shelljs": "^0.7.8",
"ts-node": "^3.3.0",
"tslint": "^5.7.0",
"typescript": "^2.4.2",
"uglify-js": "^3.0.26"
},

Просмотреть файл

@ -1,119 +1,148 @@
function pathToString(path: string[]): string {
return path.join(".");
return path.join(".");
}
declare module Math {
// TypeScript cannot find this function
function fround(n: number): number;
declare namespace Math {
// TypeScript cannot find this function
function fround(n: number): number;
}
// https://stackoverflow.com/questions/1068834/object-comparison-in-javascript
export default function deepEquals(x: any, y: any, path: string[] = []): boolean {
// remember that NaN === NaN returns false
// and isNaN(undefined) returns true
if (typeof x === 'number' && typeof y === 'number') {
if (isNaN(x) && isNaN(y))
return true;
// because sometimes Newtonsoft.JSON is not exact
if (Math.fround(x) === Math.fround(y))
return true;
console.error(`Numbers are not equal at path ${pathToString(path)}.`);
return false;
export default function deepEquals(
x: any,
y: any,
path: string[] = []
): boolean {
// remember that NaN === NaN returns false
// and isNaN(undefined) returns true
if (typeof x === "number" && typeof y === "number") {
if (isNaN(x) && isNaN(y)) {
return true;
}
// Compare primitives and functions.
// Check if both arguments link to the same object.
// Especially useful on the step where we compare prototypes
if (x === y) {
return true;
// because sometimes Newtonsoft.JSON is not exact
if (Math.fround(x) === Math.fround(y)) {
return true;
}
console.error(`Numbers are not equal at path ${pathToString(path)}.`);
return false;
}
if (x instanceof String && y instanceof String) {
if (x.toString() !== y.toString()) {
console.error(`Number or string not equal at path ${pathToString(path)}.`);
return false;
}
return true;
}
// At last checking prototypes as good as we can
if (!(x instanceof Object && y instanceof Object)) {
console.error(`One is not an object at path ${pathToString(path)}.`)
return false;
}
if (x.constructor !== y.constructor) {
console.error(`Not the same constructor at path ${pathToString(path)}.`);
return false;
}
if (x.prototype !== y.prototype) {
console.error(`Not the same prototype at path ${pathToString(path)}.`);
return false;
}
if (Array.isArray(x)) {
if (x.length !== y.length){
console.error(`Arrays don't have the same length at path ${pathToString(path)}.`);
return false;
}
for (let i = 0; i < x.length; i++) {
path.push(i.toString());
if (!deepEquals(x[i], y[i], path))
return false;
path.pop();
}
return true;
}
// FIXMEL The way we're looking up properties with `indexOf` makes this
// quadratic. So far no problem, so meh.
const xKeys = Object.keys(x);
const yKeys = Object.keys(y);
for (const p of yKeys) {
// We allow properties in y that aren't present in x
// so long as they're null.
if (xKeys.indexOf(p) < 0) {
if (y[p] !== null) {
console.error(`Non-null property ${p} is not expected at path ${pathToString(path)}.`);
return false;
}
continue;
}
if (typeof y[p] !== typeof x[p]) {
console.error(`Properties ${p} don't have the same types at path ${pathToString(path)}.`);
return false;
}
}
for (const p of xKeys) {
if (yKeys.indexOf(p) < 0) {
console.error(`Expected property ${p} not found at path ${pathToString(path)}.`);
return false;
}
if (typeof x[p] !== typeof y[p]) {
console.error(`Properties ${p} don't have the same types at path ${pathToString(path)}.`);
return false;
}
switch (typeof(x[p])) {
case 'object':
path.push(p);
if (!deepEquals(x[p], y[p], path)) {
return false;
}
path.pop();
break;
default:
if (x[p] !== y[p]) {
console.error(`Non-object properties ${p} are not equal at path ${pathToString(path)}.`)
return false;
}
break;
}
}
// Compare primitives and functions.
// Check if both arguments link to the same object.
// Especially useful on the step where we compare prototypes
if (x === y) {
return true;
}
}
if (x instanceof String && y instanceof String) {
if (x.toString() !== y.toString()) {
console.error(
`Number or string not equal at path ${pathToString(path)}.`
);
return false;
}
return true;
}
// At last checking prototypes as good as we can
if (!(x instanceof Object && y instanceof Object)) {
console.error(`One is not an object at path ${pathToString(path)}.`);
return false;
}
if (x.constructor !== y.constructor) {
console.error(`Not the same constructor at path ${pathToString(path)}.`);
return false;
}
if (x.prototype !== y.prototype) {
console.error(`Not the same prototype at path ${pathToString(path)}.`);
return false;
}
if (Array.isArray(x)) {
if (x.length !== y.length) {
console.error(
`Arrays don't have the same length at path ${pathToString(path)}.`
);
return false;
}
for (let i = 0; i < x.length; i++) {
path.push(i.toString());
if (!deepEquals(x[i], y[i], path)) {
return false;
}
path.pop();
}
return true;
}
// FIXMEL The way we're looking up properties with `indexOf` makes this
// quadratic. So far no problem, so meh.
const xKeys = Object.keys(x);
const yKeys = Object.keys(y);
for (const p of yKeys) {
// We allow properties in y that aren't present in x
// so long as they're null.
if (xKeys.indexOf(p) < 0) {
if (y[p] !== null) {
console.error(
`Non-null property ${p} is not expected at path ${pathToString(
path
)}.`
);
return false;
}
continue;
}
if (typeof y[p] !== typeof x[p]) {
console.error(
`Properties ${p} don't have the same types at path ${pathToString(
path
)}.`
);
return false;
}
}
for (const p of xKeys) {
if (yKeys.indexOf(p) < 0) {
console.error(
`Expected property ${p} not found at path ${pathToString(path)}.`
);
return false;
}
if (typeof x[p] !== typeof y[p]) {
console.error(
`Properties ${p} don't have the same types at path ${pathToString(
path
)}.`
);
return false;
}
switch (typeof x[p]) {
case "object":
path.push(p);
if (!deepEquals(x[p], y[p], path)) {
return false;
}
path.pop();
break;
default:
if (x[p] !== y[p]) {
console.error(
`Non-object properties ${p} are not equal at path ${pathToString(
path
)}.`
);
return false;
}
break;
}
}
return true;
}

Просмотреть файл

@ -2,87 +2,97 @@ import * as cluster from "cluster";
import * as process from "process";
import * as _ from "lodash";
const exit = require('exit');
const exit = require("exit");
const WORKERS = ["👷🏻", "👷🏼", "👷🏽", "👷🏾", "👷🏿"];
export interface ParallelArgs<Item, Result, Acc> {
queue: Item[]
workers: number;
setup(): Promise<Acc>;
map(item: Item, index: number): Promise<Result>;
reduce?(accum: Acc, result: Result, item: Item): Promise<Acc>;
done?(accum: Acc);
queue: Item[];
workers: number;
setup(): Promise<Acc>;
map(item: Item, index: number): Promise<Result>;
reduce?(accum: Acc, result: Result, item: Item): Promise<Acc>;
done?(accum: Acc);
}
function randomPick<T>(arr: T[]): T {
return arr[Math.floor(Math.random() * arr.length)];
return arr[Math.floor(Math.random() * arr.length)];
}
function guys(n: number): string {
return _.range(n).map((i) => randomPick(WORKERS)).join(' ');
return _.range(n)
.map(i => randomPick(WORKERS))
.join(" ");
}
export async function inParallel<Item, Result, Acc>(args: ParallelArgs<Item, Result, Acc>) {
let { queue } = args;
let total = queue.length;
let items = queue.map((item, i) => {
return { item, i };
export async function inParallel<Item, Result, Acc>(
args: ParallelArgs<Item, Result, Acc>
) {
let { queue } = args;
let total = queue.length;
let items = queue.map((item, i) => {
return { item, i };
});
if (cluster.isMaster) {
let { setup, reduce, workers, done, map } = args;
let accumulator = await setup();
cluster.on("message", (worker, { result, item }) => {
if (result && reduce) {
reduce(accumulator, result, item);
}
if (items.length) {
worker.send(items.shift());
} else {
worker.kill();
if (_.isEmpty(cluster.workers)) {
if (done) {
done(accumulator);
}
}
}
});
if (cluster.isMaster) {
let { setup, reduce, workers, done, map } = args;
let accumulator = await setup();
cluster.on("exit", (worker, code, signal) => {
if (code && code !== 0) {
// Kill workers and exit if any worker dies
_.forIn(cluster.workers, w => w.kill());
exit(code);
}
});
cluster.on("message", (worker, { result, item }) => {
result && reduce && reduce(accumulator, result, item);
if (items.length) {
worker.send(items.shift());
} else {
worker.kill();
if (_.isEmpty(cluster.workers)) {
done && done(accumulator);
}
}
});
cluster.on("exit", (worker, code, signal) => {
if (code && code !== 0) {
// Kill workers and exit if any worker dies
_.forIn(cluster.workers, (w) => w.kill());
exit(code);
}
});
console.error(`* Forking ${workers} workers ${guys(workers)}`);
if (workers < 2) {
// We run everything on the master process if only one worker
for (let { item, i } of items) {
let result = await map(item, i);
accumulator = reduce && await reduce(accumulator, result, item);
}
return done && done(accumulator);
} else {
_.range(workers).forEach((i) => cluster.fork({
worker: i,
// https://github.com/TypeStrong/ts-node/issues/367
TS_NODE_PROJECT: "test/tsconfig.json"
}));
}
console.error(`* Forking ${workers} workers ${guys(workers)}`);
if (workers < 2) {
// We run everything on the master process if only one worker
for (let { item, i } of items) {
let result = await map(item, i);
accumulator = reduce && (await reduce(accumulator, result, item));
}
return done && done(accumulator);
} else {
// Setup a worker
let { map } = args;
// master sends a { fixtureName, sample } to run
process.on('message', async ({ item, i }) => {
process.send({
result: await map(item, i)
});
});
// Ask master for work
process.send("ready");
_.range(workers).forEach(i =>
cluster.fork({
worker: i,
// https://github.com/TypeStrong/ts-node/issues/367
TS_NODE_PROJECT: "test/tsconfig.json"
})
);
}
}
} else {
// Setup a worker
let { map } = args;
// master sends a { fixtureName, sample } to run
process.on("message", async ({ item, i }) => {
process.send({
result: await map(item, i)
});
});
// Ask master for work
process.send("ready");
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

95
test/tslint.json Normal file
Просмотреть файл

@ -0,0 +1,95 @@
{
"rules": {
"align": [true, "parameters", "statements"],
"ban": false,
"class-name": true,
"comment-format": [true, "check-space"],
"curly": true,
"eofline": false,
"forin": true,
"indent": [true, "spaces"],
"interface-name": [true, "never-prefix"],
"jsdoc-format": true,
"jsx-no-lambda": false,
"jsx-no-multiline-js": false,
"label-position": true,
"max-line-length": false,
"member-ordering": [
true,
// "public-before-private",
"static-before-instance"
//"variables-before-functions"
],
// TODO Turn this back on eventually
"no-any": false,
"no-arg": true,
"no-bitwise": true,
"no-console": [
false,
"log",
"error",
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-consecutive-blank-lines": true,
"no-construct": true,
"no-debugger": true,
"no-duplicate-variable": true,
"no-empty": [true, "allow-empty-catch"],
"no-eval": true,
"no-shadowed-variable": true,
"no-string-literal": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": false,
"no-unused-expression": true,
"no-use-before-declare": true,
"one-line": [
true,
"check-catch",
"check-else",
"check-open-brace",
"check-whitespace"
],
"quotemark": [true, "double", "jsx-double"],
"radix": true,
"semicolon": [true, "ignore-bound-class-methods"],
"switch-default": true,
"trailing-comma": false,
"triple-equals": [true, "allow-null-check"],
"typedef": [true, "parameter", "property-declaration"],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"variable-name": [
true,
"ban-keywords",
"check-format",
"allow-leading-underscore",
"allow-pascal-case"
],
"whitespace": [
true,
"check-branch",
"check-decl",
"check-module",
"check-operator",
"check-separator",
"check-type",
"check-typecast"
]
}
}