mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
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
This commit is contained in:
committed by
Facebook GitHub Bot
parent
f20486cc77
commit
3e0fc8899b
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"presets": [ "@babel/preset-flow", ["@babel/preset-env", {
|
||||
"targets": {
|
||||
"node": "current"
|
||||
}
|
||||
}]
|
||||
],
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
.DS_Store
|
||||
bin/
|
||||
node_modules/
|
||||
@@ -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`.
|
||||
@@ -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;',
|
||||
]);
|
||||
});
|
||||
@@ -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;']);
|
||||
});
|
||||
@@ -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');
|
||||
});
|
||||
@@ -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 <code>Debugger.scriptParsed</code>.' },
|
||||
{ '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<int> 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{};
|
||||
};
|
||||
`);
|
||||
});
|
||||
@@ -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 <code>Debugger.scriptParsed</code>.' },
|
||||
{ '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;
|
||||
}
|
||||
`);
|
||||
});
|
||||
@@ -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<double>');
|
||||
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<runtime::ExceptionDetails>');
|
||||
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<runtime::StackTrace>');
|
||||
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<std::vector<std::string>>');
|
||||
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<schema::Domain>');
|
||||
expect(prop.getCppIdentifier()).toBe('domains');
|
||||
expect(prop.getInitializer()).toBe('');
|
||||
});
|
||||
@@ -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 <code>Debugger.scriptParsed</code>.' },
|
||||
{ '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;']);
|
||||
});
|
||||
@@ -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": {
|
||||
".*": "<rootDir>/node_modules/babel-jest"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Property>;
|
||||
returns: Array<Property>;
|
||||
|
||||
static create(
|
||||
domain: string,
|
||||
obj: any,
|
||||
ignoreExperimental: boolean,
|
||||
includeExperimental: Set<string>,
|
||||
): ?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<string>,
|
||||
) {
|
||||
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<string> {
|
||||
const decls = [`struct ${this.getRequestCppType()};`];
|
||||
const respCppType = this.getResponseCppType();
|
||||
if (respCppType) {
|
||||
decls.push(`struct ${respCppType};`);
|
||||
}
|
||||
return decls;
|
||||
}
|
||||
|
||||
getForwardDeclSortKey(): string {
|
||||
return this.getRequestCppType();
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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<Property>;
|
||||
|
||||
static create(
|
||||
domain: string,
|
||||
obj: any,
|
||||
ignoreExperimental: boolean,
|
||||
includeExperimental: Set<string>,
|
||||
): ?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<string>,
|
||||
) {
|
||||
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<string> {
|
||||
return [`struct ${this.getCppType()};`];
|
||||
}
|
||||
|
||||
getForwardDeclSortKey(): string {
|
||||
return this.getCppType();
|
||||
}
|
||||
}
|
||||
@@ -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 <<SignedSource::*O*zOeWoEQle#+L!plEphiEmie@IsG>>';
|
||||
@@ -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<Node>;
|
||||
state: 'none' | 'visiting' | 'visited';
|
||||
|
||||
constructor(id: NodeId) {
|
||||
this.id = id;
|
||||
this.children = new Set();
|
||||
this.state = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
export class Graph {
|
||||
nodes: Map<NodeId, Node>;
|
||||
|
||||
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<NodeId>): {
|
||||
nodes: Array<NodeId>,
|
||||
cycles: Array<NodeCycle>,
|
||||
} {
|
||||
// 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<NodeId> = [];
|
||||
const cycles: Array<NodeCycle> = [];
|
||||
postorder(root, nodes, cycles);
|
||||
|
||||
// remove fake root node
|
||||
nodes.splice(-1);
|
||||
|
||||
return {nodes: nodes, cycles: cycles};
|
||||
}
|
||||
}
|
||||
|
||||
function postorder(node: Node, nodes: Array<NodeId>, cycles: Array<NodeCycle>) {
|
||||
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);
|
||||
}
|
||||
@@ -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<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-modern/chrome/MessageInterfaces.h>
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace facebook {
|
||||
namespace hermes {
|
||||
namespace inspector_modern {
|
||||
namespace chrome {
|
||||
namespace message {
|
||||
|
||||
template<typename T>
|
||||
void deleter(T* p);
|
||||
`);
|
||||
}
|
||||
|
||||
writeForwardDecls() {
|
||||
this.stream.write('struct UnknownRequest;\n\n');
|
||||
|
||||
const namespaceMap: Map<string, Array<Type | Command | Event>> = 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<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;
|
||||
${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<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;
|
||||
std::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');
|
||||
}
|
||||
@@ -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<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.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<Command>) {
|
||||
stream.write(`
|
||||
using RequestBuilder = std::unique_ptr<Request> (*)(const dynamic &);
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
std::unique_ptr<Request> makeUnique(const dynamic &obj) {
|
||||
return std::make_unique<T>(obj);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<Request> Request::fromJsonThrowOnError(const std::string &str) {
|
||||
static std::unordered_map<std::string, RequestBuilder> 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<UnknownRequest>(obj);
|
||||
}
|
||||
|
||||
auto builder = it->second;
|
||||
return builder(obj);
|
||||
}
|
||||
|
||||
folly::Try<std::unique_ptr<Request>> 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`);
|
||||
}
|
||||
@@ -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<any>,
|
||||
ignoreExperimental: boolean,
|
||||
includeExperimental: Set<string>,
|
||||
): Array<Property> {
|
||||
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<void(${type}*)>>`;
|
||||
} 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 '';
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<string>,
|
||||
): ?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<string> {
|
||||
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<string> {
|
||||
return [`using ${this.getCppType()} = ${jsTypeToCppType(this.type)};`];
|
||||
}
|
||||
}
|
||||
|
||||
export class PropsType extends Type {
|
||||
type: 'object';
|
||||
properties: Array<Property>;
|
||||
|
||||
constructor(
|
||||
domain: string,
|
||||
obj: any,
|
||||
ignoreExperimental: boolean,
|
||||
includeExperimental: Set<string>,
|
||||
) {
|
||||
super(domain, obj);
|
||||
this.type = obj.type;
|
||||
this.properties = Property.createArray(
|
||||
domain,
|
||||
obj.id,
|
||||
obj.properties || [],
|
||||
ignoreExperimental,
|
||||
includeExperimental,
|
||||
);
|
||||
}
|
||||
|
||||
getForwardDecls(): Array<string> {
|
||||
return [`struct ${this.getCppType()};`];
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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<Type>,
|
||||
commands: Array<Command>,
|
||||
events: Array<Event>,
|
||||
|};
|
||||
|
||||
function mergeDomains(original: any, extra: any) {
|
||||
return {...original, domains: original.domains.concat(extra.domains)};
|
||||
}
|
||||
|
||||
const proto = mergeDomains(standard, custom);
|
||||
|
||||
function parseDomains(
|
||||
domainObjs: Array<any>,
|
||||
ignoreExperimental: boolean,
|
||||
includeExperimental: Set<string>,
|
||||
): Descriptor {
|
||||
const desc = {
|
||||
types: ([]: Array<Type>),
|
||||
commands: ([]: Array<Command>),
|
||||
events: ([]: Array<Event>),
|
||||
};
|
||||
|
||||
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<Property>) {
|
||||
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<string> {
|
||||
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<string>,
|
||||
): 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<string, Type> = 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<string> = 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<void> {
|
||||
const args = await yargs
|
||||
.usage('Usage: msggen <header_path> <cpp_path>')
|
||||
.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();
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user