typeslayer 0.0.0 → 0.1.1
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 +53 -0
- package/bin/typeslayer.js +69 -0
- package/package.json +98 -7
- package/scripts/postinstall.js +111 -0
- package/index.js +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|
|
2
|
+
<p align="center">
|
|
3
|
+
<img src="src/assets/typeslayer-nightmare.png">
|
|
4
|
+
</p>
|
|
5
|
+
|
|
6
|
+
<p align="center">
|
|
7
|
+
a tool for diagnosing and fixing TypeScript performance problems
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
## Quickstart
|
|
11
|
+
|
|
12
|
+
run:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx typeslayer
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
in the root package you want to inspect (i.e. colocated to your package.json). The tool will:
|
|
19
|
+
|
|
20
|
+
1. start a local web UI,
|
|
21
|
+
2. run TypeScript tooling to produce traces and CPU profiles
|
|
22
|
+
3. provide interactive visualizations (treemaps, force graphs, speedscope/perfetto views) that you can use to identify problems
|
|
23
|
+
|
|
24
|
+
## Frequently Asked Questions
|
|
25
|
+
|
|
26
|
+
- will this ever get CI support for analysis file generation?
|
|
27
|
+
- yeah prolly eventually.
|
|
28
|
+
- will this support monorepos?
|
|
29
|
+
- that's the hope. one step at a time.
|
|
30
|
+
- why isn't this just a CLI tool?
|
|
31
|
+
- A goal of the project is show intuitive/beautiful interactive visualizations like treemaps and force graphs, inherently not something a terminal can provide.
|
|
32
|
+
- I don't like CLI tools. I view them as a last resort, at this point in engineering history. If you're someone that stays up late into the night staring at your dotfiles from neovim... I'm happy for you. Be happy for me too?
|
|
33
|
+
|
|
34
|
+
## Data / Security
|
|
35
|
+
|
|
36
|
+
TypeSlayer supports Linux x64, macOS x64 (Intel), macOS ARM64 (Apple Silicon), and Windows x64. Please note that next year is the year of the Linux desktop.
|
|
37
|
+
|
|
38
|
+
TypeSlayer currently does not collect any analytics - although it probably will try to collect "someone somewhere ran it at XYZ timestamp" data in the future. All data is stored:
|
|
39
|
+
|
|
40
|
+
- Linux: `~/.local/share/typeslayer/`
|
|
41
|
+
- macOS: `~/Library/Application Support/typeslayer/`
|
|
42
|
+
- Windows: `%APPDATA%\typeslayer\`
|
|
43
|
+
|
|
44
|
+
This tool can read any file the running user can read and it can run package.json scripts (so treat it as you would your terminal).
|
|
45
|
+
|
|
46
|
+
## Contributing
|
|
47
|
+
|
|
48
|
+
1. all commits (and therefor PR merges) must be the next bar from "My Name Is" by Eminem, until further notice
|
|
49
|
+
2. no further requirements
|
|
50
|
+
|
|
51
|
+
## Thank You
|
|
52
|
+
|
|
53
|
+
This app is built with Tauri, TanStack, Vite, React, MUI, and of course, TypeScript.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { arch, platform } from "node:os";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
|
|
12
|
+
// Store the original directory where the user ran the command
|
|
13
|
+
const userCwd = process.cwd();
|
|
14
|
+
|
|
15
|
+
// Get the binary path based on platform
|
|
16
|
+
const getBinaryInfo = () => {
|
|
17
|
+
const plat = platform();
|
|
18
|
+
const architecture = arch();
|
|
19
|
+
|
|
20
|
+
let platformDir, binaryName;
|
|
21
|
+
|
|
22
|
+
if (plat === "linux" && architecture === "x64") {
|
|
23
|
+
platformDir = "linux-x64";
|
|
24
|
+
binaryName = "typeslayer";
|
|
25
|
+
} else if (plat === "darwin" && architecture === "x64") {
|
|
26
|
+
platformDir = "darwin-x64";
|
|
27
|
+
binaryName = "typeslayer";
|
|
28
|
+
} else if (plat === "darwin" && architecture === "arm64") {
|
|
29
|
+
platformDir = "darwin-arm64";
|
|
30
|
+
binaryName = "typeslayer";
|
|
31
|
+
} else if (plat === "win32" && architecture === "x64") {
|
|
32
|
+
platformDir = "win32-x64";
|
|
33
|
+
binaryName = "typeslayer.exe";
|
|
34
|
+
} else {
|
|
35
|
+
throw new Error(`Unsupported platform: ${plat}-${architecture}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
path: join(__dirname, "..", "binaries", platformDir, binaryName),
|
|
40
|
+
platform: `${plat}-${architecture}`,
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const binaryInfo = getBinaryInfo();
|
|
46
|
+
|
|
47
|
+
if (!existsSync(binaryInfo.path)) {
|
|
48
|
+
console.error(`\n❌ Binary not available for ${binaryInfo.platform}`);
|
|
49
|
+
console.error(
|
|
50
|
+
`\nYour platform (${binaryInfo.platform}) is not yet supported.`,
|
|
51
|
+
);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const proc = spawn(binaryInfo.path, [], {
|
|
56
|
+
stdio: "inherit",
|
|
57
|
+
env: {
|
|
58
|
+
...process.env,
|
|
59
|
+
USER_CWD: userCwd,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
proc.on("exit", (code) => {
|
|
64
|
+
process.exit(code || 0);
|
|
65
|
+
});
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error("Error:", error.message);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,100 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
"name": "typeslayer",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Slay your TypeScript types",
|
|
5
|
+
"private": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"typescript",
|
|
9
|
+
"ts",
|
|
10
|
+
"tauri",
|
|
11
|
+
"desktop",
|
|
12
|
+
"benchmarking",
|
|
13
|
+
"performance"
|
|
14
|
+
],
|
|
15
|
+
"author": "Dimitri Mitropoulos",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/dimitropoulos/typeslayer.git"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/dimitropoulos/typeslayer/issues"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/dimitropoulos/typeslayer#readme",
|
|
25
|
+
"bin": {
|
|
26
|
+
"typeslayer": "bin/typeslayer.js"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"bin",
|
|
30
|
+
"binaries",
|
|
31
|
+
"scripts"
|
|
32
|
+
],
|
|
33
|
+
"os": [
|
|
34
|
+
"linux",
|
|
35
|
+
"darwin",
|
|
36
|
+
"win32"
|
|
37
|
+
],
|
|
38
|
+
"cpu": [
|
|
39
|
+
"x64",
|
|
40
|
+
"arm64"
|
|
41
|
+
],
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=24.0.0",
|
|
44
|
+
"pnpm": ">=10.0.0"
|
|
45
|
+
},
|
|
46
|
+
"packageManager": "pnpm@10.6.5",
|
|
47
|
+
"scripts": {
|
|
48
|
+
"postinstall": "node scripts/postinstall.js",
|
|
49
|
+
"dev": "vite",
|
|
50
|
+
"build": "tsc && vite build",
|
|
51
|
+
"preview": "vite preview",
|
|
52
|
+
"tauri": "tauri"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@tauri-apps/api": "2.9.0",
|
|
56
|
+
"@tauri-apps/plugin-clipboard-manager": "~2",
|
|
57
|
+
"@tauri-apps/plugin-dialog": "2.4.2",
|
|
58
|
+
"@tauri-apps/plugin-opener": "2.5.2",
|
|
59
|
+
"@tauri-apps/plugin-upload": "^2.3.2",
|
|
60
|
+
"react": "19.2.0",
|
|
61
|
+
"react-dom": "19.2.0"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@emotion/react": "11.14.0",
|
|
65
|
+
"@emotion/styled": "11.14.1",
|
|
66
|
+
"@fastify/cors": "11.1.0",
|
|
67
|
+
"@fastify/static": "8.3.0",
|
|
68
|
+
"@fontsource/roboto": "5.2.9",
|
|
69
|
+
"@mui/icons-material": "7.3.5",
|
|
70
|
+
"@mui/material": "7.3.5",
|
|
71
|
+
"@mui/x-tree-view": "8.19.0",
|
|
72
|
+
"@tanstack/react-query": "5.90.10",
|
|
73
|
+
"@tanstack/react-router": "1.139.3",
|
|
74
|
+
"@tauri-apps/cli": "2.9.4",
|
|
75
|
+
"@types/mime-types": "3.0.1",
|
|
76
|
+
"@types/node": "24.10.1",
|
|
77
|
+
"@types/ramda": "0.31.1",
|
|
78
|
+
"@types/react": "19.2.6",
|
|
79
|
+
"@types/react-dom": "19.2.3",
|
|
80
|
+
"@typeslayer/analyze-trace": "workspace:*",
|
|
81
|
+
"@typeslayer/validate": "workspace:*",
|
|
82
|
+
"@vitejs/plugin-react": "5.1.1",
|
|
83
|
+
"concurrently": "9.2.1",
|
|
84
|
+
"fastify": "5.6.2",
|
|
85
|
+
"mime-types": "3.0.2",
|
|
86
|
+
"ramda": "0.32.0",
|
|
87
|
+
"ramda-adjunct": "5.1.0",
|
|
88
|
+
"react": "19.2.0",
|
|
89
|
+
"react-dom": "19.2.0",
|
|
90
|
+
"tsx": "4.20.6",
|
|
91
|
+
"typescript": "5.9.3",
|
|
92
|
+
"vite": "7.2.4",
|
|
93
|
+
"zod": "4.1.12"
|
|
94
|
+
},
|
|
95
|
+
"pnpm": {
|
|
96
|
+
"onlyBuiltDependencies": [
|
|
97
|
+
"esbuild"
|
|
98
|
+
]
|
|
99
|
+
}
|
|
9
100
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { chmodSync, createWriteStream, existsSync, mkdirSync } from "node:fs";
|
|
4
|
+
import { get } from "node:https";
|
|
5
|
+
import { arch, platform } from "node:os";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
|
|
12
|
+
const PACKAGE_VERSION = process.env.npm_package_version;
|
|
13
|
+
|
|
14
|
+
const getBinaryInfo = () => {
|
|
15
|
+
const plat = platform();
|
|
16
|
+
const architecture = arch();
|
|
17
|
+
|
|
18
|
+
let platformDir, binaryName;
|
|
19
|
+
|
|
20
|
+
if (plat === "linux" && architecture === "x64") {
|
|
21
|
+
platformDir = "linux-x64";
|
|
22
|
+
binaryName = "typeslayer";
|
|
23
|
+
} else if (plat === "darwin" && architecture === "x64") {
|
|
24
|
+
platformDir = "darwin-x64";
|
|
25
|
+
binaryName = "typeslayer";
|
|
26
|
+
} else if (plat === "darwin" && architecture === "arm64") {
|
|
27
|
+
platformDir = "darwin-arm64";
|
|
28
|
+
binaryName = "typeslayer";
|
|
29
|
+
} else if (plat === "win32" && architecture === "x64") {
|
|
30
|
+
platformDir = "win32-x64";
|
|
31
|
+
binaryName = "typeslayer.exe";
|
|
32
|
+
} else {
|
|
33
|
+
console.warn(`⚠️ Platform ${plat}-${architecture} is not supported`);
|
|
34
|
+
process.exit(0); // Don't fail the install, just skip
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return { platformDir, binaryName };
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const downloadBinary = (url, destPath) => {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
console.log(`📦 Downloading binary from ${url}...`);
|
|
43
|
+
|
|
44
|
+
get(url, (response) => {
|
|
45
|
+
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
46
|
+
// Follow redirect
|
|
47
|
+
return downloadBinary(response.headers.location, destPath).then(
|
|
48
|
+
resolve,
|
|
49
|
+
reject,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (response.statusCode !== 200) {
|
|
54
|
+
reject(
|
|
55
|
+
new Error(
|
|
56
|
+
`Failed to download: ${response.statusCode} ${response.statusMessage}`,
|
|
57
|
+
),
|
|
58
|
+
);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const fileStream = createWriteStream(destPath);
|
|
63
|
+
response.pipe(fileStream);
|
|
64
|
+
|
|
65
|
+
fileStream.on("finish", () => {
|
|
66
|
+
fileStream.close();
|
|
67
|
+
// Make executable on Unix-like systems
|
|
68
|
+
if (process.platform !== "win32") {
|
|
69
|
+
chmodSync(destPath, 0o755);
|
|
70
|
+
}
|
|
71
|
+
console.log("✅ Binary downloaded successfully");
|
|
72
|
+
resolve();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
fileStream.on("error", (err) => {
|
|
76
|
+
reject(err);
|
|
77
|
+
});
|
|
78
|
+
}).on("error", (err) => {
|
|
79
|
+
reject(err);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
(async () => {
|
|
85
|
+
try {
|
|
86
|
+
const { platformDir, binaryName } = getBinaryInfo();
|
|
87
|
+
const binariesDir = join(__dirname, "..", "binaries", platformDir);
|
|
88
|
+
const binaryPath = join(binariesDir, binaryName);
|
|
89
|
+
|
|
90
|
+
// Skip if binary already exists
|
|
91
|
+
if (existsSync(binaryPath)) {
|
|
92
|
+
console.log("✅ Binary already present, skipping download");
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Create directory if it doesn't exist
|
|
97
|
+
mkdirSync(binariesDir, { recursive: true });
|
|
98
|
+
|
|
99
|
+
// Download from GitHub release
|
|
100
|
+
const releaseUrl = `https://github.com/dimitropoulos/typeslayer/releases/download/typeslayer-v${PACKAGE_VERSION}/${binaryName}`;
|
|
101
|
+
|
|
102
|
+
await downloadBinary(releaseUrl, binaryPath);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error("❌ Failed to download binary:", error.message);
|
|
105
|
+
console.error(
|
|
106
|
+
"You can manually download the binary from: https://github.com/dimitropoulos/typeslayer/releases",
|
|
107
|
+
);
|
|
108
|
+
// Don't fail the install, just warn
|
|
109
|
+
process.exit(0);
|
|
110
|
+
}
|
|
111
|
+
})();
|
package/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
console.log('typeslayer');
|