From 68fed081db1eabc9e2a84457c6aaef0719254fdd Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 11 Apr 2024 16:34:50 +0200 Subject: [PATCH] feat: interactive typings generation for android --- lib/commands/typings.ts | 104 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 4 deletions(-) diff --git a/lib/commands/typings.ts b/lib/commands/typings.ts index 0f2c81028b..851ce5ebf4 100644 --- a/lib/commands/typings.ts +++ b/lib/commands/typings.ts @@ -1,9 +1,13 @@ -import { IOptions, IStaticConfig } from "../declarations"; +import { glob } from "glob"; +import { homedir } from "os"; +import * as path from "path"; +import { PromptObject } from "prompts"; +import { color } from "../color"; import { IChildProcess, IFileSystem, IHostInfo } from "../common/declarations"; import { ICommand, ICommandParameter } from "../common/definitions/commands"; import { injector } from "../common/yok"; +import { IOptions, IStaticConfig } from "../declarations"; import { IProjectData } from "../definitions/project"; -import * as path from "path"; export class TypingsCommand implements ICommand { public allowedParameters: ICommandParameter[] = []; @@ -15,7 +19,8 @@ export class TypingsCommand implements ICommand { private $mobileHelper: Mobile.IMobileHelper, private $childProcess: IChildProcess, private $hostInfo: IHostInfo, - private $staticConfig: IStaticConfig + private $staticConfig: IStaticConfig, + private $prompter: IPrompter ) {} public async execute(args: string[]): Promise { @@ -49,8 +54,98 @@ export class TypingsCommand implements ICommand { return true; } + private async resolveGradleDependencies(target: string) { + const gradleHome = path.resolve( + process.env.GRADLE_USER_HOME ?? path.join(homedir(), `/.gradle`) + ); + const gradleFiles = path.resolve(gradleHome, "caches/modules-2/files-2.1/"); + + if (!this.$fs.exists(gradleFiles)) { + this.$logger.warn("No gradle files found"); + return; + } + + const pattern = `${target.replaceAll(":", "/")}/**/*.{jar,aar}`; + + const res = await glob(pattern, { + cwd: gradleFiles, + }); + + if (!res || res.length === 0) { + this.$logger.warn("No files found"); + return []; + } + + const items = res.map((item) => { + const [group, artifact, version, sha1, file] = item.split("/"); + return { + id: sha1 + version, + group, + artifact, + version, + sha1, + file, + path: path.resolve(gradleFiles, item), + }; + }); + + this.$logger.clearScreen(); + + const choices = await this.$prompter.promptForChoice( + `Select dependencies to generate typings for (${color.greenBright( + target + )})`, + items + .sort((a, b) => { + if (a.artifact < b.artifact) return -1; + if (a.artifact > b.artifact) return 1; + + return a.version.localeCompare(b.version, undefined, { + numeric: true, + sensitivity: "base", + }); + }) + .map((item) => { + return { + title: `${color.white(item.group)}:${color.greenBright( + item.artifact + )}:${color.yellow(item.version)} - ${color.cyanBright.bold( + item.file + )}`, + value: item.id, + }; + }), + true, + { + optionsPerPage: process.stdout.rows - 6, // 6 lines are taken up by the instructions + } as Partial + ); + + this.$logger.clearScreen(); + + return items + .filter((item) => choices.includes(item.id)) + .map((item) => item.path); + } + private async handleAndroidTypings() { - if (!(this.$options.jar || this.$options.aar)) { + const targets = this.$options.argv._.slice(2) ?? []; + const paths: string[] = []; + + if (targets.length) { + for (const target of targets) { + try { + paths.push(...(await this.resolveGradleDependencies(target))); + } catch (err) { + this.$logger.trace( + `Failed to resolve gradle dependencies for target "${target}"`, + err + ); + } + } + } + + if (!paths.length && !(this.$options.jar || this.$options.aar)) { this.$logger.warn( [ "No .jar or .aar file specified. Please specify at least one of the following:", @@ -97,6 +192,7 @@ export class TypingsCommand implements ICommand { const inputs: string[] = [ ...asArray(this.$options.jar), ...asArray(this.$options.aar), + ...paths, ]; await this.$childProcess.spawnFromEvent(