react-native
Version:
A framework for building native apps using React
324 lines (252 loc) • 7.96 kB
JavaScript
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import {Writable} from 'stream';
import {GeneratedHeader} from './GeneratedHeader';
import {Property} from './Property';
import {PropsType, Type} from './Type';
import {Command} from './Command';
import {Event} from './Event';
import {toCppNamespace} from './Converters';
export class HeaderWriter {
stream: Writable;
types: Array<Type>;
commands: Array<Command>;
events: Array<Event>;
constructor(
stream: Writable,
types: Array<Type>,
commands: Array<Command>,
events: Array<Event>,
) {
this.stream = stream;
this.types = types;
this.commands = commands;
this.events = events;
}
write() {
this.writePrologue();
this.writeForwardDecls();
this.writeRequestHandlerDecls();
this.writeTypeDecls();
this.writeRequestDecls();
this.writeResponseDecls();
this.writeNotificationDecls();
this.writeEpilogue();
}
writePrologue() {
this.stream.write(`${GeneratedHeader}
#pragma once
#include <hermes/inspector/chrome/MessageInterfaces.h>
#include <vector>
#include <folly/Optional.h>
namespace facebook {
namespace hermes {
namespace inspector {
namespace chrome {
namespace message {
`);
}
writeForwardDecls() {
this.stream.write('struct UnknownRequest;\n\n');
const namespaceMap: Map<string, Array<Type | Command | Event>> = new Map();
const addToMap = function (type) {
const domain = type.domain;
let types = namespaceMap.get(domain);
if (!types) {
types = [];
namespaceMap.set(domain, types);
}
types.push(type);
};
this.types.forEach(addToMap);
this.commands.forEach(addToMap);
this.events.forEach(addToMap);
for (const [domain, types] of namespaceMap) {
types.sort((a, b) => {
const nameA = a.getForwardDeclSortKey();
const nameB = b.getForwardDeclSortKey();
return nameA < nameB ? -1 : nameA > nameB ? 1 : 0;
});
const ns = toCppNamespace(domain);
this.stream.write(`namespace ${ns} {\n`);
for (const type of types) {
for (const decl of type.getForwardDecls()) {
this.stream.write(`${decl}\n`);
}
}
this.stream.write(`} // namespace ${ns}\n\n`);
}
}
writeRequestHandlerDecls() {
this.stream.write(
'\n/// RequestHandler handles requests via the visitor pattern.\n',
);
emitRequestHandlerDecl(this.stream, this.commands);
this.stream.write(
'\n/// NoopRequestHandler can be subclassed to only handle some requests.\n',
);
emitNoopRequestHandlerDecl(this.stream, this.commands);
}
writeTypeDecls() {
this.stream.write('\n/// Types\n');
for (const type of this.types) {
if (type instanceof PropsType) {
emitTypeDecl(this.stream, type);
}
}
}
writeRequestDecls() {
this.stream.write('\n/// Requests\n');
emitUnknownRequestDecl(this.stream);
for (const command of this.commands) {
emitRequestDecl(this.stream, command);
}
}
writeResponseDecls() {
this.stream.write('\n/// Responses\n');
emitErrorResponseDecl(this.stream);
emitOkResponseDecl(this.stream);
for (const command of this.commands) {
emitResponseDecl(this.stream, command);
}
}
writeNotificationDecls() {
this.stream.write('\n/// Notifications\n');
for (const event of this.events) {
emitNotificationDecl(this.stream, event);
}
}
writeEpilogue() {
this.stream.write(`
} // namespace message
} // namespace chrome
} // namespace inspector
} // namespace hermes
} // namespace facebook
`);
}
}
function emitRequestHandlerDecl(stream: Writable, commands: Array<Command>) {
stream.write(`struct RequestHandler {
virtual ~RequestHandler() = default;
virtual void handle(const UnknownRequest &req) = 0;
`);
for (const command of commands) {
const cppNs = command.getCppNamespace();
const cppType = command.getRequestCppType();
stream.write(`virtual void handle(const ${cppNs}::${cppType} &req) = 0;`);
}
stream.write('};\n');
}
function emitNoopRequestHandlerDecl(
stream: Writable,
commands: Array<Command>,
) {
stream.write(`struct NoopRequestHandler : public RequestHandler {
void handle(const UnknownRequest &req) override {}
`);
for (const command of commands) {
const cppNs = command.getCppNamespace();
const cppType = command.getRequestCppType();
stream.write(`void handle(const ${cppNs}::${cppType} &req) override {}`);
}
stream.write('};\n');
}
function emitProps(stream: Writable, props: ?Array<Property>) {
if (!props || props.length === 0) {
return;
}
stream.write('\n');
for (const prop of props) {
const fullCppType = prop.getFullCppType();
const cppId = prop.getCppIdentifier();
const init = prop.getInitializer();
stream.write(` ${fullCppType} ${cppId}${init};\n`);
}
}
export function emitTypeDecl(stream: Writable, type: PropsType) {
const cppNs = type.getCppNamespace();
const cppType = type.getCppType();
stream.write(`struct ${cppNs}::${cppType} : public Serializable {
${cppType}() = default;
explicit ${cppType}(const folly::dynamic &obj);
folly::dynamic toDynamic() const override;
`);
if (type instanceof PropsType) {
emitProps(stream, type.properties);
}
stream.write('};\n\n');
}
function emitUnknownRequestDecl(stream: Writable) {
stream.write(`struct UnknownRequest : public Request {
UnknownRequest();
explicit UnknownRequest(const folly::dynamic &obj);
folly::dynamic toDynamic() const override;
void accept(RequestHandler &handler) const override;
folly::Optional<folly::dynamic> params;
};
`);
}
export function emitRequestDecl(stream: Writable, command: Command) {
const cppNs = command.getCppNamespace();
const cppType = command.getRequestCppType();
stream.write(`struct ${cppNs}::${cppType} : public Request {
${cppType}();
explicit ${cppType}(const folly::dynamic &obj);
folly::dynamic toDynamic() const override;
void accept(RequestHandler &handler) const override;
`);
emitProps(stream, command.parameters);
stream.write('};\n\n');
}
function emitErrorResponseDecl(stream: Writable) {
stream.write(`struct ErrorResponse : public Response {
ErrorResponse() = default;
explicit ErrorResponse(const folly::dynamic &obj);
folly::dynamic toDynamic() const override;
int code;
std::string message;
folly::Optional<folly::dynamic> data;
};
`);
}
function emitOkResponseDecl(stream: Writable) {
stream.write(`struct OkResponse : public Response {
OkResponse() = default;
explicit OkResponse(const folly::dynamic &obj);
folly::dynamic toDynamic() const override;
};
`);
}
export function emitResponseDecl(stream: Writable, command: Command) {
const cppNs = command.getCppNamespace();
const cppType = command.getResponseCppType();
if (!cppType) {
return;
}
stream.write(`struct ${cppNs}::${cppType} : public Response {
${cppType}() = default;
explicit ${cppType}(const folly::dynamic &obj);
folly::dynamic toDynamic() const override;
`);
emitProps(stream, command.returns);
stream.write('};\n\n');
}
export function emitNotificationDecl(stream: Writable, event: Event) {
const cppNs = event.getCppNamespace();
const cppType = event.getCppType();
stream.write(`struct ${cppNs}::${cppType} : public Notification {
${cppType}();
explicit ${cppType}(const folly::dynamic &obj);
folly::dynamic toDynamic() const override;
`);
emitProps(stream, event.parameters);
stream.write('};\n\n');
}