From fa40885106b31d8b69ee2b2b80c92b1eb7627d4d Mon Sep 17 00:00:00 2001 From: Ryan Kotzen Date: Sat, 17 Jun 2017 16:47:53 +0200 Subject: [PATCH 1/6] Adding flow support --- .babelrc | 3 +++ .eslintrc | 1 + package-lock.json | 24 ++++++++++++++++++++++++ package.json | 3 +++ src/app.js | 2 +- 5 files changed, 32 insertions(+), 1 deletion(-) diff --git a/.babelrc b/.babelrc index aa62491..aee7521 100644 --- a/.babelrc +++ b/.babelrc @@ -1,4 +1,7 @@ { + "plugins": [ + "transform-flow-strip-types" + ], "presets": [ [ "env", diff --git a/.eslintrc b/.eslintrc index f3d88ac..43cc407 100644 --- a/.eslintrc +++ b/.eslintrc @@ -5,6 +5,7 @@ "es6": true, "mocha": true }, + "parser": "babel-eslint", "parserOptions": { "ecmaVersion": 8, "sourceType": "module", diff --git a/package-lock.json b/package-lock.json index 8e9ea37..faf9c08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -310,6 +310,12 @@ "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.25.0.tgz", "integrity": "sha1-fdQrBGPHQunVKW3rPsZ6kyLa1yk=" }, + "babel-eslint": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-7.2.3.tgz", + "integrity": "sha1-sv4tgBJkcPXBlELcdXJTqJdxCCc=", + "dev": true + }, "babel-generator": { "version": "6.25.0", "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.25.0.tgz", @@ -410,6 +416,12 @@ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=" }, + "babel-plugin-syntax-flow": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", + "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=", + "dev": true + }, "babel-plugin-syntax-trailing-function-commas": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", @@ -550,6 +562,12 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=" }, + "babel-plugin-transform-flow-strip-types": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", + "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", + "dev": true + }, "babel-plugin-transform-regenerator": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz", @@ -2318,6 +2336,12 @@ "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", "dev": true }, + "flow": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/flow/-/flow-0.2.3.tgz", + "integrity": "sha1-+Npl76JJEn7Jk3aiiJZXKpeV0a8=", + "dev": true + }, "fn-name": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-2.0.1.tgz", diff --git a/package.json b/package.json index d5f2e09..774a00c 100644 --- a/package.json +++ b/package.json @@ -108,6 +108,8 @@ }, "devDependencies": { "babel-cli": "6.24.1", + "babel-eslint": "7.2.3", + "babel-plugin-transform-flow-strip-types": "6.22.0", "babel-preset-env": "1.5.2", "chai": "4.0.2", "dirty-chai": "2.0.0", @@ -115,6 +117,7 @@ "eslint-config-prettier": "2.1.1", "eslint-plugin-node": "5.0.0", "eslint-plugin-prettier": "2.1.2", + "flow": "0.2.3", "glob": "7.1.2", "istanbul": "0.4.5", "mocha": "3.4.2", diff --git a/src/app.js b/src/app.js index bb2eb8a..d978b40 100644 --- a/src/app.js +++ b/src/app.js @@ -17,7 +17,7 @@ const authentication = require('./authentication'); const permissions = require('./permissions'); const expressSanitized = require('express-sanitize-escape'); -module.exports = function initialise(callback) { +module.exports = function initialise(callback: Function) { async.waterfall( [ createApp, From ea135734748eb06a76b9f33154e659cb948bd12c Mon Sep 17 00:00:00 2001 From: Ryan Kotzen Date: Sat, 17 Jun 2017 17:05:00 +0200 Subject: [PATCH 2/6] lint rules for flow. --- .eslintrc | 23 ++++++++++++++++++----- package-lock.json | 6 ++++++ package.json | 1 + 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/.eslintrc b/.eslintrc index 43cc407..1e9c81d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -17,11 +17,13 @@ }, "plugins": [ "node", - "prettier" + "prettier", + "flowtype" ], "extends": [ "eslint:recommended", "plugin:node/recommended", + "plugin:flowtype/recommended", "prettier" ], "rules": { @@ -47,10 +49,21 @@ "error", "module.exports" ], - "node/no-unsupported-features": ["off"], - "node/no-missing-import": ["error"], - "node/no-extraneous-import": ["error"], - "node/no-unpublished-import": ["error"], + "node/no-unsupported-features": [ + "off" + ], + "node/no-missing-import": [ + "error" + ], + "node/no-extraneous-import": [ + "error" + ], + "node/no-unpublished-import": [ + "error" + ], + "flowtype/no-types-missing-file-annotation": [ + "off" + ], "strict": [ "error", "global" diff --git a/package-lock.json b/package-lock.json index faf9c08..94f3634 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2002,6 +2002,12 @@ } } }, + "eslint-plugin-flowtype": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.34.0.tgz", + "integrity": "sha1-uYdfMUZS5QgWI8nSsYo0a7t1nAk=", + "dev": true + }, "eslint-plugin-node": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-5.0.0.tgz", diff --git a/package.json b/package.json index 774a00c..5d75ec3 100644 --- a/package.json +++ b/package.json @@ -115,6 +115,7 @@ "dirty-chai": "2.0.0", "eslint": "4.0.0", "eslint-config-prettier": "2.1.1", + "eslint-plugin-flowtype": "2.34.0", "eslint-plugin-node": "5.0.0", "eslint-plugin-prettier": "2.1.2", "flow": "0.2.3", From 3e3a517c0304f1298222b060c37c86fa80b7b806 Mon Sep 17 00:00:00 2001 From: Ryan Kotzen Date: Sat, 17 Jun 2017 17:29:26 +0200 Subject: [PATCH 3/6] Trying to run the flow command --- .flowconfig | 14 ++++++++++++++ package.json | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 .flowconfig diff --git a/.flowconfig b/.flowconfig new file mode 100644 index 0000000..4321b2b --- /dev/null +++ b/.flowconfig @@ -0,0 +1,14 @@ +[ignore] +.*/.nyc_output/.* +.*/coverage/.* +.*/lib/.* +.*/logs/.* +.*/public/.* + +[include] +.*/src/*.js + +[libs] + +[options] + diff --git a/package.json b/package.json index 5d75ec3..c317c84 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,8 @@ "ensureNoWildcards": "node ./utilities/check-dependencies-for-wildcards/index.js", "snyk-protect": "snyk protect", "snyk-test": "snyk test", - "prepare": "npm run snyk-protect" + "prepare": "npm run snyk-protect", + "flow": "flow" }, "repository": { "type": "git", From f748cc05150962faaa7aaeae82b0ed7c8499be94 Mon Sep 17 00:00:00 2001 From: Ryan Kotzen Date: Sat, 17 Jun 2017 17:34:36 +0200 Subject: [PATCH 4/6] Trying out flow-bin --- flow-typed/npm/express_v4.x.x.js | 189 +++++++++++++++++++++++++++++++ package-lock.json | 6 + package.json | 1 + 3 files changed, 196 insertions(+) create mode 100644 flow-typed/npm/express_v4.x.x.js diff --git a/flow-typed/npm/express_v4.x.x.js b/flow-typed/npm/express_v4.x.x.js new file mode 100644 index 0000000..07b1e0b --- /dev/null +++ b/flow-typed/npm/express_v4.x.x.js @@ -0,0 +1,189 @@ +// flow-typed signature: 5ab2422f34a4867000a06e5093ff423a +// flow-typed version: a46da1b82a/express_v4.x.x/flow_>=v0.32.x + +import type { Server } from 'http'; + +declare type express$RouterOptions = { + caseSensitive?: boolean, + mergeParams?: boolean, + strict?: boolean +}; + +declare class express$RequestResponseBase { + app: express$Application; + get(field: string): string | void; +} + +declare class express$Request extends http$IncomingMessage mixins express$RequestResponseBase { + baseUrl: string; + body: any; + cookies: {[cookie: string]: string}; + fresh: boolean; + hostname: string; + ip: string; + ips: Array; + method: string; + originalUrl: string; + params: {[param: string]: string}; + path: string; + protocol: 'https' | 'http'; + query: {[name: string]: string}; + route: string; + secure: boolean; + signedCookies: {[signedCookie: string]: string}; + stale: boolean; + subdomains: Array; + xhr: boolean; + accepts(types: string): string | false; + acceptsCharsets(...charsets: Array): string | false; + acceptsEncodings(...encoding: Array): string | false; + acceptsLanguages(...lang: Array): string | false; + header(field: string): string | void; + is(type: string): boolean; + param(name: string, defaultValue?: string): string | void; +} + +declare type express$CookieOptions = { + domain?: string, + encode?: (value: string) => string, + expires?: Date, + httpOnly?: boolean, + maxAge?: number, + path?: string, + secure?: boolean, + signed?: boolean +}; + +declare type express$RenderCallback = (err: Error | null, html?: string) => mixed; + +declare type express$SendFileOptions = { + maxAge?: number, + root?: string, + lastModified?: boolean, + headers?: {[name: string]: string}, + dotfiles?: 'allow' | 'deny' | 'ignore' +}; + +declare class express$Response extends http$ServerResponse mixins express$RequestResponseBase { + headersSent: boolean; + locals: {[name: string]: mixed}; + append(field: string, value?: string): this; + attachment(filename?: string): this; + cookie(name: string, value: string, options?: express$CookieOptions): this; + clearCookie(name: string, options?: express$CookieOptions): this; + download(path: string, filename?: string, callback?: (err?: ?Error) => void): this; + format(typesObject: {[type: string]: Function}): this; + json(body?: mixed): this; + jsonp(body?: mixed): this; + links(links: {[name: string]: string}): this; + location(path: string): this; + redirect(url: string, ...args: Array): this; + redirect(status: number, url: string, ...args: Array): this; + render(view: string, locals?: {[name: string]: mixed}, callback?: express$RenderCallback): this; + send(body?: mixed): this; + sendFile(path: string, options?: express$SendFileOptions, callback?: (err?: ?Error) => mixed): this; + sendStatus(statusCode: number): this; + header(field: string, value?: string): this; + header(headers: {[name: string]: string}): this; + set(field: string, value?: string|string[]): this; + set(headers: {[name: string]: string}): this; + status(statusCode: number): this; + type(type: string): this; + vary(field: string): this; +} + +declare type express$NextFunction = (err?: ?Error | 'route') => mixed; +declare type express$Middleware = + ((req: express$Request, res: express$Response, next: express$NextFunction) => mixed) | + ((error: ?Error, req: express$Request, res: express$Response, next: express$NextFunction) => mixed); +declare interface express$RouteMethodType { + (middleware: express$Middleware): T; + (...middleware: Array): T; + (path: string|RegExp|string[], ...middleware: Array): T; +} +declare class express$Route { + all: express$RouteMethodType; + get: express$RouteMethodType; + post: express$RouteMethodType; + put: express$RouteMethodType; + head: express$RouteMethodType; + delete: express$RouteMethodType; + options: express$RouteMethodType; + trace: express$RouteMethodType; + copy: express$RouteMethodType; + lock: express$RouteMethodType; + mkcol: express$RouteMethodType; + move: express$RouteMethodType; + purge: express$RouteMethodType; + propfind: express$RouteMethodType; + proppatch: express$RouteMethodType; + unlock: express$RouteMethodType; + report: express$RouteMethodType; + mkactivity: express$RouteMethodType; + checkout: express$RouteMethodType; + merge: express$RouteMethodType; + + // @TODO Missing 'm-search' but get flow illegal name error. + + notify: express$RouteMethodType; + subscribe: express$RouteMethodType; + unsubscribe: express$RouteMethodType; + patch: express$RouteMethodType; + search: express$RouteMethodType; + connect: express$RouteMethodType; +} + +declare class express$Router extends express$Route { + constructor(options?: express$RouterOptions): void; + route(path: string): express$Route; + static (options?: express$RouterOptions): express$Router; + use(middleware: express$Middleware): this; + use(...middleware: Array): this; + use(path: string|RegExp|string[], ...middleware: Array): this; + use(path: string, router: express$Router): this; + handle(req: http$IncomingMessage, res: http$ServerResponse, next: express$NextFunction): void; + + // Can't use regular callable signature syntax due to https://github.com/facebook/flow/issues/3084 + $call: (req: http$IncomingMessage, res: http$ServerResponse, next?: ?express$NextFunction) => void; +} + +declare class express$Application extends express$Router mixins events$EventEmitter { + constructor(): void; + locals: {[name: string]: mixed}; + mountpath: string; + listen(port: number, hostname?: string, backlog?: number, callback?: (err?: ?Error) => mixed): Server; + listen(port: number, hostname?: string, callback?: (err?: ?Error) => mixed): Server; + listen(port: number, callback?: (err?: ?Error) => mixed): Server; + listen(path: string, callback?: (err?: ?Error) => mixed): Server; + listen(handle: Object, callback?: (err?: ?Error) => mixed): Server; + disable(name: string): void; + disabled(name: string): boolean; + enable(name: string): void; + enabled(name: string): boolean; + engine(name: string, callback: Function): void; + /** + * Mixed will not be taken as a value option. Issue around using the GET http method name and the get for settings. + */ + // get(name: string): mixed; + set(name: string, value: mixed): mixed; + render(name: string, optionsOrFunction: {[name: string]: mixed}, callback: express$RenderCallback): void; + handle(req: http$IncomingMessage, res: http$ServerResponse, next?: ?express$NextFunction): void; +} + +declare module 'express' { + declare function serveStatic(root: string, options?: Object): express$Middleware; + + declare type RouterOptions = express$RouterOptions; + declare type CookieOptions = express$CookieOptions; + declare type Middleware = express$Middleware; + declare type NextFunction = express$NextFunction; + declare type $Response = express$Response; + declare type $Request = express$Request; + declare type $Application = express$Application; + + declare module.exports: { + (): express$Application, // If you try to call like a function, it will use this signature + static: serveStatic, // `static` property on the function + Router: typeof express$Router, // `Router` property on the function + }; +} diff --git a/package-lock.json b/package-lock.json index 94f3634..7624e51 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2348,6 +2348,12 @@ "integrity": "sha1-+Npl76JJEn7Jk3aiiJZXKpeV0a8=", "dev": true }, + "flow-bin": { + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.48.0.tgz", + "integrity": "sha1-ctB1FDUkNY24kBUl48eE3BOnx+4=", + "dev": true + }, "fn-name": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-2.0.1.tgz", diff --git a/package.json b/package.json index c317c84..95c404a 100644 --- a/package.json +++ b/package.json @@ -120,6 +120,7 @@ "eslint-plugin-node": "5.0.0", "eslint-plugin-prettier": "2.1.2", "flow": "0.2.3", + "flow-bin": "0.48.0", "glob": "7.1.2", "istanbul": "0.4.5", "mocha": "3.4.2", From f7ecf77fe82305b206e0572c334213b55ff5c009 Mon Sep 17 00:00:00 2001 From: Ryan Kotzen Date: Sat, 17 Jun 2017 21:12:40 +0200 Subject: [PATCH 5/6] Updating app.js to use flow. adding node_modules to ignore list --- .flowconfig | 1 + src/app.js | 1 + 2 files changed, 2 insertions(+) diff --git a/.flowconfig b/.flowconfig index 4321b2b..ecab934 100644 --- a/.flowconfig +++ b/.flowconfig @@ -3,6 +3,7 @@ .*/coverage/.* .*/lib/.* .*/logs/.* +.*/node_modules/.* .*/public/.* [include] diff --git a/src/app.js b/src/app.js index d978b40..c50f67e 100644 --- a/src/app.js +++ b/src/app.js @@ -1,3 +1,4 @@ +// @flow import * as async from 'async'; const express = require('express'); const bodyParser = require('body-parser'); From cfd6f2911c855edf0339be22d4c447d8eb4e4955 Mon Sep 17 00:00:00 2001 From: Ryan Kotzen Date: Sat, 17 Jun 2017 21:34:16 +0200 Subject: [PATCH 6/6] testing more --- .flowconfig | 3 ++ flow-typed/npm/body-parser_v1.x.x.js | 43 ++++++++++++++++++++++++++++ src/app.js | 4 +-- 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 flow-typed/npm/body-parser_v1.x.x.js diff --git a/.flowconfig b/.flowconfig index ecab934..95e87d2 100644 --- a/.flowconfig +++ b/.flowconfig @@ -8,8 +8,11 @@ [include] .*/src/*.js +.*/node_modules/async/*.js +.*/node_modules/cors/*.js [libs] + [options] diff --git a/flow-typed/npm/body-parser_v1.x.x.js b/flow-typed/npm/body-parser_v1.x.x.js new file mode 100644 index 0000000..f689b14 --- /dev/null +++ b/flow-typed/npm/body-parser_v1.x.x.js @@ -0,0 +1,43 @@ +// flow-typed signature: f39e87ae093403a8f3c789273ccddbf6 +// flow-typed version: 7e7c66e29a/body-parser_v1.x.x/flow_>=v0.30.x + +import type { Middleware, $Request, $Response } from 'express'; + +declare type bodyParser$Options = { + inflate?: boolean; + limit?: number | string; + type?: string | string[] | ((req: $Request) => any); + verify?: (req: $Request, res: $Response, buf: Buffer, encoding: string) => void; +}; + +declare type bodyParser$OptionsText = bodyParser$Options & { + reviever?: (key: string, value: any) => any; + strict?: boolean; +}; + +declare type bodyParser$OptionsJson = bodyParser$Options & { + reviever?: (key: string, value: any) => any; + strict?: boolean; +}; + +declare type bodyParser$OptionsUrlencoded = bodyParser$Options & { + extended?: boolean; + parameterLimit?: number; +}; + +declare module "body-parser" { + + declare type Options = bodyParser$Options; + declare type OptionsText = bodyParser$OptionsText; + declare type OptionsJson = bodyParser$OptionsJson; + declare type OptionsUrlencoded = bodyParser$OptionsUrlencoded; + + declare function json(options?: OptionsJson): Middleware; + + declare function raw(options?: Options): Middleware; + + declare function text(options?: OptionsText): Middleware; + + declare function urlencoded(options?: OptionsUrlencoded): Middleware; + +} diff --git a/src/app.js b/src/app.js index c50f67e..86fbee6 100644 --- a/src/app.js +++ b/src/app.js @@ -51,11 +51,11 @@ function createApp(callback) { app.use(expressSanitized.middleware()); configureRequestId(app); configureMorgan(app); - app.use(function(req, res, next) { + app.use(function(req : express$Request, res : express$Response, next: express$NextFunction) { req.process = {}; next(); }); - console.log('App Created on ' + app.settings.env); + console.log('App Created'); callback(null, app); }