UNPKG

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
#!/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")); }