diff --git a/.eslintrc.yaml b/.eslintrc.yaml index e6b916af4..e142567fe 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -52,7 +52,7 @@ rules: # complexity # computed-property-spacing: [error, never] >> Prettier consistent-return: error - consistent-this: [error, self] + consistent-this: [error, that] # constructor-super: error >> Class are disabled by no-restricted-syntax curly: [error, all] # default-case >> SwitchStatement disabled by no-restricted-syntax diff --git a/components/.ordering b/components/.ordering index 2a9f7eb3f..0981e2b95 100644 --- a/components/.ordering +++ b/components/.ordering @@ -15,6 +15,7 @@ hash patch peer file +load time group prompts diff --git a/components/agent/default/index.mjs b/components/agent/default/index.mjs index 029359c6f..b48305efd 100644 --- a/components/agent/default/index.mjs +++ b/components/agent/default/index.mjs @@ -28,7 +28,6 @@ import { formatResolvePayload as formatFrontendResolvePayload, formatRejectPayload as formatFrontendRejectPayload, formatYieldPayload as formatFrontendYieldPayload, - formatResumePayload as formatFrontendResumePayload, formatRequestPayload as formatFrontendRequestPayload, formatResponsePayload as formatFrontendResponsePayload, formatQueryPayload as formatFrontendQueryPayload, @@ -177,9 +176,6 @@ export const formatRejectPayload = generateFormatPayload( export const formatYieldPayload = generateFormatPayload( formatFrontendYieldPayload, ); -export const formatResumePayload = generateFormatPayload( - formatFrontendResumePayload, -); export const formatRequestPayload = generateFormatPayload( formatFrontendRequestPayload, ); diff --git a/components/classmap/default/module.mjs b/components/classmap/default/module.mjs index dd66df94a..f95ba0bf6 100644 --- a/components/classmap/default/module.mjs +++ b/components/classmap/default/module.mjs @@ -62,7 +62,13 @@ export const createModule = ({ }; export const lookupModuleClosure = ( - { estree: { filename }, infos, references }, + { + estree: { + loc: { filename }, + }, + infos, + references, + }, position, ) => { const position_string = stringifyPosition(position); diff --git a/components/command/node/index.mjs b/components/command/node/index.mjs index 2a841988a..d5a8ae990 100644 --- a/components/command/node/index.mjs +++ b/components/command/node/index.mjs @@ -111,7 +111,7 @@ export const compileConfigurationCommandAsync = async (configuration, env) => { const { "recursive-process-recording": recursive, recorder, - agent: { directory }, + agent: { directory: self }, command: { tokens }, "command-options": options, } = configuration; @@ -125,13 +125,13 @@ export const compileConfigurationCommandAsync = async (configuration, env) => { (recorder_recursive === null || recorder_recursive === recursive) && name === recorder, ); - const [exec, ...argv] = await hookCommandAsync(tokens, directory); + const [exec, ...argv] = await hookCommandAsync(tokens, self, options.cwd); return { exec, argv, options: { ...options, - env: hookEnvironment(env, directory), + env: hookEnvironment(env, self, options.cwd), }, }; }; diff --git a/components/command/node/jest-config.mjs b/components/command/node/jest-config.mjs index 71d485478..1ace955bd 100644 --- a/components/command/node/jest-config.mjs +++ b/components/command/node/jest-config.mjs @@ -3,54 +3,21 @@ import { createRequire } from "node:module"; import { hasOwnProperty } from "../../util/index.mjs"; import { logError, logDebug } from "../../log/index.mjs"; import { ExternalAppmapError } from "../../error/index.mjs"; -import { self_directory } from "../../self/index.mjs"; -import { - convertFileUrlToPath, - convertPathToFileUrl, -} from "../../path/index.mjs"; -import { getLastUrlExtension, toAbsoluteUrl } from "../../url/index.mjs"; +import { loadAsync, isLoadMissingError } from "../../load/index.mjs"; +import { convertPathToFileUrl } from "../../path/index.mjs"; +import { toAbsoluteUrl } from "../../url/index.mjs"; const { URL, JSON: { parse: parseJSON }, } = globalThis; -// The location of require does not matter because it will only load file urls. -const require = createRequire(self_directory); - -const loadConfigModuleAsync = async (url) => { - if (getLastUrlExtension(url) === ".mjs") { - return (await import(new URL(url))).default; - } else { - return require(convertFileUrlToPath(url)); - } -}; - const loadConfigFileAsync = async (url, strict) => { try { - if (getLastUrlExtension(url) === ".json") { - return parseJSON(await readFileAsync(new URL(url), "utf8")); - } else { - const config = await loadConfigModuleAsync(url); - if (typeof config === "function") { - return await config(); - } else { - return config; - } - } + return await loadAsync(url); } catch (error) { - if ( - hasOwnProperty(error, "code") && - (error.code === "ENOENT" || - error.code === "ERR_MODULE_NOT_FOUND" || - error.code === "MODULE_NOT_FOUND") - ) { - if (strict) { - logError("Cannot find jest configuration file at %j", url); - throw new ExternalAppmapError("Cannot find jest configuration file"); - } else { - return null; - } + if (!strict && isLoadMissingError(error)) { + return null; } else { logError( "Failed to load jest configuration file at %j >> %O", diff --git a/components/command/node/jest-config.test.mjs b/components/command/node/jest-config.test.mjs index 08fbb3723..b5f720ad6 100644 --- a/components/command/node/jest-config.test.mjs +++ b/components/command/node/jest-config.test.mjs @@ -13,12 +13,7 @@ const { URL } = globalThis; const home = toAbsoluteUrl(`${getUuid()}/`, getTmpUrl()); await mkdirAsync(new URL(home)); -////////////////////// -// Explicit >> JSON // -////////////////////// - -// Missing // - +// Explicit >> Missing // await assertReject( loadJestConfigAsync( { @@ -29,38 +24,27 @@ await assertReject( root: "file:///A:/root/", }, ), - /^ExternalAppmapError: Cannot find jest configuration file$/u, -); - -// Invalid // - -await writeFileAsync( - new URL("invalid.config.json", home), - "invalid-json", - "utf8", + /^ExternalAppmapError: Failed to load jest configuration file$/u, ); -await assertReject( - loadJestConfigAsync( - { - config: "invalid.config.json", - }, +// Implicit >> Missing // +assertDeepEqual( + await loadJestConfigAsync( + {}, { - base: home, - root: "file:///A:/root/", + base: "file:///A:/base/", + root: home, }, ), - /^ExternalAppmapError: Failed to load jest configuration file$/u, + {}, ); -// Valid // - +// Explicit >> Present // await writeFileAsync( new URL("valid.config.json", home), `{"filename": "valid.config.json"}`, "utf8", ); - assertDeepEqual( await loadJestConfigAsync( { @@ -74,167 +58,17 @@ assertDeepEqual( { filename: "valid.config.json" }, ); -///////////////////// -// Explicit >> CJS // -///////////////////// - -// Missing // - -await assertReject( - loadJestConfigAsync( - { - config: "missing.config.cjs", - }, - { - base: home, - root: "file:///A:/root/", - }, - ), - /^ExternalAppmapError: Cannot find jest configuration file$/u, -); - -// Invalid // - -await writeFileAsync( - new URL("invalid.config.cjs", home), - "invalid cjs", - "utf8", -); - -await assertReject( - loadJestConfigAsync( - { - config: "invalid.config.cjs", - }, - { - base: home, - root: "file:///A:/root/", - }, - ), - /^ExternalAppmapError: Failed to load jest configuration file$/u, -); - -// Valid // - -await writeFileAsync( - new URL("valid.config.cjs", home), - ` - const { basename } = require("node:path"); - module.exports = { filename: basename(__filename) }; - `, - "utf8", -); - -assertDeepEqual( - await loadJestConfigAsync( - { - config: "valid.config.cjs", - }, - { - base: home, - root: "file:///A:/root/", - }, - ), - { filename: "valid.config.cjs" }, -); - -//////////////////// -// Explict >> ESM // -//////////////////// - -// Missing // - -await assertReject( - loadJestConfigAsync( - { - config: "missing.config.esm", - }, - { - base: home, - root: "file:///A:/root/", - }, - ), - /^ExternalAppmapError: Cannot find jest configuration file$/u, -); - -// Invalid // - -await writeFileAsync( - new URL("invalid.config.mjs", home), - "invalid esm", - "utf8", -); - -await assertReject( - loadJestConfigAsync( - { - config: "invalid.config.mjs", - }, - { - base: home, - root: "file:///A:/root/", - }, - ), - /^ExternalAppmapError: Failed to load jest configuration file$/u, -); - -// Valid // - -await writeFileAsync( - new URL("valid.config.mjs", home), - ` - import { basename } from "node:path"; - import { fileURLToPath } from "node:url"; - export default () => ({ - filename: basename(fileURLToPath(import.meta.url)), - }); - `, - "utf8", -); - -assertDeepEqual( - await loadJestConfigAsync( - { - config: "valid.config.mjs", - }, - { - base: home, - root: "file:///A:/root/", - }, - ), - { filename: "valid.config.mjs" }, -); - -////////////// -// Implicit // -////////////// - -// Missing // - -assertDeepEqual( - await loadJestConfigAsync( - {}, - { - base: "file:///A:/base/", - root: home, - }, - ), - {}, -); - -// Config // - +// Implicit >> Present // await writeFileAsync( new URL("jest.config.json", home), `{"filename": "jest.config.json"}`, "utf8", ); - assertDeepEqual( await loadJestConfigAsync( {}, { - base: "file:///A:/base/", + base: "file://A:/base/", root: home, }, ), @@ -281,7 +115,7 @@ assertDeepEqual( await assertReject( resolveJestPresetAsync({ preset: "./missing-jest-preset.json" }, home), - /^ExternalAppmapError: Cannot find jest configuration file$/u, + /^ExternalAppmapError: Failed to load jest configuration file$/u, ); await assertReject( diff --git a/components/command/node/jest.mjs b/components/command/node/jest.mjs index 13282d6e2..771f64231 100644 --- a/components/command/node/jest.mjs +++ b/components/command/node/jest.mjs @@ -1,10 +1,6 @@ -import { cwd } from "node:process"; import { coalesce } from "../../util/index.mjs"; -import { - convertFileUrlToPath, - convertPathToFileUrl, -} from "../../path/index.mjs"; -import { toAbsoluteUrl, toDirectoryUrl } from "../../url/index.mjs"; +import { convertFileUrlToPath } from "../../path/index.mjs"; +import { toAbsoluteUrl } from "../../url/index.mjs"; import { escapeNodeOption } from "./escape.mjs"; import { sniffTokens, splitTokens } from "./package.mjs"; import { hookJestArgvAsync } from "./jest-argv.mjs"; @@ -14,26 +10,23 @@ export const recursive = null; export const doesSupport = (tokens) => sniffTokens(tokens, "jest"); -export const hookCommandAsync = async (tokens, base) => { +export const hookCommandAsync = async (tokens, self, base) => { const { exec, argv } = splitTokens(tokens); return [ ...exec, - ...(await hookJestArgvAsync( - argv, - toDirectoryUrl(convertPathToFileUrl(cwd())), - )), + ...(await hookJestArgvAsync(argv, base)), "--setupFilesAfterEnv", - convertFileUrlToPath(toAbsoluteUrl("lib/node/recorder.mjs", base)), + convertFileUrlToPath(toAbsoluteUrl("lib/node/recorder.mjs", self)), ]; }; -export const hookEnvironment = (env, base) => ({ +export const hookEnvironment = (env, self, _base) => ({ ...env, NODE_OPTIONS: `${coalesce( env, "NODE_OPTIONS", "", )} --experimental-vm-modules --experimental-loader=${escapeNodeOption( - toAbsoluteUrl("lib/node/loader-esm.mjs", base), + toAbsoluteUrl("lib/node/loader-esm.mjs", self), )}`, }); diff --git a/components/command/node/jest.test.mjs b/components/command/node/jest.test.mjs index 2e0384366..15dde31db 100644 --- a/components/command/node/jest.test.mjs +++ b/components/command/node/jest.test.mjs @@ -8,14 +8,15 @@ const { JSON: { stringify: stringifyJSON }, } = globalThis; +const self = "file:///A:/self/"; const base = "file:///A:/base/"; const recorder_path = convertFileUrlToPath( - "file:///A:/base/lib/node/recorder.mjs", + "file:///A:/self/lib/node/recorder.mjs", ); const transformer_path = convertFileUrlToPath( toAbsoluteUrl("lib/node/transformer-jest.mjs", self_directory), ); -const loader_url = "file:///A:/base/lib/node/loader-esm.mjs"; +const loader_url = "file:///A:/self/lib/node/loader-esm.mjs"; ////////////////// // mocha --argv // @@ -23,7 +24,7 @@ const loader_url = "file:///A:/base/lib/node/loader-esm.mjs"; assertEqual(doesSupport(["jest", "--argv"]), true); -assertDeepEqual(await hookCommandAsync(["jest", "--argv"], base), [ +assertDeepEqual(await hookCommandAsync(["jest", "--argv"], self, base), [ "jest", "--argv", "--transform", @@ -44,7 +45,7 @@ assertDeepEqual(await hookCommandAsync(["jest", "--argv"], base), [ ///////////////////// assertDeepEqual( - hookEnvironment({ FOO: "bar", NODE_OPTIONS: "options" }, base), + hookEnvironment({ FOO: "bar", NODE_OPTIONS: "options" }, self, base), { FOO: "bar", NODE_OPTIONS: `options --experimental-vm-modules --experimental-loader=${loader_url}`, diff --git a/components/command/node/mocha.mjs b/components/command/node/mocha.mjs index 5000a9c0b..a8fd498ba 100644 --- a/components/command/node/mocha.mjs +++ b/components/command/node/mocha.mjs @@ -9,23 +9,23 @@ export const recursive = null; export const doesSupport = (tokens) => sniffTokens(tokens, "mocha"); -export const hookCommandAsync = (tokens, base) => { +export const hookCommandAsync = (tokens, self, _base) => { const { exec, argv } = splitTokens(tokens); return [ ...exec, "--require", - convertFileUrlToPath(toAbsoluteUrl("lib/node/mocha-hook.mjs", base)), + convertFileUrlToPath(toAbsoluteUrl("lib/node/mocha-hook.mjs", self)), ...argv, ]; }; -export const hookEnvironment = (env, base) => ({ +export const hookEnvironment = (env, self, _base) => ({ ...env, NODE_OPTIONS: `${coalesce( env, "NODE_OPTIONS", "", )} --experimental-loader=${escapeNodeOption( - toAbsoluteUrl("lib/node/recorder.mjs", base), + toAbsoluteUrl("lib/node/recorder.mjs", self), )}`, }); diff --git a/components/command/node/mocha.test.mjs b/components/command/node/mocha.test.mjs index 8d997df50..af842c222 100644 --- a/components/command/node/mocha.test.mjs +++ b/components/command/node/mocha.test.mjs @@ -2,16 +2,17 @@ import { assertDeepEqual, assertEqual } from "../../__fixture__.mjs"; import { fileURLToPath } from "node:url"; import { doesSupport, hookCommandAsync, hookEnvironment } from "./mocha.mjs"; +const self = "file:///A:/self/"; const base = "file:///A:/base/"; -const hook_path = fileURLToPath("file:///A:/base/lib/node/mocha-hook.mjs"); -const recorder_url = "file:///A:/base/lib/node/recorder.mjs"; +const hook_path = fileURLToPath("file:///A:/self/lib/node/mocha-hook.mjs"); +const recorder_url = "file:///A:/self/lib/node/recorder.mjs"; ////////////////// // mocha --argv // ////////////////// assertEqual(doesSupport(["mocha", "--argv"]), true); -assertDeepEqual(await hookCommandAsync(["mocha", "--argv"], base), [ +assertDeepEqual(await hookCommandAsync(["mocha", "--argv"], self, base), [ "mocha", "--require", hook_path, @@ -23,7 +24,7 @@ assertDeepEqual(await hookCommandAsync(["mocha", "--argv"], base), [ ///////////////////// assertDeepEqual( - hookEnvironment({ FOO: "bar", NODE_OPTIONS: "options" }, base), + hookEnvironment({ FOO: "bar", NODE_OPTIONS: "options" }, self, base), { FOO: "bar", NODE_OPTIONS: `options --experimental-loader=${recorder_url}`, diff --git a/components/command/node/node-recursive.mjs b/components/command/node/node-recursive.mjs index c534f4ecd..5bd96b82b 100644 --- a/components/command/node/node-recursive.mjs +++ b/components/command/node/node-recursive.mjs @@ -8,15 +8,15 @@ export const generateNodeRecorder = (recorder) => ({ name: recorder, recursive: true, doesSupport, - hookCommandAsync: (tokens, _base) => tokens, - hookEnvironment: (env, base) => ({ + hookCommandAsync: (tokens, _self, _base) => tokens, + hookEnvironment: (env, self, _base) => ({ ...env, NODE_OPTIONS: `${coalesce( env, "NODE_OPTIONS", "", )} --experimental-loader=${escapeNodeOption( - toAbsoluteUrl(`lib/node/recorder.mjs`, base), + toAbsoluteUrl(`lib/node/recorder.mjs`, self), )}`, }), }); diff --git a/components/command/node/node-recursive.test.mjs b/components/command/node/node-recursive.test.mjs index b6e1c5df7..2229363dd 100644 --- a/components/command/node/node-recursive.test.mjs +++ b/components/command/node/node-recursive.test.mjs @@ -5,7 +5,8 @@ const { name, recursive, doesSupport, hookCommandAsync, hookEnvironment } = generateNodeRecorder("process"); const base = "file:///A:/base/"; -const recorder_url = "file:///A:/base/lib/node/recorder.mjs"; +const self = "file:///A:/self/"; +const recorder_url = "file:///A:/self/lib/node/recorder.mjs"; assertEqual(name, "process"); @@ -13,10 +14,10 @@ assertEqual(recursive, true); assertEqual(doesSupport(["token"]), true); -assertDeepEqual(await hookCommandAsync(["token"], base), ["token"]); +assertDeepEqual(await hookCommandAsync(["token"], self, base), ["token"]); assertDeepEqual( - hookEnvironment({ FOO: "bar", NODE_OPTIONS: "options" }, base), + hookEnvironment({ FOO: "bar", NODE_OPTIONS: "options" }, self, base), { FOO: "bar", NODE_OPTIONS: `options --experimental-loader=${recorder_url}`, diff --git a/components/command/node/node.mjs b/components/command/node/node.mjs index 4635952df..baf25c7b4 100644 --- a/components/command/node/node.mjs +++ b/components/command/node/node.mjs @@ -26,14 +26,14 @@ export const generateNodeRecorder = (recorder) => ({ doesSupport, recursive: false, name: recorder, - hookCommandAsync: (tokens, base) => { + hookCommandAsync: (tokens, self, _base) => { const { exec, argv } = splitNodeCommand(tokens); return [ ...exec, "--experimental-loader", - toAbsoluteUrl(`lib/node/recorder.mjs`, base), + toAbsoluteUrl(`lib/node/recorder.mjs`, self), ...argv, ]; }, - hookEnvironment: (env, _base) => env, + hookEnvironment: (env, _self, _base) => env, }); diff --git a/components/command/node/node.test.mjs b/components/command/node/node.test.mjs index c13373a88..110314c1c 100644 --- a/components/command/node/node.test.mjs +++ b/components/command/node/node.test.mjs @@ -4,18 +4,19 @@ import { generateNodeRecorder } from "./node.mjs"; const { name, recursive, doesSupport, hookCommandAsync, hookEnvironment } = generateNodeRecorder("process"); +const self = "file:///A:/self/"; const base = "file:///A:/base/"; -const recorder_url = "file:///A:/base/lib/node/recorder.mjs"; +const recorder_url = "file:///A:/self/lib/node/recorder.mjs"; assertEqual(name, "process"); assertEqual(recursive, false); assertEqual(doesSupport(["node.ext", "main.mjs"]), true); -assertDeepEqual(await hookCommandAsync(["node.ext", "main.mjs"], base), [ +assertDeepEqual(await hookCommandAsync(["node.ext", "main.mjs"], self, base), [ "node.ext", "--experimental-loader", recorder_url, "main.mjs", ]); -assertDeepEqual(hookEnvironment({ FOO: "bar" }, base), { FOO: "bar" }); +assertDeepEqual(hookEnvironment({ FOO: "bar" }, self, base), { FOO: "bar" }); diff --git a/components/configuration-accessor/default/index.mjs b/components/configuration-accessor/default/index.mjs index d281ac056..935405dcc 100644 --- a/components/configuration-accessor/default/index.mjs +++ b/components/configuration-accessor/default/index.mjs @@ -117,7 +117,8 @@ export const isConfigurationEnabled = ({ processes, main, "default-process": default_process, -}) => main === null || lookupSpecifier(processes, main, default_process); +}) => + main === null || lookupSpecifier(processes, main, default_process).enabled; export const getConfigurationPackage = ( { packages, "default-package": default_package }, diff --git a/components/configuration/default/index.mjs b/components/configuration/default/index.mjs index cc9a92f9b..fe2601424 100644 --- a/components/configuration/default/index.mjs +++ b/components/configuration/default/index.mjs @@ -44,6 +44,17 @@ const extendCommandOptions = (options1, options2) => ({ // Normalize // /////////////// +const normalizeDefaultProcess = (default_process, _base) => { + if (typeof default_process === "boolean") { + return { enabled: default_process }; + } else { + return { + enabled: false, + ...default_process, + }; + } +}; + const normalizeExclusion = (exclusion, _base) => { if (typeof exclusion === "string") { exclusion = { @@ -218,7 +229,7 @@ const normalizeProcessSpecifier = (specifier, base) => { enabled: true, ...specifier, }; - return [createSpecifier(rest, base), enabled]; + return [createSpecifier(rest, base), { enabled }]; }; const normalizeProcesses = (specifiers, base) => { @@ -333,7 +344,7 @@ const fields = { }, "default-process": { extend: overwrite, - normalize: identity, + normalize: normalizeDefaultProcess, }, processes: { extend: prepend, @@ -486,7 +497,7 @@ export const createConfiguration = (home) => ({ }, appmap_dir: toAbsoluteUrl("tmp/appmap/", home), appmap_file: null, - "default-process": true, + "default-process": { enabled: true }, processes: [], recorder: null, "postmortem-function-exclusion": null, diff --git a/components/configuration/default/index.test.mjs b/components/configuration/default/index.test.mjs index 180fac783..72e8ed48b 100644 --- a/components/configuration/default/index.test.mjs +++ b/components/configuration/default/index.test.mjs @@ -231,6 +231,28 @@ assertDeepEqual( ], ); +// default-process // + +assertDeepEqual( + extend( + "default-process", + true, + "protocol://host/base/", + "protocol://host/home", + ), + { enabled: true }, +); + +assertDeepEqual( + extend( + "default-process", + { enabled: true }, + "protocol://host/base/", + "protocol://host/home", + ), + { enabled: true }, +); + // processes // assertDeepEqual( @@ -238,7 +260,7 @@ assertDeepEqual( [ [ { base: "protocol://host/base/", source: "^(?:\\/foo)$", flags: "" }, - true, + { enabled: true }, ], ], ); diff --git a/components/frontend/default/index.mjs b/components/frontend/default/index.mjs index 53a32c0f6..2b258c304 100644 --- a/components/frontend/default/index.mjs +++ b/components/frontend/default/index.mjs @@ -20,7 +20,6 @@ export { formatResolvePayload, formatRejectPayload, formatYieldPayload, - formatResumePayload, formatRequestPayload, formatResponsePayload, formatQueryPayload, diff --git a/components/frontend/default/payload.mjs b/components/frontend/default/payload.mjs index 656d8b3bc..fd895497f 100644 --- a/components/frontend/default/payload.mjs +++ b/components/frontend/default/payload.mjs @@ -54,11 +54,6 @@ export const formatYieldPayload = ({ serialization }, iterator) => ({ iterator: serialize(serialization, iterator), }); -export const formatResumePayload = ({ serialization }, argument) => ({ - type: "resume", - argument: serialize(serialization, argument), -}); - export const formatRequestPayload = ( { serialization }, side, diff --git a/components/frontend/default/payload.test.mjs b/components/frontend/default/payload.test.mjs index a99e02304..281d83685 100644 --- a/components/frontend/default/payload.test.mjs +++ b/components/frontend/default/payload.test.mjs @@ -12,7 +12,6 @@ import { formatResolvePayload, formatRejectPayload, formatYieldPayload, - formatResumePayload, formatQueryPayload, getAnswerPayload, formatRequestPayload, @@ -29,8 +28,6 @@ validatePayload(getBundlePayload({ serialization })); validatePayload(getJumpPayload({ serialization })); -validatePayload(formatResumePayload({ serialization }), "argument"); - validatePayload(getAnswerPayload({ serialization })); // apply // diff --git a/components/hook-apply/default/index.mjs b/components/hook-apply/default/index.mjs index db4ed2e90..81744651b 100644 --- a/components/hook-apply/default/index.mjs +++ b/components/hook-apply/default/index.mjs @@ -19,7 +19,6 @@ import { formatResolvePayload, formatRejectPayload, formatYieldPayload, - formatResumePayload, } from "../../agent/index.mjs"; const { @@ -71,9 +70,6 @@ export const hook = (agent, { hooks: { apply: apply_hook_variable } }) => { recordYield: (tab, iterator) => { recordBeforeEvent(agent, tab, formatYieldPayload(agent, iterator)); }, - recordResume: (tab, argument) => { - recordAfterEvent(agent, tab, formatResumePayload(agent, argument)); - }, }; defineProperty(globalThis, apply_hook_variable, { __proto__: null, @@ -91,7 +87,6 @@ export const hook = (agent, { hooks: { apply: apply_hook_variable } }) => { "recordResolve", "recordReject", "recordYield", - "recordResume", ].map((key) => ({ object: runtime, key, diff --git a/components/hook-apply/default/index.test.mjs b/components/hook-apply/default/index.test.mjs index 2720a4430..9afbd8f9f 100644 --- a/components/hook-apply/default/index.test.mjs +++ b/components/hook-apply/default/index.test.mjs @@ -43,7 +43,7 @@ assertDeepEqual( "argument", ]); globalThis.$.recordYield(tab, "iterator"); - globalThis.$.recordResume(tab); + globalThis.$.recordResolve(tab, "result"); globalThis.$.recordReturn(tab, "hash|protocol://host:0:0", "result"); } }, @@ -63,7 +63,7 @@ assertDeepEqual( // tab3 // "begin/apply", "before/yield", - "after/resume", + "after/resolve", "end/return", ], ); diff --git a/components/instrumentation/default/visit.mjs b/components/instrumentation/default/visit.mjs index 8ba7d2d8d..a6264bacb 100644 --- a/components/instrumentation/default/visit.mjs +++ b/components/instrumentation/default/visit.mjs @@ -14,6 +14,7 @@ import { stringifyLocation } from "../../location/index.mjs"; import { isExcluded } from "./exclusion.mjs"; const { + Error, String, Array: { isArray }, Object: { fromEntries }, @@ -138,6 +139,13 @@ const makeConditionalExpression = (node1, node2, node3) => ({ alternate: node3, }); +const makeLogicalExpression = (operator, node1, node2) => ({ + type: "LogicalExpression", + operator, + left: node1, + right: node2, +}); + const makeCatchClause = (node1, node2) => ({ type: "CatchClause", param: node1, @@ -242,6 +250,21 @@ const makeReturnStatement = (argument) => ({ // Component // /////////////// +const isJumpClosureNode = (node) => { + if (node.type === "Program") { + return node.sourceType === "module"; + } else if ( + node.type === "FunctionExpression" || + node.type === "FunctionDeclaration" + ) { + return node.async || node.generator; + } else if (node.type === "ArrowFunctionExpression") { + return node.async; + } /* c8 ignore start */ else { + throw new Error("unexpected closure node"); + } /* c8 ignore stop */ +}; + const isSubclassConstructor = (_node, parent, grand_parent) => parent.type === "MethodDefinition" && parent.kind === "constructor" && @@ -331,34 +354,22 @@ const instrumentClosure = (node, parent, grand_parent, closure, context) => { ), ), makeVariableDeclarator( - makeIdentifier(`${context.apply}_RETURN`), + makeIdentifier(`${context.apply}_RESULT`), null, ), makeVariableDeclarator( - makeIdentifier(`${context.apply}_RETURNED`), - makeLiteral(true), + makeIdentifier(`${context.apply}_DONE`), + makeLiteral(false), ), - ...(node.generator + ...(isJumpClosureNode(node) ? [ makeVariableDeclarator( - makeIdentifier(`${context.apply}_YIELD`), + makeIdentifier(`${context.apply}_JUMP`), null, ), makeVariableDeclarator( - makeIdentifier(`${context.apply}_YIELD_TAB`), - null, - ), - ] - : []), - ...(node.async - ? [ - makeVariableDeclarator( - makeIdentifier(`${context.apply}_AWAIT`), - null, - ), - makeVariableDeclarator( - makeIdentifier(`${context.apply}_AWAIT_TAB`), - null, + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeLiteral(null), ), ] : []), @@ -431,7 +442,7 @@ const instrumentClosure = (node, parent, grand_parent, closure, context) => { node.expression ? makeReturnStatement( makeAssignmentExpression( - makeIdentifier(`${context.apply}_RETURN`), + makeIdentifier(`${context.apply}_RESULT`), visitNode(node.body, node, parent, closure, context), ), ) @@ -440,13 +451,13 @@ const instrumentClosure = (node, parent, grand_parent, closure, context) => { makeCatchClause( makeIdentifier(`${context.apply}_ERROR`), makeBlockStatement([ - ...(node.async + ...(isJumpClosureNode(node) ? [ makeIfStatement( makeBinaryExpression( "!==", - makeIdentifier(`${context.apply}_AWAIT_TAB`), - makeUnaryExpression("void", makeLiteral(0)), + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeLiteral(null), ), makeBlockStatement([ makeStatement( @@ -456,11 +467,17 @@ const instrumentClosure = (node, parent, grand_parent, closure, context) => { "recordReject", ), [ - makeIdentifier(`${context.apply}_AWAIT_TAB`), + makeIdentifier(`${context.apply}_JUMP_TAB`), makeIdentifier(`${context.apply}_ERROR`), ], ), ), + makeStatement( + makeAssignmentExpression( + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeLiteral(null), + ), + ), ]), null, ), @@ -468,8 +485,8 @@ const instrumentClosure = (node, parent, grand_parent, closure, context) => { : []), makeExpressionStatement( makeAssignmentExpression( - makeIdentifier(`${context.apply}_RETURNED`), - makeLiteral(false), + makeIdentifier(`${context.apply}_DONE`), + makeLiteral(true), ), ), makeExpressionStatement( @@ -486,8 +503,40 @@ const instrumentClosure = (node, parent, grand_parent, closure, context) => { ]), ), makeBlockStatement([ + ...(isJumpClosureNode(node) + ? [ + makeIfStatement( + makeBinaryExpression( + "!==", + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeLiteral(null), + ), + makeBlockStatement([ + makeStatement( + makeCallExpression( + makeRegularMemberExpression( + context.apply, + "recordResolve", + ), + [ + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeRegularMemberExpression(context.apply, "empty"), + ], + ), + ), + makeStatement( + makeAssignmentExpression( + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeLiteral(null), + ), + ), + ]), + null, + ), + ] + : []), makeIfStatement( - makeIdentifier(`${context.apply}_RETURNED`), + makeUnaryExpression("!", makeIdentifier(`${context.apply}_DONE`)), makeBlockStatement([ makeExpressionStatement( makeCallExpression( @@ -495,7 +544,7 @@ const instrumentClosure = (node, parent, grand_parent, closure, context) => { [ makeIdentifier(`${context.apply}_BUNDLE_TAB`), makeLiteral(location_string), - makeIdentifier(`${context.apply}_RETURN`), + makeIdentifier(`${context.apply}_RESULT`), ], ), ), @@ -523,90 +572,82 @@ const instrumentClosure = (node, parent, grand_parent, closure, context) => { } }; -const instrumenters = { - AwaitExpression: (node, parent, _grand_parent, closure, context) => +const compileInstrumentJumpExpression = + (makeRecordJumpExpression, makeForwardJumpExpression) => + (node, parent, _grand_parent, closure, context) => closure.instrumented ? makeSequenceExpression([ makeAssignmentExpression( - makeIdentifier(`${context.apply}_AWAIT`), + makeIdentifier(`${context.apply}_JUMP`), visitNode(node.argument, node, parent, closure, context), ), + makeLogicalExpression( + "||", + makeBinaryExpression( + "===", + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeLiteral(null), + ), + makeIdentifier(`${context.apply}_APPMAP_JUMP_ASSERTION_VIOLATION`), + ), makeAssignmentExpression( - makeIdentifier(`${context.apply}_AWAIT_TAB`), + makeIdentifier(`${context.apply}_JUMP_TAB`), makeCallExpression( makeRegularMemberExpression(context.apply, "getFreshTab"), [], ), ), - makeCallExpression( - makeRegularMemberExpression(context.apply, "recordAwait"), - [ - makeIdentifier(`${context.apply}_AWAIT_TAB`), - makeIdentifier(`${context.apply}_AWAIT`), - ], - ), + makeRecordJumpExpression(node, context.apply), makeAssignmentExpression( - makeIdentifier(`${context.apply}_AWAIT`), - makeAwaitExpression(makeIdentifier(`${context.apply}_AWAIT`)), + makeIdentifier(`${context.apply}_JUMP`), + makeForwardJumpExpression(node, context.apply), ), makeCallExpression( makeRegularMemberExpression(context.apply, "recordResolve"), [ - makeIdentifier(`${context.apply}_AWAIT_TAB`), - makeIdentifier(`${context.apply}_AWAIT`), - ], - ), - makeAssignmentExpression( - makeIdentifier(`${context.apply}_AWAIT_TAB`), - makeUnaryExpression("void", makeLiteral(0)), - ), - makeIdentifier(`${context.apply}_AWAIT`), - ]) - : null, - YieldExpression: (node, parent, _grand_parent, closure, context) => - closure.instrumented - ? makeSequenceExpression([ - makeAssignmentExpression( - makeIdentifier(`${context.apply}_YIELD`), - visitNode(node.argument, node, parent, closure, context), - ), - makeAssignmentExpression( - makeIdentifier(`${context.apply}_YIELD_TAB`), - makeCallExpression( - makeRegularMemberExpression(context.apply, "getFreshTab"), - [], - ), - ), - makeCallExpression( - makeRegularMemberExpression(context.apply, "recordYield"), - [ - makeIdentifier(`${context.apply}_YIELD_TAB`), - makeLiteral(node.delegate), - makeIdentifier(`${context.apply}_YIELD`), + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeIdentifier(`${context.apply}_JUMP`), ], ), makeAssignmentExpression( - makeIdentifier(`${context.apply}_YIELD`), - makeYieldExpression( - node.delegate, - makeIdentifier(`${context.apply}_YIELD`), - ), - ), - makeCallExpression( - makeRegularMemberExpression(context.apply, "recordResume"), - [ - makeIdentifier(`${context.apply}_YIELD_TAB`), - makeIdentifier(`${context.apply}_YIELD`), - ], + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeLiteral(null), ), - makeIdentifier(`${context.apply}_YIELD`), + makeIdentifier(`${context.apply}_JUMP`), ]) - : null, + : null; + +const instrumenters = { + AwaitExpression: compileInstrumentJumpExpression( + (_node, namespace) => + makeCallExpression( + makeRegularMemberExpression(namespace, "recordAwait"), + [ + makeIdentifier(`${namespace}_JUMP_TAB`), + makeIdentifier(`${namespace}_JUMP`), + ], + ), + (_node, namespace) => + makeAwaitExpression(makeIdentifier(`${namespace}_JUMP`)), + ), + YieldExpression: compileInstrumentJumpExpression( + ({ delegate }, namespace) => + makeCallExpression( + makeRegularMemberExpression(namespace, "recordYield"), + [ + makeIdentifier(`${namespace}_JUMP_TAB`), + makeLiteral(delegate), + makeIdentifier(`${namespace}_JUMP`), + ], + ), + ({ delegate }, namespace) => + makeYieldExpression(delegate, makeIdentifier(`${namespace}_JUMP`)), + ), ReturnStatement: (node, parent, _grand_parent, closure, context) => closure.instrumented && node.argument !== null ? makeReturnStatement( makeAssignmentExpression( - makeIdentifier(`${context.apply}_RETURN`), + makeIdentifier(`${context.apply}_RESULT`), visitNode(node.argument, node, parent, closure, context), ), ) @@ -641,12 +682,7 @@ const instrumenters = { } }, TryStatement: (node, parent, _grand_parent, closure, context) => { - if ( - closure.instrumented && - ((closure.node.type === "Program" && - closure.node.sourceType === "module") || - (hasOwnProperty(closure.node, "async") && closure.node.async)) - ) { + if (closure.instrumented && isJumpClosureNode(closure.node)) { return makeTryStatement( visitNode(node.block, node, parent, closure, context), makeCatchClause( @@ -655,23 +691,23 @@ const instrumenters = { makeIfStatement( makeBinaryExpression( "!==", - makeIdentifier(`${context.apply}_AWAIT_TAB`), - makeUnaryExpression("void", makeLiteral(0)), + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeLiteral(null), ), makeBlockStatement([ makeStatement( makeCallExpression( makeRegularMemberExpression(context.apply, "recordReject"), [ - makeIdentifier(`${context.apply}_AWAIT_TAB`), + makeIdentifier(`${context.apply}_JUMP_TAB`), makeIdentifier(`${context.apply}_ERROR`), ], ), ), makeStatement( makeAssignmentExpression( - makeIdentifier(`${context.apply}_AWAIT_TAB`), - makeUnaryExpression("void", makeLiteral(0)), + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeLiteral(null), ), ), ]), @@ -706,9 +742,36 @@ const instrumenters = { ]), ]), ), - node.finalizer === null - ? null - : visitNode(node.finalizer, node, parent, closure, context), + makeBlockStatement([ + makeIfStatement( + makeBinaryExpression( + "!==", + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeLiteral(null), + ), + makeBlockStatement([ + makeStatement( + makeCallExpression( + makeRegularMemberExpression(context.apply, "recordResolve"), + [ + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeRegularMemberExpression(context.apply, "empty"), + ], + ), + ), + makeStatement( + makeAssignmentExpression( + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeLiteral(null), + ), + ), + ]), + null, + ), + ...(node.finalizer === null + ? [] + : [visitNode(node.finalizer, node, parent, closure, context)]), + ]), ); } else { return null; @@ -742,12 +805,12 @@ const instrumenters = { ), ), makeVariableDeclarator( - makeIdentifier(`${context.apply}_AWAIT`), + makeIdentifier(`${context.apply}_JUMP`), null, ), makeVariableDeclarator( - makeIdentifier(`${context.apply}_AWAIT_TAB`), - null, + makeIdentifier(`${context.apply}_JUMP_TAB`), + makeLiteral(null), ), ]), ...node.body.map((child) => diff --git a/components/instrumentation/default/visit.test.mjs b/components/instrumentation/default/visit.test.mjs index b85c05837..930b86f7f 100644 --- a/components/instrumentation/default/visit.test.mjs +++ b/components/instrumentation/default/visit.test.mjs @@ -65,8 +65,8 @@ const makeCodeLocation = (source, line, column) => (() => { var APPLY_BUNDLE_TAB = APPLY.getFreshTab(), - APPLY_RETURN, - APPLY_RETURNED = true; + APPLY_RESULT, + APPLY_DONE = false; APPLY.recordApply( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 1, 1)}, @@ -74,9 +74,9 @@ const makeCodeLocation = (source, line, column) => [], ); try { - return APPLY_RETURN = 123; + return APPLY_RESULT = 123; } catch (APPLY_ERROR) { - APPLY_RETURNED = false; + APPLY_DONE = true; APPLY.recordThrow( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 1, 1)}, @@ -84,11 +84,11 @@ const makeCodeLocation = (source, line, column) => ); throw APPLY_ERROR; } finally { - if (APPLY_RETURNED) { + if (!APPLY_DONE) { APPLY.recordReturn( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 1, 1)}, - APPLY_RETURN, + APPLY_RESULT, ); } } @@ -115,8 +115,8 @@ const makeCodeLocation = (source, line, column) => (class C extends D { constructor () { var APPLY_BUNDLE_TAB = APPLY.getFreshTab(), - APPLY_RETURN, - APPLY_RETURNED = true; + APPLY_RESULT, + APPLY_DONE = false; APPLY.recordApply( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 2, 12)}, @@ -128,7 +128,7 @@ const makeCodeLocation = (source, line, column) => 123; } } catch (APPLY_ERROR) { - APPLY_RETURNED = false; + APPLY_DONE = true; APPLY.recordThrow( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 2, 12)}, @@ -136,11 +136,11 @@ const makeCodeLocation = (source, line, column) => ); throw APPLY_ERROR; } finally { - if (APPLY_RETURNED) { + if (!APPLY_DONE) { APPLY.recordReturn( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 2, 12)}, - APPLY_RETURN, + APPLY_RESULT, ); } } @@ -168,8 +168,8 @@ const makeCodeLocation = (source, line, column) => ((APPLY_ARGUMENT_0, APPLY_ARGUMENT_1, ...APPLY_ARGUMENT_2) => { var APPLY_BUNDLE_TAB = APPLY.getFreshTab(), - APPLY_RETURN, - APPLY_RETURNED = true; + APPLY_RESULT, + APPLY_DONE = false; APPLY.recordApply( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 1, 1)}, @@ -182,10 +182,10 @@ const makeCodeLocation = (source, line, column) => y = APPLY_ARGUMENT_1 === void 0 ? 123 : APPLY_ARGUMENT_1, rest = APPLY_ARGUMENT_2; { - return APPLY_RETURN = 456; + return APPLY_RESULT = 456; } } catch (APPLY_ERROR) { - APPLY_RETURNED = false; + APPLY_DONE = true; APPLY.recordThrow( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 1, 1)}, @@ -193,11 +193,11 @@ const makeCodeLocation = (source, line, column) => ); throw APPLY_ERROR; } finally { - if (APPLY_RETURNED) { + if (!APPLY_DONE) { APPLY.recordReturn( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 1, 1)}, - APPLY_RETURN, + APPLY_RESULT, ); } } @@ -224,10 +224,10 @@ const makeCodeLocation = (source, line, column) => (function* () { var APPLY_BUNDLE_TAB = APPLY.getFreshTab(), - APPLY_RETURN, - APPLY_RETURNED = true, - APPLY_YIELD, - APPLY_YIELD_TAB; + APPLY_RESULT, + APPLY_DONE = false, + APPLY_JUMP, + APPLY_JUMP_TAB = null; APPLY.recordApply( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 1, 1)}, @@ -237,16 +237,25 @@ const makeCodeLocation = (source, line, column) => try { { ( - APPLY_YIELD = 123, - APPLY_YIELD_TAB = APPLY.getFreshTab(), - APPLY.recordYield(APPLY_YIELD_TAB, true, APPLY_YIELD), - APPLY_YIELD = yield* APPLY_YIELD, - APPLY.recordResume(APPLY_YIELD_TAB, APPLY_YIELD), - APPLY_YIELD + APPLY_JUMP = 123, + ( + APPLY_JUMP_TAB === null || + APPLY_APPMAP_JUMP_ASSERTION_VIOLATION + ), + APPLY_JUMP_TAB = APPLY.getFreshTab(), + APPLY.recordYield(APPLY_JUMP_TAB, true, APPLY_JUMP), + APPLY_JUMP = yield* APPLY_JUMP, + APPLY.recordResolve(APPLY_JUMP_TAB, APPLY_JUMP), + APPLY_JUMP_TAB = null, + APPLY_JUMP ); } } catch (APPLY_ERROR) { - APPLY_RETURNED = false; + if (APPLY_JUMP_TAB !== null) { + APPLY.recordReject(APPLY_JUMP_TAB, APPLY_ERROR); + APPLY_JUMP_TAB = null; + } + APPLY_DONE = true; APPLY.recordThrow( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 1, 1)}, @@ -254,11 +263,15 @@ const makeCodeLocation = (source, line, column) => ); throw APPLY_ERROR; } finally { - if (APPLY_RETURNED) { + if (APPLY_JUMP_TAB !== null) { + APPLY.recordResolve(APPLY_JUMP_TAB, APPLY.empty); + APPLY_JUMP_TAB = null; + } + if (!APPLY_DONE) { APPLY.recordReturn( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 1, 1)}, - APPLY_RETURN, + APPLY_RESULT, ); } } @@ -291,10 +304,10 @@ const makeCodeLocation = (source, line, column) => (async () => { var APPLY_BUNDLE_TAB = APPLY.getFreshTab(), - APPLY_RETURN, - APPLY_RETURNED = true, - APPLY_AWAIT, - APPLY_AWAIT_TAB; + APPLY_RESULT, + APPLY_DONE = false, + APPLY_JUMP, + APPLY_JUMP_TAB = null; APPLY.recordApply( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 2, 7)}, @@ -305,32 +318,43 @@ const makeCodeLocation = (source, line, column) => { try { ( - APPLY_AWAIT = 123, - APPLY_AWAIT_TAB = APPLY.getFreshTab(), - APPLY.recordAwait(APPLY_AWAIT_TAB, APPLY_AWAIT), - APPLY_AWAIT = await APPLY_AWAIT, - APPLY.recordResolve(APPLY_AWAIT_TAB, APPLY_AWAIT), - APPLY_AWAIT_TAB = void 0, - APPLY_AWAIT + APPLY_JUMP = 123, + ( + APPLY_JUMP_TAB === null || + APPLY_APPMAP_JUMP_ASSERTION_VIOLATION + ), + APPLY_JUMP_TAB = APPLY.getFreshTab(), + APPLY.recordAwait(APPLY_JUMP_TAB, APPLY_JUMP), + APPLY_JUMP = await APPLY_JUMP, + APPLY.recordResolve(APPLY_JUMP_TAB, APPLY_JUMP), + APPLY_JUMP_TAB = null, + APPLY_JUMP ); } catch (APPLY_ERROR) { - if (APPLY_AWAIT_TAB !== void 0) { - APPLY.recordReject(APPLY_AWAIT_TAB, APPLY_ERROR); - APPLY_AWAIT_TAB = void 0; + if (APPLY_JUMP_TAB !== null) { + APPLY.recordReject(APPLY_JUMP_TAB, APPLY_ERROR); + APPLY_JUMP_TAB = null; } let error = APPLY_ERROR; { 456; } } finally { - 789; + if (APPLY_JUMP_TAB !== null) { + APPLY.recordResolve(APPLY_JUMP_TAB, APPLY.empty); + APPLY_JUMP_TAB = null; + } + { + 789; + } } } } catch (APPLY_ERROR) { - if (APPLY_AWAIT_TAB !== void 0) { - APPLY.recordReject(APPLY_AWAIT_TAB, APPLY_ERROR); + if (APPLY_JUMP_TAB !== null) { + APPLY.recordReject(APPLY_JUMP_TAB, APPLY_ERROR); + APPLY_JUMP_TAB = null; } - APPLY_RETURNED = false; + APPLY_DONE = true; APPLY.recordThrow( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 2, 7)}, @@ -338,11 +362,15 @@ const makeCodeLocation = (source, line, column) => ); throw APPLY_ERROR; } finally { - if (APPLY_RETURNED) { + if (APPLY_JUMP_TAB !== null) { + APPLY.recordResolve(APPLY_JUMP_TAB, APPLY.empty); + APPLY_JUMP_TAB = null; + } + if (!APPLY_DONE) { APPLY.recordReturn( APPLY_BUNDLE_TAB, ${makeCodeLocation(source, 2, 7)}, - APPLY_RETURN, + APPLY_RESULT, ); } } @@ -395,18 +423,23 @@ assertEqual( ` let APPLY_BUNDLE_TAB = APPLY.getFreshTab(), - APPLY_AWAIT, - APPLY_AWAIT_TAB; + APPLY_JUMP, + APPLY_JUMP_TAB = null; try { 123; } catch (APPLY_ERROR) { - if (APPLY_AWAIT_TAB !== void 0) { - APPLY.recordReject(APPLY_AWAIT_TAB, APPLY_ERROR); - APPLY_AWAIT_TAB = void 0; + if (APPLY_JUMP_TAB !== null) { + APPLY.recordReject(APPLY_JUMP_TAB, APPLY_ERROR); + APPLY_JUMP_TAB = null; } { 456; } + } finally { + if (APPLY_JUMP_TAB !== null) { + APPLY.recordResolve(APPLY_JUMP_TAB, APPLY.empty); + APPLY_JUMP_TAB = null; + } } export default 789; `, @@ -427,17 +460,23 @@ assertEqual( ` let APPLY_BUNDLE_TAB = APPLY.getFreshTab(), - APPLY_AWAIT, - APPLY_AWAIT_TAB; + APPLY_JUMP, + APPLY_JUMP_TAB = null; try { 123; } catch (APPLY_ERROR) { - if (APPLY_AWAIT_TAB !== void 0) { - APPLY.recordReject(APPLY_AWAIT_TAB, APPLY_ERROR); - APPLY_AWAIT_TAB = void 0; + if (APPLY_JUMP_TAB !== null) { + APPLY.recordReject(APPLY_JUMP_TAB, APPLY_ERROR); + APPLY_JUMP_TAB = null; } } finally { - 456; + if (APPLY_JUMP_TAB !== null) { + APPLY.recordResolve(APPLY_JUMP_TAB, APPLY.empty); + APPLY_JUMP_TAB = null; + } + { + 456; + } } export default 789; `, diff --git a/components/load/node/.env b/components/load/node/.env new file mode 100644 index 000000000..eb0faad4f --- /dev/null +++ b/components/load/node/.env @@ -0,0 +1,2 @@ +test +node diff --git a/components/load/node/index.mjs b/components/load/node/index.mjs new file mode 100644 index 000000000..15c6e77ae --- /dev/null +++ b/components/load/node/index.mjs @@ -0,0 +1,39 @@ +import { readFile as readFileAsync } from "node:fs/promises"; +import { hasOwnProperty } from "../../util/index.mjs"; +import { getLastUrlExtension } from "../../url/index.mjs"; +import { parse as parseYaml } from "yaml"; + +const { + URL, + JSON: { parse: parseJson }, +} = globalThis; + +const loadJsonAsync = async (url) => + parseJson(await readFileAsync(new URL(url), "utf8")); + +const loadYamlAsync = async (url) => + parseYaml(await readFileAsync(new URL(url), "utf8")); + +const loaders = { + ".json": loadJsonAsync, + ".yaml": loadYamlAsync, + ".yml": loadYamlAsync, +}; + +export const loadAsync = async (url) => { + const extension = getLastUrlExtension(url); + if (hasOwnProperty(loaders, extension)) { + return await loaders[extension](url); + } else { + // Can load both cjs and esm modules + // cf: https://nodejs.org/api/packages.html#packagejson-and-file-extensions + // Currently, we do not support typescript. + return (await import(url)).default; + } +}; + +export const isLoadMissingError = (error) => + hasOwnProperty(error, "code") && + (error.code === "ENOENT" || + error.code === "ERR_MODULE_NOT_FOUND" || + error.code === "MODULE_NOT_FOUND"); diff --git a/components/load/node/index.test.mjs b/components/load/node/index.test.mjs new file mode 100644 index 000000000..f338efb9e --- /dev/null +++ b/components/load/node/index.test.mjs @@ -0,0 +1,54 @@ +import { + mkdir as mkdirAsync, + writeFile as writeFileAsync, +} from "node:fs/promises"; +import { assertEqual } from "../../__fixture__.mjs"; +import { getTmpUrl } from "../../path/index.mjs"; +import { getUuid } from "../../uuid/random/index.mjs"; +import { toAbsoluteUrl } from "../../url/index.mjs"; +import { loadAsync, isLoadMissingError } from "./index.mjs"; + +const { Error, Symbol, URL } = globalThis; + +const SUCCESS = Symbol("success"); +const home = toAbsoluteUrl(`${getUuid()}/`, getTmpUrl()); +await mkdirAsync(new URL(home)); + +const callFailureAsync = async (runAsync, ...args) => { + try { + await runAsync(...args); + throw SUCCESS; + } catch (error) { + if (error === SUCCESS) { + throw new Error("unexpected success"); + } else { + return error; + } + } +}; + +const testAsync = async (filename, content, value, test_invalid) => { + const url = toAbsoluteUrl(filename, home); + assertEqual(isLoadMissingError(await callFailureAsync(loadAsync, url)), true); + // Syntax errors in esm modules does not appear to be catchable + if (test_invalid) { + await writeFileAsync(new URL(url), "}{", "utf8"); + assertEqual( + isLoadMissingError(await callFailureAsync(loadAsync, url)), + false, + ); + } + await writeFileAsync(new URL(url), content, "utf8"); + assertEqual(await loadAsync(url), value); +}; + +// json && yaml // +for (const filename of ["file.json", "file.yaml", "file.yml"]) { + await testAsync(filename, "123", 123, true); +} + +// esm // +await testAsync("file.mjs", "export default 123;", 123, false); + +// cjs // +await testAsync("file.cjs", "module.exports = 123;", 123, false); diff --git a/components/trace/appmap/ordering/matching.mjs b/components/trace/appmap/ordering/matching.mjs index ba9675a33..589eff146 100644 --- a/components/trace/appmap/ordering/matching.mjs +++ b/components/trace/appmap/ordering/matching.mjs @@ -70,10 +70,6 @@ const payloads = { print: "APPMAP-YIELD", }, }, - resume: { - type: "resume", - function: null, - }, await: { type: "await", function: null, @@ -115,7 +111,8 @@ const matching = [ ["begin/group", "end/ungroup", ["group"]], ["before/await", "after/resolve", ["function"]], ["before/await", "after/reject", ["function"]], - ["before/yield", "after/resume", ["function"]], + ["before/yield", "after/resolve", ["function"]], + ["before/yield", "after/reject", ["function"]], ["before/jump", "after/jump", []], ["before/request", "after/response", ["side"]], ["before/query", "after/answer", []], diff --git a/package-lock.json b/package-lock.json index e1e91e41f..f011aa0e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,7 +55,8 @@ "semantic-release": "^19.0.5", "sinon": "^14.0.0", "source-map": "^0.7.4", - "sqlite3": "^5.0.2" + "sqlite3": "^5.0.2", + "ts-node": "^10.9.1" }, "engines": { "node": "14.x.x || 16.x.x || 17.x.x || 18.x.x || 19.x.x" @@ -767,6 +768,28 @@ "node": ">=0.1.90" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", @@ -2086,6 +2109,30 @@ "node": ">= 6" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, "node_modules/@types/babel__core": { "version": "7.1.20", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", @@ -2269,6 +2316,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -2437,6 +2493,12 @@ "node": ">= 6" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3355,6 +3417,12 @@ "node": ">= 6" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -7009,6 +7077,12 @@ "semver": "bin/semver.js" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/make-fetch-happen": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", @@ -12629,6 +12703,58 @@ "node": ">=8" } }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -12699,6 +12825,20 @@ "node": ">= 0.6" } }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/uglify-js": { "version": "3.17.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.2.tgz", @@ -12836,6 +12976,12 @@ "node": ">= 0.4.0" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/v8-to-istanbul": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", @@ -13101,6 +13247,15 @@ "node": ">=8" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -13654,6 +13809,27 @@ "dev": true, "optional": true }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, "@eslint/eslintrc": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", @@ -14692,6 +14868,30 @@ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "optional": true }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, "@types/babel__core": { "version": "7.1.20", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", @@ -14864,6 +15064,12 @@ "dev": true, "requires": {} }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -14993,6 +15199,12 @@ } } }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -15695,6 +15907,12 @@ } } }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -18460,6 +18678,12 @@ } } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "make-fetch-happen": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", @@ -22545,6 +22769,35 @@ "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, "tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -22599,6 +22852,13 @@ "mime-types": "~2.1.24" } }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "peer": true + }, "uglify-js": { "version": "3.17.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.2.tgz", @@ -22699,6 +22959,12 @@ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "v8-to-istanbul": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", @@ -22906,6 +23172,12 @@ } } }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index edebc35fe..b68dcf2a7 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,8 @@ "semantic-release": "^19.0.5", "sinon": "^14.0.0", "source-map": "^0.7.4", - "sqlite3": "^5.0.2" + "sqlite3": "^5.0.2", + "ts-node": "^10.9.1" }, "publishConfig": { "cache": "~/.npm", diff --git a/schema/definitions/configuration-external.yaml b/schema/definitions/configuration-external.yaml index b9bf17ede..2dda27247 100644 --- a/schema/definitions/configuration-external.yaml +++ b/schema/definitions/configuration-external.yaml @@ -99,7 +99,9 @@ properties: ordering: $ref: ordering default-process: - type: boolean + anyOf: + - type: boolean + - $ref: process processes: anyOf: - $ref: specifier-process diff --git a/schema/definitions/configuration-internal.yaml b/schema/definitions/configuration-internal.yaml index 2869af332..1ec357a8a 100644 --- a/schema/definitions/configuration-internal.yaml +++ b/schema/definitions/configuration-internal.yaml @@ -125,7 +125,7 @@ properties: ordering: $ref: ordering default-process: - type: boolean + $ref: process processes: type: array items: @@ -134,7 +134,7 @@ properties: maxItems: 2 items: - $ref: specifier-cooked - - type: boolean + - $ref: process main: anyOf: - const: null diff --git a/schema/definitions/payload-resume.yaml b/schema/definitions/payload-resume.yaml deleted file mode 100644 index 35e5c229c..000000000 --- a/schema/definitions/payload-resume.yaml +++ /dev/null @@ -1,9 +0,0 @@ -type: object -additionalProperties: false -required: - - type -properties: - type: - const: resume - argument: - $ref: serial diff --git a/schema/definitions/payload.yaml b/schema/definitions/payload.yaml index 0353d7523..0e4eb740a 100644 --- a/schema/definitions/payload.yaml +++ b/schema/definitions/payload.yaml @@ -10,7 +10,6 @@ anyOf: - $ref: payload-request - $ref: payload-resolve - $ref: payload-response - - $ref: payload-resume - $ref: payload-return - $ref: payload-throw - $ref: payload-ungroup diff --git a/schema/definitions/process.yaml b/schema/definitions/process.yaml new file mode 100644 index 000000000..d794b35e4 --- /dev/null +++ b/schema/definitions/process.yaml @@ -0,0 +1,7 @@ +type: object +additionalProperties: false +required: + - enabled +properties: + enabled: + type: boolean diff --git a/test/cases/default-parameter/appmap.yml b/test/cases/default-parameter/appmap.yml new file mode 100644 index 000000000..41350a74b --- /dev/null +++ b/test/cases/default-parameter/appmap.yml @@ -0,0 +1,16 @@ +recorder: process +packages: + path: main.mjs + enabled: true +command: node main.mjs +appmap_dir: . +appmap_file: main +hooks: + cjs: false + esm: true + eval: false + apply: true + http: false + mysql: false + pg: false + sqlite3: false diff --git a/test/cases/default-parameter/main.mjs b/test/cases/default-parameter/main.mjs new file mode 100644 index 000000000..6eecd2c5c --- /dev/null +++ b/test/cases/default-parameter/main.mjs @@ -0,0 +1,4 @@ +import { strict as Assert } from "node:assert"; +const { equal: assertEqual } = Assert; +const defaultParameter = (x = 123) => x; +assertEqual(defaultParameter(), 123); diff --git a/test/cases/default-parameter/process/main.subset.yaml b/test/cases/default-parameter/process/main.subset.yaml new file mode 100644 index 000000000..a3f5221b2 --- /dev/null +++ b/test/cases/default-parameter/process/main.subset.yaml @@ -0,0 +1,7 @@ +events: + - event: call + id: 1 + method_id: defaultParameter + - event: return + id: 2 + parent_id: 1 diff --git a/test/cases/generator-method/appmap.yml b/test/cases/generator-method/appmap.yml new file mode 100644 index 000000000..41350a74b --- /dev/null +++ b/test/cases/generator-method/appmap.yml @@ -0,0 +1,16 @@ +recorder: process +packages: + path: main.mjs + enabled: true +command: node main.mjs +appmap_dir: . +appmap_file: main +hooks: + cjs: false + esm: true + eval: false + apply: true + http: false + mysql: false + pg: false + sqlite3: false diff --git a/test/cases/generator-method/main.mjs b/test/cases/generator-method/main.mjs new file mode 100644 index 000000000..73b788c0c --- /dev/null +++ b/test/cases/generator-method/main.mjs @@ -0,0 +1,25 @@ +import { strict as Assert } from "node:assert"; +const { throws: assertThrow, deepEqual: assertDeepEqual } = Assert; +const { Error, undefined } = globalThis; + +function* g() { + yield 1; + yield 2; + yield 3; +} + +{ + const i = g(); + assertDeepEqual(i.next(), { value: 1, done: false }); + assertDeepEqual(i.return("result"), { value: "result", done: true }); + assertDeepEqual(i.next(), { value: undefined, done: true }); +} + +{ + const i = g(); + assertDeepEqual(i.next(), { value: 1, done: false }); + assertThrow(() => { + i.throw(new Error("message")); + }, /^Error: message$/u); + assertDeepEqual(i.next(), { value: undefined, done: true }); +} diff --git a/test/cases/generator-method/process/main.subset.yaml b/test/cases/generator-method/process/main.subset.yaml new file mode 100644 index 000000000..eed361796 --- /dev/null +++ b/test/cases/generator-method/process/main.subset.yaml @@ -0,0 +1,7 @@ +events: + - event: call + id: 1 + method_id: g + - event: return + id: 2 + parent_id: 1 diff --git a/test/cases/ts-node-esm/appmap.yml b/test/cases/ts-node-esm/appmap.yml new file mode 100644 index 000000000..c9f524a8c --- /dev/null +++ b/test/cases/ts-node-esm/appmap.yml @@ -0,0 +1,23 @@ +recorder: process +processes: + - regexp: /child-entrypoint\.js$ + enabled: true +default-process: + enabled: false +packages: + glob: "*" + enabled: true +default-package: + enabled: false +command: npx ts-node-esm square.test.ts +appmap_dir: . +appmap_file: square +hooks: + cjs: true + esm: true + apply: true + eval: false + http: false + mysql: false + pg: false + sqlite3: false diff --git a/test/cases/ts-node-esm/square.test.ts b/test/cases/ts-node-esm/square.test.ts new file mode 100644 index 000000000..eb33ed55a --- /dev/null +++ b/test/cases/ts-node-esm/square.test.ts @@ -0,0 +1,5 @@ +import { square } from "./square"; + +if (square(3) !== 9) { + throw new Error("expected 3 * 3 to be 9"); +} diff --git a/test/cases/ts-node-esm/square.ts b/test/cases/ts-node-esm/square.ts new file mode 100644 index 000000000..ae7cd51f2 --- /dev/null +++ b/test/cases/ts-node-esm/square.ts @@ -0,0 +1 @@ +export const square = (x: number): number => x * x;