foresthouse 1.0.0-dev.2 → 1.0.0-dev.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,6 +19,7 @@
19
19
  - Resolves local imports, re-exports, `require()`, and string-literal dynamic `import()`
20
20
  - Honors the nearest `tsconfig.json` or `jsconfig.json`, including `baseUrl` and `paths`
21
21
  - Prints a tree by default, or JSON with `--json`
22
+ - Colorizes ASCII output automatically when the terminal supports ANSI colors
22
23
 
23
24
  ## Usage
24
25
 
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as graphToSerializableReactTree, n as printReactUsageTree, o as analyzeDependencies, r as analyzeReactUsage, s as graphToSerializableTree, t as printDependencyTree } from "./tree-Cp8CNmeY.mjs";
2
+ import { a as graphToSerializableReactTree, n as printReactUsageTree, o as analyzeDependencies, r as analyzeReactUsage, s as graphToSerializableTree, t as printDependencyTree } from "./tree-B5Q_Mgkq.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import process from "node:process";
5
5
  //#region src/cli.ts
@@ -27,12 +27,13 @@ function main() {
27
27
  ...options.configPath === void 0 ? {} : { configPath: options.configPath }
28
28
  });
29
29
  if (options.json) {
30
- process.stdout.write(`${JSON.stringify(graphToSerializableTree(graph), null, 2)}\n`);
30
+ process.stdout.write(`${JSON.stringify(graphToSerializableTree(graph, { omitUnused: options.omitUnused }), null, 2)}\n`);
31
31
  return;
32
32
  }
33
33
  process.stdout.write(`${printDependencyTree(graph, {
34
34
  cwd: options.cwd ?? graph.cwd,
35
- includeExternals: options.includeExternals
35
+ includeExternals: options.includeExternals,
36
+ omitUnused: options.omitUnused
36
37
  })}\n`);
