Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,37 @@ module.exports = {
cases: {
camelCase: true, // pascalCase: true,
},
ignore: [/rn-extension\.ts/],
ignore: [
/rn-extension\.ts/,
/CDPAPINames\.ts/,
/ConsoleLogger\.ts/,
/ICDPMessageHandler\.ts/,
/IExperiment\.ts/,
/IWDPHelper\.ts/,
/LogHelper\.ts/,
/NullLogger\.ts/,
/OutputChannelLogger\.ts/,
/RNTPreviewPrompt\.ts/,
/baseCDPMessageHandler\.ts/,
/configEASBuild\.ts/,
/graphQLFormatter\.ts/,
/hermesCDPMessageHandler\.ts/,
/iOSClienDevice\.ts/,
/iOSContainerUtility\.ts/,
/iOSDebugModeManager\.ts/,
/iOSDeviceTracker\.ts/,
/iOSDirectCDPMessageHandler\.ts/,
/iOSPlatform\.ts/,
/iOSTargetManager\.ts/,
/macOSDebugModeManager\.ts/,
/macOSPlatform\.ts/,
/nodeJS\.ts/,
/openEASProject\.ts/,
/openRNUpgradeHelper\.ts/,
/reactNativeCDPProxy\.ts/,
/reopenQRCode\.ts/,
/rnCDPMessageHandler\.ts/,
],
},
],
"unicorn/no-array-reduce": "warn",
Expand Down
6 changes: 6 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
6 changes: 3 additions & 3 deletions .github/workflows/build-vsix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- uses: actions/setup-node@v4
- uses: actions/setup-node@v7
with:
node-version: "24"
cache: npm
Expand All @@ -44,7 +44,7 @@ jobs:
gh release create "$GITHUB_REF_NAME" ./*.vsix --generate-notes
fi

- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: vsix
path: "*.vsix"
Expand Down
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: CI

on:
push:
branches:
- master
pull_request:

permissions:
contents: read

jobs:
ci:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v7

- uses: actions/setup-node@v7
with:
node-version: "24"
cache: npm

- name: Install dependencies
run: npm ci

- name: Lint
run: npm run lint

- name: Bundle extension
run: npx gulp prod-build

- name: Build
run: npm run build

- name: Test
run: xvfb-run -a npm test

- name: Localization tests
run: xvfb-run -a npm run test-localization
6 changes: 4 additions & 2 deletions src/cdp-proxy/CDPMessageHandlers/hermesCDPMessageHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export class HermesCDPMessageHandler extends BaseCDPMessageHandler {
private isFirstRun: boolean = true;
private reloadTimer: NodeJS.Timeout | null = null;

public processDebuggerCDPMessage(event: any): ProcessedCDPMessage {
public processDebuggerCDPMessage(initialEvent: any): ProcessedCDPMessage {
let event = initialEvent;
let sendBack = false;
if (event.method === CDP_API_NAMES.CLOSE) {
this.cancelFirstRunReload();
Expand All @@ -60,7 +61,8 @@ export class HermesCDPMessageHandler extends BaseCDPMessageHandler {
};
}

public processApplicationCDPMessage(event: any): ProcessedCDPMessage {
public processApplicationCDPMessage(initialEvent: any): ProcessedCDPMessage {
let event = initialEvent;
const sendBack = false;
if (event.method === CDP_API_NAMES.DEBUGGER_PAUSED) {
event = this.handlePausedEvent(event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ export class IOSDirectCDPMessageHandler extends BaseCDPMessageHandler {
};
}

public processApplicationCDPMessage(event: any): ProcessedCDPMessage {
public processApplicationCDPMessage(initialEvent: any): ProcessedCDPMessage {
let event = initialEvent;
if (event.method === CDP_API_NAMES.CONSOLE_MESSAGE_ADDED) {
event = this.processDeprecatedConsoleMessage(event);
}
Expand Down
7 changes: 6 additions & 1 deletion src/cdp-proxy/debuggerEndpointHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,26 @@ export class DebuggerEndpointHelper {
*/
public async retryGetWSEndpoint(
browserURL: string,
attemptNumber: number,
initialAttemptNumber: number,
cancellationToken: CancellationToken,
isHermes: boolean = false,
settingsPort?: number,
): Promise<string> {
let attemptNumber = initialAttemptNumber;
while (true) {
try {
let url = "";
if (settingsPort) {
url = `http://localhost:${settingsPort}`;
try {
// eslint-disable-next-line no-await-in-loop -- sequential retry loop
return await this.getWSEndpoint(browserURL, isHermes);
} catch {
// eslint-disable-next-line no-await-in-loop -- sequential retry loop
return await this.getWSEndpoint(url, isHermes);
}
} else {
// eslint-disable-next-line no-await-in-loop -- sequential retry loop
return await this.getWSEndpoint(browserURL, isHermes);
}
} catch (err) {
Expand All @@ -71,6 +75,7 @@ export class DebuggerEndpointHelper {
}

attemptNumber--;
// eslint-disable-next-line no-await-in-loop -- delay between retry attempts
await PromiseUtil.delay(700);
}
}
Expand Down
20 changes: 9 additions & 11 deletions src/cdp-proxy/reactNativeCDPProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,15 @@ export class ReactNativeCDPProxy {
this.debuggerTarget.pause(); // don't listen for events until the target is ready

if (!this.browserInspectUri) {
if (this.cancellationToken) {
this.browserInspectUri = await this.debuggerEndpointHelper.retryGetWSEndpoint(
`http://localhost:${this.applicationTargetPort}`,
90,
this.cancellationToken,
);
} else {
this.browserInspectUri = await this.debuggerEndpointHelper.getWSEndpoint(
`http://localhost:${this.applicationTargetPort}`,
);
}
this.browserInspectUri = this.cancellationToken
? await this.debuggerEndpointHelper.retryGetWSEndpoint(
`http://localhost:${this.applicationTargetPort}`,
90,
this.cancellationToken,
)
: await this.debuggerEndpointHelper.getWSEndpoint(
`http://localhost:${this.applicationTargetPort}`,
);
}

this.applicationTarget = new Connection(await this.createApplicationTransport());
Expand Down
8 changes: 6 additions & 2 deletions src/common/entryPointHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,18 @@ export class EntryPointHandler {
}

private handleErrors(
error: InternalError,
internalError: InternalError,
resultOfCode: Promise<void>,
errorsAreFatal: boolean,
): Promise<void> {
resultOfCode.catch(reason => {
const isDebugeeProcess = this.processType === ProcessType.Debugee;
const shouldLogStack = !errorsAreFatal || isDebugeeProcess;
this.logger.error(error.message, ErrorHelper.wrapError(error, reason), shouldLogStack);
this.logger.error(
internalError.message,
ErrorHelper.wrapError(internalError, reason),
shouldLogStack,
);
// For the debugee process we don't want to throw an exception because the debugger
// will appear to the user if he turned on the VS Code uncaught exceptions feature.
if (errorsAreFatal) {
Expand Down
11 changes: 7 additions & 4 deletions src/common/installHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@ import { SimctrlHelper } from "../extension/ios/simctl";
import { OutputChannelLogger } from "../extension/log/OutputChannelLogger";
import { ChildProcess } from "./node/childProcess";

export async function installAndroidApplication(project: AppLauncher, appPath: string) {
export async function installAndroidApplication(
project: AppLauncher,
appPath: string,
): Promise<void> {
const logger = OutputChannelLogger.getMainChannel();
const adbHelper = new AdbHelper(
project.getPackager().getProjectPath(),
project.getOrUpdateNodeModulesRoot(),
);

const targets = await adbHelper.getOnlineTargets();
if (targets.length == 0) {
if (targets.length === 0) {
throw new Error("No online target found, please check your emulator status.");
} else if (targets.length > 1) {
logger.logStream(
Expand All @@ -37,7 +40,7 @@ export async function installAndroidApplication(project: AppLauncher, appPath: s
}
}

export async function installiOSApplication(project: AppLauncher, appPath: string) {
export async function installiOSApplication(project: AppLauncher, appPath: string): Promise<void> {
const logger = OutputChannelLogger.getMainChannel();
const childProcess: ChildProcess = new ChildProcess();

Expand All @@ -54,7 +57,7 @@ export async function installiOSApplication(project: AppLauncher, appPath: strin
throw e;
}

if (targets.length == 1) {
if (targets.length === 1) {
throw new Error("No booted iOS simulator found, please check your simulator status.");
} else if (targets.length > 2) {
logger.logStream(
Expand Down
13 changes: 2 additions & 11 deletions src/common/node/childProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,7 @@ export class ChildProcess {
process = this.childProcess.exec(
command,
options,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
(
error: nodeChildProcess.ExecException | null,
stdout: string | Buffer,
stderr: string | Buffer,
) => {
(error: nodeChildProcess.ExecException | null, stdout: string | Buffer) => {
if (error) {
reject(
ErrorHelper.getNestedError(
Expand Down Expand Up @@ -98,11 +93,7 @@ export class ChildProcess {
command,
args,
options,
(
error: nodeChildProcess.ExecException | null,
stdout: string | Buffer,
stderr: string | Buffer,
) => {
(error: nodeChildProcess.ExecException | null, stdout: string | Buffer) => {
if (error) {
reject(
ErrorHelper.getNestedError(
Expand Down
26 changes: 13 additions & 13 deletions src/common/node/promise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ export class PromiseUtil {
): Promise<void> {
const arraySources: T[] = sources instanceof Promise ? await sources : sources;

return arraySources.reduce(async (previousReduction: Promise<void>, newSource: T) => {
await previousReduction;
return generateAsyncOperation(newSource);
}, Promise.resolve());
for (const source of arraySources) {
// eslint-disable-next-line no-await-in-loop -- operations run sequentially by design
await generateAsyncOperation(source);
}
}

public static async delay(duration: number): Promise<void> {
Expand All @@ -66,7 +66,7 @@ export class PromiseUtil {
interval: number = 1000,
timeout?: number,
): Promise<T | null> {
return new Promise(async (resolve, reject) => {
return new Promise((resolve, reject) => {
let rejectTimeout: NodeJS.Timeout | undefined;
// eslint-disable-next-line prefer-const
let сheckInterval: NodeJS.Timeout | undefined;
Expand Down Expand Up @@ -103,14 +103,14 @@ export class PromiseUtil {
}
};

const resolved = await tryToResolve();
if (resolved) {
return;
}

сheckInterval = setInterval(async () => {
await tryToResolve();
}, interval);
void tryToResolve().then(resolved => {
if (resolved) {
return;
}
сheckInterval = setInterval(async () => {
await tryToResolve();
}, interval);
});
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/common/nodeHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import { ChildProcess } from "./node/childProcess";

export async function getNodeVersion(projectPath: string, env: object) {
export async function getNodeVersion(projectPath: string, env: object): Promise<string> {
try {
return await new ChildProcess().execToString("node -v", { cwd: projectPath, env });
} catch (error) {
Expand Down
4 changes: 3 additions & 1 deletion src/common/packageLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ export class PackageLoader {
const load = this.packagesQueue.length;
const packagesForInstall = this.packagesQueue.slice(0, load);

// eslint-disable-next-line no-await-in-loop -- packages are installed one npm command at a time
await commandExecutor.spawnWithProgress(
HostPlatform.getNpmCliCommand("npm"),
["install", ...packagesForInstall, "--verbose", "--no-save", "--global-style"],
Expand All @@ -184,7 +185,8 @@ export class PackageLoader {
);
// Try to require all pending packages after every 'npm install ...' command
const requiresToRemove: ((load?: string[]) => Promise<boolean>)[] = [];
for (tryToRequire of this.requireQueue) {
for (const tryToRequire of this.requireQueue) {
// eslint-disable-next-line no-await-in-loop -- iterates a live queue that may grow while awaiting
if (await tryToRequire(packagesForInstall)) {
requiresToRemove.push(tryToRequire);
}
Expand Down
7 changes: 5 additions & 2 deletions src/common/packager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,16 @@ export class Packager {
);

let packagerSpawnResult;
if (this.runOptions?.platform != "exponent" && this.runOptions?.platform != "expoweb") {
if (
this.runOptions?.platform !== "exponent" &&
this.runOptions?.platform !== "expoweb"
) {
packagerSpawnResult = new CommandExecutor(
nodeModulesRoot,
this.projectPath,
this.logger,
).spawnReactPackager(args, spawnOptions);
} else if (this.runOptions?.platform == "exponent") {
} else if (this.runOptions?.platform === "exponent") {
this.runOptions?.expoPlatformType &&
args.push(`--${this.runOptions?.expoPlatformType?.toLowerCase()}`);
logger.log(
Expand Down
Loading
Loading