nuka-code
Version:
A package brought to you by the Nuka-Cola Corporation to zap away those pesky `cache`, `node_modules`, and other related files & directories.
534 lines (529 loc) • 27.1 kB
JavaScript
#!/usr/bin/env node
import chalk from 'chalk';
import consola2 from 'consola';
import { glob } from 'glob';
import { match, P } from 'ts-pattern';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import yoctoSpinner from 'yocto-spinner';
import { exec } from 'child_process';
import utils from 'util';
import { writeFile, access, readdir, readFile } from 'fs/promises';
import path3 from 'path';
import { constants } from 'fs';
import ignore from 'ignore';
import { rimraf } from 'rimraf';
var vaultBoy2 = `
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28C0\u28C0\u28C0\u28F4\u2837\u28F6\u28C4\u28C0\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2880\u28FC\u28FF\u28F7\u28FE\u281F\u281B\u281B\u280B\u2800\u2808\u2809\u281B\u28FF\u28E6\u2840\u2800\u2800\u2800\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28B8\u28FF\u2808\u2809\u28E1\u2874\u2836\u28E4\u2836\u2837\u28E6\u2800\u28C0\u28C8\u283B\u28FF\u2840\u2800\u2800\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28B8\u28FF\u28F3\u28FE\u28EF\u2800\u2800\u2800\u2800\u28E4\u2848\u2809\u2809\u28B9\u2847\u28B9\u28F7\u2800\u2800\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u28C0\u28C0\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2898\u28FF\u280B\u28E4\u2844\u2800\u28E4\u2800\u2880\u2848\u2813\u2800\u28FC\u28FF\u28C4\u28B8\u28FF\u2800\u2800\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u28F4\u287F\u281B\u281B\u28FF\u2867\u2800\u2800\u2800\u2800\u2800\u2800\u28FC\u285F\u2800\u281B\u28A1\u287E\u280B\u2800\u2838\u2807\u2800\u2800\u28FE\u28FF\u28FF\u28FE\u281F\u2800\u2800\u2800\u2800\u2800\u2800
\u2800\u2800\u28B8\u28FF\u2800\u2800\u28B0\u28FF\u2807\u2800\u2800\u2800\u2800\u2800\u2800\u28FF\u2847\u2880\u2840\u2818\u2817\u2800\u2800\u28E4\u2840\u2800\u2800\u2808\u281B\u28BF\u28FF\u2800\u2800\u2800\u2800\u2800\u2800\u2800
\u2880\u28E0\u28E8\u28FF\u28C6\u2800\u2839\u28FF\u2844\u2800\u2800\u2800\u2800\u2800\u2800\u28B8\u28FF\u2839\u282F\u28FF\u28D2\u28DA\u28ED\u283F\u285F\u2800\u2800\u2880\u28E0\u28FE\u287F\u2800\u2800\u2800\u2800\u2800\u2800\u2800
\u28FF\u281B\u2809\u2809\u281B\u2833\u28A6\u2848\u28BF\u28E6\u28C0\u2800\u2800\u2800\u2800\u2800\u28BB\u28F7\u2840\u2818\u281B\u2803\u2800\u2800\u2800\u2880\u28F4\u28FF\u28DF\u2801\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800
\u28FF\u2836\u2836\u2836\u2826\u28E4\u28E8\u2847\u2800\u28FF\u287F\u28B7\u28F6\u28F6\u28E6\u28F4\u28FE\u28FF\u285F\u2836\u28E4\u28C0\u28C0\u2840\u2898\u28FF\u280F\u28B9\u285F\u283F\u28F7\u28E6\u28C0\u2800\u2800\u2800\u2800\u2800
\u28FF\u28E4\u28E4\u28E4\u28C0\u28C0\u2899\u2846\u28F0\u288F\u2847\u2800\u2800\u2808\u2809\u2809\u2800\u2800\u2833\u28C4\u2848\u281B\u281B\u281B\u280B\u2801\u28C0\u28FC\u2803\u2800\u2800\u2819\u283B\u28FF\u28E6\u2840\u2800\u2800
\u28FF\u2845\u28B0\u28C4\u2808\u2809\u28FB\u2881\u287D\u28F8\u2803\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2808\u2819\u281B\u28E6\u2800\u2800\u28B9\u284B\u2801\u2800\u2800\u2800\u2800\u2800\u2808\u283B\u28FF\u28C6\u2800
\u2818\u283B\u28F6\u28ED\u28FF\u28FF\u28FF\u28DF\u28F1\u281F\u2800\u2800\u2800\u2800\u2880\u28E0\u28FE\u2807\u2800\u2800\u2800\u2800\u28B9\u2800\u2800\u2808\u2847\u2800\u2800\u28BF\u2800\u2800\u2800\u2800\u2800\u2808\u28BB\u2847
\u2800\u2800\u2800\u2809\u2809\u2809\u281B\u281B\u283F\u28F7\u2856\u2812\u28F6\u287F\u281B\u28FF\u2800\u2800\u2800\u2800\u2800\u2800\u2838\u2847\u2800\u2800\u28B9\u2800\u2800\u28B8\u2846\u28F4\u2856\u2800\u2800\u2800\u2800\u28FF
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2880\u28FF\u2846\u2800\u2800\u2800\u2800\u2800\u2800\u2847\u2800\u2800\u28B8\u2846\u2800\u2808\u28FF\u280F\u2800\u2800\u2800\u2800\u28F0\u2807
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2818\u28FF\u28E7\u2840\u2800\u2800\u2800\u2800\u2800\u2847\u2800\u2800\u2800\u2847\u28C0\u28F4\u28BF\u28C0\u2840\u2800\u2800\u28F0\u284F\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28A0\u28FF\u284F\u2819\u2833\u2836\u2826\u28E4\u28E4\u2847\u2800\u2800\u2800\u281B\u2809\u2800\u28B8\u2809\u2819\u28B7\u28FE\u285F\u2801\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2838\u28FF\u2847\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2880\u28E0\u28FE\u2846\u28C0\u28FC\u287F\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28A0\u28FF\u2819\u2837\u28A6\u28E4\u28C4\u28C0\u28C0\u28E0\u28E4\u28E4\u2876\u283E\u281B\u2809\u28B8\u28C7\u28F9\u28FF\u2807\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28FE\u285F\u2800\u2800\u2800\u2800\u2808\u2809\u2809\u2809\u28C4\u2800\u2800\u2800\u2800\u2800\u2800\u28FF\u28FF\u2801\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28FF\u2847\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28FE\u2803\u2800\u2800\u2800\u2800\u2800\u2800\u28FF\u287F\u2800\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28B0\u28FF\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28FC\u2847\u2800\u2800\u2800\u2800\u2800\u2800\u28A0\u28FF\u2847\u2800\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28FE\u284F\u2800\u2800\u2800\u2800\u2800\u2800\u28F8\u28FF\u28C7\u2800\u2800\u2800\u2800\u2800\u2800\u28B8\u28FF\u2800\u2800\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28FC\u28FF\u2801\u2800\u2800\u2800\u2800\u2800\u28A0\u28FF\u28FF\u28FF\u2800\u2800\u2800\u2800\u2800\u2800\u28FE\u287F\u2800\u2800\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28A0\u28FF\u2847\u2800\u2800\u2800\u2800\u2800\u2800\u28FE\u287F\u28B8\u285F\u2800\u2800\u2800\u2800\u2800\u28B0\u28FF\u2847\u2800\u2800\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28B8\u28FF\u2800\u2800\u2800\u2800\u2800\u2800\u28F8\u28FF\u2803\u28B8\u2847\u2800\u2800\u2800\u2800\u2800\u28FC\u28FF\u2800\u2800\u2800\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28B8\u28FF\u28C0\u2800\u2800\u2800\u2880\u28F4\u28FF\u2803\u2800\u28B8\u28F7\u28E6\u28E4\u28E4\u28E4\u28F4\u28FF\u28F7\u28E4\u2840\u2800\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u280F\u2801\u2800\u2800\u2808\u283B\u287F\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u2846\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u283B\u28BF\u287F\u28FF\u28FF\u281F\u2801\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2809\u2809\u2809\u2809\u2809\u2809\u2800\u2800\u2800\u2800\u2800
`;
var logo = `
\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2880\u28C0\u28C0\u28C0\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800
\u2800\u2800\u2800\u2800\u28E0\u2874\u28BE\u2805\u2800\u2800\u2800\u2809\u2801\u2809\u2809\u2830\u2864\u2880\u2800\u2800\u2800
\u2800\u2880\u2816\u281A\u2809\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2811\u2877\u2840\u2800
\u2800\u289E\u2886\u2800\u2800\u2800\u2800\u2800\u2800\u28C0\u2800\u2840\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28A7\u2800
\u2800\u2800\u282B\u2884\u28E0\u28E4\u28C4\u28E4\u28FF\u281B\u281F\u283B\u28BB\u28FF\u28C6\u2800\u2880\u28E0\u28E4\u281E\u2800 \u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
\u2800\u2800\u2800\u2800\u2808\u2809\u2809\u281B\u28BB\u2800\u2800\u2800\u28B8\u283F\u281B\u281B\u280B\u2809\u2801\u2800\u2800 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D
\u2800\u2800\u2800\u2800\u2800\u2800\u2880\u28C0\u283D\u2840\u2840\u28F0\u2838\u28A4\u28C0\u2800\u2800\u2800\u2800\u2800\u2800 \u2588\u2588\u2551\u255A\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557
\u2800\u2800\u2800\u2800\u28B0\u284A\u2800\u2800\u2840\u2880\u2841\u28C0\u28C0\u2800\u2800\u28FC\u2806\u2800\u2800\u2800\u2800 \u2588\u2588\u2551 \u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D
\u2800\u2800\u2800\u2800\u2800\u2809\u2819\u281B\u28BB\u28B9\u280B\u284B\u28FF\u281B\u2809\u2801\u2800\u2800\u2800\u2800\u2800 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
\u2800\u2800\u2800\u2800\u2840\u2824\u2800\u28F0\u28DE\u2838\u2800\u2807\u28B8\u2816\u2850\u2804\u2800\u2800\u2800\u2800\u2800 \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D
\u2800\u28C0\u28F4\u28FE\u28FF\u28FF\u28FE\u28E0\u28CF\u2800\u2864\u28E0\u2848\u28A7\u28DD\u28F7\u28F6\u28C4\u2840\u2800\u2800
\u2808\u2800\u2801\u2808\u2819\u2839\u283F\u283F\u2837\u283B\u287F\u28FF\u283F\u283F\u283F\u283B\u283B\u282F\u283B\u2816\u2846
`;
var logoSmall = `
\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D
\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557
\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D
\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D
`;
var ascii_default = {
vaultBoy2,
logo,
logoSmall};
var execAsync = utils.promisify(exec);
async function isGitDirty(cwd = process.cwd()) {
try {
const { stdout } = await execAsync("git status --short", { cwd });
return stdout.length > 0;
} catch (e) {
return false;
}
}
async function exists(filePath) {
try {
await access(filePath, constants.F_OK);
return true;
} catch {
return false;
}
}
function isLockfile(filePath) {
return match(path3.basename(filePath)).with("pnpm-lock.yaml", () => true).with("yarn.lock", () => true).with("package-lock.json", () => true).otherwise(() => false);
}
function hasLockfile(filePaths) {
return filePaths.some((filePath) => {
return isLockfile(filePath);
});
}
async function readPackageJson(filePath) {
try {
return await readPackageJsonOrThrow(filePath);
} catch (error) {
return null;
}
}
async function readPackageJsonOrThrow(filePath) {
const finalPath = match(filePath).when(
(p) => p.endsWith("/package.json"),
(p) => p
).otherwise((p) => `${p}/package.json`);
const packageJson = await readFile(finalPath, "utf8");
return JSON.parse(packageJson);
}
// src/lib/project.ts
var DIR_CACHE = ".nuke";
var FILE_IGNORE = ".nukeignore";
var FILE_GITIGNORE = ".gitignore";
var ignoreFileCache = null;
async function readIgnoreFile(filePath = process.cwd()) {
try {
if (ignoreFileCache) {
return ignoreFileCache;
}
const ignoreFile = path3.join(filePath, FILE_IGNORE);
ignoreFileCache = await readFile(ignoreFile, "utf8");
return ignoreFileCache;
} catch (error) {
return null;
}
}
async function isInitialized(filePath = process.cwd()) {
const ignoreFile = path3.join(filePath, FILE_IGNORE);
return await exists(ignoreFile);
}
async function initialize(filePath = process.cwd(), force = false) {
const cacheDir = path3.join(filePath, DIR_CACHE);
const ignoreFile = path3.join(filePath, FILE_IGNORE);
const gitignoreFile = path3.join(filePath, FILE_GITIGNORE);
if (!await exists(cacheDir)) {
const packageJson = await readPackageJson(
path3.join(process.cwd(), "package.json")
);
if (!packageJson) {
throw new Error(
"No package.json found in current working directory, please run this command in the root of your project."
);
}
const root = await (async () => {
if (force === true) {
return true;
}
const root2 = await isRoot();
if (!root2) {
consola2.info(
`Uh oh! You don't have a ${DIR_CACHE} directory in your current working directory.`
);
return await consola2.prompt("Are you in the root of your project?", {
type: "confirm",
default: false
});
}
return root2;
})();
if (root && !await isInitialized(filePath)) {
consola2.info("Initializing project...");
if (!await exists(ignoreFile)) {
await writeFile(
ignoreFile,
"# Add your project's ignore patterns here for the files you DO NOT want to nuke"
);
}
await appendToGitignore(gitignoreFile);
return true;
}
}
return false;
}
async function appendToGitignore(gitignoreFile) {
const nukeIgnoreContents = `
# Nuke (nuka-cola)
.nuke
!.nukeignore
`.trim();
if (!await exists(gitignoreFile)) {
consola2.info("No .gitignore file found, creating one...");
await writeFile(gitignoreFile, `${nukeIgnoreContents}
`);
}
const gitignoreContents = await readFile(gitignoreFile, "utf8");
if (gitignoreContents.includes(".nuke") || gitignoreContents.includes("!.nukeignore")) {
return;
}
await writeFile(
gitignoreFile,
`${gitignoreContents}
${nukeIgnoreContents}
`
);
}
async function isRoot(filePath = process.cwd()) {
const allFilePaths = await readdir(filePath);
return hasLockfile(allFilePaths);
}
var DEFAULT_OPTIONS = {
trailingSlash: false,
lineAscii: false
};
var SYMBOLS_ANSI = {
BRANCH: chalk.gray("\u251C\u2500\u2500 "),
INDENT: " ",
LAST_BRANCH: chalk.gray("\u2514\u2500\u2500 "),
VERTICAL: chalk.gray("\u2502 ")
};
var SYMBOLS_ASCII = {
BRANCH: chalk.gray("|-- "),
INDENT: " ",
LAST_BRANCH: chalk.gray("`-- "),
VERTICAL: chalk.gray("| ")
};
function toTree(filePaths) {
const sortedPaths = [...filePaths].sort();
const root = {
name: "<root>",
path: "",
isDirectory: true,
children: []
};
for (const filePath of sortedPaths) {
const parts = filePath.split(path3.sep);
let current = root;
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
const isLast = i === parts.length - 1;
const currentPath = parts.slice(0, i + 1).join(path3.sep);
let node = current.children?.find((child) => child.name === part);
if (!node) {
node = {
name: part,
path: currentPath,
isDirectory: !isLast || i < parts.length - 1,
// A node is a directory if it's not the last part OR if it has children
children: []
// Always create children array for potential future children
};
current.children?.push(node);
} else if (!isLast) {
node.isDirectory = true;
if (!node.children) {
node.children = [];
}
}
current = node;
}
}
function cleanupEmptyChildren(node) {
if (node.children) {
const filteredChildren = node.children.map((child) => cleanupEmptyChildren(child)).filter((child) => child.children?.length !== 0);
return {
...node,
children: filteredChildren.length > 0 ? filteredChildren : void 0
};
}
return node;
}
return cleanupEmptyChildren(root);
}
function printNode(node, currentDepth, precedingSymbols, options, isLast) {
const lines = [];
const SYMBOLS = options.lineAscii ? SYMBOLS_ASCII : SYMBOLS_ANSI;
const line = [precedingSymbols];
if (currentDepth >= 1) {
line.push(isLast ? SYMBOLS.LAST_BRANCH : SYMBOLS.BRANCH);
}
line.push(
node.name === "<root>" ? `${chalk.cyan("<root>")}` : `${chalk.red(node.name)}`
);
if (node.isDirectory && options.trailingSlash) {
line.push("/");
}
lines.push(line.join(""));
if (node.children) {
const children = node.children;
children.forEach((child, index) => {
const isChildLast = index === children.length - 1;
const childLines = printNode(
child,
currentDepth + 1,
precedingSymbols + (isLast ? SYMBOLS.INDENT : SYMBOLS.VERTICAL),
options,
isChildLast
);
lines.push(...childLines);
});
}
return lines;
}
function printTree(filePaths, options = {}) {
const combinedOptions = { ...DEFAULT_OPTIONS, ...options };
const tree = toTree(filePaths);
console.log(printNode(tree, 0, "", combinedOptions, true).join("\n"));
}
function unique(array) {
return Array.from(new Set(array));
}
function toDeepGlob(filePaths) {
return unique(
filePaths.flatMap((filePath) => {
if (filePath.includes("node_modules")) {
return [filePath, `**/${filePath}`];
}
return [filePath, `**/[!node_modules]**/${filePath}`];
})
);
}
// src/nuke.ts
async function nukeEverything(rootDir = process.cwd()) {
const runId = Date.now();
const cache = await nukeCache(rootDir, runId);
const builds = await nukeBuilds(rootDir, runId);
const nodeModules = await nukeNodeModules(rootDir, runId);
return {
cache,
builds,
node_modules: nodeModules
};
}
async function nukeNodeModules(rootDir = process.cwd(), runId = Date.now()) {
const ignoreHelper = await createIgnoreFileHelper(rootDir);
return await rimraf(getNukeNodeModulesGlob(), {
glob: true,
filter: async (filePath) => {
return !ignoreHelper.test(path3.relative(rootDir, filePath)).ignored;
}
});
}
async function nukeCache(rootDir = process.cwd(), runId = Date.now()) {
const ignoreHelper = await createIgnoreFileHelper(rootDir);
return await rimraf(getNukeCacheGlob(), {
glob: true,
filter: async (filePath) => {
return !ignoreHelper.test(path3.relative(rootDir, filePath)).ignored;
}
});
}
async function nukeBuilds(rootDir = process.cwd(), runId = Date.now()) {
const ignoreHelper = await createIgnoreFileHelper(rootDir);
return await rimraf(getNukeBuildsGlob(), {
glob: true,
filter: async (filePath) => {
return !ignoreHelper.test(path3.relative(rootDir, filePath)).ignored;
}
});
}
function getNukeEverythingGlob() {
return unique([
...getNukeNodeModulesGlob(),
...getNukeCacheGlob(),
...getNukeBuildsGlob()
]);
}
function getNukeNodeModulesGlob() {
return [
// Deeply nested node_modules
"node_modules",
"**/node_modules",
// Yarn 2+
".pnp.cjs",
".pnp.loader.mjs"
];
}
function getNukeCacheGlob() {
return toDeepGlob([".turbo", ".nx/cache"]);
}
function getNukeBuildsGlob() {
return toDeepGlob([
// Build artifacts
"dist",
"out",
"output",
"outputs",
"bundle",
".output",
".outputs",
".build",
// Frameworks
".vercel",
".next",
".nuxt",
".svelte-kit",
".vinxi",
".vuepress/dist",
"storybook-static",
"coverage",
"public/build"
]);
}
async function createIgnoreFileHelper(rootDir = process.cwd()) {
const ignoreFile = await readIgnoreFile(rootDir);
return ignore().add(ignoreFile ?? "");
}
// src/cli.ts
var cli = yargs(hideBin(process.argv));
cli.scriptName("nuke").version().wrap(Math.min(100, cli.terminalWidth())).usage(
[
match(cli.terminalWidth()).with(
P.number,
(s) => s > 100,
() => ascii_default.logo
).with(
P.number,
(s) => s >= 80,
() => ascii_default.logoSmall
).otherwise(() => `\u2622\uFE0F ${chalk.bold.green("Nuka-Code")}`),
match(cli.terminalWidth()).with(
P.number,
(s) => s >= 80,
() => "\n--------------------------------------------------------------------------\n"
).otherwise(() => "---------------------------------------------\n"),
`${chalk.bold.green("nuke")} - A CLI tool for ${chalk.italic("nuking")} your non-essentials aka your node_modules, cache, and build directories.`
].join("\n")
).option("no-fun", {
type: "boolean",
description: "Do not print ascii art to the console",
default: false
}).option("verbose", {
alias: "V",
type: "boolean",
description: "Run with verbose output",
default: false
}).showHelpOnFail(false).fail((msg, err, yargs2) => {
consola2.error(err.message);
process.exit(1);
}).command(
["*", "it"],
`Time to ${chalk.bold("NUKE IT")}! Drop the nuke on your project`,
(yargs2) => {
return yargs2.positional("type", {
describe: "The type of nuke to perform",
choices: ["all", "node_modules", "cache", "build"],
default: "all"
}).positional("force", {
describe: "DANGER: Bypassing safety checks is not recommended by Vault-Tec",
type: "boolean",
default: false
});
},
async (argv) => {
consola2.start("Pushing the button...");
consola2.info("You have 5 seconds to reconsider...");
let i = 0;
while (i < 5) {
consola2.info(`${5 - i} seconds remaining...`);
await new Promise((resolve) => setTimeout(resolve, 1e3));
i++;
}
if (await isGitDirty()) {
if (argv.force === true) {
consola2.warn(
"You have unsaved changes, but you are forcing the nuke... good luck!"
);
} else {
throw new Error("You have unsaved changes, please commit them first");
}
}
await initialize();
const spinner = yoctoSpinner({
text: "Nuking your project... brace for impact!"
}).start();
const result = await match(argv.type).with("all", () => nukeEverything(process.cwd())).with("node_modules", () => nukeNodeModules(process.cwd())).with("cache", () => nukeCache(process.cwd())).with("build", () => nukeBuilds(process.cwd())).otherwise(() => Promise.resolve(false));
spinner.success();
if (result) {
if (argv.noFun !== true) {
console.log(ascii_default.vaultBoy2);
}
consola2.success("You successfully nuked your project, good job!");
} else {
consola2.info(
"Well this is awkward... nothing was nuked. Maybe you should try again?"
);
}
}
).command(
"list",
"List all the files that would be nuked",
(yargs2) => {
return yargs2.positional("type", {
describe: "The type of nuke to perform",
choices: ["all", "node_modules", "cache", "build"],
default: "all"
}).option("glob", {
describe: "Show the glob patterns instead of the files",
type: "boolean",
default: false
});
},
async (argv) => {
const globbed = getNukeEverythingGlob();
if (argv.glob) {
consola2.info("The following globs will be nuked:\n");
printList(globbed, (g) => chalk.cyan(g));
console.log(
"\n (this does not include what is ignored in your .nukeignore file)"
);
} else {
consola2.info("The following files & directories will be nuked:\n");
const finalGlobbed = globbed.map((g) => {
if (argv.verbose) {
return `${g}/**/*`;
}
return g;
});
const found = await glob(finalGlobbed, {
root: process.cwd(),
includeChildMatches: argv.verbose
});
const ignoreHelper = await createIgnoreFileHelper(process.cwd());
printTree(ignoreHelper.filter(found));
}
}
).command("init", "Initialize the project", async (argv) => {
if (await isInitialized(process.cwd())) {
consola2.success("Project already initialized");
return;
}
await initialize(process.cwd(), true);
consola2.success("Project initialized");
}).parse();
function printList(items, transform = (i) => i) {
console.log(items.map((i) => ` \u2022 ${chalk.red(transform(i))}`).join("\n"));
}