37
38
  } catch (error) {
38
39
  const message = error instanceof Error ? error.message : "Unknown error occurred.";
@@ -53,6 +54,7 @@ function parseArgs(argv) {
53
54
  let cwd;
54
55
  let configPath;
55
56
  let includeExternals = false;
57
+ let omitUnused = false;
56
58
  let json = false;
57
59
  let react;
58
60
  for (let index = 0; index < argv.length; index += 1) {
@@ -72,6 +74,10 @@ function parseArgs(argv) {
72
74
  includeExternals = true;
73
75
  continue;
74
76
  }
77
+ if (argument === "--no-unused") {
78
+ omitUnused = true;
79
+ continue;
80
+ }
75
81
  if (argument === "--json") {
76
82
  json = true;
77
83
  continue;
@@ -98,6 +104,7 @@ function parseArgs(argv) {
98
104
  cwd,
99
105
  configPath,
100
106
  includeExternals,
107
+ omitUnused,
101
108
  json,
102
109
  react
103
110
  };
@@ -117,6 +124,7 @@ Options:
117
124
  --cwd <path> Working directory used for relative paths.
118
125
  --config <path> Explicit tsconfig.json or jsconfig.json path.
119
126
  --include-externals Include packages and Node built-ins in the tree.
127
+ --no-unused Omit imports that are never referenced.
120
128
  --react[=component|hook] Print a React usage tree instead of the import tree.
121
129
  --json Print the dependency tree as JSON.
122
130
  -v, --version Show the current version.
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { createRequire } from 'node:module'\nimport process from 'node:process'\n\nimport { analyzeDependencies, graphToSerializableTree } from './analyzer.js'\nimport {\n analyzeReactUsage,\n graphToSerializableReactTree,\n} from './react-analyzer.js'\nimport { printReactUsageTree } from './react-tree.js'\nimport { printDependencyTree } from './tree.js'\nimport type { ReactUsageFilter } from './types.js'\n\nconst require = createRequire(import.meta.url)\nconst { version } = require('../package.json') as { version: string }\n\ninterface CliOptions {\n readonly entryFile: string\n readonly cwd: string | undefined\n readonly configPath: string | undefined\n readonly includeExternals: boolean\n readonly json: boolean\n readonly react: ReactUsageFilter | undefined\n}\n\nfunction main(): void {\n try {\n const options = parseArgs(process.argv.slice(2))\n\n if (options.react !== undefined) {\n const graph = analyzeReactUsage(options.entryFile, {\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n ...(options.configPath === undefined\n ? {}\n : { configPath: options.configPath }),\n })\n\n if (options.json) {\n process.stdout.write(\n `${JSON.stringify(\n graphToSerializableReactTree(graph, {\n filter: options.react,\n }),\n null,\n 2,\n )}\\n`,\n )\n return\n }\n\n process.stdout.write(\n `${printReactUsageTree(graph, {\n cwd: options.cwd ?? graph.cwd,\n filter: options.react,\n })}\\n`,\n )\n return\n }\n\n const graph = analyzeDependencies(options.entryFile, {\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n ...(options.configPath === undefined\n ? {}\n : { configPath: options.configPath }),\n })\n\n if (options.json) {\n process.stdout.write(\n `${JSON.stringify(graphToSerializableTree(graph), null, 2)}\\n`,\n )\n return\n }\n\n process.stdout.write(\n `${printDependencyTree(graph, {\n cwd: options.cwd ?? graph.cwd,\n includeExternals: options.includeExternals,\n })}\\n`,\n )\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error occurred.'\n process.stderr.write(`foresthouse: ${message}\\n`)\n process.exitCode = 1\n }\n}\n\nfunction parseArgs(argv: string[]): CliOptions {\n if (argv.includes('--version') || argv.includes('-v')) {\n process.stdout.write(`${version}\\n`)\n process.exit(0)\n }\n\n if (argv.length === 0 || argv.includes('--help') || argv.includes('-h')) {\n printHelp()\n process.exit(0)\n }\n\n let entryFile: string | undefined\n let cwd: string | undefined\n let configPath: string | undefined\n let includeExternals = false\n let json = false\n let react: ReactUsageFilter | undefined\n\n for (let index = 0; index < argv.length; index += 1) {\n const argument = argv[index]\n if (argument === undefined) {\n continue\n }\n\n if (argument === '--cwd') {\n cwd = readOptionValue(argv, index, '--cwd')\n index += 1\n continue\n }\n\n if (argument === '--config') {\n configPath = readOptionValue(argv, index, '--config')\n index += 1\n continue\n }\n\n if (argument === '--include-externals') {\n includeExternals = true\n continue\n }\n\n if (argument === '--json') {\n json = true\n continue\n }\n\n if (argument === '--react') {\n react = 'all'\n continue\n }\n\n if (argument.startsWith('--react=')) {\n const value = argument.slice('--react='.length)\n if (value === 'component' || value === 'hook') {\n react = value\n continue\n }\n\n throw new Error(`Unknown React mode: ${value}`)\n }\n\n if (argument.startsWith('-')) {\n throw new Error(`Unknown option: ${argument}`)\n }\n\n if (entryFile !== undefined) {\n throw new Error('Only one entry file can be provided.')\n }\n\n entryFile = argument\n }\n\n if (entryFile === undefined) {\n throw new Error('An entry file is required.')\n }\n\n return {\n entryFile,\n cwd,\n configPath,\n includeExternals,\n json,\n react,\n }\n}\n\nfunction readOptionValue(\n argv: string[],\n index: number,\n optionName: string,\n): string {\n const value = argv[index + 1]\n if (value === undefined || value.startsWith('-')) {\n throw new Error(`Missing value for ${optionName}`)\n }\n\n return value\n}\n\nfunction printHelp(): void {\n process.stdout.write(`foresthouse v${version}\n\nUsage:\n foresthouse <entry-file> [options]\n\nOptions:\n --cwd <path> Working directory used for relative paths.\n --config <path> Explicit tsconfig.json or jsconfig.json path.\n --include-externals Include packages and Node built-ins in the tree.\n --react[=component|hook] Print a React usage tree instead of the import tree.\n --json Print the dependency tree as JSON.\n -v, --version Show the current version.\n -h, --help Show this help message.\n`)\n}\n\nmain()\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { createRequire } from 'node:module'\nimport process from 'node:process'\n\nimport { analyzeDependencies, graphToSerializableTree } from './analyzer.js'\nimport {\n analyzeReactUsage,\n graphToSerializableReactTree,\n} from './react-analyzer.js'\nimport { printReactUsageTree } from './react-tree.js'\nimport { printDependencyTree } from './tree.js'\nimport type { ReactUsageFilter } from './types.js'\n\nconst require = createRequire(import.meta.url)\nconst { version } = require('../package.json') as { version: string }\n\ninterface CliOptions {\n readonly entryFile: string\n readonly cwd: string | undefined\n readonly configPath: string | undefined\n readonly includeExternals: boolean\n readonly omitUnused: boolean\n readonly json: boolean\n readonly react: ReactUsageFilter | undefined\n}\n\nfunction main(): void {\n try {\n const options = parseArgs(process.argv.slice(2))\n\n if (options.react !== undefined) {\n const graph = analyzeReactUsage(options.entryFile, {\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n ...(options.configPath === undefined\n ? {}\n : { configPath: options.configPath }),\n })\n\n if (options.json) {\n process.stdout.write(\n `${JSON.stringify(\n graphToSerializableReactTree(graph, {\n filter: options.react,\n }),\n null,\n 2,\n )}\\n`,\n )\n return\n }\n\n process.stdout.write(\n `${printReactUsageTree(graph, {\n cwd: options.cwd ?? graph.cwd,\n filter: options.react,\n })}\\n`,\n )\n return\n }\n\n const graph = analyzeDependencies(options.entryFile, {\n ...(options.cwd === undefined ? {} : { cwd: options.cwd }),\n ...(options.configPath === undefined\n ? {}\n : { configPath: options.configPath }),\n })\n\n if (options.json) {\n process.stdout.write(\n `${JSON.stringify(\n graphToSerializableTree(graph, {\n omitUnused: options.omitUnused,\n }),\n null,\n 2,\n )}\\n`,\n )\n return\n }\n\n process.stdout.write(\n `${printDependencyTree(graph, {\n cwd: options.cwd ?? graph.cwd,\n includeExternals: options.includeExternals,\n omitUnused: options.omitUnused,\n })}\\n`,\n )\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error occurred.'\n process.stderr.write(`foresthouse: ${message}\\n`)\n process.exitCode = 1\n }\n}\n\nfunction parseArgs(argv: string[]): CliOptions {\n if (argv.includes('--version') || argv.includes('-v')) {\n process.stdout.write(`${version}\\n`)\n process.exit(0)\n }\n\n if (argv.length === 0 || argv.includes('--help') || argv.includes('-h')) {\n printHelp()\n process.exit(0)\n }\n\n let entryFile: string | undefined\n let cwd: string | undefined\n let configPath: string | undefined\n let includeExternals = false\n let omitUnused = false\n let json = false\n let react: ReactUsageFilter | undefined\n\n for (let index = 0; index < argv.length; index += 1) {\n const argument = argv[index]\n if (argument === undefined) {\n continue\n }\n\n if (argument === '--cwd') {\n cwd = readOptionValue(argv, index, '--cwd')\n index += 1\n continue\n }\n\n if (argument === '--config') {\n configPath = readOptionValue(argv, index, '--config')\n index += 1\n continue\n }\n\n if (argument === '--include-externals') {\n includeExternals = true\n continue\n }\n\n if (argument === '--no-unused') {\n omitUnused = true\n continue\n }\n\n if (argument === '--json') {\n json = true\n continue\n }\n\n if (argument === '--react') {\n react = 'all'\n continue\n }\n\n if (argument.startsWith('--react=')) {\n const value = argument.slice('--react='.length)\n if (value === 'component' || value === 'hook') {\n react = value\n continue\n }\n\n throw new Error(`Unknown React mode: ${value}`)\n }\n\n if (argument.startsWith('-')) {\n throw new Error(`Unknown option: ${argument}`)\n }\n\n if (entryFile !== undefined) {\n throw new Error('Only one entry file can be provided.')\n }\n\n entryFile = argument\n }\n\n if (entryFile === undefined) {\n throw new Error('An entry file is required.')\n }\n\n return {\n entryFile,\n cwd,\n configPath,\n includeExternals,\n omitUnused,\n json,\n react,\n }\n}\n\nfunction readOptionValue(\n argv: string[],\n index: number,\n optionName: string,\n): string {\n const value = argv[index + 1]\n if (value === undefined || value.startsWith('-')) {\n throw new Error(`Missing value for ${optionName}`)\n }\n\n return value\n}\n\nfunction printHelp(): void {\n process.stdout.write(`foresthouse v${version}\n\nUsage:\n foresthouse <entry-file> [options]\n\nOptions:\n --cwd <path> Working directory used for relative paths.\n --config <path> Explicit tsconfig.json or jsconfig.json path.\n --include-externals Include packages and Node built-ins in the tree.\n --no-unused Omit imports that are never referenced.\n --react[=component|hook] Print a React usage tree instead of the import tree.\n --json Print the dependency tree as JSON.\n -v, --version Show the current version.\n -h, --help Show this help message.\n`)\n}\n\nmain()\n"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -5,6 +5,7 @@ interface DependencyEdge {
5
5
  readonly specifier: string;
6
6
  readonly referenceKind: ReferenceKind;
7
7
  readonly isTypeOnly: boolean;
8
+ readonly unused: boolean;
8
9
  readonly kind: DependencyKind;
9
10
  readonly target: string;
10
11
  }
@@ -25,8 +26,11 @@ interface AnalyzeOptions {
25
26
  interface PrintTreeOptions {
26
27
  readonly cwd?: string;
27
28
  readonly includeExternals?: boolean;
29
+ readonly omitUnused?: boolean;
30
+ readonly color?: ColorMode;
28
31
  }
29
32
  type ReactSymbolKind = 'component' | 'hook';
33
+ type ColorMode = boolean | 'auto';
30
34
  type ReactUsageFilter = 'all' | ReactSymbolKind;
31
35
  type ReactUsageEdgeKind = 'render' | 'hook-call';
32
36
  interface ReactUsageEdge {
@@ -49,11 +53,14 @@ interface ReactUsageGraph {
49
53
  interface PrintReactTreeOptions {
50
54
  readonly cwd?: string;
51
55
  readonly filter?: ReactUsageFilter;
56
+ readonly color?: ColorMode;
52
57
  }
53
58
  //#endregion
54
59
  //#region src/analyzer.d.ts
55
60
  declare function analyzeDependencies(entryFile: string, options?: AnalyzeOptions): DependencyGraph;
56
- declare function graphToSerializableTree(graph: DependencyGraph): object;
61
+ declare function graphToSerializableTree(graph: DependencyGraph, options?: {
62
+ readonly omitUnused?: boolean;
63
+ }): object;
57
64
  //#endregion
58
65
  //#region src/react-analyzer.d.ts
59
66
  declare function analyzeReactUsage(entryFile: string, options?: AnalyzeOptions): ReactUsageGraph;
@@ -68,5 +75,5 @@ declare function printReactUsageTree(graph: ReactUsageGraph, options?: PrintReac
68
75
  //#region src/tree.d.ts
69
76
  declare function printDependencyTree(graph: DependencyGraph, options?: PrintTreeOptions): string;
70
77
  //#endregion
71
- export { type AnalyzeOptions, type DependencyEdge, type DependencyGraph, type DependencyKind, type PrintReactTreeOptions, type PrintTreeOptions, type ReactSymbolKind, type ReactUsageEdge, type ReactUsageEdgeKind, type ReactUsageFilter, type ReactUsageGraph, type ReactUsageNode, type ReferenceKind, type SourceModuleNode, analyzeDependencies, analyzeReactUsage, getReactUsageRoots, graphToSerializableReactTree, graphToSerializableTree, printDependencyTree, printReactUsageTree };
78
+ export { type AnalyzeOptions, type ColorMode, type DependencyEdge, type DependencyGraph, type DependencyKind, type PrintReactTreeOptions, type PrintTreeOptions, type ReactSymbolKind, type ReactUsageEdge, type ReactUsageEdgeKind, type ReactUsageFilter, type ReactUsageGraph, type ReactUsageNode, type ReferenceKind, type SourceModuleNode, analyzeDependencies, analyzeReactUsage, getReactUsageRoots, graphToSerializableReactTree, graphToSerializableTree, printDependencyTree, printReactUsageTree };
72
79
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/analyzer.ts","../src/react-analyzer.ts","../src/react-tree.ts","../src/tree.ts"],"mappings":";KAAY,cAAA;AAAA,KAEA,aAAA;AAAA,UAOK,cAAA;EAAA,SACN,SAAA;EAAA,SACA,aAAA,EAAe,aAAA;EAAA,SACf,UAAA;EAAA,SACA,IAAA,EAAM,cAAA;EAAA,SACN,MAAA;AAAA;AAAA,UAGM,gBAAA;EAAA,SACN,EAAA;EAAA,SACA,YAAA,WAAuB,cAAA;AAAA;AAAA,UAGjB,eAAA;EAAA,SACN,GAAA;EAAA,SACA,OAAA;EAAA,SACA,KAAA,EAAO,WAAA,SAAoB,gBAAA;EAAA,SAC3B,UAAA;AAAA;AAAA,UAGM,cAAA;EAAA,SACN,GAAA;EAAA,SACA,UAAA;AAAA;AAAA,UAGM,gBAAA;EAAA,SACN,GAAA;EAAA,SACA,gBAAA;AAAA;AAAA,KAGC,eAAA;AAAA,KAEA,gBAAA,WAA2B,eAAA;AAAA,KAE3B,kBAAA;AAAA,UAEK,cAAA;EAAA,SACN,IAAA,EAAM,kBAAA;EAAA,SACN,MAAA;AAAA;AAAA,UAGM,cAAA;EAAA,SACN,EAAA;EAAA,SACA,IAAA;EAAA,SACA,IAAA,EAAM,eAAA;EAAA,SACN,QAAA;EAAA,SACA,WAAA;EAAA,SACA,MAAA,WAAiB,cAAA;AAAA;AAAA,UAGX,eAAA;EAAA,SACN,GAAA;EAAA,SACA,OAAA;EAAA,SACA,KAAA,EAAO,WAAA,SAAoB,cAAA;AAAA;AAAA,UAGrB,qBAAA;EAAA,SACN,GAAA;EAAA,SACA,MAAA,GAAS,gBAAA;AAAA;;;iBCrCJ,mBAAA,CACd,SAAA,UACA,OAAA,GAAS,cAAA,GACR,eAAA;AAAA,iBA4Ba,uBAAA,CAAwB,KAAA,EAAO,eAAA;;;iBCoB/B,iBAAA,CACd,SAAA,UACA,OAAA,GAAS,cAAA,GACR,eAAA;AAAA,iBAyHa,4BAAA,CACd,KAAA,EAAO,eAAA,EACP,OAAA;EAAA,SACW,MAAA,GAAS,gBAAA;AAAA;AAAA,iBAkBN,kBAAA,CACd,KAAA,EAAO,eAAA,EACP,MAAA,GAAQ,gBAAA;;;iBC3NM,mBAAA,CACd,KAAA,EAAO,eAAA,EACP,OAAA,GAAS,qBAAA;;;iBCJK,mBAAA,CACd,KAAA,EAAO,eAAA,EACP,OAAA,GAAS,gBAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/analyzer.ts","../src/react-analyzer.ts","../src/react-tree.ts","../src/tree.ts"],"mappings":";KAAY,cAAA;AAAA,KAEA,aAAA;AAAA,UAOK,cAAA;EAAA,SACN,SAAA;EAAA,SACA,aAAA,EAAe,aAAA;EAAA,SACf,UAAA;EAAA,SACA,MAAA;EAAA,SACA,IAAA,EAAM,cAAA;EAAA,SACN,MAAA;AAAA;AAAA,UAGM,gBAAA;EAAA,SACN,EAAA;EAAA,SACA,YAAA,WAAuB,cAAA;AAAA;AAAA,UAGjB,eAAA;EAAA,SACN,GAAA;EAAA,SACA,OAAA;EAAA,SACA,KAAA,EAAO,WAAA,SAAoB,gBAAA;EAAA,SAC3B,UAAA;AAAA;AAAA,UAGM,cAAA;EAAA,SACN,GAAA;EAAA,SACA,UAAA;AAAA;AAAA,UAGM,gBAAA;EAAA,SACN,GAAA;EAAA,SACA,gBAAA;EAAA,SACA,UAAA;EAAA,SACA,KAAA,GAAQ,SAAA;AAAA;AAAA,KAGP,eAAA;AAAA,KAEA,SAAA;AAAA,KAEA,gBAAA,WAA2B,eAAA;AAAA,KAE3B,kBAAA;AAAA,UAEK,cAAA;EAAA,SACN,IAAA,EAAM,kBAAA;EAAA,SACN,MAAA;AAAA;AAAA,UAGM,cAAA;EAAA,SACN,EAAA;EAAA,SACA,IAAA;EAAA,SACA,IAAA,EAAM,eAAA;EAAA,SACN,QAAA;EAAA,SACA,WAAA;EAAA,SACA,MAAA,WAAiB,cAAA;AAAA;AAAA,UAGX,eAAA;EAAA,SACN,GAAA;EAAA,SACA,OAAA;EAAA,SACA,KAAA,EAAO,WAAA,SAAoB,cAAA;AAAA;AAAA,UAGrB,qBAAA;EAAA,SACN,GAAA;EAAA,SACA,MAAA,GAAS,gBAAA;EAAA,SACT,KAAA,GAAQ,SAAA;AAAA;;;iBC1CH,mBAAA,CACd,SAAA,UACA,OAAA,GAAS,cAAA,GACR,eAAA;AAAA,iBA8Ba,uBAAA,CACd,KAAA,EAAO,eAAA,EACP,OAAA;EAAA,SACW,UAAA;AAAA;;;iBCcG,iBAAA,CACd,SAAA,UACA,OAAA,GAAS,cAAA,GACR,eAAA;AAAA,iBAyHa,4BAAA,CACd,KAAA,EAAO,eAAA,EACP,OAAA;EAAA,SACW,MAAA,GAAS,gBAAA;AAAA;AAAA,iBAkBN,kBAAA,CACd,KAAA,EAAO,eAAA,EACP,MAAA,GAAQ,gBAAA;;;iBC1NM,mBAAA,CACd,KAAA,EAAO,eAAA,EACP,OAAA,GAAS,qBAAA;;;iBCJK,mBAAA,CACd,KAAA,EAAO,eAAA,EACP,OAAA,GAAS,gBAAA"}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as graphToSerializableReactTree, i as getReactUsageRoots, n as printReactUsageTree, o as analyzeDependencies, r as analyzeReactUsage, s as graphToSerializableTree, t as printDependencyTree } from "./tree-Cp8CNmeY.mjs";
1
+ import { a as graphToSerializableReactTree, i as getReactUsageRoots, n as printReactUsageTree, o as analyzeDependencies, r as analyzeReactUsage, s as graphToSerializableTree, t as printDependencyTree } from "./tree-B5Q_Mgkq.mjs";
2
2
  export { analyzeDependencies, analyzeReactUsage, getReactUsageRoots, graphToSerializableReactTree, graphToSerializableTree, printDependencyTree, printReactUsageTree };
@@ -3,6 +3,7 @@ import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import ts from "typescript";
5
5
  import { parseSync, visitorKeys } from "oxc-parser";
6
+ import process$1 from "node:process";
6
7
  //#region src/config.ts
7
8
  function loadCompilerOptions(searchFrom, explicitConfigPath) {
8
9
  const configPath = explicitConfigPath === void 0 ? findNearestConfig(searchFrom) : path.resolve(searchFrom, explicitConfigPath);
@@ -86,7 +87,8 @@ function analyzeDependencies(entryFile, options = {}) {
86
87
  ...ts.sys.realpath === void 0 ? {} : { realpath: ts.sys.realpath }
87
88
  };
88
89
  const nodes = /* @__PURE__ */ new Map();
89
- visitFile(resolvedEntryPath, compilerOptions, host, nodes);
90
+ const program = createProgram(resolvedEntryPath, compilerOptions, cwd);
91
+ visitFile(resolvedEntryPath, compilerOptions, host, program.getTypeChecker(), program, nodes);
90
92
  return {
91
93
  cwd,
92
94
  entryId: resolvedEntryPath,
@@ -94,11 +96,11 @@ function analyzeDependencies(entryFile, options = {}) {
94
96
  ...configPath === void 0 ? {} : { configPath }
95
97
  };
96
98
  }
97
- function graphToSerializableTree(graph) {
99
+ function graphToSerializableTree(graph, options = {}) {
98
100
  const visited = /* @__PURE__ */ new Set();
99
- return serializeNode(graph.entryId, graph, visited);
101
+ return serializeNode(graph.entryId, graph, visited, options.omitUnused ?? false);
100
102
  }
101
- function serializeNode(filePath, graph, visited) {
103
+ function serializeNode(filePath, graph, visited, omitUnused) {
102
104
  const node = graph.nodes.get(filePath);
103
105
  const displayPath = toDisplayPath(filePath, graph.cwd);
104
106
  if (node === void 0) return {
@@ -112,11 +114,12 @@ function serializeNode(filePath, graph, visited) {
112
114
  dependencies: []
113
115
  };
114
116
  visited.add(filePath);
115
- const dependencies = node.dependencies.map((dependency) => {
117
+ const dependencies = node.dependencies.filter((dependency) => !omitUnused || !dependency.unused).map((dependency) => {
116
118
  if (dependency.kind !== "source") return {
117
119
  specifier: dependency.specifier,
118
120
  referenceKind: dependency.referenceKind,
119
121
  isTypeOnly: dependency.isTypeOnly,
122
+ unused: dependency.unused,
120
123
  kind: dependency.kind,
121
124
  target: dependency.kind === "missing" ? dependency.target : toDisplayPath(dependency.target, graph.cwd)
122
125
  };
@@ -124,9 +127,10 @@ function serializeNode(filePath, graph, visited) {
124
127
  specifier: dependency.specifier,
125
128
  referenceKind: dependency.referenceKind,
126
129
  isTypeOnly: dependency.isTypeOnly,
130
+ unused: dependency.unused,
127
131
  kind: dependency.kind,
128
132
  target: toDisplayPath(dependency.target, graph.cwd),
129
- node: serializeNode(dependency.target, graph, new Set(visited))
133
+ node: serializeNode(dependency.target, graph, new Set(visited), omitUnused)
130
134
  };
131
135
  });
132
136
  return {
@@ -135,50 +139,56 @@ function serializeNode(filePath, graph, visited) {
135
139
  dependencies
136
140
  };
137
141
  }
138
- function visitFile(filePath, compilerOptions, host, nodes) {
142
+ function visitFile(filePath, compilerOptions, host, checker, program, nodes) {
139
143
  const normalizedPath = normalizeFilePath(filePath);
140
144
  if (nodes.has(normalizedPath)) return;
141
- const sourceText = fs.readFileSync(normalizedPath, "utf8");
142
- const dependencies = collectModuleReferences(ts.createSourceFile(normalizedPath, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(normalizedPath))).map((reference) => resolveDependency(reference, normalizedPath, compilerOptions, host));
145
+ const dependencies = collectModuleReferences(program.getSourceFile(normalizedPath) ?? createSourceFile(normalizedPath), checker).map((reference) => resolveDependency(reference, normalizedPath, compilerOptions, host));
143
146
  nodes.set(normalizedPath, {
144
147
  id: normalizedPath,
145
148
  dependencies
146
149
  });
147
- for (const dependency of dependencies) if (dependency.kind === "source") visitFile(dependency.target, compilerOptions, host, nodes);
150
+ for (const dependency of dependencies) if (dependency.kind === "source") visitFile(dependency.target, compilerOptions, host, checker, program, nodes);
148
151
  }
149
- function collectModuleReferences(sourceFile) {
150
- const references = [];
151
- const seen = /* @__PURE__ */ new Set();
152
- function addReference(specifier, referenceKind, isTypeOnly) {
152
+ function collectModuleReferences(sourceFile, checker) {
153
+ const references = /* @__PURE__ */ new Map();
154
+ const unusedImports = collectUnusedImports(sourceFile, checker);
155
+ function addReference(specifier, referenceKind, isTypeOnly, unused) {
153
156
  const key = `${referenceKind}:${isTypeOnly ? "type" : "value"}:${specifier}`;
154
- if (seen.has(key)) return;
155
- seen.add(key);
156
- references.push({
157
+ const existing = references.get(key);
158
+ if (existing !== void 0) {
159
+ if (existing.unused && !unused) references.set(key, {
160
+ ...existing,
161
+ unused: false
162
+ });
163
+ return;
164
+ }
165
+ references.set(key, {
157
166
  specifier,
158
167
  referenceKind,
159
- isTypeOnly
168
+ isTypeOnly,
169
+ unused
160
170
  });
161
171
  }
162
172
  function visit(node) {
163
- if (ts.isImportDeclaration(node) && ts.isStringLiteralLike(node.moduleSpecifier)) addReference(node.moduleSpecifier.text, "import", node.importClause?.isTypeOnly ?? false);
164
- else if (ts.isExportDeclaration(node) && node.moduleSpecifier !== void 0 && ts.isStringLiteralLike(node.moduleSpecifier)) addReference(node.moduleSpecifier.text, "export", node.isTypeOnly ?? false);
173
+ if (ts.isImportDeclaration(node) && ts.isStringLiteralLike(node.moduleSpecifier)) addReference(node.moduleSpecifier.text, "import", node.importClause?.isTypeOnly ?? false, unusedImports.get(node) ?? false);
174
+ else if (ts.isExportDeclaration(node) && node.moduleSpecifier !== void 0 && ts.isStringLiteralLike(node.moduleSpecifier)) addReference(node.moduleSpecifier.text, "export", node.isTypeOnly ?? false, false);
165
175
  else if (ts.isImportEqualsDeclaration(node)) {
166
176
  const moduleReference = node.moduleReference;
167
- if (ts.isExternalModuleReference(moduleReference) && moduleReference.expression !== void 0 && ts.isStringLiteralLike(moduleReference.expression)) addReference(moduleReference.expression.text, "import-equals", false);
177
+ if (ts.isExternalModuleReference(moduleReference) && moduleReference.expression !== void 0 && ts.isStringLiteralLike(moduleReference.expression)) addReference(moduleReference.expression.text, "import-equals", false, false);
168
178
  } else if (ts.isCallExpression(node)) {
169
179
  if (node.expression.kind === ts.SyntaxKind.ImportKeyword && node.arguments.length === 1) {
170
180
  const [argument] = node.arguments;
171
- if (argument !== void 0 && ts.isStringLiteralLike(argument)) addReference(argument.text, "dynamic-import", false);
181
+ if (argument !== void 0 && ts.isStringLiteralLike(argument)) addReference(argument.text, "dynamic-import", false, false);
172
182
  }
173
183
  if (ts.isIdentifier(node.expression) && node.expression.text === "require" && node.arguments.length === 1) {
174
184
  const [argument] = node.arguments;
175
- if (argument !== void 0 && ts.isStringLiteralLike(argument)) addReference(argument.text, "require", false);
185
+ if (argument !== void 0 && ts.isStringLiteralLike(argument)) addReference(argument.text, "require", false, false);
176
186
  }
177
187
  }
178
188
  ts.forEachChild(node, visit);
179
189
  }
180
190
  visit(sourceFile);
181
- return references;
191
+ return [...references.values()];
182
192
  }
183
193
  function resolveDependency(reference, containingFile, compilerOptions, host) {
184
194
  const specifier = reference.specifier;
@@ -197,10 +207,92 @@ function createEdge(reference, kind, target) {
197
207
  specifier: reference.specifier,
198
208
  referenceKind: reference.referenceKind,
199
209
  isTypeOnly: reference.isTypeOnly,
210
+ unused: reference.unused,
200
211
  kind,
201
212
  target
202
213
  };
203
214
  }
215
+ function createProgram(entryFile, compilerOptions, cwd) {
216
+ const host = ts.createCompilerHost(compilerOptions, true);
217
+ host.getCurrentDirectory = () => cwd;
218
+ if (ts.sys.realpath !== void 0) host.realpath = ts.sys.realpath;
219
+ return ts.createProgram({
220
+ rootNames: [entryFile],
221
+ options: compilerOptions,
222
+ host
223
+ });
224
+ }
225
+ function createSourceFile(filePath) {
226
+ const sourceText = fs.readFileSync(filePath, "utf8");
227
+ return ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(filePath));
228
+ }
229
+ function collectUnusedImports(sourceFile, checker) {
230
+ const importUsage = /* @__PURE__ */ new Map();
231
+ const symbolToImportDeclaration = /* @__PURE__ */ new Map();
232
+ const importedLocalNames = /* @__PURE__ */ new Set();
233
+ sourceFile.statements.forEach((statement) => {
234
+ if (!ts.isImportDeclaration(statement) || statement.importClause === void 0) return;
235
+ const identifiers = getImportBindingIdentifiers(statement.importClause);
236
+ if (identifiers.length === 0) return;
237
+ importUsage.set(statement, {
238
+ canTrack: false,
239
+ used: false
240
+ });
241
+ identifiers.forEach((identifier) => {
242
+ importedLocalNames.add(identifier.text);
243
+ const symbol = tryGetSymbolAtLocation(checker, identifier);
244
+ if (symbol === void 0) return;
245
+ symbolToImportDeclaration.set(symbol, statement);
246
+ const state = importUsage.get(statement);
247
+ if (state !== void 0) state.canTrack = true;
248
+ });
249
+ });
250
+ function visit(node) {
251
+ if (ts.isImportDeclaration(node)) return;
252
+ if (ts.isIdentifier(node) && importedLocalNames.has(node.text) && isReferenceIdentifier(node)) {
253
+ const symbol = tryGetSymbolAtLocation(checker, node);
254
+ const declaration = symbol === void 0 ? void 0 : symbolToImportDeclaration.get(symbol);
255
+ if (declaration !== void 0) {
256
+ const state = importUsage.get(declaration);
257
+ if (state !== void 0) state.used = true;
258
+ }
259
+ }
260
+ ts.forEachChild(node, visit);
261
+ }
262
+ visit(sourceFile);
263
+ return new Map([...importUsage.entries()].map(([declaration, state]) => [declaration, state.canTrack && !state.used]));
264
+ }
265
+ function getImportBindingIdentifiers(importClause) {
266
+ const identifiers = [];
267
+ if (importClause.name !== void 0) identifiers.push(importClause.name);
268
+ const namedBindings = importClause.namedBindings;
269
+ if (namedBindings === void 0) return identifiers;
270
+ if (ts.isNamespaceImport(namedBindings)) {
271
+ identifiers.push(namedBindings.name);
272
+ return identifiers;
273
+ }
274
+ namedBindings.elements.forEach((element) => {
275
+ identifiers.push(element.name);
276
+ });
277
+ return identifiers;
278
+ }
279
+ function isReferenceIdentifier(node) {
280
+ const parent = node.parent;
281
+ if (ts.isPropertyAccessExpression(parent) && parent.name === node) return false;
282
+ if (ts.isQualifiedName(parent) && parent.right === node) return false;
283
+ if (ts.isPropertyAssignment(parent) && parent.name === node) return false;
284
+ if (ts.isBindingElement(parent) && parent.propertyName === node) return false;
285
+ if (ts.isJsxAttribute(parent) && parent.name === node) return false;
286
+ if (ts.isExportSpecifier(parent)) return parent.propertyName === node || parent.propertyName === void 0;
287
+ return true;
288
+ }
289
+ function tryGetSymbolAtLocation(checker, node) {
290
+ try {
291
+ return checker.getSymbolAtLocation(node);
292
+ } catch {
293
+ return;
294
+ }
295
+ }
204
296
  function getScriptKind(filePath) {
205
297
  switch (path.extname(filePath).toLowerCase()) {
206
298
  case ".js":
@@ -659,9 +751,33 @@ function isComponentName(name) {
659
751
  return /^[A-Z]/.test(name);
660
752
  }
661
753
  //#endregion
754
+ //#region src/color.ts
755
+ const ANSI_RESET = "\x1B[0m";
756
+ const ANSI_COMPONENT = "\x1B[36m";
757
+ const ANSI_HOOK = "\x1B[35m";
758
+ const ANSI_UNUSED = "\x1B[38;5;214m";
759
+ function resolveColorSupport(mode = "auto", options = {}) {
760
+ if (mode === true) return true;
761
+ if (mode === false) return false;
762
+ const forceColor = "forceColor" in options ? options.forceColor : process$1.env.FORCE_COLOR;
763
+ if (forceColor !== void 0) return forceColor !== "0";
764
+ if (("noColor" in options ? options.noColor : process$1.env.NO_COLOR) !== void 0) return false;
765
+ return ("isTTY" in options ? options.isTTY : process$1.stdout.isTTY) === true;
766
+ }
767
+ function colorizeUnusedMarker(text, enabled) {
768
+ if (!enabled) return text;
769
+ return text.replaceAll("(unused)", `${ANSI_UNUSED}(unused)${ANSI_RESET}`);
770
+ }
771
+ function formatReactSymbolLabel(name, kind, enabled) {
772
+ const label = `${name} [${kind}]`;
773
+ if (!enabled) return label;
774
+ return `${kind === "component" ? ANSI_COMPONENT : ANSI_HOOK}${label}${ANSI_RESET}`;
775
+ }
776
+ //#endregion
662
777
  //#region src/react-tree.ts
663
778
  function printReactUsageTree(graph, options = {}) {
664
779
  const cwd = options.cwd ?? graph.cwd;
780
+ const color = resolveColorSupport(options.color);
665
781
  const filter = options.filter ?? "all";
666
782
  const roots = getReactUsageRoots(graph, filter);
667
783
  if (roots.length === 0) return "No React symbols found.";
@@ -669,52 +785,54 @@ function printReactUsageTree(graph, options = {}) {
669
785
  roots.forEach((rootId, index) => {
670
786
  const root = graph.nodes.get(rootId);
671
787
  if (root === void 0) return;
672
- lines.push(formatReactNodeLabel(root, cwd));
788
+ lines.push(formatReactNodeLabel(root, cwd, color));
673
789
  const usages = getFilteredUsages(root, graph, filter);
674
790
  usages.forEach((usage, usageIndex) => {
675
- lines.push(...renderUsage(usage, graph, cwd, filter, new Set([root.id]), "", usageIndex === usages.length - 1));
791
+ lines.push(...renderUsage(usage, graph, cwd, filter, color, new Set([root.id]), "", usageIndex === usages.length - 1));
676
792
  });
677
793
  if (index < roots.length - 1) lines.push("");
678
794
  });
679
795
  return lines.join("\n");
680
796
  }
681
- function renderUsage(usage, graph, cwd, filter, visited, prefix, isLast) {
797
+ function renderUsage(usage, graph, cwd, filter, color, visited, prefix, isLast) {
682
798
  const branch = `${prefix}${isLast ? "└─ " : "├─ "}`;
683
799
  const target = graph.nodes.get(usage.target);
684
800
  if (target === void 0) return [`${branch}${usage.target}`];
685
- if (visited.has(target.id)) return [`${branch}${formatReactNodeLabel(target, cwd)} (circular)`];
686
- const childLines = [`${branch}${formatReactNodeLabel(target, cwd)}`];
801
+ if (visited.has(target.id)) return [`${branch}${formatReactNodeLabel(target, cwd, color)} (circular)`];
802
+ const childLines = [`${branch}${formatReactNodeLabel(target, cwd, color)}`];
687
803
  const nextVisited = new Set(visited);
688
804
  nextVisited.add(target.id);
689
805
  const nextPrefix = `${prefix}${isLast ? " " : "│ "}`;
690
806
  const childUsages = getFilteredUsages(target, graph, filter);
691
807
  childUsages.forEach((childUsage, index) => {
692
- childLines.push(...renderUsage(childUsage, graph, cwd, filter, nextVisited, nextPrefix, index === childUsages.length - 1));
808
+ childLines.push(...renderUsage(childUsage, graph, cwd, filter, color, nextVisited, nextPrefix, index === childUsages.length - 1));
693
809
  });
694
810
  return childLines;
695
811
  }
696
- function formatReactNodeLabel(node, cwd) {
697
- return `${node.name} [${node.kind}] (${toDisplayPath(node.filePath, cwd)})`;
812
+ function formatReactNodeLabel(node, cwd, color) {
813
+ return `${formatReactSymbolLabel(node.name, node.kind, color)} (${toDisplayPath(node.filePath, cwd)})`;
698
814
  }
699
815
  //#endregion
700
816
  //#region src/tree.ts
701
817
  function printDependencyTree(graph, options = {}) {
702
818
  const cwd = options.cwd ?? graph.cwd;
819
+ const color = resolveColorSupport(options.color);
703
820
  const includeExternals = options.includeExternals ?? false;
821
+ const omitUnused = options.omitUnused ?? false;
704
822
  const rootLines = [toDisplayPath(graph.entryId, cwd)];
705
823
  const visited = new Set([graph.entryId]);
706
824
  const entryNode = graph.nodes.get(graph.entryId);
707
825
  if (entryNode === void 0) return rootLines.join("\n");
708
- const rootDependencies = filterDependencies(entryNode.dependencies, includeExternals);
826
+ const rootDependencies = filterDependencies(entryNode.dependencies, includeExternals, omitUnused);
709
827
  rootDependencies.forEach((dependency, index) => {
710
- const lines = renderDependency(dependency, graph, visited, "", index === rootDependencies.length - 1, includeExternals, cwd);
828
+ const lines = renderDependency(dependency, graph, visited, "", index === rootDependencies.length - 1, includeExternals, omitUnused, color, cwd);
711
829
  rootLines.push(...lines);
712
830
  });
713
831
  return rootLines.join("\n");
714
832
  }
715
- function renderDependency(dependency, graph, visited, prefix, isLast, includeExternals, cwd) {
833
+ function renderDependency(dependency, graph, visited, prefix, isLast, includeExternals, omitUnused, color, cwd) {
716
834
  const branch = `${prefix}${isLast ? "└─ " : "├─ "}`;
717
- const label = formatDependencyLabel(dependency, graph, cwd);
835
+ const label = formatDependencyLabel(dependency, cwd, color);
718
836
  if (dependency.kind !== "source") return [`${branch}${label}`];
719
837
  if (visited.has(dependency.target)) return [`${branch}${label} (circular)`];
720
838
  const childNode = graph.nodes.get(dependency.target);
@@ -723,20 +841,21 @@ function renderDependency(dependency, graph, visited, prefix, isLast, includeExt
723
841
  const nextVisited = new Set(visited);
724
842
  nextVisited.add(dependency.target);
725
843
  const childLines = [`${branch}${label}`];
726
- const childDependencies = filterDependencies(childNode.dependencies, includeExternals);
844
+ const childDependencies = filterDependencies(childNode.dependencies, includeExternals, omitUnused);
727
845
  childDependencies.forEach((childDependency, index) => {
728
846
  const isChildLast = index === childDependencies.length - 1;
729
- childLines.push(...renderDependency(childDependency, graph, nextVisited, nextPrefix, isChildLast, includeExternals, cwd));
847
+ childLines.push(...renderDependency(childDependency, graph, nextVisited, nextPrefix, isChildLast, includeExternals, omitUnused, color, cwd));
730
848
  });
731
849
  return childLines;
732
850
  }
733
- function filterDependencies(dependencies, includeExternals) {
851
+ function filterDependencies(dependencies, includeExternals, omitUnused) {
734
852
  return dependencies.filter((dependency) => {
853
+ if (omitUnused && dependency.unused) return false;
735
854
  if (dependency.kind === "source" || dependency.kind === "missing") return true;
736
855
  return includeExternals;
737
856
  });
738
857
  }
739
- function formatDependencyLabel(dependency, _graph, cwd) {
858
+ function formatDependencyLabel(dependency, cwd, color) {
740
859
  const prefixes = [];
741
860
  if (dependency.isTypeOnly) prefixes.push("type");
742
861
  if (dependency.referenceKind === "require") prefixes.push("require");
@@ -744,12 +863,15 @@ function formatDependencyLabel(dependency, _graph, cwd) {
744
863
  else if (dependency.referenceKind === "export") prefixes.push("re-export");
745
864
  else if (dependency.referenceKind === "import-equals") prefixes.push("import=");
746
865
  const annotation = prefixes.length > 0 ? `[${prefixes.join(", ")}] ` : "";
747
- if (dependency.kind === "source") return `${annotation}${toDisplayPath(dependency.target, cwd)}`;
748
- if (dependency.kind === "missing") return `${annotation}${dependency.specifier} [missing]`;
749
- if (dependency.kind === "builtin") return `${annotation}${dependency.target} [builtin]`;
750
- return `${annotation}${dependency.target} [external]`;
866
+ if (dependency.kind === "source") return colorizeUnusedMarker(withUnusedSuffix(`${annotation}${toDisplayPath(dependency.target, cwd)}`, dependency.unused), color);
867
+ if (dependency.kind === "missing") return colorizeUnusedMarker(withUnusedSuffix(`${annotation}${dependency.specifier} [missing]`, dependency.unused), color);
868
+ if (dependency.kind === "builtin") return colorizeUnusedMarker(withUnusedSuffix(`${annotation}${dependency.target} [builtin]`, dependency.unused), color);
869
+ return colorizeUnusedMarker(withUnusedSuffix(`${annotation}${dependency.target} [external]`, dependency.unused), color);
870
+ }
871
+ function withUnusedSuffix(label, unused) {
872
+ return unused ? `${label} (unused)` : label;
751
873
  }
752
874
  //#endregion
753
875
  export { graphToSerializableReactTree as a, getReactUsageRoots as i, printReactUsageTree as n, analyzeDependencies as o, analyzeReactUsage as r, graphToSerializableTree as s, printDependencyTree as t };
754
876
 
755
- //# sourceMappingURL=tree-Cp8CNmeY.mjs.map
877
+ //# sourceMappingURL=tree-B5Q_Mgkq.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree-B5Q_Mgkq.mjs","names":["process"],"sources":["../src/config.ts","../src/path-utils.ts","../src/analyzer.ts","../src/react-analyzer.ts","../src/color.ts","../src/react-tree.ts","../src/tree.ts"],"sourcesContent":["import path from 'node:path'\nimport ts from 'typescript'\n\nexport interface LoadedConfig {\n readonly path?: string\n readonly compilerOptions: ts.CompilerOptions\n}\n\nexport function loadCompilerOptions(\n searchFrom: string,\n explicitConfigPath?: string,\n): LoadedConfig {\n const configPath =\n explicitConfigPath === undefined\n ? findNearestConfig(searchFrom)\n : path.resolve(searchFrom, explicitConfigPath)\n\n if (configPath === undefined) {\n return {\n compilerOptions: defaultCompilerOptions(),\n }\n }\n\n const readResult = ts.readConfigFile(configPath, ts.sys.readFile)\n if (readResult.error !== undefined) {\n throw new Error(\n `Failed to read TypeScript config at ${configPath}: ${formatDiagnostic(\n readResult.error,\n )}`,\n )\n }\n\n const parsed = ts.parseJsonConfigFileContent(\n readResult.config,\n ts.sys,\n path.dirname(configPath),\n defaultCompilerOptions(),\n configPath,\n )\n\n if (parsed.errors.length > 0) {\n const [firstError] = parsed.errors\n if (firstError === undefined) {\n throw new Error(`Failed to parse TypeScript config at ${configPath}.`)\n }\n\n throw new Error(\n `Failed to parse TypeScript config at ${configPath}: ${formatDiagnostic(\n firstError,\n )}`,\n )\n }\n\n return {\n path: configPath,\n compilerOptions: parsed.options,\n }\n}\n\nfunction findNearestConfig(searchFrom: string): string | undefined {\n let currentDirectory = path.resolve(searchFrom)\n\n while (true) {\n const tsconfigPath = path.join(currentDirectory, 'tsconfig.json')\n if (ts.sys.fileExists(tsconfigPath)) {\n return tsconfigPath\n }\n\n const jsconfigPath = path.join(currentDirectory, 'jsconfig.json')\n if (ts.sys.fileExists(jsconfigPath)) {\n return jsconfigPath\n }\n\n const parentDirectory = path.dirname(currentDirectory)\n if (parentDirectory === currentDirectory) {\n return undefined\n }\n\n currentDirectory = parentDirectory\n }\n}\n\nfunction defaultCompilerOptions(): ts.CompilerOptions {\n return {\n allowJs: true,\n jsx: ts.JsxEmit.ReactJSX,\n module: ts.ModuleKind.NodeNext,\n moduleResolution: ts.ModuleResolutionKind.NodeNext,\n target: ts.ScriptTarget.ESNext,\n resolveJsonModule: true,\n esModuleInterop: true,\n }\n}\n\nfunction formatDiagnostic(diagnostic: ts.Diagnostic): string {\n return ts.flattenDiagnosticMessageText(diagnostic.messageText, '\\n')\n}\n","import path from 'node:path'\n\nexport const SOURCE_EXTENSIONS = new Set([\n '.js',\n '.jsx',\n '.ts',\n '.tsx',\n '.mjs',\n '.cjs',\n '.mts',\n '.cts',\n])\n\nexport function normalizeFilePath(filePath: string): string {\n return path.normalize(filePath)\n}\n\nexport function toDisplayPath(filePath: string, cwd: string): string {\n const relativePath = path.relative(cwd, filePath)\n if (relativePath === '') {\n return '.'\n }\n\n const normalizedPath = relativePath.split(path.sep).join('/')\n return normalizedPath.startsWith('..') ? filePath : normalizedPath\n}\n\nexport function isSourceCodeFile(filePath: string): boolean {\n return SOURCE_EXTENSIONS.has(path.extname(filePath).toLowerCase())\n}\n","import fs from 'node:fs'\nimport { builtinModules } from 'node:module'\nimport path from 'node:path'\nimport ts from 'typescript'\n\nimport { loadCompilerOptions } from './config.js'\nimport {\n isSourceCodeFile,\n normalizeFilePath,\n toDisplayPath,\n} from './path-utils.js'\nimport type {\n AnalyzeOptions,\n DependencyEdge,\n DependencyGraph,\n DependencyKind,\n ReferenceKind,\n SourceModuleNode,\n} from './types.js'\n\ninterface ModuleReference {\n readonly specifier: string\n readonly referenceKind: ReferenceKind\n readonly isTypeOnly: boolean\n readonly unused: boolean\n}\n\nconst BUILTIN_MODULES = new Set(\n builtinModules.flatMap((name) => [name, `node:${name}`]),\n)\n\nexport function analyzeDependencies(\n entryFile: string,\n options: AnalyzeOptions = {},\n): DependencyGraph {\n const cwd = path.resolve(options.cwd ?? process.cwd())\n const resolvedEntryPath = resolveExistingPath(cwd, entryFile)\n const { compilerOptions, path: configPath } = loadCompilerOptions(\n path.dirname(resolvedEntryPath),\n options.configPath,\n )\n\n const host: ts.ModuleResolutionHost = {\n fileExists: ts.sys.fileExists,\n readFile: ts.sys.readFile,\n directoryExists: ts.sys.directoryExists,\n getCurrentDirectory: () => cwd,\n getDirectories: ts.sys.getDirectories,\n ...(ts.sys.realpath === undefined ? {} : { realpath: ts.sys.realpath }),\n }\n\n const nodes = new Map<string, SourceModuleNode>()\n const program = createProgram(resolvedEntryPath, compilerOptions, cwd)\n const checker = program.getTypeChecker()\n visitFile(resolvedEntryPath, compilerOptions, host, checker, program, nodes)\n\n return {\n cwd,\n entryId: resolvedEntryPath,\n nodes,\n ...(configPath === undefined ? {} : { configPath }),\n }\n}\n\nexport function graphToSerializableTree(\n graph: DependencyGraph,\n options: {\n readonly omitUnused?: boolean\n } = {},\n): object {\n const visited = new Set<string>()\n return serializeNode(\n graph.entryId,\n graph,\n visited,\n options.omitUnused ?? false,\n )\n}\n\nfunction serializeNode(\n filePath: string,\n graph: DependencyGraph,\n visited: Set<string>,\n omitUnused: boolean,\n): object {\n const node = graph.nodes.get(filePath)\n const displayPath = toDisplayPath(filePath, graph.cwd)\n\n if (node === undefined) {\n return {\n path: displayPath,\n kind: 'missing',\n dependencies: [],\n }\n }\n\n if (visited.has(filePath)) {\n return {\n path: displayPath,\n kind: 'circular',\n dependencies: [],\n }\n }\n\n visited.add(filePath)\n\n const dependencies = node.dependencies\n .filter((dependency) => !omitUnused || !dependency.unused)\n .map((dependency) => {\n if (dependency.kind !== 'source') {\n return {\n specifier: dependency.specifier,\n referenceKind: dependency.referenceKind,\n isTypeOnly: dependency.isTypeOnly,\n unused: dependency.unused,\n kind: dependency.kind,\n target:\n dependency.kind === 'missing'\n ? dependency.target\n : toDisplayPath(dependency.target, graph.cwd),\n }\n }\n\n return {\n specifier: dependency.specifier,\n referenceKind: dependency.referenceKind,\n isTypeOnly: dependency.isTypeOnly,\n unused: dependency.unused,\n kind: dependency.kind,\n target: toDisplayPath(dependency.target, graph.cwd),\n node: serializeNode(\n dependency.target,\n graph,\n new Set(visited),\n omitUnused,\n ),\n }\n })\n\n return {\n path: displayPath,\n kind: filePath === graph.entryId ? 'entry' : 'source',\n dependencies,\n }\n}\n\nfunction visitFile(\n filePath: string,\n compilerOptions: ts.CompilerOptions,\n host: ts.ModuleResolutionHost,\n checker: ts.TypeChecker,\n program: ts.Program,\n nodes: Map<string, SourceModuleNode>,\n): void {\n const normalizedPath = normalizeFilePath(filePath)\n if (nodes.has(normalizedPath)) {\n return\n }\n\n const sourceFile =\n program.getSourceFile(normalizedPath) ?? createSourceFile(normalizedPath)\n\n const references = collectModuleReferences(sourceFile, checker)\n const dependencies = references.map((reference) =>\n resolveDependency(reference, normalizedPath, compilerOptions, host),\n )\n\n nodes.set(normalizedPath, {\n id: normalizedPath,\n dependencies,\n })\n\n for (const dependency of dependencies) {\n if (dependency.kind === 'source') {\n visitFile(\n dependency.target,\n compilerOptions,\n host,\n checker,\n program,\n nodes,\n )\n }\n }\n}\n\nfunction collectModuleReferences(\n sourceFile: ts.SourceFile,\n checker: ts.TypeChecker,\n): ModuleReference[] {\n const references = new Map<string, ModuleReference>()\n const unusedImports = collectUnusedImports(sourceFile, checker)\n\n function addReference(\n specifier: string,\n referenceKind: ReferenceKind,\n isTypeOnly: boolean,\n unused: boolean,\n ): void {\n const key = `${referenceKind}:${isTypeOnly ? 'type' : 'value'}:${specifier}`\n const existing = references.get(key)\n if (existing !== undefined) {\n if (existing.unused && !unused) {\n references.set(key, {\n ...existing,\n unused: false,\n })\n }\n return\n }\n\n references.set(key, {\n specifier,\n referenceKind,\n isTypeOnly,\n unused,\n })\n }\n\n function visit(node: ts.Node): void {\n if (\n ts.isImportDeclaration(node) &&\n ts.isStringLiteralLike(node.moduleSpecifier)\n ) {\n addReference(\n node.moduleSpecifier.text,\n 'import',\n node.importClause?.isTypeOnly ?? false,\n unusedImports.get(node) ?? false,\n )\n } else if (\n ts.isExportDeclaration(node) &&\n node.moduleSpecifier !== undefined &&\n ts.isStringLiteralLike(node.moduleSpecifier)\n ) {\n addReference(\n node.moduleSpecifier.text,\n 'export',\n node.isTypeOnly ?? false,\n false,\n )\n } else if (ts.isImportEqualsDeclaration(node)) {\n const moduleReference = node.moduleReference\n if (\n ts.isExternalModuleReference(moduleReference) &&\n moduleReference.expression !== undefined &&\n ts.isStringLiteralLike(moduleReference.expression)\n ) {\n addReference(\n moduleReference.expression.text,\n 'import-equals',\n false,\n false,\n )\n }\n } else if (ts.isCallExpression(node)) {\n if (\n node.expression.kind === ts.SyntaxKind.ImportKeyword &&\n node.arguments.length === 1\n ) {\n const [argument] = node.arguments\n if (argument !== undefined && ts.isStringLiteralLike(argument)) {\n addReference(argument.text, 'dynamic-import', false, false)\n }\n }\n\n if (\n ts.isIdentifier(node.expression) &&\n node.expression.text === 'require' &&\n node.arguments.length === 1\n ) {\n const [argument] = node.arguments\n if (argument !== undefined && ts.isStringLiteralLike(argument)) {\n addReference(argument.text, 'require', false, false)\n }\n }\n }\n\n ts.forEachChild(node, visit)\n }\n\n visit(sourceFile)\n return [...references.values()]\n}\n\nfunction resolveDependency(\n reference: ModuleReference,\n containingFile: string,\n compilerOptions: ts.CompilerOptions,\n host: ts.ModuleResolutionHost,\n): DependencyEdge {\n const specifier = reference.specifier\n if (BUILTIN_MODULES.has(specifier)) {\n return createEdge(reference, 'builtin', specifier)\n }\n\n const resolution = ts.resolveModuleName(\n specifier,\n containingFile,\n compilerOptions,\n host,\n ).resolvedModule\n\n if (resolution !== undefined) {\n const resolvedPath = normalizeFilePath(resolution.resolvedFileName)\n if (\n resolution.isExternalLibraryImport ||\n resolvedPath.includes(`${path.sep}node_modules${path.sep}`)\n ) {\n return createEdge(reference, 'external', specifier)\n }\n\n if (isSourceCodeFile(resolvedPath) && !resolvedPath.endsWith('.d.ts')) {\n return createEdge(reference, 'source', resolvedPath)\n }\n }\n\n if (!specifier.startsWith('.') && !path.isAbsolute(specifier)) {\n return createEdge(reference, 'external', specifier)\n }\n\n return createEdge(reference, 'missing', specifier)\n}\n\nfunction createEdge(\n reference: ModuleReference,\n kind: DependencyKind,\n target: string,\n): DependencyEdge {\n return {\n specifier: reference.specifier,\n referenceKind: reference.referenceKind,\n isTypeOnly: reference.isTypeOnly,\n unused: reference.unused,\n kind,\n target,\n }\n}\n\nfunction createProgram(\n entryFile: string,\n compilerOptions: ts.CompilerOptions,\n cwd: string,\n): ts.Program {\n const host = ts.createCompilerHost(compilerOptions, true)\n host.getCurrentDirectory = () => cwd\n\n if (ts.sys.realpath !== undefined) {\n host.realpath = ts.sys.realpath\n }\n\n return ts.createProgram({\n rootNames: [entryFile],\n options: compilerOptions,\n host,\n })\n}\n\nfunction createSourceFile(filePath: string): ts.SourceFile {\n const sourceText = fs.readFileSync(filePath, 'utf8')\n return ts.createSourceFile(\n filePath,\n sourceText,\n ts.ScriptTarget.Latest,\n true,\n getScriptKind(filePath),\n )\n}\n\nfunction collectUnusedImports(\n sourceFile: ts.SourceFile,\n checker: ts.TypeChecker,\n): ReadonlyMap<ts.ImportDeclaration, boolean> {\n const importUsage = new Map<\n ts.ImportDeclaration,\n {\n canTrack: boolean\n used: boolean\n }\n >()\n const symbolToImportDeclaration = new Map<ts.Symbol, ts.ImportDeclaration>()\n const importedLocalNames = new Set<string>()\n\n sourceFile.statements.forEach((statement) => {\n if (\n !ts.isImportDeclaration(statement) ||\n statement.importClause === undefined\n ) {\n return\n }\n\n const identifiers = getImportBindingIdentifiers(statement.importClause)\n if (identifiers.length === 0) {\n return\n }\n\n importUsage.set(statement, {\n canTrack: false,\n used: false,\n })\n\n identifiers.forEach((identifier) => {\n importedLocalNames.add(identifier.text)\n\n const symbol = tryGetSymbolAtLocation(checker, identifier)\n if (symbol === undefined) {\n return\n }\n\n symbolToImportDeclaration.set(symbol, statement)\n const state = importUsage.get(statement)\n if (state !== undefined) {\n state.canTrack = true\n }\n })\n })\n\n function visit(node: ts.Node): void {\n if (ts.isImportDeclaration(node)) {\n return\n }\n\n if (\n ts.isIdentifier(node) &&\n importedLocalNames.has(node.text) &&\n isReferenceIdentifier(node)\n ) {\n const symbol = tryGetSymbolAtLocation(checker, node)\n const declaration =\n symbol === undefined ? undefined : symbolToImportDeclaration.get(symbol)\n if (declaration !== undefined) {\n const state = importUsage.get(declaration)\n if (state !== undefined) {\n state.used = true\n }\n }\n }\n\n ts.forEachChild(node, visit)\n }\n\n visit(sourceFile)\n\n return new Map(\n [...importUsage.entries()].map(([declaration, state]) => [\n declaration,\n state.canTrack && !state.used,\n ]),\n )\n}\n\nfunction getImportBindingIdentifiers(\n importClause: ts.ImportClause,\n): ts.Identifier[] {\n const identifiers: ts.Identifier[] = []\n\n if (importClause.name !== undefined) {\n identifiers.push(importClause.name)\n }\n\n const namedBindings = importClause.namedBindings\n if (namedBindings === undefined) {\n return identifiers\n }\n\n if (ts.isNamespaceImport(namedBindings)) {\n identifiers.push(namedBindings.name)\n return identifiers\n }\n\n namedBindings.elements.forEach((element) => {\n identifiers.push(element.name)\n })\n\n return identifiers\n}\n\nfunction isReferenceIdentifier(node: ts.Identifier): boolean {\n const parent = node.parent\n\n if (ts.isPropertyAccessExpression(parent) && parent.name === node) {\n return false\n }\n\n if (ts.isQualifiedName(parent) && parent.right === node) {\n return false\n }\n\n if (ts.isPropertyAssignment(parent) && parent.name === node) {\n return false\n }\n\n if (ts.isBindingElement(parent) && parent.propertyName === node) {\n return false\n }\n\n if (ts.isJsxAttribute(parent) && parent.name === node) {\n return false\n }\n\n if (ts.isExportSpecifier(parent)) {\n return parent.propertyName === node || parent.propertyName === undefined\n }\n\n return true\n}\n\nfunction tryGetSymbolAtLocation(\n checker: ts.TypeChecker,\n node: ts.Node,\n): ts.Symbol | undefined {\n try {\n return checker.getSymbolAtLocation(node)\n } catch {\n return undefined\n }\n}\n\nfunction getScriptKind(filePath: string): ts.ScriptKind {\n switch (path.extname(filePath).toLowerCase()) {\n case '.js':\n case '.mjs':\n case '.cjs':\n return ts.ScriptKind.JS\n case '.jsx':\n return ts.ScriptKind.JSX\n case '.tsx':\n return ts.ScriptKind.TSX\n case '.json':\n return ts.ScriptKind.JSON\n default:\n return ts.ScriptKind.TS\n }\n}\n\nfunction resolveExistingPath(cwd: string, entryFile: string): string {\n const absolutePath = path.resolve(cwd, entryFile)\n const normalizedPath = normalizeFilePath(absolutePath)\n\n if (!fs.existsSync(normalizedPath)) {\n throw new Error(`Entry file not found: ${entryFile}`)\n }\n\n if (!isSourceCodeFile(normalizedPath)) {\n throw new Error(`Entry file must be a JS/TS source file: ${entryFile}`)\n }\n\n return normalizedPath\n}\n","import fs from 'node:fs'\nimport type {\n ArrowFunctionExpression,\n CallExpression,\n ExportDefaultDeclaration,\n ExportNamedDeclaration,\n Expression,\n FunctionBody,\n ImportDeclaration,\n ImportDeclarationSpecifier,\n JSXElement,\n JSXElementName,\n JSXFragment,\n ModuleExportName,\n Node,\n Function as OxcFunction,\n Program,\n Statement,\n VariableDeclarator,\n} from 'oxc-parser'\nimport { parseSync, visitorKeys } from 'oxc-parser'\n\nimport { analyzeDependencies } from './analyzer.js'\nimport { isSourceCodeFile, toDisplayPath } from './path-utils.js'\nimport type {\n AnalyzeOptions,\n ReactSymbolKind,\n ReactUsageEdge,\n ReactUsageFilter,\n ReactUsageGraph,\n ReactUsageNode,\n} from './types.js'\n\ninterface PendingReactUsageNode {\n readonly id: string\n readonly name: string\n readonly kind: ReactSymbolKind\n readonly filePath: string\n readonly declaration: OxcFunction | ArrowFunctionExpression\n readonly exportNames: Set<string>\n readonly componentReferences: Set<string>\n readonly hookReferences: Set<string>\n}\n\ninterface ImportBinding {\n readonly importedName: string\n readonly sourceSpecifier: string\n readonly sourcePath?: string\n}\n\ninterface FileAnalysis {\n readonly filePath: string\n readonly importsByLocalName: Map<string, ImportBinding>\n readonly exportsByName: Map<string, string>\n readonly symbolsById: Map<string, PendingReactUsageNode>\n readonly symbolsByName: Map<string, PendingReactUsageNode>\n}\n\ninterface SerializedReactUsageNode {\n readonly id: string\n readonly name: string\n readonly symbolKind: ReactSymbolKind | 'circular'\n readonly filePath: string\n readonly exportNames: readonly string[]\n readonly usages: readonly SerializedReactUsageEdge[]\n}\n\ninterface SerializedReactUsageEdge {\n readonly kind: ReactUsageEdge['kind']\n readonly targetId: string\n readonly node: SerializedReactUsageNode\n}\n\nconst FUNCTION_NODE_TYPES = new Set([\n 'FunctionDeclaration',\n 'FunctionExpression',\n 'ArrowFunctionExpression',\n 'TSDeclareFunction',\n 'TSEmptyBodyFunctionExpression',\n])\n\nexport function analyzeReactUsage(\n entryFile: string,\n options: AnalyzeOptions = {},\n): ReactUsageGraph {\n const dependencyGraph = analyzeDependencies(entryFile, options)\n const reachableFiles = new Set<string>([\n dependencyGraph.entryId,\n ...dependencyGraph.nodes.keys(),\n ])\n const fileAnalyses = new Map<string, FileAnalysis>()\n\n for (const filePath of [...reachableFiles].sort()) {\n if (!isSourceCodeFile(filePath) || filePath.endsWith('.d.ts')) {\n continue\n }\n\n const sourceText = fs.readFileSync(filePath, 'utf8')\n const parseResult = parseSync(filePath, sourceText, {\n astType: 'ts',\n sourceType: 'unambiguous',\n })\n\n const dependencyNode = dependencyGraph.nodes.get(filePath)\n const sourceDependencies = new Map<string, string>()\n dependencyNode?.dependencies.forEach((dependency) => {\n if (dependency.kind === 'source') {\n sourceDependencies.set(dependency.specifier, dependency.target)\n }\n })\n\n fileAnalyses.set(\n filePath,\n analyzeReactFile(parseResult.program, filePath, sourceDependencies),\n )\n }\n\n const nodes = new Map<string, ReactUsageNode>()\n for (const fileAnalysis of fileAnalyses.values()) {\n for (const symbol of fileAnalysis.symbolsById.values()) {\n nodes.set(symbol.id, {\n id: symbol.id,\n name: symbol.name,\n kind: symbol.kind,\n filePath: symbol.filePath,\n exportNames: [...symbol.exportNames].sort(),\n usages: [],\n })\n }\n }\n\n for (const fileAnalysis of fileAnalyses.values()) {\n fileAnalysis.importsByLocalName.forEach((binding, localName) => {\n if (binding.sourcePath !== undefined) {\n return\n }\n\n if (!isHookName(localName) && !isHookName(binding.importedName)) {\n return\n }\n\n const externalNode = createExternalHookNode(binding, localName)\n if (!nodes.has(externalNode.id)) {\n nodes.set(externalNode.id, externalNode)\n }\n })\n }\n\n for (const fileAnalysis of fileAnalyses.values()) {\n for (const symbol of fileAnalysis.symbolsById.values()) {\n const usages = new Map<string, ReactUsageEdge>()\n\n symbol.componentReferences.forEach((referenceName) => {\n const targetId = resolveReactReference(\n fileAnalysis,\n fileAnalyses,\n referenceName,\n 'component',\n )\n if (targetId !== undefined && targetId !== symbol.id) {\n usages.set(`render:${targetId}`, {\n kind: 'render',\n target: targetId,\n })\n }\n })\n\n symbol.hookReferences.forEach((referenceName) => {\n const targetId = resolveReactReference(\n fileAnalysis,\n fileAnalyses,\n referenceName,\n 'hook',\n )\n if (targetId !== undefined && targetId !== symbol.id) {\n usages.set(`hook:${targetId}`, {\n kind: 'hook-call',\n target: targetId,\n })\n }\n })\n\n const node = nodes.get(symbol.id)\n if (node === undefined) {\n continue\n }\n\n const sortedUsages = [...usages.values()].sort((left, right) =>\n compareReactNodeIds(left.target, right.target, nodes),\n )\n\n nodes.set(symbol.id, {\n ...node,\n usages: sortedUsages,\n })\n }\n }\n\n return {\n cwd: dependencyGraph.cwd,\n entryId: dependencyGraph.entryId,\n nodes,\n }\n}\n\nexport function graphToSerializableReactTree(\n graph: ReactUsageGraph,\n options: {\n readonly filter?: ReactUsageFilter\n } = {},\n): object {\n const roots = getReactUsageRoots(graph, options.filter)\n\n return {\n kind: 'react-usage',\n roots: roots.map((rootId) =>\n serializeReactUsageNode(\n rootId,\n graph,\n options.filter ?? 'all',\n new Set(),\n ),\n ),\n }\n}\n\nexport function getReactUsageRoots(\n graph: ReactUsageGraph,\n filter: ReactUsageFilter = 'all',\n): string[] {\n const filteredNodes = getFilteredReactUsageNodes(graph, filter)\n const inboundCounts = new Map<string, number>()\n\n filteredNodes.forEach((node) => {\n inboundCounts.set(node.id, 0)\n })\n\n filteredNodes.forEach((node) => {\n getFilteredUsages(node, graph, filter).forEach((usage) => {\n inboundCounts.set(\n usage.target,\n (inboundCounts.get(usage.target) ?? 0) + 1,\n )\n })\n })\n\n const roots = filteredNodes\n .filter((node) => (inboundCounts.get(node.id) ?? 0) === 0)\n .map((node) => node.id)\n\n if (roots.length > 0) {\n return roots.sort((left, right) =>\n compareReactNodeIds(left, right, graph.nodes),\n )\n }\n\n return filteredNodes\n .map((node) => node.id)\n .sort((left, right) => compareReactNodeIds(left, right, graph.nodes))\n}\n\nexport function getFilteredUsages(\n node: ReactUsageNode,\n graph: ReactUsageGraph,\n filter: ReactUsageFilter = 'all',\n): ReactUsageEdge[] {\n return node.usages.filter((usage) => {\n const targetNode = graph.nodes.get(usage.target)\n return targetNode !== undefined && matchesReactFilter(targetNode, filter)\n })\n}\n\nfunction analyzeReactFile(\n program: Program,\n filePath: string,\n sourceDependencies: ReadonlyMap<string, string>,\n): FileAnalysis {\n const symbolsByName = new Map<string, PendingReactUsageNode>()\n\n program.body.forEach((statement) => {\n collectTopLevelReactSymbols(statement, filePath, symbolsByName)\n })\n\n const importsByLocalName = new Map<string, ImportBinding>()\n const exportsByName = new Map<string, string>()\n\n program.body.forEach((statement) => {\n collectImportsAndExports(\n statement,\n sourceDependencies,\n symbolsByName,\n importsByLocalName,\n exportsByName,\n )\n })\n\n symbolsByName.forEach((symbol) => {\n analyzeSymbolUsages(symbol)\n })\n\n return {\n filePath,\n importsByLocalName,\n exportsByName,\n symbolsById: new Map(\n [...symbolsByName.values()].map((symbol) => [symbol.id, symbol]),\n ),\n symbolsByName,\n }\n}\n\nfunction collectTopLevelReactSymbols(\n statement: Statement,\n filePath: string,\n symbolsByName: Map<string, PendingReactUsageNode>,\n): void {\n switch (statement.type) {\n case 'FunctionDeclaration':\n addFunctionSymbol(statement, filePath, symbolsByName)\n return\n case 'VariableDeclaration':\n statement.declarations.forEach((declarator) => {\n addVariableSymbol(declarator, filePath, symbolsByName)\n })\n return\n case 'ExportNamedDeclaration':\n if (statement.declaration !== null) {\n collectTopLevelReactSymbols(\n statement.declaration,\n filePath,\n symbolsByName,\n )\n }\n return\n case 'ExportDefaultDeclaration':\n addDefaultExportSymbol(statement, filePath, symbolsByName)\n return\n default:\n return\n }\n}\n\nfunction addFunctionSymbol(\n declaration: OxcFunction,\n filePath: string,\n symbolsByName: Map<string, PendingReactUsageNode>,\n): void {\n const name = declaration.id?.name\n if (name === undefined) {\n return\n }\n\n const kind = classifyReactSymbol(name, declaration)\n if (kind === undefined) {\n return\n }\n\n symbolsByName.set(\n name,\n createPendingSymbol(filePath, name, kind, declaration),\n )\n}\n\nfunction addVariableSymbol(\n declarator: VariableDeclarator,\n filePath: string,\n symbolsByName: Map<string, PendingReactUsageNode>,\n): void {\n if (declarator.id.type !== 'Identifier' || declarator.init === null) {\n return\n }\n\n if (\n declarator.init.type !== 'ArrowFunctionExpression' &&\n declarator.init.type !== 'FunctionExpression'\n ) {\n return\n }\n\n const name = declarator.id.name\n const kind = classifyReactSymbol(name, declarator.init)\n if (kind === undefined) {\n return\n }\n\n symbolsByName.set(\n name,\n createPendingSymbol(filePath, name, kind, declarator.init),\n )\n}\n\nfunction addDefaultExportSymbol(\n declaration: ExportDefaultDeclaration,\n filePath: string,\n symbolsByName: Map<string, PendingReactUsageNode>,\n): void {\n if (\n declaration.declaration.type === 'FunctionDeclaration' ||\n declaration.declaration.type === 'FunctionExpression'\n ) {\n addFunctionSymbol(declaration.declaration, filePath, symbolsByName)\n } else if (declaration.declaration.type === 'ArrowFunctionExpression') {\n const name = 'default'\n const kind = declaration.declaration.body\n ? classifyReactSymbol(name, declaration.declaration)\n : undefined\n if (kind !== undefined) {\n symbolsByName.set(\n name,\n createPendingSymbol(filePath, name, kind, declaration.declaration),\n )\n }\n }\n}\n\nfunction createPendingSymbol(\n filePath: string,\n name: string,\n kind: ReactSymbolKind,\n declaration: OxcFunction | ArrowFunctionExpression,\n): PendingReactUsageNode {\n return {\n id: `${filePath}#${kind}:${name}`,\n name,\n kind,\n filePath,\n declaration,\n exportNames: new Set<string>(),\n componentReferences: new Set<string>(),\n hookReferences: new Set<string>(),\n }\n}\n\nfunction collectImportsAndExports(\n statement: Statement,\n sourceDependencies: ReadonlyMap<string, string>,\n symbolsByName: ReadonlyMap<string, PendingReactUsageNode>,\n importsByLocalName: Map<string, ImportBinding>,\n exportsByName: Map<string, string>,\n): void {\n switch (statement.type) {\n case 'ImportDeclaration':\n collectImportBindings(statement, sourceDependencies, importsByLocalName)\n return\n case 'ExportNamedDeclaration':\n collectNamedExports(statement, symbolsByName, exportsByName)\n return\n case 'ExportDefaultDeclaration':\n collectDefaultExport(statement, symbolsByName, exportsByName)\n return\n default:\n return\n }\n}\n\nfunction collectImportBindings(\n declaration: ImportDeclaration,\n sourceDependencies: ReadonlyMap<string, string>,\n importsByLocalName: Map<string, ImportBinding>,\n): void {\n if (declaration.importKind === 'type') {\n return\n }\n\n const sourceSpecifier = declaration.source.value\n const sourcePath = sourceDependencies.get(declaration.source.value)\n\n declaration.specifiers.forEach((specifier) => {\n const binding = getImportBinding(specifier, sourceSpecifier, sourcePath)\n if (binding === undefined) {\n return\n }\n\n importsByLocalName.set(binding.localName, {\n importedName: binding.importedName,\n sourceSpecifier: binding.sourceSpecifier,\n ...(binding.sourcePath === undefined\n ? {}\n : { sourcePath: binding.sourcePath }),\n })\n })\n}\n\nfunction getImportBinding(\n specifier: ImportDeclarationSpecifier,\n sourceSpecifier: string,\n sourcePath: string | undefined,\n):\n | {\n readonly localName: string\n readonly importedName: string\n readonly sourceSpecifier: string\n readonly sourcePath?: string\n }\n | undefined {\n if (specifier.type === 'ImportSpecifier') {\n if (specifier.importKind === 'type') {\n return undefined\n }\n\n return {\n localName: specifier.local.name,\n importedName: toModuleExportName(specifier.imported),\n sourceSpecifier,\n ...(sourcePath === undefined ? {} : { sourcePath }),\n }\n }\n\n if (specifier.type === 'ImportDefaultSpecifier') {\n return {\n localName: specifier.local.name,\n importedName: 'default',\n sourceSpecifier,\n ...(sourcePath === undefined ? {} : { sourcePath }),\n }\n }\n\n return undefined\n}\n\nfunction collectNamedExports(\n declaration: ExportNamedDeclaration,\n symbolsByName: ReadonlyMap<string, PendingReactUsageNode>,\n exportsByName: Map<string, string>,\n): void {\n if (declaration.exportKind === 'type') {\n return\n }\n\n if (declaration.declaration !== null) {\n if (declaration.declaration.type === 'FunctionDeclaration') {\n const name = declaration.declaration.id?.name\n if (name !== undefined) {\n addExportBinding(name, name, symbolsByName, exportsByName)\n }\n } else if (declaration.declaration.type === 'VariableDeclaration') {\n declaration.declaration.declarations.forEach((declarator) => {\n if (declarator.id.type === 'Identifier') {\n addExportBinding(\n declarator.id.name,\n declarator.id.name,\n symbolsByName,\n exportsByName,\n )\n }\n })\n }\n\n return\n }\n\n if (declaration.source !== null) {\n return\n }\n\n declaration.specifiers.forEach((specifier) => {\n if (specifier.exportKind === 'type') {\n return\n }\n\n const localName = toModuleExportName(specifier.local)\n const exportedName = toModuleExportName(specifier.exported)\n addExportBinding(localName, exportedName, symbolsByName, exportsByName)\n })\n}\n\nfunction collectDefaultExport(\n declaration: ExportDefaultDeclaration,\n symbolsByName: ReadonlyMap<string, PendingReactUsageNode>,\n exportsByName: Map<string, string>,\n): void {\n if (\n declaration.declaration.type === 'FunctionDeclaration' ||\n declaration.declaration.type === 'FunctionExpression'\n ) {\n const localName = declaration.declaration.id?.name\n if (localName !== undefined) {\n addExportBinding(localName, 'default', symbolsByName, exportsByName)\n }\n return\n }\n\n if (declaration.declaration.type === 'Identifier') {\n addExportBinding(\n declaration.declaration.name,\n 'default',\n symbolsByName,\n exportsByName,\n )\n return\n }\n\n if (declaration.declaration.type === 'ArrowFunctionExpression') {\n addExportBinding('default', 'default', symbolsByName, exportsByName)\n }\n}\n\nfunction addExportBinding(\n localName: string,\n exportedName: string,\n symbolsByName: ReadonlyMap<string, PendingReactUsageNode>,\n exportsByName: Map<string, string>,\n): void {\n const symbol = symbolsByName.get(localName)\n if (symbol === undefined) {\n return\n }\n\n symbol.exportNames.add(exportedName)\n exportsByName.set(exportedName, symbol.id)\n}\n\nfunction analyzeSymbolUsages(symbol: PendingReactUsageNode): void {\n const root =\n symbol.declaration.type === 'ArrowFunctionExpression'\n ? symbol.declaration.body\n : symbol.declaration.body\n\n if (root === null) {\n return\n }\n\n walkReactUsageTree(root, (node) => {\n if (node.type === 'JSXElement') {\n const name = getComponentReferenceName(node)\n if (name !== undefined) {\n symbol.componentReferences.add(name)\n }\n return\n }\n\n if (node.type === 'CallExpression') {\n const hookReference = getHookReferenceName(node)\n if (hookReference !== undefined) {\n symbol.hookReferences.add(hookReference)\n }\n\n const componentReference = getCreateElementComponentReferenceName(node)\n if (componentReference !== undefined) {\n symbol.componentReferences.add(componentReference)\n }\n }\n })\n}\n\nfunction classifyReactSymbol(\n name: string,\n declaration: OxcFunction | ArrowFunctionExpression,\n): ReactSymbolKind | undefined {\n if (isHookName(name)) {\n return 'hook'\n }\n\n if (isComponentName(name) && returnsReactElement(declaration)) {\n return 'component'\n }\n\n return undefined\n}\n\nfunction returnsReactElement(\n declaration: OxcFunction | ArrowFunctionExpression,\n): boolean {\n if (\n declaration.type === 'ArrowFunctionExpression' &&\n declaration.expression\n ) {\n return containsReactElementLikeExpression(declaration.body as Expression)\n }\n\n const body = declaration.body\n if (body === null) {\n return false\n }\n\n let found = false\n walkReactUsageTree(body, (node) => {\n if (node.type !== 'ReturnStatement' || node.argument === null) {\n return\n }\n\n if (containsReactElementLikeExpression(node.argument)) {\n found = true\n }\n })\n\n return found\n}\n\nfunction containsReactElementLikeExpression(expression: Expression): boolean {\n let found = false\n\n walkNode(expression, (node) => {\n if (\n node.type === 'JSXElement' ||\n node.type === 'JSXFragment' ||\n (node.type === 'CallExpression' && isReactCreateElementCall(node))\n ) {\n found = true\n }\n })\n\n return found\n}\n\nfunction getComponentReferenceName(node: JSXElement): string | undefined {\n const name = getJsxName(node.openingElement.name)\n return name !== undefined && isComponentName(name) ? name : undefined\n}\n\nfunction getHookReferenceName(node: CallExpression): string | undefined {\n const calleeName = getIdentifierName(node.callee)\n return calleeName !== undefined && isHookName(calleeName)\n ? calleeName\n : undefined\n}\n\nfunction getCreateElementComponentReferenceName(\n node: CallExpression,\n): string | undefined {\n if (!isReactCreateElementCall(node)) {\n return undefined\n }\n\n const [firstArgument] = node.arguments\n if (firstArgument === undefined || firstArgument.type !== 'Identifier') {\n return undefined\n }\n\n return isComponentName(firstArgument.name) ? firstArgument.name : undefined\n}\n\nfunction isReactCreateElementCall(node: CallExpression): boolean {\n const callee = unwrapExpression(node.callee)\n if (callee.type !== 'MemberExpression' || callee.computed) {\n return false\n }\n\n return (\n callee.object.type === 'Identifier' &&\n callee.object.name === 'React' &&\n callee.property.name === 'createElement'\n )\n}\n\nfunction getJsxName(name: JSXElementName): string | undefined {\n if (name.type === 'JSXIdentifier') {\n return name.name\n }\n\n return undefined\n}\n\nfunction getIdentifierName(expression: Expression): string | undefined {\n const unwrapped = unwrapExpression(expression)\n return unwrapped.type === 'Identifier' ? unwrapped.name : undefined\n}\n\nfunction unwrapExpression(expression: Expression): Expression {\n let current = expression\n\n while (true) {\n if (\n current.type === 'ParenthesizedExpression' ||\n current.type === 'TSAsExpression' ||\n current.type === 'TSSatisfiesExpression' ||\n current.type === 'TSTypeAssertion' ||\n current.type === 'TSNonNullExpression'\n ) {\n current = current.expression\n continue\n }\n\n return current\n }\n}\n\nfunction walkReactUsageTree(\n root: FunctionBody | Expression | JSXFragment | JSXElement,\n visit: (node: Node) => void,\n): void {\n walkNode(root, visit, true)\n}\n\nfunction walkNode(\n node: Node,\n visit: (node: Node) => void,\n allowNestedFunctions = false,\n): void {\n visit(node)\n\n const keys = visitorKeys[node.type]\n if (keys === undefined) {\n return\n }\n\n keys.forEach((key) => {\n const value = (node as unknown as Record<string, unknown>)[key]\n walkChild(value, visit, allowNestedFunctions)\n })\n}\n\nfunction walkChild(\n value: unknown,\n visit: (node: Node) => void,\n allowNestedFunctions: boolean,\n): void {\n if (Array.isArray(value)) {\n value.forEach((entry) => {\n walkChild(entry, visit, allowNestedFunctions)\n })\n return\n }\n\n if (!isNode(value)) {\n return\n }\n\n if (!allowNestedFunctions && FUNCTION_NODE_TYPES.has(value.type)) {\n return\n }\n\n walkNode(value, visit, false)\n}\n\nfunction isNode(value: unknown): value is Node {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n typeof (value as { type: unknown }).type === 'string'\n )\n}\n\nfunction resolveReactReference(\n fileAnalysis: FileAnalysis,\n fileAnalyses: ReadonlyMap<string, FileAnalysis>,\n name: string,\n kind: ReactSymbolKind,\n): string | undefined {\n const localSymbol = fileAnalysis.symbolsByName.get(name)\n if (localSymbol !== undefined && localSymbol.kind === kind) {\n return localSymbol.id\n }\n\n const importBinding = fileAnalysis.importsByLocalName.get(name)\n if (importBinding === undefined) {\n return undefined\n }\n\n if (importBinding.sourcePath === undefined) {\n return kind === 'hook'\n ? getExternalHookNodeId(importBinding, name)\n : undefined\n }\n\n const sourceFileAnalysis = fileAnalyses.get(importBinding.sourcePath)\n if (sourceFileAnalysis === undefined) {\n return undefined\n }\n\n const targetId = sourceFileAnalysis.exportsByName.get(\n importBinding.importedName,\n )\n if (targetId === undefined) {\n return undefined\n }\n\n const targetSymbol = sourceFileAnalysis.symbolsById.get(targetId)\n return targetSymbol?.kind === kind ? targetId : undefined\n}\n\nfunction createExternalHookNode(\n binding: ImportBinding,\n localName: string,\n): ReactUsageNode {\n const name = getExternalHookName(binding, localName)\n\n return {\n id: getExternalHookNodeId(binding, localName),\n name,\n kind: 'hook',\n filePath: binding.sourceSpecifier,\n exportNames: [binding.importedName],\n usages: [],\n }\n}\n\nfunction getExternalHookNodeId(\n binding: ImportBinding,\n localName: string,\n): string {\n return `external:${binding.sourceSpecifier}#hook:${getExternalHookName(binding, localName)}`\n}\n\nfunction getExternalHookName(\n binding: ImportBinding,\n localName: string,\n): string {\n return binding.importedName === 'default' ? localName : binding.importedName\n}\n\nfunction getFilteredReactUsageNodes(\n graph: ReactUsageGraph,\n filter: ReactUsageFilter,\n): ReactUsageNode[] {\n return [...graph.nodes.values()]\n .filter((node) => matchesReactFilter(node, filter))\n .sort((left, right) => compareReactNodes(left, right))\n}\n\nfunction matchesReactFilter(\n node: ReactUsageNode,\n filter: ReactUsageFilter,\n): boolean {\n return filter === 'all' || node.kind === filter\n}\n\nfunction serializeReactUsageNode(\n nodeId: string,\n graph: ReactUsageGraph,\n filter: ReactUsageFilter,\n visited: Set<string>,\n): SerializedReactUsageNode {\n const node = graph.nodes.get(nodeId)\n if (node === undefined) {\n return {\n id: nodeId,\n name: nodeId,\n symbolKind: 'circular',\n filePath: '',\n exportNames: [],\n usages: [],\n }\n }\n\n if (visited.has(nodeId)) {\n return {\n id: node.id,\n name: node.name,\n symbolKind: 'circular',\n filePath: toDisplayPath(node.filePath, graph.cwd),\n exportNames: node.exportNames,\n usages: [],\n }\n }\n\n const nextVisited = new Set(visited)\n nextVisited.add(nodeId)\n\n return {\n id: node.id,\n name: node.name,\n symbolKind: node.kind,\n filePath: toDisplayPath(node.filePath, graph.cwd),\n exportNames: node.exportNames,\n usages: getFilteredUsages(node, graph, filter).map((usage) => ({\n kind: usage.kind,\n targetId: usage.target,\n node: serializeReactUsageNode(usage.target, graph, filter, nextVisited),\n })),\n }\n}\n\nfunction compareReactNodeIds(\n leftId: string,\n rightId: string,\n nodes: ReadonlyMap<string, ReactUsageNode>,\n): number {\n const left = nodes.get(leftId)\n const right = nodes.get(rightId)\n\n if (left === undefined || right === undefined) {\n return leftId.localeCompare(rightId)\n }\n\n return compareReactNodes(left, right)\n}\n\nfunction compareReactNodes(\n left: ReactUsageNode,\n right: ReactUsageNode,\n): number {\n return (\n left.filePath.localeCompare(right.filePath) ||\n left.name.localeCompare(right.name) ||\n left.kind.localeCompare(right.kind)\n )\n}\n\nfunction toModuleExportName(name: ModuleExportName): string {\n return name.type === 'Literal' ? name.value : name.name\n}\n\nfunction isHookName(name: string): boolean {\n return /^use[A-Z0-9]/.test(name)\n}\n\nfunction isComponentName(name: string): boolean {\n return /^[A-Z]/.test(name)\n}\n","import process from 'node:process'\n\nimport type { ColorMode, ReactSymbolKind } from './types.js'\n\nconst ANSI_RESET = '\\u001B[0m'\nconst ANSI_COMPONENT = '\\u001B[36m'\nconst ANSI_HOOK = '\\u001B[35m'\nconst ANSI_UNUSED = '\\u001B[38;5;214m'\n\ninterface ResolveColorSupportOptions {\n readonly forceColor?: string | undefined\n readonly isTTY?: boolean | undefined\n readonly noColor?: string | undefined\n}\n\nexport function resolveColorSupport(\n mode: ColorMode = 'auto',\n options: ResolveColorSupportOptions = {},\n): boolean {\n if (mode === true) {\n return true\n }\n\n if (mode === false) {\n return false\n }\n\n const forceColor =\n 'forceColor' in options ? options.forceColor : process.env.FORCE_COLOR\n if (forceColor !== undefined) {\n return forceColor !== '0'\n }\n\n const noColor = 'noColor' in options ? options.noColor : process.env.NO_COLOR\n if (noColor !== undefined) {\n return false\n }\n\n const isTTY = 'isTTY' in options ? options.isTTY : process.stdout.isTTY\n return isTTY === true\n}\n\nexport function colorizeUnusedMarker(text: string, enabled: boolean): string {\n if (!enabled) {\n return text\n }\n\n return text.replaceAll('(unused)', `${ANSI_UNUSED}(unused)${ANSI_RESET}`)\n}\n\nexport function formatReactSymbolLabel(\n name: string,\n kind: ReactSymbolKind,\n enabled: boolean,\n): string {\n const label = `${name} [${kind}]`\n if (!enabled) {\n return label\n }\n\n const color = kind === 'component' ? ANSI_COMPONENT : ANSI_HOOK\n return `${color}${label}${ANSI_RESET}`\n}\n","import { formatReactSymbolLabel, resolveColorSupport } from './color.js'\nimport { toDisplayPath } from './path-utils.js'\nimport { getFilteredUsages, getReactUsageRoots } from './react-analyzer.js'\nimport type {\n PrintReactTreeOptions,\n ReactUsageEdge,\n ReactUsageGraph,\n ReactUsageNode,\n} from './types.js'\n\nexport function printReactUsageTree(\n graph: ReactUsageGraph,\n options: PrintReactTreeOptions = {},\n): string {\n const cwd = options.cwd ?? graph.cwd\n const color = resolveColorSupport(options.color)\n const filter = options.filter ?? 'all'\n const roots = getReactUsageRoots(graph, filter)\n\n if (roots.length === 0) {\n return 'No React symbols found.'\n }\n\n const lines: string[] = []\n roots.forEach((rootId, index) => {\n const root = graph.nodes.get(rootId)\n if (root === undefined) {\n return\n }\n\n lines.push(formatReactNodeLabel(root, cwd, color))\n const usages = getFilteredUsages(root, graph, filter)\n usages.forEach((usage, usageIndex) => {\n lines.push(\n ...renderUsage(\n usage,\n graph,\n cwd,\n filter,\n color,\n new Set([root.id]),\n '',\n usageIndex === usages.length - 1,\n ),\n )\n })\n\n if (index < roots.length - 1) {\n lines.push('')\n }\n })\n\n return lines.join('\\n')\n}\n\nfunction renderUsage(\n usage: ReactUsageEdge,\n graph: ReactUsageGraph,\n cwd: string,\n filter: NonNullable<PrintReactTreeOptions['filter']>,\n color: boolean,\n visited: ReadonlySet<string>,\n prefix: string,\n isLast: boolean,\n): string[] {\n const branch = `${prefix}${isLast ? '└─ ' : '├─ '}`\n const target = graph.nodes.get(usage.target)\n\n if (target === undefined) {\n return [`${branch}${usage.target}`]\n }\n\n if (visited.has(target.id)) {\n return [`${branch}${formatReactNodeLabel(target, cwd, color)} (circular)`]\n }\n\n const childLines = [`${branch}${formatReactNodeLabel(target, cwd, color)}`]\n const nextVisited = new Set(visited)\n nextVisited.add(target.id)\n const nextPrefix = `${prefix}${isLast ? ' ' : '│ '}`\n const childUsages = getFilteredUsages(target, graph, filter)\n\n childUsages.forEach((childUsage, index) => {\n childLines.push(\n ...renderUsage(\n childUsage,\n graph,\n cwd,\n filter,\n color,\n nextVisited,\n nextPrefix,\n index === childUsages.length - 1,\n ),\n )\n })\n\n return childLines\n}\n\nfunction formatReactNodeLabel(\n node: ReactUsageNode,\n cwd: string,\n color: boolean,\n): string {\n return `${formatReactSymbolLabel(node.name, node.kind, color)} (${toDisplayPath(node.filePath, cwd)})`\n}\n","import { colorizeUnusedMarker, resolveColorSupport } from './color.js'\nimport { toDisplayPath } from './path-utils.js'\nimport type {\n DependencyEdge,\n DependencyGraph,\n PrintTreeOptions,\n} from './types.js'\n\nexport function printDependencyTree(\n graph: DependencyGraph,\n options: PrintTreeOptions = {},\n): string {\n const cwd = options.cwd ?? graph.cwd\n const color = resolveColorSupport(options.color)\n const includeExternals = options.includeExternals ?? false\n const omitUnused = options.omitUnused ?? false\n const rootLines = [toDisplayPath(graph.entryId, cwd)]\n const visited = new Set<string>([graph.entryId])\n const entryNode = graph.nodes.get(graph.entryId)\n\n if (entryNode === undefined) {\n return rootLines.join('\\n')\n }\n\n const rootDependencies = filterDependencies(\n entryNode.dependencies,\n includeExternals,\n omitUnused,\n )\n\n rootDependencies.forEach((dependency, index) => {\n const isLast = index === rootDependencies.length - 1\n const lines = renderDependency(\n dependency,\n graph,\n visited,\n '',\n isLast,\n includeExternals,\n omitUnused,\n color,\n cwd,\n )\n rootLines.push(...lines)\n })\n\n return rootLines.join('\\n')\n}\n\nfunction renderDependency(\n dependency: DependencyEdge,\n graph: DependencyGraph,\n visited: ReadonlySet<string>,\n prefix: string,\n isLast: boolean,\n includeExternals: boolean,\n omitUnused: boolean,\n color: boolean,\n cwd: string,\n): string[] {\n const branch = `${prefix}${isLast ? '└─ ' : '├─ '}`\n const label = formatDependencyLabel(dependency, cwd, color)\n\n if (dependency.kind !== 'source') {\n return [`${branch}${label}`]\n }\n\n if (visited.has(dependency.target)) {\n return [`${branch}${label} (circular)`]\n }\n\n const childNode = graph.nodes.get(dependency.target)\n if (childNode === undefined) {\n return [`${branch}${label}`]\n }\n\n const nextPrefix = `${prefix}${isLast ? ' ' : '│ '}`\n const nextVisited = new Set(visited)\n nextVisited.add(dependency.target)\n\n const childLines = [`${branch}${label}`]\n const childDependencies = filterDependencies(\n childNode.dependencies,\n includeExternals,\n omitUnused,\n )\n\n childDependencies.forEach((childDependency, index) => {\n const isChildLast = index === childDependencies.length - 1\n childLines.push(\n ...renderDependency(\n childDependency,\n graph,\n nextVisited,\n nextPrefix,\n isChildLast,\n includeExternals,\n omitUnused,\n color,\n cwd,\n ),\n )\n })\n\n return childLines\n}\n\nfunction filterDependencies(\n dependencies: readonly DependencyEdge[],\n includeExternals: boolean,\n omitUnused: boolean,\n): DependencyEdge[] {\n return dependencies.filter((dependency) => {\n if (omitUnused && dependency.unused) {\n return false\n }\n\n if (dependency.kind === 'source' || dependency.kind === 'missing') {\n return true\n }\n\n return includeExternals\n })\n}\n\nfunction formatDependencyLabel(\n dependency: DependencyEdge,\n cwd: string,\n color: boolean,\n): string {\n const prefixes: string[] = []\n if (dependency.isTypeOnly) {\n prefixes.push('type')\n }\n\n if (dependency.referenceKind === 'require') {\n prefixes.push('require')\n } else if (dependency.referenceKind === 'dynamic-import') {\n prefixes.push('dynamic')\n } else if (dependency.referenceKind === 'export') {\n prefixes.push('re-export')\n } else if (dependency.referenceKind === 'import-equals') {\n prefixes.push('import=')\n }\n\n const annotation = prefixes.length > 0 ? `[${prefixes.join(', ')}] ` : ''\n\n if (dependency.kind === 'source') {\n return colorizeUnusedMarker(\n withUnusedSuffix(\n `${annotation}${toDisplayPath(dependency.target, cwd)}`,\n dependency.unused,\n ),\n color,\n )\n }\n\n if (dependency.kind === 'missing') {\n return colorizeUnusedMarker(\n withUnusedSuffix(\n `${annotation}${dependency.specifier} [missing]`,\n dependency.unused,\n ),\n color,\n )\n }\n\n if (dependency.kind === 'builtin') {\n return colorizeUnusedMarker(\n withUnusedSuffix(\n `${annotation}${dependency.target} [builtin]`,\n dependency.unused,\n ),\n color,\n )\n }\n\n return colorizeUnusedMarker(\n withUnusedSuffix(\n `${annotation}${dependency.target} [external]`,\n dependency.unused,\n ),\n color,\n )\n}\n\nfunction withUnusedSuffix(label: string, unused: boolean): string {\n return unused ? `${label} (unused)` : label\n}\n"],"mappings":";;;;;;;AAQA,SAAgB,oBACd,YACA,oBACc;CACd,MAAM,aACJ,uBAAuB,KAAA,IACnB,kBAAkB,WAAW,GAC7B,KAAK,QAAQ,YAAY,mBAAmB;AAElD,KAAI,eAAe,KAAA,EACjB,QAAO,EACL,iBAAiB,wBAAwB,EAC1C;CAGH,MAAM,aAAa,GAAG,eAAe,YAAY,GAAG,IAAI,SAAS;AACjE,KAAI,WAAW,UAAU,KAAA,EACvB,OAAM,IAAI,MACR,uCAAuC,WAAW,IAAI,iBACpD,WAAW,MACZ,GACF;CAGH,MAAM,SAAS,GAAG,2BAChB,WAAW,QACX,GAAG,KACH,KAAK,QAAQ,WAAW,EACxB,wBAAwB,EACxB,WACD;AAED,KAAI,OAAO,OAAO,SAAS,GAAG;EAC5B,MAAM,CAAC,cAAc,OAAO;AAC5B,MAAI,eAAe,KAAA,EACjB,OAAM,IAAI,MAAM,wCAAwC,WAAW,GAAG;AAGxE,QAAM,IAAI,MACR,wCAAwC,WAAW,IAAI,iBACrD,WACD,GACF;;AAGH,QAAO;EACL,MAAM;EACN,iBAAiB,OAAO;EACzB;;AAGH,SAAS,kBAAkB,YAAwC;CACjE,IAAI,mBAAmB,KAAK,QAAQ,WAAW;AAE/C,QAAO,MAAM;EACX,MAAM,eAAe,KAAK,KAAK,kBAAkB,gBAAgB;AACjE,MAAI,GAAG,IAAI,WAAW,aAAa,CACjC,QAAO;EAGT,MAAM,eAAe,KAAK,KAAK,kBAAkB,gBAAgB;AACjE,MAAI,GAAG,IAAI,WAAW,aAAa,CACjC,QAAO;EAGT,MAAM,kBAAkB,KAAK,QAAQ,iBAAiB;AACtD,MAAI,oBAAoB,iBACtB;AAGF,qBAAmB;;;AAIvB,SAAS,yBAA6C;AACpD,QAAO;EACL,SAAS;EACT,KAAK,GAAG,QAAQ;EAChB,QAAQ,GAAG,WAAW;EACtB,kBAAkB,GAAG,qBAAqB;EAC1C,QAAQ,GAAG,aAAa;EACxB,mBAAmB;EACnB,iBAAiB;EAClB;;AAGH,SAAS,iBAAiB,YAAmC;AAC3D,QAAO,GAAG,6BAA6B,WAAW,aAAa,KAAK;;;;AC7FtE,MAAa,oBAAoB,IAAI,IAAI;CACvC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAgB,kBAAkB,UAA0B;AAC1D,QAAO,KAAK,UAAU,SAAS;;AAGjC,SAAgB,cAAc,UAAkB,KAAqB;CACnE,MAAM,eAAe,KAAK,SAAS,KAAK,SAAS;AACjD,KAAI,iBAAiB,GACnB,QAAO;CAGT,MAAM,iBAAiB,aAAa,MAAM,KAAK,IAAI,CAAC,KAAK,IAAI;AAC7D,QAAO,eAAe,WAAW,KAAK,GAAG,WAAW;;AAGtD,SAAgB,iBAAiB,UAA2B;AAC1D,QAAO,kBAAkB,IAAI,KAAK,QAAQ,SAAS,CAAC,aAAa,CAAC;;;;ACDpE,MAAM,kBAAkB,IAAI,IAC1B,eAAe,SAAS,SAAS,CAAC,MAAM,QAAQ,OAAO,CAAC,CACzD;AAED,SAAgB,oBACd,WACA,UAA0B,EAAE,EACX;CACjB,MAAM,MAAM,KAAK,QAAQ,QAAQ,OAAO,QAAQ,KAAK,CAAC;CACtD,MAAM,oBAAoB,oBAAoB,KAAK,UAAU;CAC7D,MAAM,EAAE,iBAAiB,MAAM,eAAe,oBAC5C,KAAK,QAAQ,kBAAkB,EAC/B,QAAQ,WACT;CAED,MAAM,OAAgC;EACpC,YAAY,GAAG,IAAI;EACnB,UAAU,GAAG,IAAI;EACjB,iBAAiB,GAAG,IAAI;EACxB,2BAA2B;EAC3B,gBAAgB,GAAG,IAAI;EACvB,GAAI,GAAG,IAAI,aAAa,KAAA,IAAY,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,UAAU;EACvE;CAED,MAAM,wBAAQ,IAAI,KAA+B;CACjD,MAAM,UAAU,cAAc,mBAAmB,iBAAiB,IAAI;AAEtE,WAAU,mBAAmB,iBAAiB,MAD9B,QAAQ,gBAAgB,EACqB,SAAS,MAAM;AAE5E,QAAO;EACL;EACA,SAAS;EACT;EACA,GAAI,eAAe,KAAA,IAAY,EAAE,GAAG,EAAE,YAAY;EACnD;;AAGH,SAAgB,wBACd,OACA,UAEI,EAAE,EACE;CACR,MAAM,0BAAU,IAAI,KAAa;AACjC,QAAO,cACL,MAAM,SACN,OACA,SACA,QAAQ,cAAc,MACvB;;AAGH,SAAS,cACP,UACA,OACA,SACA,YACQ;CACR,MAAM,OAAO,MAAM,MAAM,IAAI,SAAS;CACtC,MAAM,cAAc,cAAc,UAAU,MAAM,IAAI;AAEtD,KAAI,SAAS,KAAA,EACX,QAAO;EACL,MAAM;EACN,MAAM;EACN,cAAc,EAAE;EACjB;AAGH,KAAI,QAAQ,IAAI,SAAS,CACvB,QAAO;EACL,MAAM;EACN,MAAM;EACN,cAAc,EAAE;EACjB;AAGH,SAAQ,IAAI,SAAS;CAErB,MAAM,eAAe,KAAK,aACvB,QAAQ,eAAe,CAAC,cAAc,CAAC,WAAW,OAAO,CACzD,KAAK,eAAe;AACnB,MAAI,WAAW,SAAS,SACtB,QAAO;GACL,WAAW,WAAW;GACtB,eAAe,WAAW;GAC1B,YAAY,WAAW;GACvB,QAAQ,WAAW;GACnB,MAAM,WAAW;GACjB,QACE,WAAW,SAAS,YAChB,WAAW,SACX,cAAc,WAAW,QAAQ,MAAM,IAAI;GAClD;AAGH,SAAO;GACL,WAAW,WAAW;GACtB,eAAe,WAAW;GAC1B,YAAY,WAAW;GACvB,QAAQ,WAAW;GACnB,MAAM,WAAW;GACjB,QAAQ,cAAc,WAAW,QAAQ,MAAM,IAAI;GACnD,MAAM,cACJ,WAAW,QACX,OACA,IAAI,IAAI,QAAQ,EAChB,WACD;GACF;GACD;AAEJ,QAAO;EACL,MAAM;EACN,MAAM,aAAa,MAAM,UAAU,UAAU;EAC7C;EACD;;AAGH,SAAS,UACP,UACA,iBACA,MACA,SACA,SACA,OACM;CACN,MAAM,iBAAiB,kBAAkB,SAAS;AAClD,KAAI,MAAM,IAAI,eAAe,CAC3B;CAOF,MAAM,eADa,wBAFjB,QAAQ,cAAc,eAAe,IAAI,iBAAiB,eAAe,EAEpB,QAAQ,CAC/B,KAAK,cACnC,kBAAkB,WAAW,gBAAgB,iBAAiB,KAAK,CACpE;AAED,OAAM,IAAI,gBAAgB;EACxB,IAAI;EACJ;EACD,CAAC;AAEF,MAAK,MAAM,cAAc,aACvB,KAAI,WAAW,SAAS,SACtB,WACE,WAAW,QACX,iBACA,MACA,SACA,SACA,MACD;;AAKP,SAAS,wBACP,YACA,SACmB;CACnB,MAAM,6BAAa,IAAI,KAA8B;CACrD,MAAM,gBAAgB,qBAAqB,YAAY,QAAQ;CAE/D,SAAS,aACP,WACA,eACA,YACA,QACM;EACN,MAAM,MAAM,GAAG,cAAc,GAAG,aAAa,SAAS,QAAQ,GAAG;EACjE,MAAM,WAAW,WAAW,IAAI,IAAI;AACpC,MAAI,aAAa,KAAA,GAAW;AAC1B,OAAI,SAAS,UAAU,CAAC,OACtB,YAAW,IAAI,KAAK;IAClB,GAAG;IACH,QAAQ;IACT,CAAC;AAEJ;;AAGF,aAAW,IAAI,KAAK;GAClB;GACA;GACA;GACA;GACD,CAAC;;CAGJ,SAAS,MAAM,MAAqB;AAClC,MACE,GAAG,oBAAoB,KAAK,IAC5B,GAAG,oBAAoB,KAAK,gBAAgB,CAE5C,cACE,KAAK,gBAAgB,MACrB,UACA,KAAK,cAAc,cAAc,OACjC,cAAc,IAAI,KAAK,IAAI,MAC5B;WAED,GAAG,oBAAoB,KAAK,IAC5B,KAAK,oBAAoB,KAAA,KACzB,GAAG,oBAAoB,KAAK,gBAAgB,CAE5C,cACE,KAAK,gBAAgB,MACrB,UACA,KAAK,cAAc,OACnB,MACD;WACQ,GAAG,0BAA0B,KAAK,EAAE;GAC7C,MAAM,kBAAkB,KAAK;AAC7B,OACE,GAAG,0BAA0B,gBAAgB,IAC7C,gBAAgB,eAAe,KAAA,KAC/B,GAAG,oBAAoB,gBAAgB,WAAW,CAElD,cACE,gBAAgB,WAAW,MAC3B,iBACA,OACA,MACD;aAEM,GAAG,iBAAiB,KAAK,EAAE;AACpC,OACE,KAAK,WAAW,SAAS,GAAG,WAAW,iBACvC,KAAK,UAAU,WAAW,GAC1B;IACA,MAAM,CAAC,YAAY,KAAK;AACxB,QAAI,aAAa,KAAA,KAAa,GAAG,oBAAoB,SAAS,CAC5D,cAAa,SAAS,MAAM,kBAAkB,OAAO,MAAM;;AAI/D,OACE,GAAG,aAAa,KAAK,WAAW,IAChC,KAAK,WAAW,SAAS,aACzB,KAAK,UAAU,WAAW,GAC1B;IACA,MAAM,CAAC,YAAY,KAAK;AACxB,QAAI,aAAa,KAAA,KAAa,GAAG,oBAAoB,SAAS,CAC5D,cAAa,SAAS,MAAM,WAAW,OAAO,MAAM;;;AAK1D,KAAG,aAAa,MAAM,MAAM;;AAG9B,OAAM,WAAW;AACjB,QAAO,CAAC,GAAG,WAAW,QAAQ,CAAC;;AAGjC,SAAS,kBACP,WACA,gBACA,iBACA,MACgB;CAChB,MAAM,YAAY,UAAU;AAC5B,KAAI,gBAAgB,IAAI,UAAU,CAChC,QAAO,WAAW,WAAW,WAAW,UAAU;CAGpD,MAAM,aAAa,GAAG,kBACpB,WACA,gBACA,iBACA,KACD,CAAC;AAEF,KAAI,eAAe,KAAA,GAAW;EAC5B,MAAM,eAAe,kBAAkB,WAAW,iBAAiB;AACnE,MACE,WAAW,2BACX,aAAa,SAAS,GAAG,KAAK,IAAI,cAAc,KAAK,MAAM,CAE3D,QAAO,WAAW,WAAW,YAAY,UAAU;AAGrD,MAAI,iBAAiB,aAAa,IAAI,CAAC,aAAa,SAAS,QAAQ,CACnE,QAAO,WAAW,WAAW,UAAU,aAAa;;AAIxD,KAAI,CAAC,UAAU,WAAW,IAAI,IAAI,CAAC,KAAK,WAAW,UAAU,CAC3D,QAAO,WAAW,WAAW,YAAY,UAAU;AAGrD,QAAO,WAAW,WAAW,WAAW,UAAU;;AAGpD,SAAS,WACP,WACA,MACA,QACgB;AAChB,QAAO;EACL,WAAW,UAAU;EACrB,eAAe,UAAU;EACzB,YAAY,UAAU;EACtB,QAAQ,UAAU;EAClB;EACA;EACD;;AAGH,SAAS,cACP,WACA,iBACA,KACY;CACZ,MAAM,OAAO,GAAG,mBAAmB,iBAAiB,KAAK;AACzD,MAAK,4BAA4B;AAEjC,KAAI,GAAG,IAAI,aAAa,KAAA,EACtB,MAAK,WAAW,GAAG,IAAI;AAGzB,QAAO,GAAG,cAAc;EACtB,WAAW,CAAC,UAAU;EACtB,SAAS;EACT;EACD,CAAC;;AAGJ,SAAS,iBAAiB,UAAiC;CACzD,MAAM,aAAa,GAAG,aAAa,UAAU,OAAO;AACpD,QAAO,GAAG,iBACR,UACA,YACA,GAAG,aAAa,QAChB,MACA,cAAc,SAAS,CACxB;;AAGH,SAAS,qBACP,YACA,SAC4C;CAC5C,MAAM,8BAAc,IAAI,KAMrB;CACH,MAAM,4CAA4B,IAAI,KAAsC;CAC5E,MAAM,qCAAqB,IAAI,KAAa;AAE5C,YAAW,WAAW,SAAS,cAAc;AAC3C,MACE,CAAC,GAAG,oBAAoB,UAAU,IAClC,UAAU,iBAAiB,KAAA,EAE3B;EAGF,MAAM,cAAc,4BAA4B,UAAU,aAAa;AACvE,MAAI,YAAY,WAAW,EACzB;AAGF,cAAY,IAAI,WAAW;GACzB,UAAU;GACV,MAAM;GACP,CAAC;AAEF,cAAY,SAAS,eAAe;AAClC,sBAAmB,IAAI,WAAW,KAAK;GAEvC,MAAM,SAAS,uBAAuB,SAAS,WAAW;AAC1D,OAAI,WAAW,KAAA,EACb;AAGF,6BAA0B,IAAI,QAAQ,UAAU;GAChD,MAAM,QAAQ,YAAY,IAAI,UAAU;AACxC,OAAI,UAAU,KAAA,EACZ,OAAM,WAAW;IAEnB;GACF;CAEF,SAAS,MAAM,MAAqB;AAClC,MAAI,GAAG,oBAAoB,KAAK,CAC9B;AAGF,MACE,GAAG,aAAa,KAAK,IACrB,mBAAmB,IAAI,KAAK,KAAK,IACjC,sBAAsB,KAAK,EAC3B;GACA,MAAM,SAAS,uBAAuB,SAAS,KAAK;GACpD,MAAM,cACJ,WAAW,KAAA,IAAY,KAAA,IAAY,0BAA0B,IAAI,OAAO;AAC1E,OAAI,gBAAgB,KAAA,GAAW;IAC7B,MAAM,QAAQ,YAAY,IAAI,YAAY;AAC1C,QAAI,UAAU,KAAA,EACZ,OAAM,OAAO;;;AAKnB,KAAG,aAAa,MAAM,MAAM;;AAG9B,OAAM,WAAW;AAEjB,QAAO,IAAI,IACT,CAAC,GAAG,YAAY,SAAS,CAAC,CAAC,KAAK,CAAC,aAAa,WAAW,CACvD,aACA,MAAM,YAAY,CAAC,MAAM,KAC1B,CAAC,CACH;;AAGH,SAAS,4BACP,cACiB;CACjB,MAAM,cAA+B,EAAE;AAEvC,KAAI,aAAa,SAAS,KAAA,EACxB,aAAY,KAAK,aAAa,KAAK;CAGrC,MAAM,gBAAgB,aAAa;AACnC,KAAI,kBAAkB,KAAA,EACpB,QAAO;AAGT,KAAI,GAAG,kBAAkB,cAAc,EAAE;AACvC,cAAY,KAAK,cAAc,KAAK;AACpC,SAAO;;AAGT,eAAc,SAAS,SAAS,YAAY;AAC1C,cAAY,KAAK,QAAQ,KAAK;GAC9B;AAEF,QAAO;;AAGT,SAAS,sBAAsB,MAA8B;CAC3D,MAAM,SAAS,KAAK;AAEpB,KAAI,GAAG,2BAA2B,OAAO,IAAI,OAAO,SAAS,KAC3D,QAAO;AAGT,KAAI,GAAG,gBAAgB,OAAO,IAAI,OAAO,UAAU,KACjD,QAAO;AAGT,KAAI,GAAG,qBAAqB,OAAO,IAAI,OAAO,SAAS,KACrD,QAAO;AAGT,KAAI,GAAG,iBAAiB,OAAO,IAAI,OAAO,iBAAiB,KACzD,QAAO;AAGT,KAAI,GAAG,eAAe,OAAO,IAAI,OAAO,SAAS,KAC/C,QAAO;AAGT,KAAI,GAAG,kBAAkB,OAAO,CAC9B,QAAO,OAAO,iBAAiB,QAAQ,OAAO,iBAAiB,KAAA;AAGjE,QAAO;;AAGT,SAAS,uBACP,SACA,MACuB;AACvB,KAAI;AACF,SAAO,QAAQ,oBAAoB,KAAK;SAClC;AACN;;;AAIJ,SAAS,cAAc,UAAiC;AACtD,SAAQ,KAAK,QAAQ,SAAS,CAAC,aAAa,EAA5C;EACE,KAAK;EACL,KAAK;EACL,KAAK,OACH,QAAO,GAAG,WAAW;EACvB,KAAK,OACH,QAAO,GAAG,WAAW;EACvB,KAAK,OACH,QAAO,GAAG,WAAW;EACvB,KAAK,QACH,QAAO,GAAG,WAAW;EACvB,QACE,QAAO,GAAG,WAAW;;;AAI3B,SAAS,oBAAoB,KAAa,WAA2B;CAEnE,MAAM,iBAAiB,kBADF,KAAK,QAAQ,KAAK,UAAU,CACK;AAEtD,KAAI,CAAC,GAAG,WAAW,eAAe,CAChC,OAAM,IAAI,MAAM,yBAAyB,YAAY;AAGvD,KAAI,CAAC,iBAAiB,eAAe,CACnC,OAAM,IAAI,MAAM,2CAA2C,YAAY;AAGzE,QAAO;;;;AC1dT,MAAM,sBAAsB,IAAI,IAAI;CAClC;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAgB,kBACd,WACA,UAA0B,EAAE,EACX;CACjB,MAAM,kBAAkB,oBAAoB,WAAW,QAAQ;CAC/D,MAAM,iBAAiB,IAAI,IAAY,CACrC,gBAAgB,SAChB,GAAG,gBAAgB,MAAM,MAAM,CAChC,CAAC;CACF,MAAM,+BAAe,IAAI,KAA2B;AAEpD,MAAK,MAAM,YAAY,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE;AACjD,MAAI,CAAC,iBAAiB,SAAS,IAAI,SAAS,SAAS,QAAQ,CAC3D;EAIF,MAAM,cAAc,UAAU,UADX,GAAG,aAAa,UAAU,OAAO,EACA;GAClD,SAAS;GACT,YAAY;GACb,CAAC;EAEF,MAAM,iBAAiB,gBAAgB,MAAM,IAAI,SAAS;EAC1D,MAAM,qCAAqB,IAAI,KAAqB;AACpD,kBAAgB,aAAa,SAAS,eAAe;AACnD,OAAI,WAAW,SAAS,SACtB,oBAAmB,IAAI,WAAW,WAAW,WAAW,OAAO;IAEjE;AAEF,eAAa,IACX,UACA,iBAAiB,YAAY,SAAS,UAAU,mBAAmB,CACpE;;CAGH,MAAM,wBAAQ,IAAI,KAA6B;AAC/C,MAAK,MAAM,gBAAgB,aAAa,QAAQ,CAC9C,MAAK,MAAM,UAAU,aAAa,YAAY,QAAQ,CACpD,OAAM,IAAI,OAAO,IAAI;EACnB,IAAI,OAAO;EACX,MAAM,OAAO;EACb,MAAM,OAAO;EACb,UAAU,OAAO;EACjB,aAAa,CAAC,GAAG,OAAO,YAAY,CAAC,MAAM;EAC3C,QAAQ,EAAE;EACX,CAAC;AAIN,MAAK,MAAM,gBAAgB,aAAa,QAAQ,CAC9C,cAAa,mBAAmB,SAAS,SAAS,cAAc;AAC9D,MAAI,QAAQ,eAAe,KAAA,EACzB;AAGF,MAAI,CAAC,WAAW,UAAU,IAAI,CAAC,WAAW,QAAQ,aAAa,CAC7D;EAGF,MAAM,eAAe,uBAAuB,SAAS,UAAU;AAC/D,MAAI,CAAC,MAAM,IAAI,aAAa,GAAG,CAC7B,OAAM,IAAI,aAAa,IAAI,aAAa;GAE1C;AAGJ,MAAK,MAAM,gBAAgB,aAAa,QAAQ,CAC9C,MAAK,MAAM,UAAU,aAAa,YAAY,QAAQ,EAAE;EACtD,MAAM,yBAAS,IAAI,KAA6B;AAEhD,SAAO,oBAAoB,SAAS,kBAAkB;GACpD,MAAM,WAAW,sBACf,cACA,cACA,eACA,YACD;AACD,OAAI,aAAa,KAAA,KAAa,aAAa,OAAO,GAChD,QAAO,IAAI,UAAU,YAAY;IAC/B,MAAM;IACN,QAAQ;IACT,CAAC;IAEJ;AAEF,SAAO,eAAe,SAAS,kBAAkB;GAC/C,MAAM,WAAW,sBACf,cACA,cACA,eACA,OACD;AACD,OAAI,aAAa,KAAA,KAAa,aAAa,OAAO,GAChD,QAAO,IAAI,QAAQ,YAAY;IAC7B,MAAM;IACN,QAAQ;IACT,CAAC;IAEJ;EAEF,MAAM,OAAO,MAAM,IAAI,OAAO,GAAG;AACjC,MAAI,SAAS,KAAA,EACX;EAGF,MAAM,eAAe,CAAC,GAAG,OAAO,QAAQ,CAAC,CAAC,MAAM,MAAM,UACpD,oBAAoB,KAAK,QAAQ,MAAM,QAAQ,MAAM,CACtD;AAED,QAAM,IAAI,OAAO,IAAI;GACnB,GAAG;GACH,QAAQ;GACT,CAAC;;AAIN,QAAO;EACL,KAAK,gBAAgB;EACrB,SAAS,gBAAgB;EACzB;EACD;;AAGH,SAAgB,6BACd,OACA,UAEI,EAAE,EACE;AAGR,QAAO;EACL,MAAM;EACN,OAJY,mBAAmB,OAAO,QAAQ,OAAO,CAIxC,KAAK,WAChB,wBACE,QACA,OACA,QAAQ,UAAU,uBAClB,IAAI,KAAK,CACV,CACF;EACF;;AAGH,SAAgB,mBACd,OACA,SAA2B,OACjB;CACV,MAAM,gBAAgB,2BAA2B,OAAO,OAAO;CAC/D,MAAM,gCAAgB,IAAI,KAAqB;AAE/C,eAAc,SAAS,SAAS;AAC9B,gBAAc,IAAI,KAAK,IAAI,EAAE;GAC7B;AAEF,eAAc,SAAS,SAAS;AAC9B,oBAAkB,MAAM,OAAO,OAAO,CAAC,SAAS,UAAU;AACxD,iBAAc,IACZ,MAAM,SACL,cAAc,IAAI,MAAM,OAAO,IAAI,KAAK,EAC1C;IACD;GACF;CAEF,MAAM,QAAQ,cACX,QAAQ,UAAU,cAAc,IAAI,KAAK,GAAG,IAAI,OAAO,EAAE,CACzD,KAAK,SAAS,KAAK,GAAG;AAEzB,KAAI,MAAM,SAAS,EACjB,QAAO,MAAM,MAAM,MAAM,UACvB,oBAAoB,MAAM,OAAO,MAAM,MAAM,CAC9C;AAGH,QAAO,cACJ,KAAK,SAAS,KAAK,GAAG,CACtB,MAAM,MAAM,UAAU,oBAAoB,MAAM,OAAO,MAAM,MAAM,CAAC;;AAGzE,SAAgB,kBACd,MACA,OACA,SAA2B,OACT;AAClB,QAAO,KAAK,OAAO,QAAQ,UAAU;EACnC,MAAM,aAAa,MAAM,MAAM,IAAI,MAAM,OAAO;AAChD,SAAO,eAAe,KAAA,KAAa,mBAAmB,YAAY,OAAO;GACzE;;AAGJ,SAAS,iBACP,SACA,UACA,oBACc;CACd,MAAM,gCAAgB,IAAI,KAAoC;AAE9D,SAAQ,KAAK,SAAS,cAAc;AAClC,8BAA4B,WAAW,UAAU,cAAc;GAC/D;CAEF,MAAM,qCAAqB,IAAI,KAA4B;CAC3D,MAAM,gCAAgB,IAAI,KAAqB;AAE/C,SAAQ,KAAK,SAAS,cAAc;AAClC,2BACE,WACA,oBACA,eACA,oBACA,cACD;GACD;AAEF,eAAc,SAAS,WAAW;AAChC,sBAAoB,OAAO;GAC3B;AAEF,QAAO;EACL;EACA;EACA;EACA,aAAa,IAAI,IACf,CAAC,GAAG,cAAc,QAAQ,CAAC,CAAC,KAAK,WAAW,CAAC,OAAO,IAAI,OAAO,CAAC,CACjE;EACD;EACD;;AAGH,SAAS,4BACP,WACA,UACA,eACM;AACN,SAAQ,UAAU,MAAlB;EACE,KAAK;AACH,qBAAkB,WAAW,UAAU,cAAc;AACrD;EACF,KAAK;AACH,aAAU,aAAa,SAAS,eAAe;AAC7C,sBAAkB,YAAY,UAAU,cAAc;KACtD;AACF;EACF,KAAK;AACH,OAAI,UAAU,gBAAgB,KAC5B,6BACE,UAAU,aACV,UACA,cACD;AAEH;EACF,KAAK;AACH,0BAAuB,WAAW,UAAU,cAAc;AAC1D;EACF,QACE;;;AAIN,SAAS,kBACP,aACA,UACA,eACM;CACN,MAAM,OAAO,YAAY,IAAI;AAC7B,KAAI,SAAS,KAAA,EACX;CAGF,MAAM,OAAO,oBAAoB,MAAM,YAAY;AACnD,KAAI,SAAS,KAAA,EACX;AAGF,eAAc,IACZ,MACA,oBAAoB,UAAU,MAAM,MAAM,YAAY,CACvD;;AAGH,SAAS,kBACP,YACA,UACA,eACM;AACN,KAAI,WAAW,GAAG,SAAS,gBAAgB,WAAW,SAAS,KAC7D;AAGF,KACE,WAAW,KAAK,SAAS,6BACzB,WAAW,KAAK,SAAS,qBAEzB;CAGF,MAAM,OAAO,WAAW,GAAG;CAC3B,MAAM,OAAO,oBAAoB,MAAM,WAAW,KAAK;AACvD,KAAI,SAAS,KAAA,EACX;AAGF,eAAc,IACZ,MACA,oBAAoB,UAAU,MAAM,MAAM,WAAW,KAAK,CAC3D;;AAGH,SAAS,uBACP,aACA,UACA,eACM;AACN,KACE,YAAY,YAAY,SAAS,yBACjC,YAAY,YAAY,SAAS,qBAEjC,mBAAkB,YAAY,aAAa,UAAU,cAAc;UAC1D,YAAY,YAAY,SAAS,2BAA2B;EACrE,MAAM,OAAO;EACb,MAAM,OAAO,YAAY,YAAY,OACjC,oBAAoB,MAAM,YAAY,YAAY,GAClD,KAAA;AACJ,MAAI,SAAS,KAAA,EACX,eAAc,IACZ,MACA,oBAAoB,UAAU,MAAM,MAAM,YAAY,YAAY,CACnE;;;AAKP,SAAS,oBACP,UACA,MACA,MACA,aACuB;AACvB,QAAO;EACL,IAAI,GAAG,SAAS,GAAG,KAAK,GAAG;EAC3B;EACA;EACA;EACA;EACA,6BAAa,IAAI,KAAa;EAC9B,qCAAqB,IAAI,KAAa;EACtC,gCAAgB,IAAI,KAAa;EAClC;;AAGH,SAAS,yBACP,WACA,oBACA,eACA,oBACA,eACM;AACN,SAAQ,UAAU,MAAlB;EACE,KAAK;AACH,yBAAsB,WAAW,oBAAoB,mBAAmB;AACxE;EACF,KAAK;AACH,uBAAoB,WAAW,eAAe,cAAc;AAC5D;EACF,KAAK;AACH,wBAAqB,WAAW,eAAe,cAAc;AAC7D;EACF,QACE;;;AAIN,SAAS,sBACP,aACA,oBACA,oBACM;AACN,KAAI,YAAY,eAAe,OAC7B;CAGF,MAAM,kBAAkB,YAAY,OAAO;CAC3C,MAAM,aAAa,mBAAmB,IAAI,YAAY,OAAO,MAAM;AAEnE,aAAY,WAAW,SAAS,cAAc;EAC5C,MAAM,UAAU,iBAAiB,WAAW,iBAAiB,WAAW;AACxE,MAAI,YAAY,KAAA,EACd;AAGF,qBAAmB,IAAI,QAAQ,WAAW;GACxC,cAAc,QAAQ;GACtB,iBAAiB,QAAQ;GACzB,GAAI,QAAQ,eAAe,KAAA,IACvB,EAAE,GACF,EAAE,YAAY,QAAQ,YAAY;GACvC,CAAC;GACF;;AAGJ,SAAS,iBACP,WACA,iBACA,YAQY;AACZ,KAAI,UAAU,SAAS,mBAAmB;AACxC,MAAI,UAAU,eAAe,OAC3B;AAGF,SAAO;GACL,WAAW,UAAU,MAAM;GAC3B,cAAc,mBAAmB,UAAU,SAAS;GACpD;GACA,GAAI,eAAe,KAAA,IAAY,EAAE,GAAG,EAAE,YAAY;GACnD;;AAGH,KAAI,UAAU,SAAS,yBACrB,QAAO;EACL,WAAW,UAAU,MAAM;EAC3B,cAAc;EACd;EACA,GAAI,eAAe,KAAA,IAAY,EAAE,GAAG,EAAE,YAAY;EACnD;;AAML,SAAS,oBACP,aACA,eACA,eACM;AACN,KAAI,YAAY,eAAe,OAC7B;AAGF,KAAI,YAAY,gBAAgB,MAAM;AACpC,MAAI,YAAY,YAAY,SAAS,uBAAuB;GAC1D,MAAM,OAAO,YAAY,YAAY,IAAI;AACzC,OAAI,SAAS,KAAA,EACX,kBAAiB,MAAM,MAAM,eAAe,cAAc;aAEnD,YAAY,YAAY,SAAS,sBAC1C,aAAY,YAAY,aAAa,SAAS,eAAe;AAC3D,OAAI,WAAW,GAAG,SAAS,aACzB,kBACE,WAAW,GAAG,MACd,WAAW,GAAG,MACd,eACA,cACD;IAEH;AAGJ;;AAGF,KAAI,YAAY,WAAW,KACzB;AAGF,aAAY,WAAW,SAAS,cAAc;AAC5C,MAAI,UAAU,eAAe,OAC3B;AAKF,mBAFkB,mBAAmB,UAAU,MAAM,EAChC,mBAAmB,UAAU,SAAS,EACjB,eAAe,cAAc;GACvE;;AAGJ,SAAS,qBACP,aACA,eACA,eACM;AACN,KACE,YAAY,YAAY,SAAS,yBACjC,YAAY,YAAY,SAAS,sBACjC;EACA,MAAM,YAAY,YAAY,YAAY,IAAI;AAC9C,MAAI,cAAc,KAAA,EAChB,kBAAiB,WAAW,WAAW,eAAe,cAAc;AAEtE;;AAGF,KAAI,YAAY,YAAY,SAAS,cAAc;AACjD,mBACE,YAAY,YAAY,MACxB,WACA,eACA,cACD;AACD;;AAGF,KAAI,YAAY,YAAY,SAAS,0BACnC,kBAAiB,WAAW,WAAW,eAAe,cAAc;;AAIxE,SAAS,iBACP,WACA,cACA,eACA,eACM;CACN,MAAM,SAAS,cAAc,IAAI,UAAU;AAC3C,KAAI,WAAW,KAAA,EACb;AAGF,QAAO,YAAY,IAAI,aAAa;AACpC,eAAc,IAAI,cAAc,OAAO,GAAG;;AAG5C,SAAS,oBAAoB,QAAqC;CAChE,MAAM,OACJ,OAAO,YAAY,SAAS,4BACxB,OAAO,YAAY,OACnB,OAAO,YAAY;AAEzB,KAAI,SAAS,KACX;AAGF,oBAAmB,OAAO,SAAS;AACjC,MAAI,KAAK,SAAS,cAAc;GAC9B,MAAM,OAAO,0BAA0B,KAAK;AAC5C,OAAI,SAAS,KAAA,EACX,QAAO,oBAAoB,IAAI,KAAK;AAEtC;;AAGF,MAAI,KAAK,SAAS,kBAAkB;GAClC,MAAM,gBAAgB,qBAAqB,KAAK;AAChD,OAAI,kBAAkB,KAAA,EACpB,QAAO,eAAe,IAAI,cAAc;GAG1C,MAAM,qBAAqB,uCAAuC,KAAK;AACvE,OAAI,uBAAuB,KAAA,EACzB,QAAO,oBAAoB,IAAI,mBAAmB;;GAGtD;;AAGJ,SAAS,oBACP,MACA,aAC6B;AAC7B,KAAI,WAAW,KAAK,CAClB,QAAO;AAGT,KAAI,gBAAgB,KAAK,IAAI,oBAAoB,YAAY,CAC3D,QAAO;;AAMX,SAAS,oBACP,aACS;AACT,KACE,YAAY,SAAS,6BACrB,YAAY,WAEZ,QAAO,mCAAmC,YAAY,KAAmB;CAG3E,MAAM,OAAO,YAAY;AACzB,KAAI,SAAS,KACX,QAAO;CAGT,IAAI,QAAQ;AACZ,oBAAmB,OAAO,SAAS;AACjC,MAAI,KAAK,SAAS,qBAAqB,KAAK,aAAa,KACvD;AAGF,MAAI,mCAAmC,KAAK,SAAS,CACnD,SAAQ;GAEV;AAEF,QAAO;;AAGT,SAAS,mCAAmC,YAAiC;CAC3E,IAAI,QAAQ;AAEZ,UAAS,aAAa,SAAS;AAC7B,MACE,KAAK,SAAS,gBACd,KAAK,SAAS,iBACb,KAAK,SAAS,oBAAoB,yBAAyB,KAAK,CAEjE,SAAQ;GAEV;AAEF,QAAO;;AAGT,SAAS,0BAA0B,MAAsC;CACvE,MAAM,OAAO,WAAW,KAAK,eAAe,KAAK;AACjD,QAAO,SAAS,KAAA,KAAa,gBAAgB,KAAK,GAAG,OAAO,KAAA;;AAG9D,SAAS,qBAAqB,MAA0C;CACtE,MAAM,aAAa,kBAAkB,KAAK,OAAO;AACjD,QAAO,eAAe,KAAA,KAAa,WAAW,WAAW,GACrD,aACA,KAAA;;AAGN,SAAS,uCACP,MACoB;AACpB,KAAI,CAAC,yBAAyB,KAAK,CACjC;CAGF,MAAM,CAAC,iBAAiB,KAAK;AAC7B,KAAI,kBAAkB,KAAA,KAAa,cAAc,SAAS,aACxD;AAGF,QAAO,gBAAgB,cAAc,KAAK,GAAG,cAAc,OAAO,KAAA;;AAGpE,SAAS,yBAAyB,MAA+B;CAC/D,MAAM,SAAS,iBAAiB,KAAK,OAAO;AAC5C,KAAI,OAAO,SAAS,sBAAsB,OAAO,SAC/C,QAAO;AAGT,QACE,OAAO,OAAO,SAAS,gBACvB,OAAO,OAAO,SAAS,WACvB,OAAO,SAAS,SAAS;;AAI7B,SAAS,WAAW,MAA0C;AAC5D,KAAI,KAAK,SAAS,gBAChB,QAAO,KAAK;;AAMhB,SAAS,kBAAkB,YAA4C;CACrE,MAAM,YAAY,iBAAiB,WAAW;AAC9C,QAAO,UAAU,SAAS,eAAe,UAAU,OAAO,KAAA;;AAG5D,SAAS,iBAAiB,YAAoC;CAC5D,IAAI,UAAU;AAEd,QAAO,MAAM;AACX,MACE,QAAQ,SAAS,6BACjB,QAAQ,SAAS,oBACjB,QAAQ,SAAS,2BACjB,QAAQ,SAAS,qBACjB,QAAQ,SAAS,uBACjB;AACA,aAAU,QAAQ;AAClB;;AAGF,SAAO;;;AAIX,SAAS,mBACP,MACA,OACM;AACN,UAAS,MAAM,OAAO,KAAK;;AAG7B,SAAS,SACP,MACA,OACA,uBAAuB,OACjB;AACN,OAAM,KAAK;CAEX,MAAM,OAAO,YAAY,KAAK;AAC9B,KAAI,SAAS,KAAA,EACX;AAGF,MAAK,SAAS,QAAQ;EACpB,MAAM,QAAS,KAA4C;AAC3D,YAAU,OAAO,OAAO,qBAAqB;GAC7C;;AAGJ,SAAS,UACP,OACA,OACA,sBACM;AACN,KAAI,MAAM,QAAQ,MAAM,EAAE;AACxB,QAAM,SAAS,UAAU;AACvB,aAAU,OAAO,OAAO,qBAAqB;IAC7C;AACF;;AAGF,KAAI,CAAC,OAAO,MAAM,CAChB;AAGF,KAAI,CAAC,wBAAwB,oBAAoB,IAAI,MAAM,KAAK,CAC9D;AAGF,UAAS,OAAO,OAAO,MAAM;;AAG/B,SAAS,OAAO,OAA+B;AAC7C,QACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,OAAQ,MAA4B,SAAS;;AAIjD,SAAS,sBACP,cACA,cACA,MACA,MACoB;CACpB,MAAM,cAAc,aAAa,cAAc,IAAI,KAAK;AACxD,KAAI,gBAAgB,KAAA,KAAa,YAAY,SAAS,KACpD,QAAO,YAAY;CAGrB,MAAM,gBAAgB,aAAa,mBAAmB,IAAI,KAAK;AAC/D,KAAI,kBAAkB,KAAA,EACpB;AAGF,KAAI,cAAc,eAAe,KAAA,EAC/B,QAAO,SAAS,SACZ,sBAAsB,eAAe,KAAK,GAC1C,KAAA;CAGN,MAAM,qBAAqB,aAAa,IAAI,cAAc,WAAW;AACrE,KAAI,uBAAuB,KAAA,EACzB;CAGF,MAAM,WAAW,mBAAmB,cAAc,IAChD,cAAc,aACf;AACD,KAAI,aAAa,KAAA,EACf;AAIF,QADqB,mBAAmB,YAAY,IAAI,SAAS,EAC5C,SAAS,OAAO,WAAW,KAAA;;AAGlD,SAAS,uBACP,SACA,WACgB;CAChB,MAAM,OAAO,oBAAoB,SAAS,UAAU;AAEpD,QAAO;EACL,IAAI,sBAAsB,SAAS,UAAU;EAC7C;EACA,MAAM;EACN,UAAU,QAAQ;EAClB,aAAa,CAAC,QAAQ,aAAa;EACnC,QAAQ,EAAE;EACX;;AAGH,SAAS,sBACP,SACA,WACQ;AACR,QAAO,YAAY,QAAQ,gBAAgB,QAAQ,oBAAoB,SAAS,UAAU;;AAG5F,SAAS,oBACP,SACA,WACQ;AACR,QAAO,QAAQ,iBAAiB,YAAY,YAAY,QAAQ;;AAGlE,SAAS,2BACP,OACA,QACkB;AAClB,QAAO,CAAC,GAAG,MAAM,MAAM,QAAQ,CAAC,CAC7B,QAAQ,SAAS,mBAAmB,MAAM,OAAO,CAAC,CAClD,MAAM,MAAM,UAAU,kBAAkB,MAAM,MAAM,CAAC;;AAG1D,SAAS,mBACP,MACA,QACS;AACT,QAAO,WAAW,SAAS,KAAK,SAAS;;AAG3C,SAAS,wBACP,QACA,OACA,QACA,SAC0B;CAC1B,MAAM,OAAO,MAAM,MAAM,IAAI,OAAO;AACpC,KAAI,SAAS,KAAA,EACX,QAAO;EACL,IAAI;EACJ,MAAM;EACN,YAAY;EACZ,UAAU;EACV,aAAa,EAAE;EACf,QAAQ,EAAE;EACX;AAGH,KAAI,QAAQ,IAAI,OAAO,CACrB,QAAO;EACL,IAAI,KAAK;EACT,MAAM,KAAK;EACX,YAAY;EACZ,UAAU,cAAc,KAAK,UAAU,MAAM,IAAI;EACjD,aAAa,KAAK;EAClB,QAAQ,EAAE;EACX;CAGH,MAAM,cAAc,IAAI,IAAI,QAAQ;AACpC,aAAY,IAAI,OAAO;AAEvB,QAAO;EACL,IAAI,KAAK;EACT,MAAM,KAAK;EACX,YAAY,KAAK;EACjB,UAAU,cAAc,KAAK,UAAU,MAAM,IAAI;EACjD,aAAa,KAAK;EAClB,QAAQ,kBAAkB,MAAM,OAAO,OAAO,CAAC,KAAK,WAAW;GAC7D,MAAM,MAAM;GACZ,UAAU,MAAM;GAChB,MAAM,wBAAwB,MAAM,QAAQ,OAAO,QAAQ,YAAY;GACxE,EAAE;EACJ;;AAGH,SAAS,oBACP,QACA,SACA,OACQ;CACR,MAAM,OAAO,MAAM,IAAI,OAAO;CAC9B,MAAM,QAAQ,MAAM,IAAI,QAAQ;AAEhC,KAAI,SAAS,KAAA,KAAa,UAAU,KAAA,EAClC,QAAO,OAAO,cAAc,QAAQ;AAGtC,QAAO,kBAAkB,MAAM,MAAM;;AAGvC,SAAS,kBACP,MACA,OACQ;AACR,QACE,KAAK,SAAS,cAAc,MAAM,SAAS,IAC3C,KAAK,KAAK,cAAc,MAAM,KAAK,IACnC,KAAK,KAAK,cAAc,MAAM,KAAK;;AAIvC,SAAS,mBAAmB,MAAgC;AAC1D,QAAO,KAAK,SAAS,YAAY,KAAK,QAAQ,KAAK;;AAGrD,SAAS,WAAW,MAAuB;AACzC,QAAO,eAAe,KAAK,KAAK;;AAGlC,SAAS,gBAAgB,MAAuB;AAC9C,QAAO,SAAS,KAAK,KAAK;;;;ACn+B5B,MAAM,aAAa;AACnB,MAAM,iBAAiB;AACvB,MAAM,YAAY;AAClB,MAAM,cAAc;AAQpB,SAAgB,oBACd,OAAkB,QAClB,UAAsC,EAAE,EAC/B;AACT,KAAI,SAAS,KACX,QAAO;AAGT,KAAI,SAAS,MACX,QAAO;CAGT,MAAM,aACJ,gBAAgB,UAAU,QAAQ,aAAaA,UAAQ,IAAI;AAC7D,KAAI,eAAe,KAAA,EACjB,QAAO,eAAe;AAIxB,MADgB,aAAa,UAAU,QAAQ,UAAUA,UAAQ,IAAI,cACrD,KAAA,EACd,QAAO;AAIT,SADc,WAAW,UAAU,QAAQ,QAAQA,UAAQ,OAAO,WACjD;;AAGnB,SAAgB,qBAAqB,MAAc,SAA0B;AAC3E,KAAI,CAAC,QACH,QAAO;AAGT,QAAO,KAAK,WAAW,YAAY,GAAG,YAAY,UAAU,aAAa;;AAG3E,SAAgB,uBACd,MACA,MACA,SACQ;CACR,MAAM,QAAQ,GAAG,KAAK,IAAI,KAAK;AAC/B,KAAI,CAAC,QACH,QAAO;AAIT,QAAO,GADO,SAAS,cAAc,iBAAiB,YACpC,QAAQ;;;;ACnD5B,SAAgB,oBACd,OACA,UAAiC,EAAE,EAC3B;CACR,MAAM,MAAM,QAAQ,OAAO,MAAM;CACjC,MAAM,QAAQ,oBAAoB,QAAQ,MAAM;CAChD,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,QAAQ,mBAAmB,OAAO,OAAO;AAE/C,KAAI,MAAM,WAAW,EACnB,QAAO;CAGT,MAAM,QAAkB,EAAE;AAC1B,OAAM,SAAS,QAAQ,UAAU;EAC/B,MAAM,OAAO,MAAM,MAAM,IAAI,OAAO;AACpC,MAAI,SAAS,KAAA,EACX;AAGF,QAAM,KAAK,qBAAqB,MAAM,KAAK,MAAM,CAAC;EAClD,MAAM,SAAS,kBAAkB,MAAM,OAAO,OAAO;AACrD,SAAO,SAAS,OAAO,eAAe;AACpC,SAAM,KACJ,GAAG,YACD,OACA,OACA,KACA,QACA,OACA,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,EAClB,IACA,eAAe,OAAO,SAAS,EAChC,CACF;IACD;AAEF,MAAI,QAAQ,MAAM,SAAS,EACzB,OAAM,KAAK,GAAG;GAEhB;AAEF,QAAO,MAAM,KAAK,KAAK;;AAGzB,SAAS,YACP,OACA,OACA,KACA,QACA,OACA,SACA,QACA,QACU;CACV,MAAM,SAAS,GAAG,SAAS,SAAS,QAAQ;CAC5C,MAAM,SAAS,MAAM,MAAM,IAAI,MAAM,OAAO;AAE5C,KAAI,WAAW,KAAA,EACb,QAAO,CAAC,GAAG,SAAS,MAAM,SAAS;AAGrC,KAAI,QAAQ,IAAI,OAAO,GAAG,CACxB,QAAO,CAAC,GAAG,SAAS,qBAAqB,QAAQ,KAAK,MAAM,CAAC,aAAa;CAG5E,MAAM,aAAa,CAAC,GAAG,SAAS,qBAAqB,QAAQ,KAAK,MAAM,GAAG;CAC3E,MAAM,cAAc,IAAI,IAAI,QAAQ;AACpC,aAAY,IAAI,OAAO,GAAG;CAC1B,MAAM,aAAa,GAAG,SAAS,SAAS,QAAQ;CAChD,MAAM,cAAc,kBAAkB,QAAQ,OAAO,OAAO;AAE5D,aAAY,SAAS,YAAY,UAAU;AACzC,aAAW,KACT,GAAG,YACD,YACA,OACA,KACA,QACA,OACA,aACA,YACA,UAAU,YAAY,SAAS,EAChC,CACF;GACD;AAEF,QAAO;;AAGT,SAAS,qBACP,MACA,KACA,OACQ;AACR,QAAO,GAAG,uBAAuB,KAAK,MAAM,KAAK,MAAM,MAAM,CAAC,IAAI,cAAc,KAAK,UAAU,IAAI,CAAC;;;;ACjGtG,SAAgB,oBACd,OACA,UAA4B,EAAE,EACtB;CACR,MAAM,MAAM,QAAQ,OAAO,MAAM;CACjC,MAAM,QAAQ,oBAAoB,QAAQ,MAAM;CAChD,MAAM,mBAAmB,QAAQ,oBAAoB;CACrD,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,YAAY,CAAC,cAAc,MAAM,SAAS,IAAI,CAAC;CACrD,MAAM,UAAU,IAAI,IAAY,CAAC,MAAM,QAAQ,CAAC;CAChD,MAAM,YAAY,MAAM,MAAM,IAAI,MAAM,QAAQ;AAEhD,KAAI,cAAc,KAAA,EAChB,QAAO,UAAU,KAAK,KAAK;CAG7B,MAAM,mBAAmB,mBACvB,UAAU,cACV,kBACA,WACD;AAED,kBAAiB,SAAS,YAAY,UAAU;EAE9C,MAAM,QAAQ,iBACZ,YACA,OACA,SACA,IALa,UAAU,iBAAiB,SAAS,GAOjD,kBACA,YACA,OACA,IACD;AACD,YAAU,KAAK,GAAG,MAAM;GACxB;AAEF,QAAO,UAAU,KAAK,KAAK;;AAG7B,SAAS,iBACP,YACA,OACA,SACA,QACA,QACA,kBACA,YACA,OACA,KACU;CACV,MAAM,SAAS,GAAG,SAAS,SAAS,QAAQ;CAC5C,MAAM,QAAQ,sBAAsB,YAAY,KAAK,MAAM;AAE3D,KAAI,WAAW,SAAS,SACtB,QAAO,CAAC,GAAG,SAAS,QAAQ;AAG9B,KAAI,QAAQ,IAAI,WAAW,OAAO,CAChC,QAAO,CAAC,GAAG,SAAS,MAAM,aAAa;CAGzC,MAAM,YAAY,MAAM,MAAM,IAAI,WAAW,OAAO;AACpD,KAAI,cAAc,KAAA,EAChB,QAAO,CAAC,GAAG,SAAS,QAAQ;CAG9B,MAAM,aAAa,GAAG,SAAS,SAAS,QAAQ;CAChD,MAAM,cAAc,IAAI,IAAI,QAAQ;AACpC,aAAY,IAAI,WAAW,OAAO;CAElC,MAAM,aAAa,CAAC,GAAG,SAAS,QAAQ;CACxC,MAAM,oBAAoB,mBACxB,UAAU,cACV,kBACA,WACD;AAED,mBAAkB,SAAS,iBAAiB,UAAU;EACpD,MAAM,cAAc,UAAU,kBAAkB,SAAS;AACzD,aAAW,KACT,GAAG,iBACD,iBACA,OACA,aACA,YACA,aACA,kBACA,YACA,OACA,IACD,CACF;GACD;AAEF,QAAO;;AAGT,SAAS,mBACP,cACA,kBACA,YACkB;AAClB,QAAO,aAAa,QAAQ,eAAe;AACzC,MAAI,cAAc,WAAW,OAC3B,QAAO;AAGT,MAAI,WAAW,SAAS,YAAY,WAAW,SAAS,UACtD,QAAO;AAGT,SAAO;GACP;;AAGJ,SAAS,sBACP,YACA,KACA,OACQ;CACR,MAAM,WAAqB,EAAE;AAC7B,KAAI,WAAW,WACb,UAAS,KAAK,OAAO;AAGvB,KAAI,WAAW,kBAAkB,UAC/B,UAAS,KAAK,UAAU;UACf,WAAW,kBAAkB,iBACtC,UAAS,KAAK,UAAU;UACf,WAAW,kBAAkB,SACtC,UAAS,KAAK,YAAY;UACjB,WAAW,kBAAkB,gBACtC,UAAS,KAAK,UAAU;CAG1B,MAAM,aAAa,SAAS,SAAS,IAAI,IAAI,SAAS,KAAK,KAAK,CAAC,MAAM;AAEvE,KAAI,WAAW,SAAS,SACtB,QAAO,qBACL,iBACE,GAAG,aAAa,cAAc,WAAW,QAAQ,IAAI,IACrD,WAAW,OACZ,EACD,MACD;AAGH,KAAI,WAAW,SAAS,UACtB,QAAO,qBACL,iBACE,GAAG,aAAa,WAAW,UAAU,aACrC,WAAW,OACZ,EACD,MACD;AAGH,KAAI,WAAW,SAAS,UACtB,QAAO,qBACL,iBACE,GAAG,aAAa,WAAW,OAAO,aAClC,WAAW,OACZ,EACD,MACD;AAGH,QAAO,qBACL,iBACE,GAAG,aAAa,WAAW,OAAO,cAClC,WAAW,OACZ,EACD,MACD;;AAGH,SAAS,iBAAiB,OAAe,QAAyB;AAChE,QAAO,SAAS,GAAG,MAAM,aAAa"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foresthouse",
3
- "version": "1.0.0-dev.2",
3
+ "version": "1.0.0-dev.4",
4
4
  "description": "A Node.js CLI that reads JavaScript and TypeScript entry files and prints an import tree.",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.32.1",
@@ -1 +0,0 @@
1
- {"version":3,"file":"tree-Cp8CNmeY.mjs","names":[],"sources":["../src/config.ts","../src/path-utils.ts","../src/analyzer.ts","../src/react-analyzer.ts","../src/react-tree.ts","../src/tree.ts"],"sourcesContent":["import path from 'node:path'\nimport ts from 'typescript'\n\nexport interface LoadedConfig {\n readonly path?: string\n readonly compilerOptions: ts.CompilerOptions\n}\n\nexport function loadCompilerOptions(\n searchFrom: string,\n explicitConfigPath?: string,\n): LoadedConfig {\n const configPath =\n explicitConfigPath === undefined\n ? findNearestConfig(searchFrom)\n : path.resolve(searchFrom, explicitConfigPath)\n\n if (configPath === undefined) {\n return {\n compilerOptions: defaultCompilerOptions(),\n }\n }\n\n const readResult = ts.readConfigFile(configPath, ts.sys.readFile)\n if (readResult.error !== undefined) {\n throw new Error(\n `Failed to read TypeScript config at ${configPath}: ${formatDiagnostic(\n readResult.error,\n )}`,\n )\n }\n\n const parsed = ts.parseJsonConfigFileContent(\n readResult.config,\n ts.sys,\n path.dirname(configPath),\n defaultCompilerOptions(),\n configPath,\n )\n\n if (parsed.errors.length > 0) {\n const [firstError] = parsed.errors\n if (firstError === undefined) {\n throw new Error(`Failed to parse TypeScript config at ${configPath}.`)\n }\n\n throw new Error(\n `Failed to parse TypeScript config at ${configPath}: ${formatDiagnostic(\n firstError,\n )}`,\n )\n }\n\n return {\n path: configPath,\n compilerOptions: parsed.options,\n }\n}\n\nfunction findNearestConfig(searchFrom: string): string | undefined {\n let currentDirectory = path.resolve(searchFrom)\n\n while (true) {\n const tsconfigPath = path.join(currentDirectory, 'tsconfig.json')\n if (ts.sys.fileExists(tsconfigPath)) {\n return tsconfigPath\n }\n\n const jsconfigPath = path.join(currentDirectory, 'jsconfig.json')\n if (ts.sys.fileExists(jsconfigPath)) {\n return jsconfigPath\n }\n\n const parentDirectory = path.dirname(currentDirectory)\n if (parentDirectory === currentDirectory) {\n return undefined\n }\n\n currentDirectory = parentDirectory\n }\n}\n\nfunction defaultCompilerOptions(): ts.CompilerOptions {\n return {\n allowJs: true,\n jsx: ts.JsxEmit.ReactJSX,\n module: ts.ModuleKind.NodeNext,\n moduleResolution: ts.ModuleResolutionKind.NodeNext,\n target: ts.ScriptTarget.ESNext,\n resolveJsonModule: true,\n esModuleInterop: true,\n }\n}\n\nfunction formatDiagnostic(diagnostic: ts.Diagnostic): string {\n return ts.flattenDiagnosticMessageText(diagnostic.messageText, '\\n')\n}\n","import path from 'node:path'\n\nexport const SOURCE_EXTENSIONS = new Set([\n '.js',\n '.jsx',\n '.ts',\n '.tsx',\n '.mjs',\n '.cjs',\n '.mts',\n '.cts',\n])\n\nexport function normalizeFilePath(filePath: string): string {\n return path.normalize(filePath)\n}\n\nexport function toDisplayPath(filePath: string, cwd: string): string {\n const relativePath = path.relative(cwd, filePath)\n if (relativePath === '') {\n return '.'\n }\n\n const normalizedPath = relativePath.split(path.sep).join('/')\n return normalizedPath.startsWith('..') ? filePath : normalizedPath\n}\n\nexport function isSourceCodeFile(filePath: string): boolean {\n return SOURCE_EXTENSIONS.has(path.extname(filePath).toLowerCase())\n}\n","import fs from 'node:fs'\nimport { builtinModules } from 'node:module'\nimport path from 'node:path'\nimport ts from 'typescript'\n\nimport { loadCompilerOptions } from './config.js'\nimport {\n isSourceCodeFile,\n normalizeFilePath,\n toDisplayPath,\n} from './path-utils.js'\nimport type {\n AnalyzeOptions,\n DependencyEdge,\n DependencyGraph,\n DependencyKind,\n ReferenceKind,\n SourceModuleNode,\n} from './types.js'\n\ninterface ModuleReference {\n readonly specifier: string\n readonly referenceKind: ReferenceKind\n readonly isTypeOnly: boolean\n}\n\nconst BUILTIN_MODULES = new Set(\n builtinModules.flatMap((name) => [name, `node:${name}`]),\n)\n\nexport function analyzeDependencies(\n entryFile: string,\n options: AnalyzeOptions = {},\n): DependencyGraph {\n const cwd = path.resolve(options.cwd ?? process.cwd())\n const resolvedEntryPath = resolveExistingPath(cwd, entryFile)\n const { compilerOptions, path: configPath } = loadCompilerOptions(\n path.dirname(resolvedEntryPath),\n options.configPath,\n )\n\n const host: ts.ModuleResolutionHost = {\n fileExists: ts.sys.fileExists,\n readFile: ts.sys.readFile,\n directoryExists: ts.sys.directoryExists,\n getCurrentDirectory: () => cwd,\n getDirectories: ts.sys.getDirectories,\n ...(ts.sys.realpath === undefined ? {} : { realpath: ts.sys.realpath }),\n }\n\n const nodes = new Map<string, SourceModuleNode>()\n visitFile(resolvedEntryPath, compilerOptions, host, nodes)\n\n return {\n cwd,\n entryId: resolvedEntryPath,\n nodes,\n ...(configPath === undefined ? {} : { configPath }),\n }\n}\n\nexport function graphToSerializableTree(graph: DependencyGraph): object {\n const visited = new Set<string>()\n return serializeNode(graph.entryId, graph, visited)\n}\n\nfunction serializeNode(\n filePath: string,\n graph: DependencyGraph,\n visited: Set<string>,\n): object {\n const node = graph.nodes.get(filePath)\n const displayPath = toDisplayPath(filePath, graph.cwd)\n\n if (node === undefined) {\n return {\n path: displayPath,\n kind: 'missing',\n dependencies: [],\n }\n }\n\n if (visited.has(filePath)) {\n return {\n path: displayPath,\n kind: 'circular',\n dependencies: [],\n }\n }\n\n visited.add(filePath)\n\n const dependencies = node.dependencies.map((dependency) => {\n if (dependency.kind !== 'source') {\n return {\n specifier: dependency.specifier,\n referenceKind: dependency.referenceKind,\n isTypeOnly: dependency.isTypeOnly,\n kind: dependency.kind,\n target:\n dependency.kind === 'missing'\n ? dependency.target\n : toDisplayPath(dependency.target, graph.cwd),\n }\n }\n\n return {\n specifier: dependency.specifier,\n referenceKind: dependency.referenceKind,\n isTypeOnly: dependency.isTypeOnly,\n kind: dependency.kind,\n target: toDisplayPath(dependency.target, graph.cwd),\n node: serializeNode(dependency.target, graph, new Set(visited)),\n }\n })\n\n return {\n path: displayPath,\n kind: filePath === graph.entryId ? 'entry' : 'source',\n dependencies,\n }\n}\n\nfunction visitFile(\n filePath: string,\n compilerOptions: ts.CompilerOptions,\n host: ts.ModuleResolutionHost,\n nodes: Map<string, SourceModuleNode>,\n): void {\n const normalizedPath = normalizeFilePath(filePath)\n if (nodes.has(normalizedPath)) {\n return\n }\n\n const sourceText = fs.readFileSync(normalizedPath, 'utf8')\n const sourceFile = ts.createSourceFile(\n normalizedPath,\n sourceText,\n ts.ScriptTarget.Latest,\n true,\n getScriptKind(normalizedPath),\n )\n\n const references = collectModuleReferences(sourceFile)\n const dependencies = references.map((reference) =>\n resolveDependency(reference, normalizedPath, compilerOptions, host),\n )\n\n nodes.set(normalizedPath, {\n id: normalizedPath,\n dependencies,\n })\n\n for (const dependency of dependencies) {\n if (dependency.kind === 'source') {\n visitFile(dependency.target, compilerOptions, host, nodes)\n }\n }\n}\n\nfunction collectModuleReferences(sourceFile: ts.SourceFile): ModuleReference[] {\n const references: ModuleReference[] = []\n const seen = new Set<string>()\n\n function addReference(\n specifier: string,\n referenceKind: ReferenceKind,\n isTypeOnly: boolean,\n ): void {\n const key = `${referenceKind}:${isTypeOnly ? 'type' : 'value'}:${specifier}`\n if (seen.has(key)) {\n return\n }\n\n seen.add(key)\n references.push({\n specifier,\n referenceKind,\n isTypeOnly,\n })\n }\n\n function visit(node: ts.Node): void {\n if (\n ts.isImportDeclaration(node) &&\n ts.isStringLiteralLike(node.moduleSpecifier)\n ) {\n addReference(\n node.moduleSpecifier.text,\n 'import',\n node.importClause?.isTypeOnly ?? false,\n )\n } else if (\n ts.isExportDeclaration(node) &&\n node.moduleSpecifier !== undefined &&\n ts.isStringLiteralLike(node.moduleSpecifier)\n ) {\n addReference(\n node.moduleSpecifier.text,\n 'export',\n node.isTypeOnly ?? false,\n )\n } else if (ts.isImportEqualsDeclaration(node)) {\n const moduleReference = node.moduleReference\n if (\n ts.isExternalModuleReference(moduleReference) &&\n moduleReference.expression !== undefined &&\n ts.isStringLiteralLike(moduleReference.expression)\n ) {\n addReference(moduleReference.expression.text, 'import-equals', false)\n }\n } else if (ts.isCallExpression(node)) {\n if (\n node.expression.kind === ts.SyntaxKind.ImportKeyword &&\n node.arguments.length === 1\n ) {\n const [argument] = node.arguments\n if (argument !== undefined && ts.isStringLiteralLike(argument)) {\n addReference(argument.text, 'dynamic-import', false)\n }\n }\n\n if (\n ts.isIdentifier(node.expression) &&\n node.expression.text === 'require' &&\n node.arguments.length === 1\n ) {\n const [argument] = node.arguments\n if (argument !== undefined && ts.isStringLiteralLike(argument)) {\n addReference(argument.text, 'require', false)\n }\n }\n }\n\n ts.forEachChild(node, visit)\n }\n\n visit(sourceFile)\n return references\n}\n\nfunction resolveDependency(\n reference: ModuleReference,\n containingFile: string,\n compilerOptions: ts.CompilerOptions,\n host: ts.ModuleResolutionHost,\n): DependencyEdge {\n const specifier = reference.specifier\n if (BUILTIN_MODULES.has(specifier)) {\n return createEdge(reference, 'builtin', specifier)\n }\n\n const resolution = ts.resolveModuleName(\n specifier,\n containingFile,\n compilerOptions,\n host,\n ).resolvedModule\n\n if (resolution !== undefined) {\n const resolvedPath = normalizeFilePath(resolution.resolvedFileName)\n if (\n resolution.isExternalLibraryImport ||\n resolvedPath.includes(`${path.sep}node_modules${path.sep}`)\n ) {\n return createEdge(reference, 'external', specifier)\n }\n\n if (isSourceCodeFile(resolvedPath) && !resolvedPath.endsWith('.d.ts')) {\n return createEdge(reference, 'source', resolvedPath)\n }\n }\n\n if (!specifier.startsWith('.') && !path.isAbsolute(specifier)) {\n return createEdge(reference, 'external', specifier)\n }\n\n return createEdge(reference, 'missing', specifier)\n}\n\nfunction createEdge(\n reference: ModuleReference,\n kind: DependencyKind,\n target: string,\n): DependencyEdge {\n return {\n specifier: reference.specifier,\n referenceKind: reference.referenceKind,\n isTypeOnly: reference.isTypeOnly,\n kind,\n target,\n }\n}\n\nfunction getScriptKind(filePath: string): ts.ScriptKind {\n switch (path.extname(filePath).toLowerCase()) {\n case '.js':\n case '.mjs':\n case '.cjs':\n return ts.ScriptKind.JS\n case '.jsx':\n return ts.ScriptKind.JSX\n case '.tsx':\n return ts.ScriptKind.TSX\n case '.json':\n return ts.ScriptKind.JSON\n default:\n return ts.ScriptKind.TS\n }\n}\n\nfunction resolveExistingPath(cwd: string, entryFile: string): string {\n const absolutePath = path.resolve(cwd, entryFile)\n const normalizedPath = normalizeFilePath(absolutePath)\n\n if (!fs.existsSync(normalizedPath)) {\n throw new Error(`Entry file not found: ${entryFile}`)\n }\n\n if (!isSourceCodeFile(normalizedPath)) {\n throw new Error(`Entry file must be a JS/TS source file: ${entryFile}`)\n }\n\n return normalizedPath\n}\n","import fs from 'node:fs'\nimport type {\n ArrowFunctionExpression,\n CallExpression,\n ExportDefaultDeclaration,\n ExportNamedDeclaration,\n Expression,\n FunctionBody,\n ImportDeclaration,\n ImportDeclarationSpecifier,\n JSXElement,\n JSXElementName,\n JSXFragment,\n ModuleExportName,\n Node,\n Function as OxcFunction,\n Program,\n Statement,\n VariableDeclarator,\n} from 'oxc-parser'\nimport { parseSync, visitorKeys } from 'oxc-parser'\n\nimport { analyzeDependencies } from './analyzer.js'\nimport { isSourceCodeFile, toDisplayPath } from './path-utils.js'\nimport type {\n AnalyzeOptions,\n ReactSymbolKind,\n ReactUsageEdge,\n ReactUsageFilter,\n ReactUsageGraph,\n ReactUsageNode,\n} from './types.js'\n\ninterface PendingReactUsageNode {\n readonly id: string\n readonly name: string\n readonly kind: ReactSymbolKind\n readonly filePath: string\n readonly declaration: OxcFunction | ArrowFunctionExpression\n readonly exportNames: Set<string>\n readonly componentReferences: Set<string>\n readonly hookReferences: Set<string>\n}\n\ninterface ImportBinding {\n readonly importedName: string\n readonly sourceSpecifier: string\n readonly sourcePath?: string\n}\n\ninterface FileAnalysis {\n readonly filePath: string\n readonly importsByLocalName: Map<string, ImportBinding>\n readonly exportsByName: Map<string, string>\n readonly symbolsById: Map<string, PendingReactUsageNode>\n readonly symbolsByName: Map<string, PendingReactUsageNode>\n}\n\ninterface SerializedReactUsageNode {\n readonly id: string\n readonly name: string\n readonly symbolKind: ReactSymbolKind | 'circular'\n readonly filePath: string\n readonly exportNames: readonly string[]\n readonly usages: readonly SerializedReactUsageEdge[]\n}\n\ninterface SerializedReactUsageEdge {\n readonly kind: ReactUsageEdge['kind']\n readonly targetId: string\n readonly node: SerializedReactUsageNode\n}\n\nconst FUNCTION_NODE_TYPES = new Set([\n 'FunctionDeclaration',\n 'FunctionExpression',\n 'ArrowFunctionExpression',\n 'TSDeclareFunction',\n 'TSEmptyBodyFunctionExpression',\n])\n\nexport function analyzeReactUsage(\n entryFile: string,\n options: AnalyzeOptions = {},\n): ReactUsageGraph {\n const dependencyGraph = analyzeDependencies(entryFile, options)\n const reachableFiles = new Set<string>([\n dependencyGraph.entryId,\n ...dependencyGraph.nodes.keys(),\n ])\n const fileAnalyses = new Map<string, FileAnalysis>()\n\n for (const filePath of [...reachableFiles].sort()) {\n if (!isSourceCodeFile(filePath) || filePath.endsWith('.d.ts')) {\n continue\n }\n\n const sourceText = fs.readFileSync(filePath, 'utf8')\n const parseResult = parseSync(filePath, sourceText, {\n astType: 'ts',\n sourceType: 'unambiguous',\n })\n\n const dependencyNode = dependencyGraph.nodes.get(filePath)\n const sourceDependencies = new Map<string, string>()\n dependencyNode?.dependencies.forEach((dependency) => {\n if (dependency.kind === 'source') {\n sourceDependencies.set(dependency.specifier, dependency.target)\n }\n })\n\n fileAnalyses.set(\n filePath,\n analyzeReactFile(parseResult.program, filePath, sourceDependencies),\n )\n }\n\n const nodes = new Map<string, ReactUsageNode>()\n for (const fileAnalysis of fileAnalyses.values()) {\n for (const symbol of fileAnalysis.symbolsById.values()) {\n nodes.set(symbol.id, {\n id: symbol.id,\n name: symbol.name,\n kind: symbol.kind,\n filePath: symbol.filePath,\n exportNames: [...symbol.exportNames].sort(),\n usages: [],\n })\n }\n }\n\n for (const fileAnalysis of fileAnalyses.values()) {\n fileAnalysis.importsByLocalName.forEach((binding, localName) => {\n if (binding.sourcePath !== undefined) {\n return\n }\n\n if (!isHookName(localName) && !isHookName(binding.importedName)) {\n return\n }\n\n const externalNode = createExternalHookNode(binding, localName)\n if (!nodes.has(externalNode.id)) {\n nodes.set(externalNode.id, externalNode)\n }\n })\n }\n\n for (const fileAnalysis of fileAnalyses.values()) {\n for (const symbol of fileAnalysis.symbolsById.values()) {\n const usages = new Map<string, ReactUsageEdge>()\n\n symbol.componentReferences.forEach((referenceName) => {\n const targetId = resolveReactReference(\n fileAnalysis,\n fileAnalyses,\n referenceName,\n 'component',\n )\n if (targetId !== undefined && targetId !== symbol.id) {\n usages.set(`render:${targetId}`, {\n kind: 'render',\n target: targetId,\n })\n }\n })\n\n symbol.hookReferences.forEach((referenceName) => {\n const targetId = resolveReactReference(\n fileAnalysis,\n fileAnalyses,\n referenceName,\n 'hook',\n )\n if (targetId !== undefined && targetId !== symbol.id) {\n usages.set(`hook:${targetId}`, {\n kind: 'hook-call',\n target: targetId,\n })\n }\n })\n\n const node = nodes.get(symbol.id)\n if (node === undefined) {\n continue\n }\n\n const sortedUsages = [...usages.values()].sort((left, right) =>\n compareReactNodeIds(left.target, right.target, nodes),\n )\n\n nodes.set(symbol.id, {\n ...node,\n usages: sortedUsages,\n })\n }\n }\n\n return {\n cwd: dependencyGraph.cwd,\n entryId: dependencyGraph.entryId,\n nodes,\n }\n}\n\nexport function graphToSerializableReactTree(\n graph: ReactUsageGraph,\n options: {\n readonly filter?: ReactUsageFilter\n } = {},\n): object {\n const roots = getReactUsageRoots(graph, options.filter)\n\n return {\n kind: 'react-usage',\n roots: roots.map((rootId) =>\n serializeReactUsageNode(\n rootId,\n graph,\n options.filter ?? 'all',\n new Set(),\n ),\n ),\n }\n}\n\nexport function getReactUsageRoots(\n graph: ReactUsageGraph,\n filter: ReactUsageFilter = 'all',\n): string[] {\n const filteredNodes = getFilteredReactUsageNodes(graph, filter)\n const inboundCounts = new Map<string, number>()\n\n filteredNodes.forEach((node) => {\n inboundCounts.set(node.id, 0)\n })\n\n filteredNodes.forEach((node) => {\n getFilteredUsages(node, graph, filter).forEach((usage) => {\n inboundCounts.set(\n usage.target,\n (inboundCounts.get(usage.target) ?? 0) + 1,\n )\n })\n })\n\n const roots = filteredNodes\n .filter((node) => (inboundCounts.get(node.id) ?? 0) === 0)\n .map((node) => node.id)\n\n if (roots.length > 0) {\n return roots.sort((left, right) =>\n compareReactNodeIds(left, right, graph.nodes),\n )\n }\n\n return filteredNodes\n .map((node) => node.id)\n .sort((left, right) => compareReactNodeIds(left, right, graph.nodes))\n}\n\nexport function getFilteredUsages(\n node: ReactUsageNode,\n graph: ReactUsageGraph,\n filter: ReactUsageFilter = 'all',\n): ReactUsageEdge[] {\n return node.usages.filter((usage) => {\n const targetNode = graph.nodes.get(usage.target)\n return targetNode !== undefined && matchesReactFilter(targetNode, filter)\n })\n}\n\nfunction analyzeReactFile(\n program: Program,\n filePath: string,\n sourceDependencies: ReadonlyMap<string, string>,\n): FileAnalysis {\n const symbolsByName = new Map<string, PendingReactUsageNode>()\n\n program.body.forEach((statement) => {\n collectTopLevelReactSymbols(statement, filePath, symbolsByName)\n })\n\n const importsByLocalName = new Map<string, ImportBinding>()\n const exportsByName = new Map<string, string>()\n\n program.body.forEach((statement) => {\n collectImportsAndExports(\n statement,\n sourceDependencies,\n symbolsByName,\n importsByLocalName,\n exportsByName,\n )\n })\n\n symbolsByName.forEach((symbol) => {\n analyzeSymbolUsages(symbol)\n })\n\n return {\n filePath,\n importsByLocalName,\n exportsByName,\n symbolsById: new Map(\n [...symbolsByName.values()].map((symbol) => [symbol.id, symbol]),\n ),\n symbolsByName,\n }\n}\n\nfunction collectTopLevelReactSymbols(\n statement: Statement,\n filePath: string,\n symbolsByName: Map<string, PendingReactUsageNode>,\n): void {\n switch (statement.type) {\n case 'FunctionDeclaration':\n addFunctionSymbol(statement, filePath, symbolsByName)\n return\n case 'VariableDeclaration':\n statement.declarations.forEach((declarator) => {\n addVariableSymbol(declarator, filePath, symbolsByName)\n })\n return\n case 'ExportNamedDeclaration':\n if (statement.declaration !== null) {\n collectTopLevelReactSymbols(\n statement.declaration,\n filePath,\n symbolsByName,\n )\n }\n return\n case 'ExportDefaultDeclaration':\n addDefaultExportSymbol(statement, filePath, symbolsByName)\n return\n default:\n return\n }\n}\n\nfunction addFunctionSymbol(\n declaration: OxcFunction,\n filePath: string,\n symbolsByName: Map<string, PendingReactUsageNode>,\n): void {\n const name = declaration.id?.name\n if (name === undefined) {\n return\n }\n\n const kind = classifyReactSymbol(name, declaration)\n if (kind === undefined) {\n return\n }\n\n symbolsByName.set(\n name,\n createPendingSymbol(filePath, name, kind, declaration),\n )\n}\n\nfunction addVariableSymbol(\n declarator: VariableDeclarator,\n filePath: string,\n symbolsByName: Map<string, PendingReactUsageNode>,\n): void {\n if (declarator.id.type !== 'Identifier' || declarator.init === null) {\n return\n }\n\n if (\n declarator.init.type !== 'ArrowFunctionExpression' &&\n declarator.init.type !== 'FunctionExpression'\n ) {\n return\n }\n\n const name = declarator.id.name\n const kind = classifyReactSymbol(name, declarator.init)\n if (kind === undefined) {\n return\n }\n\n symbolsByName.set(\n name,\n createPendingSymbol(filePath, name, kind, declarator.init),\n )\n}\n\nfunction addDefaultExportSymbol(\n declaration: ExportDefaultDeclaration,\n filePath: string,\n symbolsByName: Map<string, PendingReactUsageNode>,\n): void {\n if (\n declaration.declaration.type === 'FunctionDeclaration' ||\n declaration.declaration.type === 'FunctionExpression'\n ) {\n addFunctionSymbol(declaration.declaration, filePath, symbolsByName)\n } else if (declaration.declaration.type === 'ArrowFunctionExpression') {\n const name = 'default'\n const kind = declaration.declaration.body\n ? classifyReactSymbol(name, declaration.declaration)\n : undefined\n if (kind !== undefined) {\n symbolsByName.set(\n name,\n createPendingSymbol(filePath, name, kind, declaration.declaration),\n )\n }\n }\n}\n\nfunction createPendingSymbol(\n filePath: string,\n name: string,\n kind: ReactSymbolKind,\n declaration: OxcFunction | ArrowFunctionExpression,\n): PendingReactUsageNode {\n return {\n id: `${filePath}#${kind}:${name}`,\n name,\n kind,\n filePath,\n declaration,\n exportNames: new Set<string>(),\n componentReferences: new Set<string>(),\n hookReferences: new Set<string>(),\n }\n}\n\nfunction collectImportsAndExports(\n statement: Statement,\n sourceDependencies: ReadonlyMap<string, string>,\n symbolsByName: ReadonlyMap<string, PendingReactUsageNode>,\n importsByLocalName: Map<string, ImportBinding>,\n exportsByName: Map<string, string>,\n): void {\n switch (statement.type) {\n case 'ImportDeclaration':\n collectImportBindings(statement, sourceDependencies, importsByLocalName)\n return\n case 'ExportNamedDeclaration':\n collectNamedExports(statement, symbolsByName, exportsByName)\n return\n case 'ExportDefaultDeclaration':\n collectDefaultExport(statement, symbolsByName, exportsByName)\n return\n default:\n return\n }\n}\n\nfunction collectImportBindings(\n declaration: ImportDeclaration,\n sourceDependencies: ReadonlyMap<string, string>,\n importsByLocalName: Map<string, ImportBinding>,\n): void {\n if (declaration.importKind === 'type') {\n return\n }\n\n const sourceSpecifier = declaration.source.value\n const sourcePath = sourceDependencies.get(declaration.source.value)\n\n declaration.specifiers.forEach((specifier) => {\n const binding = getImportBinding(specifier, sourceSpecifier, sourcePath)\n if (binding === undefined) {\n return\n }\n\n importsByLocalName.set(binding.localName, {\n importedName: binding.importedName,\n sourceSpecifier: binding.sourceSpecifier,\n ...(binding.sourcePath === undefined\n ? {}\n : { sourcePath: binding.sourcePath }),\n })\n })\n}\n\nfunction getImportBinding(\n specifier: ImportDeclarationSpecifier,\n sourceSpecifier: string,\n sourcePath: string | undefined,\n):\n | {\n readonly localName: string\n readonly importedName: string\n readonly sourceSpecifier: string\n readonly sourcePath?: string\n }\n | undefined {\n if (specifier.type === 'ImportSpecifier') {\n if (specifier.importKind === 'type') {\n return undefined\n }\n\n return {\n localName: specifier.local.name,\n importedName: toModuleExportName(specifier.imported),\n sourceSpecifier,\n ...(sourcePath === undefined ? {} : { sourcePath }),\n }\n }\n\n if (specifier.type === 'ImportDefaultSpecifier') {\n return {\n localName: specifier.local.name,\n importedName: 'default',\n sourceSpecifier,\n ...(sourcePath === undefined ? {} : { sourcePath }),\n }\n }\n\n return undefined\n}\n\nfunction collectNamedExports(\n declaration: ExportNamedDeclaration,\n symbolsByName: ReadonlyMap<string, PendingReactUsageNode>,\n exportsByName: Map<string, string>,\n): void {\n if (declaration.exportKind === 'type') {\n return\n }\n\n if (declaration.declaration !== null) {\n if (declaration.declaration.type === 'FunctionDeclaration') {\n const name = declaration.declaration.id?.name\n if (name !== undefined) {\n addExportBinding(name, name, symbolsByName, exportsByName)\n }\n } else if (declaration.declaration.type === 'VariableDeclaration') {\n declaration.declaration.declarations.forEach((declarator) => {\n if (declarator.id.type === 'Identifier') {\n addExportBinding(\n declarator.id.name,\n declarator.id.name,\n symbolsByName,\n exportsByName,\n )\n }\n })\n }\n\n return\n }\n\n if (declaration.source !== null) {\n return\n }\n\n declaration.specifiers.forEach((specifier) => {\n if (specifier.exportKind === 'type') {\n return\n }\n\n const localName = toModuleExportName(specifier.local)\n const exportedName = toModuleExportName(specifier.exported)\n addExportBinding(localName, exportedName, symbolsByName, exportsByName)\n })\n}\n\nfunction collectDefaultExport(\n declaration: ExportDefaultDeclaration,\n symbolsByName: ReadonlyMap<string, PendingReactUsageNode>,\n exportsByName: Map<string, string>,\n): void {\n if (\n declaration.declaration.type === 'FunctionDeclaration' ||\n declaration.declaration.type === 'FunctionExpression'\n ) {\n const localName = declaration.declaration.id?.name\n if (localName !== undefined) {\n addExportBinding(localName, 'default', symbolsByName, exportsByName)\n }\n return\n }\n\n if (declaration.declaration.type === 'Identifier') {\n addExportBinding(\n declaration.declaration.name,\n 'default',\n symbolsByName,\n exportsByName,\n )\n return\n }\n\n if (declaration.declaration.type === 'ArrowFunctionExpression') {\n addExportBinding('default', 'default', symbolsByName, exportsByName)\n }\n}\n\nfunction addExportBinding(\n localName: string,\n exportedName: string,\n symbolsByName: ReadonlyMap<string, PendingReactUsageNode>,\n exportsByName: Map<string, string>,\n): void {\n const symbol = symbolsByName.get(localName)\n if (symbol === undefined) {\n return\n }\n\n symbol.exportNames.add(exportedName)\n exportsByName.set(exportedName, symbol.id)\n}\n\nfunction analyzeSymbolUsages(symbol: PendingReactUsageNode): void {\n const root =\n symbol.declaration.type === 'ArrowFunctionExpression'\n ? symbol.declaration.body\n : symbol.declaration.body\n\n if (root === null) {\n return\n }\n\n walkReactUsageTree(root, (node) => {\n if (node.type === 'JSXElement') {\n const name = getComponentReferenceName(node)\n if (name !== undefined) {\n symbol.componentReferences.add(name)\n }\n return\n }\n\n if (node.type === 'CallExpression') {\n const hookReference = getHookReferenceName(node)\n if (hookReference !== undefined) {\n symbol.hookReferences.add(hookReference)\n }\n\n const componentReference = getCreateElementComponentReferenceName(node)\n if (componentReference !== undefined) {\n symbol.componentReferences.add(componentReference)\n }\n }\n })\n}\n\nfunction classifyReactSymbol(\n name: string,\n declaration: OxcFunction | ArrowFunctionExpression,\n): ReactSymbolKind | undefined {\n if (isHookName(name)) {\n return 'hook'\n }\n\n if (isComponentName(name) && returnsReactElement(declaration)) {\n return 'component'\n }\n\n return undefined\n}\n\nfunction returnsReactElement(\n declaration: OxcFunction | ArrowFunctionExpression,\n): boolean {\n if (\n declaration.type === 'ArrowFunctionExpression' &&\n declaration.expression\n ) {\n return containsReactElementLikeExpression(declaration.body as Expression)\n }\n\n const body = declaration.body\n if (body === null) {\n return false\n }\n\n let found = false\n walkReactUsageTree(body, (node) => {\n if (node.type !== 'ReturnStatement' || node.argument === null) {\n return\n }\n\n if (containsReactElementLikeExpression(node.argument)) {\n found = true\n }\n })\n\n return found\n}\n\nfunction containsReactElementLikeExpression(expression: Expression): boolean {\n let found = false\n\n walkNode(expression, (node) => {\n if (\n node.type === 'JSXElement' ||\n node.type === 'JSXFragment' ||\n (node.type === 'CallExpression' && isReactCreateElementCall(node))\n ) {\n found = true\n }\n })\n\n return found\n}\n\nfunction getComponentReferenceName(node: JSXElement): string | undefined {\n const name = getJsxName(node.openingElement.name)\n return name !== undefined && isComponentName(name) ? name : undefined\n}\n\nfunction getHookReferenceName(node: CallExpression): string | undefined {\n const calleeName = getIdentifierName(node.callee)\n return calleeName !== undefined && isHookName(calleeName)\n ? calleeName\n : undefined\n}\n\nfunction getCreateElementComponentReferenceName(\n node: CallExpression,\n): string | undefined {\n if (!isReactCreateElementCall(node)) {\n return undefined\n }\n\n const [firstArgument] = node.arguments\n if (firstArgument === undefined || firstArgument.type !== 'Identifier') {\n return undefined\n }\n\n return isComponentName(firstArgument.name) ? firstArgument.name : undefined\n}\n\nfunction isReactCreateElementCall(node: CallExpression): boolean {\n const callee = unwrapExpression(node.callee)\n if (callee.type !== 'MemberExpression' || callee.computed) {\n return false\n }\n\n return (\n callee.object.type === 'Identifier' &&\n callee.object.name === 'React' &&\n callee.property.name === 'createElement'\n )\n}\n\nfunction getJsxName(name: JSXElementName): string | undefined {\n if (name.type === 'JSXIdentifier') {\n return name.name\n }\n\n return undefined\n}\n\nfunction getIdentifierName(expression: Expression): string | undefined {\n const unwrapped = unwrapExpression(expression)\n return unwrapped.type === 'Identifier' ? unwrapped.name : undefined\n}\n\nfunction unwrapExpression(expression: Expression): Expression {\n let current = expression\n\n while (true) {\n if (\n current.type === 'ParenthesizedExpression' ||\n current.type === 'TSAsExpression' ||\n current.type === 'TSSatisfiesExpression' ||\n current.type === 'TSTypeAssertion' ||\n current.type === 'TSNonNullExpression'\n ) {\n current = current.expression\n continue\n }\n\n return current\n }\n}\n\nfunction walkReactUsageTree(\n root: FunctionBody | Expression | JSXFragment | JSXElement,\n visit: (node: Node) => void,\n): void {\n walkNode(root, visit, true)\n}\n\nfunction walkNode(\n node: Node,\n visit: (node: Node) => void,\n allowNestedFunctions = false,\n): void {\n visit(node)\n\n const keys = visitorKeys[node.type]\n if (keys === undefined) {\n return\n }\n\n keys.forEach((key) => {\n const value = (node as unknown as Record<string, unknown>)[key]\n walkChild(value, visit, allowNestedFunctions)\n })\n}\n\nfunction walkChild(\n value: unknown,\n visit: (node: Node) => void,\n allowNestedFunctions: boolean,\n): void {\n if (Array.isArray(value)) {\n value.forEach((entry) => {\n walkChild(entry, visit, allowNestedFunctions)\n })\n return\n }\n\n if (!isNode(value)) {\n return\n }\n\n if (!allowNestedFunctions && FUNCTION_NODE_TYPES.has(value.type)) {\n return\n }\n\n walkNode(value, visit, false)\n}\n\nfunction isNode(value: unknown): value is Node {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n typeof (value as { type: unknown }).type === 'string'\n )\n}\n\nfunction resolveReactReference(\n fileAnalysis: FileAnalysis,\n fileAnalyses: ReadonlyMap<string, FileAnalysis>,\n name: string,\n kind: ReactSymbolKind,\n): string | undefined {\n const localSymbol = fileAnalysis.symbolsByName.get(name)\n if (localSymbol !== undefined && localSymbol.kind === kind) {\n return localSymbol.id\n }\n\n const importBinding = fileAnalysis.importsByLocalName.get(name)\n if (importBinding === undefined) {\n return undefined\n }\n\n if (importBinding.sourcePath === undefined) {\n return kind === 'hook'\n ? getExternalHookNodeId(importBinding, name)\n : undefined\n }\n\n const sourceFileAnalysis = fileAnalyses.get(importBinding.sourcePath)\n if (sourceFileAnalysis === undefined) {\n return undefined\n }\n\n const targetId = sourceFileAnalysis.exportsByName.get(\n importBinding.importedName,\n )\n if (targetId === undefined) {\n return undefined\n }\n\n const targetSymbol = sourceFileAnalysis.symbolsById.get(targetId)\n return targetSymbol?.kind === kind ? targetId : undefined\n}\n\nfunction createExternalHookNode(\n binding: ImportBinding,\n localName: string,\n): ReactUsageNode {\n const name = getExternalHookName(binding, localName)\n\n return {\n id: getExternalHookNodeId(binding, localName),\n name,\n kind: 'hook',\n filePath: binding.sourceSpecifier,\n exportNames: [binding.importedName],\n usages: [],\n }\n}\n\nfunction getExternalHookNodeId(\n binding: ImportBinding,\n localName: string,\n): string {\n return `external:${binding.sourceSpecifier}#hook:${getExternalHookName(binding, localName)}`\n}\n\nfunction getExternalHookName(\n binding: ImportBinding,\n localName: string,\n): string {\n return binding.importedName === 'default' ? localName : binding.importedName\n}\n\nfunction getFilteredReactUsageNodes(\n graph: ReactUsageGraph,\n filter: ReactUsageFilter,\n): ReactUsageNode[] {\n return [...graph.nodes.values()]\n .filter((node) => matchesReactFilter(node, filter))\n .sort((left, right) => compareReactNodes(left, right))\n}\n\nfunction matchesReactFilter(\n node: ReactUsageNode,\n filter: ReactUsageFilter,\n): boolean {\n return filter === 'all' || node.kind === filter\n}\n\nfunction serializeReactUsageNode(\n nodeId: string,\n graph: ReactUsageGraph,\n filter: ReactUsageFilter,\n visited: Set<string>,\n): SerializedReactUsageNode {\n const node = graph.nodes.get(nodeId)\n if (node === undefined) {\n return {\n id: nodeId,\n name: nodeId,\n symbolKind: 'circular',\n filePath: '',\n exportNames: [],\n usages: [],\n }\n }\n\n if (visited.has(nodeId)) {\n return {\n id: node.id,\n name: node.name,\n symbolKind: 'circular',\n filePath: toDisplayPath(node.filePath, graph.cwd),\n exportNames: node.exportNames,\n usages: [],\n }\n }\n\n const nextVisited = new Set(visited)\n nextVisited.add(nodeId)\n\n return {\n id: node.id,\n name: node.name,\n symbolKind: node.kind,\n filePath: toDisplayPath(node.filePath, graph.cwd),\n exportNames: node.exportNames,\n usages: getFilteredUsages(node, graph, filter).map((usage) => ({\n kind: usage.kind,\n targetId: usage.target,\n node: serializeReactUsageNode(usage.target, graph, filter, nextVisited),\n })),\n }\n}\n\nfunction compareReactNodeIds(\n leftId: string,\n rightId: string,\n nodes: ReadonlyMap<string, ReactUsageNode>,\n): number {\n const left = nodes.get(leftId)\n const right = nodes.get(rightId)\n\n if (left === undefined || right === undefined) {\n return leftId.localeCompare(rightId)\n }\n\n return compareReactNodes(left, right)\n}\n\nfunction compareReactNodes(\n left: ReactUsageNode,\n right: ReactUsageNode,\n): number {\n return (\n left.filePath.localeCompare(right.filePath) ||\n left.name.localeCompare(right.name) ||\n left.kind.localeCompare(right.kind)\n )\n}\n\nfunction toModuleExportName(name: ModuleExportName): string {\n return name.type === 'Literal' ? name.value : name.name\n}\n\nfunction isHookName(name: string): boolean {\n return /^use[A-Z0-9]/.test(name)\n}\n\nfunction isComponentName(name: string): boolean {\n return /^[A-Z]/.test(name)\n}\n","import { toDisplayPath } from './path-utils.js'\nimport { getFilteredUsages, getReactUsageRoots } from './react-analyzer.js'\nimport type {\n PrintReactTreeOptions,\n ReactUsageEdge,\n ReactUsageGraph,\n ReactUsageNode,\n} from './types.js'\n\nexport function printReactUsageTree(\n graph: ReactUsageGraph,\n options: PrintReactTreeOptions = {},\n): string {\n const cwd = options.cwd ?? graph.cwd\n const filter = options.filter ?? 'all'\n const roots = getReactUsageRoots(graph, filter)\n\n if (roots.length === 0) {\n return 'No React symbols found.'\n }\n\n const lines: string[] = []\n roots.forEach((rootId, index) => {\n const root = graph.nodes.get(rootId)\n if (root === undefined) {\n return\n }\n\n lines.push(formatReactNodeLabel(root, cwd))\n const usages = getFilteredUsages(root, graph, filter)\n usages.forEach((usage, usageIndex) => {\n lines.push(\n ...renderUsage(\n usage,\n graph,\n cwd,\n filter,\n new Set([root.id]),\n '',\n usageIndex === usages.length - 1,\n ),\n )\n })\n\n if (index < roots.length - 1) {\n lines.push('')\n }\n })\n\n return lines.join('\\n')\n}\n\nfunction renderUsage(\n usage: ReactUsageEdge,\n graph: ReactUsageGraph,\n cwd: string,\n filter: NonNullable<PrintReactTreeOptions['filter']>,\n visited: ReadonlySet<string>,\n prefix: string,\n isLast: boolean,\n): string[] {\n const branch = `${prefix}${isLast ? '└─ ' : '├─ '}`\n const target = graph.nodes.get(usage.target)\n\n if (target === undefined) {\n return [`${branch}${usage.target}`]\n }\n\n if (visited.has(target.id)) {\n return [`${branch}${formatReactNodeLabel(target, cwd)} (circular)`]\n }\n\n const childLines = [`${branch}${formatReactNodeLabel(target, cwd)}`]\n const nextVisited = new Set(visited)\n nextVisited.add(target.id)\n const nextPrefix = `${prefix}${isLast ? ' ' : '│ '}`\n const childUsages = getFilteredUsages(target, graph, filter)\n\n childUsages.forEach((childUsage, index) => {\n childLines.push(\n ...renderUsage(\n childUsage,\n graph,\n cwd,\n filter,\n nextVisited,\n nextPrefix,\n index === childUsages.length - 1,\n ),\n )\n })\n\n return childLines\n}\n\nfunction formatReactNodeLabel(node: ReactUsageNode, cwd: string): string {\n return `${node.name} [${node.kind}] (${toDisplayPath(node.filePath, cwd)})`\n}\n","import { toDisplayPath } from './path-utils.js'\nimport type {\n DependencyEdge,\n DependencyGraph,\n PrintTreeOptions,\n} from './types.js'\n\nexport function printDependencyTree(\n graph: DependencyGraph,\n options: PrintTreeOptions = {},\n): string {\n const cwd = options.cwd ?? graph.cwd\n const includeExternals = options.includeExternals ?? false\n const rootLines = [toDisplayPath(graph.entryId, cwd)]\n const visited = new Set<string>([graph.entryId])\n const entryNode = graph.nodes.get(graph.entryId)\n\n if (entryNode === undefined) {\n return rootLines.join('\\n')\n }\n\n const rootDependencies = filterDependencies(\n entryNode.dependencies,\n includeExternals,\n )\n\n rootDependencies.forEach((dependency, index) => {\n const isLast = index === rootDependencies.length - 1\n const lines = renderDependency(\n dependency,\n graph,\n visited,\n '',\n isLast,\n includeExternals,\n cwd,\n )\n rootLines.push(...lines)\n })\n\n return rootLines.join('\\n')\n}\n\nfunction renderDependency(\n dependency: DependencyEdge,\n graph: DependencyGraph,\n visited: ReadonlySet<string>,\n prefix: string,\n isLast: boolean,\n includeExternals: boolean,\n cwd: string,\n): string[] {\n const branch = `${prefix}${isLast ? '└─ ' : '├─ '}`\n const label = formatDependencyLabel(dependency, graph, cwd)\n\n if (dependency.kind !== 'source') {\n return [`${branch}${label}`]\n }\n\n if (visited.has(dependency.target)) {\n return [`${branch}${label} (circular)`]\n }\n\n const childNode = graph.nodes.get(dependency.target)\n if (childNode === undefined) {\n return [`${branch}${label}`]\n }\n\n const nextPrefix = `${prefix}${isLast ? ' ' : '│ '}`\n const nextVisited = new Set(visited)\n nextVisited.add(dependency.target)\n\n const childLines = [`${branch}${label}`]\n const childDependencies = filterDependencies(\n childNode.dependencies,\n includeExternals,\n )\n\n childDependencies.forEach((childDependency, index) => {\n const isChildLast = index === childDependencies.length - 1\n childLines.push(\n ...renderDependency(\n childDependency,\n graph,\n nextVisited,\n nextPrefix,\n isChildLast,\n includeExternals,\n cwd,\n ),\n )\n })\n\n return childLines\n}\n\nfunction filterDependencies(\n dependencies: readonly DependencyEdge[],\n includeExternals: boolean,\n): DependencyEdge[] {\n return dependencies.filter((dependency) => {\n if (dependency.kind === 'source' || dependency.kind === 'missing') {\n return true\n }\n\n return includeExternals\n })\n}\n\nfunction formatDependencyLabel(\n dependency: DependencyEdge,\n _graph: DependencyGraph,\n cwd: string,\n): string {\n const prefixes: string[] = []\n if (dependency.isTypeOnly) {\n prefixes.push('type')\n }\n\n if (dependency.referenceKind === 'require') {\n prefixes.push('require')\n } else if (dependency.referenceKind === 'dynamic-import') {\n prefixes.push('dynamic')\n } else if (dependency.referenceKind === 'export') {\n prefixes.push('re-export')\n } else if (dependency.referenceKind === 'import-equals') {\n prefixes.push('import=')\n }\n\n const annotation = prefixes.length > 0 ? `[${prefixes.join(', ')}] ` : ''\n\n if (dependency.kind === 'source') {\n return `${annotation}${toDisplayPath(dependency.target, cwd)}`\n }\n\n if (dependency.kind === 'missing') {\n return `${annotation}${dependency.specifier} [missing]`\n }\n\n if (dependency.kind === 'builtin') {\n return `${annotation}${dependency.target} [builtin]`\n }\n\n return `${annotation}${dependency.target} [external]`\n}\n"],"mappings":"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"}