callograph 0.0.1 → 0.0.2

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/dist/cli.cjs ADDED
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/analyzer/createProgram.ts
27
+ var import_typescript = __toESM(require("typescript"), 1);
28
+ function createTsProgram(tsconfigPath) {
29
+ const configFile = import_typescript.default.readConfigFile(tsconfigPath, import_typescript.default.sys.readFile);
30
+ if (configFile.error) {
31
+ throw new Error(
32
+ import_typescript.default.flattenDiagnosticMessageText(configFile.error.messageText, "\n")
33
+ );
34
+ }
35
+ const parsedConfig = import_typescript.default.parseJsonConfigFileContent(
36
+ configFile.config,
37
+ import_typescript.default.sys,
38
+ process.cwd()
39
+ );
40
+ return import_typescript.default.createProgram({
41
+ rootNames: parsedConfig.fileNames,
42
+ options: parsedConfig.options
43
+ });
44
+ }
45
+
46
+ // src/analyzer/collectFunctions.ts
47
+ var import_typescript2 = __toESM(require("typescript"), 1);
48
+ function safeName(node, sf) {
49
+ const anyNode = node;
50
+ if (anyNode.name && import_typescript2.default.isIdentifier(anyNode.name)) return anyNode.name.text;
51
+ if (anyNode.name && (import_typescript2.default.isStringLiteral(anyNode.name) || import_typescript2.default.isNumericLiteral(anyNode.name))) {
52
+ return String(anyNode.name.text);
53
+ }
54
+ const p = node.parent;
55
+ if (p && import_typescript2.default.isVariableDeclaration(p) && import_typescript2.default.isIdentifier(p.name)) return p.name.text;
56
+ if (p && import_typescript2.default.isBinaryExpression(p) && import_typescript2.default.isPropertyAccessExpression(p.left)) {
57
+ return p.left.name.text;
58
+ }
59
+ const { line, character } = sf.getLineAndCharacterOfPosition(node.getStart(sf));
60
+ return `<anonymous@${line + 1}:${character + 1}>`;
61
+ }
62
+ function collectFunctions(program2) {
63
+ const out = [];
64
+ for (const sf of program2.getSourceFiles()) {
65
+ if (sf.isDeclarationFile) continue;
66
+ if (sf.fileName.includes("node_modules")) continue;
67
+ import_typescript2.default.forEachChild(sf, function visit(n) {
68
+ if (import_typescript2.default.isFunctionDeclaration(n) || import_typescript2.default.isMethodDeclaration(n) || import_typescript2.default.isArrowFunction(n) || import_typescript2.default.isFunctionExpression(n)) {
69
+ const name = safeName(n, sf);
70
+ const id = `${sf.fileName}:${n.pos}:${name}`;
71
+ out.push({ id, name, file: sf.fileName, node: n });
72
+ }
73
+ import_typescript2.default.forEachChild(n, visit);
74
+ });
75
+ }
76
+ return out;
77
+ }
78
+
79
+ // src/analyzer/buildCallGraph.ts
80
+ var import_typescript3 = __toESM(require("typescript"), 1);
81
+ function buildCallGraph(program2, functions2) {
82
+ const checker = program2.getTypeChecker();
83
+ const graph2 = /* @__PURE__ */ new Map();
84
+ const functionMap = /* @__PURE__ */ new Map();
85
+ for (const fn of functions2) {
86
+ functionMap.set(fn.name, fn.node);
87
+ graph2.set(fn.name, /* @__PURE__ */ new Set());
88
+ }
89
+ for (const fn of functions2) {
90
+ const fnName = fn.name;
91
+ import_typescript3.default.forEachChild(fn.node, function visit(node) {
92
+ if (import_typescript3.default.isCallExpression(node)) {
93
+ const expression = node.expression;
94
+ const symbol = checker.getSymbolAtLocation(expression);
95
+ if (symbol) {
96
+ const name = symbol.getName();
97
+ if (graph2.has(fnName)) {
98
+ graph2.get(fnName).add(name);
99
+ }
100
+ }
101
+ }
102
+ import_typescript3.default.forEachChild(node, visit);
103
+ });
104
+ }
105
+ return graph2;
106
+ }
107
+
108
+ // src/cli.ts
109
+ var command = process.argv[2];
110
+ if (command !== "analyze") {
111
+ console.log("Usage: callograph analyze");
112
+ process.exit(1);
113
+ }
114
+ var program = createTsProgram("tsconfig.json");
115
+ var functions = collectFunctions(program);
116
+ var graph = buildCallGraph(program, functions);
117
+ console.log("\nCall Graph:\n");
118
+ for (const [fn, calls] of graph.entries()) {
119
+ for (const call of calls) {
120
+ console.log(`${fn} \u2192 ${call}`);
121
+ }
122
+ }
123
+ //# sourceMappingURL=cli.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/analyzer/createProgram.ts","../src/analyzer/collectFunctions.ts","../src/analyzer/buildCallGraph.ts","../src/cli.ts"],"sourcesContent":["import ts from \"typescript\";\r\n\r\nexport function createTsProgram(tsconfigPath: string) {\r\n const configFile = ts.readConfigFile(tsconfigPath, ts.sys.readFile);\r\n\r\n if (configFile.error) {\r\n throw new Error(\r\n ts.flattenDiagnosticMessageText(configFile.error.messageText, \"\\n\")\r\n );\r\n }\r\n\r\n const parsedConfig = ts.parseJsonConfigFileContent(\r\n configFile.config,\r\n ts.sys,\r\n process.cwd()\r\n );\r\n\r\n return ts.createProgram({\r\n rootNames: parsedConfig.fileNames,\r\n options: parsedConfig.options,\r\n });\r\n}\r\n","import ts from \"typescript\";\r\n\r\nexport interface FunctionNode {\r\n id: string;\r\n name: string;\r\n file: string;\r\n node: ts.FunctionLikeDeclaration;\r\n}\r\n\r\nfunction safeName(node: ts.FunctionLikeDeclaration, sf: ts.SourceFile): string {\r\n const anyNode = node as any;\r\n\r\n // Named declarations / methods: function foo() {} / class X { foo() {} }\r\n if (anyNode.name && ts.isIdentifier(anyNode.name)) return anyNode.name.text;\r\n\r\n // Methods with string/numeric names: class X { \"foo\"() {} }\r\n if (anyNode.name && (ts.isStringLiteral(anyNode.name) || ts.isNumericLiteral(anyNode.name))) {\r\n return String(anyNode.name.text);\r\n }\r\n\r\n // const foo = () => {} / const foo = function() {}\r\n const p = node.parent;\r\n if (p && ts.isVariableDeclaration(p) && ts.isIdentifier(p.name)) return p.name.text;\r\n\r\n // obj.foo = function() {}\r\n if (p && ts.isBinaryExpression(p) && ts.isPropertyAccessExpression(p.left)) {\r\n return p.left.name.text;\r\n }\r\n\r\n const { line, character } = sf.getLineAndCharacterOfPosition(node.getStart(sf));\r\n return `<anonymous@${line + 1}:${character + 1}>`;\r\n}\r\n\r\nexport function collectFunctions(program: ts.Program): FunctionNode[] {\r\n const out: FunctionNode[] = [];\r\n\r\n for (const sf of program.getSourceFiles()) {\r\n if (sf.isDeclarationFile) continue;\r\n if (sf.fileName.includes(\"node_modules\")) continue;\r\n\r\n ts.forEachChild(sf, function visit(n) {\r\n if (\r\n ts.isFunctionDeclaration(n) ||\r\n ts.isMethodDeclaration(n) ||\r\n ts.isArrowFunction(n) ||\r\n ts.isFunctionExpression(n)\r\n ) {\r\n const name = safeName(n, sf);\r\n const id = `${sf.fileName}:${n.pos}:${name}`;\r\n out.push({ id, name, file: sf.fileName, node: n });\r\n }\r\n ts.forEachChild(n, visit);\r\n });\r\n }\r\n\r\n return out;\r\n}\r\n","import ts from \"typescript\";\r\nimport { FunctionNode } from \"./collectFunctions\";\r\n\r\nexport type CallGraph = Map<string, Set<string>>;\r\n\r\nexport function buildCallGraph(\r\n program: ts.Program,\r\n functions: FunctionNode[]\r\n): CallGraph {\r\n const checker = program.getTypeChecker();\r\n const graph: CallGraph = new Map();\r\n\r\n const functionMap = new Map<string, ts.FunctionLikeDeclaration>();\r\n\r\n for (const fn of functions) {\r\n functionMap.set(fn.name, fn.node);\r\n graph.set(fn.name, new Set());\r\n }\r\n\r\n for (const fn of functions) {\r\n const fnName = fn.name;\r\n\r\n ts.forEachChild(fn.node, function visit(node) {\r\n if (ts.isCallExpression(node)) {\r\n const expression = node.expression;\r\n const symbol = checker.getSymbolAtLocation(expression);\r\n\r\n if (symbol) {\r\n const name = symbol.getName();\r\n if (graph.has(fnName)) {\r\n graph.get(fnName)!.add(name);\r\n }\r\n }\r\n }\r\n\r\n ts.forEachChild(node, visit);\r\n });\r\n }\r\n\r\n return graph;\r\n}\r\n","#!/usr/bin/env node\r\nimport { createTsProgram } from \"./analyzer/createProgram\";\r\nimport { collectFunctions } from \"./analyzer/collectFunctions\";\r\nimport { buildCallGraph } from \"./analyzer/buildCallGraph\";\r\n\r\nconst command = process.argv[2];\r\n\r\nif (command !== \"analyze\") {\r\n console.log(\"Usage: callograph analyze\");\r\n process.exit(1);\r\n}\r\n\r\nconst program = createTsProgram(\"tsconfig.json\");\r\nconst functions = collectFunctions(program);\r\nconst graph = buildCallGraph(program, functions);\r\n\r\nconsole.log(\"\\nCall Graph:\\n\");\r\n\r\nfor (const [fn, calls] of graph.entries()) {\r\n for (const call of calls) {\r\n console.log(`${fn} → ${call}`);\r\n }\r\n}\r\n"],"mappings":"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","names":["ts","import_typescript","ts","program","import_typescript","program","functions","graph","ts"]}
package/dist/cli.d.cts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/analyzer/createProgram.ts
4
+ import ts from "typescript";
5
+ function createTsProgram(tsconfigPath) {
6
+ const configFile = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
7
+ if (configFile.error) {
8
+ throw new Error(
9
+ ts.flattenDiagnosticMessageText(configFile.error.messageText, "\n")
10
+ );
11
+ }
12
+ const parsedConfig = ts.parseJsonConfigFileContent(
13
+ configFile.config,
14
+ ts.sys,
15
+ process.cwd()
16
+ );
17
+ return ts.createProgram({
18
+ rootNames: parsedConfig.fileNames,
19
+ options: parsedConfig.options
20
+ });
21
+ }
22
+
23
+ // src/analyzer/collectFunctions.ts
24
+ import ts2 from "typescript";
25
+ function safeName(node, sf) {
26
+ const anyNode = node;
27
+ if (anyNode.name && ts2.isIdentifier(anyNode.name)) return anyNode.name.text;
28
+ if (anyNode.name && (ts2.isStringLiteral(anyNode.name) || ts2.isNumericLiteral(anyNode.name))) {
29
+ return String(anyNode.name.text);
30
+ }
31
+ const p = node.parent;
32
+ if (p && ts2.isVariableDeclaration(p) && ts2.isIdentifier(p.name)) return p.name.text;
33
+ if (p && ts2.isBinaryExpression(p) && ts2.isPropertyAccessExpression(p.left)) {
34
+ return p.left.name.text;
35
+ }
36
+ const { line, character } = sf.getLineAndCharacterOfPosition(node.getStart(sf));
37
+ return `<anonymous@${line + 1}:${character + 1}>`;
38
+ }
39
+ function collectFunctions(program2) {
40
+ const out = [];
41
+ for (const sf of program2.getSourceFiles()) {
42
+ if (sf.isDeclarationFile) continue;
43
+ if (sf.fileName.includes("node_modules")) continue;
44
+ ts2.forEachChild(sf, function visit(n) {
45
+ if (ts2.isFunctionDeclaration(n) || ts2.isMethodDeclaration(n) || ts2.isArrowFunction(n) || ts2.isFunctionExpression(n)) {
46
+ const name = safeName(n, sf);
47
+ const id = `${sf.fileName}:${n.pos}:${name}`;
48
+ out.push({ id, name, file: sf.fileName, node: n });
49
+ }
50
+ ts2.forEachChild(n, visit);
51
+ });
52
+ }
53
+ return out;
54
+ }
55
+
56
+ // src/analyzer/buildCallGraph.ts
57
+ import ts3 from "typescript";
58
+ function buildCallGraph(program2, functions2) {
59
+ const checker = program2.getTypeChecker();
60
+ const graph2 = /* @__PURE__ */ new Map();
61
+ const functionMap = /* @__PURE__ */ new Map();
62
+ for (const fn of functions2) {
63
+ functionMap.set(fn.name, fn.node);
64
+ graph2.set(fn.name, /* @__PURE__ */ new Set());
65
+ }
66
+ for (const fn of functions2) {
67
+ const fnName = fn.name;
68
+ ts3.forEachChild(fn.node, function visit(node) {
69
+ if (ts3.isCallExpression(node)) {
70
+ const expression = node.expression;
71
+ const symbol = checker.getSymbolAtLocation(expression);
72
+ if (symbol) {
73
+ const name = symbol.getName();
74
+ if (graph2.has(fnName)) {
75
+ graph2.get(fnName).add(name);
76
+ }
77
+ }
78
+ }
79
+ ts3.forEachChild(node, visit);
80
+ });
81
+ }
82
+ return graph2;
83
+ }
84
+
85
+ // src/cli.ts
86
+ var command = process.argv[2];
87
+ if (command !== "analyze") {
88
+ console.log("Usage: callograph analyze");
89
+ process.exit(1);
90
+ }
91
+ var program = createTsProgram("tsconfig.json");
92
+ var functions = collectFunctions(program);
93
+ var graph = buildCallGraph(program, functions);
94
+ console.log("\nCall Graph:\n");
95
+ for (const [fn, calls] of graph.entries()) {
96
+ for (const call of calls) {
97
+ console.log(`${fn} \u2192 ${call}`);
98
+ }
99
+ }
100
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/analyzer/createProgram.ts","../src/analyzer/collectFunctions.ts","../src/analyzer/buildCallGraph.ts","../src/cli.ts"],"sourcesContent":["import ts from \"typescript\";\r\n\r\nexport function createTsProgram(tsconfigPath: string) {\r\n const configFile = ts.readConfigFile(tsconfigPath, ts.sys.readFile);\r\n\r\n if (configFile.error) {\r\n throw new Error(\r\n ts.flattenDiagnosticMessageText(configFile.error.messageText, \"\\n\")\r\n );\r\n }\r\n\r\n const parsedConfig = ts.parseJsonConfigFileContent(\r\n configFile.config,\r\n ts.sys,\r\n process.cwd()\r\n );\r\n\r\n return ts.createProgram({\r\n rootNames: parsedConfig.fileNames,\r\n options: parsedConfig.options,\r\n });\r\n}\r\n","import ts from \"typescript\";\r\n\r\nexport interface FunctionNode {\r\n id: string;\r\n name: string;\r\n file: string;\r\n node: ts.FunctionLikeDeclaration;\r\n}\r\n\r\nfunction safeName(node: ts.FunctionLikeDeclaration, sf: ts.SourceFile): string {\r\n const anyNode = node as any;\r\n\r\n // Named declarations / methods: function foo() {} / class X { foo() {} }\r\n if (anyNode.name && ts.isIdentifier(anyNode.name)) return anyNode.name.text;\r\n\r\n // Methods with string/numeric names: class X { \"foo\"() {} }\r\n if (anyNode.name && (ts.isStringLiteral(anyNode.name) || ts.isNumericLiteral(anyNode.name))) {\r\n return String(anyNode.name.text);\r\n }\r\n\r\n // const foo = () => {} / const foo = function() {}\r\n const p = node.parent;\r\n if (p && ts.isVariableDeclaration(p) && ts.isIdentifier(p.name)) return p.name.text;\r\n\r\n // obj.foo = function() {}\r\n if (p && ts.isBinaryExpression(p) && ts.isPropertyAccessExpression(p.left)) {\r\n return p.left.name.text;\r\n }\r\n\r\n const { line, character } = sf.getLineAndCharacterOfPosition(node.getStart(sf));\r\n return `<anonymous@${line + 1}:${character + 1}>`;\r\n}\r\n\r\nexport function collectFunctions(program: ts.Program): FunctionNode[] {\r\n const out: FunctionNode[] = [];\r\n\r\n for (const sf of program.getSourceFiles()) {\r\n if (sf.isDeclarationFile) continue;\r\n if (sf.fileName.includes(\"node_modules\")) continue;\r\n\r\n ts.forEachChild(sf, function visit(n) {\r\n if (\r\n ts.isFunctionDeclaration(n) ||\r\n ts.isMethodDeclaration(n) ||\r\n ts.isArrowFunction(n) ||\r\n ts.isFunctionExpression(n)\r\n ) {\r\n const name = safeName(n, sf);\r\n const id = `${sf.fileName}:${n.pos}:${name}`;\r\n out.push({ id, name, file: sf.fileName, node: n });\r\n }\r\n ts.forEachChild(n, visit);\r\n });\r\n }\r\n\r\n return out;\r\n}\r\n","import ts from \"typescript\";\r\nimport { FunctionNode } from \"./collectFunctions\";\r\n\r\nexport type CallGraph = Map<string, Set<string>>;\r\n\r\nexport function buildCallGraph(\r\n program: ts.Program,\r\n functions: FunctionNode[]\r\n): CallGraph {\r\n const checker = program.getTypeChecker();\r\n const graph: CallGraph = new Map();\r\n\r\n const functionMap = new Map<string, ts.FunctionLikeDeclaration>();\r\n\r\n for (const fn of functions) {\r\n functionMap.set(fn.name, fn.node);\r\n graph.set(fn.name, new Set());\r\n }\r\n\r\n for (const fn of functions) {\r\n const fnName = fn.name;\r\n\r\n ts.forEachChild(fn.node, function visit(node) {\r\n if (ts.isCallExpression(node)) {\r\n const expression = node.expression;\r\n const symbol = checker.getSymbolAtLocation(expression);\r\n\r\n if (symbol) {\r\n const name = symbol.getName();\r\n if (graph.has(fnName)) {\r\n graph.get(fnName)!.add(name);\r\n }\r\n }\r\n }\r\n\r\n ts.forEachChild(node, visit);\r\n });\r\n }\r\n\r\n return graph;\r\n}\r\n","#!/usr/bin/env node\r\nimport { createTsProgram } from \"./analyzer/createProgram\";\r\nimport { collectFunctions } from \"./analyzer/collectFunctions\";\r\nimport { buildCallGraph } from \"./analyzer/buildCallGraph\";\r\n\r\nconst command = process.argv[2];\r\n\r\nif (command !== \"analyze\") {\r\n console.log(\"Usage: callograph analyze\");\r\n process.exit(1);\r\n}\r\n\r\nconst program = createTsProgram(\"tsconfig.json\");\r\nconst functions = collectFunctions(program);\r\nconst graph = buildCallGraph(program, functions);\r\n\r\nconsole.log(\"\\nCall Graph:\\n\");\r\n\r\nfor (const [fn, calls] of graph.entries()) {\r\n for (const call of calls) {\r\n console.log(`${fn} → ${call}`);\r\n }\r\n}\r\n"],"mappings":"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","names":["ts","program","ts","program","functions","graph"]}
package/dist/index.cjs CHANGED
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  var __defProp = Object.defineProperty;
2
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export const version = \"0.0.1\";"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,IAAM,UAAU;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export const version = \"0.0.1\";"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,IAAM,UAAU;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "callograph",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "TypeScript call graph and side-effect analyzer.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -8,7 +8,9 @@
8
8
  "module": "./dist/index.js",
9
9
  "types": "./dist/index.d.ts",
10
10
  "files": [
11
- "dist"
11
+ "dist",
12
+ "README.md",
13
+ "LICENSE"
12
14
  ],
13
15
  "scripts": {
14
16
  "build": "tsup",
@@ -16,7 +18,19 @@
16
18
  "prepublishOnly": "npm run build"
17
19
  },
18
20
  "devDependencies": {
21
+ "@types/node": "^25.2.3",
19
22
  "tsup": "^8.5.1",
20
23
  "typescript": "^5.9.3"
21
- }
24
+ },
25
+ "bin": {
26
+ "callograph": "./dist/cli.cjs"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/<your-username>/callograph.git"
31
+ },
32
+ "bugs": {
33
+ "url": "https://github.com/<your-username>/callograph/issues"
34
+ },
35
+ "homepage": "https://github.com/<your-username>/callograph#readme"
22
36
  }