A CLI for scaffolding ATProto web applications

does execa work

besaid.zone 9ec8b2ad b4bc81ef

verified
+179 -27
+7 -27
__tests__/cli.test.ts
··· 1 - import child_process from "node:child_process"; 2 1 import { join } from "node:path"; 3 2 import { expect, test } from "vitest"; 3 + import type { SyncOptions } from "execa" 4 + import {execaCommandSync} from "execa" 4 5 5 6 const CLI_PATH = join(import.meta.dirname, ".."); 6 7 7 - async function run(args: string[], input = "\n") { 8 - const proc = child_process.spawn("node", [CLI_PATH, ...args], { 9 - stdio: ["pipe", "pipe", "pipe"], 10 - }); 11 - 12 - let stdout = ""; 13 - let stderr = ""; 14 - 15 - proc.stdout?.on("data", (data) => { 16 - stdout += data.toString(); 17 - }); 18 - proc.stderr?.on("data", (data) => { 19 - stderr += data.toString(); 20 - }); 21 - 22 - proc.stdin?.write(input); 23 - proc.stdin?.end(); 24 - 25 - return new Promise<{ stdout: string; stderr: string; code: number | null }>( 26 - (resolve, reject) => { 27 - proc.on("close", (code) => { 28 - resolve({ stdout, stderr, code }); 29 - }); 30 - proc.on("error", reject); 31 - }, 32 - ); 8 + async function run(args: string[], options?: SyncOptions) { 9 + return execaCommandSync(`node ${CLI_PATH} ${args.join(" ")}`, { 10 + env: { ...process.env, _VITE_TEST_CLI: 'true' }, 11 + ...options 12 + }) 33 13 } 34 14 35 15 test("should prompt for project name", async () => {
+1
package.json
··· 41 41 "@clack/prompts": "^1.0.1", 42 42 "@types/node": "^22.0.0", 43 43 "citty": "^0.2.1", 44 + "execa": "^9.6.1", 44 45 "lefthook": "^2.1.1", 45 46 "oxfmt": "^0.32.0", 46 47 "picocolors": "^1.1.1",
+171
pnpm-lock.yaml
··· 21 21 citty: 22 22 specifier: ^0.2.1 23 23 version: 0.2.1 24 + execa: 25 + specifier: ^9.6.1 26 + version: 9.6.1 24 27 lefthook: 25 28 specifier: ^2.1.1 26 29 version: 2.1.1 ··· 603 606 cpu: [x64] 604 607 os: [win32] 605 608 609 + '@sec-ant/readable-stream@0.4.1': 610 + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} 611 + 612 + '@sindresorhus/merge-streams@4.0.0': 613 + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} 614 + engines: {node: '>=18'} 615 + 606 616 '@standard-schema/spec@1.1.0': 607 617 resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} 608 618 ··· 684 694 engines: {node: ^20.19.0 || >=22.12.0} 685 695 hasBin: true 686 696 697 + cross-spawn@7.0.6: 698 + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 699 + engines: {node: '>= 8'} 700 + 687 701 defu@6.1.4: 688 702 resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} 689 703 ··· 711 725 estree-walker@3.0.3: 712 726 resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 713 727 728 + execa@9.6.1: 729 + resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} 730 + engines: {node: ^18.19.0 || >=20.5.0} 731 + 714 732 expect-type@1.3.0: 715 733 resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} 716 734 engines: {node: '>=12.0.0'} ··· 724 742 picomatch: 725 743 optional: true 726 744 745 + figures@6.1.0: 746 + resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} 747 + engines: {node: '>=18'} 748 + 727 749 fsevents@2.3.3: 728 750 resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 729 751 engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 730 752 os: [darwin] 731 753 754 + get-stream@9.0.1: 755 + resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} 756 + engines: {node: '>=18'} 757 + 732 758 get-tsconfig@4.13.6: 733 759 resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} 734 760 735 761 hookable@6.0.1: 736 762 resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==} 763 + 764 + human-signals@8.0.1: 765 + resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} 766 + engines: {node: '>=18.18.0'} 737 767 738 768 import-without-cache@0.2.5: 739 769 resolution: {integrity: sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A==} 740 770 engines: {node: '>=20.19.0'} 771 + 772 + is-plain-obj@4.1.0: 773 + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} 774 + engines: {node: '>=12'} 775 + 776 + is-stream@4.0.1: 777 + resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} 778 + engines: {node: '>=18'} 779 + 780 + is-unicode-supported@2.1.0: 781 + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} 782 + engines: {node: '>=18'} 783 + 784 + isexe@2.0.0: 785 + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 741 786 742 787 jsesc@3.1.0: 743 788 resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} ··· 806 851 engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 807 852 hasBin: true 808 853 854 + npm-run-path@6.0.0: 855 + resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} 856 + engines: {node: '>=18'} 857 + 809 858 obug@2.1.1: 810 859 resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} 811 860 ··· 814 863 engines: {node: ^20.19.0 || >=22.12.0} 815 864 hasBin: true 816 865 866 + parse-ms@4.0.0: 867 + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} 868 + engines: {node: '>=18'} 869 + 870 + path-key@3.1.1: 871 + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 872 + engines: {node: '>=8'} 873 + 874 + path-key@4.0.0: 875 + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} 876 + engines: {node: '>=12'} 877 + 817 878 pathe@2.0.3: 818 879 resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} 819 880 ··· 827 888 postcss@8.5.6: 828 889 resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} 829 890 engines: {node: ^10 || ^12 || >=14} 891 + 892 + pretty-ms@9.3.0: 893 + resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} 894 + engines: {node: '>=18'} 830 895 831 896 quansync@1.0.0: 832 897 resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} ··· 868 933 engines: {node: '>=10'} 869 934 hasBin: true 870 935 936 + shebang-command@2.0.0: 937 + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 938 + engines: {node: '>=8'} 939 + 940 + shebang-regex@3.0.0: 941 + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 942 + engines: {node: '>=8'} 943 + 871 944 siginfo@2.0.0: 872 945 resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} 873 946 947 + signal-exit@4.1.0: 948 + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 949 + engines: {node: '>=14'} 950 + 874 951 sisteransi@1.0.5: 875 952 resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} 876 953 ··· 883 960 884 961 std-env@3.10.0: 885 962 resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} 963 + 964 + strip-final-newline@4.0.0: 965 + resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} 966 + engines: {node: '>=18'} 886 967 887 968 tinybench@2.9.0: 888 969 resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} ··· 951 1032 undici-types@6.21.0: 952 1033 resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} 953 1034 1035 + unicorn-magic@0.3.0: 1036 + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} 1037 + engines: {node: '>=18'} 1038 + 954 1039 unrun@0.2.27: 955 1040 resolution: {integrity: sha512-Mmur1UJpIbfxasLOhPRvox/QS4xBiDii71hMP7smfRthGcwFL2OAmYRgduLANOAU4LUkvVamuP+02U+c90jlrw==} 956 1041 engines: {node: '>=20.19.0'} ··· 1035 1120 jsdom: 1036 1121 optional: true 1037 1122 1123 + which@2.0.2: 1124 + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1125 + engines: {node: '>= 8'} 1126 + hasBin: true 1127 + 1038 1128 why-is-node-running@2.3.0: 1039 1129 resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} 1040 1130 engines: {node: '>=8'} 1041 1131 hasBin: true 1132 + 1133 + yoctocolors@2.1.2: 1134 + resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} 1135 + engines: {node: '>=18'} 1042 1136 1043 1137 snapshots: 1044 1138 ··· 1371 1465 '@rollup/rollup-win32-x64-msvc@4.57.1': 1372 1466 optional: true 1373 1467 1468 + '@sec-ant/readable-stream@0.4.1': {} 1469 + 1470 + '@sindresorhus/merge-streams@4.0.0': {} 1471 + 1374 1472 '@standard-schema/spec@1.1.0': {} 1375 1473 1376 1474 '@tybys/wasm-util@0.10.1': ··· 1452 1550 1453 1551 create-vite@8.3.0: {} 1454 1552 1553 + cross-spawn@7.0.6: 1554 + dependencies: 1555 + path-key: 3.1.1 1556 + shebang-command: 2.0.0 1557 + which: 2.0.2 1558 + 1455 1559 defu@6.1.4: {} 1456 1560 1457 1561 dts-resolver@2.1.3: {} ··· 1493 1597 dependencies: 1494 1598 '@types/estree': 1.0.8 1495 1599 1600 + execa@9.6.1: 1601 + dependencies: 1602 + '@sindresorhus/merge-streams': 4.0.0 1603 + cross-spawn: 7.0.6 1604 + figures: 6.1.0 1605 + get-stream: 9.0.1 1606 + human-signals: 8.0.1 1607 + is-plain-obj: 4.1.0 1608 + is-stream: 4.0.1 1609 + npm-run-path: 6.0.0 1610 + pretty-ms: 9.3.0 1611 + signal-exit: 4.1.0 1612 + strip-final-newline: 4.0.0 1613 + yoctocolors: 2.1.2 1614 + 1496 1615 expect-type@1.3.0: {} 1497 1616 1498 1617 fdir@6.5.0(picomatch@4.0.3): 1499 1618 optionalDependencies: 1500 1619 picomatch: 4.0.3 1501 1620 1621 + figures@6.1.0: 1622 + dependencies: 1623 + is-unicode-supported: 2.1.0 1624 + 1502 1625 fsevents@2.3.3: 1503 1626 optional: true 1504 1627 1628 + get-stream@9.0.1: 1629 + dependencies: 1630 + '@sec-ant/readable-stream': 0.4.1 1631 + is-stream: 4.0.1 1632 + 1505 1633 get-tsconfig@4.13.6: 1506 1634 dependencies: 1507 1635 resolve-pkg-maps: 1.0.0 1508 1636 1509 1637 hookable@6.0.1: {} 1510 1638 1639 + human-signals@8.0.1: {} 1640 + 1511 1641 import-without-cache@0.2.5: {} 1642 + 1643 + is-plain-obj@4.1.0: {} 1644 + 1645 + is-stream@4.0.1: {} 1646 + 1647 + is-unicode-supported@2.1.0: {} 1648 + 1649 + isexe@2.0.0: {} 1512 1650 1513 1651 jsesc@3.1.0: {} 1514 1652 ··· 1561 1699 1562 1700 nanoid@3.3.11: {} 1563 1701 1702 + npm-run-path@6.0.0: 1703 + dependencies: 1704 + path-key: 4.0.0 1705 + unicorn-magic: 0.3.0 1706 + 1564 1707 obug@2.1.1: {} 1565 1708 1566 1709 oxfmt@0.32.0: ··· 1587 1730 '@oxfmt/binding-win32-ia32-msvc': 0.32.0 1588 1731 '@oxfmt/binding-win32-x64-msvc': 0.32.0 1589 1732 1733 + parse-ms@4.0.0: {} 1734 + 1735 + path-key@3.1.1: {} 1736 + 1737 + path-key@4.0.0: {} 1738 + 1590 1739 pathe@2.0.3: {} 1591 1740 1592 1741 picocolors@1.1.1: {} ··· 1599 1748 picocolors: 1.1.1 1600 1749 source-map-js: 1.2.1 1601 1750 1751 + pretty-ms@9.3.0: 1752 + dependencies: 1753 + parse-ms: 4.0.0 1754 + 1602 1755 quansync@1.0.0: {} 1603 1756 1604 1757 resolve-pkg-maps@1.0.0: {} ··· 1672 1825 1673 1826 semver@7.7.4: {} 1674 1827 1828 + shebang-command@2.0.0: 1829 + dependencies: 1830 + shebang-regex: 3.0.0 1831 + 1832 + shebang-regex@3.0.0: {} 1833 + 1675 1834 siginfo@2.0.0: {} 1835 + 1836 + signal-exit@4.1.0: {} 1676 1837 1677 1838 sisteransi@1.0.5: {} 1678 1839 ··· 1682 1843 1683 1844 std-env@3.10.0: {} 1684 1845 1846 + strip-final-newline@4.0.0: {} 1847 + 1685 1848 tinybench@2.9.0: {} 1686 1849 1687 1850 tinyexec@1.0.2: {} ··· 1743 1906 1744 1907 undici-types@6.21.0: {} 1745 1908 1909 + unicorn-magic@0.3.0: {} 1910 + 1746 1911 unrun@0.2.27: 1747 1912 dependencies: 1748 1913 rolldown: 1.0.0-rc.3 ··· 1797 1962 - tsx 1798 1963 - yaml 1799 1964 1965 + which@2.0.2: 1966 + dependencies: 1967 + isexe: 2.0.0 1968 + 1800 1969 why-is-node-running@2.3.0: 1801 1970 dependencies: 1802 1971 siginfo: 2.0.0 1803 1972 stackback: 0.0.2 1973 + 1974 + yoctocolors@2.1.2: {}