{"id":13454694,"url":"https://github.com/acrazing/dpdm","last_synced_at":"2025-05-15T01:06:22.987Z","repository":{"id":38419688,"uuid":"196680135","full_name":"acrazing/dpdm","owner":"acrazing","description":"Detect circular dependencies in your TypeScript projects.","archived":false,"fork":false,"pushed_at":"2024-10-09T17:02:34.000Z","size":1096,"stargazers_count":786,"open_issues_count":6,"forks_count":18,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-14T03:43:18.788Z","etag":null,"topics":["circular","command-line","dependency","javascript","madge","typescript","typescript3","visualization"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/acrazing.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-13T04:59:28.000Z","updated_at":"2025-05-13T08:58:37.000Z","dependencies_parsed_at":"2024-12-06T05:00:29.470Z","dependency_job_id":"69f4733d-9898-41a5-9494-355a115ac08a","html_url":"https://github.com/acrazing/dpdm","commit_stats":{"total_commits":51,"total_committers":7,"mean_commits":7.285714285714286,"dds":0.5294117647058824,"last_synced_commit":"6f8e0de5ad60ac3cc6e44d03ac6dd0e95c51576f"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acrazing%2Fdpdm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acrazing%2Fdpdm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acrazing%2Fdpdm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acrazing%2Fdpdm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/acrazing","download_url":"https://codeload.github.com/acrazing/dpdm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254104796,"owners_count":22015546,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["circular","command-line","dependency","javascript","madge","typescript","typescript3","visualization"],"created_at":"2024-07-31T08:00:56.938Z","updated_at":"2025-05-15T01:06:21.275Z","avatar_url":"https://github.com/acrazing.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","command-line","visualization"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n    DPDM\n    \u003cbr/\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/dpdm\" alt=\"version\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/dm/dpdm\" alt=\"downloads\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/stars/acrazing/dpdm\" alt=\"stars\"\u003e\n    \u003cimg src=\"https://img.shields.io/librariesio/github/acrazing/dpdm\" alt=\"dependencies\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/license/acrazing/dpdm\" alt=\"license\"\u003e\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003eA robust static dependency analyzer for your \u003ccode\u003eJavaScript\u003c/code\u003e and \u003ccode\u003eTypeScript\u003c/code\u003e projects.\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"#highlights\"\u003eHighlights\u003c/a\u003e\n    \u003cspan\u003e\u0026nbsp;|\u0026nbsp;\u003c/span\u003e\n    \u003ca href=\"#install\"\u003eInstall\u003c/a\u003e\n    \u003cspan\u003e\u0026nbsp;|\u0026nbsp;\u003c/span\u003e\n    \u003ca href=\"#usage-in-command-line\"\u003eUsage\u003c/a\u003e\n    \u003cspan\u003e\u0026nbsp;|\u0026nbsp;\u003c/span\u003e\n    \u003ca href=\"#options\"\u003eOptions\u003c/a\u003e\n    \u003cspan\u003e\u0026nbsp;|\u0026nbsp;\u003c/span\u003e\n    \u003ca href=\"#usage-as-a-package\"\u003eAPI\u003c/a\u003e\n\u003c/p\u003e\n\n## Highlights\n\n- Supports `CommonJS`, `ESM`.\n- Supports `JavaScript` and `TypeScript` completely.\n  - Supports TypeScript [path mapping](https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping).\n  - Supports ignore TypeScript type dependencies.\n- Light weight: use [TypeScript](https://npmjs.com/package/typescript) to parse all modules.\n- Fast: use asynchronous API to load modules.\n- Stable output: This is compared to `madge`, whose results are completely inconclusive when analyze `TypeScript`.\n\n## Install\n\n1. For command line\n\n   ```bash\n   npm i -g dpdm\n   # or via yarn\n   yarn global add dpdm\n   ```\n\n2. As a module\n\n   ```bash\n   npm i -D dpdm\n   # or via yarn\n   yarn add -D dpdm\n   ```\n\n## Usage in command line\n\n1. Simple usage\n\n   ```bash\n   dpdm ./src/index.ts\n   ```\n\n2. Print circular dependencies only\n\n   ```bash\n   dpdm --no-warning --no-tree ./src/index.ts\n   ```\n\n3. Exit with a non-zero code if a circular dependency is found.\n\n   ```bash\n   dpdm --exit-code circular:1 ./src/index.ts\n   ```\n\n4. Ignore type dependencies for TypeScript modules\n\n   ```bash\n   dpdm -T ./src/index.ts\n   ```\n\n5. Find unused files by `index.js` in `src` directory:\n\n   ```bash\n   dpdm --no-tree --no-warning --no-circular --detect-unused-files-from 'src/**/*.*' 'index.js'\n   ```\n\n6. Skip dynamic imports:\n\n   ```bash\n   # The value circular will only ignore the dynamic imports\n   # when parse circular references.\n   # You can set it as tree to ignore the dynamic imports\n   # when parse source files.\n   dpdm --skip-dynamic-imports circular index.js\n   ```\n\n### Options\n\n```bash\ndpdm [options] \u003cfiles...\u003e\n\nAnalyze the files' dependencies.\n\nPositionals:\n  files  The file paths or globs                                                            [string]\n\nOptions:\n      --version                   Show version number                                      [boolean]\n      --context                   the context directory to shorten path, default is current\n                                  directory                                                 [string]\n      --extensions, --ext         comma separated extensions to resolve\n                                                  [string] [default: \".ts,.tsx,.mjs,.js,.jsx,.json\"]\n      --js                        comma separated extensions indicate the file is js like\n                                                        [string] [default: \".ts,.tsx,.mjs,.js,.jsx\"]\n      --include                   included filenames regexp in string, default includes all files\n                                                                            [string] [default: \".*\"]\n      --exclude                   excluded filenames regexp in string, set as empty string to\n                                  include all files               [string] [default: \"node_modules\"]\n  -o, --output                    output json to file                                       [string]\n      --tree                      print tree to stdout                     [boolean] [default: true]\n      --circular                  print circular to stdout                 [boolean] [default: true]\n      --warning                   print warning to stdout                  [boolean] [default: true]\n      --tsconfig                  the tsconfig path, which is used for resolve path alias, default\n                                  is tsconfig.json if it exists in context directory        [string]\n  -T, --transform                 transform typescript modules to javascript before analyze, it\n                                  allows you to omit types dependency in typescript\n                                                                          [boolean] [default: false]\n      --exit-code                 exit with specified code, the value format is CASE:CODE,\n                                  `circular` is the only supported CASE, CODE should be a integer\n                                  between 0 and 128. For example: `dpdm --exit-code circular:1` the\n                                  program will exit with code 1 if circular dependency found.\n                                                                                            [string]\n      --progress                  show progress bar                        [boolean] [default: true]\n      --detect-unused-files-from  this file is a glob, used for finding unused files.       [string]\n      --skip-dynamic-imports      Skip parse import(...) statement.\n                                                              [string] [choices: \"tree\", \"circular\"]\n  -h, --help                      Show help                                                [boolean]\n```\n\n### Example output\n\n![Screenshot](./assets/screenshot.png)\n\n## Usage as a package\n\n```typescript jsx\nimport { parseDependencyTree, parseCircular, prettyCircular } from 'dpdm';\n\nparseDependencyTree('./index', {\n  /* options, see below */\n}).then((tree) =\u003e {\n  const circulars = parseCircular(tree);\n  console.log(prettyCircular(circulars));\n});\n```\n\n### API Reference\n\n1. `parseDependencyTree(entries, option, output)`: parse dependencies for glob entries\n\n   ```typescript jsx\n   /**\n    * @param entries - the glob entries to match\n    * @param options - the options, see below\n    */\n   export declare function parseDependencyTree(\n     entries: string | string[],\n     options: ParserOptions,\n   ): Promise\u003cDependencyTree\u003e;\n\n   /**\n    * the parse options\n    */\n   export interface ParseOptions {\n      context: string;\n      extensions: string[];\n      js: string[];\n      include: RegExp;\n      exclude: RegExp;\n      tsconfig: string | undefined;\n      onProgress: (event: 'start' | 'end', target: string) =\u003e void;\n      transform: boolean;\n      skipDynamicImports: boolean;\n   }\n\n   export enum DependencyKind {\n     CommonJS = 'CommonJS', // require\n     StaticImport = 'StaticImport', // import ... from \"foo\"\n     DynamicImport = 'DynamicImport', // import(\"foo\")\n     StaticExport = 'StaticExport', // export ... from \"foo\"\n   }\n\n   export interface Dependency {\n     issuer: string;\n     request: string;\n     kind: DependencyKind;\n     id: string | null; // the shortened, resolved filename, if cannot resolve, it will be null\n   }\n\n   // the parse tree result, key is file id, value is its dependencies\n   // if file is ignored, it will be null\n   export type DependencyTree = Record\u003cstring, Dependency[] | null\u003e;\n   ```\n\n2. `parseCircular(tree)`: parse circulars in dependency tree\n\n   ```typescript jsx\n   export declare function parseCircular(tree: DependencyTree): string[][];\n   ```\n\n## TODOs\n\n- [ ] Supports HTML and HTML like modules\n- [ ] Supports CSS and CSS like modules\n- [ ] Prints interactive SVG\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facrazing%2Fdpdm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Facrazing%2Fdpdm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facrazing%2Fdpdm/lists"}