1+ /**
2+ * Install Nevermore packages from npm
3+ */
4+
5+ import { Argv , CommandModule } from "yargs" ;
6+ import { OutputHelper } from "@quenty/cli-output-helpers" ;
7+ import { NevermoreGlobalArgs } from "../args/global-args" ;
8+ import {
9+ runCommandAsync ,
10+ } from "../utils/nevermore-cli-utils" ;
11+
12+ export interface InstallPackageArgs extends NevermoreGlobalArgs {
13+ packages : string [ ] ;
14+ }
15+
16+ /**
17+ * Install a Nevermore package from npm
18+ */
19+ export class InstallPackageCommand < T > implements CommandModule < T , InstallPackageArgs > {
20+ public command = "install [packages..]" ;
21+ public aliases = [ "i" ] ;
22+ public describe = "Install Nevermore packages from npm" ;
23+
24+ private static _validatePackageName ( name : string ) : void {
25+ if ( ! name ) {
26+ throw new Error ( "Package name is required!" ) ;
27+ }
28+ }
29+
30+ private static async _getPackages ( ) : Promise < string [ ] > {
31+ try {
32+ const response = await fetch (
33+ "https://registry.npmjs.org/-/v1/search?text=@quenty/&size=1000"
34+ ) ;
35+ const data = await response . json ( ) ;
36+ return data . objects
37+ . map ( ( obj : any ) => obj . package . name )
38+ . filter ( ( name : string ) => name . startsWith ( "@quenty/" ) )
39+ . map ( ( name : string ) => name . replace ( "@quenty/" , "" ) )
40+ . sort ( ) ;
41+ } catch {
42+ return [ ] ;
43+ }
44+ }
45+
46+ public builder ( args : Argv < T > ) {
47+ args . positional ( "packages" , {
48+ type : "string" ,
49+ array : true ,
50+ describe : "Name of the package(s) to install" ,
51+ completion : async ( current : string ) => {
52+ const packages = await InstallPackageCommand . _getPackages ( ) ;
53+ return packages . filter ( name => ! current || name . startsWith ( current ) ) ;
54+ }
55+ } ) ;
56+ return args as Argv < InstallPackageArgs > ;
57+ }
58+
59+ public async handler ( args : InstallPackageArgs ) {
60+ const srcRoot = process . cwd ( ) ;
61+
62+ if ( ! args . packages ?. length ) {
63+ throw new Error ( "No packages specified!" ) ;
64+ }
65+
66+ args . packages . forEach ( packageName => InstallPackageCommand . _validatePackageName ( packageName ) ) ;
67+
68+ const availablePackages = await InstallPackageCommand . _getPackages ( ) ;
69+ const invalidPackages = args . packages . filter (
70+ packageName => ! availablePackages . includes ( packageName )
71+ ) ;
72+
73+ if ( invalidPackages . length > 0 ) {
74+ throw new Error ( `Invalid packages: ${ invalidPackages . join ( ", " ) } ` ) ;
75+ }
76+
77+ const prefixedPackages = args . packages . map ( packageName => `@quenty/${ packageName } ` ) ;
78+
79+ OutputHelper . info ( `Installing packages: ${ args . packages . join ( ", " ) } ` ) ;
80+
81+ await runCommandAsync ( args , "npm" , [ "install" , ...prefixedPackages ] , {
82+ cwd : srcRoot ,
83+ } ) ;
84+ }
85+ }
0 commit comments