{"id":10737,"library":"detective-amd","title":"AMD Module Dependency Detective","description":"detective-amd is a JavaScript utility for statically analyzing JavaScript files or Abstract Syntax Trees (ASTs) to identify dependencies declared using various AMD (Asynchronous Module Definition) module syntaxes. It supports the four core AMD forms ('named', 'dependency list', 'factory', 'no dependencies'), as well as 'driver script' (`require([deps], func)`) and CommonJS-like 'REM' forms (`define(function(require, exports, module) {})`). The package also handles dynamically loaded dependencies and JSX code through `node-source-walk`. The current stable version is 6.0.1. While not on a fixed release schedule, it sees updates to maintain compatibility with modern Node.js versions and dependencies, with major versions primarily driven by Node.js LTS support drops. Its key differentiator is its specialized focus on AMD syntax, offering a robust solution for environments still leveraging RequireJS or similar AMD loaders, distinguishing it from general-purpose CommonJS or ESM dependency analysis tools.","status":"active","version":"6.0.1","language":"javascript","source_language":"en","source_url":"https://github.com/dependents/node-detective-amd","tags":["javascript","amd","detective","dependencies","ast","static analysis","requirejs","jsx","module"],"install":[{"cmd":"npm install detective-amd","lang":"bash","label":"npm"},{"cmd":"yarn add detective-amd","lang":"bash","label":"yarn"},{"cmd":"pnpm add detective-amd","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Used for parsing and walking the AST, providing support for JSX syntax.","package":"node-source-walk","optional":false}],"imports":[{"note":"This package is primarily CommonJS. While Node.js >=18 is required, its primary export mechanism is `module.exports`.","wrong":"import detective from 'detective-amd';","symbol":"detective","correct":"const detective = require('detective-amd');"},{"note":"The package exports a single function as its default. Named imports are not available.","wrong":"import { detective } from 'detective-amd';","symbol":"detective (named import attempt)","correct":"const detective = require('detective-amd');"},{"note":"If used in an ESM context, dynamic `import()` is required to load this CommonJS module, and you'll then access `detective.default`.","wrong":"import detective from 'detective-amd';","symbol":"detective (ESM dynamic import)","correct":"const detective = await import('detective-amd');"}],"quickstart":{"code":"const fs = require('fs');\nconst detective = require('detective-amd');\n\n// Create a dummy AMD file for demonstration\nconst fileContent = `\n// a.js\ndefine(['./b', './c'], function (b, c) {\n  console.log(b, c);\n});\n\n// b.js\ndefine({\n  name: 'foo'\n});\n\n// c.js\ndefine(function () {\n  return 'bar';\n});\n\n// main.js - A driver script\nrequire(['./a'], function (a) {\n  // My app will get booted up from here\n});\n\n// another.js - with expression-based require\ndefine(function (require) {\n  const dynamicDep = 'dynamic_module';\n  const x = require('./' + dynamicDep);\n  const y = require('./static_module');\n});\n`;\n\nfs.writeFileSync('example.js', fileContent, 'utf8');\n\n// Analyze the 'a.js' part of the content\nconst srcA = `define(['./b', './c'], function (b, c) { console.log(b, c); });`;\nconsole.log('Dependencies for a.js:', detective(srcA));\n\n// Analyze the 'main.js' part of the content\nconst srcMain = `require(['./a'], function (a) {});`;\nconsole.log('Dependencies for main.js (driver script):', detective(srcMain));\n\n// Analyze the 'another.js' part with expression-based requires\nconst srcAnother = `\ndefine(function (require) {\n  const dynamicDep = 'dynamic_module';\n  const x = require('./' + dynamicDep);\n  const y = require('./static_module');\n});\n`;\nconsole.log('Dependencies for another.js (expression-based):', detective(srcAnother));\n\n// Clean up dummy file (optional)\nfs.unlinkSync('example.js');","lang":"javascript","description":"Demonstrates how to synchronously extract AMD dependencies from source code, including standard `define` calls, `require` driver scripts, and expression-based requires."},"warnings":[{"fix":"Upgrade your Node.js environment to version 18 or higher. If unable to upgrade Node.js, remain on `detective-amd@5.x`.","message":"Version 6.0.0 introduced a breaking change by dropping support for Node.js versions older than 18. Users on older Node.js runtimes will encounter errors or unexpected behavior.","severity":"breaking","affected_versions":">=6.0.0"},{"fix":"Upgrade your Node.js environment to version 14 or higher (or 18+ for v6+). If unable to upgrade Node.js, remain on `detective-amd@4.x`.","message":"Version 5.0.0 dropped support for Node.js 12. Environments running Node.js 12 or earlier will not be able to use this version.","severity":"breaking","affected_versions":">=5.0.0 <6.0.0"},{"fix":"Be aware that dynamically resolved paths cannot be fully analyzed statically. Manual inspection or runtime analysis might be needed for these cases.","message":"When an AMD `require` call uses an expression instead of a string literal (e.g., `require('./' + variable)`), `detective-amd` will return a string representation of that expression (e.g., `\"'./' + variable\"`) rather than attempting to resolve it. This means dynamic dependencies will not yield concrete file paths.","severity":"gotcha","affected_versions":">=3.x"},{"fix":"In an ESM context, use a dynamic import: `const detectiveModule = await import('detective-amd'); const detective = detectiveModule.default;`","message":"The package is primarily designed for CommonJS consumption. Attempting to use `import detective from 'detective-amd';` in an ES module context will result in a runtime error because `module.exports` is not directly compatible with default ES module imports.","severity":"gotcha","affected_versions":">=3.x"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"This package is CommonJS. If you are in an ES module context (e.g., `\"type\": \"module\"` in package.json), you must use dynamic `import()` to load it: `const detectiveModule = await import('detective-amd'); const detective = detectiveModule.default;`","cause":"Attempting to `require()` this package from an ES module context, or the package itself has become ESM-only (which it has not, but this is a common problem in the ecosystem).","error":"Error [ERR_REQUIRE_ESM]: require() of ES Module ... not supported."},{"fix":"Ensure the source code being passed to `detective-amd` exclusively uses AMD or older JavaScript syntax. If you need to detect ES module dependencies, use a different package designed for ESM analysis.","cause":"You are using `detective-amd` in a CJS file, but the source code you are passing to it contains ES module syntax (e.g., `import` or `export` statements). While `detective-amd` supports JSX, it is specifically for AMD syntax analysis, not ESM.","error":"SyntaxError: Unexpected token 'export' (or 'import')"},{"fix":"When using `await import('detective-amd')` in ESM, the main function is accessed via the `.default` property: `const detectiveModule = await import('detective-amd'); const detective = detectiveModule.default;`","cause":"This typically occurs when `detective-amd` is imported incorrectly in an ESM context, where `import detective from 'detective-amd';` results in `detective` being the entire module object, not the function itself.","error":"TypeError: detective is not a function"}],"ecosystem":"npm"}