diff --git a/babel.config.js b/babel.config.js index f9bc5083..8b3a41cc 100644 --- a/babel.config.js +++ b/babel.config.js @@ -3,6 +3,9 @@ module.exports = function(api) { // https://babeljs.io/docs/en/config-files#apicache api.cache.forever() return { - presets: ["@babel/preset-env", "@babel/preset-flow"] + presets: ["@babel/preset-env", "@babel/preset-flow"], + plugins: [ + "@babel/plugin-proposal-class-properties" + ] }; }; diff --git a/examples/flow/generated/proto/examplecom/annotations_pb_service.js b/examples/flow/generated/proto/examplecom/annotations_pb_service.js new file mode 100644 index 00000000..414651f0 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/annotations_pb_service.js @@ -0,0 +1,3 @@ +// package: examplecom +// file: proto/examplecom/annotations.proto + diff --git a/examples/flow/generated/proto/examplecom/annotations_pb_service.js.flow b/examples/flow/generated/proto/examplecom/annotations_pb_service.js.flow new file mode 100644 index 00000000..f33e1150 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/annotations_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: examplecom +// file: proto/examplecom/annotations.proto + diff --git a/examples/flow/generated/proto/examplecom/empty_message_no_service_pb_service.js b/examples/flow/generated/proto/examplecom/empty_message_no_service_pb_service.js new file mode 100644 index 00000000..8f08f53e --- /dev/null +++ b/examples/flow/generated/proto/examplecom/empty_message_no_service_pb_service.js @@ -0,0 +1,3 @@ +// package: examplecom +// file: proto/examplecom/empty_message_no_service.proto + diff --git a/examples/flow/generated/proto/examplecom/empty_message_no_service_pb_service.js.flow b/examples/flow/generated/proto/examplecom/empty_message_no_service_pb_service.js.flow new file mode 100644 index 00000000..8b1702e0 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/empty_message_no_service_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: examplecom +// file: proto/examplecom/empty_message_no_service.proto + diff --git a/examples/flow/generated/proto/examplecom/enum_message_pb_service.js b/examples/flow/generated/proto/examplecom/enum_message_pb_service.js new file mode 100644 index 00000000..d12dd4aa --- /dev/null +++ b/examples/flow/generated/proto/examplecom/enum_message_pb_service.js @@ -0,0 +1,3 @@ +// package: examplecom +// file: proto/examplecom/enum_message.proto + diff --git a/examples/flow/generated/proto/examplecom/enum_message_pb_service.js.flow b/examples/flow/generated/proto/examplecom/enum_message_pb_service.js.flow new file mode 100644 index 00000000..c4f7eb94 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/enum_message_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: examplecom +// file: proto/examplecom/enum_message.proto + diff --git a/examples/flow/generated/proto/examplecom/map_message_pb_service.js b/examples/flow/generated/proto/examplecom/map_message_pb_service.js new file mode 100644 index 00000000..f80a25a1 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/map_message_pb_service.js @@ -0,0 +1,3 @@ +// package: examplecom +// file: proto/examplecom/map_message.proto + diff --git a/examples/flow/generated/proto/examplecom/map_message_pb_service.js.flow b/examples/flow/generated/proto/examplecom/map_message_pb_service.js.flow new file mode 100644 index 00000000..26167368 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/map_message_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: examplecom +// file: proto/examplecom/map_message.proto + diff --git a/examples/flow/generated/proto/examplecom/oneof_message_pb_service.js b/examples/flow/generated/proto/examplecom/oneof_message_pb_service.js new file mode 100644 index 00000000..62a2c13b --- /dev/null +++ b/examples/flow/generated/proto/examplecom/oneof_message_pb_service.js @@ -0,0 +1,3 @@ +// package: examplecom +// file: proto/examplecom/oneof_message.proto + diff --git a/examples/flow/generated/proto/examplecom/oneof_message_pb_service.js.flow b/examples/flow/generated/proto/examplecom/oneof_message_pb_service.js.flow new file mode 100644 index 00000000..3076ae5f --- /dev/null +++ b/examples/flow/generated/proto/examplecom/oneof_message_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: examplecom +// file: proto/examplecom/oneof_message.proto + diff --git a/examples/flow/generated/proto/examplecom/parent_message_v2_pb_service.js b/examples/flow/generated/proto/examplecom/parent_message_v2_pb_service.js new file mode 100644 index 00000000..dfa8872c --- /dev/null +++ b/examples/flow/generated/proto/examplecom/parent_message_v2_pb_service.js @@ -0,0 +1,3 @@ +// package: examplecom +// file: proto/examplecom/parent_message_v2.proto + diff --git a/examples/flow/generated/proto/examplecom/parent_message_v2_pb_service.js.flow b/examples/flow/generated/proto/examplecom/parent_message_v2_pb_service.js.flow new file mode 100644 index 00000000..13272599 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/parent_message_v2_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: examplecom +// file: proto/examplecom/parent_message_v2.proto + diff --git a/examples/flow/generated/proto/examplecom/parent_message_v3_pb_service.js b/examples/flow/generated/proto/examplecom/parent_message_v3_pb_service.js new file mode 100644 index 00000000..419294c2 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/parent_message_v3_pb_service.js @@ -0,0 +1,3 @@ +// package: examplecom +// file: proto/examplecom/parent_message_v3.proto + diff --git a/examples/flow/generated/proto/examplecom/parent_message_v3_pb_service.js.flow b/examples/flow/generated/proto/examplecom/parent_message_v3_pb_service.js.flow new file mode 100644 index 00000000..48e81a7c --- /dev/null +++ b/examples/flow/generated/proto/examplecom/parent_message_v3_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: examplecom +// file: proto/examplecom/parent_message_v3.proto + diff --git a/examples/flow/generated/proto/examplecom/primitive_message_v2_pb_service.js b/examples/flow/generated/proto/examplecom/primitive_message_v2_pb_service.js new file mode 100644 index 00000000..cd565930 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/primitive_message_v2_pb_service.js @@ -0,0 +1,3 @@ +// package: examplecom +// file: proto/examplecom/primitive_message_v2.proto + diff --git a/examples/flow/generated/proto/examplecom/primitive_message_v2_pb_service.js.flow b/examples/flow/generated/proto/examplecom/primitive_message_v2_pb_service.js.flow new file mode 100644 index 00000000..309ce0ea --- /dev/null +++ b/examples/flow/generated/proto/examplecom/primitive_message_v2_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: examplecom +// file: proto/examplecom/primitive_message_v2.proto + diff --git a/examples/flow/generated/proto/examplecom/primitive_message_v3_pb_service.js b/examples/flow/generated/proto/examplecom/primitive_message_v3_pb_service.js new file mode 100644 index 00000000..e091f3ae --- /dev/null +++ b/examples/flow/generated/proto/examplecom/primitive_message_v3_pb_service.js @@ -0,0 +1,3 @@ +// package: examplecom +// file: proto/examplecom/primitive_message_v3.proto + diff --git a/examples/flow/generated/proto/examplecom/primitive_message_v3_pb_service.js.flow b/examples/flow/generated/proto/examplecom/primitive_message_v3_pb_service.js.flow new file mode 100644 index 00000000..abc5f91d --- /dev/null +++ b/examples/flow/generated/proto/examplecom/primitive_message_v3_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: examplecom +// file: proto/examplecom/primitive_message_v3.proto + diff --git a/examples/flow/generated/proto/examplecom/repeated_primitive_message_pb_service.js b/examples/flow/generated/proto/examplecom/repeated_primitive_message_pb_service.js new file mode 100644 index 00000000..b7dbeb7d --- /dev/null +++ b/examples/flow/generated/proto/examplecom/repeated_primitive_message_pb_service.js @@ -0,0 +1,3 @@ +// package: examplecom +// file: proto/examplecom/repeated_primitive_message.proto + diff --git a/examples/flow/generated/proto/examplecom/repeated_primitive_message_pb_service.js.flow b/examples/flow/generated/proto/examplecom/repeated_primitive_message_pb_service.js.flow new file mode 100644 index 00000000..49963aef --- /dev/null +++ b/examples/flow/generated/proto/examplecom/repeated_primitive_message_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: examplecom +// file: proto/examplecom/repeated_primitive_message.proto + diff --git a/examples/flow/generated/proto/examplecom/reserved_words_pb_service.js b/examples/flow/generated/proto/examplecom/reserved_words_pb_service.js new file mode 100644 index 00000000..951d1a13 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/reserved_words_pb_service.js @@ -0,0 +1,3 @@ +// package: examplecom +// file: proto/examplecom/reserved_words.proto + diff --git a/examples/flow/generated/proto/examplecom/reserved_words_pb_service.js.flow b/examples/flow/generated/proto/examplecom/reserved_words_pb_service.js.flow new file mode 100644 index 00000000..1bae95ef --- /dev/null +++ b/examples/flow/generated/proto/examplecom/reserved_words_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: examplecom +// file: proto/examplecom/reserved_words.proto + diff --git a/examples/flow/generated/proto/examplecom/simple_pb_service.js b/examples/flow/generated/proto/examplecom/simple_pb_service.js new file mode 100644 index 00000000..82de7c02 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/simple_pb_service.js @@ -0,0 +1,3 @@ +// package: examplecom +// file: proto/examplecom/simple.proto + diff --git a/examples/flow/generated/proto/examplecom/simple_pb_service.js.flow b/examples/flow/generated/proto/examplecom/simple_pb_service.js.flow new file mode 100644 index 00000000..dc6e9a43 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/simple_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: examplecom +// file: proto/examplecom/simple.proto + diff --git a/examples/flow/generated/proto/examplecom/simple_service_pb_service.js b/examples/flow/generated/proto/examplecom/simple_service_pb_service.js new file mode 100644 index 00000000..4cfbff7a --- /dev/null +++ b/examples/flow/generated/proto/examplecom/simple_service_pb_service.js @@ -0,0 +1,255 @@ +// package: examplecom +// file: proto/examplecom/simple_service.proto + +var proto_examplecom_simple_service_pb = require("../../proto/examplecom/simple_service_pb"); +var proto_othercom_external_child_message_pb = require("../../proto/othercom/external_child_message_pb"); +var google_protobuf_empty_pb = require("google-protobuf/google/protobuf/empty_pb"); +var grpc = require("grpc-web-client").grpc; + +var SimpleService = (function () { + function SimpleService() {} + SimpleService.serviceName = "examplecom.SimpleService"; + return SimpleService; +}()); + +SimpleService.DoUnary = { + methodName: "DoUnary", + service: SimpleService, + requestStream: false, + responseStream: false, + requestType: proto_examplecom_simple_service_pb.UnaryRequest, + responseType: proto_othercom_external_child_message_pb.ExternalChildMessage +}; + +SimpleService.DoServerStream = { + methodName: "DoServerStream", + service: SimpleService, + requestStream: false, + responseStream: true, + requestType: proto_examplecom_simple_service_pb.StreamRequest, + responseType: proto_othercom_external_child_message_pb.ExternalChildMessage +}; + +SimpleService.DoClientStream = { + methodName: "DoClientStream", + service: SimpleService, + requestStream: true, + responseStream: false, + requestType: proto_examplecom_simple_service_pb.StreamRequest, + responseType: google_protobuf_empty_pb.Empty +}; + +SimpleService.DoBidiStream = { + methodName: "DoBidiStream", + service: SimpleService, + requestStream: true, + responseStream: true, + requestType: proto_examplecom_simple_service_pb.StreamRequest, + responseType: proto_othercom_external_child_message_pb.ExternalChildMessage +}; + +SimpleService.Delete = { + methodName: "Delete", + service: SimpleService, + requestStream: false, + responseStream: false, + requestType: proto_examplecom_simple_service_pb.UnaryRequest, + responseType: proto_examplecom_simple_service_pb.UnaryResponse +}; + +exports.SimpleService = SimpleService; + +function SimpleServiceClient(serviceHost, options) { + this.serviceHost = serviceHost; + this.options = options || {}; +} + +SimpleServiceClient.prototype.doUnary = function doUnary(requestMessage, metadata, callback) { + if (arguments.length === 2) { + callback = arguments[1]; + } + var client = grpc.unary(SimpleService.DoUnary, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onEnd: function (response) { + if (callback) { + if (response.status !== grpc.Code.OK) { + var err = new Error(response.statusMessage); + err.code = response.status; + err.metadata = response.trailers; + callback(err, null); + } else { + callback(null, response.message); + } + } + } + }); + return { + cancel: function () { + callback = null; + client.close(); + } + }; +}; + +SimpleServiceClient.prototype.doServerStream = function doServerStream(requestMessage, metadata) { + var listeners = { + data: [], + end: [], + status: [] + }; + var client = grpc.invoke(SimpleService.DoServerStream, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onMessage: function (responseMessage) { + listeners.data.forEach(function (handler) { + handler(responseMessage); + }); + }, + onEnd: function (status, statusMessage, trailers) { + listeners.end.forEach(function (handler) { + handler(); + }); + listeners.status.forEach(function (handler) { + handler({ code: status, details: statusMessage, metadata: trailers }); + }); + listeners = null; + } + }); + return { + on: function (type, handler) { + listeners[type].push(handler); + return this; + }, + cancel: function () { + listeners = null; + client.close(); + } + }; +}; + +SimpleServiceClient.prototype.doClientStream = function doClientStream(metadata) { + var listeners = { + end: [], + status: [] + }; + var client = grpc.client(SimpleService.DoClientStream, { + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport + }); + client.onEnd(function (status, statusMessage, trailers) { + listeners.end.forEach(function (handler) { + handler(); + }); + listeners.status.forEach(function (handler) { + handler({ code: status, details: statusMessage, metadata: trailers }); + }); + listeners = null; + }); + return { + on: function (type, handler) { + listeners[type].push(handler); + return this; + }, + write: function (requestMessage) { + if (!client.started) { + client.start(metadata); + } + client.send(requestMessage); + return this; + }, + end: function () { + client.finishSend(); + }, + cancel: function () { + listeners = null; + client.close(); + } + }; +}; + +SimpleServiceClient.prototype.doBidiStream = function doBidiStream(metadata) { + var listeners = { + data: [], + end: [], + status: [] + }; + var client = grpc.client(SimpleService.DoBidiStream, { + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport + }); + client.onEnd(function (status, statusMessage, trailers) { + listeners.end.forEach(function (handler) { + handler(); + }); + listeners.status.forEach(function (handler) { + handler({ code: status, details: statusMessage, metadata: trailers }); + }); + listeners = null; + }); + client.onMessage(function (message) { + listeners.data.forEach(function (handler) { + handler(message); + }) + }); + client.start(metadata); + return { + on: function (type, handler) { + listeners[type].push(handler); + return this; + }, + write: function (requestMessage) { + client.send(requestMessage); + return this; + }, + end: function () { + client.finishSend(); + }, + cancel: function () { + listeners = null; + client.close(); + } + }; +}; + +SimpleServiceClient.prototype.delete = function pb_delete(requestMessage, metadata, callback) { + if (arguments.length === 2) { + callback = arguments[1]; + } + var client = grpc.unary(SimpleService.Delete, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onEnd: function (response) { + if (callback) { + if (response.status !== grpc.Code.OK) { + var err = new Error(response.statusMessage); + err.code = response.status; + err.metadata = response.trailers; + callback(err, null); + } else { + callback(null, response.message); + } + } + } + }); + return { + cancel: function () { + callback = null; + client.close(); + } + }; +}; + +exports.SimpleServiceClient = SimpleServiceClient; + diff --git a/examples/flow/generated/proto/examplecom/simple_service_pb_service.js.flow b/examples/flow/generated/proto/examplecom/simple_service_pb_service.js.flow new file mode 100644 index 00000000..09b975f7 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/simple_service_pb_service.js.flow @@ -0,0 +1,118 @@ +// @flow +// package: examplecom +// file: proto/examplecom/simple_service.proto + +import * as proto_examplecom_simple_service_pb from "../../proto/examplecom/simple_service_pb"; +import * as proto_othercom_external_child_message_pb from "../../proto/othercom/external_child_message_pb"; +import * as google_protobuf_empty_pb from "google-protobuf/google/protobuf/empty_pb"; +import {grpc} from "grpc-web-client"; + +type SimpleServiceDoUnary = { + +methodName: string, + +service: typeof SimpleService, + +requestStream: false, + +responseStream: false, + +requestType: typeof proto_examplecom_simple_service_pb.UnaryRequest, + +responseType: typeof proto_othercom_external_child_message_pb.ExternalChildMessage, +}; + +type SimpleServiceDoServerStream = { + +methodName: string, + +service: typeof SimpleService, + +requestStream: false, + +responseStream: true, + +requestType: typeof proto_examplecom_simple_service_pb.StreamRequest, + +responseType: typeof proto_othercom_external_child_message_pb.ExternalChildMessage, +}; + +type SimpleServiceDoClientStream = { + +methodName: string, + +service: typeof SimpleService, + +requestStream: true, + +responseStream: false, + +requestType: typeof proto_examplecom_simple_service_pb.StreamRequest, + +responseType: typeof google_protobuf_empty_pb.Empty, +}; + +type SimpleServiceDoBidiStream = { + +methodName: string, + +service: typeof SimpleService, + +requestStream: true, + +responseStream: true, + +requestType: typeof proto_examplecom_simple_service_pb.StreamRequest, + +responseType: typeof proto_othercom_external_child_message_pb.ExternalChildMessage, +}; + +type SimpleServiceDelete = { + +methodName: string, + +service: typeof SimpleService, + +requestStream: false, + +responseStream: false, + +requestType: typeof proto_examplecom_simple_service_pb.UnaryRequest, + +responseType: typeof proto_examplecom_simple_service_pb.UnaryResponse, +}; + +export class SimpleService { + static +serviceName: string; + static +DoUnary: SimpleServiceDoUnary; + static +DoServerStream: SimpleServiceDoServerStream; + static +DoClientStream: SimpleServiceDoClientStream; + static +DoBidiStream: SimpleServiceDoBidiStream; + static +Delete: SimpleServiceDelete; +} + +export type ServiceError = { message: string, code: number; metadata: grpc.Metadata } +export type Status = { details: string, code: number; metadata: grpc.Metadata } + +interface UnaryResponse { + cancel(): void; +} +interface ResponseStream { + cancel(): void; + on(type: 'data', handler: (message: T) => void): ResponseStream; + on(type: 'end', handler: () => void): ResponseStream; + on(type: 'status', handler: (status: Status) => void): ResponseStream; +} +interface RequestStream { + write(message: T): RequestStream; + end(): void; + cancel(): void; + on(type: 'end', handler: () => void): RequestStream; + on(type: 'status', handler: (status: Status) => void): RequestStream; +} +interface BidirectionalStream { + write(message: ReqT): BidirectionalStream; + end(): void; + cancel(): void; + on(type: 'data', handler: (message: ResT) => void): BidirectionalStream; + on(type: 'end', handler: () => void): BidirectionalStream; + on(type: 'status', handler: (status: Status) => void): BidirectionalStream; +} + +declare export class SimpleServiceClient { + +serviceHost: string; + + constructor(serviceHost: string, options?: grpc.RpcOptions): SimpleServiceClient; + doUnary( + requestMessage: proto_examplecom_simple_service_pb.UnaryRequest, + metadata: grpc.Metadata, + callback: (error: ServiceError|null, responseMessage: proto_othercom_external_child_message_pb.ExternalChildMessage|null) => void + ): UnaryResponse; + doUnary( + requestMessage: proto_examplecom_simple_service_pb.UnaryRequest, + callback: (error: ServiceError|null, responseMessage: proto_othercom_external_child_message_pb.ExternalChildMessage|null) => void + ): UnaryResponse; + doServerStream(requestMessage: proto_examplecom_simple_service_pb.StreamRequest, metadata?: grpc.Metadata): ResponseStream; + doClientStream(metadata?: grpc.Metadata): RequestStream; + doBidiStream(metadata?: grpc.Metadata): BidirectionalStream; + delete( + requestMessage: proto_examplecom_simple_service_pb.UnaryRequest, + metadata: grpc.Metadata, + callback: (error: ServiceError|null, responseMessage: proto_examplecom_simple_service_pb.UnaryResponse|null) => void + ): UnaryResponse; + delete( + requestMessage: proto_examplecom_simple_service_pb.UnaryRequest, + callback: (error: ServiceError|null, responseMessage: proto_examplecom_simple_service_pb.UnaryResponse|null) => void + ): UnaryResponse; +} + diff --git a/examples/flow/generated/proto/examplecom/simplevalue_pb_service.js b/examples/flow/generated/proto/examplecom/simplevalue_pb_service.js new file mode 100644 index 00000000..5d3f2d5a --- /dev/null +++ b/examples/flow/generated/proto/examplecom/simplevalue_pb_service.js @@ -0,0 +1,3 @@ +// package: examplecom +// file: proto/examplecom/simplevalue.proto + diff --git a/examples/flow/generated/proto/examplecom/simplevalue_pb_service.js.flow b/examples/flow/generated/proto/examplecom/simplevalue_pb_service.js.flow new file mode 100644 index 00000000..bf2358f3 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/simplevalue_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: examplecom +// file: proto/examplecom/simplevalue.proto + diff --git a/examples/flow/generated/proto/examplecom/well_known_message_pb_service.js b/examples/flow/generated/proto/examplecom/well_known_message_pb_service.js new file mode 100644 index 00000000..3251d3d5 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/well_known_message_pb_service.js @@ -0,0 +1,3 @@ +// package: examplecom +// file: proto/examplecom/well_known_message.proto + diff --git a/examples/flow/generated/proto/examplecom/well_known_message_pb_service.js.flow b/examples/flow/generated/proto/examplecom/well_known_message_pb_service.js.flow new file mode 100644 index 00000000..a56d1533 --- /dev/null +++ b/examples/flow/generated/proto/examplecom/well_known_message_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: examplecom +// file: proto/examplecom/well_known_message.proto + diff --git a/examples/flow/generated/proto/orphan_pb_service.js b/examples/flow/generated/proto/orphan_pb_service.js new file mode 100644 index 00000000..d9594ffb --- /dev/null +++ b/examples/flow/generated/proto/orphan_pb_service.js @@ -0,0 +1,109 @@ +// package: +// file: proto/orphan.proto + +var proto_orphan_pb = require("../proto/orphan_pb"); +var grpc = require("grpc-web-client").grpc; + +var OrphanService = (function () { + function OrphanService() {} + OrphanService.serviceName = "OrphanService"; + return OrphanService; +}()); + +OrphanService.DoUnary = { + methodName: "DoUnary", + service: OrphanService, + requestStream: false, + responseStream: false, + requestType: proto_orphan_pb.OrphanUnaryRequest, + responseType: proto_orphan_pb.OrphanMessage +}; + +OrphanService.DoStream = { + methodName: "DoStream", + service: OrphanService, + requestStream: false, + responseStream: true, + requestType: proto_orphan_pb.OrphanStreamRequest, + responseType: proto_orphan_pb.OrphanMessage +}; + +exports.OrphanService = OrphanService; + +function OrphanServiceClient(serviceHost, options) { + this.serviceHost = serviceHost; + this.options = options || {}; +} + +OrphanServiceClient.prototype.doUnary = function doUnary(requestMessage, metadata, callback) { + if (arguments.length === 2) { + callback = arguments[1]; + } + var client = grpc.unary(OrphanService.DoUnary, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onEnd: function (response) { + if (callback) { + if (response.status !== grpc.Code.OK) { + var err = new Error(response.statusMessage); + err.code = response.status; + err.metadata = response.trailers; + callback(err, null); + } else { + callback(null, response.message); + } + } + } + }); + return { + cancel: function () { + callback = null; + client.close(); + } + }; +}; + +OrphanServiceClient.prototype.doStream = function doStream(requestMessage, metadata) { + var listeners = { + data: [], + end: [], + status: [] + }; + var client = grpc.invoke(OrphanService.DoStream, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onMessage: function (responseMessage) { + listeners.data.forEach(function (handler) { + handler(responseMessage); + }); + }, + onEnd: function (status, statusMessage, trailers) { + listeners.end.forEach(function (handler) { + handler(); + }); + listeners.status.forEach(function (handler) { + handler({ code: status, details: statusMessage, metadata: trailers }); + }); + listeners = null; + } + }); + return { + on: function (type, handler) { + listeners[type].push(handler); + return this; + }, + cancel: function () { + listeners = null; + client.close(); + } + }; +}; + +exports.OrphanServiceClient = OrphanServiceClient; + diff --git a/examples/flow/generated/proto/orphan_pb_service.js.flow b/examples/flow/generated/proto/orphan_pb_service.js.flow new file mode 100644 index 00000000..582adbe7 --- /dev/null +++ b/examples/flow/generated/proto/orphan_pb_service.js.flow @@ -0,0 +1,75 @@ +// @flow +// package: +// file: proto/orphan.proto + +import * as proto_orphan_pb from "../proto/orphan_pb"; +import {grpc} from "grpc-web-client"; + +type OrphanServiceDoUnary = { + +methodName: string, + +service: typeof OrphanService, + +requestStream: false, + +responseStream: false, + +requestType: typeof proto_orphan_pb.OrphanUnaryRequest, + +responseType: typeof proto_orphan_pb.OrphanMessage, +}; + +type OrphanServiceDoStream = { + +methodName: string, + +service: typeof OrphanService, + +requestStream: false, + +responseStream: true, + +requestType: typeof proto_orphan_pb.OrphanStreamRequest, + +responseType: typeof proto_orphan_pb.OrphanMessage, +}; + +export class OrphanService { + static +serviceName: string; + static +DoUnary: OrphanServiceDoUnary; + static +DoStream: OrphanServiceDoStream; +} + +export type ServiceError = { message: string, code: number; metadata: grpc.Metadata } +export type Status = { details: string, code: number; metadata: grpc.Metadata } + +interface UnaryResponse { + cancel(): void; +} +interface ResponseStream { + cancel(): void; + on(type: 'data', handler: (message: T) => void): ResponseStream; + on(type: 'end', handler: () => void): ResponseStream; + on(type: 'status', handler: (status: Status) => void): ResponseStream; +} +interface RequestStream { + write(message: T): RequestStream; + end(): void; + cancel(): void; + on(type: 'end', handler: () => void): RequestStream; + on(type: 'status', handler: (status: Status) => void): RequestStream; +} +interface BidirectionalStream { + write(message: ReqT): BidirectionalStream; + end(): void; + cancel(): void; + on(type: 'data', handler: (message: ResT) => void): BidirectionalStream; + on(type: 'end', handler: () => void): BidirectionalStream; + on(type: 'status', handler: (status: Status) => void): BidirectionalStream; +} + +declare export class OrphanServiceClient { + +serviceHost: string; + + constructor(serviceHost: string, options?: grpc.RpcOptions): OrphanServiceClient; + doUnary( + requestMessage: proto_orphan_pb.OrphanUnaryRequest, + metadata: grpc.Metadata, + callback: (error: ServiceError|null, responseMessage: proto_orphan_pb.OrphanMessage|null) => void + ): UnaryResponse; + doUnary( + requestMessage: proto_orphan_pb.OrphanUnaryRequest, + callback: (error: ServiceError|null, responseMessage: proto_orphan_pb.OrphanMessage|null) => void + ): UnaryResponse; + doStream(requestMessage: proto_orphan_pb.OrphanStreamRequest, metadata?: grpc.Metadata): ResponseStream; +} + diff --git a/examples/flow/generated/proto/othercom/external_child_message_pb_service.js b/examples/flow/generated/proto/othercom/external_child_message_pb_service.js new file mode 100644 index 00000000..393230ae --- /dev/null +++ b/examples/flow/generated/proto/othercom/external_child_message_pb_service.js @@ -0,0 +1,3 @@ +// package: othercom +// file: proto/othercom/external_child_message.proto + diff --git a/examples/flow/generated/proto/othercom/external_child_message_pb_service.js.flow b/examples/flow/generated/proto/othercom/external_child_message_pb_service.js.flow new file mode 100644 index 00000000..25aec786 --- /dev/null +++ b/examples/flow/generated/proto/othercom/external_child_message_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: othercom +// file: proto/othercom/external_child_message.proto + diff --git a/examples/flow/generated/proto/othercom/external_enum_pb_service.js b/examples/flow/generated/proto/othercom/external_enum_pb_service.js new file mode 100644 index 00000000..e24e3c22 --- /dev/null +++ b/examples/flow/generated/proto/othercom/external_enum_pb_service.js @@ -0,0 +1,3 @@ +// package: othercom +// file: proto/othercom/external_enum.proto + diff --git a/examples/flow/generated/proto/othercom/external_enum_pb_service.js.flow b/examples/flow/generated/proto/othercom/external_enum_pb_service.js.flow new file mode 100644 index 00000000..14bcfc2e --- /dev/null +++ b/examples/flow/generated/proto/othercom/external_enum_pb_service.js.flow @@ -0,0 +1,4 @@ +// @flow +// package: othercom +// file: proto/othercom/external_enum.proto + diff --git a/generate.sh b/generate.sh index 170f64c5..29bad2de 100755 --- a/generate.sh +++ b/generate.sh @@ -64,7 +64,7 @@ mkdir -p "$EXAMPLES_FLOW_GENERATED_DIR" $PROTOC \ --plugin=protoc-gen-flow=./bin/protoc-gen-flow \ --js_out=import_style=commonjs,binary:$EXAMPLES_FLOW_GENERATED_DIR \ - --flow_out=$EXAMPLES_FLOW_GENERATED_DIR \ + --flow_out=service=true:$EXAMPLES_FLOW_GENERATED_DIR \ ./proto/othercom/*.proto \ ./proto/examplecom/*.proto \ ./proto/*.proto diff --git a/package-lock.json b/package-lock.json index ab78fcc1..04d22a7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", "dev": true, "requires": { - "@babel/highlight": "7.0.0" + "@babel/highlight": "^7.0.0" } }, "@babel/core": { @@ -19,20 +19,20 @@ "integrity": "sha512-Hz6PJT6e44iUNpAn8AoyAs6B3bl60g7MJQaI0rZEar6ECzh6+srYO1xlIdssio34mPaUtAb1y+XlkkSJzok3yw==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0", - "@babel/generator": "7.1.6", - "@babel/helpers": "7.1.5", - "@babel/parser": "7.1.6", - "@babel/template": "7.1.2", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6", - "convert-source-map": "1.6.0", - "debug": "4.1.0", - "json5": "2.1.0", - "lodash": "4.17.11", - "resolve": "1.8.1", - "semver": "5.6.0", - "source-map": "0.5.7" + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.1.6", + "@babel/helpers": "^7.1.5", + "@babel/parser": "^7.1.6", + "@babel/template": "^7.1.2", + "@babel/traverse": "^7.1.6", + "@babel/types": "^7.1.6", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.10", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" } }, "@babel/generator": { @@ -41,11 +41,11 @@ "integrity": "sha512-brwPBtVvdYdGxtenbQgfCdDPmtkmUBZPjUoK5SXJEBuHaA5BCubh9ly65fzXz7R6o5rA76Rs22ES8Z+HCc0YIQ==", "dev": true, "requires": { - "@babel/types": "7.1.6", - "jsesc": "2.5.2", - "lodash": "4.17.11", - "source-map": "0.5.7", - "trim-right": "1.0.1" + "@babel/types": "^7.1.6", + "jsesc": "^2.5.1", + "lodash": "^4.17.10", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" } }, "@babel/helper-annotate-as-pure": { @@ -54,7 +54,7 @@ "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { @@ -63,8 +63,8 @@ "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "7.1.0", - "@babel/types": "7.1.6" + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-call-delegate": { @@ -73,9 +73,98 @@ "integrity": "sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "7.0.0", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/helper-hoist-variables": "^7.0.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.0.tgz", + "integrity": "sha512-DUsQNS2CGLZZ7I3W3fvh0YpPDd6BuWJlDl+qmZZpABZHza2ErE3LxtEzLJFHFC1ZwtlAXvHhbFYbtM5o5B0WBw==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.2.3" + }, + "dependencies": { + "@babel/generator": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.0.tgz", + "integrity": "sha512-dZTwMvTgWfhmibq4V9X+LMf6Bgl7zAodRn9PvcPdhlzFMbvUutx74dbEv7Atz3ToeEpevYEJtAwfxq/bDCzHWg==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0", + "jsesc": "^2.5.1", + "lodash": "^4.17.10", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + }, + "dependencies": { + "@babel/types": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", + "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.10", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-replace-supers": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.2.3.tgz", + "integrity": "sha512-GyieIznGUfPXPWu0yLS6U55Mz67AZD9cUk0BfirOWlPrXlBcan9Gz+vHGz+cPfuoweZSnPzPIm67VtQM0OWZbA==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.2.3", + "@babel/types": "^7.0.0" + } + }, + "@babel/parser": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.1.tgz", + "integrity": "sha512-ATz6yX/L8LEnC3dtLQnIx4ydcPxhLcoy9Vl6re00zb2w5lG6itY6Vhnr1KFRPq/FHNsgl/gh2mjNN20f9iJTTA==", + "dev": true + }, + "@babel/traverse": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz", + "integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.2.2", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.2.3", + "@babel/types": "^7.2.2", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.10" + }, + "dependencies": { + "@babel/types": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", + "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.10", + "to-fast-properties": "^2.0.0" + } + } + } + } } }, "@babel/helper-define-map": { @@ -84,9 +173,9 @@ "integrity": "sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg==", "dev": true, "requires": { - "@babel/helper-function-name": "7.1.0", - "@babel/types": "7.1.6", - "lodash": "4.17.11" + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.0.0", + "lodash": "^4.17.10" } }, "@babel/helper-explode-assignable-expression": { @@ -95,8 +184,8 @@ "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", "dev": true, "requires": { - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-function-name": { @@ -105,9 +194,9 @@ "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "7.0.0", - "@babel/template": "7.1.2", - "@babel/types": "7.1.6" + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-get-function-arity": { @@ -116,7 +205,7 @@ "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-hoist-variables": { @@ -125,7 +214,7 @@ "integrity": "sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-member-expression-to-functions": { @@ -134,7 +223,7 @@ "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-module-imports": { @@ -143,7 +232,7 @@ "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-module-transforms": { @@ -152,12 +241,12 @@ "integrity": "sha512-0JZRd2yhawo79Rcm4w0LwSMILFmFXjugG3yqf+P/UsKsRS1mJCmMwwlHDlMg7Avr9LrvSpp4ZSULO9r8jpCzcw==", "dev": true, "requires": { - "@babel/helper-module-imports": "7.0.0", - "@babel/helper-simple-access": "7.1.0", - "@babel/helper-split-export-declaration": "7.0.0", - "@babel/template": "7.1.2", - "@babel/types": "7.1.6", - "lodash": "4.17.11" + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0", + "lodash": "^4.17.10" } }, "@babel/helper-optimise-call-expression": { @@ -166,7 +255,7 @@ "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-plugin-utils": { @@ -181,7 +270,7 @@ "integrity": "sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==", "dev": true, "requires": { - "lodash": "4.17.11" + "lodash": "^4.17.10" } }, "@babel/helper-remap-async-to-generator": { @@ -190,11 +279,11 @@ "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "7.0.0", - "@babel/helper-wrap-function": "7.1.0", - "@babel/template": "7.1.2", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-replace-supers": { @@ -203,10 +292,10 @@ "integrity": "sha512-BvcDWYZRWVuDeXTYZWxekQNO5D4kO55aArwZOTFXw6rlLQA8ZaDicJR1sO47h+HrnCiDFiww0fSPV0d713KBGQ==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "7.0.0", - "@babel/helper-optimise-call-expression": "7.0.0", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-simple-access": { @@ -215,8 +304,8 @@ "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", "dev": true, "requires": { - "@babel/template": "7.1.2", - "@babel/types": "7.1.6" + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-split-export-declaration": { @@ -225,7 +314,7 @@ "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-wrap-function": { @@ -234,10 +323,10 @@ "integrity": "sha512-R6HU3dete+rwsdAfrOzTlE9Mcpk4RjU3aX3gi9grtmugQY0u79X7eogUvfXA5sI81Mfq1cn6AgxihfN33STjJA==", "dev": true, "requires": { - "@babel/helper-function-name": "7.1.0", - "@babel/template": "7.1.2", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helpers": { @@ -246,9 +335,9 @@ "integrity": "sha512-2jkcdL02ywNBry1YNFAH/fViq4fXG0vdckHqeJk+75fpQ2OH+Az6076tX/M0835zA45E0Cqa6pV5Kiv9YOqjEg==", "dev": true, "requires": { - "@babel/template": "7.1.2", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/template": "^7.1.2", + "@babel/traverse": "^7.1.5", + "@babel/types": "^7.1.5" } }, "@babel/highlight": { @@ -257,9 +346,9 @@ "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", "dev": true, "requires": { - "chalk": "2.4.1", - "esutils": "2.0.2", - "js-tokens": "4.0.0" + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" } }, "@babel/parser": { @@ -274,9 +363,19 @@ "integrity": "sha512-Fq803F3Jcxo20MXUSDdmZZXrPe6BWyGcWBPPNB/M7WaUYESKDeKMOGIxEzQOjGSmW/NWb6UaPZrtTB2ekhB/ew==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-remap-async-to-generator": "7.1.0", - "@babel/plugin-syntax-async-generators": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.0.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.0.tgz", + "integrity": "sha512-wNHxLkEKTQ2ay0tnsam2z7fGZUi+05ziDJflEt3AZTP3oXLKHJp9HqhfroB/vdMvt3sda9fAbq7FsG8QPDrZBg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.3.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-proposal-json-strings": { @@ -285,8 +384,8 @@ "integrity": "sha512-kfVdUkIAGJIVmHmtS/40i/fg/AGnw/rsZBCaapY5yjeO5RA9m165Xbw9KMOu2nqXP5dTFjEjHdfNdoVcHv133Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/plugin-syntax-json-strings": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.0.0" } }, "@babel/plugin-proposal-object-rest-spread": { @@ -295,8 +394,8 @@ "integrity": "sha512-14fhfoPcNu7itSen7Py1iGN0gEm87hX/B+8nZPqkdmANyyYWYMY2pjA3r8WXbWVKMzfnSNS0xY8GVS0IjXi/iw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/plugin-syntax-object-rest-spread": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.0.0" } }, "@babel/plugin-proposal-optional-catch-binding": { @@ -305,8 +404,8 @@ "integrity": "sha512-JPqAvLG1s13B/AuoBjdBYvn38RqW6n1TzrQO839/sIpqLpbnXKacsAgpZHzLD83Sm8SDXMkkrAvEnJ25+0yIpw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.0.0" } }, "@babel/plugin-proposal-unicode-property-regex": { @@ -315,9 +414,9 @@ "integrity": "sha512-tM3icA6GhC3ch2SkmSxv7J/hCWKISzwycub6eGsDrFDgukD4dZ/I+x81XgW0YslS6mzNuQ1Cbzh5osjIMgepPQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-regex": "7.0.0", - "regexpu-core": "4.2.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.2.0" } }, "@babel/plugin-syntax-async-generators": { @@ -326,7 +425,7 @@ "integrity": "sha512-im7ged00ddGKAjcZgewXmp1vxSZQQywuQXe2B1A7kajjZmDeY/ekMPmWr9zJgveSaQH0k7BcGrojQhcK06l0zA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-flow": { @@ -335,7 +434,7 @@ "integrity": "sha512-zGcuZWiWWDa5qTZ6iAnpG0fnX/GOu49pGR5PFvkQ9GmKNaSphXQnlNXh/LG20sqWtNrx/eB6krzfEzcwvUyeFA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-json-strings": { @@ -344,7 +443,7 @@ "integrity": "sha512-UlSfNydC+XLj4bw7ijpldc1uZ/HB84vw+U6BTuqMdIEmz/LDe63w/GHtpQMdXWdqQZFeAI9PjnHe/vDhwirhKA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-object-rest-spread": { @@ -353,7 +452,7 @@ "integrity": "sha512-5A0n4p6bIiVe5OvQPxBnesezsgFJdHhSs3uFSvaPdMqtsovajLZ+G2vZyvNe10EzJBWWo3AcHGKhAFUxqwp2dw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-optional-catch-binding": { @@ -362,7 +461,7 @@ "integrity": "sha512-Wc+HVvwjcq5qBg1w5RG9o9RVzmCaAg/Vp0erHCKpAYV8La6I94o4GQAmFYNmkzoMO6gzoOSulpKeSSz6mPEoZw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-arrow-functions": { @@ -371,7 +470,7 @@ "integrity": "sha512-2EZDBl1WIO/q4DIkIp4s86sdp4ZifL51MoIviLY/gG/mLSuOIEg7J8o6mhbxOTvUJkaN50n+8u41FVsr5KLy/w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-async-to-generator": { @@ -380,9 +479,9 @@ "integrity": "sha512-rNmcmoQ78IrvNCIt/R9U+cixUHeYAzgusTFgIAv+wQb9HJU4szhpDD6e5GCACmj/JP5KxuCwM96bX3L9v4ZN/g==", "dev": true, "requires": { - "@babel/helper-module-imports": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-remap-async-to-generator": "7.1.0" + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" } }, "@babel/plugin-transform-block-scoped-functions": { @@ -391,7 +490,7 @@ "integrity": "sha512-AOBiyUp7vYTqz2Jibe1UaAWL0Hl9JUXEgjFvvvcSc9MVDItv46ViXFw2F7SVt1B5k+KWjl44eeXOAk3UDEaJjQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-block-scoping": { @@ -400,8 +499,8 @@ "integrity": "sha512-jlYcDrz+5ayWC7mxgpn1Wj8zj0mmjCT2w0mPIMSwO926eXBRxpEgoN/uQVRBfjtr8ayjcmS+xk2G1jaP8JjMJQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "lodash": "4.17.11" + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.10" } }, "@babel/plugin-transform-classes": { @@ -410,14 +509,14 @@ "integrity": "sha512-rNaqoD+4OCBZjM7VaskladgqnZ1LO6o2UxuWSDzljzW21pN1KXkB7BstAVweZdxQkHAujps5QMNOTWesBciKFg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "7.0.0", - "@babel/helper-define-map": "7.1.0", - "@babel/helper-function-name": "7.1.0", - "@babel/helper-optimise-call-expression": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-replace-supers": "7.1.0", - "@babel/helper-split-export-declaration": "7.0.0", - "globals": "11.9.0" + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.1.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { @@ -426,7 +525,7 @@ "integrity": "sha512-ubouZdChNAv4AAWAgU7QKbB93NU5sHwInEWfp+/OzJKA02E6Woh9RVoX4sZrbRwtybky/d7baTUqwFx+HgbvMA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-destructuring": { @@ -435,7 +534,7 @@ "integrity": "sha512-Mb9M4DGIOspH1ExHOUnn2UUXFOyVTiX84fXCd+6B5iWrQg/QMeeRmSwpZ9lnjYLSXtZwiw80ytVMr3zue0ucYw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-dotall-regex": { @@ -444,9 +543,9 @@ "integrity": "sha512-00THs8eJxOJUFVx1w8i1MBF4XH4PsAjKjQ1eqN/uCH3YKwP21GCKfrn6YZFZswbOk9+0cw1zGQPHVc1KBlSxig==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-regex": "7.0.0", - "regexpu-core": "4.2.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" } }, "@babel/plugin-transform-duplicate-keys": { @@ -455,7 +554,7 @@ "integrity": "sha512-w2vfPkMqRkdxx+C71ATLJG30PpwtTpW7DDdLqYt2acXU7YjztzeWW2Jk1T6hKqCLYCcEA5UQM/+xTAm+QCSnuQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-exponentiation-operator": { @@ -464,8 +563,8 @@ "integrity": "sha512-uZt9kD1Pp/JubkukOGQml9tqAeI8NkE98oZnHZ2qHRElmeKCodbTZgOEUtujSCSLhHSBWbzNiFSDIMC4/RBTLQ==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-flow-strip-types": { @@ -474,8 +573,8 @@ "integrity": "sha512-0tyFAAjJmnRlr8MVJV39ASn1hv+PbdVP71hf7aAseqLfQ0o9QXk9htbMbq7/ZYXnUIp6gDw0lUUP0+PQMbbtmg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/plugin-syntax-flow": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.0.0" } }, "@babel/plugin-transform-for-of": { @@ -484,7 +583,7 @@ "integrity": "sha512-TlxKecN20X2tt2UEr2LNE6aqA0oPeMT1Y3cgz8k4Dn1j5ObT8M3nl9aA37LLklx0PBZKETC9ZAf9n/6SujTuXA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-function-name": { @@ -493,8 +592,8 @@ "integrity": "sha512-VxOa1TMlFMtqPW2IDYZQaHsFrq/dDoIjgN098NowhexhZcz3UGlvPgZXuE1jEvNygyWyxRacqDpCZt+par1FNg==", "dev": true, "requires": { - "@babel/helper-function-name": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-literals": { @@ -503,7 +602,7 @@ "integrity": "sha512-1NTDBWkeNXgpUcyoVFxbr9hS57EpZYXpje92zv0SUzjdu3enaRwF/l3cmyRnXLtIdyJASyiS6PtybK+CgKf7jA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-modules-amd": { @@ -512,8 +611,8 @@ "integrity": "sha512-wt8P+xQ85rrnGNr2x1iV3DW32W8zrB6ctuBkYBbf5/ZzJY99Ob4MFgsZDFgczNU76iy9PWsy4EuxOliDjdKw6A==", "dev": true, "requires": { - "@babel/helper-module-transforms": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-modules-commonjs": { @@ -522,9 +621,9 @@ "integrity": "sha512-wtNwtMjn1XGwM0AXPspQgvmE6msSJP15CX2RVfpTSTNPLhKhaOjaIfBaVfj4iUZ/VrFSodcFedwtPg/NxwQlPA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-simple-access": "7.1.0" + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0" } }, "@babel/plugin-transform-modules-systemjs": { @@ -533,8 +632,8 @@ "integrity": "sha512-PvTxgjxQAq4pvVUZF3mD5gEtVDuId8NtWkJsZLEJZMZAW3TvgQl1pmydLLN1bM8huHFVVU43lf0uvjQj9FRkKw==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-hoist-variables": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-modules-umd": { @@ -543,8 +642,8 @@ "integrity": "sha512-enrRtn5TfRhMmbRwm7F8qOj0qEYByqUvTttPEGimcBH4CJHphjyK1Vg7sdU7JjeEmgSpM890IT/efS2nMHwYig==", "dev": true, "requires": { - "@babel/helper-module-transforms": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-new-target": { @@ -553,7 +652,7 @@ "integrity": "sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-object-super": { @@ -562,8 +661,8 @@ "integrity": "sha512-/O02Je1CRTSk2SSJaq0xjwQ8hG4zhZGNjE8psTsSNPXyLRCODv7/PBozqT5AmQMzp7MI3ndvMhGdqp9c96tTEw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-replace-supers": "7.1.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0" } }, "@babel/plugin-transform-parameters": { @@ -572,9 +671,9 @@ "integrity": "sha512-vHV7oxkEJ8IHxTfRr3hNGzV446GAb+0hgbA7o/0Jd76s+YzccdWuTU296FOCOl/xweU4t/Ya4g41yWz80RFCRw==", "dev": true, "requires": { - "@babel/helper-call-delegate": "7.1.0", - "@babel/helper-get-function-arity": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-call-delegate": "^7.1.0", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-regenerator": { @@ -583,7 +682,7 @@ "integrity": "sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw==", "dev": true, "requires": { - "regenerator-transform": "0.13.3" + "regenerator-transform": "^0.13.3" } }, "@babel/plugin-transform-shorthand-properties": { @@ -592,7 +691,7 @@ "integrity": "sha512-g/99LI4vm5iOf5r1Gdxq5Xmu91zvjhEG5+yZDJW268AZELAu4J1EiFLnkSG3yuUsZyOipVOVUKoGPYwfsTymhw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-spread": { @@ -601,7 +700,7 @@ "integrity": "sha512-L702YFy2EvirrR4shTj0g2xQp7aNwZoWNCkNu2mcoU0uyzMl0XRwDSwzB/xp6DSUFiBmEXuyAyEN16LsgVqGGQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-sticky-regex": { @@ -610,8 +709,8 @@ "integrity": "sha512-LFUToxiyS/WD+XEWpkx/XJBrUXKewSZpzX68s+yEOtIbdnsRjpryDw9U06gYc6klYEij/+KQVRnD3nz3AoKmjw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-regex": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" } }, "@babel/plugin-transform-template-literals": { @@ -620,8 +719,8 @@ "integrity": "sha512-vA6rkTCabRZu7Nbl9DfLZE1imj4tzdWcg5vtdQGvj+OH9itNNB6hxuRMHuIY8SGnEt1T9g5foqs9LnrHzsqEFg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-typeof-symbol": { @@ -630,7 +729,7 @@ "integrity": "sha512-1r1X5DO78WnaAIvs5uC48t41LLckxsYklJrZjNKcevyz83sF2l4RHbw29qrCPr/6ksFsdfRpT/ZgxNWHXRnffg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-unicode-regex": { @@ -639,9 +738,9 @@ "integrity": "sha512-uJBrJhBOEa3D033P95nPHu3nbFwFE9ZgXsfEitzoIXIwqAZWk7uXcg06yFKXz9FSxBH5ucgU/cYdX0IV8ldHKw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-regex": "7.0.0", - "regexpu-core": "4.2.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" } }, "@babel/polyfill": { @@ -649,8 +748,8 @@ "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.0.0.tgz", "integrity": "sha512-dnrMRkyyr74CRelJwvgnnSUDh2ge2NCTyHVwpOdvRMHtJUyxLtMAfhBN3s64pY41zdw0kgiLPh6S20eb1NcX6Q==", "requires": { - "core-js": "2.5.7", - "regenerator-runtime": "0.11.1" + "core-js": "^2.5.7", + "regenerator-runtime": "^0.11.1" } }, "@babel/preset-env": { @@ -659,47 +758,47 @@ "integrity": "sha512-YIBfpJNQMBkb6MCkjz/A9J76SNCSuGVamOVBgoUkLzpJD/z8ghHi9I42LQ4pulVX68N/MmImz6ZTixt7Azgexw==", "dev": true, "requires": { - "@babel/helper-module-imports": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0", - "@babel/plugin-proposal-async-generator-functions": "7.1.0", - "@babel/plugin-proposal-json-strings": "7.0.0", - "@babel/plugin-proposal-object-rest-spread": "7.0.0", - "@babel/plugin-proposal-optional-catch-binding": "7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "7.0.0", - "@babel/plugin-syntax-async-generators": "7.0.0", - "@babel/plugin-syntax-object-rest-spread": "7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "7.0.0", - "@babel/plugin-transform-arrow-functions": "7.0.0", - "@babel/plugin-transform-async-to-generator": "7.1.0", - "@babel/plugin-transform-block-scoped-functions": "7.0.0", - "@babel/plugin-transform-block-scoping": "7.1.5", - "@babel/plugin-transform-classes": "7.1.0", - "@babel/plugin-transform-computed-properties": "7.0.0", - "@babel/plugin-transform-destructuring": "7.1.3", - "@babel/plugin-transform-dotall-regex": "7.0.0", - "@babel/plugin-transform-duplicate-keys": "7.0.0", - "@babel/plugin-transform-exponentiation-operator": "7.1.0", - "@babel/plugin-transform-for-of": "7.0.0", - "@babel/plugin-transform-function-name": "7.1.0", - "@babel/plugin-transform-literals": "7.0.0", - "@babel/plugin-transform-modules-amd": "7.1.0", - "@babel/plugin-transform-modules-commonjs": "7.1.0", - "@babel/plugin-transform-modules-systemjs": "7.1.3", - "@babel/plugin-transform-modules-umd": "7.1.0", - "@babel/plugin-transform-new-target": "7.0.0", - "@babel/plugin-transform-object-super": "7.1.0", - "@babel/plugin-transform-parameters": "7.1.0", - "@babel/plugin-transform-regenerator": "7.0.0", - "@babel/plugin-transform-shorthand-properties": "7.0.0", - "@babel/plugin-transform-spread": "7.0.0", - "@babel/plugin-transform-sticky-regex": "7.0.0", - "@babel/plugin-transform-template-literals": "7.0.0", - "@babel/plugin-transform-typeof-symbol": "7.0.0", - "@babel/plugin-transform-unicode-regex": "7.0.0", - "browserslist": "4.3.4", - "invariant": "2.2.4", - "js-levenshtein": "1.1.4", - "semver": "5.6.0" + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.1.0", + "@babel/plugin-proposal-json-strings": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.0.0", + "@babel/plugin-syntax-async-generators": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-async-to-generator": "^7.1.0", + "@babel/plugin-transform-block-scoped-functions": "^7.0.0", + "@babel/plugin-transform-block-scoping": "^7.1.5", + "@babel/plugin-transform-classes": "^7.1.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.0.0", + "@babel/plugin-transform-dotall-regex": "^7.0.0", + "@babel/plugin-transform-duplicate-keys": "^7.0.0", + "@babel/plugin-transform-exponentiation-operator": "^7.1.0", + "@babel/plugin-transform-for-of": "^7.0.0", + "@babel/plugin-transform-function-name": "^7.1.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-modules-amd": "^7.1.0", + "@babel/plugin-transform-modules-commonjs": "^7.1.0", + "@babel/plugin-transform-modules-systemjs": "^7.0.0", + "@babel/plugin-transform-modules-umd": "^7.1.0", + "@babel/plugin-transform-new-target": "^7.0.0", + "@babel/plugin-transform-object-super": "^7.1.0", + "@babel/plugin-transform-parameters": "^7.1.0", + "@babel/plugin-transform-regenerator": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-sticky-regex": "^7.0.0", + "@babel/plugin-transform-template-literals": "^7.0.0", + "@babel/plugin-transform-typeof-symbol": "^7.0.0", + "@babel/plugin-transform-unicode-regex": "^7.0.0", + "browserslist": "^4.1.0", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.3.0" } }, "@babel/preset-flow": { @@ -708,8 +807,8 @@ "integrity": "sha512-bJOHrYOPqJZCkPVbG1Lot2r5OSsB+iUOaxiHdlOeB1yPWS6evswVHwvkDLZ54WTaTRIk89ds0iHmGZSnxlPejQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/plugin-transform-flow-strip-types": "7.1.6" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-transform-flow-strip-types": "^7.0.0" } }, "@babel/register": { @@ -718,13 +817,13 @@ "integrity": "sha512-f/+CRmaCe7rVEvcvPvxeA8j5aJhHC3aJie7YuqcMDhUOuyWLA7J/aNrTaHIzoWPEhpHA54mec4Mm8fv8KBlv3g==", "dev": true, "requires": { - "core-js": "2.5.7", - "find-cache-dir": "1.0.0", - "home-or-tmp": "3.0.0", - "lodash": "4.17.11", - "mkdirp": "0.5.1", - "pirates": "4.0.0", - "source-map-support": "0.5.9" + "core-js": "^2.5.7", + "find-cache-dir": "^1.0.0", + "home-or-tmp": "^3.0.0", + "lodash": "^4.17.10", + "mkdirp": "^0.5.1", + "pirates": "^4.0.0", + "source-map-support": "^0.5.9" }, "dependencies": { "source-map": { @@ -739,8 +838,8 @@ "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", "dev": true, "requires": { - "buffer-from": "1.1.1", - "source-map": "0.6.1" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } } } @@ -751,9 +850,9 @@ "integrity": "sha512-SY1MmplssORfFiLDcOETrW7fCLl+PavlwMh92rrGcikQaRq4iWPVH0MpwPpY3etVMx6RnDjXtr6VZYr/IbP/Ag==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0", - "@babel/parser": "7.1.6", - "@babel/types": "7.1.6" + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.1.2", + "@babel/types": "^7.1.2" } }, "@babel/traverse": { @@ -762,15 +861,15 @@ "integrity": "sha512-CXedit6GpISz3sC2k2FsGCUpOhUqKdyL0lqNrImQojagnUMXf8hex4AxYFRuMkNGcvJX5QAFGzB5WJQmSv8SiQ==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0", - "@babel/generator": "7.1.6", - "@babel/helper-function-name": "7.1.0", - "@babel/helper-split-export-declaration": "7.0.0", - "@babel/parser": "7.1.6", - "@babel/types": "7.1.6", - "debug": "4.1.0", - "globals": "11.9.0", - "lodash": "4.17.11" + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.1.6", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.1.6", + "@babel/types": "^7.1.6", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.10" } }, "@babel/types": { @@ -779,9 +878,9 @@ "integrity": "sha512-DMiUzlY9DSjVsOylJssxLHSgj6tWM9PRFJOGW/RaOglVOK9nzTxoOMfTfRQXGUCUQ/HmlG2efwC+XqUEJ5ay4w==", "dev": true, "requires": { - "esutils": "2.0.2", - "lodash": "4.17.11", - "to-fast-properties": "2.0.0" + "esutils": "^2.0.2", + "lodash": "^4.17.10", + "to-fast-properties": "^2.0.0" } }, "@types/chai": { @@ -826,7 +925,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.3" + "color-convert": "^1.9.0" } }, "argparse": { @@ -835,7 +934,7 @@ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "arrify": { @@ -862,9 +961,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" }, "dependencies": { "ansi-styles": { @@ -875,15 +974,15 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "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" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "js-tokens": { @@ -912,7 +1011,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -934,9 +1033,9 @@ "integrity": "sha512-u5iz+ijIMUlmV8blX82VGFrB9ecnUg5qEt55CMZ/YJEhha+d8qpBfOFuutJ6F/VKRXjZoD33b6uvarpPxcl3RA==", "dev": true, "requires": { - "caniuse-lite": "1.0.30000909", - "electron-to-chromium": "1.3.84", - "node-releases": "1.0.4" + "caniuse-lite": "^1.0.30000899", + "electron-to-chromium": "^1.3.82", + "node-releases": "^1.0.1" } }, "buffer-from": { @@ -959,13 +1058,13 @@ }, "chai": { "version": "3.5.0", - "resolved": "http://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", "dev": true, "requires": { - "assertion-error": "1.1.0", - "deep-eql": "0.1.3", - "type-detect": "1.0.0" + "assertion-error": "^1.0.1", + "deep-eql": "^0.1.3", + "type-detect": "^1.0.0" } }, "chalk": { @@ -974,9 +1073,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "color-convert": { @@ -996,7 +1095,7 @@ }, "commander": { "version": "2.15.1", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, @@ -1018,7 +1117,7 @@ "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.1" } }, "core-js": { @@ -1032,12 +1131,12 @@ "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "deep-eql": { "version": "0.1.3", - "resolved": "http://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", "dev": true, "requires": { @@ -1088,9 +1187,9 @@ "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", "dev": true, "requires": { - "commondir": "1.0.1", - "make-dir": "1.3.0", - "pkg-dir": "2.0.0" + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^2.0.0" } }, "find-up": { @@ -1099,7 +1198,7 @@ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "locate-path": "2.0.0" + "locate-path": "^2.0.0" } }, "flow-bin": { @@ -1120,12 +1219,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "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" } }, "globals": { @@ -1151,7 +1250,7 @@ "integrity": "sha512-tydslNg6pPHi61aMs0HoaETTtyDR5TQyDZ0AQhbbURpOK2NW8IMrUGs/i1UMkS0H64Vj7PuggSAhDohP41yubQ==", "dev": true, "requires": { - "browser-headers": "0.4.0" + "browser-headers": "^0.4.0" } }, "has-ansi": { @@ -1160,7 +1259,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-flag": { @@ -1187,8 +1286,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -1203,7 +1302,7 @@ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dev": true, "requires": { - "loose-envify": "1.4.0" + "loose-envify": "^1.0.0" } }, "js-levenshtein": { @@ -1224,8 +1323,8 @@ "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", "dev": true, "requires": { - "argparse": "1.0.10", - "esprima": "4.0.1" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "jsesc": { @@ -1240,7 +1339,7 @@ "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", "dev": true, "requires": { - "minimist": "1.2.0" + "minimist": "^1.2.0" } }, "locate-path": { @@ -1249,8 +1348,8 @@ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" } }, "lodash": { @@ -1271,7 +1370,7 @@ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "dev": true, "requires": { - "js-tokens": "4.0.0" + "js-tokens": "^3.0.0 || ^4.0.0" } }, "make-dir": { @@ -1280,7 +1379,7 @@ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { - "pify": "3.0.0" + "pify": "^3.0.0" } }, "make-error": { @@ -1295,18 +1394,18 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, "mkdirp": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -1315,7 +1414,7 @@ "dependencies": { "minimist": { "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true } @@ -1361,7 +1460,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -1372,8 +1471,8 @@ "integrity": "sha1-iBxKCDcKn3bbFQ+yMFTjDMPjcnA=", "dev": true, "requires": { - "mocha": "5.2.0", - "moment": "2.22.2" + "mocha": "^5.0.2", + "moment": "^2.21.0" } }, "moment": { @@ -1400,7 +1499,7 @@ "integrity": "sha512-GqRV9GcHw8JCRDaP/JoeNMNzEGzHAknMvIHqMb2VeTOmg1Cf9+ej8bkV12tHfzWHQMCkQ5zUFgwFUkfraynNCw==", "dev": true, "requires": { - "semver": "5.6.0" + "semver": "^5.3.0" } }, "once": { @@ -1409,7 +1508,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "p-limit": { @@ -1418,7 +1517,7 @@ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { - "p-try": "1.0.0" + "p-try": "^1.0.0" } }, "p-locate": { @@ -1427,7 +1526,7 @@ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "p-limit": "1.3.0" + "p-limit": "^1.1.0" } }, "p-try": { @@ -1444,7 +1543,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, @@ -1466,7 +1565,7 @@ "integrity": "sha512-8t5BsXy1LUIjn3WWOlOuFDuKswhQb/tkak641lvBgmPOBUQHXveORtlMCp6OdPV1dtuTaEahKA8VNz6uLfKBtA==", "dev": true, "requires": { - "node-modules-regexp": "1.0.0" + "node-modules-regexp": "^1.0.0" } }, "pkg-dir": { @@ -1475,7 +1574,7 @@ "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { - "find-up": "2.1.0" + "find-up": "^2.1.0" } }, "private": { @@ -1496,7 +1595,7 @@ "integrity": "sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw==", "dev": true, "requires": { - "regenerate": "1.4.0" + "regenerate": "^1.4.0" } }, "regenerator-runtime": { @@ -1510,7 +1609,7 @@ "integrity": "sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA==", "dev": true, "requires": { - "private": "0.1.8" + "private": "^0.1.6" } }, "regexpu-core": { @@ -1519,12 +1618,12 @@ "integrity": "sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw==", "dev": true, "requires": { - "regenerate": "1.4.0", - "regenerate-unicode-properties": "7.0.0", - "regjsgen": "0.4.0", - "regjsparser": "0.3.0", - "unicode-match-property-ecmascript": "1.0.4", - "unicode-match-property-value-ecmascript": "1.0.2" + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^7.0.0", + "regjsgen": "^0.4.0", + "regjsparser": "^0.3.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.0.2" } }, "regjsgen": { @@ -1539,12 +1638,12 @@ "integrity": "sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA==", "dev": true, "requires": { - "jsesc": "0.5.0" + "jsesc": "~0.5.0" }, "dependencies": { "jsesc": { "version": "0.5.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true } @@ -1556,7 +1655,7 @@ "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", "dev": true, "requires": { - "path-parse": "1.0.6" + "path-parse": "^1.0.5" } }, "safe-buffer": { @@ -1583,7 +1682,7 @@ "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "dev": true, "requires": { - "source-map": "0.5.7" + "source-map": "^0.5.6" } }, "sprintf-js": { @@ -1598,7 +1697,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "supports-color": { @@ -1607,7 +1706,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } }, "to-fast-properties": { @@ -1628,14 +1727,14 @@ "integrity": "sha512-XK7QmDcNHVmZkVtkiwNDWiERRHPyU8nBqZB1+iv2UhOG0q3RQ9HsZ2CMqISlFbxjrYFGfG2mX7bW4dAyxBVzUw==", "dev": true, "requires": { - "arrify": "1.0.1", - "chalk": "2.4.1", - "diff": "3.5.0", - "make-error": "1.3.5", - "minimist": "1.2.0", - "mkdirp": "0.5.1", - "source-map-support": "0.5.9", - "yn": "2.0.0" + "arrify": "^1.0.0", + "chalk": "^2.3.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.3", + "yn": "^2.0.0" }, "dependencies": { "source-map": { @@ -1650,8 +1749,8 @@ "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", "dev": true, "requires": { - "buffer-from": "1.1.1", - "source-map": "0.6.1" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } } } @@ -1668,18 +1767,18 @@ "integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "builtin-modules": "1.1.1", - "chalk": "2.4.1", - "commander": "2.15.1", - "diff": "3.5.0", - "glob": "7.1.2", - "js-yaml": "3.12.0", - "minimatch": "3.0.4", - "resolve": "1.8.1", - "semver": "5.6.0", - "tslib": "1.9.3", - "tsutils": "2.29.0" + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.7.0", + "minimatch": "^3.0.4", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.27.2" } }, "tsutils": { @@ -1688,7 +1787,7 @@ "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", "dev": true, "requires": { - "tslib": "1.9.3" + "tslib": "^1.8.1" } }, "type-detect": { @@ -1715,8 +1814,8 @@ "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", "dev": true, "requires": { - "unicode-canonical-property-names-ecmascript": "1.0.4", - "unicode-property-aliases-ecmascript": "1.0.4" + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" } }, "unicode-match-property-value-ecmascript": { diff --git a/package.json b/package.json index c8aaa645..2a0cb4a3 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ }, "devDependencies": { "@babel/core": "^7.1.6", + "@babel/plugin-proposal-class-properties": "^7.3.0", "@babel/preset-env": "^7.1.6", "@babel/preset-flow": "^7.0.0", "@babel/register": "^7.0.0", diff --git a/src/index.ts b/src/index.ts index c82f6082..a9d2ee6a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -55,7 +55,7 @@ withAllStdIn((inputBuff: Buffer) => { } if (generateServices) { - generateGrpcWebService(outputFileName, fileNameToDescriptor[fileName], exportMap) + generateGrpcWebService(outputFileName, fileNameToDescriptor[fileName], exportMap, generateTs) .forEach(file => codeGenResponse.addFile(file)); } }); diff --git a/src/service/grpcweb.ts b/src/service/grpcweb.ts index bb7a58fe..b9c6e679 100644 --- a/src/service/grpcweb.ts +++ b/src/service/grpcweb.ts @@ -10,9 +10,15 @@ import {WellKnownTypesMap} from "../WellKnown"; import {getFieldType, MESSAGE_TYPE} from "../ts/FieldTypes"; import {CodeGeneratorResponse} from "google-protobuf/google/protobuf/compiler/plugin_pb"; -export function generateGrpcWebService(filename: string, descriptor: FileDescriptorProto, exportMap: ExportMap): CodeGeneratorResponse.File[] { +export function generateGrpcWebService(filename: string, descriptor: FileDescriptorProto, exportMap: ExportMap, generateTs: boolean): CodeGeneratorResponse.File[] { + if (generateTs) { + return [ + createFile(generateTypescriptDefinition(descriptor, exportMap), `${filename}_service.d.ts`), + createFile(generateJavaScript(descriptor, exportMap), `${filename}_service.js`), + ]; + } return [ - createFile(generateTypescriptDefinition(descriptor, exportMap), `${filename}_service.d.ts`), + createFile(generateFlowDefinition(descriptor, exportMap), `${filename}_service.js.flow`), createFile(generateJavaScript(descriptor, exportMap), `${filename}_service.js`), ]; } @@ -153,6 +159,95 @@ class GrpcWebServiceDescriptor { } } +function generateFlowDefinition(fileDescriptor: FileDescriptorProto, exportMap: ExportMap) { + const serviceDescriptor = new GrpcWebServiceDescriptor(fileDescriptor, exportMap); + const printer = new Printer(0); + + // Header. + printer.printLn(`// @flow`); + printer.printLn(`// package: ${serviceDescriptor.packageName}`); + printer.printLn(`// file: ${serviceDescriptor.filename}`); + printer.printEmptyLn(); + + if (serviceDescriptor.services.length === 0) { + return printer.getOutput(); + } + + // Import statements. + serviceDescriptor.imports + .forEach(importDescriptor => { + printer.printLn(`import * as ${importDescriptor.namespace} from "${importDescriptor.path}";`); + }); + printer.printLn(`import {grpc} from "grpc-web-client";`); + printer.printEmptyLn(); + + // Services. + serviceDescriptor.services + .forEach(service => { + + // Method Type Definitions + service.methods.forEach(method => { + printer.printLn(`type ${method.serviceName}${method.nameAsPascalCase} = {`); + printer.printIndentedLn(`+methodName: string,`); + printer.printIndentedLn(`+service: typeof ${method.serviceName},`); + printer.printIndentedLn(`+requestStream: ${method.requestStream},`); + printer.printIndentedLn(`+responseStream: ${method.responseStream},`); + printer.printIndentedLn(`+requestType: typeof ${method.requestType},`); + printer.printIndentedLn(`+responseType: typeof ${method.responseType},`); + printer.printLn(`};`); + printer.printEmptyLn(); + }); + + printer.printLn(`export class ${service.name} {`); + printer.printIndentedLn(`static +serviceName: string;`); + service.methods.forEach(method => { + printer.printIndentedLn(`static +${method.nameAsPascalCase}: ${method.serviceName}${method.nameAsPascalCase};`); + }); + printer.printLn(`}`); + printer.printEmptyLn(); + }); + + + + printer.printLn(`export type ServiceError = { message: string, code: number; metadata: grpc.Metadata }`); + printer.printLn(`export type Status = { details: string, code: number; metadata: grpc.Metadata }`); + printer.printEmptyLn(); + printer.printLn("interface UnaryResponse {"); + printer.printIndentedLn("cancel(): void;"); + printer.printLn("}"); + printer.printLn(`interface ResponseStream {`); + printer.printIndentedLn(`cancel(): void;`); + printer.printIndentedLn(`on(type: 'data', handler: (message: T) => void): ResponseStream;`); + printer.printIndentedLn(`on(type: 'end', handler: () => void): ResponseStream;`); + printer.printIndentedLn(`on(type: 'status', handler: (status: Status) => void): ResponseStream;`); + printer.printLn(`}`); + printer.printLn(`interface RequestStream {`); + printer.printIndentedLn(`write(message: T): RequestStream;`); + printer.printIndentedLn(`end(): void;`); + printer.printIndentedLn(`cancel(): void;`); + printer.printIndentedLn(`on(type: 'end', handler: () => void): RequestStream;`); + printer.printIndentedLn(`on(type: 'status', handler: (status: Status) => void): RequestStream;`); + printer.printLn(`}`); + printer.printLn(`interface BidirectionalStream {`); + printer.printIndentedLn(`write(message: ReqT): BidirectionalStream;`); + printer.printIndentedLn(`end(): void;`); + printer.printIndentedLn(`cancel(): void;`); + printer.printIndentedLn(`on(type: 'data', handler: (message: ResT) => void): BidirectionalStream;`); + printer.printIndentedLn(`on(type: 'end', handler: () => void): BidirectionalStream;`); + printer.printIndentedLn(`on(type: 'status', handler: (status: Status) => void): BidirectionalStream;`); + printer.printLn(`}`); + printer.printEmptyLn(); + + // Add a client stub that talks with the grpc-web-client library + serviceDescriptor.services + .forEach(service => { + printServiceStubFlowTypes(printer, service); + printer.printEmptyLn(); + }); + + return printer.getOutput(); +} + function generateTypescriptDefinition(fileDescriptor: FileDescriptorProto, exportMap: ExportMap) { const serviceDescriptor = new GrpcWebServiceDescriptor(fileDescriptor, exportMap); const printer = new Printer(0); @@ -489,6 +584,29 @@ function printBidirectionalStubMethod(printer: CodePrinter, method: RPCMethodDes .dedent().printLn(`};`); } +function printServiceStubFlowTypes(methodPrinter: Printer, service: RPCDescriptor) { + const printer = new CodePrinter(0, methodPrinter); + + printer + .printLn(`declare export class ${service.name}Client {`) + .indent().printLn(`+serviceHost: string;`) + .printEmptyLn() + .printLn(`constructor(serviceHost: string, options?: grpc.RpcOptions): ${service.name}Client;`); + + service.methods.forEach((method: RPCMethodDescriptor) => { + if (method.requestStream && method.responseStream) { + printBidirectionalStubMethodTypes(printer, method); + } else if (method.requestStream) { + printClientStreamStubMethodTypes(printer, method); + } else if (method.responseStream) { + printServerStreamStubMethodTypes(printer, method); + } else { + printUnaryStubMethodTypes(printer, method); + } + }); + printer.dedent().printLn("}"); +} + function printServiceStubTypes(methodPrinter: Printer, service: RPCDescriptor) { const printer = new CodePrinter(0, methodPrinter); diff --git a/test/flow/helpers/fakeGrpcTransport.js b/test/flow/helpers/fakeGrpcTransport.js new file mode 100644 index 00000000..8eeddd16 --- /dev/null +++ b/test/flow/helpers/fakeGrpcTransport.js @@ -0,0 +1,217 @@ +// @flow + +import { Message } from "google-protobuf"; +import { grpc } from "grpc-web-client"; +import * as _ from "lodash"; + +function frameResponse(request: Message): Uint8Array { + const bytes = request.serializeBinary(); + const frame = new ArrayBuffer(bytes.byteLength + 5); + new DataView(frame, 0, 5).setUint32(1, bytes.length, false /* big endian */); + new Uint8Array(frame, 5).set(bytes); + return new Uint8Array(frame); +} + +export function frameRequest(request: Message): ArrayBufferView { + const bytes = request.serializeBinary(); + const frame = new ArrayBuffer(bytes.byteLength + 5); + new DataView(frame, 1, 4).setUint32(0, bytes.length, false /* big endian */); + new Uint8Array(frame, 5).set(bytes); + return new Uint8Array(frame); +} + +function frameTrailers(trailers: grpc.Metadata): Uint8Array { + let asString = ""; + trailers.forEach((key: string, values: string[]) => { + asString += `${key}: ${values.join(", ")}\r\n`; + }); + const bytes = new Buffer(asString); + const frame = new ArrayBuffer(bytes.byteLength + 5); + const dataview = new DataView(frame, 0, 5); + dataview.setUint32(1, bytes.length, false /* big endian */); + dataview.setUint8(0, 128); + new Uint8Array(frame, 5).set(bytes); + return new Uint8Array(frame); +} + +export class StubTransportBuilder { + /*private*/ requestListener: (options: grpc.TransportOptions) => void; + /*private*/ headersListener: (headers: grpc.Metadata) => void; + /*private*/ messageListener: (messageBytes: ArrayBufferView) => void; + /*private*/ finishSendListener: () => void; + /*private*/ cancelListener: () => void; + /*private*/ preHeadersErrorCode: number | null = null; + /*private*/ headers: grpc.Metadata | null = null; + /*private*/ preMessagesError: [grpc.Code, string] | null = null; + /*private*/ messages: Array = []; + /*private*/ preTrailersError: [grpc.Code, string] | null = null; + /*private*/ trailers: grpc.Metadata | null = null; + /*private*/ autoTrigger: boolean = true; + + withRequestListener(requestListener: (options: grpc.TransportOptions) => void) { + this.requestListener = requestListener; + return this; + } + + withHeadersListener(headersListener: (headers: grpc.Metadata) => void) { + this.headersListener = headersListener; + return this; + } + + withMessageListener(messageListener: (messageBytes: ArrayBufferView) => void) { + this.messageListener = messageListener; + return this; + } + + withFinishSendListener(finishSendListener: () => void) { + this.finishSendListener = finishSendListener; + return this; + } + + withCancelListener(cancelListener: () => void) { + this.cancelListener = cancelListener; + return this; + } + + withPreHeadersError(httpCode: number) { + this.preHeadersErrorCode = httpCode; + return this; + } + + withHeaders(headers: grpc.Metadata) { + this.headers = headers; + return this; + } + + withPreMessagesError(grpcStatus: grpc.Code, grpcMessage: string) { + this.preMessagesError = [grpcStatus, grpcMessage]; + return this; + } + + withMessages(messages: Array) { + this.messages = messages; + return this; + } + + withPreTrailersError(grpcStatus: grpc.Code, grpcMessage: string) { + this.preTrailersError = [grpcStatus, grpcMessage]; + return this; + } + + withTrailers(trailers: grpc.Metadata) { + this.trailers = trailers; + return this; + } + + withManualTrigger() { + this.autoTrigger = false; + return this; + } + + build(): TriggerableTransport { + const mock = this; + + const triggers = { + options: (null: (grpc.TransportOptions | null)), + sendHeaders: () => { + if (!triggers.options) { + throw new Error("sendHeaders called before transport had been invoked"); + } + if (mock.preHeadersErrorCode !== null) { + triggers.options.onHeaders(new grpc.Metadata(), mock.preHeadersErrorCode); + triggers.options.onEnd(); + return false; + } + const headers = mock.headers || new grpc.Metadata(); + triggers.options.onHeaders(headers, 200); + return true; + }, + sendMessages: () => { + if (!triggers.options) { + throw new Error("sendMessages called before transport had been invoked"); + } + if (mock.preMessagesError !== null) { + triggers.options.onHeaders(new grpc.Metadata({ "grpc-status": String(mock.preMessagesError[0]), "grpc-message": mock.preMessagesError[1] }), 200); + triggers.options.onEnd(); + return false; + } + + mock.messages.forEach(message => { + triggers.options.onChunk(frameResponse(message)); + }); + return true; + }, + sendTrailers: () => { + if (!triggers.options) { + throw new Error("sendTrailers called before transport had been invoked"); + } + if (mock.preTrailersError !== null) { + triggers.options.onChunk(frameTrailers(new grpc.Metadata({ "grpc-status": String(mock.preTrailersError[0]), "grpc-message": mock.preTrailersError[1] }))); + triggers.options.onEnd(); + return false; + } + + const trailers = mock.trailers ? mock.trailers : new grpc.Metadata(); + + // Explicit status OK + trailers.set("grpc-status", "0"); + triggers.options.onChunk(frameTrailers(trailers)); + triggers.options.onEnd(); + return true; + }, + sendAll: () => { + if (!triggers.options) { + throw new Error("sendAll called before transport had been invoked"); + } + if (triggers.sendHeaders()) { + if (triggers.sendMessages()) { + triggers.sendTrailers(); + } + } + }, + }; + + const transportConstructor = (optionsArg: grpc.TransportOptions) => { + triggers.options = optionsArg; + + if (mock.requestListener) { + mock.requestListener(optionsArg); + } + + return { + start: (metadata: grpc.Metadata) => { + if (mock.headersListener) { + mock.headersListener(metadata); + } + if (mock.autoTrigger) { + triggers.sendAll(); + } + }, + sendMessage: (msgBytes: ArrayBufferView) => { + if (mock.messageListener) { + mock.messageListener(msgBytes); + } + }, + finishSend: () => { + if (mock.finishSendListener) { + mock.finishSendListener(); + } + }, + cancel: () => { + if (mock.cancelListener) { + mock.cancelListener(); + } + }, + }; + }; + + return (_.extend(transportConstructor, triggers): any); // tslint:disable-line + } +} + +export interface TriggerableTransport extends grpc.TransportFactory { + sendHeaders(): boolean; + sendMessages(): boolean; + sendTrailers(): boolean; + sendAll(): void; +} diff --git a/test/flow/integration/service/grpcweb.js b/test/flow/integration/service/grpcweb.js new file mode 100644 index 00000000..08a67c27 --- /dev/null +++ b/test/flow/integration/service/grpcweb.js @@ -0,0 +1,609 @@ +// @flow + +import { resolve } from "path"; +import { readFileSync, existsSync } from "fs"; +import { assert } from "chai"; +import { grpc } from "grpc-web-client"; +import { createContext, runInContext } from "vm"; + +import { frameRequest, StubTransportBuilder } from "../../helpers/fakeGrpcTransport"; +import { ExternalChildMessage } from "../../../../examples/flow/generated/proto/othercom/external_child_message_pb"; +import { SimpleService, SimpleServiceClient } from "../../../../examples/flow/generated/proto/examplecom/simple_service_pb_service"; +import { StreamRequest, UnaryRequest } from "../../../../examples/flow/generated/proto/examplecom/simple_service_pb"; +import { Empty } from "google-protobuf/google/protobuf/empty_pb"; + +describe("service/grpc-web", () => { + describe("generated service definitions", () => { + + it("should be exported", () => { + assert.strictEqual(SimpleService.serviceName, "examplecom.SimpleService"); + }); + + it("should contain the expected DoUnary method", () => { + assert.strictEqual(SimpleService.DoUnary.methodName, "DoUnary"); + assert.strictEqual(SimpleService.DoUnary.service, SimpleService); + assert.strictEqual(SimpleService.DoUnary.requestStream, false); + assert.strictEqual(SimpleService.DoUnary.responseStream, false); + assert.strictEqual(SimpleService.DoUnary.requestType, UnaryRequest); + assert.strictEqual(SimpleService.DoUnary.responseType, ExternalChildMessage); + }); + + it("should contain the expected DoServerStream method", () => { + assert.strictEqual(SimpleService.DoServerStream.methodName, "DoServerStream"); + assert.strictEqual(SimpleService.DoServerStream.service, SimpleService); + assert.strictEqual(SimpleService.DoServerStream.requestStream, false); + assert.strictEqual(SimpleService.DoServerStream.responseStream, true); + assert.strictEqual(SimpleService.DoServerStream.requestType, StreamRequest); + assert.strictEqual(SimpleService.DoServerStream.responseType, ExternalChildMessage); + }); + + it("should contain the expected DoClientStream method", () => { + assert.strictEqual(SimpleService.DoClientStream.methodName, "DoClientStream"); + assert.strictEqual(SimpleService.DoClientStream.service, SimpleService); + assert.strictEqual(SimpleService.DoClientStream.requestStream, true); + assert.strictEqual(SimpleService.DoClientStream.responseStream, false); + assert.strictEqual(SimpleService.DoClientStream.requestType, StreamRequest); + assert.strictEqual(SimpleService.DoClientStream.responseType, Empty); + }); + + it("should contain the expected DoClientStream method", () => { + assert.strictEqual(SimpleService.DoBidiStream.methodName, "DoBidiStream"); + assert.strictEqual(SimpleService.DoBidiStream.service, SimpleService); + assert.strictEqual(SimpleService.DoBidiStream.requestStream, true); + assert.strictEqual(SimpleService.DoBidiStream.responseStream, true); + assert.strictEqual(SimpleService.DoBidiStream.requestType, StreamRequest); + assert.strictEqual(SimpleService.DoBidiStream.responseType, ExternalChildMessage); + }); + }); + + it("should not output imports for namespaces that are not used in the service definition", () => { + const generatedService = readFileSync(resolve(__dirname, "../../../../examples/flow/generated/proto/examplecom/simple_service_pb_service.js.flow"), "utf8"); + assert.notInclude(generatedService, "google-protobuf/google/protobuf/timestamp_pb"); + + const generatedProto = readFileSync(resolve(__dirname, "../../../../examples/flow/generated/proto/examplecom/simple_service_pb.js"), "utf8"); + assert.include(generatedProto, "google-protobuf/google/protobuf/timestamp_pb"); + }); + + it("should generate service definition files for protos that have no service definitions", () => { + assert.isTrue(existsSync(resolve(__dirname, "../../../../examples/flow/generated/proto/examplecom/empty_message_no_service_pb_service.js.flow"))); + assert.isTrue(existsSync(resolve(__dirname, "../../../../examples/flow/generated/proto/examplecom/empty_message_no_service_pb_service.js"))); + }); + + it("should generate valid javascript sources", () => { + const generatedService = readFileSync(resolve(__dirname, "../../../../examples/flow/generated/proto/examplecom/simple_service_pb_service.js"), "utf8"); + + // Create a sandbox into which the javascript module will be exported. + const sandbox = { exports: { SimpleService: SimpleService } }; + createContext(sandbox); + + // Create a wrapper around the module's source code which injects a stubbed require function + // which will return stub modules. + const wrapper = `((require) => { ${generatedService} });`; + const fakeRequire = (name: string) => { + if (name.indexOf("/simple_service_pb") !== -1) { + return { + UnaryRequest: UnaryRequest, + StreamRequest: StreamRequest, + }; + } + else if (name.indexOf("/external_child_message_pb") !== -1) { + return { + ExternalChildMessage: ExternalChildMessage, + }; + } + return {}; + }; + + runInContext(wrapper, sandbox)(fakeRequire); + + assert.strictEqual(typeof sandbox.exports.SimpleService, "function"); + assert.strictEqual(sandbox.exports.SimpleService.serviceName, "examplecom.SimpleService"); + + assert.strictEqual(typeof sandbox.exports.SimpleService.DoUnary, "object"); + assert.strictEqual(sandbox.exports.SimpleService.DoUnary.methodName, "DoUnary"); + assert.strictEqual(sandbox.exports.SimpleService.DoUnary.service, sandbox.exports.SimpleService); + assert.strictEqual(sandbox.exports.SimpleService.DoUnary.requestStream, false); + assert.strictEqual(sandbox.exports.SimpleService.DoUnary.responseStream, false); + assert.strictEqual(sandbox.exports.SimpleService.DoUnary.requestType, UnaryRequest); + assert.strictEqual(sandbox.exports.SimpleService.DoUnary.responseType, ExternalChildMessage); + + assert.strictEqual(typeof sandbox.exports.SimpleService.DoServerStream, "object"); + assert.strictEqual(sandbox.exports.SimpleService.DoServerStream.methodName, "DoServerStream"); + assert.strictEqual(sandbox.exports.SimpleService.DoServerStream.service, sandbox.exports.SimpleService); + assert.strictEqual(sandbox.exports.SimpleService.DoServerStream.requestStream, false); + assert.strictEqual(sandbox.exports.SimpleService.DoServerStream.responseStream, true); + assert.strictEqual(sandbox.exports.SimpleService.DoServerStream.requestType, StreamRequest); + assert.strictEqual(sandbox.exports.SimpleService.DoServerStream.responseType, ExternalChildMessage); + + }); + + describe("grpc-web service stubs", () => { + function makeClient(transportBuilder: StubTransportBuilder): SimpleServiceClient { + return new SimpleServiceClient("http://localhost:1", { + transport: transportBuilder.build(), + }); + } + + function makePayloads(...values: string[]): ExternalChildMessage[] { + return values.map(value => { + const payload = new ExternalChildMessage(); + payload.setMyString(value); + return payload; + }); + } + + it("should generate a service stub", () => { + assert.typeOf(SimpleServiceClient, "function", "SimpleServiceClient class shoudl exist"); + + const client = new SimpleServiceClient("http://localhost:1"); + + assert.equal(client.serviceHost, "http://localhost:1", "Service host should be stored from constructor"); + assert.typeOf(client.doUnary, "function", "Service should have doUnary method"); + assert.typeOf(client.doServerStream, "function", "Service should have doServerStream method"); + }); + + describe("unary", () => { + it("should route the request to the expected endpoint", (done) => { + let targetUrl = ""; + + makeClient( + new StubTransportBuilder().withRequestListener(options => targetUrl = options.url) + ) + .doUnary( + new UnaryRequest(), + () => { + assert.equal(targetUrl, "http://localhost:1/examplecom.SimpleService/DoUnary"); + done(); + }); + }); + + it("should handle errors returned by the unary endpoint", (done) => { + makeClient( + new StubTransportBuilder().withPreTrailersError(grpc.Code.Internal, "some internal error") + ) + .doUnary( + new UnaryRequest(), + (error, response) => { + assert.ok(error !== null && typeof error === "object", "should yield an error"); + assert.ok(response === null, "should yield null instead of a response"); + + assert.equal(error.message, "some internal error", "should expose the grpc error message (.message)"); + assert.equal(error.code, 13, "should expose the grpc status code (.code)"); + assert.ok(error.metadata instanceof grpc.Metadata, "should expose the trailing response metadata (.metadata)"); + done(); + }); + }); + + it("should expose data returned by the unary endpoint", (done) => { + const [payload] = makePayloads("some value"); + + makeClient(new StubTransportBuilder().withMessages([payload])) + .doUnary( + new UnaryRequest(), + (error, response) => { + assert.ok(error === null, "should not yield an error"); + assert.ok(response !== null, "should yield a response"); + assert.equal(response.getMyString(), "some value", "should return the expected payload"); + done(); + }); + }); + + it("should send the supplied payload to the server", (done) => { + let sentMessageBytes: ArrayBufferView = new Uint8Array(0); + + const payload = new UnaryRequest(); + payload.setSomeInt64(42); + + makeClient(new StubTransportBuilder().withMessageListener(v => sentMessageBytes = v)) + .doUnary( + payload, + (err) => { + assert.ok(err === null, "should not yield an error"); + assert.deepEqual(sentMessageBytes, frameRequest(payload), "expected request message supplied to transport"); + done(); + } + ); + }); + + it("should allow the caller to supply Metadata", (done) => { + let sentHeaders: grpc.Metadata; + + makeClient(new StubTransportBuilder().withHeadersListener(headers => sentHeaders = headers)) + .doUnary( + new UnaryRequest(), + new grpc.Metadata({ "foo": "bar" }), + () => { + assert.ok(sentHeaders !== null, "must have intercepted request headers"); + assert.deepEqual(sentHeaders.get("foo"), ["bar"], "expected headers to have been sent"); + done(); + }); + }); + }); + + describe("server streaming", () => { + it("should route the request to the expected endpoint", (done) => { + let targetUrl = ""; + + makeClient(new StubTransportBuilder().withRequestListener(options => targetUrl = options.url)) + .doServerStream(new StreamRequest()) + .on("end", () => { + assert.equal(targetUrl, "http://localhost:1/examplecom.SimpleService/DoServerStream"); + done(); + }); + }); + + it("should invoke onEnd before onStatus", (done) => { + const [payload] = makePayloads("some value"); + let onEndInvoked = false; + + makeClient(new StubTransportBuilder().withMessages([payload])) + .doServerStream(new StreamRequest()) + .on("end", () => { onEndInvoked = true; }) + .on("status", () => { + assert.ok(onEndInvoked, "onEnd callback should be invoked before onStatus"); + done(); + }); + }); + + it("should handle an error returned ahead of any data by the endpoint", (done) => { + makeClient(new StubTransportBuilder().withPreMessagesError(grpc.Code.Internal, "some error")) + .doServerStream(new StreamRequest()) + .on("status", (status) => { + assert.equal(status.code, grpc.Code.Internal, "expected grpc status code returned"); + assert.equal(status.details, "some error", "expected grpc error details returned"); + done(); + }); + }); + + it("should handle an error returned mid-stream by the endpoint", (done) => { + const [payload] = makePayloads("some value"); + let actualData: ExternalChildMessage[] = []; + + makeClient(new StubTransportBuilder() + .withMessages([payload]) + .withPreTrailersError(grpc.Code.Internal, "some error") + ) + .doServerStream(new StreamRequest()) + .on("data", payload => actualData.push(payload)) + .on("status", status => { + assert.equal(status.code, grpc.Code.Internal, "expected grpc status code returned"); + assert.equal(status.details, "some error", "expected grpc error details returned"); + assert.equal(actualData.length, 1, "data sent before error is returned"); + assert.equal(actualData[0].getMyString(), "some value", "payload is well formed"); + done(); + }); + }); + + it("should expose the data return by the streaming endpoint", (done) => { + const [payload1, payload2] = makePayloads("some value", "another value"); + let actualData: ExternalChildMessage[] = []; + + makeClient(new StubTransportBuilder().withMessages([payload1, payload2])) + .doServerStream(new StreamRequest()) + .on("data", payload => actualData.push(payload)) + .on("status", status => { + assert.equal(status.code, grpc.Code.OK, "status code is ok"); + assert.equal(actualData.length, 2, "expected data is received"); + assert.equal(actualData[0].getMyString(), "some value", "data is received in order (#1)"); + assert.equal(actualData[1].getMyString(), "another value", "data is received in order (#2)"); + done(); + }); + }); + + it("should allow the caller to supply Metadata", (done) => { + let sentHeaders: grpc.Metadata; + + makeClient(new StubTransportBuilder().withHeadersListener(headers => sentHeaders = headers)) + .doServerStream(new StreamRequest(), new grpc.Metadata({ "foo": "bar" })) + .on("end", () => { + assert.deepEqual(sentHeaders.get("foo"), ["bar"]); + done(); + }); + }); + + it("should allow the caller to cancel the request", (done) => { + let cancelInvoked = false; + + const transport = new StubTransportBuilder() + .withMessages(makePayloads("foo", "bar")) + .withCancelListener(() => cancelInvoked = true) + .withManualTrigger() + .build(); + + const client = new SimpleServiceClient("http://localhost:1", { transport }); + let messageCount = 0; + let onEndFired = false; + let onStatusFired = false; + + const handle = client.doServerStream(new StreamRequest()) + .on("data", () => messageCount++) + .on("end", () => onEndFired = true) + .on("status", () => onStatusFired = true); + + transport.sendHeaders(); + handle.cancel(); + transport.sendMessages(); + transport.sendTrailers(); + + setTimeout(() => { + assert.equal(cancelInvoked, true, "the Transport should have been cancelled by the client"); + assert.equal(messageCount, 0, "invocation cancelled before any messages were sent"); + assert.equal(onEndFired, false, "'end' should not have fired when the invocation is cancelled"); + assert.equal(onStatusFired, false, "'status' should not have fired when the invocation is cancelled"); + done(); + }, 20); + }); + }); + + describe("client streaming", () => { + const payload = new StreamRequest(); + payload.setSomeString("some value"); + + it("should route the request to the expected endpoint", (done) => { + let targetUrl = ""; + + makeClient(new StubTransportBuilder().withRequestListener(options => targetUrl = options.url)) + .doClientStream() + .on("end", () => { + assert.equal(targetUrl, "http://localhost:1/examplecom.SimpleService/DoClientStream"); + done(); + }) + .write(payload) + .end(); + }); + + it("should close the connection when end() is invoked", (done) => { + let finishSendInvoked = false; + makeClient(new StubTransportBuilder().withFinishSendListener(() => finishSendInvoked = true)) + .doClientStream() + .on("end", () => { + assert.ok(finishSendInvoked); + done(); + }) + .write(payload) + .end(); + }); + + it("should invoke onEnd before onStatus", (done) => { + let onEndInvoked = false; + + makeClient(new StubTransportBuilder()) + .doClientStream() + .on("end", () => { onEndInvoked = true; }) + .on("status", () => { + assert.ok(onEndInvoked, "onEnd callback should be invoked before onStatus"); + done(); + }) + .write(payload) + .end(); + }); + + it("should handle an error returned ahead of any data by the server", (done) => { + makeClient(new StubTransportBuilder().withPreMessagesError(grpc.Code.Internal, "some error")) + .doClientStream() + .on("status", (status) => { + assert.equal(status.code, grpc.Code.Internal, "expected grpc status code returned"); + assert.equal(status.details, "some error", "expected grpc error details returned"); + done(); + }) + .write(payload) + .end(); + }); + + it("should allow the caller to supply multiple messages", (done) => { + const reqMsgOne = new StreamRequest(); + reqMsgOne.setSomeString("one"); + const reqMsgTwo = new StreamRequest(); + reqMsgTwo.setSomeString("two"); + const sentMessageBytes: ArrayBufferView[] = []; + + makeClient(new StubTransportBuilder().withMessageListener(v => { sentMessageBytes.push(v); })) + .doClientStream() + .on("end", () => { + assert.equal(sentMessageBytes.length, 2, "Two messages are sent"); + assert.deepEqual(sentMessageBytes[0], frameRequest(reqMsgOne)); + assert.deepEqual(sentMessageBytes[1], frameRequest(reqMsgTwo)); + done(); + }) + .write(reqMsgOne) + .write(reqMsgTwo) + .end(); + }); + + it("should allow the caller to supply Metadata", (done) => { + let sentHeaders: grpc.Metadata; + + makeClient(new StubTransportBuilder().withHeadersListener(headers => sentHeaders = headers)) + .doClientStream(new grpc.Metadata({ "foo": "bar" })) + .on("end", () => { + assert.deepEqual(sentHeaders.get("foo"), ["bar"]); + done(); + }) + .write(payload) + .end(); + }); + + it("should allow the caller to cancel the request", (done) => { + let cancelInvoked = true; + + const transport = new StubTransportBuilder() + .withCancelListener(() => cancelInvoked = true) + .withManualTrigger() + .build(); + + const client = new SimpleServiceClient("http://localhost:1", { transport }); + let onEndFired = false; + let onStatusFired = false; + + const handle = client.doClientStream() + .on("end", () => onEndFired = true) + .on("status", () => onStatusFired = true) + .write(payload); + + transport.sendHeaders(); + handle.cancel(); + transport.sendTrailers(); + + setTimeout(() => { + assert.equal(cancelInvoked, true, "the Transport should have been cancelled by the client"); + assert.equal(onEndFired, false, "'end' should not have fired when the invocation is cancelled"); + assert.equal(onStatusFired, false, "'status' should not have fired when the invocation is cancelled"); + done(); + }, 20); + }); + }); + + describe("bidirectional streaming", () => { + const payload = new StreamRequest(); + payload.setSomeString("some value"); + + it("should route the request to the expected endpoint", (done) => { + let targetUrl = ""; + + makeClient(new StubTransportBuilder().withRequestListener(options => targetUrl = options.url)) + .doBidiStream() + .on("end", () => { + assert.equal(targetUrl, "http://localhost:1/examplecom.SimpleService/DoBidiStream"); + done(); + }) + .end(); + }); + + it("should invoke onEnd before onStatus if the client ends the stream", (done) => { + let onEndInvoked = false; + + makeClient(new StubTransportBuilder()) + .doBidiStream() + .on("end", () => { onEndInvoked = true; }) + .on("status", () => { + assert.ok(onEndInvoked, "onEnd callback should be invoked before onStatus"); + done(); + }) + .write(payload) + .end(); + }); + + it("should close the connection when end() is invoked", (done) => { + let finishSendInvoked = false; + makeClient(new StubTransportBuilder().withFinishSendListener(() => finishSendInvoked = true)) + .doBidiStream() + .on("end", () => { + assert.ok(finishSendInvoked); + done(); + }) + .write(payload) + .end(); + }); + + it("should invoke onEnd before onStatus if the server ends the stream", (done) => { + let onEndInvoked = false; + + makeClient(new StubTransportBuilder().withMessages([ payload ])) + .doBidiStream() + .on("end", () => { onEndInvoked = true; }) + .on("status", () => { + assert.ok(onEndInvoked, "onEnd callback should be invoked before onStatus"); + done(); + }); + }); + + it("should handle an error returned ahead of any data by the server", (done) => { + makeClient(new StubTransportBuilder().withPreMessagesError(grpc.Code.Internal, "some error")) + .doBidiStream() + .on("status", (status) => { + assert.equal(status.code, grpc.Code.Internal, "expected grpc status code returned"); + assert.equal(status.details, "some error", "expected grpc error details returned"); + done(); + }) + .write(payload); + }); + + it("should handle an error returned mid-stream by the server", (done) => { + let actualData: ExternalChildMessage[] = []; + + makeClient(new StubTransportBuilder() + .withMessages([payload]) + .withPreTrailersError(grpc.Code.Internal, "some error") + ) + .doBidiStream() + .on("data", payload => actualData.push(payload)) + .on("status", status => { + assert.equal(status.code, grpc.Code.Internal, "expected grpc status code returned"); + assert.equal(status.details, "some error", "expected grpc error details returned"); + assert.equal(actualData.length, 1, "messages sent by the server, ahead of any error are exposed"); + assert.equal(actualData[0].getMyString(), "some value", "payload is well formed"); + done(); + }); + }); + + it("should allow the caller to supply multiple messages", (done) => { + const reqMsgOne = new StreamRequest(); + reqMsgOne.setSomeString("one"); + const reqMsgTwo = new StreamRequest(); + reqMsgTwo.setSomeString("two"); + const sentMessageBytes: ArrayBufferView[] = []; + + makeClient(new StubTransportBuilder().withMessageListener(v => { sentMessageBytes.push(v); })) + .doBidiStream() + .on("end", () => { + assert.equal(sentMessageBytes.length, 2, "Two messages are sent"); + assert.deepEqual(sentMessageBytes[0], frameRequest(reqMsgOne)); + assert.deepEqual(sentMessageBytes[1], frameRequest(reqMsgTwo)); + done(); + }) + .write(reqMsgOne) + .write(reqMsgTwo) + .end(); + }); + + it("should allow the caller to supply Metadata", (done) => { + let sentHeaders: grpc.Metadata; + + makeClient(new StubTransportBuilder().withHeadersListener(headers => sentHeaders = headers)) + .doBidiStream(new grpc.Metadata({ "foo": "bar" })) + .on("end", () => { + assert.deepEqual(sentHeaders.get("foo"), ["bar"]); + done(); + }) + .write(payload) + .end(); + }); + + it("should allow the caller to cancel the request", (done) => { + let cancelInvoked = false; + + const transport = new StubTransportBuilder() + .withManualTrigger() + .withCancelListener(() => cancelInvoked = true) + .build(); + + const client = new SimpleServiceClient("http://localhost:1", { transport }); + let onEndFired = false; + let onStatusFired = false; + + const handle = client.doBidiStream() + .on("end", () => onEndFired = true) + .on("status", () => onStatusFired = true) + .write(payload); + + transport.sendHeaders(); + handle.cancel(); + transport.sendTrailers(); + + setTimeout(() => { + assert.equal(cancelInvoked, true, "the Transport should have been cancelled by the client"); + assert.equal(onEndFired, false, "'end' should not have fired when the invocation is cancelled"); + assert.equal(onStatusFired, false, "'status' should not have fired when the invocation is cancelled"); + done(); + }, 20); + }); + }); + + describe("methods named using reserved words", () => { + it("should route the request to the expected endpoint", () => { + const client = new SimpleServiceClient("http://localhost:1"); + assert.equal(client.delete.name, "pb_delete", "an rpc method named using a reserved word should be prefixed with pb_"); + }); + }); + }); +});