microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
test-microbuild1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/extension/commands/util/command.ts

153lines · modeblame

36a21645Heniker4 years ago1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import assert = require("assert");
5import * as vscode from "vscode";
6import { EntryPointHandler } from "../../../common/entryPointHandler";
7import { ErrorHelper } from "../../../common/error/errorHelper";
8import { InternalError } from "../../../common/error/internalError";
9import { InternalErrorCode } from "../../../common/error/internalErrorCode";
10import { AppLauncher } from "../../appLauncher";
11import { PlatformType } from "../../launchArgs";
12import { OutputChannelLogger } from "../../log/OutputChannelLogger";
13import { TelemetryGenerator } from "../../../common/telemetryGenerators";
14import { selectProject } from ".";
15
16export abstract class Command<ArgT extends unknown[] = never[]> {
17private static instances = new Map<Command, unknown>();
18
19static formInstance<T extends { prototype: unknown }>(this: T): T["prototype"] {
20// 'any' because TypeScript is wrong
21// workaround from https://github.com/microsoft/TypeScript/issues/5863
22const that = this as any;
23const result = Command.instances.get(that) || new that();
24Command.instances.set(that, result);
25return result;
26}
27
28abstract readonly codeName: string;
29abstract readonly label: string;
30abstract readonly error: InternalError;
31
32get platform(): string {
33return (
34[
35PlatformType.Android,
36PlatformType.iOS,
37PlatformType.Exponent,
38PlatformType.macOS,
39PlatformType.Windows,
40].find(it => this.codeName.toLowerCase().includes(it.toLowerCase())) || ""
41);
42}
43
44private entryPointHandler?: EntryPointHandler;
45
46/** Initialize project property before executing command */
47protected requiresProject = true;
48
49/** Throw an Error if workspace is not trusted before executing command */
50protected requiresTrust = true;
51
52protected project?: AppLauncher;
53
54protected constructor() {}
55
56protected createHandler(fn = this.baseFn.bind(this)): (...args: ArgT) => Promise<void> {
57return async (...args: ArgT): Promise<void> => {
58assert(this.entryPointHandler, "this.entryPointHandler is not defined");
59
60const resultFn = async (generator: TelemetryGenerator) => {
61try {
62await this.onBeforeExecute(...args);
63await fn.bind(this)(...args);
64} catch (error) {
65switch (error.errorCode) {
66case InternalErrorCode.CommandCanceled:
67generator.addError(error);
68return;
69default:
70throw error;
71}
72}
73};
74
75OutputChannelLogger.getMainChannel().debug(`Run command: ${this.codeName}`);
76
77await this.entryPointHandler.runFunctionWExtProps(
78`commandPalette.${this.codeName}`,
79{
80platform: {
81value: this.platform,
82isPii: false,
83},
84},
85this.error,
86resultFn.bind(this),
87);
88};
89}
90
91// eslint-disable-next-line @typescript-eslint/no-unused-vars
92protected async onBeforeExecute(...args: ArgT): Promise<void> {
93if (this.requiresProject) {
94this.project = await this.selectProject();
95}
96
97if (this.requiresTrust && !isWorkspaceTrusted()) {
98throw ErrorHelper.getInternalError(
99InternalErrorCode.WorkspaceIsNotTrusted,
100this.project?.getPackager().getProjectPath() || undefined,
101this.label,
102);
103}
104
105function isWorkspaceTrusted() {
106// Remove after updating supported VS Code engine version to 1.57.0
107if (typeof (vscode.workspace as any).isTrusted === "boolean") {
108return (vscode.workspace as any).isTrusted;
109}
110
111return true;
112}
113}
114
115protected async selectProject(): Promise<AppLauncher> {
116try {
117return await selectProject();
118} catch (error) {
119switch (error.errorCode) {
120case InternalErrorCode.UserInputCanceled:
121throw ErrorHelper.getNestedError(
122error,
123InternalErrorCode.CommandCanceled,
124this.label,
125);
126default:
127throw error;
128}
129}
130}
131
132abstract baseFn(...args: ArgT): Promise<void>;
133
134/** Execute base command without telemetry */
135async executeLocally(...args: ArgT): Promise<void> {
136await this.onBeforeExecute(...args);
137await this.baseFn(...args);
138}
139
140public register = (() => {
141let isCalled = false;
142return (entryPointHandler: EntryPointHandler) => {
143this.entryPointHandler = entryPointHandler;
144
145assert(!isCalled, "Command can only be registered once");
146isCalled = true;
147return vscode.commands.registerCommand(
148`reactNative.${this.codeName}`,
149this.createHandler(),
150);
151};
152})();
153}