Skip to content

Commit

Permalink
feat: Extract typedefs (#782)
Browse files Browse the repository at this point in the history
  • Loading branch information
mykola-mokhnach authored Jan 6, 2025
1 parent b655871 commit 82ec0f9
Show file tree
Hide file tree
Showing 18 changed files with 985 additions and 682 deletions.
23 changes: 2 additions & 21 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,11 @@
/**
* @privateRemarks This is a `.ts` file so we can re-export types from other
* files; otherwise we would need to copy `@typedef`s around.
* @module
*/

import {install} from 'source-map-support';
install();

export * from './lib/adb';
// eslint-disable-next-line import/export
export {getAndroidBinaryPath} from './lib/tools/system-calls';
export {getSdkRootFromEnv} from './lib/helpers';
// TODO: move public typedefs into a separate file
export type * from './lib/logcat';
export type * from './lib/options';
export type * from './lib/tools/adb-commands';
// eslint-disable-next-line import/export
export type * from './lib/tools/system-calls';
export type * from './lib/tools/adb-emu-commands';
export type * from './lib/tools/apk-signing';
export type * from './lib/tools/apk-utils';
export type * from './lib/tools/apks-utils';
export type * from './lib/tools/aab-utils';
export type * from './lib/tools/android-manifest';
export type * from './lib/tools/keyboard-commands';
export type * from './lib/tools/lockmgmt';
export type * from './lib/tools/types';
export type * from './lib/types';

import {ADB} from './lib/adb';
export default ADB;
19 changes: 10 additions & 9 deletions lib/adb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import {
getSdkRootFromEnv
} from './helpers';
import log from './logger';
import type {ADBOptions, ADBExecutable} from './options';
import type { LogcatOpts, Logcat } from './logcat';
import type { ADBOptions, ADBExecutable } from './types';
import type { Logcat } from './logcat';
import type { LogcatOpts, StringRecord } from './tools/types';
import type { LRUCache } from 'lru-cache';
import type { ExecError } from 'teen_process';
import type { StringRecord } from '@appium/types';

import * as generalMethods from './tools/adb-commands';
import * as manifestMethods from './tools/android-manifest';
Expand All @@ -22,6 +22,7 @@ import * as aabUtilsMethods from './tools/aab-utils';
import * as emuMethods from './tools/adb-emu-commands';
import * as lockManagementCommands from './tools/lockmgmt';
import * as keyboardCommands from './tools/keyboard-commands';
import * as emuConstants from './tools/emu-constants';


export const DEFAULT_ADB_PORT = 5037;
Expand Down Expand Up @@ -362,10 +363,10 @@ export class ADB implements ADBOptions {
getEmuVersionInfo = emuMethods.getEmuVersionInfo;
getEmuImageProperties = emuMethods.getEmuImageProperties;
checkAvdExist = emuMethods.checkAvdExist;
POWER_AC_STATES = emuMethods.POWER_AC_STATES;
GSM_CALL_ACTIONS = emuMethods.GSM_CALL_ACTIONS;
GSM_VOICE_STATES = emuMethods.GSM_VOICE_STATES;
GSM_SIGNAL_STRENGTHS = emuMethods.GSM_SIGNAL_STRENGTHS;
NETWORK_SPEED = emuMethods.NETWORK_SPEED;
SENSORS = emuMethods.SENSORS;
POWER_AC_STATES = emuConstants.POWER_AC_STATES;
GSM_CALL_ACTIONS = emuConstants.GSM_CALL_ACTIONS;
GSM_VOICE_STATES = emuConstants.GSM_VOICE_STATES;
GSM_SIGNAL_STRENGTHS = emuConstants.GSM_SIGNAL_STRENGTHS;
NETWORK_SPEED = emuConstants.NETWORK_SPEED;
SENSORS = emuConstants.SENSORS;
}
77 changes: 22 additions & 55 deletions lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,26 +93,18 @@ export async function requireSdkRoot (customRoot = null) {
return /** @type {string} */ (sdkRoot);
}

/**
* @typedef {Object} PlatformInfo
* @property {string?} platform - The platform name, for example `android-24`
* or `null` if it cannot be found
* @property {string?} platformPath - Full path to the platform SDK folder
* or `null` if it cannot be found
*/

/**
* Retrieve the path to the recent installed Android platform.
*
* @param {string} sdkRoot
* @return {Promise<PlatformInfo>} The resulting path to the newest installed platform.
* @return {Promise<import('./tools/types').PlatformInfo>} The resulting path to the newest installed platform.
*/
export async function getAndroidPlatformAndPath (sdkRoot) {
const propsPaths = await fs.glob('*/build.prop', {
cwd: path.resolve(sdkRoot, 'platforms'),
absolute: true,
});
/** @type {Record<string, PlatformInfo>} */
/** @type {Record<string, import('./tools/types').PlatformInfo>} */
const platformsMapping = {};
for (const propsPath of propsPaths) {
const propsContent = await fs.readFile(propsPath, 'utf-8');
Expand Down Expand Up @@ -549,23 +541,6 @@ export const extractMatchingPermissions = function (dumpsysOutput, groupNames, g
return filteredResult;
};

/**
* @typedef {Object} InstallOptions
* @property {boolean} [allowTestPackages=false] - Set to true in order to allow test
* packages installation.
* @property {boolean} [useSdcard=false] - Set to true to install the app on sdcard
* instead of the device memory.
* @property {boolean} [grantPermissions=false] - Set to true in order to grant all the
* permissions requested in the application's manifest
* automatically after the installation is completed
* under Android 6+.
* @property {boolean} [replace=true] - Set it to false if you don't want
* the application to be upgraded/reinstalled
* if it is already present on the device.
* @property {boolean} [partialInstall=false] - Install apks partially. It is used for 'install-multiple'.
* https://android.stackexchange.com/questions/111064/what-is-a-partial-application-install-via-adb
*/

/**
* Transforms given options into the list of `adb install.install-multiple` command arguments
*
Expand Down Expand Up @@ -1008,42 +983,17 @@ export function matchComponentName (classString) {
return /^[\p{L}0-9./_]+$/u.exec(classString);
}

/**
* @typedef {Object} LaunchableActivity
* @property {string} name
* @property {string} [label]
* @property {string} [icon]
*/

/**
* @typedef {Object} ApkManifest
* @property {string} name Package name, for example 'io.appium.android.apis'
* @property {number} versionCode
* @property {string} [versionName]
* @property {string} [platformBuildVersionName]
* @property {number} [platformBuildVersionCode]
* @property {number} compileSdkVersion
* @property {string} [compileSdkVersionCodename]
* @property {number} minSdkVersion
* @property {number} [targetSdkVersion]
* @property {string[]} usesPermissions List of requested permissions
* @property {LaunchableActivity} launchableActivity
* @property {string[]} locales List of supported locales
* @property {string[]} architectures List of supported architectures. Could be empty for older apps.
* @property {number[]} densities List of supported display densities
*/

/**
* Extracts various package manifest details
* from the given application file.
*
* @this {import('./adb.js').ADB}
* @param {string} apkPath Full path to the application file.
* @returns {Promise<ApkManifest>}
* @returns {Promise<import('./tools/types').ApkManifest>}
*/
export async function readPackageManifest(apkPath) {
await this.initAapt2();
const aapt2Binary = (/** @type {import('@appium/types').StringRecord} */ (this.binaries)).aapt2;
const aapt2Binary = (/** @type {import('./tools/types').StringRecord} */ (this.binaries)).aapt2;

const args = ['dump', 'badging', apkPath];
log.debug(`Reading package manifest: '${util.quote([aapt2Binary, ...args])}'`);
Expand Down Expand Up @@ -1085,7 +1035,7 @@ export async function readPackageManifest(apkPath) {

const toInt = (/** @type {string} */ x) => parseInt(x, 10);

/** @type {ApkManifest} */
/** @type {import('./tools/types').ApkManifest} */
const result = {
name: '',
versionCode: 0,
Expand Down Expand Up @@ -1155,3 +1105,20 @@ export async function readPackageManifest(apkPath) {
}
return result;
}

/**
* @typedef {Object} InstallOptions
* @property {boolean} [allowTestPackages=false] - Set to true in order to allow test
* packages installation.
* @property {boolean} [useSdcard=false] - Set to true to install the app on sdcard
* instead of the device memory.
* @property {boolean} [grantPermissions=false] - Set to true in order to grant all the
* permissions requested in the application's manifest
* automatically after the installation is completed
* under Android 6+.
* @property {boolean} [replace=true] - Set it to false if you don't want
* the application to be upgraded/reinstalled
* if it is already present on the device.
* @property {boolean} [partialInstall=false] - Install apks partially. It is used for 'install-multiple'.
* https://android.stackexchange.com/questions/111064/what-is-a-partial-application-install-via-adb
*/
38 changes: 5 additions & 33 deletions lib/logcat.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,6 @@ const DEFAULT_FORMAT = 'threadtime';
const TRACE_PATTERN = /W\/Trace/;
const EXECVP_ERR_PATTERN = /execvp\(\)/;

/**
* @typedef {Object} LogcatOpts
* @property {string} [format] The log print format, where <format> is one of:
* brief process tag thread raw time threadtime long
* `threadtime` is the default value.
* @property {Array<string>} [filterSpecs] Series of `<tag>[:priority]`
* where `<tag>` is a log component tag (or `*` for all) and priority is:
* V Verbose
* D Debug
* I Info
* W Warn
* E Error
* F Fatal
* S Silent (supress all output)
*
* `'*'` means `'*:d'` and `<tag>` by itself means `<tag>:v`
*
* If not specified on the commandline, filterspec is set from `ANDROID_LOG_TAGS`.
* If no filterspec is found, filter defaults to `'*:I'`
*/

function requireFormat (format) {
if (!SUPPORTED_FORMATS.includes(format)) {
log.info(`The format value '${format}' is unknown. Supported values are: ${SUPPORTED_FORMATS}`);
Expand All @@ -46,18 +25,11 @@ function requireFormat (format) {
return format;
}

/**
* @typedef {Object} LogEntry
* @property {number} timestamp
* @property {'ALL'} level
* @property {string} message
*/

/**
*
* @param {string} message
* @param {number} timestamp
* @returns {LogEntry}
* @returns {import('./tools/types').LogEntry}
*/
function toLogEntry(message, timestamp) {
return {
Expand Down Expand Up @@ -216,10 +188,10 @@ export class Logcat extends EventEmitter {
}

/**
* @returns {LogEntry[]}
* @returns {import('./tools/types').LogEntry[]}
*/
getLogs () {
/** @type {LogEntry[]} */
/** @type {import('./tools/types').LogEntry[]} */
const result = [];
/** @type {number?} */
let recentLogIndex = null;
Expand All @@ -237,10 +209,10 @@ export class Logcat extends EventEmitter {
}

/**
* @returns {LogEntry[]}
* @returns {import('./tools/types').LogEntry[]}
*/
getAllLogs () {
/** @type {LogEntry[]} */
/** @type {import('./tools/types').LogEntry[]} */
const result = [];
for (const [message, timestamp] of /** @type {Generator} */ (this.logs.rvalues())) {
result.push(toLogEntry(message, timestamp));
Expand Down
35 changes: 0 additions & 35 deletions lib/options.ts
Original file line number Diff line number Diff line change
@@ -1,35 +0,0 @@
import type {Logcat} from './logcat';
import type {StringRecord} from '@appium/types';

export interface ADBOptions {
sdkRoot?: string;
udid?: string;
appDeviceReadyTimeout?: number;
useKeystore?: boolean;
keystorePath?: string;
keystorePassword?: string;
keyAlias?: string;
keyPassword?: string;
executable?: ADBExecutable;
tmpDir?: string;
curDeviceId?: string;
emulatorPort?: number;
logcat?: Logcat;
binaries?: StringRecord;
suppressKillServer?: boolean;
adbPort?: number;
adbHost?: string;
adbExecTimeout?: number;
remoteAppsCacheLimit?: number;
buildToolsVersion?: string;
allowOfflineDevices?: boolean;
allowDelayAdb?: boolean;
remoteAdbHost?: string;
remoteAdbPort?: number;
clearDeviceLogsOnStart?: boolean;
}

export interface ADBExecutable {
path: string;
defaultArgs: string[];
}
21 changes: 2 additions & 19 deletions lib/tools/aab-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,6 @@ process.on('exit', () => {
}
});

/**
* @typedef {Object} ApkCreationOptions
* @property {string} [keystore] Specifies the path to the deployment keystore used
* to sign the APKs. This flag is optional. If you don't include it,
* bundletool attempts to sign your APKs with a debug signing key.
* If the .apk has been already signed and cached then it is not going to be resigned
* unless a different keystore or key alias is used.
* @property {string} [keystorePassword] Specifies your keystore’s password.
* It is mandatory to provide this value if `keystore` one is assigned
* otherwise it is going to be ignored.
* @property {string} [keyAlias] Specifies the alias of the signing key you want to use.
* It is mandatory to provide this value if `keystore` one is assigned
* otherwise it is going to be ignored.
* @property {string} [keyPassword] Specifies the password for the signing key.
* It is mandatory to provide this value if `keystore` one is assigned
* otherwise it is going to be ignored.
*/

/**
* Builds a universal .apk from the given .aab package. See
Expand All @@ -58,7 +41,7 @@ process.on('exit', () => {
*
* @this {import('../adb.js').ADB}
* @param {string} aabPath Full path to the source .aab package
* @param {ApkCreationOptions} [opts={}]
* @param {import('./types').ApkCreationOptions} [opts={}]
* @returns The path to the resulting universal .apk. The .apk is stored in the internal cache
* by default.
* @throws {Error} If there was an error while creating the universal .apk
Expand Down Expand Up @@ -108,7 +91,7 @@ export async function extractUniversalApk (aabPath, opts = {}) {
await this.initAapt2();
const args = [
'build-apks',
'--aapt2', (/** @type {import('@appium/types').StringRecord} */ (this.binaries)).aapt2,
'--aapt2', (/** @type {import('./types').StringRecord} */ (this.binaries)).aapt2,
'--bundle', aabPath,
'--output', tmpApksPath,
...(keystore ? [
Expand Down
Loading

0 comments on commit 82ec0f9

Please sign in to comment.