├── .bercowrc-test-only-cov.yaml ├── .bercowrc-test-only.yaml ├── .bercowrc.yaml ├── .editorconfig ├── .eslintignore ├── .eslintplugin.js ├── .eslintrc.yaml ├── .github └── workflows │ ├── ci.yml │ └── main.yml ├── .gitignore ├── .npmignore ├── .ordering ├── .ordering-ignore ├── .prettierignore ├── .prettierrc.yaml ├── .releaserc.yaml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── REFERENCE.md ├── babel.config.json ├── bin ├── .eslintrc.yaml └── appmap-agent-js.cjs ├── component ├── .eslintrc.yaml ├── build-prod.mjs ├── build-test.mjs ├── build.mjs ├── bundle.mjs ├── eslint.mjs ├── home.mjs ├── layout.mjs ├── lint.mjs ├── route.mjs ├── signature.mjs └── support.mjs ├── components ├── .ordering ├── .ordering-ignore ├── __fixture__.mjs ├── assert │ ├── check │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── backend │ └── default │ │ ├── .env │ │ ├── .ordering │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ ├── track.mjs │ │ └── track.test.mjs ├── client │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── command │ └── node │ │ ├── .env │ │ ├── .ordering │ │ ├── escape.mjs │ │ ├── escape.test.mjs │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ ├── jest-argv.mjs │ │ ├── jest-argv.test.mjs │ │ ├── jest-config.mjs │ │ ├── jest-config.test.mjs │ │ ├── jest.mjs │ │ ├── jest.test.mjs │ │ ├── mocha.mjs │ │ ├── mocha.test.mjs │ │ ├── node-recursive.mjs │ │ ├── node-recursive.test.mjs │ │ ├── node.mjs │ │ ├── node.test.mjs │ │ ├── package.mjs │ │ ├── package.test.mjs │ │ ├── process-recursive.mjs │ │ ├── process-recursive.test.mjs │ │ ├── process.mjs │ │ ├── process.test.mjs │ │ ├── remote-recursive.mjs │ │ ├── remote-recursive.test.mjs │ │ ├── remote.mjs │ │ ├── remote.test.mjs │ │ ├── tokenize.mjs │ │ └── tokenize.test.mjs ├── compress │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── configuration-accessor │ └── default │ │ ├── .env │ │ ├── .ordering │ │ ├── index.mjs │ │ └── index.test.mjs ├── configuration-environment │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── configuration-process │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── configuration │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── crash-reporter │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── engine │ ├── browser │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ ├── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── stub │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── error │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── event │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── file │ ├── dead │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── frontend │ └── default │ │ ├── .env │ │ ├── .ordering │ │ ├── index.mjs │ │ └── index.test.mjs ├── glob │ ├── dead │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── minimatch │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── global │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── group │ ├── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── stub │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── hash │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── hook-apply │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── hook-error │ ├── browser │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── hook-eval │ ├── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── stub │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── hook-exit │ ├── browser │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── hook-fixture │ └── fixture │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── hook-group │ ├── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── stub │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── hook-http-client │ ├── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── stub │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── hook-http-server │ ├── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── stub │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── hook-http │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── hook-module │ ├── node │ │ ├── .env │ │ ├── .ordering │ │ ├── cjs.mjs │ │ ├── cjs.test.mjs │ │ ├── esm.mjs │ │ ├── esm.test.mjs │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ ├── stringify.mjs │ │ └── stringify.test.mjs │ └── noop │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── hook-query │ ├── node │ │ ├── .env │ │ ├── .ordering │ │ ├── convert.mjs │ │ ├── convert.test.mjs │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ ├── mysql.mjs │ │ ├── mysql.test.mjs │ │ ├── pg.mjs │ │ ├── pg.test.mjs │ │ ├── sqlite3.mjs │ │ └── sqlite3.test.mjs │ └── void │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── hook │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── http │ ├── node-http │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── void │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── init │ └── node │ │ ├── .env │ │ ├── .ordering │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ └── init.spec.mjs ├── instrumentation-inject │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── instrumentation │ ├── dead │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── default │ │ ├── .env │ │ ├── .ordering │ │ ├── __fixture__.mjs │ │ ├── codebase.mjs │ │ ├── codebase.test.mjs │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ ├── source.mjs │ │ ├── source.test.mjs │ │ ├── sourcemap.mjs │ │ ├── sourcemap.test.mjs │ │ ├── visit.mjs │ │ └── visit.test.mjs ├── interpretation │ ├── .ordering │ ├── dom │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── vm │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── load │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── location │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── log-inner │ ├── console │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ ├── stub │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── write-sync │ │ ├── .env │ │ ├── .ordering │ │ ├── index-isolate.mjs │ │ ├── index-isolate.test.mjs │ │ ├── index.mjs │ │ └── index.test.mjs ├── log │ ├── prod │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── test │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── matcher │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── mitm │ └── default │ │ ├── .env │ │ ├── .ordering │ │ ├── forward.mjs │ │ ├── forward.test.mjs │ │ ├── html.mjs │ │ ├── html.test.mjs │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ ├── intercept.mjs │ │ ├── intercept.test.mjs │ │ ├── js.mjs │ │ ├── js.test.mjs │ │ ├── proxy.mjs │ │ ├── proxy.test.mjs │ │ ├── stream.mjs │ │ ├── stream.test.mjs │ │ ├── util.mjs │ │ └── util.test.mjs ├── parse │ └── babel │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── patch │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── path │ └── node │ │ ├── .env │ │ ├── .ordering │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ ├── posix.mjs │ │ ├── posix.test.mjs │ │ ├── win32.mjs │ │ └── win32.test.mjs ├── peer │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── pool │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── position │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── prompts │ ├── fake │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── questionnaire │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── receptor │ ├── default │ │ ├── .env │ │ ├── .ordering │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ ├── port.mjs │ │ ├── port.test.mjs │ │ ├── trace.mjs │ │ ├── trace.test.mjs │ │ ├── track.mjs │ │ └── track.test.mjs │ └── stub │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── recorder-api │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── recorder-cli │ ├── browser │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ ├── jest │ │ ├── .env │ │ ├── .ordering │ │ ├── __fixture__.mjs │ │ ├── index.mjs │ │ └── index.test.mjs │ ├── mocha │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ ├── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── stub │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── recorder-standalone │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── repository │ ├── dead │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ ├── node │ │ ├── .env │ │ ├── .ordering │ │ ├── git.mjs │ │ ├── git.test.mjs │ │ ├── history.mjs │ │ ├── history.test.mjs │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ ├── package.mjs │ │ ├── package.test.mjs │ │ ├── spawn.mjs │ │ └── spawn.test.mjs │ └── stub │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── self │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── serialization │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── server │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── setup │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── socket │ ├── browser │ │ ├── .env │ │ ├── .ordering │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ ├── ready-state.mjs │ │ └── ready-state.test.mjs │ ├── mock │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── node │ │ ├── .env │ │ ├── .ordering │ │ ├── __fixture__.mjs │ │ ├── __fixture__.test.mjs │ │ ├── index-isolate.mjs │ │ ├── index-isolate.test.mjs │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ ├── net.mjs │ │ ├── net.test.mjs │ │ ├── unix.mjs │ │ └── unix.test.mjs ├── source │ └── default │ │ ├── .env │ │ ├── .ordering │ │ ├── criteria.mjs │ │ ├── criteria.test.mjs │ │ ├── entity.mjs │ │ ├── entity.test.mjs │ │ ├── index.mjs │ │ └── index.test.mjs ├── spawn │ └── node │ │ ├── .env │ │ ├── .ordering │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ ├── spawn.mjs │ │ ├── spawn.test.mjs │ │ ├── where.mjs │ │ └── where.test.mjs ├── status │ └── node │ │ ├── .env │ │ ├── .ordering │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ └── status.spec.mjs ├── test-helper.mjs ├── throttle │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── time │ ├── date │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ ├── performance-browser │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ ├── performance-node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── stub │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── trace │ ├── appmap │ │ ├── .env │ │ ├── .ordering │ │ ├── codebase │ │ │ ├── .ordering │ │ │ ├── index.mjs │ │ │ ├── index.test.mjs │ │ │ ├── specifier.mjs │ │ │ └── specifier.test.mjs │ │ ├── event │ │ │ ├── .ordering │ │ │ ├── index.mjs │ │ │ ├── index.test.mjs │ │ │ ├── payload.mjs │ │ │ └── payload.test.mjs │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ ├── metadata.mjs │ │ ├── metadata.test.mjs │ │ ├── ordering │ │ │ ├── .ordering │ │ │ ├── group.mjs │ │ │ ├── group.test.mjs │ │ │ ├── index.mjs │ │ │ ├── index.test.mjs │ │ │ ├── jump.mjs │ │ │ ├── jump.test.mjs │ │ │ ├── matching.mjs │ │ │ ├── matching.test.mjs │ │ │ ├── stack.mjs │ │ │ └── stack.test.mjs │ │ ├── output.mjs │ │ └── output.test.mjs │ └── raw │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── transformer-jest │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── url-inner │ ├── browser │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── node │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── url │ └── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── util │ └── default │ │ ├── .env │ │ ├── .ordering │ │ ├── array.mjs │ │ ├── array.test.mjs │ │ ├── box.mjs │ │ ├── box.test.mjs │ │ ├── convert.mjs │ │ ├── convert.test.mjs │ │ ├── counter.mjs │ │ ├── counter.test.mjs │ │ ├── either.mjs │ │ ├── either.test.mjs │ │ ├── error.mjs │ │ ├── error.test.mjs │ │ ├── format.mjs │ │ ├── format.test.mjs │ │ ├── function.mjs │ │ ├── function.test.mjs │ │ ├── index.mjs │ │ ├── index.test.mjs │ │ ├── maybe.mjs │ │ ├── maybe.test.mjs │ │ ├── object.mjs │ │ ├── object.test.mjs │ │ ├── version.mjs │ │ └── version.test.mjs ├── uuid │ ├── random │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── stub │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── validate-appmap │ ├── default │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── stub │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs ├── validate │ ├── ajv │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs │ └── stub │ │ ├── .env │ │ ├── index.mjs │ │ └── index.test.mjs └── version │ ├── node │ ├── .env │ ├── index.mjs │ └── index.test.mjs │ └── stub │ ├── .env │ ├── index.mjs │ └── index.test.mjs ├── doc ├── blog │ ├── abomination │ │ ├── bin │ │ ├── dep.mjs │ │ ├── index.md │ │ ├── legacy-abomination.js │ │ └── loader.mjs │ ├── dependency-injection │ │ └── index.md │ ├── tap │ │ ├── index.md │ │ ├── log.txt │ │ ├── npx.appmap.json │ │ ├── screenshot-entity.png │ │ ├── screenshot-event.png │ │ ├── tap-nyc.appmap.json │ │ ├── tap.appmap.json │ │ └── test-main.appmap.json │ ├── test-runner │ │ └── index.md │ └── thread │ │ ├── Gemfile │ │ ├── Gemfile.lock │ │ ├── event-seq-tree.png │ │ ├── index.md │ │ ├── server.mjs │ │ ├── sql-trace.mjs │ │ ├── sql-trace.rb │ │ ├── sql.mjs │ │ ├── sql.rb │ │ ├── trace.mjs │ │ └── trace.rb ├── error.md ├── pipe.mjs ├── stream.mjs └── stream.test.mjs ├── lib └── node │ ├── .eslintrc.yaml │ ├── client.mjs │ ├── configuration.mjs │ ├── error.mjs │ ├── global.mjs │ ├── help.mjs │ ├── init.mjs │ ├── loader-esm.mjs │ ├── mocha-hook.mjs │ ├── recorder-api.mjs │ ├── recorder.mjs │ ├── server.mjs │ ├── setup.mjs │ ├── status.mjs │ ├── transformer-jest.mjs │ └── version.mjs ├── package-lock.json ├── package.json ├── schema ├── build.mjs ├── definitions │ ├── agent-cooked.yaml │ ├── agent.yaml │ ├── basename.yaml │ ├── combinator.yaml │ ├── command-cooked.yaml │ ├── command-options-cooked.yaml │ ├── command-options.yaml │ ├── command.yaml │ ├── config.yaml │ ├── configuration-external.yaml │ ├── configuration-internal.yaml │ ├── criteria.yaml │ ├── encoding.yaml │ ├── env.yaml │ ├── exclude-cooked.yaml │ ├── exclude.yaml │ ├── exclusion-cooked.yaml │ ├── exclusion.yaml │ ├── group.yaml │ ├── headers.yaml │ ├── heartbeat.yaml │ ├── identifier.yaml │ ├── language.yaml │ ├── log-cooked.yaml │ ├── log-level.yaml │ ├── log.yaml │ ├── matcher-cooked.yaml │ ├── matcher-module.yaml │ ├── matcher-process.yaml │ ├── message-amend.yaml │ ├── message-error.yaml │ ├── message-event.yaml │ ├── message-group.yaml │ ├── message-source.yaml │ ├── message-start.yaml │ ├── message-stop.yaml │ ├── message.yaml │ ├── module-cooked.yaml │ ├── module.yaml │ ├── name-version-object.yaml │ ├── name-version-string.yaml │ ├── name-version.yaml │ ├── natural-nullable.yaml │ ├── natural.yaml │ ├── ordering.yaml │ ├── package.yaml │ ├── parsing.yaml │ ├── path.yaml │ ├── payload-answer.yaml │ ├── payload-apply.yaml │ ├── payload-await.yaml │ ├── payload-bundle.yaml │ ├── payload-group.yaml │ ├── payload-jump.yaml │ ├── payload-query.yaml │ ├── payload-reject.yaml │ ├── payload-request.yaml │ ├── payload-resolve.yaml │ ├── payload-response.yaml │ ├── payload-return.yaml │ ├── payload-throw.yaml │ ├── payload-ungroup.yaml │ ├── payload-yield.yaml │ ├── payload.yaml │ ├── port-cooked.yaml │ ├── port-number.yaml │ ├── port-proxy.yaml │ ├── port.yaml │ ├── process.yaml │ ├── recorder.yaml │ ├── recording-object.yaml │ ├── recording-string.yaml │ ├── recording.yaml │ ├── regexp.yaml │ ├── repository.yaml │ ├── serial-primitive.yaml │ ├── serial-reference.yaml │ ├── serial-symbol.yaml │ ├── serial.yaml │ ├── serialization.yaml │ ├── session.yaml │ ├── side.yaml │ ├── signal.yaml │ ├── site.yaml │ ├── socket.yaml │ ├── source-map.yaml │ ├── source-type.yaml │ ├── specific-array.yaml │ ├── specific-error.yaml │ ├── specific-hash.yaml │ ├── specific.yaml │ ├── stdio-stream.yaml │ ├── stdio.yaml │ ├── tab.yaml │ ├── termination-disconnect.yaml │ ├── termination-exit.yaml │ ├── termination-manual.yaml │ ├── termination-test.yaml │ ├── termination-unknown.yaml │ ├── termination.yaml │ ├── threshold.yaml │ ├── url-component.yaml │ └── url.yaml └── list-permisive-object.mjs └── test ├── .eslintrc.yaml ├── cases ├── apply-async │ ├── appmap.yml │ ├── main.mjs │ └── process │ │ └── main.subset.yaml ├── apply-generator │ ├── appmap.yml │ ├── main.mjs │ └── process │ │ └── main.subset.yaml ├── apply-mismatch │ ├── appmap.yml │ ├── main.mjs │ └── process │ │ └── main.subset.yaml ├── apply-pattern │ ├── appmap.yml │ ├── main.mjs │ └── process │ │ └── main.subset.yaml ├── apply-rest │ ├── appmap.yml │ ├── main.mjs │ └── process │ │ └── main.subset.yaml ├── apply-source │ ├── appmap.yml │ ├── generate-source-map.mjs │ ├── process │ │ └── script.subset.yaml │ ├── script.mjs │ ├── source.mjs │ └── spec.yaml ├── classmap │ ├── appmap.yml │ ├── common.cjs │ ├── main.mjs │ ├── native.mjs │ └── process │ │ └── main.subset.yaml ├── default-parameter │ ├── appmap.yml │ ├── main.mjs │ └── process │ │ └── main.subset.yaml ├── env-var │ ├── appmap.yml │ ├── main.mjs │ ├── main.test.mjs │ ├── process │ │ └── main.subset.yaml │ └── spec.yaml ├── eval │ ├── appmap.yml │ ├── main.mjs │ └── process │ │ └── main.subset.yaml ├── generator-method │ ├── appmap.yml │ ├── main.mjs │ └── process │ │ └── main.subset.yaml ├── html │ ├── appmap.yml │ ├── backend.mjs │ ├── base.mjs │ ├── frontend.mjs │ ├── process │ │ └── main.subset.yaml │ ├── public │ │ ├── index.html │ │ └── index.js │ ├── spec.mjs │ └── spec.yaml ├── http │ ├── appmap.yml │ ├── main.mjs │ └── process │ │ └── main.subset.yaml ├── jest-json │ ├── appmap.yml │ ├── jest.config.json │ ├── jest │ │ └── main.subset.yaml │ ├── main.json │ └── main.test.cjs ├── jest-transformer-preset │ ├── appmap.yml │ ├── jest.config.json │ ├── jest │ │ └── main.subset.yaml │ ├── main.cjs │ ├── main.test.cjs │ ├── node_modules │ │ └── preset │ │ │ └── jest-preset.json │ └── transform.cjs ├── jest-transformer │ ├── appmap.yml │ ├── jest.config.json │ ├── jest │ │ └── main.subset.yaml │ ├── main.cjs │ ├── main.test.cjs │ └── transform.cjs ├── jest │ ├── appmap.yml │ ├── jest.config.json │ ├── jest │ │ ├── main-async.subset.yaml │ │ ├── main-callback.subset.yaml │ │ └── main-sync.subset.yaml │ ├── main.cjs │ └── main.test.cjs ├── metadata │ ├── appmap.yml │ ├── main.mjs │ └── process │ │ └── main.subset.yaml ├── mocha │ ├── appmap.yml │ ├── main.mjs │ ├── main.test.mjs │ ├── mocha │ │ ├── suite-1.subset.yaml │ │ ├── suite-2.subset.yaml │ │ ├── suite-3.subset.yaml │ │ ├── suite-4.subset.yaml │ │ └── suite.subset.yaml │ └── spec.yaml ├── npx │ ├── appmap.yml │ ├── node_modules │ │ └── .gitignore │ ├── process │ │ └── bin-sample.subset.yaml │ └── spec.yaml ├── query │ ├── appmap.yml │ ├── main.mjs │ └── process │ │ └── main.subset.yaml ├── to-string │ ├── appmap.yml │ ├── main.mjs │ └── process │ │ └── main.subset.yaml ├── ts-node-esm │ ├── appmap.yml │ ├── square.test.ts │ └── square.ts └── version │ ├── appmap.yml │ ├── spec.yaml │ └── version.regexp.text ├── legacy ├── api │ └── index.mjs ├── cli │ ├── __fixture__.mjs │ ├── index.mjs │ └── remote.mjs ├── index.mjs └── npm │ └── index.mjs ├── log.mjs ├── match.mjs ├── spawn.mjs ├── system.mjs ├── unit.mjs └── util.mjs /.bercowrc-test-only-cov.yaml: -------------------------------------------------------------------------------- 1 | plugins: 2 | "@bercow/link-adjacent": {} 3 | "@bercow/spawn": 4 | command: npx 5 | command-win32: npx.cmd 6 | argv: 7 | - c8 8 | - --100 9 | - --include 10 | - $RELATIVE_MAIN_PATH 11 | - -- 12 | - node 13 | - --unhandled-rejections=strict 14 | - $RELATIVE_TEST_PATH 15 | -------------------------------------------------------------------------------- /.bercowrc-test-only.yaml: -------------------------------------------------------------------------------- 1 | plugins: 2 | "@bercow/link-adjacent": {} 3 | "@bercow/spawn": 4 | command: node 5 | argv: 6 | - --unhandled-rejections=strict 7 | - $TEST 8 | -------------------------------------------------------------------------------- /.bercowrc.yaml: -------------------------------------------------------------------------------- 1 | plugins: 2 | "@bercow/link-adjacent": {} 3 | "@bercow/prettier": 4 | prettier-options: "." 5 | "@bercow/eslint": {} 6 | "@bercow/spawn": 7 | command: npx 8 | command-win32: npx.cmd 9 | argv: 10 | - c8 11 | - --100 12 | - --include 13 | - $RELATIVE_MAIN_PATH 14 | - -- 15 | - node 16 | - --unhandled-rejections=strict 17 | - $RELATIVE_TEST_PATH 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | 2 | root = true 3 | 4 | [**.{js,mjs,yml,json}] 5 | charset = utf-8 6 | end_of_line = lf 7 | insert_final_newline = true 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | max_line_length = 80 12 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /.github 2 | /components/*/index.mjs 3 | /coverage 4 | /dist 5 | /doc 6 | /node_modules 7 | /test/pack 8 | /test/cases/apply-source/source.mjs 9 | /tmp 10 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Add new issues to project tracker 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | 8 | jobs: 9 | add-to-project: 10 | name: Add issue to project 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/add-to-project@main 14 | with: 15 | project-url: https://github.com/orgs/getappmap/projects/15 16 | github-token: ${{ secrets.ADD_TO_PROJECT_BOARD_PAT }} 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | /components/*/index.mjs 3 | /components/*/*/.eslintrc.json 4 | /coverage 5 | /dist 6 | /node_modules 7 | /test/cases/**/*.output.* 8 | /test/cases/**/*.appmap.* 9 | /test/cases/npx/package.json 10 | /test/cases/npx/package-lock.json 11 | /test/cases/apply-source/source.map 12 | /test/pack 13 | /tmp 14 | 15 | .DS_Store 16 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /.github 2 | /component 3 | /components 4 | /coverage 5 | /doc 6 | /node_modules 7 | /schema 8 | /test 9 | /tmp 10 | /babel.config.json 11 | /CONTRIBUTING.md 12 | /REFERENCE.md 13 | 14 | .* 15 | -------------------------------------------------------------------------------- /.ordering: -------------------------------------------------------------------------------- 1 | components 2 | -------------------------------------------------------------------------------- /.ordering-ignore: -------------------------------------------------------------------------------- 1 | **/*.test.mjs 2 | !(**/*.mjs) 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /.github 2 | /components/*/index.mjs 3 | /components/*/*/.eslintrc.json 4 | /coverage 5 | /dist 6 | /doc 7 | /node_modules 8 | /test/cases/**/*.appmap.json 9 | /test/pack 10 | /tmp 11 | /package.json 12 | /package-lock.json 13 | 14 | *.md 15 | -------------------------------------------------------------------------------- /.prettierrc.yaml: -------------------------------------------------------------------------------- 1 | trailingComma: all 2 | tabWidth: 2 3 | semi: true 4 | singleQuote: false 5 | arrowParens: always 6 | endOfLine: lf 7 | printWidth: 80 8 | proseWrap: always 9 | -------------------------------------------------------------------------------- /.releaserc.yaml: -------------------------------------------------------------------------------- 1 | repositoryUrl: https://github.com/getappmap/appmap-agent-js.git 2 | tagFormat: v${version} 3 | dryRun: false 4 | ci: true 5 | branches: 6 | - name: main 7 | plugins: 8 | - "@semantic-release/commit-analyzer" 9 | - "@semantic-release/release-notes-generator" 10 | - "@semantic-release/changelog" 11 | - "@semantic-release/npm" 12 | - "@semantic-release/git" 13 | - "@semantic-release/github" 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecated 2 | 3 | This project is deprecated. Please use https://github.com/getappmap/appmap-node/ to record Node.js applications. 4 | -------------------------------------------------------------------------------- /babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["@babel/plugin-syntax-top-level-await"] 3 | } 4 | -------------------------------------------------------------------------------- /bin/.eslintrc.yaml: -------------------------------------------------------------------------------- 1 | env: 2 | node: true 3 | -------------------------------------------------------------------------------- /component/.eslintrc.yaml: -------------------------------------------------------------------------------- 1 | env: 2 | node: true 3 | -------------------------------------------------------------------------------- /component/build-test.mjs: -------------------------------------------------------------------------------- 1 | import { home } from "./home.mjs"; 2 | import { routeAsync } from "./route.mjs"; 3 | import { writeEslintAsync } from "./eslint.mjs"; 4 | await routeAsync(home, "test", {}); 5 | await writeEslintAsync(home); 6 | -------------------------------------------------------------------------------- /component/build.mjs: -------------------------------------------------------------------------------- 1 | await import("./build-prod.mjs"); 2 | await import("./build-test.mjs"); 3 | -------------------------------------------------------------------------------- /component/home.mjs: -------------------------------------------------------------------------------- 1 | import { pathToFileURL } from "node:url"; 2 | import { cwd } from "node:process"; 3 | const { URL } = globalThis; 4 | 5 | export const home = new URL(`${pathToFileURL(cwd())}/`); 6 | -------------------------------------------------------------------------------- /component/lint.mjs: -------------------------------------------------------------------------------- 1 | import { home } from "./home.mjs"; 2 | import { checkSignatureAsync } from "./signature.mjs"; 3 | await checkSignatureAsync(home); 4 | -------------------------------------------------------------------------------- /component/support.mjs: -------------------------------------------------------------------------------- 1 | import { readFile as readFileAsync } from "node:fs/promises"; 2 | import { getInstanceSupportUrl } from "./layout.mjs"; 3 | 4 | const isNotEmptyString = (any) => any !== ""; 5 | 6 | const parseSupport = (content) => 7 | content.replace(/\r/gu, "").split("\n").filter(isNotEmptyString); 8 | 9 | export const readInstanceSupportAsync = async (home, component, instance) => 10 | parseSupport( 11 | await readFileAsync( 12 | getInstanceSupportUrl(home, component, instance), 13 | "utf8", 14 | ), 15 | ); 16 | -------------------------------------------------------------------------------- /components/.ordering-ignore: -------------------------------------------------------------------------------- 1 | */index.mjs 2 | -------------------------------------------------------------------------------- /components/assert/check/.env: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /components/assert/default/.env: -------------------------------------------------------------------------------- 1 | node 2 | browser 3 | -------------------------------------------------------------------------------- /components/assert/default/index.mjs: -------------------------------------------------------------------------------- 1 | const { Error } = globalThis; 2 | 3 | export class AssertionError extends Error { 4 | constructor(message) { 5 | super(message); 6 | this.name = "AssertionError"; 7 | } 8 | } 9 | 10 | export const assert = (boolean, message, Constructor) => { 11 | if (!boolean) { 12 | throw new Constructor(message); 13 | } 14 | }; 15 | 16 | export const generateDeadcode = (message, Constructor) => () => { 17 | throw new Constructor(message); 18 | }; 19 | -------------------------------------------------------------------------------- /components/assert/default/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual, assertThrow } from "../../__fixture__.mjs"; 2 | import { AssertionError, assert, generateDeadcode } from "./index.mjs"; 3 | 4 | const { undefined, Error } = globalThis; 5 | 6 | assertEqual(new AssertionError("message").name, "AssertionError"); 7 | 8 | assertEqual(assert(true, "foo", Error), undefined); 9 | 10 | assertThrow(() => { 11 | assert(false, "foo", Error); 12 | }, /^Error: foo/u); 13 | 14 | assertThrow(() => generateDeadcode("foo", Error)("bar"), /^Error: foo/u); 15 | -------------------------------------------------------------------------------- /components/backend/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/backend/default/.ordering: -------------------------------------------------------------------------------- 1 | track.mjs 2 | session.mjs 3 | index.mjs 4 | -------------------------------------------------------------------------------- /components/client/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/command/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/command/node/.ordering: -------------------------------------------------------------------------------- 1 | escape.mjs 2 | tokenize.mjs 3 | package.mjs 4 | mocha.mjs 5 | jest-config.mjs 6 | jest-argv.mjs 7 | jest.mjs 8 | node.mjs 9 | process.mjs 10 | remote.mjs 11 | node-recursive.mjs 12 | process-recursive.mjs 13 | remote-recursive.mjs 14 | index.mjs 15 | -------------------------------------------------------------------------------- /components/command/node/escape.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual } from "../../__fixture__.mjs"; 2 | 3 | import { escapeNodeOption, resolveShell } from "./escape.mjs"; 4 | 5 | // escapeNodeOption // 6 | 7 | assertEqual(escapeNodeOption("token"), "token"); 8 | 9 | // resolveShell // 10 | 11 | assertEqual(resolveShell("shell", {}), "shell"); 12 | 13 | assertEqual(resolveShell(false, {}), null); 14 | 15 | assertEqual(resolveShell(true, { COMSPEC: "shell", SHELL: "shell" }), "shell"); 16 | -------------------------------------------------------------------------------- /components/command/node/mocha.mjs: -------------------------------------------------------------------------------- 1 | import { coalesce } from "../../util/index.mjs"; 2 | import { convertFileUrlToPath } from "../../path/index.mjs"; 3 | import { toAbsoluteUrl } from "../../url/index.mjs"; 4 | import { escapeNodeOption } from "./escape.mjs"; 5 | import { sniffTokens, splitTokens } from "./package.mjs"; 6 | 7 | export const name = "mocha"; 8 | export const recursive = null; 9 | 10 | export const doesSupport = (tokens) => sniffTokens(tokens, "mocha"); 11 | 12 | export const hookCommandAsync = (tokens, self, _base) => { 13 | const { exec, argv } = splitTokens(tokens); 14 | return [ 15 | ...exec, 16 | "--require", 17 | convertFileUrlToPath(toAbsoluteUrl("lib/node/mocha-hook.mjs", self)), 18 | ...argv, 19 | ]; 20 | }; 21 | 22 | export const hookEnvironment = (env, self, _base) => ({ 23 | ...env, 24 | NODE_OPTIONS: `${coalesce( 25 | env, 26 | "NODE_OPTIONS", 27 | "", 28 | )} --experimental-loader=${escapeNodeOption( 29 | toAbsoluteUrl("lib/node/recorder.mjs", self), 30 | )}`, 31 | }); 32 | -------------------------------------------------------------------------------- /components/command/node/node-recursive.mjs: -------------------------------------------------------------------------------- 1 | import { constant, coalesce } from "../../util/index.mjs"; 2 | import { toAbsoluteUrl } from "../../url/index.mjs"; 3 | import { escapeNodeOption } from "./escape.mjs"; 4 | 5 | const doesSupport = constant(true); 6 | 7 | export const generateNodeRecorder = (recorder) => ({ 8 | name: recorder, 9 | recursive: true, 10 | doesSupport, 11 | hookCommandAsync: (tokens, _self, _base) => tokens, 12 | hookEnvironment: (env, self, _base) => ({ 13 | ...env, 14 | NODE_OPTIONS: `${coalesce( 15 | env, 16 | "NODE_OPTIONS", 17 | "", 18 | )} --experimental-loader=${escapeNodeOption( 19 | toAbsoluteUrl(`lib/node/recorder.mjs`, self), 20 | )}`, 21 | }), 22 | }); 23 | -------------------------------------------------------------------------------- /components/command/node/node-recursive.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual, assertDeepEqual } from "../../__fixture__.mjs"; 2 | import { generateNodeRecorder } from "./node-recursive.mjs"; 3 | 4 | const { name, recursive, doesSupport, hookCommandAsync, hookEnvironment } = 5 | generateNodeRecorder("process"); 6 | 7 | const base = "file:///A:/base/"; 8 | const self = "file:///A:/self/"; 9 | const recorder_url = "file:///A:/self/lib/node/recorder.mjs"; 10 | 11 | assertEqual(name, "process"); 12 | 13 | assertEqual(recursive, true); 14 | 15 | assertEqual(doesSupport(["token"]), true); 16 | 17 | assertDeepEqual(await hookCommandAsync(["token"], self, base), ["token"]); 18 | 19 | assertDeepEqual( 20 | hookEnvironment({ FOO: "bar", NODE_OPTIONS: "options" }, self, base), 21 | { 22 | FOO: "bar", 23 | NODE_OPTIONS: `options --experimental-loader=${recorder_url}`, 24 | }, 25 | ); 26 | -------------------------------------------------------------------------------- /components/command/node/node.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual, assertDeepEqual } from "../../__fixture__.mjs"; 2 | import { generateNodeRecorder } from "./node.mjs"; 3 | 4 | const { name, recursive, doesSupport, hookCommandAsync, hookEnvironment } = 5 | generateNodeRecorder("process"); 6 | 7 | const self = "file:///A:/self/"; 8 | const base = "file:///A:/base/"; 9 | const recorder_url = "file:///A:/self/lib/node/recorder.mjs"; 10 | 11 | assertEqual(name, "process"); 12 | assertEqual(recursive, false); 13 | 14 | assertEqual(doesSupport(["node.ext", "main.mjs"]), true); 15 | assertDeepEqual(await hookCommandAsync(["node.ext", "main.mjs"], self, base), [ 16 | "node.ext", 17 | "--experimental-loader", 18 | recorder_url, 19 | "main.mjs", 20 | ]); 21 | 22 | assertDeepEqual(hookEnvironment({ FOO: "bar" }, self, base), { FOO: "bar" }); 23 | -------------------------------------------------------------------------------- /components/command/node/process-recursive.mjs: -------------------------------------------------------------------------------- 1 | import { generateNodeRecorder } from "./node-recursive.mjs"; 2 | export const { 3 | name, 4 | recursive, 5 | doesSupport, 6 | hookCommandAsync, 7 | hookEnvironment, 8 | } = generateNodeRecorder("process"); 9 | -------------------------------------------------------------------------------- /components/command/node/process-recursive.test.mjs: -------------------------------------------------------------------------------- 1 | import "./process-recursive.mjs"; 2 | -------------------------------------------------------------------------------- /components/command/node/process.mjs: -------------------------------------------------------------------------------- 1 | import { generateNodeRecorder } from "./node.mjs"; 2 | export const { 3 | name, 4 | recursive, 5 | doesSupport, 6 | hookCommandAsync, 7 | hookEnvironment, 8 | } = generateNodeRecorder("process"); 9 | -------------------------------------------------------------------------------- /components/command/node/process.test.mjs: -------------------------------------------------------------------------------- 1 | import "./process.mjs"; 2 | -------------------------------------------------------------------------------- /components/command/node/remote-recursive.mjs: -------------------------------------------------------------------------------- 1 | import { generateNodeRecorder } from "./node-recursive.mjs"; 2 | export const { 3 | name, 4 | recursive, 5 | doesSupport, 6 | hookCommandAsync, 7 | hookEnvironment, 8 | } = generateNodeRecorder("remote"); 9 | -------------------------------------------------------------------------------- /components/command/node/remote-recursive.test.mjs: -------------------------------------------------------------------------------- 1 | import "./remote-recursive.mjs"; 2 | -------------------------------------------------------------------------------- /components/command/node/remote.mjs: -------------------------------------------------------------------------------- 1 | import { generateNodeRecorder } from "./node.mjs"; 2 | export const { 3 | name, 4 | recursive, 5 | doesSupport, 6 | hookCommandAsync, 7 | hookEnvironment, 8 | } = generateNodeRecorder("remote"); 9 | -------------------------------------------------------------------------------- /components/command/node/remote.test.mjs: -------------------------------------------------------------------------------- 1 | import "./remote.mjs"; 2 | -------------------------------------------------------------------------------- /components/command/node/tokenize.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertDeepEqual } from "../../__fixture__.mjs"; 2 | 3 | import { tokenizeShell, tokenize } from "./tokenize.mjs"; 4 | 5 | /////////////////// 6 | // tokenizeShell // 7 | /////////////////// 8 | 9 | assertDeepEqual(tokenizeShell("foo"), ["foo"]); 10 | 11 | assertDeepEqual(tokenizeShell(" foo bar "), ["foo", "bar"]); 12 | 13 | assertDeepEqual(tokenizeShell(" foo\\ bar "), ["foo\\ bar"]); 14 | 15 | assertDeepEqual(tokenizeShell(` "foo \\" bar" `), [`"foo \\" bar"`]); 16 | 17 | assertDeepEqual(tokenizeShell(` '\\foo \\ bar\\' `), [`'\\foo \\ bar\\'`]); 18 | 19 | ////////////// 20 | // tokenize // 21 | ////////////// 22 | 23 | assertDeepEqual(tokenize("foo bar", null), ["foo", "bar"]); 24 | 25 | assertDeepEqual(tokenize("foo bar", "/bin/sh"), ["/bin/sh", "-c", "foo bar"]); 26 | 27 | assertDeepEqual(tokenize("foo bar", "cmd.exe"), [ 28 | "cmd.exe", 29 | "/d", 30 | "/s", 31 | "/c", 32 | '"foo bar"', 33 | ]); 34 | -------------------------------------------------------------------------------- /components/compress/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/configuration-accessor/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/configuration-accessor/default/.ordering: -------------------------------------------------------------------------------- 1 | escape.mjs 2 | tokenize.mjs 3 | package.mjs 4 | mocha.mjs 5 | jest-config.mjs 6 | jest-argv.mjs 7 | jest.mjs 8 | node.mjs 9 | process.mjs 10 | remote.mjs 11 | node-recursive.mjs 12 | process-recursive.mjs 13 | remote-recursive.mjs 14 | index.mjs 15 | -------------------------------------------------------------------------------- /components/configuration-environment/default/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/configuration-environment/default/index.mjs: -------------------------------------------------------------------------------- 1 | import { InternalAppmapError } from "../../error/index.mjs"; 2 | import { assert, hasOwnProperty } from "../../util/index.mjs"; 3 | import { validateInternalConfiguration } from "../../validate/index.mjs"; 4 | 5 | const { 6 | JSON: { parse: parseJSON }, 7 | } = globalThis; 8 | 9 | export const loadEnvironmentConfiguration = (env) => { 10 | assert( 11 | hasOwnProperty(env, "APPMAP_CONFIGURATION"), 12 | "Missing 'APPMAP_CONFIGURATION' environment variable", 13 | InternalAppmapError, 14 | ); 15 | const { APPMAP_CONFIGURATION: content } = env; 16 | const configuration = parseJSON(content); 17 | validateInternalConfiguration(configuration); 18 | return configuration; 19 | }; 20 | -------------------------------------------------------------------------------- /components/configuration-environment/default/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "../../__fixture__.mjs"; 2 | import { createConfiguration } from "../../configuration/index.mjs"; 3 | import { loadEnvironmentConfiguration } from "./index.mjs"; 4 | 5 | const { 6 | JSON: { stringify: stringifyJSON }, 7 | } = globalThis; 8 | 9 | loadEnvironmentConfiguration({ 10 | APPMAP_CONFIGURATION: stringifyJSON( 11 | createConfiguration("protocol://host/home"), 12 | ), 13 | }); 14 | -------------------------------------------------------------------------------- /components/configuration-process/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/configuration/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/crash-reporter/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/crash-reporter/node/index.test.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getappmap/appmap-agent-js/124514f4baba2b8c9a267fd4a3357ce954e4a971/components/crash-reporter/node/index.test.mjs -------------------------------------------------------------------------------- /components/engine/browser/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/engine/browser/index.mjs: -------------------------------------------------------------------------------- 1 | import { ExternalAppmapError } from "../../error/index.mjs"; 2 | import { logErrorWhen } from "../../log/index.mjs"; 3 | import { assert } from "../../util/index.mjs"; 4 | 5 | const { 6 | navigator: { userAgent: description }, 7 | } = globalThis; 8 | 9 | const regexp = /^([^ \n\t/]+)\/([^ \n\t/]+) /u; 10 | 11 | export const getEngine = () => { 12 | const parts = regexp.exec(description); 13 | assert( 14 | !logErrorWhen( 15 | parts === null, 16 | "Could not parse navigator.userAgent: %j", 17 | description, 18 | ), 19 | "Could not parse userAgent", 20 | ExternalAppmapError, 21 | ); 22 | return `${parts[1]}@${parts[2]}`; 23 | }; 24 | -------------------------------------------------------------------------------- /components/engine/browser/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { defineGlobal } from "../../global/index.mjs"; 2 | import { assertDeepEqual } from "../../__fixture__.mjs"; 3 | 4 | defineGlobal("navigator", { 5 | userAgent: "name/version rest", 6 | }); 7 | 8 | const { getEngine } = await import("./index.mjs"); 9 | 10 | assertDeepEqual(getEngine(), "name@version"); 11 | -------------------------------------------------------------------------------- /components/engine/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/engine/node/index.mjs: -------------------------------------------------------------------------------- 1 | import { constant } from "../../util/index.mjs"; 2 | 3 | const { 4 | process: { version }, 5 | } = globalThis; 6 | 7 | export const getEngine = constant(`node@${version}`); 8 | -------------------------------------------------------------------------------- /components/engine/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "../../__fixture__.mjs"; 2 | import "./index.mjs"; 3 | -------------------------------------------------------------------------------- /components/engine/stub/.env: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /components/engine/stub/index.mjs: -------------------------------------------------------------------------------- 1 | import { constant } from "../../util/index.mjs"; 2 | export const getEngine = constant("engine@0.0.0"); 3 | -------------------------------------------------------------------------------- /components/engine/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "../../__fixture__.mjs"; 2 | import "./index.mjs"; 3 | -------------------------------------------------------------------------------- /components/error/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/event/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/file/dead/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/file/dead/index.mjs: -------------------------------------------------------------------------------- 1 | import { generateDeadcode } from "../../util/index.mjs"; 2 | import { InternalAppmapError } from "../../error/index.mjs"; 3 | 4 | export const readFile = generateDeadcode( 5 | "forbidden call to readFile", 6 | InternalAppmapError, 7 | ); 8 | 9 | export const readFileAsync = generateDeadcode( 10 | "forbidden call to readFileAsync", 11 | InternalAppmapError, 12 | ); 13 | -------------------------------------------------------------------------------- /components/file/dead/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/file/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/file/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { writeFile as writeFileAsync } from "node:fs/promises"; 2 | import { assertEqual, assertThrow } from "../../__fixture__.mjs"; 3 | import { toAbsoluteUrl } from "../../url/index.mjs"; 4 | import { getUuid } from "../../uuid/random/index.mjs"; 5 | import { getTmpUrl } from "../../path/index.mjs"; 6 | import { readFile } from "./index.mjs"; 7 | 8 | const { URL } = globalThis; 9 | 10 | { 11 | const url = toAbsoluteUrl(getUuid(), getTmpUrl()); 12 | await writeFileAsync(new URL(url), "content", "utf8"); 13 | assertEqual(readFile(url), "content"); 14 | } 15 | 16 | assertEqual(readFile("data:,Hello%2C%20World%21"), "Hello, World!"); 17 | 18 | assertEqual( 19 | readFile("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=="), 20 | "Hello, World!", 21 | ); 22 | 23 | assertThrow(() => readFile("http://locahost/"), /Error: unsupported protocol/u); 24 | -------------------------------------------------------------------------------- /components/frontend/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/frontend/default/.ordering: -------------------------------------------------------------------------------- 1 | index.mjs 2 | -------------------------------------------------------------------------------- /components/glob/dead/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/glob/dead/index.mjs: -------------------------------------------------------------------------------- 1 | import { generateDeadcode } from "../../util/index.mjs"; 2 | import { InternalAppmapError } from "../../error/index.mjs"; 3 | 4 | export const compileGlob = generateDeadcode( 5 | "forbidden compileGlob call", 6 | InternalAppmapError, 7 | ); 8 | -------------------------------------------------------------------------------- /components/glob/dead/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/glob/minimatch/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/glob/minimatch/index.mjs: -------------------------------------------------------------------------------- 1 | import Minimatch from "minimatch"; 2 | const { Minimatch: MinimatchClass } = Minimatch; 3 | 4 | export const compileGlob = (glob) => new MinimatchClass(glob).makeRe(); 5 | -------------------------------------------------------------------------------- /components/glob/minimatch/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual } from "../../__fixture__.mjs"; 2 | import { compileGlob } from "./index.mjs"; 3 | 4 | const { RegExp } = globalThis; 5 | 6 | const { source, flags } = compileGlob("*.js"); 7 | 8 | const regexp = new RegExp(source, flags); 9 | 10 | assertEqual(regexp.test("foo.js"), true); 11 | 12 | assertEqual(regexp.test("foo.ts"), false); 13 | -------------------------------------------------------------------------------- /components/global/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/global/default/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertThrow, assertEqual } from "../../__fixture__.mjs"; 2 | import { defineGlobal, writeGlobal, readGlobal } from "./index.mjs"; 3 | 4 | const { ReferenceError, undefined } = globalThis; 5 | 6 | assertThrow(() => readGlobal("__GLOBAL__"), ReferenceError); 7 | 8 | assertThrow(() => writeGlobal("__GLOBAL__", "value"), ReferenceError); 9 | 10 | assertEqual(defineGlobal("__GLOBAL__", "value", true), true); 11 | 12 | assertEqual(defineGlobal("__GLOBAL__", "value", true), false); 13 | 14 | assertEqual(readGlobal("__GLOBAL__"), "value"); 15 | 16 | assertEqual(writeGlobal("__GLOBAL__", "VALUE"), undefined); 17 | 18 | assertEqual(readGlobal("__GLOBAL__"), "VALUE"); 19 | -------------------------------------------------------------------------------- /components/group/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/group/node/index.mjs: -------------------------------------------------------------------------------- 1 | export { executionAsyncId as getCurrentGroup } from "node:async_hooks"; 2 | -------------------------------------------------------------------------------- /components/group/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/group/stub/.env: -------------------------------------------------------------------------------- 1 | test 2 | browser 3 | -------------------------------------------------------------------------------- /components/group/stub/index.mjs: -------------------------------------------------------------------------------- 1 | import { constant } from "../../util/index.mjs"; 2 | 3 | export const getCurrentGroup = constant(0); 4 | -------------------------------------------------------------------------------- /components/group/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "../../__fixture__.mjs"; 2 | import "./index.mjs"; 3 | -------------------------------------------------------------------------------- /components/hash/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | test 3 | -------------------------------------------------------------------------------- /components/hash/node/index.mjs: -------------------------------------------------------------------------------- 1 | import { createHash } from "node:crypto"; 2 | 3 | export const digest = (string) => { 4 | const hash = createHash("sha256"); 5 | hash.update(string, "utf8"); 6 | return hash.digest("base64"); 7 | }; 8 | -------------------------------------------------------------------------------- /components/hash/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual, assertNotEqual } from "../../__fixture__.mjs"; 2 | import { digest } from "./index.mjs"; 3 | 4 | assertEqual(typeof digest("foo"), "string"); 5 | 6 | assertEqual(digest("foo"), digest("foo")); 7 | 8 | assertNotEqual(digest("foo"), digest("bar")); 9 | -------------------------------------------------------------------------------- /components/hook-apply/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/hook-error/browser/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/hook-error/browser/index.mjs: -------------------------------------------------------------------------------- 1 | import { recordError } from "../../frontend/index.mjs"; 2 | 3 | const { window } = globalThis; 4 | 5 | export const hook = (frontend, _configuration) => { 6 | const listener = (error) => { 7 | recordError(frontend, error); 8 | }; 9 | window.addEventListener("error", listener); 10 | return listener; 11 | }; 12 | 13 | export const unhook = (listener) => { 14 | window.removeEventListener("error", listener); 15 | }; 16 | -------------------------------------------------------------------------------- /components/hook-error/browser/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual } from "../../__fixture__.mjs"; 2 | import { testHookAsync } from "../../hook-fixture/index.mjs"; 3 | import { defineGlobal } from "../../global/index.mjs"; 4 | 5 | const { Error } = globalThis; 6 | 7 | const window = { 8 | onError: null, 9 | addEventListener(name, listener) { 10 | assertEqual(name, "error"); 11 | this.onError = listener; 12 | }, 13 | removeEventListener(name, listener) { 14 | assertEqual(name, "error"); 15 | assertEqual(this.onError, listener); 16 | this.onError = null; 17 | }, 18 | }; 19 | 20 | defineGlobal("window", window); 21 | 22 | assertEqual( 23 | ( 24 | await testHookAsync(await import("./index.mjs"), {}, () => { 25 | window.onError(new Error("message")); 26 | }) 27 | )[0].error.specific.message, 28 | "message", 29 | ); 30 | -------------------------------------------------------------------------------- /components/hook-error/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/hook-error/node/index.mjs: -------------------------------------------------------------------------------- 1 | import process from "node:process"; 2 | import { recordError } from "../../frontend/index.mjs"; 3 | 4 | export const hook = (frontend, _configuration) => { 5 | const listener = (error) => { 6 | recordError(frontend, error); 7 | }; 8 | process.addListener("uncaughtExceptionMonitor", listener); 9 | return listener; 10 | }; 11 | 12 | export const unhook = (listener) => { 13 | process.removeListener("uncaughtExceptionMonitor", listener); 14 | }; 15 | -------------------------------------------------------------------------------- /components/hook-error/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import process from "node:process"; 2 | import { assertEqual } from "../../__fixture__.mjs"; 3 | import { testHookAsync } from "../../hook-fixture/index.mjs"; 4 | import * as HookError from "./index.mjs"; 5 | 6 | const { Error } = globalThis; 7 | 8 | assertEqual( 9 | ( 10 | await testHookAsync(HookError, {}, () => { 11 | process.emit("uncaughtExceptionMonitor", new Error("message")); 12 | }) 13 | )[0].error.specific.message, 14 | "message", 15 | ); 16 | -------------------------------------------------------------------------------- /components/hook-eval/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/hook-eval/stub/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/hook-eval/stub/index.mjs: -------------------------------------------------------------------------------- 1 | import { noop } from "../../util/index.mjs"; 2 | 3 | export const hook = noop; 4 | export const unhook = noop; 5 | -------------------------------------------------------------------------------- /components/hook-eval/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/hook-exit/browser/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/hook-exit/browser/index.mjs: -------------------------------------------------------------------------------- 1 | import { recordStopTrack } from "../../frontend/index.mjs"; 2 | 3 | const { window } = globalThis; 4 | 5 | export const hook = (frontend, _configuration) => { 6 | const listener = () => { 7 | recordStopTrack(frontend, null, { type: "exit", status: 0 }); 8 | }; 9 | window.addEventListener("beforeunload", listener); 10 | return listener; 11 | }; 12 | 13 | export const unhook = (listener) => { 14 | window.removeEventListener("beforeunload", listener); 15 | }; 16 | -------------------------------------------------------------------------------- /components/hook-exit/browser/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual, assertDeepEqual } from "../../__fixture__.mjs"; 2 | import { defineGlobal } from "../../global/index.mjs"; 3 | import { testHookAsync } from "../../hook-fixture/index.mjs"; 4 | 5 | const window = { 6 | onBeforeUnload: null, 7 | addEventListener(name, listener) { 8 | assertEqual(name, "beforeunload"); 9 | assertEqual(this.onBeforeUnload, null); 10 | this.onBeforeUnload = listener; 11 | }, 12 | removeEventListener(name, listener) { 13 | assertEqual(name, "beforeunload"); 14 | assertEqual(this.onBeforeUnload, listener); 15 | this.onBeforeUnload = null; 16 | }, 17 | }; 18 | 19 | defineGlobal("window", window); 20 | 21 | assertDeepEqual( 22 | await testHookAsync(await import("./index.mjs"), {}, () => { 23 | window.onBeforeUnload(); 24 | }), 25 | [ 26 | { 27 | type: "stop", 28 | track: null, 29 | termination: { type: "exit", status: 0 }, 30 | }, 31 | ], 32 | ); 33 | -------------------------------------------------------------------------------- /components/hook-exit/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/hook-exit/node/index.mjs: -------------------------------------------------------------------------------- 1 | import process from "node:process"; 2 | import { toInteger } from "../../util/index.mjs"; 3 | import { recordStopTrack } from "../../frontend/index.mjs"; 4 | 5 | const { 6 | Number: { isNaN }, 7 | } = globalThis; 8 | 9 | const toStatus = (any) => { 10 | const integer = toInteger(any); 11 | if (isNaN(integer) || integer < 0 || integer > 255) { 12 | return 1; 13 | } else { 14 | return integer; 15 | } 16 | }; 17 | 18 | export const hook = (frontend, _configuration) => { 19 | const listener = (status) => { 20 | recordStopTrack(frontend, null, { 21 | type: "exit", 22 | status: toStatus(status), 23 | }); 24 | }; 25 | process.addListener("beforeExit", listener); 26 | process.addListener("exit", listener); 27 | return listener; 28 | }; 29 | 30 | export const unhook = (listener) => { 31 | process.removeListener("beforeExit", listener); 32 | process.removeListener("exit", listener); 33 | }; 34 | -------------------------------------------------------------------------------- /components/hook-exit/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import process from "node:process"; 2 | import { assertDeepEqual } from "../../__fixture__.mjs"; 3 | import { testHookAsync } from "../../hook-fixture/index.mjs"; 4 | import * as HookExit from "./index.mjs"; 5 | 6 | assertDeepEqual( 7 | await testHookAsync(HookExit, {}, () => { 8 | process.emit("exit", 0); 9 | }), 10 | [ 11 | { 12 | type: "stop", 13 | track: null, 14 | termination: { type: "exit", status: 0 }, 15 | }, 16 | ], 17 | ); 18 | 19 | assertDeepEqual( 20 | await testHookAsync(HookExit, {}, () => { 21 | process.emit("exit", -1); 22 | }), 23 | [ 24 | { 25 | type: "stop", 26 | track: null, 27 | termination: { type: "exit", status: 1 }, 28 | }, 29 | ], 30 | ); 31 | 32 | process.exitCode = 0; 33 | -------------------------------------------------------------------------------- /components/hook-fixture/fixture/.env: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /components/hook-fixture/fixture/index.mjs: -------------------------------------------------------------------------------- 1 | import { 2 | createConfiguration, 3 | extendConfiguration, 4 | } from "../../configuration/index.mjs"; 5 | import { validateMessage } from "../../validate/index.mjs"; 6 | import { createFrontend, flushMessageArray } from "../../frontend/index.mjs"; 7 | 8 | export const testHookAsync = async ( 9 | { hook, unhook }, 10 | options, 11 | callbackAsync, 12 | ) => { 13 | options = { 14 | configuration: {}, 15 | url: null, 16 | ...options, 17 | }; 18 | const configuration = extendConfiguration( 19 | createConfiguration(import.meta.url), 20 | { ...options.configuration, session: "session" }, 21 | options.url, 22 | ); 23 | const frontend = createFrontend(configuration); 24 | const hooking = hook(frontend, configuration); 25 | try { 26 | await callbackAsync(); 27 | } finally { 28 | unhook(hooking); 29 | } 30 | const messages = flushMessageArray(frontend); 31 | messages.forEach(validateMessage); 32 | return messages; 33 | }; 34 | -------------------------------------------------------------------------------- /components/hook-fixture/fixture/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertDeepEqual, assertEqual } from "../../__fixture__.mjs"; 2 | import { testHookAsync } from "./index.mjs"; 3 | 4 | assertDeepEqual( 5 | await testHookAsync( 6 | { 7 | hook: (_frontend, _configuration) => "hooking", 8 | unhook: (hooking) => { 9 | assertEqual(hooking, "hooking"); 10 | }, 11 | }, 12 | {}, 13 | async () => {}, 14 | ), 15 | [], 16 | ); 17 | -------------------------------------------------------------------------------- /components/hook-group/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/hook-group/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertDeepEqual } from "../../__fixture__.mjs"; 2 | import { testHookAsync } from "../../hook-fixture/index.mjs"; 3 | import * as HookGroup from "./index.mjs"; 4 | 5 | const { Promise, setTimeout } = globalThis; 6 | 7 | assertDeepEqual( 8 | await testHookAsync( 9 | HookGroup, 10 | { configuration: { ordering: "chronological" } }, 11 | async () => { 12 | await new Promise((resolve) => { 13 | setTimeout(resolve); 14 | }); 15 | }, 16 | ), 17 | [], 18 | ); 19 | 20 | // provide an unknown async id 21 | setTimeout(() => {}, 100); 22 | 23 | await testHookAsync( 24 | HookGroup, 25 | { configuration: { ordering: "causal" } }, 26 | async () => { 27 | await new Promise((resolve) => { 28 | setTimeout(resolve, 100); 29 | }); 30 | await new Promise((resolve) => { 31 | setTimeout(resolve, 100); 32 | }); 33 | }, 34 | ); 35 | -------------------------------------------------------------------------------- /components/hook-group/stub/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/hook-group/stub/index.mjs: -------------------------------------------------------------------------------- 1 | import { noop } from "../../util/index.mjs"; 2 | 3 | export const hook = noop; 4 | export const unhook = noop; 5 | -------------------------------------------------------------------------------- /components/hook-group/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/hook-http-client/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/hook-http-client/stub/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/hook-http-client/stub/index.mjs: -------------------------------------------------------------------------------- 1 | import { noop } from "../../util/index.mjs"; 2 | 3 | export const hook = noop; 4 | export const unhook = noop; 5 | -------------------------------------------------------------------------------- /components/hook-http-client/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/hook-http-server/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/hook-http-server/stub/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/hook-http-server/stub/index.mjs: -------------------------------------------------------------------------------- 1 | import { noop } from "../../util/index.mjs"; 2 | 3 | export const hook = noop; 4 | export const unhook = noop; 5 | -------------------------------------------------------------------------------- /components/hook-http-server/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/hook-http/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/hook-module/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/hook-module/node/.ordering: -------------------------------------------------------------------------------- 1 | stringify.mjs 2 | cjs.mjs 3 | esm.mjs 4 | jest.mjs 5 | index.mjs 6 | -------------------------------------------------------------------------------- /components/hook-module/node/index.mjs: -------------------------------------------------------------------------------- 1 | import { hook as hookCjs, unhook as unhookCjs } from "./cjs.mjs"; 2 | import { hook as hookEsm, unhook as unhookEsm } from "./esm.mjs"; 3 | 4 | export const unhook = (backup) => { 5 | if (backup !== null) { 6 | unhookCjs(backup.cjs); 7 | unhookEsm(backup.esm); 8 | } 9 | }; 10 | 11 | export const hook = (frontend, configuration) => { 12 | if (configuration.recorder === "jest") { 13 | return null; 14 | } else { 15 | return { 16 | cjs: hookCjs(frontend, configuration), 17 | esm: hookEsm(frontend, configuration), 18 | }; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /components/hook-module/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertDeepEqual } from "../../__fixture__.mjs"; 2 | import { testHookAsync } from "../../hook-fixture/index.mjs"; 3 | import * as HookModule from "./index.mjs"; 4 | 5 | for (const recorder of ["process", "jest"]) { 6 | assertDeepEqual( 7 | await testHookAsync( 8 | HookModule, 9 | { 10 | configuration: { 11 | recorder, 12 | hooks: { esm: false, cjs: false }, 13 | }, 14 | url: "protocol://host/base", 15 | }, 16 | () => {}, 17 | ), 18 | [], 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /components/hook-module/node/stringify.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual, assertThrow } from "../../__fixture__.mjs"; 2 | import { stringifyContent } from "./stringify.mjs"; 3 | 4 | const { TextEncoder } = globalThis; 5 | 6 | assertEqual(stringifyContent("123;"), "123;"); 7 | 8 | assertEqual(stringifyContent(new TextEncoder("utf8").encode("123;")), "123;"); 9 | 10 | assertThrow(() => stringifyContent(123)); 11 | -------------------------------------------------------------------------------- /components/hook-module/noop/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/hook-module/noop/index.mjs: -------------------------------------------------------------------------------- 1 | import { noop } from "../../util/index.mjs"; 2 | 3 | export const hook = noop; 4 | export const unhook = noop; 5 | -------------------------------------------------------------------------------- /components/hook-module/noop/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/hook-query/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/hook-query/node/.ordering: -------------------------------------------------------------------------------- 1 | convert.mjs 2 | mysql.mjs 3 | pg.mjs 4 | sqlite3.mjs 5 | index.mjs 6 | -------------------------------------------------------------------------------- /components/hook-query/node/convert.mjs: -------------------------------------------------------------------------------- 1 | const { 2 | Set, 3 | Map, 4 | Array: { isArray, from: toArray }, 5 | Object: toObject, 6 | Object: { entries: toEntryArray, fromEntries: fromEntryArray }, 7 | } = globalThis; 8 | 9 | const isStringEntry = ([key]) => typeof key === "string"; 10 | 11 | export const toParameterCollection = (parameters) => { 12 | if (parameters instanceof Set) { 13 | return toArray(parameters.values()); 14 | } else if (parameters instanceof Map) { 15 | return fromEntryArray(toArray(parameters.entries()).filter(isStringEntry)); 16 | } else if (isArray(parameters)) { 17 | return toArray(parameters); 18 | } else { 19 | return fromEntryArray(toEntryArray(toObject(parameters))); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /components/hook-query/node/convert.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertDeepEqual } from "../../__fixture__.mjs"; 2 | import { toParameterCollection } from "./convert.mjs"; 3 | 4 | const { Set, Symbol, Map } = globalThis; 5 | 6 | assertDeepEqual(toParameterCollection([123, 456, 789]), [123, 456, 789]); 7 | 8 | assertDeepEqual( 9 | toParameterCollection(new Set([123, 456, 789])), 10 | [123, 456, 789], 11 | ); 12 | 13 | assertDeepEqual(toParameterCollection({ key: 123, [Symbol("sym")]: 456 }), { 14 | key: 123, 15 | }); 16 | 17 | assertDeepEqual( 18 | toParameterCollection( 19 | new Map([ 20 | ["key", 123], 21 | [Symbol("sym"), 456], 22 | ]), 23 | ), 24 | { key: 123 }, 25 | ); 26 | 27 | assertDeepEqual(toParameterCollection(null), {}); 28 | -------------------------------------------------------------------------------- /components/hook-query/node/index.mjs: -------------------------------------------------------------------------------- 1 | import { hook as hookMysql, unhook as unhookMysql } from "./mysql.mjs"; 2 | import { hook as hookPg, unhook as unhookPg } from "./pg.mjs"; 3 | import { hook as hookSqlite3, unhook as unhookSqlite3 } from "./sqlite3.mjs"; 4 | 5 | export const hook = (frontend, socket, configuration) => ({ 6 | mysql: hookMysql(frontend, socket, configuration), 7 | pg: hookPg(frontend, socket, configuration), 8 | sqlite3: hookSqlite3(frontend, socket, configuration), 9 | }); 10 | 11 | export const unhook = ({ mysql, pg, sqlite3 }) => { 12 | unhookMysql(mysql); 13 | unhookPg(pg); 14 | unhookSqlite3(sqlite3); 15 | }; 16 | -------------------------------------------------------------------------------- /components/hook-query/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertDeepEqual } from "../../__fixture__.mjs"; 2 | import { testHookAsync } from "../../hook-fixture/index.mjs"; 3 | import * as HookQuery from "./index.mjs"; 4 | 5 | assertDeepEqual( 6 | await testHookAsync( 7 | HookQuery, 8 | { hooks: { mysql: false, pg: false, sqlite3: false } }, 9 | (_agent) => null, 10 | ), 11 | [], 12 | ); 13 | -------------------------------------------------------------------------------- /components/hook-query/void/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/hook-query/void/index.mjs: -------------------------------------------------------------------------------- 1 | import { ExternalAppmapError } from "../../error/index.mjs"; 2 | import { logErrorWhen } from "../../log/index.mjs"; 3 | import { assert, noop } from "../../util/index.mjs"; 4 | 5 | export const unhook = noop; 6 | 7 | export const hook = (_frontend, { hooks: { mysql, pg, sqlite3 } }) => { 8 | assert( 9 | !logErrorWhen( 10 | mysql || pg || sqlite3, 11 | "No support for recording sql queries", 12 | ), 13 | "No support for recording sql queries", 14 | ExternalAppmapError, 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /components/hook-query/void/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertDeepEqual } from "../../__fixture__.mjs"; 2 | import { testHookAsync } from "../../hook-fixture/index.mjs"; 3 | import * as HookQuery from "./index.mjs"; 4 | 5 | assertDeepEqual( 6 | await testHookAsync( 7 | HookQuery, 8 | { configuration: { hooks: { mysql: false, sqlite3: false, pg: false } } }, 9 | (_agent) => null, 10 | ), 11 | [], 12 | ); 13 | -------------------------------------------------------------------------------- /components/hook/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/hook/default/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertDeepEqual } from "../../__fixture__.mjs"; 2 | import { testHookAsync } from "../../hook-fixture/index.mjs"; 3 | import * as Hook from "./index.mjs"; 4 | 5 | assertDeepEqual( 6 | await testHookAsync( 7 | Hook, 8 | { 9 | configuration: { 10 | ordering: "chronological", 11 | hooks: { 12 | apply: false, 13 | mysql: false, 14 | pg: false, 15 | sqlite3: false, 16 | cjs: false, 17 | esm: false, 18 | http: false, 19 | }, 20 | }, 21 | }, 22 | async () => {}, 23 | ), 24 | [], 25 | ); 26 | -------------------------------------------------------------------------------- /components/http/node-http/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/http/void/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/http/void/index.mjs: -------------------------------------------------------------------------------- 1 | import { InternalAppmapError } from "../../error/index.mjs"; 2 | import { generateDeadcode } from "../../util/index.mjs"; 3 | 4 | export const requestAsync = generateDeadcode( 5 | "requestAsync should not be called on http/void", 6 | InternalAppmapError, 7 | ); 8 | 9 | export const generateRespond = generateDeadcode( 10 | "requestAsync should not be called on http/void", 11 | generateDeadcode, 12 | ); 13 | -------------------------------------------------------------------------------- /components/http/void/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "../../__fixture__.mjs"; 2 | import "./index.mjs"; 3 | -------------------------------------------------------------------------------- /components/init/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/init/node/.ordering: -------------------------------------------------------------------------------- 1 | index.mjs 2 | -------------------------------------------------------------------------------- /components/init/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import runSpecs from "../../test-helper.mjs"; 2 | 3 | runSpecs(import.meta.url); 4 | -------------------------------------------------------------------------------- /components/instrumentation-inject/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/instrumentation/dead/.env: -------------------------------------------------------------------------------- 1 | node 2 | browser 3 | -------------------------------------------------------------------------------- /components/instrumentation/dead/index.mjs: -------------------------------------------------------------------------------- 1 | import { generateDeadcode } from "../../util/index.mjs"; 2 | import { InternalAppmapError } from "../../error/index.mjs"; 3 | 4 | export const instrument = generateDeadcode( 5 | "forbidden call to instrument", 6 | InternalAppmapError, 7 | ); 8 | 9 | export const extractMissingUrlArray = generateDeadcode( 10 | "forbidden call to extractMissingUrlArray", 11 | InternalAppmapError, 12 | ); 13 | -------------------------------------------------------------------------------- /components/instrumentation/dead/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/instrumentation/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/instrumentation/default/.ordering: -------------------------------------------------------------------------------- 1 | sourcemap.mjs 2 | source.mjs 3 | codebase.mjs 4 | visit.mjs 5 | index.mjs 6 | -------------------------------------------------------------------------------- /components/instrumentation/default/__fixture__.mjs: -------------------------------------------------------------------------------- 1 | import BabelParser from "@babel/parser"; 2 | import * as Astring from "astring"; 3 | 4 | export const { generate } = Astring; 5 | const { parse: parseBabel } = BabelParser; 6 | 7 | export const normalize = (code, source) => 8 | generate( 9 | parseBabel(code, { 10 | ecmaVersion: 2021, 11 | sourceType: source, 12 | allowAwaitOutsideFunction: source === "module", 13 | plugins: [["estree", { classFeatures: true }]], 14 | }).program, 15 | ); 16 | -------------------------------------------------------------------------------- /components/interpretation/.ordering: -------------------------------------------------------------------------------- 1 | dom 2 | vm 3 | -------------------------------------------------------------------------------- /components/interpretation/dom/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/interpretation/dom/index.mjs: -------------------------------------------------------------------------------- 1 | const { document } = globalThis; 2 | 3 | export const runScript = (script, _url) => { 4 | const element = document.createElement("script"); 5 | element.type = "text/javascript"; 6 | element.text = script; 7 | // TODO find out how to attach url to script element 8 | // element.src = url; 9 | document.body.appendChild(element); 10 | }; 11 | -------------------------------------------------------------------------------- /components/interpretation/vm/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/interpretation/vm/index.mjs: -------------------------------------------------------------------------------- 1 | import { runInThisContext } from "node:vm"; 2 | 3 | export const runScript = (content, url) => 4 | runInThisContext(content, { filename: url }); 5 | -------------------------------------------------------------------------------- /components/interpretation/vm/index.test.mjs: -------------------------------------------------------------------------------- 1 | /* global hidden */ 2 | /* eslint local/no-globals: ["error", "globalThis", "hidden"] */ 3 | 4 | import { assertEqual } from "../../__fixture__.mjs"; 5 | import { runScript } from "./index.mjs"; 6 | 7 | const { undefined } = globalThis; 8 | 9 | assertEqual( 10 | runScript("let hidden = 123;", "protocol://host/script.js"), 11 | undefined, 12 | ); 13 | 14 | assertEqual(hidden, 123); 15 | -------------------------------------------------------------------------------- /components/load/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/location/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/location/default/index.mjs: -------------------------------------------------------------------------------- 1 | import { InternalAppmapError } from "../../error/index.mjs"; 2 | import { assert } from "../../util/index.mjs"; 3 | 4 | const { String, parseInt, undefined } = globalThis; 5 | 6 | const regexp = /^([A-Za-z0-9+/=]+\|)?([\s\S]+):([0-9]+):([0-9]+)$/u; 7 | 8 | export const stringifyLocation = ({ 9 | url, 10 | hash, 11 | position: { line, column }, 12 | }) => { 13 | if (hash === null) { 14 | return `${url}:${String(line)}:${String(column)}`; 15 | } else { 16 | return `${hash}|${url}:${String(line)}:${String(column)}`; 17 | } 18 | }; 19 | 20 | export const parseLocation = (string) => { 21 | const parts = regexp.exec(string); 22 | assert(parts !== null, "invalid location format", InternalAppmapError); 23 | return { 24 | hash: 25 | parts[1] === undefined 26 | ? null 27 | : parts[1].substring(0, parts[1].length - 1), 28 | url: parts[2], 29 | position: { 30 | line: parseInt(parts[3]), 31 | column: parseInt(parts[4]), 32 | }, 33 | }; 34 | }; 35 | -------------------------------------------------------------------------------- /components/location/default/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertDeepEqual } from "../../__fixture__.mjs"; 2 | import { stringifyLocation, parseLocation } from "./index.mjs"; 3 | 4 | const test = (location) => { 5 | assertDeepEqual(parseLocation(stringifyLocation(location)), location); 6 | }; 7 | 8 | test({ 9 | hash: "hash", 10 | url: "protocol://host/path", 11 | position: { line: 123, column: 456 }, 12 | }); 13 | 14 | test({ 15 | hash: null, 16 | url: "protocol://host/path", 17 | position: { line: 123, column: 456 }, 18 | }); 19 | -------------------------------------------------------------------------------- /components/log-inner/console/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/log-inner/console/index.mjs: -------------------------------------------------------------------------------- 1 | export { noop as logDebug } from "../../util/index.mjs"; 2 | 3 | export const { 4 | console: { info: logInfo, warn: logWarning, error: logError }, 5 | } = globalThis; 6 | -------------------------------------------------------------------------------- /components/log-inner/console/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "../../__fixture__.mjs"; 2 | import { logDebug, logInfo, logWarning, logError } from "./index.mjs"; 3 | 4 | logDebug("debug"); 5 | logInfo("info"); 6 | logWarning("warning"); 7 | logError("error"); 8 | -------------------------------------------------------------------------------- /components/log-inner/stub/.env: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /components/log-inner/stub/index.mjs: -------------------------------------------------------------------------------- 1 | import { noop } from "../../util/index.mjs"; 2 | 3 | export const logDebug = noop; 4 | 5 | export const logInfo = noop; 6 | 7 | export const logWarning = noop; 8 | 9 | export const logError = noop; 10 | -------------------------------------------------------------------------------- /components/log-inner/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "../../__fixture__.mjs"; 2 | import { logInfo } from "./index.mjs"; 3 | 4 | logInfo("message"); 5 | -------------------------------------------------------------------------------- /components/log-inner/write-sync/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/log-inner/write-sync/.ordering: -------------------------------------------------------------------------------- 1 | index-isolate.mjs 2 | index.mjs 3 | -------------------------------------------------------------------------------- /components/log-inner/write-sync/index-isolate.mjs: -------------------------------------------------------------------------------- 1 | // NB: Synchronous loggin is important to avoid infinite loop when async hooks are enabled. 2 | import { openSync, writeSync } from "node:fs"; 3 | import { InternalAppmapError } from "../../error/index.mjs"; 4 | 5 | const { URL } = globalThis; 6 | 7 | const openLogFile = (specifier) => { 8 | if (typeof specifier === "number") { 9 | return specifier; 10 | } else if (typeof specifier === "string") { 11 | return openSync(new URL(specifier), "w"); 12 | } else { 13 | throw new InternalAppmapError("invalid specifier type for log file"); 14 | } 15 | }; 16 | 17 | const generateLog = (fd, name) => (message) => { 18 | writeSync(fd, `APPMAP-${name} ${message}\n`); 19 | }; 20 | 21 | export const makeLog = (specifier) => { 22 | const fd = openLogFile(specifier); 23 | return { 24 | logDebug: generateLog(fd, "DEBUG"), 25 | logInfo: generateLog(fd, "INFO"), 26 | logWarning: generateLog(fd, "WARNING"), 27 | logError: generateLog(fd, "ERROR"), 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /components/log-inner/write-sync/index-isolate.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertThrow, assertEqual } from "../../__fixture__.mjs"; 2 | import { getUuid } from "../../uuid/index.mjs"; 3 | import { toAbsoluteUrl } from "../../url/index.mjs"; 4 | import { getTmpUrl } from "../../path/index.mjs"; 5 | import { makeLog } from "./index-isolate.mjs"; 6 | 7 | const { undefined } = globalThis; 8 | 9 | assertEqual(makeLog(1).logInfo("stdout"), undefined); 10 | 11 | assertEqual(makeLog(2).logInfo("stderr"), undefined); 12 | 13 | assertEqual( 14 | makeLog(toAbsoluteUrl(getUuid(), getTmpUrl())).logInfo("tmp"), 15 | undefined, 16 | ); 17 | 18 | assertThrow(() => { 19 | makeLog(false); 20 | }, /^InternalAppmapError: invalid specifier type for log file$/u); 21 | -------------------------------------------------------------------------------- /components/log-inner/write-sync/index.mjs: -------------------------------------------------------------------------------- 1 | import { readGlobal } from "../../global/index.mjs"; 2 | import { makeLog } from "./index-isolate.mjs"; 3 | 4 | export const { logDebug, logInfo, logWarning, logError } = makeLog( 5 | readGlobal("__APPMAP_LOG_FILE__"), 6 | ); 7 | -------------------------------------------------------------------------------- /components/log-inner/write-sync/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { defineGlobal } from "../../global/index.mjs"; 2 | defineGlobal("__APPMAP_LOG_FILE__", 1); 3 | await import("./index.mjs"); 4 | -------------------------------------------------------------------------------- /components/log/prod/.env: -------------------------------------------------------------------------------- 1 | node 2 | browser 3 | -------------------------------------------------------------------------------- /components/log/prod/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual } from "../../__fixture__.mjs"; 2 | import { defineGlobal } from "../../global/index.mjs"; 3 | 4 | defineGlobal("__APPMAP_LOG_LEVEL__", "info"); 5 | const { logWarning, logWarningWhen, logInfo } = await import("./index.mjs"); 6 | 7 | logInfo("foo"); 8 | logWarning("bar"); 9 | assertEqual(logWarningWhen(true, "qux"), true); 10 | assertEqual(logWarningWhen(false, "qux"), false); 11 | -------------------------------------------------------------------------------- /components/log/test/.env: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /components/log/test/index.mjs: -------------------------------------------------------------------------------- 1 | import { stdout, env } from "node:process"; 2 | import { hasOwnProperty, format } from "../../util/index.mjs"; 3 | 4 | const enabled = hasOwnProperty(env, "APPMAP_TEST_LOGGING"); 5 | 6 | const log = (template, ...rest) => { 7 | const message = format(template, rest); 8 | if (enabled) { 9 | stdout.write(`${message}\n`); 10 | } 11 | }; 12 | 13 | const logWhen = (guard, template, ...rest) => { 14 | const message = format(template, rest); 15 | if (guard && enabled) { 16 | stdout.write(`${message}\n`); 17 | } 18 | return guard; 19 | }; 20 | 21 | export const logDebug = log; 22 | export const logInfo = log; 23 | export const logWarning = log; 24 | export const logError = log; 25 | export const logDebugWhen = logWhen; 26 | export const logInfoWhen = logWhen; 27 | export const logWarningWhen = logWhen; 28 | export const logErrorWhen = logWhen; 29 | -------------------------------------------------------------------------------- /components/log/test/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { env } from "node:process"; 2 | import { assertEqual } from "../../__fixture__.mjs"; 3 | 4 | const { 5 | Reflect: { defineProperty }, 6 | } = globalThis; 7 | 8 | defineProperty(env, "APPMAP_TEST_LOGGING", { 9 | __proto__: null, 10 | value: "1", 11 | writable: true, 12 | configurable: true, 13 | enumerable: true, 14 | }); 15 | 16 | const { logWarning, logWarningWhen, logInfo } = await import("./index.mjs"); 17 | 18 | logInfo("foo"); 19 | logWarning("bar"); 20 | assertEqual(logWarningWhen(true, "qux"), true); 21 | assertEqual(logWarningWhen(false, "qux"), false); 22 | -------------------------------------------------------------------------------- /components/matcher/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/mitm/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/mitm/default/.ordering: -------------------------------------------------------------------------------- 1 | util.mjs 2 | stream.mjs 3 | html.mjs 4 | js.mjs 5 | forward.mjs 6 | intercept.mjs 7 | forge.mjs 8 | proxy.mjs 9 | index.mjs 10 | -------------------------------------------------------------------------------- /components/mitm/default/js.mjs: -------------------------------------------------------------------------------- 1 | import { sendBackend } from "../../backend/index.mjs"; 2 | import { readFile } from "../../file/index.mjs"; 3 | import { instrumentInject } from "../../instrumentation-inject/index.mjs"; 4 | 5 | export const instrumentJs = (configuration, backend, { url, content }) => { 6 | const { sources, content: instrumented_content } = instrumentInject( 7 | url, 8 | content, 9 | configuration, 10 | readFile, 11 | ); 12 | for (const { url, content } of sources) { 13 | sendBackend(backend, { 14 | type: "source", 15 | url, 16 | content, 17 | }); 18 | } 19 | return instrumented_content; 20 | }; 21 | -------------------------------------------------------------------------------- /components/mitm/default/js.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual } from "../../__fixture__.mjs"; 2 | import { 3 | createConfiguration, 4 | extendConfiguration, 5 | } from "../../configuration/index.mjs"; 6 | import { createBackend } from "../../backend/index.mjs"; 7 | import { instrumentJs } from "./js.mjs"; 8 | 9 | { 10 | const configuration = extendConfiguration( 11 | createConfiguration("protocol://host/home"), 12 | { 13 | packages: { 14 | regexp: "script.js", 15 | enabled: true, 16 | }, 17 | }, 18 | "protocol://host/base", 19 | ); 20 | assertEqual( 21 | instrumentJs(configuration, createBackend(configuration), { 22 | url: "protocol://host/base/script.js", 23 | content: "123;", 24 | }), 25 | "123;\n", 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /components/mitm/default/stream.mjs: -------------------------------------------------------------------------------- 1 | import { Buffer } from "node:buffer"; 2 | const { concat: concatBufferArray } = Buffer; 3 | 4 | export const bufferReadable = (readable, callback) => { 5 | const buffers = []; 6 | readable.on("data", (buffer) => { 7 | buffers.push(buffer); 8 | }); 9 | readable.on("end", () => { 10 | callback(concatBufferArray(buffers)); 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /components/mitm/default/stream.test.mjs: -------------------------------------------------------------------------------- 1 | import { Readable } from "node:stream"; 2 | import { Buffer } from "node:buffer"; 3 | import { assertEqual } from "../../__fixture__.mjs"; 4 | import { bufferReadable } from "./stream.mjs"; 5 | 6 | const { Promise, setTimeout } = globalThis; 7 | 8 | const { from: toBuffer } = Buffer; 9 | 10 | let done = false; 11 | 12 | const readable = new Readable({ 13 | read() { 14 | if (!done) { 15 | done = true; 16 | setTimeout(() => { 17 | this.push(toBuffer("foo", "utf8")); 18 | setTimeout(() => { 19 | this.push(toBuffer("bar", "utf8")); 20 | setTimeout(() => { 21 | this.push(null); 22 | }, 0); 23 | }, 0); 24 | }, 0); 25 | } 26 | }, 27 | }); 28 | 29 | assertEqual( 30 | ( 31 | await new Promise((resolve) => { 32 | bufferReadable(readable, resolve); 33 | }) 34 | ).toString("utf8"), 35 | "foobar", 36 | ); 37 | -------------------------------------------------------------------------------- /components/parse/babel/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/patch/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/path/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/path/node/.ordering: -------------------------------------------------------------------------------- 1 | posix.mjs 2 | win32.mjs 3 | index.mjs 4 | -------------------------------------------------------------------------------- /components/peer/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/peer/node/index.mjs: -------------------------------------------------------------------------------- 1 | import { createRequire } from "node:module"; 2 | import { ExternalAppmapError } from "../../error/index.mjs"; 3 | import { logError, logDebug } from "../../log/index.mjs"; 4 | 5 | const { URL } = globalThis; 6 | 7 | export const requirePeerDependency = (specifier, { directory, strict }) => { 8 | const require = createRequire(new URL(directory)); 9 | try { 10 | return require(specifier); 11 | } catch (error) { 12 | if (strict) { 13 | logError( 14 | "Could not load peer dependency %j from %j >> %O", 15 | specifier, 16 | directory, 17 | error, 18 | ); 19 | throw new ExternalAppmapError("Could not load peer dependency"); 20 | } else { 21 | logDebug( 22 | "Could not load peer dependency %j from %j >> %O", 23 | specifier, 24 | directory, 25 | error, 26 | ); 27 | return null; 28 | } 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /components/pool/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/pool/default/index.mjs: -------------------------------------------------------------------------------- 1 | import { setTimeout, clearTimeout } from "node:timers"; 2 | 3 | const { Set } = globalThis; 4 | 5 | export const createPool = () => ({ 6 | timer: null, 7 | sockets: new Set(), 8 | }); 9 | 10 | export const addPool = (pool, socket) => { 11 | pool.sockets.add(socket); 12 | socket.on("close", () => { 13 | pool.sockets.delete(socket); 14 | if (pool.sockets.size === 0 && pool.timer !== null) { 15 | clearTimeout(pool.timer); 16 | pool.timer = null; 17 | } 18 | }); 19 | }; 20 | 21 | export const closePool = (pool, delay) => { 22 | if (delay === 0) { 23 | for (const socket of pool.sockets) { 24 | socket.destroy(); 25 | } 26 | clearTimeout(pool.timer); 27 | pool.timer = null; 28 | } else { 29 | for (const socket of pool.sockets) { 30 | socket.end(); 31 | } 32 | pool.timer = setTimeout(closePool, delay, pool, 0); 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /components/position/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/prompts/fake/.env: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /components/prompts/fake/index.mjs: -------------------------------------------------------------------------------- 1 | import { readGlobal } from "../../global/index.mjs"; 2 | 3 | export const prompts = (prompt) => readGlobal("GLOBAL_PROMPTS")(prompt); 4 | -------------------------------------------------------------------------------- /components/prompts/fake/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { defineGlobal } from "../../global/index.mjs"; 2 | import { prompts } from "./index.mjs"; 3 | 4 | defineGlobal("GLOBAL_PROMPTS", (prompt) => prompt); 5 | 6 | prompts({}); 7 | -------------------------------------------------------------------------------- /components/prompts/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/prompts/node/index.mjs: -------------------------------------------------------------------------------- 1 | export { default as prompts } from "prompts"; 2 | -------------------------------------------------------------------------------- /components/prompts/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/questionnaire/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | test 3 | -------------------------------------------------------------------------------- /components/receptor/default/.env: -------------------------------------------------------------------------------- 1 | node 2 | test 3 | -------------------------------------------------------------------------------- /components/receptor/default/.ordering: -------------------------------------------------------------------------------- 1 | port.mjs 2 | trace.mjs 3 | track.mjs 4 | index.mjs 5 | -------------------------------------------------------------------------------- /components/receptor/default/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertNotEqual } from "../../__fixture__.mjs"; 2 | import { createBackend } from "../../backend/index.mjs"; 3 | import { 4 | createConfiguration, 5 | extendConfiguration, 6 | } from "../../configuration/index.mjs"; 7 | import { 8 | openReceptorAsync, 9 | getReceptorTracePort, 10 | getReceptorTrackPort, 11 | closeReceptorAsync, 12 | } from "./index.mjs"; 13 | 14 | const configuration = extendConfiguration( 15 | createConfiguration("protocol://host/home/"), 16 | { 17 | "trace-port": 0, 18 | "track-port": 0, 19 | }, 20 | "protocol://host/base/", 21 | ); 22 | 23 | const backend = createBackend(configuration); 24 | 25 | const receptor = await openReceptorAsync(configuration, backend); 26 | 27 | assertNotEqual(getReceptorTracePort(receptor), 0); 28 | 29 | assertNotEqual(getReceptorTrackPort(receptor), 0); 30 | 31 | await closeReceptorAsync(receptor); 32 | -------------------------------------------------------------------------------- /components/receptor/default/port.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertThrow, assertEqual } from "../../__fixture__.mjs"; 2 | import { toIpcPath, convertFileUrlToPath } from "../../path/index.mjs"; 3 | import { convertPort, revertPort } from "./port.mjs"; 4 | 5 | // convertPort // 6 | assertEqual(convertPort(123), 123); 7 | assertEqual(typeof convertPort(""), "string"); 8 | assertEqual(typeof convertPort("file:///w:/port"), "string"); 9 | assertThrow(() => convertPort(null), /^InternalAppmapError: invalid port/u); 10 | 11 | // revertPort // 12 | assertEqual(revertPort({ port: 123 }), 123); 13 | assertEqual( 14 | revertPort(toIpcPath(convertFileUrlToPath("file:///w:/port"))), 15 | "file:///w:/port", 16 | ); 17 | assertThrow( 18 | () => revertPort({ port: "port" }), 19 | /^InternalAppmapError: invalid address$/u, 20 | ); 21 | -------------------------------------------------------------------------------- /components/receptor/stub/.env: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getappmap/appmap-agent-js/124514f4baba2b8c9a267fd4a3357ce954e4a971/components/receptor/stub/.env -------------------------------------------------------------------------------- /components/receptor/stub/index.mjs: -------------------------------------------------------------------------------- 1 | import { constant } from "../../util/index.mjs"; 2 | 3 | const { Promise, undefined } = globalThis; 4 | 5 | export const openReceptorAsync = constant(Promise.resolve(undefined)); 6 | 7 | export const getReceptorTracePort = constant(0); 8 | 9 | export const getReceptorTrackPort = constant(0); 10 | 11 | export const closeReceptorAsync = constant(Promise.resolve(undefined)); 12 | -------------------------------------------------------------------------------- /components/receptor/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "../../__fixture__.mjs"; 2 | import "./index.mjs"; 3 | -------------------------------------------------------------------------------- /components/recorder-api/default/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/recorder-cli/browser/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/recorder-cli/jest/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/recorder-cli/jest/.ordering: -------------------------------------------------------------------------------- 1 | index.mjs 2 | -------------------------------------------------------------------------------- /components/recorder-cli/jest/index.test.mjs: -------------------------------------------------------------------------------- 1 | import process from "node:process"; 2 | import { platform as getPlatform } from "node:os"; 3 | import { spawn } from "node:child_process"; 4 | 5 | const { String, Error } = globalThis; 6 | 7 | const child = spawn( 8 | getPlatform() === "win32" ? "npx.cmd" : "npx", 9 | [ 10 | "jest", 11 | "--runInBand", 12 | "--testMatch", 13 | "**/*.mjs", 14 | "--", 15 | "components/recorder-cli/jest/__fixture__.mjs", 16 | ], 17 | { 18 | stdio: "inherit", 19 | env: { 20 | ...process.env, 21 | NODE_OPTIONS: `--experimental-vm-modules ${ 22 | process.env.NODE_OPTIONS || "" 23 | }`, 24 | }, 25 | }, 26 | ); 27 | 28 | child.on("exit", (status, signal) => { 29 | if (status !== 0) { 30 | throw new Error(`Exit status ${String(status)}`); 31 | } 32 | if (signal !== null) { 33 | throw new Error(`Kill signal ${signal}`); 34 | } 35 | }); 36 | -------------------------------------------------------------------------------- /components/recorder-cli/mocha/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/recorder-cli/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/recorder-cli/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { cwd } from "node:process"; 2 | import "../../__fixture__.mjs"; 3 | import { toDirectoryUrl } from "../../url/index.mjs"; 4 | import { convertPathToFileUrl } from "../../path/index.mjs"; 5 | import { 6 | createConfiguration, 7 | extendConfiguration, 8 | } from "../../configuration/index.mjs"; 9 | import { recordAsync } from "./index.mjs"; 10 | 11 | const base = toDirectoryUrl(convertPathToFileUrl(cwd())); 12 | 13 | for (const recorder of ["process", "remote"]) { 14 | await recordAsync( 15 | extendConfiguration( 16 | createConfiguration("file:///w:/home/"), 17 | { 18 | processes: [{ regexp: "", enabled: true }], 19 | recorder, 20 | hooks: { 21 | cjs: false, 22 | esm: false, 23 | eval: false, 24 | apply: false, 25 | http: false, 26 | mysql: false, 27 | pg: false, 28 | sqlite3: false, 29 | }, 30 | }, 31 | base, 32 | ), 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /components/recorder-cli/stub/.env: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /components/recorder-cli/stub/index.mjs: -------------------------------------------------------------------------------- 1 | export { noop as recordAsync } from "../../util/index.mjs"; 2 | -------------------------------------------------------------------------------- /components/recorder-cli/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/recorder-standalone/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/recorder-standalone/default/index.mjs: -------------------------------------------------------------------------------- 1 | import { readGlobal } from "../../global/index.mjs"; 2 | import { recordAsync } from "../../recorder-cli/index.mjs"; 3 | // Do not use top-level await to make this a script after bundling. 4 | // This should only be used with browser recorder-cli and it resolve 5 | // directly. 6 | // In the future, we probably want to make `recorder-cli` standalone 7 | // anyway. 8 | recordAsync(readGlobal("__APPMAP_CONFIGURATION__")); 9 | -------------------------------------------------------------------------------- /components/recorder-standalone/default/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { defineGlobal } from "../../global/index.mjs"; 2 | import { createConfiguration } from "../../configuration/index.mjs"; 3 | defineGlobal( 4 | "__APPMAP_CONFIGURATION__", 5 | createConfiguration("file:///w:/home/"), 6 | ); 7 | await import("./index.mjs"); 8 | -------------------------------------------------------------------------------- /components/repository/dead/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/repository/dead/index.mjs: -------------------------------------------------------------------------------- 1 | import { InternalAppmapError } from "../../error/index.mjs"; 2 | import { generateDeadcode } from "../../util/index.mjs"; 3 | 4 | export const extractRepositoryHistory = generateDeadcode( 5 | "cannot extract repository history (disabled functionality)", 6 | InternalAppmapError, 7 | ); 8 | 9 | export const extractRepositoryPackage = generateDeadcode( 10 | "cannot extract repository package (disabled functionality)", 11 | InternalAppmapError, 12 | ); 13 | -------------------------------------------------------------------------------- /components/repository/dead/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "../../__fixture__.mjs"; 2 | import "./index.mjs"; 3 | -------------------------------------------------------------------------------- /components/repository/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/repository/node/.ordering: -------------------------------------------------------------------------------- 1 | package.mjs 2 | spawn.mjs 3 | history.mjs 4 | index.mjs 5 | -------------------------------------------------------------------------------- /components/repository/node/index.mjs: -------------------------------------------------------------------------------- 1 | export { extractRepositoryPackage } from "./package.mjs"; 2 | export { extractRepositoryHistory } from "./history.mjs"; 3 | -------------------------------------------------------------------------------- /components/repository/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/repository/stub/.env: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /components/repository/stub/index.mjs: -------------------------------------------------------------------------------- 1 | import { constant } from "../../util/index.mjs"; 2 | 3 | export const extractRepositoryHistory = constant(null); 4 | 5 | export const extractRepositoryPackage = constant(null); 6 | -------------------------------------------------------------------------------- /components/repository/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "../../__fixture__.mjs"; 2 | import "./index.mjs"; 3 | -------------------------------------------------------------------------------- /components/self/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/self/node/index.mjs: -------------------------------------------------------------------------------- 1 | // Consistent way to retreive home url in prod and test. 2 | // Indeed, components are bundled and import.meta.url will be in dist at prod. 3 | // However both test and prod import.meta.url are inside home. 4 | 5 | import { readFile as readFileAsync } from "node:fs/promises"; 6 | import { toAbsoluteUrl } from "../../url/index.mjs"; 7 | 8 | const { 9 | URL, 10 | JSON: { parse: parseJSON }, 11 | } = globalThis; 12 | 13 | let url = toAbsoluteUrl(".", import.meta.url); 14 | 15 | while (!url.endsWith("appmap-agent-js/")) { 16 | url = toAbsoluteUrl("..", url); 17 | } 18 | 19 | export const self_directory = url; 20 | 21 | export const self_package = parseJSON( 22 | await readFileAsync( 23 | new URL(toAbsoluteUrl("package.json", self_directory)), 24 | "utf8", 25 | ), 26 | ); 27 | -------------------------------------------------------------------------------- /components/self/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual } from "../../__fixture__.mjs"; 2 | import { self_package } from "./index.mjs"; 3 | 4 | assertEqual(self_package.name, "@appland/appmap-agent-js"); 5 | -------------------------------------------------------------------------------- /components/serialization/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/server/default/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/setup/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/socket/browser/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/socket/browser/.ordering: -------------------------------------------------------------------------------- 1 | ready-state.mjs 2 | index.mjs 3 | -------------------------------------------------------------------------------- /components/socket/browser/ready-state.mjs: -------------------------------------------------------------------------------- 1 | // I'm not sure if we can rely on 2 | // this values to be static field 3 | // of `WebSocket. 4 | 5 | export const CONNECTING = 0; 6 | export const OPEN = 1; 7 | export const CLOSING = 2; 8 | export const CLOSED = 3; 9 | -------------------------------------------------------------------------------- /components/socket/browser/ready-state.test.mjs: -------------------------------------------------------------------------------- 1 | import "./ready-state.mjs"; 2 | -------------------------------------------------------------------------------- /components/socket/mock/.env: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /components/socket/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/socket/node/.ordering: -------------------------------------------------------------------------------- 1 | __fixture__.mjs 2 | net.mjs 3 | unix.mjs 4 | index.mjs 5 | -------------------------------------------------------------------------------- /components/socket/node/__fixture__.test.mjs: -------------------------------------------------------------------------------- 1 | import "./__fixture__.mjs"; 2 | -------------------------------------------------------------------------------- /components/socket/node/index-isolate.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertThrow, assertEqual } from "../../__fixture__.mjs"; 2 | import { generateSocket } from "./index-isolate.mjs"; 3 | 4 | assertEqual(typeof generateSocket("unix"), "object"); 5 | assertEqual(typeof generateSocket("net"), "object"); 6 | assertThrow( 7 | () => generateSocket("foo"), 8 | /^InternalAppmapError: invalid socket implementation name$/u, 9 | ); 10 | -------------------------------------------------------------------------------- /components/socket/node/index.mjs: -------------------------------------------------------------------------------- 1 | export * from "./net.mjs"; 2 | -------------------------------------------------------------------------------- /components/socket/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/socket/node/net.test.mjs: -------------------------------------------------------------------------------- 1 | import * as SocketLibrary from "./net.mjs"; 2 | import { testAsync } from "./__fixture__.mjs"; 3 | 4 | await testAsync(SocketLibrary); 5 | -------------------------------------------------------------------------------- /components/socket/node/unix.test.mjs: -------------------------------------------------------------------------------- 1 | import { platform } from "node:process"; 2 | import { createRequire } from "node:module"; 3 | import { testAsync } from "./__fixture__.mjs"; 4 | import { generateUnixSocket } from "./unix.mjs"; 5 | 6 | if (platform !== "win32") { 7 | const require = createRequire(import.meta.url); 8 | await testAsync( 9 | generateUnixSocket( 10 | require("posix-socket"), 11 | require("posix-socket-messaging"), 12 | ), 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /components/source/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/source/default/.ordering: -------------------------------------------------------------------------------- 1 | entity.mjs 2 | criteria.mjs 3 | index.mjs 4 | -------------------------------------------------------------------------------- /components/spawn/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/spawn/node/.ordering: -------------------------------------------------------------------------------- 1 | spawn.mjs 2 | where.mjs 3 | index.mjs 4 | -------------------------------------------------------------------------------- /components/spawn/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { platform } from "node:process"; 2 | import { assertDeepEqual, assertReject } from "../../__fixture__.mjs"; 3 | import { spawnAsync } from "./index.mjs"; 4 | 5 | const { Set } = globalThis; 6 | 7 | await assertReject( 8 | spawnAsync( 9 | { 10 | exec: "MISSING-EXECUTABLE", 11 | argv: [], 12 | options: {}, 13 | }, 14 | new Set(), 15 | ), 16 | platform === "win32" 17 | ? /^Error: Could not locate executable$/u 18 | : /^Error: spawn MISSING-EXECUTABLE ENOENT$/u, 19 | ); 20 | 21 | assertDeepEqual( 22 | await spawnAsync( 23 | { 24 | exec: "node", 25 | argv: ["-e", "process.exit(123);"], 26 | options: { stdio: "ignore" }, 27 | }, 28 | new Set(), 29 | ), 30 | { signal: null, status: 123, stderr: null, stdout: null }, 31 | ); 32 | -------------------------------------------------------------------------------- /components/spawn/node/where.test.mjs: -------------------------------------------------------------------------------- 1 | import { platform } from "node:process"; 2 | import { assertEqual, assertMatch, assertReject } from "../../__fixture__.mjs"; 3 | import { pickWin32Exec, whereAsync } from "./where.mjs"; 4 | 5 | const { Set } = globalThis; 6 | 7 | assertEqual(pickWin32Exec(["foo", "foo.cmd"]), "foo.cmd"); 8 | 9 | assertEqual(pickWin32Exec(["foo", "foo.exe"]), "foo.exe"); 10 | 11 | assertEqual(pickWin32Exec(["foo.cmd", "foo.exe"]), "foo.exe"); 12 | 13 | if (platform === "win32") { 14 | assertMatch(await whereAsync("node", new Set()), /node/u); 15 | } else { 16 | await assertReject( 17 | whereAsync("node", new Set()), 18 | /^Error: spawn where.exe ENOENT$/u, 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /components/status/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/status/node/.ordering: -------------------------------------------------------------------------------- 1 | index.mjs 2 | -------------------------------------------------------------------------------- /components/status/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import runSpecs from "../../test-helper.mjs"; 2 | 3 | runSpecs(import.meta.url); 4 | -------------------------------------------------------------------------------- /components/test-helper.mjs: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | /* eslint-disable no-console */ 3 | 4 | import { dirname } from "node:path"; 5 | import { fileURLToPath } from "node:url"; 6 | import glob from "glob"; 7 | import Mocha from "mocha"; 8 | 9 | const { parseInt, process } = globalThis; 10 | 11 | export default (meta_url) => { 12 | // Instantiate a Mocha with options 13 | const mocha = new Mocha({ 14 | reporter: "spec", 15 | timeout: parseInt(process.env.MOCHA_TIMEOUT || 2000), 16 | }); 17 | 18 | const __dirname = dirname(fileURLToPath(meta_url)); 19 | const files = glob.sync("**/*.spec.mjs", { cwd: __dirname, absolute: true }); 20 | files.forEach((f) => mocha.addFile(f)); 21 | 22 | mocha 23 | .loadFilesAsync() 24 | .then(() => mocha.run((failures) => (process.exitCode = failures ? 1 : 0))) 25 | .catch((e) => { 26 | console.error(e); 27 | process.exitCode = 1; 28 | }); 29 | }; 30 | -------------------------------------------------------------------------------- /components/throttle/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/throttle/default/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { createThrottle, updateThrottle, throttleAsync } from "./index.mjs"; 2 | 3 | const { setTimeout } = globalThis; 4 | 5 | const throttle = createThrottle({}); 6 | 7 | setTimeout(() => { 8 | updateThrottle(throttle, 11); 9 | }, 0); 10 | 11 | await throttleAsync(throttle); 12 | -------------------------------------------------------------------------------- /components/time/date/.env: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /components/time/date/index.mjs: -------------------------------------------------------------------------------- 1 | export const { 2 | Date: { now }, 3 | } = globalThis; 4 | -------------------------------------------------------------------------------- /components/time/date/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/time/performance-browser/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/time/performance-browser/index.mjs: -------------------------------------------------------------------------------- 1 | const { 2 | performance, 3 | Math: { round }, 4 | } = globalThis; 5 | 6 | export const now = () => round(1000 * performance.now()) / 1000; 7 | -------------------------------------------------------------------------------- /components/time/performance-browser/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual } from "../../__fixture__.mjs"; 2 | import { defineGlobal } from "../../global/index.mjs"; 3 | 4 | defineGlobal("performance", { now: () => 0 }); 5 | 6 | const { now } = await import("./index.mjs"); 7 | 8 | assertEqual(typeof now(), "number"); 9 | -------------------------------------------------------------------------------- /components/time/performance-node/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/time/performance-node/index.mjs: -------------------------------------------------------------------------------- 1 | import { performance } from "node:perf_hooks"; 2 | 3 | const { 4 | Math: { round }, 5 | } = globalThis; 6 | 7 | export const now = () => round(1000 * performance.now()) / 1000; 8 | -------------------------------------------------------------------------------- /components/time/performance-node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual } from "../../__fixture__.mjs"; 2 | import { now } from "./index.mjs"; 3 | 4 | assertEqual(typeof now(), "number"); 5 | -------------------------------------------------------------------------------- /components/time/stub/.env: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /components/time/stub/index.mjs: -------------------------------------------------------------------------------- 1 | import { constant } from "../../util/index.mjs"; 2 | 3 | export const now = constant(0); 4 | -------------------------------------------------------------------------------- /components/time/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "../../__fixture__.mjs"; 2 | import "./index.mjs"; 3 | -------------------------------------------------------------------------------- /components/trace/appmap/.env: -------------------------------------------------------------------------------- 1 | node 2 | browser 3 | -------------------------------------------------------------------------------- /components/trace/appmap/.ordering: -------------------------------------------------------------------------------- 1 | codebase 2 | event 3 | ordering 4 | metadata.mjs 5 | output.mjs 6 | index.mjs 7 | -------------------------------------------------------------------------------- /components/trace/appmap/codebase/.ordering: -------------------------------------------------------------------------------- 1 | specifier.mjs 2 | index.mjs 3 | -------------------------------------------------------------------------------- /components/trace/appmap/event/.ordering: -------------------------------------------------------------------------------- 1 | payload.mjs 2 | index.mjs 3 | -------------------------------------------------------------------------------- /components/trace/appmap/ordering/.ordering: -------------------------------------------------------------------------------- 1 | matching.mjs 2 | stack.mjs 3 | group.mjs 4 | jump.mjs 5 | index.mjs 6 | -------------------------------------------------------------------------------- /components/trace/appmap/ordering/index.mjs: -------------------------------------------------------------------------------- 1 | // Beware, event ordering is by far the most difficult code to understand. 2 | // The ordering is mode in three passes: 3 | // 1) Rearrenge the event trace into an array of trees which each represent a top-level callstack. 4 | // 2) Resolve groups by inserting top-level trees where the asynchronous resource was registered. 5 | // 3) Resolve jumps by moving the tree framed by after events next to their corresponding before event. 6 | 7 | import { groupStack } from "./group.mjs"; 8 | import { stackify } from "./stack.mjs"; 9 | import { jumpify } from "./jump.mjs"; 10 | 11 | export const orderEventArray = (events) => 12 | jumpify(groupStack(stackify(events))); 13 | -------------------------------------------------------------------------------- /components/trace/appmap/output.mjs: -------------------------------------------------------------------------------- 1 | import { sanitizePathFilename } from "../../path/index.mjs"; 2 | import { toAbsoluteUrl } from "../../url/index.mjs"; 3 | 4 | const { encodeURIComponent } = globalThis; 5 | 6 | const pickBasename = ({ appmap_file: basename, "map-name": name }) => { 7 | if (basename !== null) { 8 | return basename; 9 | } else if (name !== null) { 10 | return name; 11 | } else { 12 | return "anonymous"; 13 | } 14 | }; 15 | 16 | export const getOutputUrl = (configuration) => 17 | toAbsoluteUrl( 18 | `${configuration.recorder}/${encodeURIComponent( 19 | sanitizePathFilename(`${pickBasename(configuration)}.appmap.json`), 20 | )}`, 21 | configuration.appmap_dir, 22 | ); 23 | -------------------------------------------------------------------------------- /components/trace/raw/.env: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /components/trace/raw/index.mjs: -------------------------------------------------------------------------------- 1 | import { toAbsoluteUrl } from "../../url/index.mjs"; 2 | 3 | const toSourceMessage = ({ url, content }) => ({ 4 | type: "source", 5 | url, 6 | content, 7 | }); 8 | 9 | export const compileTrace = (configuration, sources, messages, termination) => { 10 | const { recorder, appmap_file, appmap_dir } = configuration; 11 | return { 12 | url: toAbsoluteUrl(`${recorder}/${appmap_file}.appmap.json`, appmap_dir), 13 | content: { 14 | configuration, 15 | messages: [...sources.map(toSourceMessage), ...messages], 16 | termination, 17 | }, 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /components/transformer-jest/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/url-inner/browser/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/url-inner/browser/index.mjs: -------------------------------------------------------------------------------- 1 | export const { URL, URLSearchParams } = globalThis; 2 | -------------------------------------------------------------------------------- /components/url-inner/browser/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/url-inner/node/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/url-inner/node/index.mjs: -------------------------------------------------------------------------------- 1 | export { URL, URLSearchParams } from "node:url"; 2 | -------------------------------------------------------------------------------- /components/url-inner/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/url/default/.env: -------------------------------------------------------------------------------- 1 | node 2 | test 3 | browser 4 | -------------------------------------------------------------------------------- /components/util/default/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | browser 4 | -------------------------------------------------------------------------------- /components/util/default/.ordering: -------------------------------------------------------------------------------- 1 | array.mjs 2 | box.mjs 3 | convert.mjs 4 | error.mjs 5 | format.mjs 6 | counter.mjs 7 | either.mjs 8 | function.mjs 9 | maybe.mjs 10 | object.mjs 11 | version.mjs 12 | index.mjs 13 | -------------------------------------------------------------------------------- /components/util/default/array.mjs: -------------------------------------------------------------------------------- 1 | const { 2 | Array, 3 | Math: { min }, 4 | } = globalThis; 5 | 6 | export const zip = (array1, array2) => { 7 | const length = min(array1.length, array2.length); 8 | const pairs = new Array(length); 9 | for (let index = 0; index < length; index += 1) { 10 | pairs[index] = [array1[index], array2[index]]; 11 | } 12 | return pairs; 13 | }; 14 | -------------------------------------------------------------------------------- /components/util/default/array.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertDeepEqual } from "../../__fixture__.mjs"; 2 | import { zip } from "./array.mjs"; 3 | 4 | assertDeepEqual(zip(["foo1", "bar1", "qux1"], ["foo2", "bar2"]), [ 5 | ["foo1", "foo2"], 6 | ["bar1", "bar2"], 7 | ]); 8 | 9 | assertDeepEqual(zip(["foo1", "bar1"], ["foo2", "bar2", "qux2"]), [ 10 | ["foo1", "foo2"], 11 | ["bar1", "bar2"], 12 | ]); 13 | -------------------------------------------------------------------------------- /components/util/default/box.mjs: -------------------------------------------------------------------------------- 1 | export const createBox = (value) => ({ value }); 2 | export const getBox = ({ value }) => value; 3 | export const setBox = (box, value) => { 4 | box.value = value; 5 | }; 6 | -------------------------------------------------------------------------------- /components/util/default/box.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual } from "../../__fixture__.mjs"; 2 | import { createBox, getBox, setBox } from "./box.mjs"; 3 | 4 | const { undefined } = globalThis; 5 | 6 | const box = createBox("foo"); 7 | assertEqual(getBox(box), "foo"); 8 | assertEqual(setBox(box, "bar"), undefined); 9 | assertEqual(getBox(box), "bar"); 10 | -------------------------------------------------------------------------------- /components/util/default/counter.mjs: -------------------------------------------------------------------------------- 1 | export const createCounter = (value) => ({ value }); 2 | export const gaugeCounter = ({ value }) => value; 3 | export const incrementCounter = (counter) => (counter.value += 1); 4 | export const decrementCounter = (counter) => (counter.value -= 1); 5 | -------------------------------------------------------------------------------- /components/util/default/counter.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual } from "../../__fixture__.mjs"; 2 | import { 3 | createCounter, 4 | incrementCounter, 5 | decrementCounter, 6 | gaugeCounter, 7 | } from "./counter.mjs"; 8 | 9 | const counter = createCounter(0); 10 | assertEqual(gaugeCounter(counter), 0); 11 | assertEqual(incrementCounter(counter), 1); 12 | assertEqual(incrementCounter(counter), 2); 13 | assertEqual(decrementCounter(counter), 1); 14 | assertEqual(decrementCounter(counter), 0); 15 | -------------------------------------------------------------------------------- /components/util/default/either.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual, assertDeepEqual } from "../../__fixture__.mjs"; 2 | import { 3 | makeLeft, 4 | makeRight, 5 | isLeft, 6 | fromLeft, 7 | fromEither, 8 | mapEither, 9 | bindEither, 10 | } from "./either.mjs"; 11 | 12 | assertEqual(isLeft(makeLeft(123)), true); 13 | assertEqual(fromLeft(makeLeft(123)), 123); 14 | 15 | assertEqual( 16 | fromEither( 17 | makeLeft("foo"), 18 | (x) => `${x}bar`, 19 | (x) => `${x}qux`, 20 | ), 21 | "foobar", 22 | ); 23 | assertEqual( 24 | fromEither( 25 | makeRight("foo"), 26 | (x) => `${x}bar`, 27 | (x) => `${x}qux`, 28 | ), 29 | "fooqux", 30 | ); 31 | 32 | assertDeepEqual(mapEither(makeLeft(123)), makeLeft(123)); 33 | assertDeepEqual( 34 | mapEither(makeRight("foo"), (x) => `${x}bar`), 35 | makeRight("foobar"), 36 | ); 37 | 38 | assertDeepEqual(bindEither(makeLeft(123)), makeLeft(123)); 39 | assertDeepEqual( 40 | bindEither(makeRight("foo"), (x) => makeRight(`${x}bar`)), 41 | makeRight("foobar"), 42 | ); 43 | -------------------------------------------------------------------------------- /components/util/default/error.mjs: -------------------------------------------------------------------------------- 1 | import { hasOwnProperty } from "./object.mjs"; 2 | 3 | export function isFileNotFound(error) { 4 | // on Windows sometimes the error code is UNKNOWN 5 | return ( 6 | hasOwnProperty(error, "code") && 7 | (error.code === "ENOENT" || error.code === "UNKNOWN") 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /components/util/default/error.test.mjs: -------------------------------------------------------------------------------- 1 | import { assert } from "../../__fixture__.mjs"; 2 | import { isFileNotFound } from "./error.mjs"; 3 | 4 | const { Error } = globalThis; 5 | 6 | const enoent = new Error("ENOENT"); 7 | enoent.code = "ENOENT"; 8 | 9 | const unknown = new Error("UNKNOWN"); 10 | unknown.code = "UNKNOWN"; 11 | 12 | assert(isFileNotFound(enoent)); 13 | assert(isFileNotFound(unknown)); 14 | assert(!isFileNotFound(new Error("test"))); 15 | assert(!isFileNotFound("test")); 16 | -------------------------------------------------------------------------------- /components/util/default/index.mjs: -------------------------------------------------------------------------------- 1 | export * from "../../assert/index.mjs"; 2 | export * from "./array.mjs"; 3 | export * from "./box.mjs"; 4 | export * from "./convert.mjs"; 5 | export * from "./error.mjs"; 6 | export * from "./format.mjs"; 7 | export * from "./counter.mjs"; 8 | export * from "./either.mjs"; 9 | export * from "./function.mjs"; 10 | export * from "./maybe.mjs"; 11 | export * from "./object.mjs"; 12 | export * from "./version.mjs"; 13 | -------------------------------------------------------------------------------- /components/util/default/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/util/default/maybe.mjs: -------------------------------------------------------------------------------- 1 | export const fromMaybe = (maybe, recovery, transform) => 2 | maybe === null ? recovery : transform(maybe); 3 | 4 | export const mapMaybe = (maybe, transform) => 5 | maybe === null ? null : transform(maybe); 6 | 7 | export const recoverMaybe = (maybe, recovery) => 8 | maybe === null ? recovery : maybe; 9 | -------------------------------------------------------------------------------- /components/util/default/maybe.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual, assertFail } from "../../__fixture__.mjs"; 2 | 3 | import { fromMaybe, mapMaybe, recoverMaybe } from "./maybe.mjs"; 4 | 5 | const { String } = globalThis; 6 | 7 | // recoverMaybe // 8 | 9 | assertEqual(recoverMaybe(null, 123), 123); 10 | 11 | assertEqual(recoverMaybe(123, 456), 123); 12 | 13 | // fromMaybe // 14 | 15 | assertEqual( 16 | fromMaybe(null, 123, () => assertFail()), 17 | 123, 18 | ); 19 | 20 | assertEqual(fromMaybe(123, 456, String), "123"); 21 | 22 | // mapMaybe // 23 | 24 | assertEqual( 25 | mapMaybe(null, () => assertFail()), 26 | null, 27 | ); 28 | 29 | assertEqual( 30 | mapMaybe("foo", (x) => x + x), 31 | "foofoo", 32 | ); 33 | -------------------------------------------------------------------------------- /components/util/default/version.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual } from "../../__fixture__.mjs"; 2 | import { matchVersion } from "./version.mjs"; 3 | 4 | assertEqual(matchVersion("1.2.3", "1.2.3"), true); 5 | assertEqual(matchVersion("1.3.2", "1.2.3"), true); 6 | assertEqual(matchVersion("1.2.3", "1.3.2"), false); 7 | assertEqual(matchVersion("1.2.3", "1.2"), true); 8 | assertEqual(matchVersion("1.2", "1.2.3"), false); 9 | -------------------------------------------------------------------------------- /components/uuid/random/.env: -------------------------------------------------------------------------------- 1 | node 2 | browser 3 | -------------------------------------------------------------------------------- /components/uuid/random/index.mjs: -------------------------------------------------------------------------------- 1 | const { 2 | Date: { now }, 3 | Math: { random }, 4 | } = globalThis; 5 | 6 | export const getUuid = () => 7 | `${now().toString(32).substr(-4)}${random().toString(32).substr(-4)}`; 8 | -------------------------------------------------------------------------------- /components/uuid/random/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual, assertNotEqual } from "../../__fixture__.mjs"; 2 | import { getUuid } from "./index.mjs"; 3 | 4 | assertEqual(typeof getUuid(), "string"); 5 | assertEqual(getUuid().length, 8); 6 | assertNotEqual(getUuid(), getUuid()); 7 | -------------------------------------------------------------------------------- /components/uuid/stub/.env: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /components/uuid/stub/index.mjs: -------------------------------------------------------------------------------- 1 | import { constant } from "../../util/index.mjs"; 2 | 3 | export const getUuid = constant("uuid"); 4 | -------------------------------------------------------------------------------- /components/uuid/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "../../__fixture__.mjs"; 2 | import "./index.mjs"; 3 | -------------------------------------------------------------------------------- /components/validate-appmap/default/.env: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /components/validate-appmap/default/index.mjs: -------------------------------------------------------------------------------- 1 | import { createRequire } from "node:module"; 2 | import { InternalAppmapError } from "../../error/index.mjs"; 3 | import { logError } from "../../log/index.mjs"; 4 | 5 | const version = "1.8.0"; 6 | 7 | let validate = null; 8 | 9 | export const validateAppmap = (data) => { 10 | if (validate === null) { 11 | // Dynamic import on demand for performance 12 | const require = createRequire(import.meta.url); 13 | ({ validate } = require("@appland/appmap-validate")); 14 | } 15 | try { 16 | validate(data, { version }); 17 | } catch (error) { 18 | logError("Invalid %s appmap >> %O\n>>%j", version, error, data); 19 | throw new InternalAppmapError("Invalid appmap"); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /components/validate-appmap/default/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertThrow } from "../../__fixture__.mjs"; 2 | import { validateAppmap } from "./index.mjs"; 3 | 4 | assertThrow( 5 | () => validateAppmap({ verson: "1.2.3" }), 6 | /^InternalAppmapError: Invalid appmap$/u, 7 | ); 8 | -------------------------------------------------------------------------------- /components/validate-appmap/stub/.env: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /components/validate-appmap/stub/index.mjs: -------------------------------------------------------------------------------- 1 | export { noop as validateAppmap } from "../../util/index.mjs"; 2 | -------------------------------------------------------------------------------- /components/validate-appmap/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/validate/ajv/.env: -------------------------------------------------------------------------------- 1 | test 2 | node 3 | -------------------------------------------------------------------------------- /components/validate/ajv/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual, assertThrow } from "../../__fixture__.mjs"; 2 | import { validateExternalConfiguration } from "./index.mjs"; 3 | 4 | const { undefined } = globalThis; 5 | 6 | assertEqual( 7 | validateExternalConfiguration({ extra: "extra-root-property" }), 8 | undefined, 9 | ); 10 | 11 | assertThrow(() => { 12 | validateExternalConfiguration("invalid-configuration-type"); 13 | }, /^ExternalAppmapError: Failed to validate data against JSON schema$/u); 14 | 15 | assertThrow(() => { 16 | validateExternalConfiguration({ frameworks: ["invalid@framework@format"] }); 17 | }, /^ExternalAppmapError: Failed to validate data against JSON schema$/u); 18 | -------------------------------------------------------------------------------- /components/validate/stub/.env: -------------------------------------------------------------------------------- 1 | node 2 | browser 3 | -------------------------------------------------------------------------------- /components/validate/stub/index.mjs: -------------------------------------------------------------------------------- 1 | import { noop } from "../../util/index.mjs"; 2 | 3 | export const validateSerial = noop; 4 | export const validateMessage = noop; 5 | export const validatePayload = noop; 6 | export const validateExternalConfiguration = noop; 7 | export const validateInternalConfiguration = noop; 8 | export const validateSourceMap = noop; 9 | -------------------------------------------------------------------------------- /components/validate/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /components/version/node/.env: -------------------------------------------------------------------------------- 1 | node 2 | test 3 | -------------------------------------------------------------------------------- /components/version/node/index.mjs: -------------------------------------------------------------------------------- 1 | import { self_package } from "../../self/index.mjs"; 2 | 3 | export const version = self_package.version; 4 | -------------------------------------------------------------------------------- /components/version/node/index.test.mjs: -------------------------------------------------------------------------------- 1 | import { assertEqual } from "../../__fixture__.mjs"; 2 | import { version } from "./index.mjs"; 3 | 4 | assertEqual(typeof version, "string"); 5 | -------------------------------------------------------------------------------- /components/version/stub/.env: -------------------------------------------------------------------------------- 1 | browser 2 | -------------------------------------------------------------------------------- /components/version/stub/index.mjs: -------------------------------------------------------------------------------- 1 | export const version = "0.0.0"; 2 | -------------------------------------------------------------------------------- /components/version/stub/index.test.mjs: -------------------------------------------------------------------------------- 1 | import "./index.mjs"; 2 | -------------------------------------------------------------------------------- /doc/blog/abomination/bin: -------------------------------------------------------------------------------- 1 | import("./dep.mjs"); 2 | -------------------------------------------------------------------------------- /doc/blog/abomination/dep.mjs: -------------------------------------------------------------------------------- 1 | console.log("dep"); 2 | -------------------------------------------------------------------------------- /doc/blog/abomination/loader.mjs: -------------------------------------------------------------------------------- 1 | export const load = (url, context, loadDefaultAsync) => { 2 | console.log(`loading ${url}`); 3 | return loadDefaultAsync(url, context, loadDefaultAsync); 4 | }; 5 | -------------------------------------------------------------------------------- /doc/blog/tap/screenshot-entity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getappmap/appmap-agent-js/124514f4baba2b8c9a267fd4a3357ce954e4a971/doc/blog/tap/screenshot-entity.png -------------------------------------------------------------------------------- /doc/blog/tap/screenshot-event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getappmap/appmap-agent-js/124514f4baba2b8c9a267fd4a3357ce954e4a971/doc/blog/tap/screenshot-event.png -------------------------------------------------------------------------------- /doc/blog/thread/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "sqlite3" -------------------------------------------------------------------------------- /doc/blog/thread/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | sqlite3 (1.4.2) 5 | 6 | PLATFORMS 7 | ruby 8 | 9 | DEPENDENCIES 10 | sqlite3 11 | 12 | BUNDLED WITH 13 | 2.1.4 14 | -------------------------------------------------------------------------------- /doc/blog/thread/event-seq-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getappmap/appmap-agent-js/124514f4baba2b8c9a267fd4a3357ce954e4a971/doc/blog/thread/event-seq-tree.png -------------------------------------------------------------------------------- /doc/blog/thread/server.mjs: -------------------------------------------------------------------------------- 1 | import { createServer } from "http"; 2 | const server = createServer(); 3 | server.listen(0, function onListening() { 4 | console.log(`listening to port ${server.address().port}`); 5 | server.on("request", function onRequest(req, res) { 6 | setTimeout(function onTimeout1() { 7 | res.writeHead(200); 8 | }, 1000); 9 | setTimeout(function onTimeout2() { 10 | res.end("foobar"); 11 | }, 2000); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /doc/blog/thread/sql-trace.mjs: -------------------------------------------------------------------------------- 1 | // sql-trace.mjs 2 | import util from "util"; 3 | import sqlite3 from "sqlite3"; 4 | import { trace, traceAsync } from "./trace.mjs"; 5 | const db = new sqlite3.Database(":memory:"); 6 | const execute = util.promisify(db.all.bind(db)); 7 | const logTrace = (x) => trace(log, x); 8 | const main = () => { 9 | traceAsync(execute, "SELECT 2 * 3 as x").then(([{ x }]) => { 10 | trace(console.log, x); 11 | }); 12 | traceAsync(execute, "SELECT 4 * 5 as x").then(([{ x }]) => { 13 | trace(console.log, x); 14 | }); 15 | return 0; 16 | }; 17 | trace(main); 18 | -------------------------------------------------------------------------------- /doc/blog/thread/sql-trace.rb: -------------------------------------------------------------------------------- 1 | # sql-trace.rb 2 | require 'sqlite3' 3 | require './trace.rb' 4 | class Main 5 | def main 6 | db = SQLite3::Database.new(':memory:'); 7 | thread = Thread.new { 8 | x = trace(db, :execute, 'SELECT 2 * 3') 9 | trace(self, :puts, x) 10 | } 11 | x = trace(db, :execute, 'SELECT 4 * 5') 12 | trace(self, :puts, x) 13 | thread.join() 14 | return 0 15 | end 16 | end 17 | trace(Main.new, :main) 18 | -------------------------------------------------------------------------------- /doc/blog/thread/sql.mjs: -------------------------------------------------------------------------------- 1 | // sql.mjs 2 | import util from "util"; 3 | import sqlite3 from "sqlite3"; 4 | const db = new sqlite3.Database(":memory:"); 5 | const execute = util.promisify(db.all.bind(db)); 6 | const main = () => { 7 | execute("SELECT 2 * 3 as x").then(([{ x }]) => { 8 | console.log(x); 9 | }); 10 | execute("SELECT 4 * 5 as x").then(([{ x }]) => { 11 | console.log(x); 12 | }); 13 | return 0; 14 | }; 15 | main(); 16 | -------------------------------------------------------------------------------- /doc/blog/thread/sql.rb: -------------------------------------------------------------------------------- 1 | # sql.rb 2 | require 'sqlite3' 3 | class Main 4 | def main () 5 | db = SQLite3::Database.new(':memory:'); 6 | thread = Thread.new { 7 | x = db.execute('SELECT 2 * 3')[0][0] 8 | puts(x) 9 | } 10 | x = db.execute('SELECT 4 * 5')[0][0]; 11 | puts(x) 12 | thread.join 13 | return 0 14 | end 15 | end 16 | Main.new.main() -------------------------------------------------------------------------------- /doc/blog/thread/trace.mjs: -------------------------------------------------------------------------------- 1 | // trace.mjs 2 | let ctr = 0; 3 | export const trace = (fct, ...args) => { 4 | ctr += 1; 5 | const idx = ctr; 6 | console.log( 7 | `${process.pid} call #${idx} ${fct.name} ${JSON.stringify(args)}`, 8 | ); 9 | const res = fct(...args); 10 | console.log( 11 | `${process.pid} return #${idx} ${fct.name} ${JSON.stringify(res)}`, 12 | ); 13 | return res; 14 | }; 15 | export const traceAsync = async (fct, ...args) => { 16 | ctr += 1; 17 | const idx = ctr; 18 | console.log( 19 | `${process.pid} call #${idx} ${fct.name} ${JSON.stringify(args)}`, 20 | ); 21 | const res = await fct(...args); 22 | console.log( 23 | `${process.pid} return #${idx} ${fct.name} ${JSON.stringify(res)}`, 24 | ); 25 | return res; 26 | }; 27 | -------------------------------------------------------------------------------- /doc/blog/thread/trace.rb: -------------------------------------------------------------------------------- 1 | # trace.rb 2 | $ctr = 0 3 | def trace (obj, key, *args) 4 | $ctr += 1 5 | idx = $ctr 6 | puts("#{Thread.current.object_id} call \##{idx} #{key} #{args}") 7 | res = obj.send(key, *args) 8 | puts("#{Thread.current.object_id} return \##{idx} #{key} #{res}") 9 | return res 10 | end -------------------------------------------------------------------------------- /lib/node/.eslintrc.yaml: -------------------------------------------------------------------------------- 1 | env: 2 | node: true 3 | -------------------------------------------------------------------------------- /lib/node/client.mjs: -------------------------------------------------------------------------------- 1 | import { default as process } from "node:process"; 2 | import { updateGlobalConfiguration } from "./global.mjs"; 3 | import "./error.mjs"; 4 | 5 | const { loadProcessConfiguration } = await import( 6 | "../../dist/bundles/configuration-process.mjs" 7 | ); 8 | 9 | const configuration = loadProcessConfiguration(process); 10 | 11 | updateGlobalConfiguration(configuration); 12 | 13 | const { mainAsync } = await import("../../dist/bundles/client.mjs"); 14 | 15 | export default mainAsync(process, configuration); 16 | -------------------------------------------------------------------------------- /lib/node/configuration.mjs: -------------------------------------------------------------------------------- 1 | import { env } from "node:process"; 2 | import { updateGlobalConfiguration } from "./global.mjs"; 3 | 4 | const { loadEnvironmentConfiguration } = await import( 5 | "../../dist/bundles/configuration-environment.mjs" 6 | ); 7 | 8 | export const configuration = loadEnvironmentConfiguration(env); 9 | 10 | updateGlobalConfiguration(configuration); 11 | -------------------------------------------------------------------------------- /lib/node/error.mjs: -------------------------------------------------------------------------------- 1 | import { default as process, stderr } from "node:process"; 2 | import "./global.mjs"; 3 | 4 | const { reportError } = await import("../../dist/bundles/error.mjs"); 5 | const { reportException } = await import( 6 | "../../dist/bundles/crash-reporter.mjs" 7 | ); 8 | 9 | process.on("uncaughtExceptionMonitor", (error) => { 10 | reportException(error); 11 | stderr.write(reportError(error)); 12 | }); 13 | -------------------------------------------------------------------------------- /lib/node/global.mjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable local/global-object-access */ 2 | 3 | const { 4 | Reflect: { defineProperty }, 5 | } = globalThis; 6 | 7 | const define = (object, key, value) => { 8 | defineProperty(object, key, { 9 | __proto__: null, 10 | value, 11 | writable: true, 12 | enumerable: true, 13 | configurable: true, 14 | }); 15 | }; 16 | 17 | define(globalThis, "__APPMAP_LOG_FILE__", 1); 18 | define(globalThis, "__APPMAP_LOG_LEVEL__", "info"); 19 | define(globalThis, "__APPMAP_SOCKET__", "net"); 20 | 21 | export const updateGlobalConfiguration = (configuration) => { 22 | define(globalThis, "__APPMAP_LOG_FILE__", configuration.log.file); 23 | define(globalThis, "__APPMAP_LOG_LEVEL__", configuration.log.level); 24 | define(globalThis, "__APPMAP_SOCKET__", configuration.socket); 25 | }; 26 | -------------------------------------------------------------------------------- /lib/node/init.mjs: -------------------------------------------------------------------------------- 1 | import "./global.mjs"; 2 | import "./error.mjs"; 3 | 4 | const { 5 | process: { argv, cwd }, 6 | } = globalThis; 7 | 8 | const { main } = await import("../../dist/bundles/init.mjs"); 9 | 10 | const root = argv[2] || cwd(); 11 | 12 | export default main(root); 13 | -------------------------------------------------------------------------------- /lib/node/recorder-api.mjs: -------------------------------------------------------------------------------- 1 | import { cwd } from "node:process"; 2 | import { pathToFileURL } from "node:url"; 3 | import "./global.mjs"; 4 | import "./error.mjs"; 5 | 6 | const url = pathToFileURL(cwd()).toString(); 7 | 8 | const { Appmap } = await import("../../dist/bundles/recorder-api.mjs"); 9 | 10 | export const createAppMap = (home = url, conf = {}, base = url) => 11 | new Appmap(home, conf, base); 12 | -------------------------------------------------------------------------------- /lib/node/recorder.mjs: -------------------------------------------------------------------------------- 1 | import "./global.mjs"; 2 | import "./error.mjs"; 3 | import { configuration } from "./configuration.mjs"; 4 | export * from "./loader-esm.mjs"; 5 | 6 | const map = { 7 | __proto__: null, 8 | remote: "node", 9 | process: "node", 10 | mocha: "mocha", 11 | jest: "jest", 12 | }; 13 | 14 | // Use top-level await to wait for ./configuration.mjs to update env variables. 15 | const { recordAsync } = await import( 16 | `../../dist/bundles/recorder-${map[configuration.recorder]}.mjs` 17 | ); 18 | 19 | await recordAsync(configuration); 20 | -------------------------------------------------------------------------------- /lib/node/server.mjs: -------------------------------------------------------------------------------- 1 | import process from "node:process"; 2 | import { updateGlobalConfiguration } from "./global.mjs"; 3 | import "./error.mjs"; 4 | 5 | const { loadProcessConfiguration } = await import( 6 | "../../dist/bundles/configuration-process.mjs" 7 | ); 8 | 9 | const configuration = loadProcessConfiguration(process); 10 | 11 | updateGlobalConfiguration(configuration); 12 | 13 | const { mainAsync } = await import("../../dist/bundles/server.mjs"); 14 | 15 | export default mainAsync(process, configuration); 16 | -------------------------------------------------------------------------------- /lib/node/setup.mjs: -------------------------------------------------------------------------------- 1 | import process from "node:process"; 2 | import "./global.mjs"; 3 | import "./error.mjs"; 4 | 5 | const { mainAsync } = await import("../../dist/bundles/setup.mjs"); 6 | 7 | export default mainAsync(process); 8 | -------------------------------------------------------------------------------- /lib/node/status.mjs: -------------------------------------------------------------------------------- 1 | import { argv, cwd } from "node:process"; 2 | import "./global.mjs"; 3 | import "./error.mjs"; 4 | 5 | const { main } = await import("../../dist/bundles/status.mjs"); 6 | 7 | const root = argv[2] || cwd(); 8 | 9 | export default main(root); 10 | -------------------------------------------------------------------------------- /lib/node/transformer-jest.mjs: -------------------------------------------------------------------------------- 1 | // https://github.com/facebook/jest/blob/ee63afcbe7904d18558d3cc40e0940804df3deb7/packages/jest-transform/src/ScriptTransformer.ts#L261 2 | 3 | import "./global.mjs"; 4 | import "./error.mjs"; 5 | import { configuration } from "./configuration.mjs"; 6 | 7 | const { compileCreateTransformer } = await import( 8 | "../../dist/bundles/transformer-jest.mjs" 9 | ); 10 | 11 | export default { 12 | createTransformer: compileCreateTransformer(configuration), 13 | }; 14 | -------------------------------------------------------------------------------- /lib/node/version.mjs: -------------------------------------------------------------------------------- 1 | import { createRequire } from "node:module"; 2 | 3 | const { Promise, URL, process } = globalThis; 4 | 5 | const require = createRequire(new URL(import.meta.url)); 6 | 7 | const { name, version } = require("../../package.json"); 8 | 9 | export default new Promise((resolve, reject) => { 10 | process.stdout.write(`${name}@${version}${"\n"}`, "utf8", (error) => { 11 | if (error) { 12 | reject(error); 13 | } else { 14 | resolve(0); 15 | } 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /schema/definitions/agent-cooked.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - directory 5 | - package 6 | properties: 7 | directory: 8 | $ref: url 9 | package: 10 | $ref: package 11 | -------------------------------------------------------------------------------- /schema/definitions/agent.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - directory 5 | - package 6 | properties: 7 | directory: 8 | $ref: path 9 | package: 10 | $ref: package 11 | -------------------------------------------------------------------------------- /schema/definitions/basename.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | pattern: ^[^/.]+$ 3 | -------------------------------------------------------------------------------- /schema/definitions/combinator.yaml: -------------------------------------------------------------------------------- 1 | enum: 2 | - and 3 | - or 4 | -------------------------------------------------------------------------------- /schema/definitions/command-cooked.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | nullable: true 4 | properties: 5 | tokens: 6 | type: array 7 | nullable: true 8 | items: 9 | type: string 10 | source: 11 | type: string 12 | nullable: true 13 | -------------------------------------------------------------------------------- /schema/definitions/command-options-cooked.yaml: -------------------------------------------------------------------------------- 1 | allOf: 2 | - $ref: command-options 3 | - type: object 4 | required: 5 | - shell 6 | - cwd 7 | - encoding 8 | - env 9 | - stdio 10 | - timeout 11 | - killSignal 12 | -------------------------------------------------------------------------------- /schema/definitions/command-options.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | properties: 4 | shell: 5 | anyOf: 6 | - type: boolean 7 | - type: string 8 | cwd: 9 | $ref: path 10 | encoding: 11 | $ref: encoding 12 | env: 13 | $ref: env 14 | stdio: 15 | $ref: stdio 16 | timeout: 17 | type: integer 18 | minimum: 0 19 | killSignal: 20 | $ref: signal 21 | -------------------------------------------------------------------------------- /schema/definitions/command.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - type: string 3 | - type: array 4 | items: 5 | type: string 6 | -------------------------------------------------------------------------------- /schema/definitions/config.yaml: -------------------------------------------------------------------------------- 1 | # Alias for the installer 2 | # https://github.com/getappmap/appmap-js/blob/f917b055dca17065b307620c67c8917457826fd9/packages/cli/src/service/config/validator.ts#L26 3 | 4 | $ref: configuration-external 5 | -------------------------------------------------------------------------------- /schema/definitions/criteria.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - type: boolean 3 | - type: string 4 | -------------------------------------------------------------------------------- /schema/definitions/encoding.yaml: -------------------------------------------------------------------------------- 1 | enum: 2 | - buffer 3 | - utf8 4 | - utf16le 5 | - latin1 6 | -------------------------------------------------------------------------------- /schema/definitions/env.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | patternProperties: 4 | ^: 5 | type: string 6 | -------------------------------------------------------------------------------- /schema/definitions/exclude-cooked.yaml: -------------------------------------------------------------------------------- 1 | type: array 2 | items: 3 | $ref: exclusion-cooked 4 | -------------------------------------------------------------------------------- /schema/definitions/exclude.yaml: -------------------------------------------------------------------------------- 1 | type: array 2 | items: 3 | $ref: exclusion 4 | -------------------------------------------------------------------------------- /schema/definitions/exclusion-cooked.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - combinator 5 | - qualified-name 6 | - name 7 | - every-label 8 | - some-label 9 | - excluded 10 | - recursive 11 | properties: 12 | combinator: 13 | $ref: combinator 14 | qualified-name: 15 | $ref: criteria 16 | name: 17 | $ref: criteria 18 | every-label: 19 | $ref: criteria 20 | some-label: 21 | $ref: criteria 22 | excluded: 23 | type: boolean 24 | recursive: 25 | type: boolean 26 | -------------------------------------------------------------------------------- /schema/definitions/exclusion.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - type: string 3 | - type: object 4 | additionalProperties: false 5 | properties: 6 | combinator: 7 | $ref: combinator 8 | qualified-name: 9 | $ref: criteria 10 | name: 11 | $ref: criteria 12 | every-label: 13 | $ref: criteria 14 | some-label: 15 | $ref: criteria 16 | excluded: 17 | type: boolean 18 | recursive: 19 | type: boolean 20 | -------------------------------------------------------------------------------- /schema/definitions/group.yaml: -------------------------------------------------------------------------------- 1 | type: number 2 | -------------------------------------------------------------------------------- /schema/definitions/headers.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | patternProperties: 4 | ^: 5 | type: string 6 | -------------------------------------------------------------------------------- /schema/definitions/heartbeat.yaml: -------------------------------------------------------------------------------- 1 | $ref: natural-nullable 2 | -------------------------------------------------------------------------------- /schema/definitions/identifier.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | pattern: ^[a-zA-Z_$][a-zA-Z_$-9]*$ 3 | -------------------------------------------------------------------------------- /schema/definitions/language.yaml: -------------------------------------------------------------------------------- 1 | const: javascript 2 | -------------------------------------------------------------------------------- /schema/definitions/log-cooked.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | properties: 4 | level: 5 | $ref: log-level 6 | file: 7 | anyOf: 8 | - $ref: url 9 | - const: 1 10 | - const: 2 11 | -------------------------------------------------------------------------------- /schema/definitions/log-level.yaml: -------------------------------------------------------------------------------- 1 | enum: 2 | - debug 3 | - info 4 | - warning 5 | - error 6 | - off 7 | -------------------------------------------------------------------------------- /schema/definitions/log.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - $ref: log-level 3 | - type: object 4 | additionalProperties: false 5 | properties: 6 | level: 7 | $ref: log-level 8 | file: 9 | anyOf: 10 | - $ref: path 11 | - const: 1 12 | - const: 2 13 | -------------------------------------------------------------------------------- /schema/definitions/matcher-cooked.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - type: boolean 3 | - type: object 4 | additionalProperties: false 5 | required: 6 | - base 7 | - source 8 | - flags 9 | properties: 10 | base: 11 | anyOf: 12 | - const: null 13 | - $ref: url 14 | source: 15 | type: string 16 | flags: 17 | type: string 18 | -------------------------------------------------------------------------------- /schema/definitions/message-amend.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - session 6 | - site 7 | - tab 8 | - payload 9 | properties: 10 | type: 11 | const: amend 12 | session: 13 | $ref: session 14 | site: 15 | $ref: site 16 | tab: 17 | $ref: tab 18 | payload: 19 | $ref: payload 20 | -------------------------------------------------------------------------------- /schema/definitions/message-error.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - session 6 | - error 7 | properties: 8 | type: 9 | const: error 10 | session: 11 | $ref: session 12 | error: 13 | $ref: serial 14 | -------------------------------------------------------------------------------- /schema/definitions/message-group.yaml: -------------------------------------------------------------------------------- 1 | # Shorthand for group event pair to improve performance. 2 | # Group-related messages are a large part of the trace. 3 | 4 | type: object 5 | additionalProperties: false 6 | required: 7 | - type 8 | - session 9 | - group 10 | - child 11 | - description 12 | properties: 13 | type: 14 | const: group 15 | session: 16 | $ref: session 17 | group: 18 | $ref: group 19 | child: 20 | $ref: group 21 | description: 22 | type: string 23 | -------------------------------------------------------------------------------- /schema/definitions/message-source.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - url 6 | - content 7 | properties: 8 | type: 9 | const: source 10 | url: 11 | $ref: url 12 | content: 13 | type: string 14 | nullable: true 15 | -------------------------------------------------------------------------------- /schema/definitions/message-start.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - track 6 | - configuration 7 | properties: 8 | type: 9 | const: start 10 | track: 11 | type: string 12 | configuration: 13 | $ref: configuration-internal 14 | -------------------------------------------------------------------------------- /schema/definitions/message-stop.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - track 6 | - termination 7 | properties: 8 | type: 9 | const: stop 10 | track: 11 | type: string 12 | nullable: true 13 | termination: 14 | $ref: termination 15 | -------------------------------------------------------------------------------- /schema/definitions/message.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - $ref: message-amend 3 | - $ref: message-error 4 | - $ref: message-event 5 | - $ref: message-group 6 | - $ref: message-source 7 | - $ref: message-start 8 | - $ref: message-stop 9 | -------------------------------------------------------------------------------- /schema/definitions/module-cooked.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - enabled 5 | - shallow 6 | - inline-source 7 | - exclude 8 | - parsing 9 | properties: 10 | enabled: 11 | type: boolean 12 | shallow: 13 | type: boolean 14 | inline-source: 15 | type: boolean 16 | nullable: true 17 | exclude: 18 | $ref: exclude-cooked 19 | source-type: 20 | $ref: source-type 21 | parsing: 22 | $ref: parsing 23 | -------------------------------------------------------------------------------- /schema/definitions/module.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - type: boolean 3 | - type: object 4 | additionalProperties: false 5 | properties: 6 | enabled: 7 | type: boolean 8 | shallow: 9 | type: boolean 10 | inline-source: 11 | type: boolean 12 | nullable: true 13 | exclude: 14 | $ref: exclude 15 | source-type: 16 | $ref: source-type 17 | parsing: 18 | $ref: parsing 19 | -------------------------------------------------------------------------------- /schema/definitions/name-version-object.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - name 5 | - version 6 | properties: 7 | name: 8 | type: string 9 | version: 10 | type: string 11 | nullable: true 12 | -------------------------------------------------------------------------------- /schema/definitions/name-version-string.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | pattern: ^[^@]+(@[^@]+)?$ 3 | -------------------------------------------------------------------------------- /schema/definitions/name-version.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - $ref: name-version-string 3 | - $ref: name-version-object 4 | -------------------------------------------------------------------------------- /schema/definitions/natural-nullable.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - const: null 3 | - $ref: natural 4 | -------------------------------------------------------------------------------- /schema/definitions/natural.yaml: -------------------------------------------------------------------------------- 1 | type: integer 2 | minimum: 0 3 | maximum: 9007199254740991 4 | -------------------------------------------------------------------------------- /schema/definitions/ordering.yaml: -------------------------------------------------------------------------------- 1 | enum: 2 | - chronological 3 | - causal 4 | -------------------------------------------------------------------------------- /schema/definitions/package.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - name 5 | - version 6 | - homepage 7 | properties: 8 | name: 9 | type: string 10 | version: 11 | type: string 12 | homepage: 13 | type: string 14 | nullable: true 15 | -------------------------------------------------------------------------------- /schema/definitions/parsing.yaml: -------------------------------------------------------------------------------- 1 | type: array 2 | nullable: true 3 | items: 4 | anyOf: 5 | - type: string 6 | - type: array 7 | minItems: 2 8 | maxItems: 2 9 | items: 10 | - type: string 11 | - type: object 12 | -------------------------------------------------------------------------------- /schema/definitions/path.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | -------------------------------------------------------------------------------- /schema/definitions/payload-answer.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | properties: 6 | type: 7 | const: answer 8 | -------------------------------------------------------------------------------- /schema/definitions/payload-apply.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - function 6 | - this 7 | - arguments 8 | properties: 9 | type: 10 | const: apply 11 | function: 12 | type: string 13 | this: 14 | $ref: serial 15 | arguments: 16 | type: array 17 | items: 18 | $ref: serial 19 | -------------------------------------------------------------------------------- /schema/definitions/payload-await.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - promise 6 | properties: 7 | type: 8 | const: await 9 | promise: 10 | $ref: serial 11 | -------------------------------------------------------------------------------- /schema/definitions/payload-bundle.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | properties: 6 | type: 7 | const: bundle 8 | -------------------------------------------------------------------------------- /schema/definitions/payload-group.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - group 6 | - description 7 | properties: 8 | type: 9 | const: group 10 | group: 11 | $ref: group 12 | description: 13 | type: string 14 | -------------------------------------------------------------------------------- /schema/definitions/payload-jump.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | properties: 6 | type: 7 | const: jump 8 | -------------------------------------------------------------------------------- /schema/definitions/payload-query.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - database 6 | - version 7 | - sql 8 | - parameters 9 | properties: 10 | type: 11 | const: query 12 | database: 13 | type: string 14 | nullable: true 15 | version: 16 | type: string 17 | nullable: true 18 | sql: 19 | type: string 20 | parameters: 21 | anyOf: 22 | - type: array 23 | items: 24 | $ref: serial 25 | - type: object 26 | additionalProperties: false 27 | patternProperties: 28 | ^: 29 | $ref: serial 30 | -------------------------------------------------------------------------------- /schema/definitions/payload-reject.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - error 6 | properties: 7 | type: 8 | const: reject 9 | error: 10 | $ref: serial 11 | -------------------------------------------------------------------------------- /schema/definitions/payload-request.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - side 6 | - protocol 7 | - method 8 | - url 9 | - route 10 | - headers 11 | - body 12 | properties: 13 | type: 14 | const: request 15 | side: 16 | $ref: side 17 | protocol: 18 | type: string 19 | method: 20 | type: string 21 | url: 22 | type: string 23 | route: 24 | type: string 25 | nullable: true 26 | headers: 27 | $ref: headers 28 | body: 29 | $ref: serial 30 | -------------------------------------------------------------------------------- /schema/definitions/payload-resolve.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - result 6 | properties: 7 | type: 8 | const: resolve 9 | result: 10 | $ref: serial 11 | -------------------------------------------------------------------------------- /schema/definitions/payload-response.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - side 6 | - status 7 | - message 8 | - headers 9 | - body 10 | properties: 11 | type: 12 | const: response 13 | side: 14 | $ref: side 15 | status: 16 | type: integer 17 | message: 18 | type: string 19 | headers: 20 | $ref: headers 21 | body: 22 | $ref: serial 23 | -------------------------------------------------------------------------------- /schema/definitions/payload-return.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - function 6 | - result 7 | properties: 8 | type: 9 | const: return 10 | function: 11 | type: string 12 | result: 13 | $ref: serial 14 | -------------------------------------------------------------------------------- /schema/definitions/payload-throw.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - function 6 | - error 7 | properties: 8 | type: 9 | const: throw 10 | function: 11 | type: string 12 | error: 13 | $ref: serial 14 | -------------------------------------------------------------------------------- /schema/definitions/payload-ungroup.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - group 6 | properties: 7 | type: 8 | const: ungroup 9 | group: 10 | $ref: group 11 | -------------------------------------------------------------------------------- /schema/definitions/payload-yield.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - iterator 6 | properties: 7 | type: 8 | const: yield 9 | iterator: 10 | $ref: serial 11 | -------------------------------------------------------------------------------- /schema/definitions/payload.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - $ref: payload-answer 3 | - $ref: payload-apply 4 | - $ref: payload-await 5 | - $ref: payload-bundle 6 | - $ref: payload-group 7 | - $ref: payload-jump 8 | - $ref: payload-query 9 | - $ref: payload-reject 10 | - $ref: payload-request 11 | - $ref: payload-resolve 12 | - $ref: payload-response 13 | - $ref: payload-return 14 | - $ref: payload-throw 15 | - $ref: payload-ungroup 16 | - $ref: payload-yield 17 | -------------------------------------------------------------------------------- /schema/definitions/port-cooked.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - const: 0 3 | - const: "" 4 | - $ref: port-number 5 | - $ref: url 6 | -------------------------------------------------------------------------------- /schema/definitions/port-number.yaml: -------------------------------------------------------------------------------- 1 | type: integer 2 | minimum: 1 3 | maximum: 65535 4 | -------------------------------------------------------------------------------- /schema/definitions/port-proxy.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - const: null 3 | - const: 0 4 | - $ref: port-number 5 | -------------------------------------------------------------------------------- /schema/definitions/port.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - const: 0 3 | - const: "" 4 | - $ref: port-number 5 | - $ref: path 6 | -------------------------------------------------------------------------------- /schema/definitions/process.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - enabled 5 | properties: 6 | enabled: 7 | type: boolean 8 | -------------------------------------------------------------------------------- /schema/definitions/recorder.yaml: -------------------------------------------------------------------------------- 1 | # NOTE: when changing this, make sure to adjust the type map in components/trace/appmap/metadata 2 | enum: 3 | - process 4 | - mocha 5 | - jest 6 | - manual 7 | - remote 8 | -------------------------------------------------------------------------------- /schema/definitions/recording-object.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - defined-class 5 | - method-id 6 | properties: 7 | defined-class: 8 | type: string 9 | method-id: 10 | type: string 11 | -------------------------------------------------------------------------------- /schema/definitions/recording-string.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | pattern: ^[^.]+.[^.]+$ 3 | -------------------------------------------------------------------------------- /schema/definitions/recording.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - $ref: recording-string 3 | - $ref: recording-object 4 | -------------------------------------------------------------------------------- /schema/definitions/regexp.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | -------------------------------------------------------------------------------- /schema/definitions/repository.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - directory 5 | - history 6 | - package 7 | properties: 8 | directory: 9 | $ref: url 10 | history: 11 | type: object 12 | nullable: true 13 | package: 14 | anyOf: 15 | - const: null 16 | - $ref: package 17 | -------------------------------------------------------------------------------- /schema/definitions/serial-primitive.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - print 6 | properties: 7 | type: 8 | enum: 9 | - "null" 10 | - undefined 11 | - boolean 12 | - number 13 | - string 14 | - bigint 15 | print: 16 | type: string 17 | -------------------------------------------------------------------------------- /schema/definitions/serial-reference.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - print 6 | - index 7 | - constructor 8 | - specific 9 | properties: 10 | type: 11 | enum: 12 | - object 13 | - function 14 | print: 15 | type: string 16 | index: 17 | $ref: natural 18 | constructor: 19 | type: string 20 | nullable: true 21 | specific: 22 | $ref: specific 23 | -------------------------------------------------------------------------------- /schema/definitions/serial-symbol.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - print 6 | - index 7 | properties: 8 | type: 9 | const: symbol 10 | print: 11 | type: string 12 | index: 13 | $ref: natural 14 | -------------------------------------------------------------------------------- /schema/definitions/serial.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - const: null 3 | - $ref: serial-primitive 4 | - $ref: serial-reference 5 | - $ref: serial-symbol 6 | -------------------------------------------------------------------------------- /schema/definitions/serialization.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | properties: 4 | maximum-print-length: 5 | type: number 6 | nullable: true 7 | minimum: 0 8 | maximum-properties-length: 9 | type: number 10 | nullable: true 11 | minimum: 0 12 | impure-printing: 13 | type: boolean 14 | impure-constructor-naming: 15 | type: boolean 16 | impure-array-inspection: 17 | type: boolean 18 | impure-error-inspection: 19 | type: boolean 20 | impure-hash-inspection: 21 | type: boolean 22 | -------------------------------------------------------------------------------- /schema/definitions/session.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | -------------------------------------------------------------------------------- /schema/definitions/side.yaml: -------------------------------------------------------------------------------- 1 | enum: 2 | - client 3 | - server 4 | -------------------------------------------------------------------------------- /schema/definitions/signal.yaml: -------------------------------------------------------------------------------- 1 | enum: 2 | - SIGINT 3 | - SIGTERM 4 | - SIGKILL 5 | -------------------------------------------------------------------------------- /schema/definitions/site.yaml: -------------------------------------------------------------------------------- 1 | enum: 2 | - begin 3 | - end 4 | - before 5 | - after 6 | -------------------------------------------------------------------------------- /schema/definitions/socket.yaml: -------------------------------------------------------------------------------- 1 | enum: 2 | - unix 3 | - net 4 | -------------------------------------------------------------------------------- /schema/definitions/source-map.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | required: 3 | - version 4 | - sources 5 | - names 6 | - mappings 7 | properties: 8 | version: 9 | const: 3 10 | file: 11 | type: string 12 | nullable: true 13 | sourceRoot: 14 | type: string 15 | nullable: true 16 | sources: 17 | type: array 18 | items: 19 | type: string 20 | sourcesContent: 21 | type: array 22 | nullable: true 23 | items: 24 | type: string 25 | nullable: true 26 | names: 27 | type: array 28 | items: 29 | type: string 30 | mappings: 31 | type: string 32 | -------------------------------------------------------------------------------- /schema/definitions/source-type.yaml: -------------------------------------------------------------------------------- 1 | enum: 2 | - null 3 | - script 4 | - module 5 | -------------------------------------------------------------------------------- /schema/definitions/specific-array.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - length 6 | properties: 7 | type: 8 | const: array 9 | length: 10 | $ref: natural 11 | -------------------------------------------------------------------------------- /schema/definitions/specific-error.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - name 6 | - message 7 | - stack 8 | properties: 9 | type: 10 | const: error 11 | name: 12 | type: string 13 | nullable: true 14 | message: 15 | type: string 16 | nullable: true 17 | stack: 18 | type: string 19 | nullable: true 20 | -------------------------------------------------------------------------------- /schema/definitions/specific-hash.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - length 6 | - properties 7 | properties: 8 | type: 9 | const: hash 10 | length: 11 | $ref: natural 12 | properties: 13 | type: object 14 | additionalProperties: false 15 | patternProperties: 16 | ^: 17 | type: string 18 | -------------------------------------------------------------------------------- /schema/definitions/specific.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - const: null 3 | - $ref: specific-array 4 | - $ref: specific-error 5 | - $ref: specific-hash 6 | -------------------------------------------------------------------------------- /schema/definitions/stdio-stream.yaml: -------------------------------------------------------------------------------- 1 | enum: 2 | - ignore 3 | - pipe 4 | - inherit 5 | -------------------------------------------------------------------------------- /schema/definitions/stdio.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - $ref: stdio-stream 3 | - type: array 4 | minItems: 3 5 | maxItems: 3 6 | items: 7 | - $ref: stdio-stream 8 | - $ref: stdio-stream 9 | - $ref: stdio-stream 10 | -------------------------------------------------------------------------------- /schema/definitions/tab.yaml: -------------------------------------------------------------------------------- 1 | $ref: natural 2 | -------------------------------------------------------------------------------- /schema/definitions/termination-disconnect.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | properties: 6 | type: 7 | const: disconnect 8 | -------------------------------------------------------------------------------- /schema/definitions/termination-exit.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - status 6 | properties: 7 | type: 8 | const: exit 9 | status: 10 | type: integer 11 | minimum: 0 12 | maximum: 255 13 | -------------------------------------------------------------------------------- /schema/definitions/termination-manual.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | properties: 6 | type: 7 | const: manual 8 | -------------------------------------------------------------------------------- /schema/definitions/termination-test.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | - passed 6 | properties: 7 | type: 8 | const: test 9 | passed: 10 | type: boolean 11 | -------------------------------------------------------------------------------- /schema/definitions/termination-unknown.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | additionalProperties: false 3 | required: 4 | - type 5 | properties: 6 | type: 7 | const: unknown 8 | -------------------------------------------------------------------------------- /schema/definitions/termination.yaml: -------------------------------------------------------------------------------- 1 | anyOf: 2 | - $ref: termination-exit 3 | - $ref: termination-disconnect 4 | - $ref: termination-test 5 | - $ref: termination-manual 6 | - $ref: termination-unknown 7 | -------------------------------------------------------------------------------- /schema/definitions/threshold.yaml: -------------------------------------------------------------------------------- 1 | $ref: natural-nullable 2 | -------------------------------------------------------------------------------- /schema/definitions/url-component.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | pattern: "[A–Za–z0–9\\-_.!~*'()]+" 3 | -------------------------------------------------------------------------------- /schema/definitions/url.yaml: -------------------------------------------------------------------------------- 1 | type: string 2 | pattern: ^([a-z]+://|data:) 3 | -------------------------------------------------------------------------------- /schema/list-permisive-object.mjs: -------------------------------------------------------------------------------- 1 | import { stdout } from "node:process"; 2 | import { 3 | readdir as readdirAsync, 4 | readFile as readFileAsync, 5 | } from "node:fs/promises"; 6 | 7 | const { String, URL } = globalThis; 8 | 9 | const { url } = import.meta; 10 | 11 | for (const filename of await readdirAsync(new URL("definitions", url))) { 12 | (await readFileAsync(new URL(`definitions/${filename}`, url), "utf8")) 13 | .split("\n") 14 | .forEach((line, index, lines) => { 15 | if (/type:\s*object/u.test(line)) { 16 | if ( 17 | index + 1 >= lines.length || 18 | !/additionalProperties:\s*false/u.test(lines[index + 1]) 19 | ) { 20 | stdout.write(`${filename}:${String(index + 1)}\n`); 21 | } 22 | } 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /test/.eslintrc.yaml: -------------------------------------------------------------------------------- 1 | env: 2 | node: true 3 | -------------------------------------------------------------------------------- /test/cases/apply-async/appmap.yml: -------------------------------------------------------------------------------- 1 | recorder: process 2 | packages: 3 | path: main.mjs 4 | enabled: true 5 | command: node main.mjs 6 | appmap_dir: . 7 | appmap_file: main 8 | hooks: 9 | cjs: false 10 | esm: true 11 | eval: false 12 | apply: true 13 | http: false 14 | mysql: false 15 | pg: false 16 | sqlite3: false 17 | validate: 18 | appmap: true 19 | -------------------------------------------------------------------------------- /test/cases/apply-async/main.mjs: -------------------------------------------------------------------------------- 1 | import { strict as Assert } from "node:assert"; 2 | const { equal: assertEqual } = Assert; 3 | const { Promise } = globalThis; 4 | async function mainAsync(x) { 5 | assertEqual(x, 123); 6 | return await new Promise(function promiseCallback(resolve, _reject) { 7 | resolve(456); 8 | }); 9 | } 10 | assertEqual(await mainAsync(123), 456); 11 | -------------------------------------------------------------------------------- /test/cases/apply-async/process/main.subset.yaml: -------------------------------------------------------------------------------- 1 | events: 2 | - event: call 3 | id: 1 4 | method_id: mainAsync 5 | - event: call 6 | id: 2 7 | method_id: promiseCallback 8 | - event: return 9 | id: 3 10 | parent_id: 2 11 | - event: return 12 | id: 4 13 | parent_id: 1 14 | -------------------------------------------------------------------------------- /test/cases/apply-generator/appmap.yml: -------------------------------------------------------------------------------- 1 | recorder: process 2 | packages: 3 | path: main.mjs 4 | enabled: true 5 | command: node main.mjs 6 | appmap_dir: . 7 | appmap_file: main 8 | hooks: 9 | cjs: false 10 | esm: true 11 | eval: false 12 | apply: true 13 | http: false 14 | mysql: false 15 | pg: false 16 | sqlite3: false 17 | validate: 18 | appmap: true 19 | -------------------------------------------------------------------------------- /test/cases/apply-generator/main.mjs: -------------------------------------------------------------------------------- 1 | import { strict as Assert } from "node:assert"; 2 | const { equal: assertEqual, deepEqual: assertDeepEqual } = Assert; 3 | const { undefined } = globalThis; 4 | function* g(x) { 5 | assertEqual(yield 1 * x, "bar"); 6 | assertEqual(yield 2 * x, undefined); 7 | assertEqual(yield* [3 * x, 4 * x], undefined); 8 | return "result"; 9 | } 10 | const i = g(2); 11 | assertDeepEqual(i.next("foo"), { value: 2, done: false }); 12 | assertDeepEqual(i.next("bar"), { value: 4, done: false }); 13 | assertDeepEqual(i.next(), { value: 6, done: false }); 14 | assertDeepEqual(i.next("qux"), { value: 8, done: false }); 15 | assertDeepEqual(i.next(), { value: "result", done: true }); 16 | assertDeepEqual(i.next(), { value: undefined, done: true }); 17 | -------------------------------------------------------------------------------- /test/cases/apply-generator/process/main.subset.yaml: -------------------------------------------------------------------------------- 1 | events: 2 | - event: call 3 | id: 1 4 | method_id: g 5 | - event: return 6 | id: 2 7 | parent_id: 1 8 | -------------------------------------------------------------------------------- /test/cases/apply-mismatch/appmap.yml: -------------------------------------------------------------------------------- 1 | recorder: process 2 | packages: 3 | path: main.mjs 4 | enabled: true 5 | command: node main.mjs 6 | appmap_dir: . 7 | appmap_file: main 8 | hooks: 9 | cjs: false 10 | esm: true 11 | eval: false 12 | apply: true 13 | http: false 14 | mysql: false 15 | pg: false 16 | sqlite3: false 17 | validate: 18 | appmap: true 19 | -------------------------------------------------------------------------------- /test/cases/apply-mismatch/main.mjs: -------------------------------------------------------------------------------- 1 | import { strict as Assert } from "node:assert"; 2 | const { undefined } = globalThis; 3 | const { deepEqual: assertDeepEqual } = Assert; 4 | const pairup = (x, y) => [x, y]; 5 | assertDeepEqual(pairup(123, 456, 789), [123, 456]); 6 | assertDeepEqual(pairup(123), [123, undefined]); 7 | -------------------------------------------------------------------------------- /test/cases/apply-mismatch/process/main.subset.yaml: -------------------------------------------------------------------------------- 1 | events: 2 | - event: call 3 | id: 1 4 | method_id: pairup 5 | parameters: 6 | - name: x 7 | - name: y 8 | - event: return 9 | id: 2 10 | parent_id: 1 11 | - event: call 12 | id: 3 13 | method_id: pairup 14 | parameters: 15 | - name: x 16 | - name: y 17 | - event: return 18 | id: 4 19 | parent_id: 3 20 | -------------------------------------------------------------------------------- /test/cases/apply-pattern/appmap.yml: -------------------------------------------------------------------------------- 1 | recorder: process 2 | packages: 3 | path: main.mjs 4 | enabled: true 5 | command: node main.mjs 6 | appmap_dir: . 7 | appmap_file: main 8 | hooks: 9 | cjs: false 10 | esm: true 11 | eval: false 12 | apply: true 13 | http: false 14 | mysql: false 15 | pg: false 16 | sqlite3: false 17 | validate: 18 | appmap: true 19 | -------------------------------------------------------------------------------- /test/cases/apply-pattern/main.mjs: -------------------------------------------------------------------------------- 1 | import { strict as Assert } from "node:assert"; 2 | const { deepEqual: assertDeepEqual } = Assert; 3 | const toObject = ([x1, x2]) => ({ x1, x2 }); 4 | assertDeepEqual(toObject([123, 456]), { x1: 123, x2: 456 }); 5 | -------------------------------------------------------------------------------- /test/cases/apply-pattern/process/main.subset.yaml: -------------------------------------------------------------------------------- 1 | events: 2 | - event: call 3 | id: 1 4 | method_id: toObject 5 | parameters: 6 | - name: "[x1, x2]" 7 | - event: return 8 | id: 2 9 | parent_id: 1 10 | -------------------------------------------------------------------------------- /test/cases/apply-rest/appmap.yml: -------------------------------------------------------------------------------- 1 | recorder: process 2 | packages: 3 | path: main.mjs 4 | enabled: true 5 | command: node main.mjs 6 | appmap_dir: . 7 | appmap_file: main 8 | hooks: 9 | cjs: false 10 | esm: true 11 | eval: false 12 | apply: true 13 | http: false 14 | mysql: false 15 | pg: false 16 | sqlite3: false 17 | validate: 18 | appmap: true 19 | -------------------------------------------------------------------------------- /test/cases/apply-rest/main.mjs: -------------------------------------------------------------------------------- 1 | import { strict as Assert } from "node:assert"; 2 | const { deepEqual: assertDeepEqual } = Assert; 3 | const rest = (x, ...xs) => ({ x, xs }); 4 | assertDeepEqual(rest(123, 456, 789), { x: 123, xs: [456, 789] }); 5 | -------------------------------------------------------------------------------- /test/cases/apply-rest/process/main.subset.yaml: -------------------------------------------------------------------------------- 1 | events: 2 | - event: call 3 | id: 1 4 | method_id: rest 5 | parameters: 6 | - name: x 7 | - name: ...xs 8 | - event: return 9 | id: 2 10 | parent_id: 1 11 | -------------------------------------------------------------------------------- /test/cases/apply-source/appmap.yml: -------------------------------------------------------------------------------- 1 | recorder: process 2 | pruning: false 3 | packages: 4 | path: source.mjs 5 | enabled: true 6 | source-type: module 7 | parsing: 8 | - decorators 9 | command: node script.mjs 10 | appmap_dir: . 11 | appmap_file: script 12 | hooks: 13 | cjs: false 14 | esm: true 15 | eval: false 16 | apply: true 17 | http: false 18 | mysql: false 19 | pg: false 20 | sqlite3: false 21 | validate: 22 | appmap: true 23 | -------------------------------------------------------------------------------- /test/cases/apply-source/generate-source-map.mjs: -------------------------------------------------------------------------------- 1 | import { writeFile as writeFileAsync } from "node:fs/promises"; 2 | import SourceMap from "source-map"; 3 | const { SourceMapGenerator } = SourceMap; 4 | const generator = new SourceMapGenerator(); 5 | const { URL } = globalThis; 6 | generator.addMapping({ 7 | source: "source.mjs", 8 | original: { line: 3, column: 0 }, 9 | generated: { line: 1, column: 0 }, 10 | }); 11 | generator.addMapping({ 12 | source: "source.mjs", 13 | original: { line: 6, column: 0 }, 14 | generated: { line: 4, column: 0 }, 15 | }); 16 | await writeFileAsync( 17 | new URL("source.map", import.meta.url), 18 | generator.toString(), 19 | "utf8", 20 | ); 21 | -------------------------------------------------------------------------------- /test/cases/apply-source/script.mjs: -------------------------------------------------------------------------------- 1 | function f() {} 2 | f(); 3 | 4 | function g(_x) {} 5 | g(); 6 | 7 | //# sourceMappingURL=source.map 8 | -------------------------------------------------------------------------------- /test/cases/apply-source/source.mjs: -------------------------------------------------------------------------------- 1 | // Source // 2 | 3 | function f(_x) {} 4 | f(); 5 | 6 | function g() {} 7 | g(); 8 | 9 | @a 10 | class c {} 11 | -------------------------------------------------------------------------------- /test/cases/apply-source/spec.yaml: -------------------------------------------------------------------------------- 1 | commands: 2 | - node generate-source-map.mjs 3 | - node $1 4 | -------------------------------------------------------------------------------- /test/cases/classmap/appmap.yml: -------------------------------------------------------------------------------- 1 | recorder: process 2 | packages: 3 | glob: "*" 4 | enabled: true 5 | command: node main.mjs 6 | appmap_dir: . 7 | appmap_file: main 8 | hooks: 9 | cjs: true 10 | esm: true 11 | eval: false 12 | apply: true 13 | http: false 14 | mysql: false 15 | pg: false 16 | sqlite3: false 17 | validate: 18 | appmap: true 19 | -------------------------------------------------------------------------------- /test/cases/classmap/common.cjs: -------------------------------------------------------------------------------- 1 | /* eslint local/no-globals: ["error", "exports"] */ 2 | exports.common = function common() {}; 3 | -------------------------------------------------------------------------------- /test/cases/classmap/main.mjs: -------------------------------------------------------------------------------- 1 | import { common } from "./common.cjs"; 2 | import { native } from "./native.mjs"; 3 | function main() { 4 | common(); 5 | native(); 6 | } 7 | main(); 8 | -------------------------------------------------------------------------------- /test/cases/classmap/native.mjs: -------------------------------------------------------------------------------- 1 | export function native() {} 2 | -------------------------------------------------------------------------------- /test/cases/classmap/process/main.subset.yaml: -------------------------------------------------------------------------------- 1 | classMap: 2 | - type: package 3 | name: "." 4 | children: 5 | - type: class 6 | name: main 7 | children: 8 | - type: function 9 | name: main 10 | location: ./main.mjs:3 11 | static: false 12 | source: null 13 | comment: null 14 | labels: [] 15 | - type: class 16 | name: native 17 | children: 18 | - type: function 19 | name: native 20 | location: ./native.mjs:1 21 | static: false 22 | source: null 23 | comment: null 24 | labels: [] 25 | - type: class 26 | name: common 27 | children: 28 | - type: function 29 | name: common 30 | location: ./common.cjs:2 31 | static: false 32 | source: null 33 | comment: null 34 | labels: [] 35 | -------------------------------------------------------------------------------- /test/cases/default-parameter/appmap.yml: -------------------------------------------------------------------------------- 1 | recorder: process 2 | packages: 3 | path: main.mjs 4 | enabled: true 5 | command: node main.mjs 6 | appmap_dir: . 7 | appmap_file: main 8 | hooks: 9 | cjs: false 10 | esm: true 11 | eval: false 12 | apply: true 13 | http: false 14 | mysql: false 15 | pg: false 16 | sqlite3: false 17 | validate: 18 | appmap: true 19 | -------------------------------------------------------------------------------- /test/cases/default-parameter/main.mjs: -------------------------------------------------------------------------------- 1 | import { strict as Assert } from "node:assert"; 2 | const { equal: assertEqual } = Assert; 3 | const defaultParameter = (x = 123) => x; 4 | assertEqual(defaultParameter(), 123); 5 | -------------------------------------------------------------------------------- /test/cases/default-parameter/process/main.subset.yaml: -------------------------------------------------------------------------------- 1 | events: 2 | - event: call 3 | id: 1 4 | method_id: defaultParameter 5 | - event: return 6 | id: 2 7 | parent_id: 1 8 | -------------------------------------------------------------------------------- /test/cases/env-var/appmap.yml: -------------------------------------------------------------------------------- 1 | packages: 2 | path: main.mjs 3 | enabled: true 4 | recorder: process 5 | command: FOO=BAR node main.mjs 6 | command-options: 7 | shell: true 8 | appmap_dir: . 9 | appmap_file: main 10 | hooks: 11 | cjs: false 12 | esm: true 13 | eval: false 14 | apply: true 15 | http: false 16 | mysql: false 17 | pg: false 18 | sqlite3: false 19 | validate: 20 | appmap: true 21 | -------------------------------------------------------------------------------- /test/cases/env-var/main.mjs: -------------------------------------------------------------------------------- 1 | import { env } from "node:process"; 2 | import { strict as Assert } from "node:assert"; 3 | const { 4 | undefined, 5 | Reflect: { getOwnPropertyDescriptor }, 6 | } = globalThis; 7 | const { equal: assertEqual, notEqual: assertNotEqual } = Assert; 8 | assertNotEqual(getOwnPropertyDescriptor(env, "FOO"), undefined); 9 | assertEqual(env.FOO, "BAR"); 10 | -------------------------------------------------------------------------------- /test/cases/env-var/main.test.mjs: -------------------------------------------------------------------------------- 1 | import { env } from "node:process"; 2 | import { strict as Assert } from "node:assert"; 3 | import { describe, it } from "mocha"; 4 | import { main } from "./main.mjs"; 5 | const { 6 | undefined, 7 | Reflect: { getOwnPropertyDescriptor }, 8 | } = globalThis; 9 | const { equal: assertEqual, notEqual: assertNotEqual } = Assert; 10 | assertNotEqual(getOwnPropertyDescriptor(env, "FOO"), undefined); 11 | assertEqual(env.FOO, "BAR"); 12 | describe("suite", function () { 13 | it("case", function () { 14 | assertEqual(main(), "MAIN"); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/cases/env-var/process/main.subset.yaml: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /test/cases/env-var/spec.yaml: -------------------------------------------------------------------------------- 1 | os: ^(?!win32$) 2 | -------------------------------------------------------------------------------- /test/cases/eval/appmap.yml: -------------------------------------------------------------------------------- 1 | recorder: process 2 | packages: 3 | path: main.mjs 4 | enabled: true 5 | command: node main.mjs 6 | pruning: false 7 | appmap_dir: . 8 | appmap_file: main 9 | hooks: 10 | cjs: true 11 | esm: true 12 | apply: true 13 | eval: true 14 | http: false 15 | mysql: false 16 | pg: false 17 | sqlite3: false 18 | validate: 19 | appmap: true 20 | -------------------------------------------------------------------------------- /test/cases/eval/main.mjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-eval */ 2 | /* eslint local/no-globals: ["error", "eval"] */ 3 | function f() {} 4 | f(); 5 | const codes = ["function g () {}; g();", "function h () {}; h();"]; 6 | for (const code of codes) { 7 | eval(code); 8 | } 9 | -------------------------------------------------------------------------------- /test/cases/eval/process/main.subset.yaml: -------------------------------------------------------------------------------- 1 | classMap: 2 | - type: package 3 | name: . 4 | children: 5 | - type: class 6 | name: main 7 | children: 8 | - type: function 9 | name: f 10 | location: ./main.mjs:3 11 | - type: package 12 | name: main.mjs 13 | children: 14 | - type: class 15 | name: eval-7-2 16 | children: 17 | - type: function 18 | name: g 19 | location: ./main.mjs/eval-7-2.js#0:1 20 | - type: class 21 | name: eval-7-2 22 | children: 23 | - type: function 24 | name: h 25 | location: ./main.mjs/eval-7-2.js#1:1 26 | events: 27 | - event: call 28 | method_id: f 29 | - event: return 30 | - event: call 31 | method_id: g 32 | - event: return 33 | - event: call 34 | method_id: h 35 | - event: return 36 | -------------------------------------------------------------------------------- /test/cases/generator-method/appmap.yml: -------------------------------------------------------------------------------- 1 | recorder: process 2 | packages: 3 | path: main.mjs 4 | enabled: true 5 | command: node main.mjs 6 | appmap_dir: . 7 | appmap_file: main 8 | hooks: 9 | cjs: false 10 | esm: true 11 | eval: false 12 | apply: true 13 | http: false 14 | mysql: false 15 | pg: false 16 | sqlite3: false 17 | validate: 18 | appmap: true 19 | -------------------------------------------------------------------------------- /test/cases/generator-method/main.mjs: -------------------------------------------------------------------------------- 1 | import { strict as Assert } from "node:assert"; 2 | const { throws: assertThrow, deepEqual: assertDeepEqual } = Assert; 3 | const { Error, undefined } = globalThis; 4 | 5 | function* g() { 6 | yield 1; 7 | yield 2; 8 | yield 3; 9 | } 10 | 11 | { 12 | const i = g(); 13 | assertDeepEqual(i.next(), { value: 1, done: false }); 14 | assertDeepEqual(i.return("result"), { value: "result", done: true }); 15 | assertDeepEqual(i.next(), { value: undefined, done: true }); 16 | } 17 | 18 | { 19 | const i = g(); 20 | assertDeepEqual(i.next(), { value: 1, done: false }); 21 | assertThrow(() => { 22 | i.throw(new Error("message")); 23 | }, /^Error: message$/u); 24 | assertDeepEqual(i.next(), { value: undefined, done: true }); 25 | } 26 | -------------------------------------------------------------------------------- /test/cases/generator-method/process/main.subset.yaml: -------------------------------------------------------------------------------- 1 | events: 2 | - event: call 3 | id: 1 4 | method_id: g 5 | - event: return 6 | id: 2 7 | parent_id: 1 8 | -------------------------------------------------------------------------------- /test/cases/html/appmap.yml: -------------------------------------------------------------------------------- 1 | recorder: process 2 | packages: 3 | - regexp: "^http://localhost:8080/index.html" 4 | relative: false 5 | enabled: true 6 | - url: "http://localhost:8080/index.js" 7 | enabled: true 8 | proxy-port: 8888 9 | ordering: chronological 10 | appmap_dir: . 11 | appmap_file: main 12 | hooks: 13 | cjs: false 14 | esm: false 15 | eval: false 16 | apply: true 17 | http: false 18 | mysql: false 19 | pg: false 20 | sqlite3: false 21 | validate: 22 | appmap: true 23 | -------------------------------------------------------------------------------- /test/cases/html/process/main.subset.yaml: -------------------------------------------------------------------------------- 1 | events: 2 | - event: call 3 | id: 1 4 | method_id: internal 5 | - event: return 6 | id: 2 7 | parent_id: 1 8 | - event: call 9 | id: 3 10 | method_id: external 11 | - event: return 12 | id: 4 13 | parent_id: 3 14 | -------------------------------------------------------------------------------- /test/cases/html/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 8 | 9 |