diff --git a/lib/client/es2015/node/channel.js b/lib/client/es2015/node/channel.js index 9ac9c3b7e..0ac192ac8 100644 --- a/lib/client/es2015/node/channel.js +++ b/lib/client/es2015/node/channel.js @@ -7,10 +7,10 @@ const global_Error = Error; const mapping = { __proto__: null, "1.0": ["http1.0", "1"], - "1.1": ["http1.1", "1"] - "2": ["http2-prior-knowledge", "2"], - "2.0": ["http2-prior-knowledge", "2"] - "3": ["http3", "3"] + 1.1: ["http1.1", "1"], + 2: ["http2-prior-knowledge", "2"], + "2.0": ["http2-prior-knowledge", "2"], + 3: ["http3", "3"], }; module.exports = (env) => { @@ -20,8 +20,10 @@ module.exports = (env) => { APPMAP_CHANNEL: "inline", APPMAP_HTTP_VERSION: "1.1", APPMAP_HOST: "localhost", - APPMAP_PORT: "8080" - }, env); + APPMAP_PORT: "8080", + }, + env + ); if (env.APPMAP_CHANNEL[0] === "/") { return require(env.APPMAP_CHANNEL); } @@ -29,19 +31,29 @@ module.exports = (env) => { return require("../../../../dist/inline-channel.js")(); } if (!(env.APPMAP_HTTP_VERSION in mapping)) { - throw new global_Error(`Invalid APPMAP_HTTP_VERSION environment variable, got: ${env.APPMAP_HTTP_VERSION}`); + throw new global_Error( + `Invalid APPMAP_HTTP_VERSION environment variable, got: ${env.APPMAP_HTTP_VERSION}` + ); } - const requestSync = require("./request/curl-sync.js")(mapping[env.APPMAP_HTTP_VERSION][0], env.APPMAP_HOST, env.APPMAP_PORT); + const requestSync = require("./request/curl-sync.js")( + mapping[env.APPMAP_HTTP_VERSION][0], + env.APPMAP_HOST, + env.APPMAP_PORT + ); let requestAsync; if (env.APPMAP_CHANNEL === "http") { - requestAsync = require(`./request/http${mapping[env.APPMAP_HTTP_VERSION][1]}-async.js`)(env.APPMAP_HOST, env.APPMAP_PORT); + requestAsync = require(`./request/http${ + mapping[env.APPMAP_HTTP_VERSION][1] + }-async.js`)(env.APPMAP_HOST, env.APPMAP_PORT); } else if (env.APPMAP_CHANNEL === "fork") { requestAsync = require(`./request/fork-async.js`)(); } else { - throw new global_Error(`Invalid APPMAP_CHANNEL environment variable, got: ${env.APPMAP_CHANNEL}`); + throw new global_Error( + `Invalid APPMAP_CHANNEL environment variable, got: ${env.APPMAP_CHANNEL}` + ); } return { requestSync, - requestAsync + requestAsync, }; }; diff --git a/lib/client/es2015/node/setup.js b/lib/client/es2015/node/setup.js index 8d8c3a4da..0cd06b426 100644 --- a/lib/client/es2015/node/setup.js +++ b/lib/client/es2015/node/setup.js @@ -7,27 +7,24 @@ const global_Object_assign = Object.assign; const global_Error = Error; module.exports = (process) => { + const { requestSync, requestAsync } = makeChannel(env); - const {requestSync, requestAsync} = makeChannel(env); - - const {session, prefix} = requestSync( - { - name: "initialize", - init: { - env: process.env, - pid: process.pid, - engine: `node@${process.version}`, - feature: "TODO", - feature_group: "TODO", - labels: ["TODO"], - frameworks: ["TODO"], - recording: { - defined_class: "TODO", - method_id: "TODO", - } - } - } - ); + const { session, prefix } = requestSync({ + name: "initialize", + init: { + env: process.env, + pid: process.pid, + engine: `node@${process.version}`, + feature: "TODO", + feature_group: "TODO", + labels: ["TODO"], + frameworks: ["TODO"], + recording: { + defined_class: "TODO", + method_id: "TODO", + }, + }, + }); VirtualMachine.runInThisContext( FileSystem.readFileSync( @@ -40,7 +37,9 @@ module.exports = (process) => { ); /* eslint-disable no-eval */ - eval(`${prefix}_GLOBAL_EMIT = (event) => requestAsync({name:"emit", session, event}, null);`); + eval( + `${prefix}_GLOBAL_EMIT = (event) => requestAsync({name:"emit", session, event}, null);` + ); eval(`${prefix}_GLOBAL_PID = process.id;`); /* eslint-enable no-eval */ @@ -52,7 +51,7 @@ module.exports = (process) => { requestSync({ name: "terminate", session, - reason + reason, }); } }; @@ -85,20 +84,24 @@ module.exports = (process) => { return { instrumentModule: (path, content, pending) => { - requestAsync({ + requestAsync( + { + name: "instrument", + session, + source: "module", + path, + content, + }, + pending + ); + }, + instrumentScript: (path, content) => + requestSync({ name: "instrument", session, - source: "module", + source: "script", path, - content - }, pending); - }, - instrumentScript: (path, content) => requestSync({ - name: "instrument", - session, - source: "script", - path, - content - }); + content, + }), }; }; diff --git a/lib/server/dispatcher.mjs b/lib/server/dispatcher.mjs index 4f8ecda7e..97798bb34 100644 --- a/lib/server/dispatcher.mjs +++ b/lib/server/dispatcher.mjs @@ -1,6 +1,5 @@ - -import logger from "./logger.mjs"; -import Appmap from "./appmap/index.mjs"; +import logger from './logger.mjs'; +import Appmap from './appmap/index.mjs'; const checkHas = (object, key) => { if (Reflect.getOwnPropertyDescriptor(object, key) === undefined) { @@ -10,70 +9,72 @@ const checkHas = (object, key) => { const checkNotNull = (any) => { if (any === null) { - throw new Error("Unexpected null"); + throw new Error('Unexpected null'); } }; const checkTypeof = (value, type) => { if (typeof value !== type) { - throw new Error(`Invalid value type: expected a ${type} and got a ${typeof value}`); + throw new Error( + `Invalid value type: expected a ${type} and got a ${typeof value}`, + ); } }; const checkAnyof = (value, values) => { if (!values.includes(value)) { - throw new Error("Invalid enumeration-based value"); + throw new Error('Invalid enumeration-based value'); } }; -const sources = ["script", "module"]; +const sources = ['script', 'module']; export default (class Dispatcher { - constructor (config) { + constructor(config) { this.config = config; - this.appmaps = {__proto__:null}; - }, - dispatch (json) { - checkTypeof(json, "object"); + this.appmaps = { __proto__: null }; + } + dispatch(json) { + checkTypeof(json, 'object'); checkNotNull(json); - checkHas(json, "name"); - if (json.name === "initialize") { - checkHas(json, "init"); - let session + checkHas(json, 'name'); + if (json.name === 'initialize') { + checkHas(json, 'init'); + let session; do { - session = Math.random().toString(36).substring(2) + session = Math.random().toString(36).substring(2); } while (session in this.appmaps); const appmap = new Appmap(this.config, json.init); this.appmaps[session] = appmap; return { session, - prefix: appmap.getEscapePrefix() + prefix: appmap.getEscapePrefix(), }; } - checkHas(json, "session"); - checkTypeof(json.session, "string"); + checkHas(json, 'session'); + checkTypeof(json.session, 'string'); checkHas(this.appmaps, json.session); const appmap = this.appmaps[json.session]; - if (json.name === "terminate") { - checkHas(json, "reason"); + if (json.name === 'terminate') { + checkHas(json, 'reason'); appmap.terminate(json.reason); - delete this.appmaps[json.session] + delete this.appmaps[json.session]; return null; } - if (json.name === "instrument") { - checkHas(json, "source"); - checkHas(json, "path"); - checkHas(json, "content"); + if (json.name === 'instrument') { + checkHas(json, 'source'); + checkHas(json, 'path'); + checkHas(json, 'content'); checkAnyof(json.source, sources); - checkTypeof(json.path, "string"); - checkTypeof(json.content, "string"); + checkTypeof(json.path, 'string'); + checkTypeof(json.content, 'string'); return appmap.instrument(json.source, json.path, json.content); } - if (json.name === "emit") { - checkHas(json, "event"); + if (json.name === 'emit') { + checkHas(json, 'event'); appmap.emit(json.event); return null; } - throw new Error("Unrecognized name"); + throw new Error('Unrecognized name'); } }); diff --git a/lib/server/inline/channel.mjs b/lib/server/inline/channel.mjs index e05fd3eb7..05807f593 100644 --- a/lib/server/inline/channel.mjs +++ b/lib/server/inline/channel.mjs @@ -1,5 +1,5 @@ -import { getDefaultConfig } from './config.mjs'; -import { makeDispatch } from './dispatch.mjs'; -import { makeChannel } from './response/inline.mjs'; +import { getDefaultConfig } from '../config.mjs'; +import { makeDispatch } from '../dispatch.mjs'; +import { makeChannel } from './response.mjs'; export default () => makeChannel(makeDispatch(getDefaultConfig())); diff --git a/lib/server/inline/main.mjs b/lib/server/inline/main.mjs index 73b929569..24fb0b368 100644 --- a/lib/server/inline/main.mjs +++ b/lib/server/inline/main.mjs @@ -30,7 +30,7 @@ export default (argv, stdio) => { }, { __proto__: null }, ), - APPMAP_CHANNEL: "inline" + APPMAP_CHANNEL: 'inline', }; if (Reflect.getOwnPropertyDescriptor(argv, 'esm') && argv.esm) { let name; diff --git a/lib/server/inline/response.mjs b/lib/server/inline/response.mjs index 65c570be3..ad0a63409 100644 --- a/lib/server/inline/response.mjs +++ b/lib/server/inline/response.mjs @@ -1,12 +1,11 @@ - -import logger from "../../logger.mjs"; +import logger from '../../logger.mjs'; export const makeChannel = (dispatcher) => ({ requestSync: (json1) => { logger.info(); const json2 = dispatcher.dispatch(json1); logger.info(); - }; + }, requestAsync: (json1, pending) => { logger.info(); if (pending === null) { @@ -24,5 +23,5 @@ export const makeChannel = (dispatcher) => ({ logger.info(json2); pending.resolve(json2); } - } + }, }); diff --git a/lib/server/main.mjs b/lib/server/main.mjs index 9f2b0e139..696377920 100644 --- a/lib/server/main.mjs +++ b/lib/server/main.mjs @@ -1,73 +1,111 @@ - -import { fork } from "child_process"; -import { makeServer as createHttp1Server } from "./response/http1.mjs"; -import { makeServer as createHttp2Server } from "./response/http2.mjs"; -import { registerChild } from "./response/fork.mjs"; -import home from "../../../home.js"; +import { fork } from 'child_process'; +import { makeServer as createHttp1Server } from './response/http1.mjs'; +import { makeServer as createHttp2Server } from './response/http2.mjs'; +import { registerChild } from './response/fork.mjs'; +import home from '../../../home.js'; const mapping = { - "1": createHttp1Server, - "1.0": createHttp1Server, - "1.1": createHttp1Server, - "2": createHttp2Server, - "2.0": createHttp2Server + 1: createHttp1Server, + '1.0': createHttp1Server, + 1.1: createHttp1Server, + 2: createHttp2Server, + '2.0': createHttp2Server, }; -export default = (env) => { +export default (env) => { + const dispatcher = new Dispatcher(getDefaultConfig().extendWithEnv(env)); env = { - APPMAP_PORT: "8080", - APPMAP_HTTP_VERSION: "1.1", - ...env + APPMAP_PORT: '8080', + APPMAP_HTTP_VERSION: '1.1', + ...env, }; - const dispatcher = new Dispatcher(getDefaultConfig().extendWithEnv(env)); if (!(env.APPMAP_HTTP_VERSION in mapping)) { - logger.warning("Unrecognized APPMAP_HTTP_VERSION, defaulting to 1.1 and got: %s", env.APPMAP_HTTP_VERSION); - env.APPMAP_HTTP_VERSION = "1.1"; + logger.warning( + 'Unrecognized APPMAP_HTTP_VERSION, defaulting to 1.1 and got: %s', + env.APPMAP_HTTP_VERSION, + ); + env.APPMAP_HTTP_VERSION = '1.1'; } const server = mapping[env.APPMAP_HTTP_VERSION](dispatcher); server.listen(env.APPMAP_PORT); return { server, fork: (path, argv, options) => { - const ecma = "es2015"; - if (Reflect.getOwnPropertyDescriptor(options, "ecma") !== undefined) { - if (options.ecma !== "es2015") { - logger.warning("At the moment only options.ecma es2015 is supported, got: %s", options.ecma); + const options = { + __proto__: null, + ...options, + }; + const ecma = 'es2015'; + if ('ecma' in options) { + if (options.ecma !== 'es2015') { + logger.warning( + 'At the moment only options.ecma es2015 is supported, got: %s', + options.ecma, + ); } } const execArgv = []; - if (Reflect.getOwnPropertyDescriptor(options, "esm") !== undefined && options.esm) { - execArgv.push("--experimental-loader"); - if (Reflect.getOwnPropertyDescriptor(options, "cjs") !== undefined && options.cjs) { - logger.info("Instrumenting both esm and cjs modules on %s", path); - execArgv.push(Path.join(home, "client", ecma, "node", "main-both.js")); + if (options.esm) { + execArgv.push('--experimental-loader'); + if (options.cjs) { + logger.info('Instrumenting both esm and cjs modules on %s', path); + execArgv.push( + Path.join(home, 'client', ecma, 'node', 'main-both.js'), + ); } else { - logger.info("Instrumenting only esm modules on %s", path); - execArgv.push(Path.join(home, "client", ecma, "node", "main-esm.js")); + logger.info('Instrumenting only esm modules on %s', path); + execArgv.push(Path.join(home, 'client', ecma, 'node', 'main-esm.js')); } - } else if (Reflect.getOwnPropertyDescriptor(options, "cjs") !== undefined && options.cjs) { - logger.info("Instrumenting only cjs modules on %s", path); - execArgv.push("--require"); - execArgv.push(Path.join(home, "client", ecma, "node", "main-cjs.js")); + } else if (options.cjs) { + logger.info('Instrumenting only cjs modules on %s', path); + execArgv.push('--require'); + execArgv.push(Path.join(home, 'client', ecma, 'node', 'main-cjs.js')); } else { - logger.warning("Not instrumenting anything because options.cjs and options.esm are both falsy"); + logger.warning( + 'Not instrumenting anything because options.cjs and options.esm are both falsy', + ); } - if (Reflect.getOwnPropertyDescriptor(options, "execArgv") !== undefined) { + if ('execArgv' in options) { execArgv.push(...options.execArgv); } + const env1 = { + ...('env' in options ? options.env : process.env), + }; + const env2 = { + __proto__: null, + APPMAP_CHANNEL: 'fork', + APPMAP_HOST: 'localhost', + APPMAP_PORT: String(env.APPMAP_PORT), + APPMAP_HTTP_VERSION: env.APPMAP_HTTP_VERSION, + }; + for (let key in env1) { + if (!key.startsWith('APPMAP_') || env1[key] !== env[key]) { + env2[key] = env1[key]; + } + } + const env1 = { __proto__: null }; + if ('env' in options) { + env = { + __proto__: null, + ...options, + }; + } else { + } const child = ChildProcess.fork(path, argv, { ...options, execArgv, env: { - ...Reflect.getOwnPropertyDescriptor(options, "env") === undefined ? process.env : options.env, - APPMAP_CHANNEL: "fork", - APPMAP_HOST: "localhost", + ...(Reflect.getOwnPropertyDescriptor(options, 'env') === undefined + ? process.env + : options.env), + APPMAP_CHANNEL: 'fork', + APPMAP_HOST: 'localhost', APPMAP_PORT: String(env.APPMAP_PORT), APPMAP_HTTP_VERSION: env.APPMAP_HTTP_VERSION, - } + }, }); registerChild(child, dispatcher); return child; - } - } + }, + }; };