From 3e0fc8899bda07e416fc9f28a92808fe6b2ecd39 Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Fri, 3 Jan 2025 04:29:09 -0800 Subject: [PATCH] Remove hermes-inspector-msggen (#48465) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/48465 Removes the `packages/hermes-inspector-msggen` workspace. Since https://github.com/facebook/react-native/pull/39300, this is no longer referenced in React Native, and is now part of the Hermes repo. Changelog: [Internal] Reviewed By: cortinico, hoxyq Differential Revision: D67791612 fbshipit-source-id: 73da135b264d8df632fefe87cc4e3101075ae98c --- packages/hermes-inspector-msggen/.babelrc | 8 - packages/hermes-inspector-msggen/.gitignore | 3 - packages/hermes-inspector-msggen/README.md | 21 - .../__tests__/command-test.js | 62 --- .../__tests__/event-test.js | 47 -- .../__tests__/graph-test.js | 80 ---- .../__tests__/header-writer-test.js | 132 ------ .../__tests__/implementation-writer-test.js | 171 ------- .../__tests__/property-test.js | 131 ------ .../__tests__/type-test.js | 50 --- packages/hermes-inspector-msggen/package.json | 40 -- .../hermes-inspector-msggen/src/Command.js | 91 ---- .../hermes-inspector-msggen/src/Converters.js | 39 -- packages/hermes-inspector-msggen/src/Event.js | 71 --- .../src/GeneratedHeader.js | 16 - packages/hermes-inspector-msggen/src/Graph.js | 98 ---- .../src/HeaderWriter.js | 327 -------------- .../src/ImplementationWriter.js | 420 ------------------ .../hermes-inspector-msggen/src/Property.js | 244 ---------- .../src/TestHelpers.js | 40 -- packages/hermes-inspector-msggen/src/Type.js | 117 ----- .../hermes-inspector-msggen/src/custom.json | 26 -- packages/hermes-inspector-msggen/src/index.js | 283 ------------ yarn.lock | 91 +--- 24 files changed, 8 insertions(+), 2600 deletions(-) delete mode 100644 packages/hermes-inspector-msggen/.babelrc delete mode 100644 packages/hermes-inspector-msggen/.gitignore delete mode 100644 packages/hermes-inspector-msggen/README.md delete mode 100644 packages/hermes-inspector-msggen/__tests__/command-test.js delete mode 100644 packages/hermes-inspector-msggen/__tests__/event-test.js delete mode 100644 packages/hermes-inspector-msggen/__tests__/graph-test.js delete mode 100644 packages/hermes-inspector-msggen/__tests__/header-writer-test.js delete mode 100644 packages/hermes-inspector-msggen/__tests__/implementation-writer-test.js delete mode 100644 packages/hermes-inspector-msggen/__tests__/property-test.js delete mode 100644 packages/hermes-inspector-msggen/__tests__/type-test.js delete mode 100644 packages/hermes-inspector-msggen/package.json delete mode 100644 packages/hermes-inspector-msggen/src/Command.js delete mode 100644 packages/hermes-inspector-msggen/src/Converters.js delete mode 100644 packages/hermes-inspector-msggen/src/Event.js delete mode 100644 packages/hermes-inspector-msggen/src/GeneratedHeader.js delete mode 100644 packages/hermes-inspector-msggen/src/Graph.js delete mode 100644 packages/hermes-inspector-msggen/src/HeaderWriter.js delete mode 100644 packages/hermes-inspector-msggen/src/ImplementationWriter.js delete mode 100644 packages/hermes-inspector-msggen/src/Property.js delete mode 100644 packages/hermes-inspector-msggen/src/TestHelpers.js delete mode 100644 packages/hermes-inspector-msggen/src/Type.js delete mode 100644 packages/hermes-inspector-msggen/src/custom.json delete mode 100644 packages/hermes-inspector-msggen/src/index.js diff --git a/packages/hermes-inspector-msggen/.babelrc b/packages/hermes-inspector-msggen/.babelrc deleted file mode 100644 index 8ad6d5109ddf39..00000000000000 --- a/packages/hermes-inspector-msggen/.babelrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "presets": [ "@babel/preset-flow", ["@babel/preset-env", { - "targets": { - "node": "current" - } - }] - ], -} diff --git a/packages/hermes-inspector-msggen/.gitignore b/packages/hermes-inspector-msggen/.gitignore deleted file mode 100644 index 050ba480f8f873..00000000000000 --- a/packages/hermes-inspector-msggen/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.DS_Store -bin/ -node_modules/ diff --git a/packages/hermes-inspector-msggen/README.md b/packages/hermes-inspector-msggen/README.md deleted file mode 100644 index b2b98932e32dd4..00000000000000 --- a/packages/hermes-inspector-msggen/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# @react-native/hermes-inspector-msggen - -[![Version][version-badge]][package] - -## Installation - -``` -yarn add --dev @babel/cli @babel/core @babel/preset-env @babel/preset-flow jest @react-native/hermes-inspector-msggen -``` - -*Note: We're using `yarn` to install deps. Feel free to change commands to use `npm` 3+ and `npx` if you like* - -[version-badge]: https://img.shields.io/npm/v/@react-native/hermes-inspector-msggen?style=flat-square -[package]: https://www.npmjs.com/package/@react-native/hermes-inspector-msggen - -## Testing - -To run the tests in this package, run the following commands from the React Native root folder: - -1. `yarn` to install the dependencies. You just need to run this once -2. `yarn jest packages/hermes-inspector-msggen`. diff --git a/packages/hermes-inspector-msggen/__tests__/command-test.js b/packages/hermes-inspector-msggen/__tests__/command-test.js deleted file mode 100644 index b409e81cced78b..00000000000000 --- a/packages/hermes-inspector-msggen/__tests__/command-test.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * 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. - */ - -import {Command} from '../src/Command.js'; - -test('parses simple command', () => { - let obj = { - 'name': 'setBreakpointsActive', - 'parameters': [ - { 'name': 'active', 'type': 'boolean', 'description': 'New value for breakpoints active state.' }, - ], - 'description': 'Activates / deactivates all breakpoints on the page.', - }; - let command = Command.create('Debugger', obj, false); - - expect(command.domain).toBe('Debugger'); - expect(command.name).toBe('setBreakpointsActive'); - expect(command.description).toBe('Activates / deactivates all breakpoints on the page.'); - expect(command.parameters.map(p => p.name)).toEqual(['active']); - expect(command.returns.length).toBe(0); - - expect(command.getDebuggerName()).toBe('Debugger.setBreakpointsActive'); - expect(command.getCppNamespace()).toBe('debugger'); - expect(command.getRequestCppType()).toBe('SetBreakpointsActiveRequest'); - expect(command.getResponseCppType()).toBeUndefined(); - expect(command.getForwardDecls()).toEqual(['struct SetBreakpointsActiveRequest;']); -}); - -test('parses command with return', () => { - let obj = { - 'name': 'setBreakpoint', - 'parameters': [ - { 'name': 'location', '$ref': 'Location', 'description': 'Location to set breakpoint in.' }, - { 'name': 'condition', 'type': 'string', 'optional': true, 'description': 'Expression to use as a breakpoint condition. When specified, debugger will only stop on the breakpoint if this expression evaluates to true.' }, - ], - 'returns': [ - { 'name': 'breakpointId', '$ref': 'BreakpointId', 'description': 'Id of the created breakpoint for further reference.' }, - { 'name': 'actualLocation', '$ref': 'Location', 'description': 'Location this breakpoint resolved into.' }, - ], - 'description': 'Sets JavaScript breakpoint at a given location.', - }; - let command = Command.create('Debugger', obj, false); - - expect(command.domain).toBe('Debugger'); - expect(command.name).toBe('setBreakpoint'); - expect(command.description).toBe('Sets JavaScript breakpoint at a given location.'); - expect(command.parameters.map(p => p.name)).toEqual(['location', 'condition']); - expect(command.returns.map(p => p.name)).toEqual(['breakpointId', 'actualLocation']); - - expect(command.getDebuggerName()).toBe('Debugger.setBreakpoint'); - expect(command.getCppNamespace()).toBe('debugger'); - expect(command.getRequestCppType()).toBe('SetBreakpointRequest'); - expect(command.getResponseCppType()).toBe('SetBreakpointResponse'); - expect(command.getForwardDecls()).toEqual([ - 'struct SetBreakpointRequest;', - 'struct SetBreakpointResponse;', - ]); -}); diff --git a/packages/hermes-inspector-msggen/__tests__/event-test.js b/packages/hermes-inspector-msggen/__tests__/event-test.js deleted file mode 100644 index 8ebb1ecb6e918f..00000000000000 --- a/packages/hermes-inspector-msggen/__tests__/event-test.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * 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. - */ - -import {Event} from '../src/Event.js'; - -test('parses simple event', () => { - let obj = { - 'name': 'resumed', - 'description': 'Fired when the virtual machine resumed execution.', - }; - let event = Event.create('Debugger', obj, false); - - expect(event.domain).toBe('Debugger'); - expect(event.name).toBe('resumed'); - expect(event.description).toBe('Fired when the virtual machine resumed execution.'); - - expect(event.getDebuggerName()).toBe('Debugger.resumed'); - expect(event.getCppNamespace()).toBe('debugger'); - expect(event.getCppType()).toBe('ResumedNotification'); - expect(event.getForwardDecls()).toEqual(['struct ResumedNotification;']); -}); - -test('parses event with params', () => { - let obj = { - 'name': 'breakpointResolved', - 'parameters': [ - { 'name': 'breakpointId', '$ref': 'BreakpointId', 'description': 'Breakpoint unique identifier.' }, - { 'name': 'location', '$ref': 'Location', 'description': 'Actual breakpoint location.' }, - ], - 'description': 'Fired when breakpoint is resolved to an actual script and location.', - }; - let event = Event.create('Debugger', obj, false); - - expect(event.domain).toBe('Debugger'); - expect(event.name).toBe('breakpointResolved'); - expect(event.description).toBe('Fired when breakpoint is resolved to an actual script and location.'); - expect(event.parameters.map(p => p.name)).toEqual(['breakpointId', 'location']); - - expect(event.getDebuggerName()).toBe('Debugger.breakpointResolved'); - expect(event.getCppNamespace()).toBe('debugger'); - expect(event.getCppType()).toBe('BreakpointResolvedNotification'); - expect(event.getForwardDecls()).toEqual(['struct BreakpointResolvedNotification;']); -}); diff --git a/packages/hermes-inspector-msggen/__tests__/graph-test.js b/packages/hermes-inspector-msggen/__tests__/graph-test.js deleted file mode 100644 index 5d4043b80e0017..00000000000000 --- a/packages/hermes-inspector-msggen/__tests__/graph-test.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * 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. - */ - -import {Graph} from '../src/Graph.js'; - -// graph looks like this before test: https://pxl.cl/9k8t -let graph = null; - -beforeEach(() => { - graph = new Graph(); - graph.addEdge('A1', 'B1'); - graph.addEdge('A2', 'B1'); - graph.addEdge('A2', 'B2'); - graph.addEdge('A3', 'B2'); - graph.addEdge('A3', 'C3'); - graph.addEdge('B1', 'C1'); - graph.addEdge('B1', 'C2'); - graph.addEdge('B1', 'C3'); - graph.addEdge('B2', 'C2'); -}); - -// checks id1 occurs after id2 in arr -function expectOccursAfter(arr, id1, id2) { - const idx1 = arr.indexOf(id1); - const idx2 = arr.indexOf(id2); - - expect(idx1).not.toBe(-1); - expect(idx2).not.toBe(-1); - expect(idx1).toBeGreaterThan(idx2); -} - -test('detects cycle', () => { - graph.addEdge('C2', 'A1'); - - const {cycles} = graph.traverse(['A2']); - expect(cycles).toContainEqual({from: 'A1', to: 'B1'}); -}); - -test('checks for presence of root', () => { - expect(() => graph.traverse(['A1', 'NX'])).toThrow(/^No node/); -}); - -test('traverses partial graph', () => { - const {nodes: ids} = graph.traverse(['B1', 'A3']); - - // Check that expected nodes are there - const sortedIds = ids.slice().sort(); - expect(sortedIds).toEqual(['A3', 'B1', 'B2', 'C1', 'C2', 'C3']); - - // Check that the result is topologically sorted - expectOccursAfter(ids, 'A3', 'B2'); - expectOccursAfter(ids, 'A3', 'C3'); - expectOccursAfter(ids, 'B1', 'C1'); - expectOccursAfter(ids, 'B1', 'C2'); - expectOccursAfter(ids, 'B1', 'C3'); - expectOccursAfter(ids, 'B2', 'C2'); -}); - -test('traverses complete graph', () => { - const {nodes: ids} = graph.traverse(['A1', 'A2', 'A3']); - - // Check that expected nodes are there - const sortedIds = ids.slice().sort(); - expect(sortedIds).toEqual(['A1', 'A2', 'A3', 'B1', 'B2', 'C1', 'C2', 'C3']); - - // Check that the result is topologically sorted - expectOccursAfter(ids, 'A1', 'B1'); - expectOccursAfter(ids, 'A2', 'B1'); - expectOccursAfter(ids, 'A2', 'B2'); - expectOccursAfter(ids, 'A3', 'B2'); - expectOccursAfter(ids, 'A3', 'C3'); - expectOccursAfter(ids, 'B1', 'C1'); - expectOccursAfter(ids, 'B1', 'C2'); - expectOccursAfter(ids, 'B1', 'C3'); - expectOccursAfter(ids, 'B2', 'C2'); -}); diff --git a/packages/hermes-inspector-msggen/__tests__/header-writer-test.js b/packages/hermes-inspector-msggen/__tests__/header-writer-test.js deleted file mode 100644 index e793c803cdfcb4..00000000000000 --- a/packages/hermes-inspector-msggen/__tests__/header-writer-test.js +++ /dev/null @@ -1,132 +0,0 @@ -/** - * 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. - */ - -import { Command } from '../src/Command'; -import { Event } from '../src/Event'; -import { - emitNotificationDecl, - emitRequestDecl, - emitResponseDecl, - emitTypeDecl, -} from '../src/HeaderWriter'; -import {FakeWritable, expectCodeIsEqual} from '../src/TestHelpers'; -import { Type } from '../src/Type'; - -let stream = null; - -beforeEach(() => { - stream = new FakeWritable(); -}); - -test('emits type decl', () => { - let obj = { - 'id': 'Location', - 'type': 'object', - 'properties': [ - { 'name': 'scriptId', '$ref': 'Runtime.ScriptId', 'description': 'Script identifier as reported in the Debugger.scriptParsed.' }, - { 'name': 'lineNumber', 'type': 'integer', 'description': 'Line number in the script (0-based).' }, - { 'name': 'columnNumber', 'type': 'integer', 'optional': true, 'description': 'Column number in the script (0-based).' }, - ], - 'description': 'Location in the source code.', - }; - let type = Type.create('Debugger', obj); - - emitTypeDecl(stream, type); - - expectCodeIsEqual(stream.get(), ` - struct debugger::Location : public Serializable { - Location() = default; - Location(Location&&) = default; - Location(const Location&) = delete; - explicit Location(const folly::dynamic &obj); - folly::dynamic toDynamic() const override; - Location& operator=(const Location&) = delete; - Location& operator=(Location&&) = default; - - runtime::ScriptId scriptId{}; - int lineNumber{}; - std::optional columnNumber; - }; - `); -}); - -test('emits request decl', () => { - let obj = { - 'name': 'getScriptSource', - 'parameters': [ - { 'name': 'scriptId', '$ref': 'Runtime.ScriptId', 'description': 'Id of the script to get source for.' }, - ], - 'returns': [ - { 'name': 'scriptSource', 'type': 'string', 'description': 'Script source.' }, - ], - 'description': 'Returns source for the script with given id.', - }; - let command = Command.create('Debugger', obj); - - emitRequestDecl(stream, command); - - expectCodeIsEqual(stream.get(), ` - struct debugger::GetScriptSourceRequest : public Request { - GetScriptSourceRequest(); - explicit GetScriptSourceRequest(const folly::dynamic &obj); - - folly::dynamic toDynamic() const override; - void accept(RequestHandler &handler) const override; - - runtime::ScriptId scriptId{}; - }; - `); -}); - -test('emits response decl', () => { - let obj = { - 'name': 'getScriptSource', - 'parameters': [ - { 'name': 'scriptId', '$ref': 'Runtime.ScriptId', 'description': 'Id of the script to get source for.' }, - ], - 'returns': [ - { 'name': 'scriptSource', 'type': 'string', 'description': 'Script source.' }, - ], - 'description': 'Returns source for the script with given id.', - }; - let command = Command.create('Debugger', obj); - - emitResponseDecl(stream, command); - - expectCodeIsEqual(stream.get(), ` - struct debugger::GetScriptSourceResponse : public Response { - GetScriptSourceResponse() = default; - explicit GetScriptSourceResponse(const folly::dynamic &obj); - folly::dynamic toDynamic() const override; - - std::string scriptSource; - }; - `); -}); - -test('emits notification decl', () => { - let obj = { - 'name': 'messageAdded', - 'parameters': [ - { 'name': 'message', '$ref': 'ConsoleMessage', 'description': 'Console message that has been added.' }, - ], - 'description': 'Issued when new console message is added.', - }; - let event = Event.create('Console', obj); - - emitNotificationDecl(stream, event); - - expectCodeIsEqual(stream.get(), ` - struct console::MessageAddedNotification : public Notification { - MessageAddedNotification(); - explicit MessageAddedNotification(const folly::dynamic &obj); - folly::dynamic toDynamic() const override; - - console::ConsoleMessage message{}; - }; - `); -}); diff --git a/packages/hermes-inspector-msggen/__tests__/implementation-writer-test.js b/packages/hermes-inspector-msggen/__tests__/implementation-writer-test.js deleted file mode 100644 index 8d83a9cc67c59f..00000000000000 --- a/packages/hermes-inspector-msggen/__tests__/implementation-writer-test.js +++ /dev/null @@ -1,171 +0,0 @@ -/** - * 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. - */ - -import { Command } from '../src/Command'; -import { Event } from '../src/Event'; -import { - emitNotificationDef, - emitRequestDef, - emitResponseDef, - emitTypeDef, -} from '../src/ImplementationWriter'; -import {FakeWritable, expectCodeIsEqual} from '../src/TestHelpers'; -import { Type } from '../src/Type'; - -let stream = null; - -beforeEach(() => { - stream = new FakeWritable(); -}); - -test('emits type def', () => { - let obj = { - 'id': 'Location', - 'type': 'object', - 'properties': [ - { 'name': 'scriptId', '$ref': 'Runtime.ScriptId', 'description': 'Script identifier as reported in the Debugger.scriptParsed.' }, - { 'name': 'lineNumber', 'type': 'integer', 'description': 'Line number in the script (0-based).' }, - { 'name': 'columnNumber', 'type': 'integer', 'optional': true, 'description': 'Column number in the script (0-based).' }, - ], - 'description': 'Location in the source code.', - }; - let type = Type.create('Debugger', obj); - - emitTypeDef(stream, type); - - expectCodeIsEqual(stream.get(), ` - debugger::Location::Location(const dynamic &obj) { - assign(scriptId, obj, "scriptId"); - assign(lineNumber, obj, "lineNumber"); - assign(columnNumber, obj, "columnNumber"); - } - - dynamic debugger::Location::toDynamic() const { - dynamic obj = dynamic::object; - put(obj, "scriptId", scriptId); - put(obj, "lineNumber", lineNumber); - put(obj, "columnNumber", columnNumber); - return obj; - } - `); -}); - -test('emits request def', () => { - let obj = { - 'name': 'getScriptSource', - 'parameters': [ - { 'name': 'scriptId', '$ref': 'Runtime.ScriptId', 'description': 'Id of the script to get source for.' }, - ], - 'returns': [ - { 'name': 'scriptSource', 'type': 'string', 'description': 'Script source.' }, - ], - 'description': 'Returns source for the script with given id.', - }; - let command = Command.create('Debugger', obj); - - emitRequestDef(stream, command); - - expectCodeIsEqual(stream.get(), ` - debugger::GetScriptSourceRequest::GetScriptSourceRequest() - : Request("Debugger.getScriptSource") {} - - debugger::GetScriptSourceRequest::GetScriptSourceRequest(const dynamic &obj) - : Request("Debugger.getScriptSource") { - assign(id, obj, "id"); - assign(method, obj, "method"); - - dynamic params = obj.at("params"); - assign(scriptId, params, "scriptId"); - } - - dynamic debugger::GetScriptSourceRequest::toDynamic() const { - dynamic params = dynamic::object; - put(params, "scriptId", scriptId); - - dynamic obj = dynamic::object; - put(obj, "id", id); - put(obj, "method", method); - put(obj, "params", std::move(params)); - return obj; - } - - void debugger::GetScriptSourceRequest::accept(RequestHandler &handler) const { - handler.handle(*this); - } - `); -}); - -test('emits response def', () => { - let obj = { - 'name': 'getScriptSource', - 'parameters': [ - { 'name': 'scriptId', '$ref': 'Runtime.ScriptId', 'description': 'Id of the script to get source for.' }, - ], - 'returns': [ - { 'name': 'scriptSource', 'type': 'string', 'description': 'Script source.' }, - ], - 'description': 'Returns source for the script with given id.', - }; - let command = Command.create('Debugger', obj); - - emitResponseDef(stream, command); - - expectCodeIsEqual(stream.get(), ` - debugger::GetScriptSourceResponse::GetScriptSourceResponse(const dynamic &obj) { - assign(id, obj, "id"); - - dynamic res = obj.at("result"); - assign(scriptSource, res, "scriptSource"); - } - - dynamic debugger::GetScriptSourceResponse::toDynamic() const { - dynamic res = dynamic::object; - put(res, "scriptSource", scriptSource); - - dynamic obj = dynamic::object; - put(obj, "id", id); - put(obj, "result", std::move(res)); - return obj; - } - `); -}); - -test('emits notification def', () => { - let obj = { - 'name': 'messageAdded', - 'parameters': [ - { 'name': 'message', '$ref': 'ConsoleMessage', 'description': 'Console message that has been added.' }, - ], - 'description': 'Issued when new console message is added.', - }; - let event = Event.create('Console', obj); - - emitNotificationDef(stream, event); - - expectCodeIsEqual(stream.get(), ` - console::MessageAddedNotification::MessageAddedNotification() - : Notification("Console.messageAdded") {} - - console::MessageAddedNotification::MessageAddedNotification(const dynamic &obj) - : Notification("Console.messageAdded") { - assign(method, obj, "method"); - - dynamic params = obj.at("params"); - assign(message, params, "message"); - } - - dynamic console::MessageAddedNotification::toDynamic() const { - dynamic params = dynamic::object; - put(params, "message", message); - - dynamic obj = dynamic::object; - put(obj, "method", method); - put(obj, "params", std::move(params)); - return obj; - } - `); -}); diff --git a/packages/hermes-inspector-msggen/__tests__/property-test.js b/packages/hermes-inspector-msggen/__tests__/property-test.js deleted file mode 100644 index 96dcf6b4ab6fac..00000000000000 --- a/packages/hermes-inspector-msggen/__tests__/property-test.js +++ /dev/null @@ -1,131 +0,0 @@ -/** - * 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. - */ - -import {Property} from '../src/Property.js'; - -test('parses required primitive prop', () => { - let obj = { - 'name': 'lineNumber', - 'type': 'integer', - 'description': 'Line number in the script (0-based).', - }; - let prop = Property.create('Debugger', obj); - - expect(prop.domain).toBe('Debugger'); - expect(prop.name).toBe('lineNumber'); - expect(prop.type).toBe('integer'); - expect(prop.optional).toBeUndefined(); - expect(prop.description).toBe('Line number in the script (0-based).'); - - expect(prop.getFullCppType()).toBe('int'); - expect(prop.getCppIdentifier()).toBe('lineNumber'); - expect(prop.getInitializer()).toBe('{}'); -}); - -test('parses optional primitive prop', () => { - let obj = { - 'name': 'samplingInterval', - 'type': 'number', - 'optional': true, - 'description': 'Average sample interval in bytes.', - }; - let prop = Property.create('HeapProfiler', obj); - - expect(prop.domain).toBe('HeapProfiler'); - expect(prop.name).toBe('samplingInterval'); - expect(prop.type).toBe('number'); - expect(prop.optional).toBe(true); - expect(prop.description).toBe('Average sample interval in bytes.'); - - expect(prop.getFullCppType()).toBe('std::optional'); - expect(prop.getCppIdentifier()).toBe('samplingInterval'); - expect(prop.getInitializer()).toBe(''); -}); - -test('parses optional ref prop', () => { - let obj = { - 'name': 'exceptionDetails', - 'optional': true, - '$ref': 'Runtime.ExceptionDetails', - 'description': 'Exception details if any.', - }; - let prop = Property.create('Debugger', obj); - - expect(prop.domain).toBe('Debugger'); - expect(prop.name).toBe('exceptionDetails'); - expect(prop.optional).toBe(true); - expect(prop.$ref).toBe('Runtime.ExceptionDetails'); - expect(prop.description).toBe('Exception details if any.'); - - expect(prop.getFullCppType()).toBe('std::optional'); - expect(prop.getCppIdentifier()).toBe('exceptionDetails'); - expect(prop.getInitializer()).toBe(''); -}); - -test('parses recursive ref prop', () => { - let obj = { - 'name': 'parent', - '$ref': 'StackTrace', - 'optional': true, - 'recursive': true, - 'description': 'Asynchronous JavaScript stack trace...', - }; - let prop = Property.create('Runtime', obj); - - expect(prop.domain).toBe('Runtime'); - expect(prop.name).toBe('parent'); - expect(prop.optional).toBe(true); - expect(prop.recursive).toBe(true); - expect(prop.$ref).toBe('StackTrace'); - expect(prop.description).toBe('Asynchronous JavaScript stack trace...'); - - expect(prop.getFullCppType()).toBe('std::unique_ptr'); - expect(prop.getCppIdentifier()).toBe('parent'); - expect(prop.getInitializer()).toBe(''); -}); - -test('parses optional array items prop', () => { - let obj = { - 'name': 'hitBreakpoints', - 'type': 'array', - 'optional': true, - 'items': { 'type': 'string' }, - 'description': 'Hit breakpoints IDs', - }; - let prop = Property.create('Debugger', obj); - - expect(prop.domain).toBe('Debugger'); - expect(prop.name).toBe('hitBreakpoints'); - expect(prop.type).toBe('array'); - expect(prop.optional).toBe(true); - expect(prop.items).toEqual({ 'type': 'string' }); - expect(prop.description).toBe('Hit breakpoints IDs'); - - expect(prop.getFullCppType()).toBe('std::optional>'); - expect(prop.getCppIdentifier()).toBe('hitBreakpoints'); - expect(prop.getInitializer()).toBe(''); -}); - -test('parses array ref prop', () => { - let obj = { - 'name': 'domains', - 'type': 'array', - 'items': { '$ref': 'Domain' }, - 'description': 'List of supported domains.', - }; - let prop = Property.create('Schema', obj); - - expect(prop.domain).toBe('Schema'); - expect(prop.name).toBe('domains'); - expect(prop.type).toBe('array'); - expect(prop.items).toEqual({ $ref: 'Domain' }); - expect(prop.description).toBe('List of supported domains.'); - - expect(prop.getFullCppType()).toBe('std::vector'); - expect(prop.getCppIdentifier()).toBe('domains'); - expect(prop.getInitializer()).toBe(''); -}); diff --git a/packages/hermes-inspector-msggen/__tests__/type-test.js b/packages/hermes-inspector-msggen/__tests__/type-test.js deleted file mode 100644 index 14fc860e1e2d0d..00000000000000 --- a/packages/hermes-inspector-msggen/__tests__/type-test.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * 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. - */ - -import {Type} from '../src/Type.js'; - -test('parses primitive type', () => { - let obj = { - 'id': 'Timestamp', - 'type': 'number', - 'description': 'Number of milliseconds since epoch.', - }; - let type = Type.create('Runtime', obj, false); - - expect(type.domain).toBe('Runtime'); - expect(type.id).toBe('Timestamp'); - expect(type.type).toBe('number'); - expect(type.description).toBe('Number of milliseconds since epoch.'); - - expect(type.getCppNamespace()).toBe('runtime'); - expect(type.getCppType()).toBe('Timestamp'); - expect(type.getForwardDecls()).toEqual(['using Timestamp = double;']); -}); - -test('parses object type', () => { - let obj = { - 'id': 'Location', - 'type': 'object', - 'properties': [ - { 'name': 'scriptId', '$ref': 'Runtime.ScriptId', 'description': 'Script identifier as reported in the Debugger.scriptParsed.' }, - { 'name': 'lineNumber', 'type': 'integer', 'description': 'Line number in the script (0-based).' }, - { 'name': 'columnNumber', 'type': 'integer', 'optional': true, 'description': 'Column number in the script (0-based).' }, - ], - 'description': 'Location in the source code.', - }; - let type = Type.create('Debugger', obj, false); - - expect(type.domain).toBe('Debugger'); - expect(type.id).toBe('Location'); - expect(type.type).toBe('object'); - expect(type.properties.map(p => p.name)).toEqual(['scriptId', 'lineNumber', 'columnNumber']); - expect(type.description).toBe('Location in the source code.'); - - expect(type.getCppNamespace()).toBe('debugger'); - expect(type.getCppType()).toBe('Location'); - expect(type.getForwardDecls()).toEqual(['struct Location;']); -}); diff --git a/packages/hermes-inspector-msggen/package.json b/packages/hermes-inspector-msggen/package.json deleted file mode 100644 index 0fa9dbfa91443a..00000000000000 --- a/packages/hermes-inspector-msggen/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "@react-native/hermes-inspector-msggen", - "version": "0.77.0-main", - "private": true, - "description": "Hermes Inspector Message Generator for React Native", - "license": "MIT", - "repository": { - "type": "git", - "url": "git+https://github.com/facebook/react-native.git", - "directory": "packages/hermes-inspector-msggen" - }, - "bin": { - "msggen": "bin/index.js" - }, - "engines": { - "node": ">=18" - }, - "scripts": { - "flow": "flow", - "build": "babel src --out-dir bin --source-maps", - "watch": "babel src --out-dir bin --source-maps --watch", - "test": "jest" - }, - "dependencies": { - "devtools-protocol": "0.0.1107588", - "yargs": "^17.6.2" - }, - "devDependencies": { - "@babel/cli": "^7.24.8", - "@babel/core": "^7.25.2", - "@babel/preset-env": "^7.25.3", - "@babel/preset-flow": "^7.24.7", - "jest": "^29.6.3" - }, - "jest": { - "transform": { - ".*": "/node_modules/babel-jest" - } - } -} diff --git a/packages/hermes-inspector-msggen/src/Command.js b/packages/hermes-inspector-msggen/src/Command.js deleted file mode 100644 index f6da8dffa8c665..00000000000000 --- a/packages/hermes-inspector-msggen/src/Command.js +++ /dev/null @@ -1,91 +0,0 @@ -/** - * 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 {toCppNamespace, toCppType} from './Converters'; -import {Property} from './Property'; - -export class Command { - domain: string; - name: string; - description: ?string; - experimental: ?boolean; - parameters: Array; - returns: Array; - - static create( - domain: string, - obj: any, - ignoreExperimental: boolean, - includeExperimental: Set, - ): ?Command { - return ignoreExperimental && - obj.experimental && - !includeExperimental.has(domain + '.' + obj.name) - ? null - : new Command(domain, obj, ignoreExperimental, includeExperimental); - } - - constructor( - domain: string, - obj: any, - ignoreExperimental: boolean, - includeExperimental: Set, - ) { - this.domain = domain; - this.name = obj.name; - this.description = obj.description; - this.experimental = obj.experimental; - this.parameters = Property.createArray( - domain, - obj.name, - obj.parameters || [], - ignoreExperimental, - includeExperimental, - ); - this.returns = Property.createArray( - domain, - obj.name, - obj.returns || [], - ignoreExperimental, - includeExperimental, - ); - } - - getDebuggerName(): string { - return `${this.domain}.${this.name}`; - } - - getCppNamespace(): string { - return toCppNamespace(this.domain); - } - - getRequestCppType(): string { - return toCppType(this.name + 'Request'); - } - - getResponseCppType(): ?string { - if (this.returns && this.returns.length > 0) { - return toCppType(this.name + 'Response'); - } - } - - getForwardDecls(): Array { - const decls = [`struct ${this.getRequestCppType()};`]; - const respCppType = this.getResponseCppType(); - if (respCppType) { - decls.push(`struct ${respCppType};`); - } - return decls; - } - - getForwardDeclSortKey(): string { - return this.getRequestCppType(); - } -} diff --git a/packages/hermes-inspector-msggen/src/Converters.js b/packages/hermes-inspector-msggen/src/Converters.js deleted file mode 100644 index aa5dbf86552cb6..00000000000000 --- a/packages/hermes-inspector-msggen/src/Converters.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * 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 strict-local - * @format - */ - -export function toCppNamespace(domain: string): string { - return domain.slice(0, 1).toLowerCase() + domain.slice(1); -} - -export function toCppType(type: string): string { - return type.slice(0, 1).toUpperCase() + type.slice(1); -} - -export type JsTypeString = - | 'any' - | 'boolean' - | 'integer' - | 'number' - | 'object' - | 'string'; - -const jsTypeMappings = { - any: 'folly::dynamic', - array: 'folly::dynamic', - boolean: 'bool', - integer: 'int', - number: 'double', - object: 'folly::dynamic', - string: 'std::string', -}; - -export function jsTypeToCppType(jsTypeStr: JsTypeString): string { - return jsTypeMappings[jsTypeStr]; -} diff --git a/packages/hermes-inspector-msggen/src/Event.js b/packages/hermes-inspector-msggen/src/Event.js deleted file mode 100644 index bb9f2c4f5658a5..00000000000000 --- a/packages/hermes-inspector-msggen/src/Event.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * 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 {toCppNamespace, toCppType} from './Converters'; -import {Property} from './Property'; - -export class Event { - domain: string; - name: string; - description: ?string; - experimental: ?boolean; - parameters: Array; - - static create( - domain: string, - obj: any, - ignoreExperimental: boolean, - includeExperimental: Set, - ): ?Event { - return ignoreExperimental && - obj.experimental && - !includeExperimental.has(domain + '.' + obj.name) - ? null - : new Event(domain, obj, ignoreExperimental, includeExperimental); - } - - constructor( - domain: string, - obj: any, - ignoreExperimental: boolean, - includeExperimental: Set, - ) { - this.domain = domain; - this.name = obj.name; - this.description = obj.description; - this.parameters = Property.createArray( - domain, - obj.name, - obj.parameters || [], - ignoreExperimental, - includeExperimental, - ); - } - - getDebuggerName(): string { - return `${this.domain}.${this.name}`; - } - - getCppNamespace(): string { - return toCppNamespace(this.domain); - } - - getCppType(): string { - return toCppType(this.name + 'Notification'); - } - - getForwardDecls(): Array { - return [`struct ${this.getCppType()};`]; - } - - getForwardDeclSortKey(): string { - return this.getCppType(); - } -} diff --git a/packages/hermes-inspector-msggen/src/GeneratedHeader.js b/packages/hermes-inspector-msggen/src/GeneratedHeader.js deleted file mode 100644 index 9533b2425e2866..00000000000000 --- a/packages/hermes-inspector-msggen/src/GeneratedHeader.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * 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 - */ - -'use strict'; - -// placeholder token that will be replaced by signedsource script -export const GeneratedHeader: string = - '// Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved.\n' + - '// @generated <>'; diff --git a/packages/hermes-inspector-msggen/src/Graph.js b/packages/hermes-inspector-msggen/src/Graph.js deleted file mode 100644 index a3b22d3a206290..00000000000000 --- a/packages/hermes-inspector-msggen/src/Graph.js +++ /dev/null @@ -1,98 +0,0 @@ -/** - * 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 strict-local - * @format - */ - -import invariant from 'assert'; - -type NodeId = string; -type NodeCycle = {from: NodeId, to: NodeId}; - -class Node { - id: NodeId; - children: Set; - state: 'none' | 'visiting' | 'visited'; - - constructor(id: NodeId) { - this.id = id; - this.children = new Set(); - this.state = 'none'; - } -} - -export class Graph { - nodes: Map; - - constructor() { - this.nodes = new Map(); - } - - addNode(nodeId: NodeId): Node { - let node = this.nodes.get(nodeId); - if (!node) { - node = new Node(nodeId); - this.nodes.set(nodeId, node); - } - return node; - } - - addEdge(srcId: NodeId, dstId: NodeId) { - const src = this.addNode(srcId); - const dst = this.addNode(dstId); - src.children.add(dst); - } - - // traverse returns all nodes in the graph reachable from the given rootIds. - // the returned nodes are topologically sorted, with the deepest nodes - // returned first. - traverse(rootIds: Array): { - nodes: Array, - cycles: Array, - } { - // clear marks - for (const node of this.nodes.values()) { - node.state = 'none'; - } - - // make a fake root node that points to all the provided rootIds - const root = new Node('root'); - for (const id of rootIds) { - const node = this.nodes.get(id); - invariant(node != null, `No node ${id} in graph`); - root.children.add(node); - } - - const nodes: Array = []; - const cycles: Array = []; - postorder(root, nodes, cycles); - - // remove fake root node - nodes.splice(-1); - - return {nodes: nodes, cycles: cycles}; - } -} - -function postorder(node: Node, nodes: Array, cycles: Array) { - if (node.state === 'visited') { - return; - } - - node.state = 'visiting'; - for (const child of node.children) { - if (child.state === 'visiting') { - // This will lead to a cycle; we need to mark that and move on - cycles.push({from: node.id, to: child.id}); - } else { - postorder(child, nodes, cycles); - } - } - - node.state = 'visited'; - nodes.push(node.id); -} diff --git a/packages/hermes-inspector-msggen/src/HeaderWriter.js b/packages/hermes-inspector-msggen/src/HeaderWriter.js deleted file mode 100644 index 612e44e783a5d8..00000000000000 --- a/packages/hermes-inspector-msggen/src/HeaderWriter.js +++ /dev/null @@ -1,327 +0,0 @@ -/** - * 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 {Command} from './Command'; -import {toCppNamespace} from './Converters'; -import {Event} from './Event'; -import {GeneratedHeader} from './GeneratedHeader'; -import {Property} from './Property'; -import {PropsType, Type} from './Type'; -import {Writable} from 'stream'; - -export class HeaderWriter { - stream: Writable; - types: Array; - commands: Array; - events: Array; - - constructor( - stream: Writable, - types: Array, - commands: Array, - events: Array, - ) { - 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 - - #include - #include - - namespace facebook { - namespace hermes { - namespace inspector_modern { - namespace chrome { - namespace message { - -template -void deleter(T* p); - `); - } - - writeForwardDecls() { - this.stream.write('struct UnknownRequest;\n\n'); - - const namespaceMap: Map> = new Map(); - const addToMap = function (type: Type | Command | Event) { - 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_modern - } // namespace hermes - } // namespace facebook - `); - } -} - -function emitRequestHandlerDecl(stream: Writable, commands: Array) { - 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, -) { - 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) { - 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; - ${cppType}(${cppType}&&) = default; - ${cppType}(const ${cppType}&) = delete; - explicit ${cppType}(const folly::dynamic &obj); - folly::dynamic toDynamic() const override; - ${cppType}& operator=(const ${cppType}&) = delete; - ${cppType}& operator=(${cppType}&&) = default; - `); - - 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; - - std::optional 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; - std::optional 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'); -} diff --git a/packages/hermes-inspector-msggen/src/ImplementationWriter.js b/packages/hermes-inspector-msggen/src/ImplementationWriter.js deleted file mode 100644 index 030cee099f05e5..00000000000000 --- a/packages/hermes-inspector-msggen/src/ImplementationWriter.js +++ /dev/null @@ -1,420 +0,0 @@ -/** - * 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 {Command} from './Command'; -import {Event} from './Event'; -import {GeneratedHeader} from './GeneratedHeader'; -import {PropsType, Type} from './Type'; -import {Writable} from 'stream'; - -export class ImplementationWriter { - stream: Writable; - types: Array; - commands: Array; - events: Array; - - constructor( - stream: Writable, - types: Array, - commands: Array, - events: Array, - ) { - this.stream = stream; - this.types = types; - this.commands = commands; - this.events = events; - } - - write() { - this.writePrologue(); - this.writeRequestParser(); - this.writeTypeDefs(); - this.writeRequestDefs(); - this.writeResponseDefs(); - this.writeNotificationDefs(); - this.writeEpilogue(); - } - - writePrologue() { - this.stream.write(`${GeneratedHeader} - - #include "MessageTypes.h" - - #include "MessageTypesInlines.h" - - namespace facebook { - namespace hermes { - namespace inspector_modern { - namespace chrome { - namespace message { - - `); - } - - writeRequestParser() { - emitRequestParser(this.stream, this.commands); - } - - writeTypeDefs() { - this.stream.write('\n/// Types\n'); - - for (const type of this.types) { - if (type instanceof PropsType) { - emitTypeDef(this.stream, type); - } - } - } - - writeRequestDefs() { - this.stream.write('\n/// Requests\n'); - - emitUnknownRequestDef(this.stream); - - for (const command of this.commands) { - emitRequestDef(this.stream, command); - } - } - - writeResponseDefs() { - this.stream.write('\n/// Responses\n'); - - emitErrorResponseDef(this.stream); - emitOkResponseDef(this.stream); - - for (const command of this.commands) { - emitResponseDef(this.stream, command); - } - } - - writeNotificationDefs() { - this.stream.write('\n/// Notifications\n'); - - for (const event of this.events) { - emitNotificationDef(this.stream, event); - } - } - - writeEpilogue() { - this.stream.write(` - } // namespace message - } // namespace chrome - } // namespace inspector_modern - } // namespace hermes - } // namespace facebook - `); - } -} - -function emitRequestParser(stream: Writable, commands: Array) { - stream.write(` - using RequestBuilder = std::unique_ptr (*)(const dynamic &); - - namespace { - - template - std::unique_ptr makeUnique(const dynamic &obj) { - return std::make_unique(obj); - } - - } // namespace - - std::unique_ptr Request::fromJsonThrowOnError(const std::string &str) { - static std::unordered_map builders = { - `); - - for (const command of commands) { - const cppNs = command.getCppNamespace(); - const cppType = command.getRequestCppType(); - const dbgName = command.getDebuggerName(); - - stream.write(`{"${dbgName}", makeUnique<${cppNs}::${cppType}>},\n`); - } - - stream.write(`}; - - dynamic obj = folly::parseJson(str); - std::string method = obj.at("method").asString(); - - auto it = builders.find(method); - if (it == builders.end()) { - return std::make_unique(obj); - } - - auto builder = it->second; - return builder(obj); - } - - folly::Try> Request::fromJson(const std::string &str) { - return folly::makeTryWith( - [&str] { return Request::fromJsonThrowOnError(str); }); - }\n\n`); - - stream.write('\n'); -} - -export function emitTypeDef(stream: Writable, type: PropsType) { - const cppNs = type.getCppNamespace(); - const cppType = type.getCppType(); - const props = type.properties || []; - - // From-dynamic constructor - stream.write(`${cppNs}::${cppType}::${cppType}(const dynamic &obj) {\n`); - - for (const prop of props) { - const id = prop.getCppIdentifier(); - const name = prop.name; - stream.write(`assign(${id}, obj, "${name}");\n`); - } - - stream.write('}\n\n'); - - // toDynamic - stream.write(`dynamic ${cppNs}::${cppType}::toDynamic() const { - dynamic obj = dynamic::object;\n\n`); - - for (const prop of props) { - const id = prop.getCppIdentifier(); - const name = prop.name; - stream.write(`put(obj, "${name}", ${id});\n`); - } - - stream.write('return obj;\n}\n\n'); -} - -function emitErrorResponseDef(stream: Writable) { - stream.write(`ErrorResponse::ErrorResponse(const dynamic &obj) { - assign(id, obj, "id"); - - dynamic error = obj.at("error"); - assign(code, error, "code"); - assign(message, error, "message"); - assign(data, error, "data"); - } - - dynamic ErrorResponse::toDynamic() const { - dynamic error = dynamic::object; - put(error, "code", code); - put(error, "message", message); - put(error, "data", data); - - dynamic obj = dynamic::object; - put(obj, "id", id); - put(obj, "error", std::move(error)); - return obj; - }\n\n`); -} - -function emitOkResponseDef(stream: Writable) { - stream.write(`OkResponse::OkResponse(const dynamic &obj) { - assign(id, obj, "id"); - } - - dynamic OkResponse::toDynamic() const { - dynamic result = dynamic::object; - - dynamic obj = dynamic::object; - put(obj, "id", id); - put(obj, "result", std::move(result)); - return obj; - }\n\n`); -} - -function emitUnknownRequestDef(stream: Writable) { - stream.write(`UnknownRequest::UnknownRequest() {} - -UnknownRequest::UnknownRequest(const dynamic &obj) { - assign(id, obj, "id"); - assign(method, obj, "method"); - assign(params, obj, "params"); -} - -dynamic UnknownRequest::toDynamic() const { - dynamic obj = dynamic::object; - put(obj, "id", id); - put(obj, "method", method); - put(obj, "params", params); - return obj; -} - -void UnknownRequest::accept(RequestHandler &handler) const { - handler.handle(*this); -}\n\n`); -} - -export function emitRequestDef(stream: Writable, command: Command) { - const cppNs = command.getCppNamespace(); - const cppType = command.getRequestCppType(); - const dbgName = command.getDebuggerName(); - const props = command.parameters || []; - - // Default constructor - stream.write(`${cppNs}::${cppType}::${cppType}() - : Request("${dbgName}") {}\n\n`); - - // From-dynamic constructor - stream.write(`${cppNs}::${cppType}::${cppType}(const dynamic &obj) - : Request("${dbgName}") { - assign(id, obj, "id"); - assign(method, obj, "method");\n\n`); - - if (props.length > 0) { - const optionalParams = props.every(p => p.optional); - if (optionalParams) { - stream.write(` - auto it = obj.find("params"); - if (it != obj.items().end()) { - dynamic params = it->second; - `); - } else { - stream.write('dynamic params = obj.at("params");\n'); - } - - for (const prop of props) { - const id = prop.getCppIdentifier(); - const name = prop.name; - stream.write(`assign(${id}, params, "${name}");\n`); - } - - if (optionalParams) { - stream.write('}'); - } - } - - stream.write('}\n\n'); - - // toDynamic - stream.write(`dynamic ${cppNs}::${cppType}::toDynamic() const {\n`); - - if (props.length > 0) { - stream.write('dynamic params = dynamic::object;\n'); - - for (const prop of props) { - const id = prop.getCppIdentifier(); - const name = prop.name; - stream.write(`put(params, "${name}", ${id});\n`); - } - } - - stream.write(` - dynamic obj = dynamic::object; - put(obj, "id", id); - put(obj, "method", method); - `); - - if (props.length > 0) { - stream.write('put(obj, "params", std::move(params));\n'); - } - - stream.write(`return obj; - }\n\n`); - - // visitor - stream.write(`void ${cppNs}::${cppType}::accept(RequestHandler &handler) const { - handler.handle(*this); - }\n\n`); -} - -export function emitResponseDef(stream: Writable, command: Command) { - const cppNs = command.getCppNamespace(); - const cppType = command.getResponseCppType(); - if (!cppType) { - return; - } - - // From-dynamic constructor - stream.write(`${cppNs}::${cppType}::${cppType}(const dynamic &obj) { - assign(id, obj, "id");\n\n`); - - const props = command.returns || []; - if (props.length > 0) { - stream.write('dynamic res = obj.at("result");\n'); - - for (const prop of props) { - const id = prop.getCppIdentifier(); - const name = prop.name; - stream.write(`assign(${id}, res, "${name}");\n`); - } - } - - stream.write('}\n\n'); - - // toDynamic - stream.write(`dynamic ${cppNs}::${cppType}::toDynamic() const {\n`); - - if (props.length > 0) { - stream.write('dynamic res = dynamic::object;\n'); - - for (const prop of props) { - const id = prop.getCppIdentifier(); - const name = prop.name; - stream.write(`put(res, "${name}", ${id});\n`); - } - } - - stream.write(` - dynamic obj = dynamic::object; - put(obj, "id", id); - put(obj, "result", std::move(res)); - return obj; - }\n\n`); -} - -export function emitNotificationDef(stream: Writable, event: Event) { - const cppNs = event.getCppNamespace(); - const cppType = event.getCppType(); - const dbgName = event.getDebuggerName(); - const props = event.parameters || []; - - // Default constructor - stream.write(`${cppNs}::${cppType}::${cppType}() - : Notification("${dbgName}") {}\n\n`); - - // From-dynamic constructor - stream.write(`${cppNs}::${cppType}::${cppType}(const dynamic &obj) - : Notification("${dbgName}") { - assign(method, obj, "method");\n\n`); - - if (props.length > 0) { - stream.write('dynamic params = obj.at("params");\n'); - - for (const prop of props) { - const id = prop.getCppIdentifier(); - const name = prop.name; - stream.write(`assign(${id}, params, "${name}");\n`); - } - } - - stream.write('}\n\n'); - - // toDynamic - stream.write(`dynamic ${cppNs}::${cppType}::toDynamic() const {\n`); - - if (props.length > 0) { - stream.write('dynamic params = dynamic::object;\n'); - - for (const prop of props) { - const id = prop.getCppIdentifier(); - const name = prop.name; - stream.write(`put(params, "${name}", ${id});\n`); - } - } - - stream.write(` - dynamic obj = dynamic::object; - put(obj, "method", method); - `); - - if (props.length > 0) { - stream.write('put(obj, "params", std::move(params));\n'); - } - - stream.write(`return obj; - }\n\n`); -} diff --git a/packages/hermes-inspector-msggen/src/Property.js b/packages/hermes-inspector-msggen/src/Property.js deleted file mode 100644 index 3874d83c58c733..00000000000000 --- a/packages/hermes-inspector-msggen/src/Property.js +++ /dev/null @@ -1,244 +0,0 @@ -/** - * 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 { - type JsTypeString, - jsTypeToCppType, - toCppNamespace, - toCppType, -} from './Converters'; - -export class Property { - domain: string; - name: string; - description: ?string; - exported: ?boolean; - experimental: ?boolean; - optional: ?boolean; - - static create(domain: string, obj: any): Property { - if (obj.$ref) { - return new RefProperty(domain, obj); - } else if (obj.type === 'array') { - return new ArrayProperty(domain, obj); - } - return new PrimitiveProperty(domain, obj); - } - - static createArray( - domain: string, - parent: string, - elements: Array, - ignoreExperimental: boolean, - includeExperimental: Set, - ): Array { - let props = elements.map(elem => Property.create(domain, elem)); - if (ignoreExperimental) { - props = props.filter(prop => { - return ( - !prop.experimental || - includeExperimental.has(domain + '.' + parent + '.' + prop.name) - ); - }); - } - return props; - } - - constructor(domain: string, obj: any) { - this.domain = domain; - this.name = obj.name; - this.description = obj.description; - this.exported = obj.exported; - this.experimental = obj.experimental; - this.optional = obj.optional; - } - - getRefDebuggerName(): ?string { - throw new Error('subclass must implement'); - } - - getFullCppType(): string { - throw new Error('subclass must implement'); - } - - getCppIdentifier(): string { - // need to munge identifier if it matches a C++ keyword like "this" - if (this.name === 'this') { - return 'thisObj'; - } - return this.name; - } - - getInitializer(): string { - throw new Error('subclass must implement'); - } -} - -function maybeWrapOptional( - type: string, - optional: ?boolean, - recursive: ?boolean, - cyclical: ?boolean, -) { - if (cyclical) { - // n.b. need to use unique_ptr with a custom deleter since - // due to the type cycle we only have the fwd def here and - // the type is incomplete - return `std::unique_ptr<${type}, std::function>`; - } else if (optional) { - return recursive ? `std::unique_ptr<${type}>` : `std::optional<${type}>`; - } - return type; -} - -function toDomainAndId( - curDomain: string, - absOrRelRef: string, -): [string, string] { - let [domain, id] = ['', '']; - - // absOrRelRef can be: - // 1) absolute ref with a "." referencing a type from another namespace, like - // "Runtime.ExceptionDetails" - // 2) relative ref without a "." referencing a type in current domain, like - // "Domain" - const i = absOrRelRef.indexOf('.'); - if (i === -1) { - domain = curDomain; - id = absOrRelRef; - } else { - domain = absOrRelRef.slice(0, i); - id = absOrRelRef.slice(i + 1); - } - - return [domain, id]; -} - -function toFullCppType(curDomain: string, absOrRelRef: string) { - const [domain, id] = toDomainAndId(curDomain, absOrRelRef); - return `${toCppNamespace(domain)}::${toCppType(id)}`; -} - -class PrimitiveProperty extends Property { - type: JsTypeString; - - constructor(domain: string, obj: any) { - super(domain, obj); - this.type = obj.type; - } - - getRefDebuggerName(): ?string { - return undefined; - } - - getFullCppType(): string { - return maybeWrapOptional(jsTypeToCppType(this.type), this.optional); - } - - getInitializer(): string { - // std::optional doesn't need to be explicitly zero-init - if (this.optional) { - return ''; - } - - // we want to explicitly zero-init bool, int, and double - const type = this.type; - if (type === 'boolean' || type === 'integer' || type === 'number') { - return '{}'; - } - - // everything else (folly::dynamic and std::string) has sensible default - // constructor, no need to explicitly zero-init - return ''; - } -} - -class RefProperty extends Property { - $ref: string; - recursive: ?boolean; - cyclical: ?boolean; - - constructor(domain: string, obj: any) { - super(domain, obj); - this.$ref = obj.$ref; - this.recursive = obj.recursive; - this.cyclical = obj.cyclical; - } - - getRefDebuggerName(): ?string { - const [domain, id] = toDomainAndId(this.domain, this.$ref); - return `${domain}.${id}`; - } - - getFullCppType(): string { - const fullCppType = toFullCppType(this.domain, this.$ref); - return maybeWrapOptional( - `${fullCppType}`, - this.optional, - this.recursive, - this.cyclical, - ); - } - - getInitializer(): string { - // must zero-init non-optional ref props since the ref could just be an - // alias to a C++ primitive type like int which we always want to zero-init - const fullCppType = toFullCppType(this.domain, this.$ref); - return this.cyclical - ? `{nullptr, deleter<${fullCppType}>}` - : this.optional - ? '' - : '{}'; - } -} - -class ArrayProperty extends Property { - type: 'array'; - items: - | {|type: JsTypeString, recursive: false|} - | {|$ref: string, recursive: ?boolean|}; - - constructor(domain: string, obj: any) { - super(domain, obj); - this.type = obj.type; - this.items = obj.items; - } - - getRefDebuggerName(): ?string { - if (this.items && this.items.$ref && !this.items.recursive) { - const [domain, id] = toDomainAndId(this.domain, this.items.$ref); - return `${domain}.${id}`; - } - } - - getFullCppType(): string { - let elemType: string = 'folly::dynamic'; - let recursive: ?(false | boolean) = false; - - if (this.items) { - if (this.items.type) { - elemType = jsTypeToCppType(this.items.type); - } else if (this.items.$ref) { - elemType = toFullCppType(this.domain, this.items.$ref); - recursive = this.items.recursive; - } - } - - return maybeWrapOptional( - `std::vector<${elemType}>`, - this.optional, - recursive, - ); - } - - getInitializer(): string { - return ''; - } -} diff --git a/packages/hermes-inspector-msggen/src/TestHelpers.js b/packages/hermes-inspector-msggen/src/TestHelpers.js deleted file mode 100644 index c53ab4c946789a..00000000000000 --- a/packages/hermes-inspector-msggen/src/TestHelpers.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * 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. - */ - -/*global expect*/ - -// munges string so that it's nice to look at in a test diff -function strip(str) { - // Trim leading and trailing WS - str = str.replace(/^\s+/, ''); - str = str.replace(/\s+$/, ''); - - // Collapse all repeating newlines (possibly with spaces in between) into a - // single newline - str = str.replace(/\n(\s*)/g, '\n'); - - // Collapse all non-newline whitespace into a single space - return str.replace(/[^\S\n]+/g, ' '); -} - -export function expectCodeIsEqual(actual, expected) { - expect(strip(actual)).toBe(strip(expected)); -} - -export class FakeWritable { - constructor() { - this.result = ''; - } - - write(str) { - this.result += str; - } - - get() { - return this.result; - } -} diff --git a/packages/hermes-inspector-msggen/src/Type.js b/packages/hermes-inspector-msggen/src/Type.js deleted file mode 100644 index 9371fbce0f2a3d..00000000000000 --- a/packages/hermes-inspector-msggen/src/Type.js +++ /dev/null @@ -1,117 +0,0 @@ -/** - * 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 {jsTypeToCppType, toCppNamespace, toCppType} from './Converters'; -import {Property} from './Property'; - -export class Type { - domain: string; - id: string; - description: ?string; - exported: ?boolean; - experimental: ?boolean; - - static create( - domain: string, - obj: any, - ignoreExperimental: boolean, - includeExperimental: Set, - ): ?Type { - let type = null; - - if (obj.type === 'object' && obj.properties) { - type = new PropsType( - domain, - obj, - ignoreExperimental, - includeExperimental, - ); - } else if (obj.type) { - type = new PrimitiveType(domain, obj, ignoreExperimental); - } else { - throw new TypeError('Type requires `type` property.'); - } - - if (ignoreExperimental && type.experimental) { - if (!includeExperimental.has(domain + '.' + type.id)) { - type = null; - } - } - - return type; - } - - constructor(domain: string, obj: any) { - this.domain = domain; - this.id = obj.id; - this.description = obj.description; - this.exported = obj.exported; - this.experimental = obj.experimental; - } - - getDebuggerName(): string { - return `${this.domain}.${this.id}`; - } - - getCppNamespace(): string { - return toCppNamespace(this.domain); - } - - getCppType(): string { - return toCppType(this.id); - } - - getForwardDecls(): Array { - throw new Error('subclass must implement'); - } - - getForwardDeclSortKey(): string { - return this.getCppType(); - } -} - -export class PrimitiveType extends Type { - type: 'integer' | 'number' | 'object' | 'string'; - - constructor(domain: string, obj: any, ignoreExperimental: boolean) { - super(domain, obj); - this.type = obj.type; - } - - getForwardDecls(): Array { - return [`using ${this.getCppType()} = ${jsTypeToCppType(this.type)};`]; - } -} - -export class PropsType extends Type { - type: 'object'; - properties: Array; - - constructor( - domain: string, - obj: any, - ignoreExperimental: boolean, - includeExperimental: Set, - ) { - super(domain, obj); - this.type = obj.type; - this.properties = Property.createArray( - domain, - obj.id, - obj.properties || [], - ignoreExperimental, - includeExperimental, - ); - } - - getForwardDecls(): Array { - return [`struct ${this.getCppType()};`]; - } -} diff --git a/packages/hermes-inspector-msggen/src/custom.json b/packages/hermes-inspector-msggen/src/custom.json deleted file mode 100644 index c9650a9c293a77..00000000000000 --- a/packages/hermes-inspector-msggen/src/custom.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "domains": [ - { - "domain": "Hermes", - "description": "Hermes specific messages", - "commands": [ - { - "name": "setPauseOnLoad", - "description": "Pause VM when new scripts are loaded (reason='load')", - "parameters": [ - { - "name": "state", - "description": "Pause on script load mode", - "type": "string", - "enum": [ - "none", - "smart", - "all" - ] - } - ] - } - ] - } - ] -} diff --git a/packages/hermes-inspector-msggen/src/index.js b/packages/hermes-inspector-msggen/src/index.js deleted file mode 100644 index 761390faca7c07..00000000000000 --- a/packages/hermes-inspector-msggen/src/index.js +++ /dev/null @@ -1,283 +0,0 @@ -/** - * 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 {Command} from './Command'; -import {Event} from './Event'; -import {Graph} from './Graph'; -import {HeaderWriter} from './HeaderWriter'; -import {ImplementationWriter} from './ImplementationWriter'; -import {Property} from './Property'; -import {PropsType, Type} from './Type'; -import fs from 'fs'; -import yargs from 'yargs'; - -const custom = require('../src/custom.json'); -// $FlowFixMe[cannot-resolve-module] : this isn't a module, just a JSON file. -const standard = require('devtools-protocol/json/js_protocol.json'); - -type Descriptor = {| - types: Array, - commands: Array, - events: Array, -|}; - -function mergeDomains(original: any, extra: any) { - return {...original, domains: original.domains.concat(extra.domains)}; -} - -const proto = mergeDomains(standard, custom); - -function parseDomains( - domainObjs: Array, - ignoreExperimental: boolean, - includeExperimental: Set, -): Descriptor { - const desc = { - types: ([]: Array), - commands: ([]: Array), - events: ([]: Array), - }; - - for (const obj of domainObjs) { - const domain = obj.domain; - - for (const typeObj of obj.types || []) { - const type = Type.create( - domain, - typeObj, - ignoreExperimental, - includeExperimental, - ); - if (type) { - desc.types.push(type); - } - } - - for (const commandObj of obj.commands || []) { - const command = Command.create( - domain, - commandObj, - !includeExperimental.has(`${domain}.${commandObj.name}`) && - ignoreExperimental, - includeExperimental, - ); - if (command) { - desc.commands.push(command); - } - } - - for (const eventObj of obj.events || []) { - const event = Event.create( - domain, - eventObj, - ignoreExperimental, - includeExperimental, - ); - if (event) { - desc.events.push(event); - } - } - } - - return desc; -} - -function buildGraph(desc: Descriptor): Graph { - const graph = new Graph(); - - const types = desc.types; - const commands = desc.commands; - const events = desc.events; - - const maybeAddPropEdges = function (nodeId: string, props: ?Array) { - if (props) { - for (const prop of props) { - const refId = prop.getRefDebuggerName(); - (prop: Object).recursive = refId && refId === nodeId; - if (refId && refId !== nodeId) { - // Don't add edges for recursive properties. - graph.addEdge(nodeId, refId); - } - } - } - }; - - for (const type of types) { - graph.addNode(type.getDebuggerName()); - - if (type instanceof PropsType) { - maybeAddPropEdges(type.getDebuggerName(), type.properties); - } - } - - for (const command of commands) { - graph.addNode(command.getDebuggerName()); - - maybeAddPropEdges(command.getDebuggerName(), command.parameters); - maybeAddPropEdges(command.getDebuggerName(), command.returns); - } - - for (const event of events) { - graph.addNode(event.getDebuggerName()); - - maybeAddPropEdges(event.getDebuggerName(), event.parameters); - } - - return graph; -} - -function parseRoots(desc: Descriptor, rootsPath: ?string): Array { - const roots = []; - - if (rootsPath) { - const buf = fs.readFileSync(rootsPath); - for (let line of buf.toString().split('\n')) { - line = line.trim(); - - // ignore comments and blank lines - if (!line.match(/\s*#/) && line.length > 0) { - roots.push(line); - } - } - } else { - for (const type of desc.types) { - roots.push(type.getDebuggerName()); - } - for (const command of desc.commands) { - roots.push(command.getDebuggerName()); - } - for (const event of desc.events) { - roots.push(event.getDebuggerName()); - } - } - - return roots; -} - -// only include types, commands, events that can be reached from the given -// root messages -function filterReachableFromRoots( - desc: Descriptor, - graph: Graph, - roots: Array, -): Descriptor { - const traversal = graph.traverse(roots); - const topoSortedIds = traversal.nodes; - - // Types can include other types by value, so they need to be topologically - // sorted in the header. - const typeMap: Map = new Map(); - for (const type of desc.types) { - typeMap.set(type.getDebuggerName(), type); - } - - const types = []; - for (const id of topoSortedIds) { - const type = typeMap.get(id); - if (type) { - types.push(type); - } - } - - const cycles: Set = new Set(); - for (const cycle of traversal.cycles) { - const from = typeMap.get(cycle.from); - const to = typeMap.get(cycle.to); - if (from && to) { - cycles.add(from.id + ' > ' + to.id); - } - } - - for (const type of types) { - if (type instanceof PropsType) { - for (const prop of type.properties) { - const ref = (prop: Object).$ref; - if (ref) { - const cycleKey = `${type.id} > ${ref}`; - if (cycles.has(cycleKey)) { - (prop: Object).cyclical = true; - } - } - } - } - } - - // Commands and events don't depend on each other, so just emit them in the - // order we got them from the JSON file. - const ids = new Set(topoSortedIds); - const commands = desc.commands.filter(cmd => ids.has(cmd.getDebuggerName())); - const events = desc.events.filter(event => ids.has(event.getDebuggerName())); - - // Sort commands and events so the code is easier to read. Types have to be - // topologically sorted as explained above. - const comparator = (a: Command | Event, b: Command | Event) => { - const id1 = a.getDebuggerName(); - const id2 = b.getDebuggerName(); - return id1 < id2 ? -1 : id1 > id2 ? 1 : 0; - }; - commands.sort(comparator); - events.sort(comparator); - - return {types, commands, events}; -} - -async function main(): Promise { - const args = await yargs - .usage('Usage: msggen ') - .alias('h', 'help') - .help('h') - .boolean('e') - .alias('e', 'ignore-experimental') - .describe('e', 'ignore experimental commands, props, and types') - .alias('i', 'include-experimental') - .describe('i', 'experimental commands to include') - .alias('r', 'roots') - .describe('r', 'path to a file listing root types, events, and commands') - .nargs('r', 1) - .demandCommand(2, 2).argv; - - const ignoreExperimental = !!args.e; - const includeExperimental = new Set( - typeof args.i === 'string' ? args.i.split(',') : [], - ); - const [headerPath, implPath] = args._; - - const headerStream = fs.createWriteStream(headerPath); - const implStream = fs.createWriteStream(implPath); - - const desc = parseDomains( - proto.domains, - ignoreExperimental, - includeExperimental, - ); - const graph = buildGraph(desc); - const roots = parseRoots(desc, String(args.roots)); - - const reachable = filterReachableFromRoots(desc, graph, roots); - - const hw = new HeaderWriter( - headerStream, - reachable.types, - reachable.commands, - reachable.events, - ); - hw.write(); - - const iw = new ImplementationWriter( - implStream, - reachable.types, - reachable.commands, - reachable.events, - ); - iw.write(); -} - -// $FlowFixMe[unused-promise] -main(); diff --git a/yarn.lock b/yarn.lock index 716ec0b8d6b0f2..4e6b3efc494bc0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,22 +10,6 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@babel/cli@^7.24.8": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.25.6.tgz#bc35561adc78ade43ac9c09a690768493ab9ed95" - integrity sha512-Z+Doemr4VtvSD2SNHTrkiFZ1LX+JI6tyRXAAOb4N9khIuPyoEPmTPJarPm8ljJV1D6bnMQjyHMWTT9NeKbQuXA== - dependencies: - "@jridgewell/trace-mapping" "^0.3.25" - commander "^6.2.0" - convert-source-map "^2.0.0" - fs-readdir-recursive "^1.1.0" - glob "^7.2.0" - make-dir "^2.1.0" - slash "^2.0.0" - optionalDependencies: - "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" - chokidar "^3.6.0" - "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" @@ -1589,11 +1573,6 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": - version "2.1.8-no-fsevents.3" - resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" - integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== - "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": version "5.1.1-v1" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" @@ -2478,7 +2457,7 @@ ansi-styles@^6.0.0, ansi-styles@^6.2.1: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -anymatch@^3.0.3, anymatch@~3.1.2: +anymatch@^3.0.3: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== @@ -2879,11 +2858,6 @@ before-after-hook@^2.2.0: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ== -binary-extensions@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" - integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== - bl@^4.0.3, bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -2908,7 +2882,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.3, braces@~3.0.2: +braces@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -3083,21 +3057,6 @@ charm@^1.0.2: dependencies: inherits "^2.0.1" -chokidar@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" - integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - chownr@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" @@ -3296,11 +3255,6 @@ commander@^2.12.1, commander@^2.18.0, commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" - integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== - commander@^9.4.1: version "9.5.0" resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" @@ -3680,11 +3634,6 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -devtools-protocol@0.0.1107588: - version "0.0.1107588" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1107588.tgz#f8cac707840b97cc30b029359341bcbbb0ad8ffa" - integrity sha512-yIR+pG9x65Xko7bErCUSQaDLrO/P1p3JUzEk7JCU4DowPcGHkTGUGQapcfcLc4qj0UaALwZ+cr0riFgiqpixcg== - diff-sequences@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" @@ -4553,17 +4502,12 @@ fs-minipass@^2.0.0: dependencies: minipass "^3.0.0" -fs-readdir-recursive@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" - integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2, fsevents@~2.3.2: +fsevents@^2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -4685,7 +4629,7 @@ git-config-path@^1.0.1: fs-exists-sync "^0.1.0" homedir-polyfill "^1.0.0" -glob-parent@^5.1.2, glob-parent@~5.1.2: +glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -4699,7 +4643,7 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^7.0.0, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.2.0: +glob@^7.0.0, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -5134,13 +5078,6 @@ is-bigint@^1.0.1: dependencies: has-bigints "^1.0.1" -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - is-boolean-object@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" @@ -5243,7 +5180,7 @@ is-generator-function@^1.0.10: dependencies: has-tostringtag "^1.0.0" -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -6818,7 +6755,7 @@ node-stream-zip@^1.9.1: semver "^7.3.4" validate-npm-package-license "^3.0.1" -normalize-path@^3.0.0, normalize-path@~3.0.0: +normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== @@ -7180,7 +7117,7 @@ picocolors@^1.0.0, picocolors@^1.0.1: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -7431,13 +7368,6 @@ readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - readline-sync@^1.4.9: version "1.4.10" resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.10.tgz#41df7fbb4b6312d673011594145705bf56d8873b" @@ -7953,11 +7883,6 @@ sisteransi@^1.0.5: resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"