Skip to content

Commit 4c5d6a0

Browse files
committed
Removing unintended
1 parent 6e0ad36 commit 4c5d6a0

2 files changed

Lines changed: 172 additions & 169 deletions

File tree

src/cdpTarget.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { IRemoteTargetJson } from './utils';
88
export class CDPTarget extends vscode.TreeItem {
99
readonly targetJson: IRemoteTargetJson;
1010
readonly propertyName: string | null = null;
11-
readonly iconPath: { dark: string, light: string } | undefined;
1211
contextValue: 'cdpTarget' | 'cdpTargetProperty' | 'cdpTargetClosing';
1312

1413
private readonly extensionPath: string | undefined;
@@ -21,7 +20,9 @@ export class CDPTarget extends vscode.TreeItem {
2120
this.propertyName = propertyName;
2221
this.extensionPath = extensionPath;
2322
this.contextValue = (this.propertyName ? 'cdpTargetProperty' : 'cdpTarget');
24-
const treeItemLabel = `${this.label}: ${this.description}.`;
23+
24+
const treeLabel = typeof this.label === 'object' && this.label && 'label' in this.label ? this.label.label : this.label as string;
25+
const treeItemLabel = `${treeLabel}: ${this.description}.`;
2526

2627
// collapsibleState = 1 means the treeItem is the base CDPTarget treeItem.
2728
// collapsibleState = 0 means the treeItem is a child description treeItem (e.g. id, title, type, etc.)
@@ -34,14 +35,14 @@ export class CDPTarget extends vscode.TreeItem {
3435
if (this.extensionPath) {
3536
if (iconPath) {
3637
this.iconPath = {
37-
dark: iconPath,
38-
light: iconPath,
38+
dark: vscode.Uri.file(iconPath),
39+
light: vscode.Uri.file(iconPath),
3940
};
4041
} else {
4142
const icon = `${this.targetJson.type}.svg`;
4243
this.iconPath = {
43-
dark: path.join(this.extensionPath, 'resources', 'dark', icon),
44-
light: path.join(this.extensionPath, 'resources', 'light', icon),
44+
dark: vscode.Uri.file(path.join(this.extensionPath, 'resources', 'dark', icon)),
45+
light: vscode.Uri.file(path.join(this.extensionPath, 'resources', 'light', icon)),
4546
};
4647
}
4748
}
@@ -59,7 +60,8 @@ export class CDPTarget extends vscode.TreeItem {
5960
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
6061
// @ts-ignore
6162
get tooltip(): string {
62-
return `${this.label} - ${this.description}`;
63+
const treeLabel = typeof this.label === 'object' && this.label && 'label' in this.label ? this.label.label : this.label as string;
64+
return `${treeLabel} - ${this.description}`;
6365
}
6466

6567
get websocketUrl(): string {

src/cdpTargetsProvider.ts

Lines changed: 163 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,163 @@
1-
// Copyright (c) Microsoft Corporation. All rights reserved.
2-
// Licensed under the MIT License.
3-
4-
import * as vscode from 'vscode';
5-
import TelemetryReporter from '@vscode/extension-telemetry';
6-
import * as path from 'path';
7-
import * as fs from 'fs';
8-
import { CDPTarget } from './cdpTarget';
9-
import { fixRemoteWebSocket, getListOfTargets, getRemoteEndpointSettings, IRemoteTargetJson, isLocalResource, SETTINGS_STORE_NAME } from './utils';
10-
import { IncomingMessage } from 'http';
11-
import * as https from 'https';
12-
import { LaunchConfigManager } from './launchConfigManager';
13-
14-
export class CDPTargetsProvider implements vscode.TreeDataProvider<CDPTarget> {
15-
readonly onDidChangeTreeData: vscode.Event<CDPTarget | null>;
16-
readonly changeDataEvent: vscode.EventEmitter<CDPTarget | null>;
17-
private extensionPath: string;
18-
private telemetryReporter: Readonly<TelemetryReporter>;
19-
20-
constructor(context: vscode.ExtensionContext, telemetryReporter: Readonly<TelemetryReporter>) {
21-
this.changeDataEvent = new vscode.EventEmitter<CDPTarget | null>();
22-
this.onDidChangeTreeData = this.changeDataEvent.event;
23-
this.extensionPath = context.extensionPath;
24-
this.telemetryReporter = telemetryReporter;
25-
}
26-
27-
getTreeItem(element: CDPTarget): vscode.TreeItem {
28-
return element;
29-
}
30-
31-
async getChildren(element?: CDPTarget): Promise<CDPTarget[]> {
32-
let targets: CDPTarget[] = [];
33-
34-
const willShowWorkers = vscode.workspace.getConfiguration(SETTINGS_STORE_NAME).get('showWorkers');
35-
36-
if (!element) {
37-
// Get a list of the targets available
38-
const { hostname, port, useHttps } = getRemoteEndpointSettings();
39-
const responseArray = await getListOfTargets(hostname, port, useHttps);
40-
if (Array.isArray(responseArray)) {
41-
await this.clearFaviconResourceDirectory();
42-
if (responseArray.length > 0) {
43-
const responseIconPromiseArray: Array<Promise<IRemoteTargetJson>> = [];
44-
responseArray.forEach((target: IRemoteTargetJson) => {
45-
const actualTarget = fixRemoteWebSocket(hostname, port, target);
46-
if (actualTarget.type === 'page' || actualTarget.type === 'iframe') {
47-
responseIconPromiseArray.push(this.downloadFaviconFromSitePromise(actualTarget));
48-
} else if ((actualTarget.type !== 'service_worker' && actualTarget.type !== 'shared_worker') || willShowWorkers) {
49-
targets.push(new CDPTarget(actualTarget, '', this.extensionPath));
50-
}
51-
});
52-
53-
const iconResultsArray = await Promise.all(responseIconPromiseArray);
54-
for (const actualTarget of iconResultsArray) {
55-
if (isLocalResource(actualTarget.faviconUrl)) {
56-
targets.push(new CDPTarget(actualTarget, '', this.extensionPath, actualTarget.faviconUrl));
57-
} else {
58-
targets.push(new CDPTarget(actualTarget, '', this.extensionPath));
59-
}
60-
}
61-
}
62-
} else {
63-
this.telemetryReporter.sendTelemetryEvent('view/error/no_json_array');
64-
}
65-
66-
// Sort the targets by type and then title, but keep 'page' types at the top
67-
// since those are the ones most likely to be the ones the user wants.
68-
targets.sort((a: CDPTarget, b: CDPTarget) => {
69-
if (a.targetJson.type === b.targetJson.type) {
70-
return a.targetJson.title < b.targetJson.title ? -1 : 1;
71-
} if (a.targetJson.type === 'page') {
72-
return -1;
73-
} if (b.targetJson.type === 'page') {
74-
return 1;
75-
}
76-
return a.targetJson.type < b.targetJson.type ? -1 : 1;
77-
78-
});
79-
} else {
80-
// Just expand the element to show its properties
81-
targets = element.getChildren();
82-
}
83-
84-
return targets;
85-
}
86-
87-
refresh(): void {
88-
this.changeDataEvent.fire(null);
89-
void this.clearFaviconResourceDirectory();
90-
LaunchConfigManager.instance.updateLaunchConfig();
91-
}
92-
93-
async clearFaviconResourceDirectory(): Promise<void> {
94-
const directory = path.join(this.extensionPath, 'resources', 'favicons');
95-
const files = await fs.promises.readdir(directory);
96-
for (const file of files) {
97-
const fileString = file.toString();
98-
if (fileString !== '.gitkeep') {
99-
await fs.promises.unlink(path.join(directory, fileString));
100-
}
101-
}
102-
}
103-
104-
downloadFaviconFromSitePromise(actualTarget: IRemoteTargetJson) : Promise<IRemoteTargetJson> {
105-
if (!actualTarget.url || !actualTarget.url.startsWith('https')) {
106-
return Promise.resolve(actualTarget);
107-
}
108-
const faviconRegex = /((?:\/\/|\.)([^.]*)\.[^.^/]+\/).*/;
109-
110-
// Example regex match: https://learn.microsoft.com/en-us/microsoft-edge/
111-
// urlMatch[0] = .microsoft.com/en-us/microsoft-edge/
112-
// urlMatch[1] = .microsoft.com/
113-
// urlMatch[2] = microsoft
114-
const urlMatch = faviconRegex.exec(actualTarget.url);
115-
let filename;
116-
if (urlMatch) {
117-
filename = `${urlMatch[2]}Favicon.ico`;
118-
} else {
119-
return Promise.resolve(actualTarget);
120-
}
121-
122-
// Replacing ".microsoft.com/en-us/microsoft-edge/" with ".microsoft.com/favicon.ico"
123-
const faviconUrl = actualTarget.url.replace(faviconRegex, '$1favicon.ico');
124-
125-
const filePath = path.join(this.extensionPath, 'resources', 'favicons', filename);
126-
127-
const promise = new Promise<IRemoteTargetJson>((resolve, reject) => {
128-
https.get(faviconUrl, (response: IncomingMessage) => {
129-
if (response.headers['content-type'] && response.headers['content-type'].includes('icon')) {
130-
const buffer: Uint8Array[] = [];
131-
response.on('data', (data: Uint8Array) => {
132-
buffer.push(data);
133-
});
134-
135-
// eslint-disable-next-line @typescript-eslint/no-misused-promises
136-
response.on('end', async () => {
137-
try {
138-
await fs.promises.writeFile(filePath, Buffer.concat(buffer));
139-
actualTarget.faviconUrl = filePath;
140-
resolve(actualTarget);
141-
} catch {
142-
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
143-
reject(actualTarget);
144-
}
145-
});
146-
} else {
147-
resolve(actualTarget);
148-
}
149-
});
150-
});
151-
152-
const timeout = new Promise<IRemoteTargetJson>(resolve => {
153-
const id = setTimeout(() => {
154-
clearTimeout(id);
155-
resolve(actualTarget);
156-
}, 1000);
157-
});
158-
159-
// If it takes over a second to download, we will resolve null and use default icons.
160-
return Promise.race([promise, timeout]);
161-
}
162-
}
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import * as vscode from 'vscode';
5+
import TelemetryReporter from '@vscode/extension-telemetry';
6+
import * as path from 'path';
7+
import * as fs from 'fs';
8+
import { CDPTarget } from './cdpTarget';
9+
import { fixRemoteWebSocket, getListOfTargets, getRemoteEndpointSettings, IRemoteTargetJson, isLocalResource, SETTINGS_STORE_NAME } from './utils';
10+
import { IncomingMessage } from 'http';
11+
import * as https from 'https';
12+
import { LaunchConfigManager } from './launchConfigManager';
13+
14+
export class CDPTargetsProvider implements vscode.TreeDataProvider<CDPTarget> {
15+
readonly onDidChangeTreeData: vscode.Event<CDPTarget | null>;
16+
readonly changeDataEvent: vscode.EventEmitter<CDPTarget | null>;
17+
private extensionPath: string;
18+
private telemetryReporter: Readonly<TelemetryReporter>;
19+
20+
constructor(context: vscode.ExtensionContext, telemetryReporter: Readonly<TelemetryReporter>) {
21+
this.changeDataEvent = new vscode.EventEmitter<CDPTarget | null>();
22+
this.onDidChangeTreeData = this.changeDataEvent.event;
23+
this.extensionPath = context.extensionPath;
24+
this.telemetryReporter = telemetryReporter;
25+
}
26+
27+
getTreeItem(element: CDPTarget): vscode.TreeItem {
28+
return element;
29+
}
30+
31+
async getChildren(element?: CDPTarget): Promise<CDPTarget[]> {
32+
let targets: CDPTarget[] = [];
33+
34+
const willShowWorkers = vscode.workspace.getConfiguration(SETTINGS_STORE_NAME).get('showWorkers');
35+
36+
if (!element) {
37+
// Get a list of the targets available
38+
const { hostname, port, useHttps } = getRemoteEndpointSettings();
39+
const responseArray = await getListOfTargets(hostname, port, useHttps);
40+
if (Array.isArray(responseArray)) {
41+
await this.clearFaviconResourceDirectory();
42+
if (responseArray.length > 0) {
43+
const responseIconPromiseArray: Array<Promise<IRemoteTargetJson>> = [];
44+
responseArray.forEach((target: IRemoteTargetJson) => {
45+
const actualTarget = fixRemoteWebSocket(hostname, port, target);
46+
if (actualTarget.type === 'page' || actualTarget.type === 'iframe') {
47+
responseIconPromiseArray.push(this.downloadFaviconFromSitePromise(actualTarget));
48+
} else if ((actualTarget.type !== 'service_worker' && actualTarget.type !== 'shared_worker') || willShowWorkers) {
49+
targets.push(new CDPTarget(actualTarget, '', this.extensionPath));
50+
}
51+
});
52+
53+
const iconResultsArray = await Promise.all(responseIconPromiseArray);
54+
for (const actualTarget of iconResultsArray) {
55+
if (isLocalResource(actualTarget.faviconUrl)) {
56+
targets.push(new CDPTarget(actualTarget, '', this.extensionPath, actualTarget.faviconUrl));
57+
} else {
58+
targets.push(new CDPTarget(actualTarget, '', this.extensionPath));
59+
}
60+
}
61+
}
62+
} else {
63+
this.telemetryReporter.sendTelemetryEvent('view/error/no_json_array');
64+
}
65+
66+
// Sort the targets by type and then title, but keep 'page' types at the top
67+
// since those are the ones most likely to be the ones the user wants.
68+
targets.sort((a: CDPTarget, b: CDPTarget) => {
69+
if (a.targetJson.type === b.targetJson.type) {
70+
return a.targetJson.title < b.targetJson.title ? -1 : 1;
71+
} if (a.targetJson.type === 'page') {
72+
return -1;
73+
} if (b.targetJson.type === 'page') {
74+
return 1;
75+
}
76+
return a.targetJson.type < b.targetJson.type ? -1 : 1;
77+
78+
});
79+
} else {
80+
// Just expand the element to show its properties
81+
targets = element.getChildren();
82+
}
83+
84+
return targets;
85+
}
86+
87+
refresh(): void {
88+
this.changeDataEvent.fire(null);
89+
void this.clearFaviconResourceDirectory();
90+
LaunchConfigManager.instance.updateLaunchConfig();
91+
}
92+
93+
async clearFaviconResourceDirectory(): Promise<void> {
94+
const directory = path.join(this.extensionPath, 'resources', 'favicons');
95+
const files = await fs.promises.readdir(directory);
96+
for (const file of files) {
97+
const fileString = file.toString();
98+
if (fileString !== '.gitkeep') {
99+
await fs.promises.unlink(path.join(directory, fileString));
100+
}
101+
}
102+
}
103+
104+
downloadFaviconFromSitePromise(actualTarget: IRemoteTargetJson) : Promise<IRemoteTargetJson> {
105+
if (!actualTarget.url || !actualTarget.url.startsWith('https')) {
106+
return Promise.resolve(actualTarget);
107+
}
108+
const faviconRegex = /((?:\/\/|\.)([^\.]*)\.[^\.^\/]+\/).*/;
109+
110+
// Example regex match: https://learn.microsoft.com/en-us/microsoft-edge/
111+
// urlMatch[0] = .microsoft.com/en-us/microsoft-edge/
112+
// urlMatch[1] = .microsoft.com/
113+
// urlMatch[2] = microsoft
114+
const urlMatch = faviconRegex.exec(actualTarget.url);
115+
let filename;
116+
if (urlMatch) {
117+
filename = `${urlMatch[2]}Favicon.ico`;
118+
} else {
119+
return Promise.resolve(actualTarget);
120+
}
121+
122+
// Replacing ".microsoft.com/en-us/microsoft-edge/" with ".microsoft.com/favicon.ico"
123+
const faviconUrl = actualTarget.url.replace(faviconRegex, '$1favicon.ico');
124+
125+
const filePath = path.join(this.extensionPath, 'resources', 'favicons', filename);
126+
127+
const promise = new Promise<IRemoteTargetJson>((resolve, reject) => {
128+
https.get(faviconUrl, (response: IncomingMessage) => {
129+
if (response.headers['content-type'] && response.headers['content-type'].includes('icon')) {
130+
const buffer: Uint8Array[] = [];
131+
response.on('data', (data: Uint8Array) => {
132+
buffer.push(data);
133+
});
134+
135+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
136+
response.on('end', async () => {
137+
try {
138+
await fs.promises.writeFile(filePath, Buffer.concat(buffer));
139+
actualTarget.faviconUrl = filePath;
140+
resolve(actualTarget);
141+
} catch {
142+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
143+
reject(actualTarget);
144+
}
145+
});
146+
} else {
147+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
148+
resolve(actualTarget);
149+
}
150+
});
151+
});
152+
153+
const timeout = new Promise<IRemoteTargetJson>(resolve => {
154+
const id = setTimeout(() => {
155+
clearTimeout(id);
156+
resolve(actualTarget);
157+
}, 1000);
158+
});
159+
160+
// If it takes over a second to download, we will resolve null and use default icons.
161+
return Promise.race([promise, timeout]);
162+
}
163+
}

0 commit comments

Comments
 (0)