Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/microsoft/vscode.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Dima <alexdima@microsoft.com>2022-01-20 16:46:08 +0300
committerAlex Dima <alexdima@microsoft.com>2022-01-20 16:46:08 +0300
commit43d18c529c9a2ec5c4ad76f57340897ea20195c7 (patch)
treea5c2ee78e0dce9e228563c115b6399b2526c3454 /resources
parente5167eb8f253dfd5605cc92a81376610bbc24c19 (diff)
parent8a9b17d61880b98e1292ff5753cccd8603f18db9 (diff)
Merge remote-tracking branch 'origin/main' into alex/issue-140997
Diffstat (limited to 'resources')
-rw-r--r--resources/server/bin-dev/code-server.bat43
-rw-r--r--resources/server/bin-dev/code-server.js93
-rwxr-xr-xresources/server/bin-dev/code-server.sh28
-rw-r--r--resources/server/bin-dev/code-web.js87
-rw-r--r--resources/server/web.bat24
-rwxr-xr-xresources/server/web.sh26
-rw-r--r--resources/web/bin-dev/code-web-playground.js130
-rw-r--r--resources/web/callback.html81
-rw-r--r--resources/web/code-web.js663
9 files changed, 223 insertions, 952 deletions
diff --git a/resources/server/bin-dev/code-server.bat b/resources/server/bin-dev/code-server.bat
deleted file mode 100644
index ac152f65f06..00000000000
--- a/resources/server/bin-dev/code-server.bat
+++ /dev/null
@@ -1,43 +0,0 @@
-@echo off
-setlocal
-
-title VSCode Remote Agent
-
-pushd %~dp0\..\..\..
-
-:: Configuration
-set NODE_ENV=development
-set VSCODE_DEV=1
-
-:: Sync built-in extensions
-call yarn download-builtin-extensions
-
-FOR /F "tokens=*" %%g IN ('node build/lib/node.js') do (SET NODE=%%g)
-
-:: Download nodejs executable for remote
-IF NOT EXIST "%NODE%" (
- call yarn gulp node
-)
-
-:: Launch Agent
-set _FIRST_ARG=%1
-if "%_FIRST_ARG:~0,9%"=="--inspect" (
- set INSPECT=%1
- shift
-) else (
- set INSPECT=
-)
-
-:loop1
-if "%~1"=="" goto after_loop
-set RESTVAR=%RESTVAR% %1
-shift
-goto loop1
-
-:after_loop
-
-call "%NODE%" %INSPECT% "out\server-main.js" %RESTVAR%
-
-popd
-
-endlocal
diff --git a/resources/server/bin-dev/code-server.js b/resources/server/bin-dev/code-server.js
new file mode 100644
index 00000000000..5b46325a906
--- /dev/null
+++ b/resources/server/bin-dev/code-server.js
@@ -0,0 +1,93 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+// @ts-check
+
+const cp = require('child_process');
+const path = require('path');
+const os = require('os');
+const opn = require('opn');
+const crypto = require('crypto');
+const minimist = require('minimist');
+
+const args = minimist(process.argv.slice(2), {
+ boolean: [
+ 'help',
+ ],
+ string: [
+ 'host',
+ 'port',
+ 'driver',
+ 'connection-token'
+ ],
+});
+
+if (args.help) {
+ console.log(
+ './scripts/code-server.sh|bat [options]\n' +
+ ' --launch Opens a browser'
+ );
+}
+
+const serverArgs = process.argv.slice(2).filter(v => v !== '--launch');
+
+const HOST = args['host'] ?? 'localhost';
+const PORT = args['port'] ?? '9888';
+const TOKEN = args['connection-token'] ?? String(crypto.randomInt(0xffffffff));
+
+if (!args['connection-token'] === undefined && !args['connection-token-file'] === undefined && !args['no-connection-token']) {
+ serverArgs.push('--connection-token', TOKEN);
+}
+if (args['host'] === undefined) {
+ serverArgs.push('--host', HOST);
+}
+if (args['port'] === undefined) {
+ serverArgs.push('--port', PORT);
+}
+
+if (args['driver']) {
+ // given a DRIVER, we auto-shutdown when tests are done
+ serverArgs.push('--enable-remote-auto-shutdown', '--remote-auto-shutdown-without-delay');
+}
+
+const env = { ...process.env };
+env['VSCODE_AGENT_FOLDER'] = env['VSCODE_AGENT_FOLDER'] || path.join(os.homedir(), '.vscode-server-oss-dev');
+env['NODE_ENV'] = 'development';
+env['VSCODE_DEV'] = '1';
+const entryPoint = path.join(__dirname, '..', '..', '..', 'out', 'server-main.js');
+
+startServer();
+
+function startServer() {
+ console.log(`Starting server: ${entryPoint} ${serverArgs.join(' ')}`);
+ const proc = cp.spawn(process.execPath, [entryPoint, ...serverArgs], { env });
+
+ proc.stdout.on('data', data => {
+ // Log everything
+ console.log(data.toString());
+ });
+
+ // Log errors
+ proc.stderr.on('data', data => {
+ console.error(data.toString());
+ });
+
+ proc.on('exit', () => process.exit());
+
+ process.on('exit', () => proc.kill());
+ process.on('SIGINT', () => {
+ proc.kill();
+ process.exit(128 + 2); // https://nodejs.org/docs/v14.16.0/api/process.html#process_signal_events
+ });
+ process.on('SIGTERM', () => {
+ proc.kill();
+ process.exit(128 + 15); // https://nodejs.org/docs/v14.16.0/api/process.html#process_signal_events
+ });
+
+}
+
+if (args['launch']) {
+ opn(`http://${HOST}:${PORT}/?tkn=${TOKEN}`);
+}
diff --git a/resources/server/bin-dev/code-server.sh b/resources/server/bin-dev/code-server.sh
deleted file mode 100755
index 88c67ed4801..00000000000
--- a/resources/server/bin-dev/code-server.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env bash
-
-if [[ "$OSTYPE" == "darwin"* ]]; then
- realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
- ROOT=$(dirname $(dirname $(dirname $(dirname $(realpath "$0")))))
-else
- ROOT=$(dirname $(dirname $(dirname $(dirname $(readlink -f $0)))))
-fi
-
-function code() {
- cd $ROOT
-
- # Sync built-in extensions
- yarn download-builtin-extensions
-
- NODE=$(node build/lib/node.js)
-
- # Download nodejs
- if [ ! -f $NODE ]; then
- yarn gulp node
- fi
-
- NODE_ENV=development \
- VSCODE_DEV=1 \
- $NODE "$ROOT/out/server-main.js" "$@"
-}
-
-code "$@"
diff --git a/resources/server/bin-dev/code-web.js b/resources/server/bin-dev/code-web.js
deleted file mode 100644
index 0fdb7c76d2c..00000000000
--- a/resources/server/bin-dev/code-web.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-// @ts-check
-
-const cp = require('child_process');
-const path = require('path');
-const os = require('os');
-
-const serverArgs = [];
-
-// Server Config
-let PORT = 9888;
-let DRIVER = undefined;
-let LOGS_PATH = undefined;
-
-// Workspace Config
-let FOLDER = undefined;
-let WORKSPACE = undefined;
-
-// Settings Sync Config
-let GITHUB_AUTH_TOKEN = undefined;
-let ENABLE_SYNC = false;
-
-for (let idx = 0; idx <= process.argv.length - 2; idx++) {
- const arg = process.argv[idx];
- switch (arg) {
- case '--port': PORT = Number(process.argv[idx + 1]); break;
- case '--folder': FOLDER = process.argv[idx + 1]; break;
- case '--workspace': WORKSPACE = process.argv[idx + 1]; break;
- case '--driver': DRIVER = process.argv[idx + 1]; break;
- case '--github-auth': GITHUB_AUTH_TOKEN = process.argv[idx + 1]; break;
- case '--logsPath': LOGS_PATH = process.argv[idx + 1]; break;
- case '--enable-sync': ENABLE_SYNC = true; break;
- }
-}
-
-serverArgs.push('--port', String(PORT));
-if (FOLDER) {
- serverArgs.push('--folder', FOLDER);
-}
-if (WORKSPACE) {
- serverArgs.push('--workspace', WORKSPACE);
-}
-if (DRIVER) {
- serverArgs.push('--driver', DRIVER);
-
- // given a DRIVER, we auto-shutdown when tests are done
- serverArgs.push('--enable-remote-auto-shutdown', '--remote-auto-shutdown-without-delay');
-}
-if (LOGS_PATH) {
- serverArgs.push('--logsPath', LOGS_PATH);
-}
-if (GITHUB_AUTH_TOKEN) {
- serverArgs.push('--github-auth', GITHUB_AUTH_TOKEN);
-}
-if (ENABLE_SYNC) {
- serverArgs.push('--enable-sync', true);
-}
-
-// Connection Token
-serverArgs.push('--connection-token', '00000');
-
-// Server should really only listen from localhost
-serverArgs.push('--host', '127.0.0.1');
-
-const env = { ...process.env };
-env['VSCODE_AGENT_FOLDER'] = env['VSCODE_AGENT_FOLDER'] || path.join(os.homedir(), '.vscode-web-dev');
-const entryPoint = path.join(__dirname, '..', '..', '..', 'out', 'vs', 'server', 'main.js');
-
-startServer();
-
-function startServer() {
- const proc = cp.spawn(process.execPath, [entryPoint, ...serverArgs], { env });
-
- proc.stdout.on('data', data => {
- // Log everything
- console.log(data.toString());
- });
-
- // Log errors
- proc.stderr.on('data', data => {
- console.error(data.toString());
- });
-}
diff --git a/resources/server/web.bat b/resources/server/web.bat
deleted file mode 100644
index d131dafffc6..00000000000
--- a/resources/server/web.bat
+++ /dev/null
@@ -1,24 +0,0 @@
-@echo off
-setlocal
-
-title VSCode Web Server
-
-pushd %~dp0\..\..
-
-:: Configuration
-set NODE_ENV=development
-set VSCODE_DEV=1
-
-:: Sync built-in extensions
-call yarn download-builtin-extensions
-
-:: Download nodejs executable for remote
-call yarn gulp node
-
-:: Launch Server
-FOR /F "tokens=*" %%g IN ('node build/lib/node.js') do (SET NODE=%%g)
-call "%NODE%" resources\server\bin-dev\code-web.js %*
-
-popd
-
-endlocal \ No newline at end of file
diff --git a/resources/server/web.sh b/resources/server/web.sh
deleted file mode 100755
index da072e5f2d0..00000000000
--- a/resources/server/web.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env bash
-
-if [[ "$OSTYPE" == "darwin"* ]]; then
- realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
- ROOT=$(dirname $(dirname $(dirname $(realpath "$0"))))
-else
- ROOT=$(dirname $(dirname $(dirname $(readlink -f $0))))
-fi
-
-function code() {
- cd $ROOT
-
- # Sync built-in extensions
- yarn download-builtin-extensions
-
- # Load remote node
- yarn gulp node
-
- NODE=$(node build/lib/node.js)
-
- NODE_ENV=development \
- VSCODE_DEV=1 \
- $NODE $(dirname "$0")/bin-dev/code-web.js "$@"
-}
-
-code "$@"
diff --git a/resources/web/bin-dev/code-web-playground.js b/resources/web/bin-dev/code-web-playground.js
new file mode 100644
index 00000000000..57a3e4d8d26
--- /dev/null
+++ b/resources/web/bin-dev/code-web-playground.js
@@ -0,0 +1,130 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+// @ts-check
+
+const testWeb = require('@vscode/test-web');
+
+const fs = require('fs');
+const path = require('path');
+
+const minimist = require('minimist');
+const fancyLog = require('fancy-log');
+const ansiColors = require('ansi-colors');
+const remote = require('gulp-remote-retry-src');
+const vfs = require('vinyl-fs');
+const opn = require('opn');
+
+const APP_ROOT = path.join(__dirname, '..', '..', '..');
+const WEB_DEV_EXTENSIONS_ROOT = path.join(APP_ROOT, '.build', 'builtInWebDevExtensions');
+
+const WEB_PLAYGROUND_VERSION = '0.0.13';
+
+const args = minimist(process.argv.slice(2), {
+ boolean: [
+ 'help',
+ 'verbose',
+ 'open-devtools'
+ ],
+ string: [
+ 'host',
+ 'port',
+ 'extension',
+ 'browserType'
+ ],
+});
+
+if (args.help) {
+ console.log(
+ './scripts/code-web.sh|bat [options]\n' +
+ ' --host Server host address\n' +
+ ' --port Server port\n' +
+ ' --browserType The browser type to launch: `chromium` (default), `firefox`, `webkit` or `none`' +
+ ' --extension Path of an extension to include\n' +
+ ' --open-devtools Open the dev tools' +
+ ' --verbose Print out more information\n' +
+ ' --help\n' +
+ '[Example]\n' +
+ ' ./scripts/code-web.sh|bat --port 8080'
+ );
+ process.exit(0);
+}
+
+openTestWeb();
+
+
+async function openTestWeb() {
+ await ensureWebDevExtensions();
+ const extensionPaths = [WEB_DEV_EXTENSIONS_ROOT];
+ const extensions = args['extension'];
+ if (Array.isArray(extensions)) {
+ extensionPaths.push(...extensions);
+ } else if (extensions) {
+ extensionPaths.push(extensions);
+ }
+ const host = args.host || 'localhost';
+ const port = args.port || 8080;
+
+ await testWeb.open({
+ browserType: args['browserType'] ?? 'none',
+ host,
+ port,
+ folderUri: 'memfs:///sample-folder',
+ vsCodeDevPath: APP_ROOT,
+ extensionPaths,
+ devTools: !!args['open-devtools'],
+ hideServerLog: !args['verbose'],
+ verbose: !!args['verbose']
+ });
+
+
+ if (!args['browserType']) {
+ opn(`http://${host}:${port}/`);
+ }
+}
+
+async function directoryExists(path) {
+ try {
+ return (await fs.promises.stat(path)).isDirectory();
+ } catch {
+ return false;
+ }
+}
+
+async function ensureWebDevExtensions() {
+
+ // Playground (https://github.com/microsoft/vscode-web-playground)
+ const webDevPlaygroundRoot = path.join(WEB_DEV_EXTENSIONS_ROOT, 'vscode-web-playground');
+ const webDevPlaygroundExists = await directoryExists(webDevPlaygroundRoot);
+
+ let downloadPlayground = false;
+ if (webDevPlaygroundExists) {
+ try {
+ const webDevPlaygroundPackageJson = JSON.parse(((await fs.promises.readFile(path.join(webDevPlaygroundRoot, 'package.json'))).toString()));
+ if (webDevPlaygroundPackageJson.version !== WEB_PLAYGROUND_VERSION) {
+ downloadPlayground = true;
+ }
+ } catch (error) {
+ downloadPlayground = true;
+ }
+ } else {
+ downloadPlayground = true;
+ }
+
+ if (downloadPlayground) {
+ if (args.verbose) {
+ fancyLog(`${ansiColors.magenta('Web Development extensions')}: Downloading vscode-web-playground to ${webDevPlaygroundRoot}`);
+ }
+ await new Promise((resolve, reject) => {
+ remote(['package.json', 'dist/extension.js', 'dist/extension.js.map'], {
+ base: 'https://raw.githubusercontent.com/microsoft/vscode-web-playground/main/'
+ }).pipe(vfs.dest(webDevPlaygroundRoot)).on('end', resolve).on('error', reject);
+ });
+ } else {
+ if (args.verbose) {
+ fancyLog(`${ansiColors.magenta('Web Development extensions')}: Using existing vscode-web-playground in ${webDevPlaygroundRoot}`);
+ }
+ }
+}
diff --git a/resources/web/callback.html b/resources/web/callback.html
deleted file mode 100644
index 81f217e980b..00000000000
--- a/resources/web/callback.html
+++ /dev/null
@@ -1,81 +0,0 @@
-<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
-<!DOCTYPE html>
-<html>
-
-<head>
- <meta charset="utf-8" />
-
- <!-- Disable pinch zooming -->
- <meta name="viewport"
- content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
-
- <!-- Content Security Policy -->
- <meta http-equiv="Content-Security-Policy" content="
- default-src 'self';
- img-src 'self' https: data: blob:;
- media-src 'none';
- script-src 'self';
- style-src 'self' 'unsafe-inline';
- font-src 'self' blob:;
- ">
-
- <title>Visual Studio Code</title>
-
- <!-- Styling -->
- <style type="text/css">
- html {
- height: 100%;
- }
-
- body {
- box-sizing: border-box;
- min-height: 100%;
- margin: 0;
- padding: 15px 30px;
- display: flex;
- flex-direction: column;
- color: white;
- font-family: "Segoe UI", "Helvetica Neue", "Helvetica", Arial, sans-serif;
- background-color: #373277;
- }
-
- .branding {
- background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PGRlZnM+PHN0eWxlPi5pY29uLWNhbnZhcy10cmFuc3BhcmVudHtmaWxsOiNmNmY2ZjY7b3BhY2l0eTowO30uaWNvbi13aGl0ZXtmaWxsOiNmZmY7fTwvc3R5bGU+PC9kZWZzPjx0aXRsZT5CcmFuZFZpc3VhbFN0dWRpb0NvZGUyMDE3UlRXXzI0eF93aGl0ZV8yNHg8L3RpdGxlPjxwYXRoIGNsYXNzPSJpY29uLWNhbnZhcy10cmFuc3BhcmVudCIgZD0iTTI0LDBWMjRIMFYwWiIvPjxwYXRoIGNsYXNzPSJpY29uLXdoaXRlIiBkPSJNMjQsMi41VjIxLjVMMTgsMjQsMCwxOC41di0uNTYxbDE4LDEuNTQ1VjBaTTEsMTMuMTExLDQuMzg1LDEwLDEsNi44ODlsMS40MTgtLjgyN0w1Ljg1Myw4LjY1LDEyLDNsMywxLjQ1NlYxNS41NDRMMTIsMTcsNS44NTMsMTEuMzUsMi40MTksMTMuOTM5Wk03LjY0NCwxMCwxMiwxMy4yODNWNi43MTdaIi8+PC9zdmc+");
- background-size: 24px;
- background-repeat: no-repeat;
- background-position: left 50%;
- padding-left: 36px;
- font-size: 20px;
- letter-spacing: -0.04rem;
- font-weight: 400;
- color: white;
- text-decoration: none;
- }
-
- .message-container {
- flex-grow: 1;
- display: flex;
- align-items: center;
- justify-content: center;
- margin: 0 30px;
- }
-
- .message {
- font-weight: 300;
- font-size: 1.3rem;
- }
- </style>
-</head>
-
-<body>
- <span class="branding">
- Visual Studio Code
- </span>
- <div class="message-container">
- <div class="message">
- You can close this page now.
- </div>
- </div>
-</body>
-
-</html>
diff --git a/resources/web/code-web.js b/resources/web/code-web.js
deleted file mode 100644
index 1f038e7d5f8..00000000000
--- a/resources/web/code-web.js
+++ /dev/null
@@ -1,663 +0,0 @@
-#!/usr/bin/env node
-
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-// @ts-check
-
-const http = require('http');
-const url = require('url');
-const fs = require('fs');
-const path = require('path');
-const util = require('util');
-const opn = require('opn');
-const minimist = require('minimist');
-const fancyLog = require('fancy-log');
-const ansiColors = require('ansi-colors');
-const remote = require('gulp-remote-retry-src');
-const vfs = require('vinyl-fs');
-const uuid = require('uuid');
-
-const extensions = require('../../build/lib/extensions');
-const { getBuiltInExtensions } = require('../../build/lib/builtInExtensions');
-
-const APP_ROOT = path.join(__dirname, '..', '..');
-const BUILTIN_EXTENSIONS_ROOT = path.join(APP_ROOT, 'extensions');
-const BUILTIN_MARKETPLACE_EXTENSIONS_ROOT = path.join(APP_ROOT, '.build', 'builtInExtensions');
-const WEB_DEV_EXTENSIONS_ROOT = path.join(APP_ROOT, '.build', 'builtInWebDevExtensions');
-const WEB_MAIN = path.join(APP_ROOT, 'src', 'vs', 'code', 'browser', 'workbench', 'workbench-dev.html');
-
-// This is useful to simulate real world CORS
-const ALLOWED_CORS_ORIGINS = [
- 'http://localhost:8081',
- 'http://127.0.0.1:8081',
- 'http://localhost:8080',
- 'http://127.0.0.1:8080',
-];
-
-const WEB_PLAYGROUND_VERSION = '0.0.13';
-
-const args = minimist(process.argv, {
- boolean: [
- 'no-launch',
- 'help',
- 'verbose',
- 'wrap-iframe',
- 'enable-sync',
- ],
- string: [
- 'scheme',
- 'host',
- 'port',
- 'local_port',
- 'extension',
- 'extensionId',
- 'github-auth',
- 'open-file'
- ],
-});
-
-if (args.help) {
- console.log(
- 'yarn web [options]\n' +
- ' --no-launch Do not open Code in the browser\n' +
- ' --wrap-iframe Wrap the Web Worker Extension Host in an iframe\n' +
- ' --enable-sync Enable sync by default\n' +
- ' --scheme Protocol (https or http)\n' +
- ' --host Remote host\n' +
- ' --port Remote/Local port\n' +
- ' --local_port Local port override\n' +
- ' --extension Path of an extension to include\n' +
- ' --extensionId Id of an extension to include\n' +
- ' --open-file uri of the file to open. Also support selections in the file. Eg: scheme://authority/path#L1:2-L10:3\n' +
- ' --github-auth Github authentication token\n' +
- ' --verbose Print out more information\n' +
- ' --help\n' +
- '[Example]\n' +
- ' yarn web --scheme https --host example.com --port 8080 --local_port 30000'
- );
- process.exit(0);
-}
-
-const PORT = args.port || process.env.PORT || 8080;
-const LOCAL_PORT = args.local_port || process.env.LOCAL_PORT || PORT;
-const SCHEME = args.scheme || process.env.VSCODE_SCHEME || 'http';
-const HOST = args.host || 'localhost';
-const AUTHORITY = process.env.VSCODE_AUTHORITY || `${HOST}:${PORT}`;
-
-const exists = (path) => util.promisify(fs.exists)(path);
-const readFile = (path) => util.promisify(fs.readFile)(path);
-
-async function getBuiltInExtensionInfos() {
- await getBuiltInExtensions();
-
- const allExtensions = [];
- /** @type {Object.<string, string>} */
- const locations = {};
-
- const [localExtensions, marketplaceExtensions, webDevExtensions] = await Promise.all([
- extensions.scanBuiltinExtensions(BUILTIN_EXTENSIONS_ROOT),
- extensions.scanBuiltinExtensions(BUILTIN_MARKETPLACE_EXTENSIONS_ROOT),
- ensureWebDevExtensions().then(() => extensions.scanBuiltinExtensions(WEB_DEV_EXTENSIONS_ROOT))
- ]);
- for (const ext of localExtensions) {
- allExtensions.push(ext);
- locations[ext.extensionPath] = path.join(BUILTIN_EXTENSIONS_ROOT, ext.extensionPath);
- }
- for (const ext of marketplaceExtensions) {
- allExtensions.push(ext);
- locations[ext.extensionPath] = path.join(BUILTIN_MARKETPLACE_EXTENSIONS_ROOT, ext.extensionPath);
- }
- for (const ext of webDevExtensions) {
- allExtensions.push(ext);
- locations[ext.extensionPath] = path.join(WEB_DEV_EXTENSIONS_ROOT, ext.extensionPath);
- }
- for (const ext of allExtensions) {
- if (ext.packageJSON.browser) {
- let mainFilePath = path.join(locations[ext.extensionPath], ext.packageJSON.browser);
- if (path.extname(mainFilePath) !== '.js') {
- mainFilePath += '.js';
- }
- if (!await exists(mainFilePath)) {
- fancyLog(`${ansiColors.red('Error')}: Could not find ${mainFilePath}. Use ${ansiColors.cyan('yarn watch-web')} to build the built-in extensions.`);
- }
- }
- }
- return { extensions: allExtensions, locations };
-}
-
-async function ensureWebDevExtensions() {
-
- // Playground (https://github.com/microsoft/vscode-web-playground)
- const webDevPlaygroundRoot = path.join(WEB_DEV_EXTENSIONS_ROOT, 'vscode-web-playground');
- const webDevPlaygroundExists = await exists(webDevPlaygroundRoot);
-
- let downloadPlayground = false;
- if (webDevPlaygroundExists) {
- try {
- const webDevPlaygroundPackageJson = JSON.parse(((await readFile(path.join(webDevPlaygroundRoot, 'package.json'))).toString()));
- if (webDevPlaygroundPackageJson.version !== WEB_PLAYGROUND_VERSION) {
- downloadPlayground = true;
- }
- } catch (error) {
- downloadPlayground = true;
- }
- } else {
- downloadPlayground = true;
- }
-
- if (downloadPlayground) {
- if (args.verbose) {
- fancyLog(`${ansiColors.magenta('Web Development extensions')}: Downloading vscode-web-playground to ${webDevPlaygroundRoot}`);
- }
- await new Promise((resolve, reject) => {
- remote(['package.json', 'dist/extension.js', 'dist/extension.js.map'], {
- base: 'https://raw.githubusercontent.com/microsoft/vscode-web-playground/main/'
- }).pipe(vfs.dest(webDevPlaygroundRoot)).on('end', resolve).on('error', reject);
- });
- } else {
- if (args.verbose) {
- fancyLog(`${ansiColors.magenta('Web Development extensions')}: Using existing vscode-web-playground in ${webDevPlaygroundRoot}`);
- }
- }
-}
-
-async function getCommandlineProvidedExtensionInfos() {
- const extensions = [];
-
- /** @type {Object.<string, string>} */
- const locations = {};
-
- let extensionArg = args['extension'];
- let extensionIdArg = args['extensionId'];
- if (!extensionArg && !extensionIdArg) {
- return { extensions, locations };
- }
-
- if (extensionArg) {
- const extensionPaths = Array.isArray(extensionArg) ? extensionArg : [extensionArg];
- await Promise.all(extensionPaths.map(async extensionPath => {
- extensionPath = path.resolve(process.cwd(), extensionPath);
- const packageJSON = await getExtensionPackageJSON(extensionPath);
- if (packageJSON) {
- const extensionId = `${packageJSON.publisher}.${packageJSON.name}`;
- extensions.push({ scheme: SCHEME, authority: AUTHORITY, path: `/extension/${extensionId}` });
- locations[extensionId] = extensionPath;
- }
- }));
- }
-
- if (extensionIdArg) {
- extensions.push(...(Array.isArray(extensionIdArg) ? extensionIdArg : [extensionIdArg]));
- }
-
- return { extensions, locations };
-}
-
-async function getExtensionPackageJSON(extensionPath) {
-
- const packageJSONPath = path.join(extensionPath, 'package.json');
- if (await exists(packageJSONPath)) {
- try {
- let packageJSON = JSON.parse((await readFile(packageJSONPath)).toString());
- if (packageJSON.main && !packageJSON.browser) {
- return; // unsupported
- }
- return packageJSON;
- } catch (e) {
- console.log(e);
- }
- }
- return undefined;
-}
-
-const builtInExtensionsPromise = getBuiltInExtensionInfos();
-const commandlineProvidedExtensionsPromise = getCommandlineProvidedExtensionInfos();
-
-const mapCallbackUriToRequestId = new Map();
-
-/**
- * @param req {http.IncomingMessage}
- * @param res {http.ServerResponse}
- */
-const requestHandler = (req, res) => {
- const parsedUrl = url.parse(req.url, true);
- const pathname = parsedUrl.pathname;
-
- res.setHeader('Access-Control-Allow-Origin', '*');
-
- try {
- if (/(\/static)?\/favicon\.ico/.test(pathname)) {
- // favicon
- return serveFile(req, res, path.join(APP_ROOT, 'resources', 'win32', 'code.ico'));
- }
- if (/(\/static)?\/manifest\.json/.test(pathname)) {
- // manifest
- res.writeHead(200, { 'Content-Type': 'application/json' });
- return res.end(JSON.stringify({
- 'name': 'Code - OSS',
- 'short_name': 'Code - OSS',
- 'start_url': '/',
- 'lang': 'en-US',
- 'display': 'standalone'
- }));
- }
- if (/^\/static\//.test(pathname)) {
- // static requests
- return handleStatic(req, res, parsedUrl);
- }
- if (/^\/extension\//.test(pathname)) {
- // default extension requests
- return handleExtension(req, res, parsedUrl);
- }
- if (pathname === '/') {
- // main web
- return handleRoot(req, res);
- } else if (pathname === '/callback') {
- // callback support
- return handleCallback(req, res, parsedUrl);
- } else if (pathname === '/fetch-callback') {
- // callback fetch support
- return handleFetchCallback(req, res, parsedUrl);
- } else if (pathname === '/builtin') {
- // builtin extnesions JSON
- return handleBuiltInExtensions(req, res, parsedUrl);
- }
-
- return serveError(req, res, 404, 'Not found.');
- } catch (error) {
- console.error(error.toString());
-
- return serveError(req, res, 500, 'Internal Server Error.');
- }
-};
-
-const server = http.createServer(requestHandler);
-server.listen(LOCAL_PORT, () => {
- if (LOCAL_PORT !== PORT) {
- console.log(`Operating location at http://0.0.0.0:${LOCAL_PORT}`);
- }
- console.log(`Web UI available at ${SCHEME}://${AUTHORITY}`);
-});
-server.on('error', err => {
- console.error(`Error occurred in server:`);
- console.error(err);
-});
-
-/**
- * @param {import('http').IncomingMessage} req
- */
-function addCORSReplyHeader(req) {
- if (typeof req.headers['origin'] !== 'string') {
- // not a CORS request
- return false;
- }
- return (ALLOWED_CORS_ORIGINS.indexOf(req.headers['origin']) >= 0);
-}
-
-/**
- * @param {import('http').IncomingMessage} req
- * @param {import('http').ServerResponse} res
- * @param {import('url').UrlWithParsedQuery} parsedUrl
- */
-async function handleBuiltInExtensions(req, res, parsedUrl) {
- const { extensions } = await builtInExtensionsPromise;
- res.writeHead(200, { 'Content-Type': 'application/json' });
- return res.end(JSON.stringify(extensions));
-}
-
-/**
- * @param {import('http').IncomingMessage} req
- * @param {import('http').ServerResponse} res
- * @param {import('url').UrlWithParsedQuery} parsedUrl
- */
-async function handleStatic(req, res, parsedUrl) {
-
- if (/^\/static\/extensions\//.test(parsedUrl.pathname)) {
- const relativePath = decodeURIComponent(parsedUrl.pathname.substr('/static/extensions/'.length));
- const filePath = getExtensionFilePath(relativePath, (await builtInExtensionsPromise).locations);
- const responseHeaders = {};
- if (addCORSReplyHeader(req)) {
- responseHeaders['Access-Control-Allow-Origin'] = '*';
- }
- if (!filePath) {
- return serveError(req, res, 400, `Bad request.`, responseHeaders);
- }
- return serveFile(req, res, filePath, responseHeaders);
- }
-
- // Strip `/static/` from the path
- const relativeFilePath = path.normalize(decodeURIComponent(parsedUrl.pathname.substr('/static/'.length)));
-
- return serveFile(req, res, path.join(APP_ROOT, relativeFilePath));
-}
-
-/**
- * @param {import('http').IncomingMessage} req
- * @param {import('http').ServerResponse} res
- * @param {import('url').UrlWithParsedQuery} parsedUrl
- */
-async function handleExtension(req, res, parsedUrl) {
- // Strip `/extension/` from the path
- const relativePath = decodeURIComponent(parsedUrl.pathname.substr('/extension/'.length));
- const filePath = getExtensionFilePath(relativePath, (await commandlineProvidedExtensionsPromise).locations);
- const responseHeaders = {};
- if (addCORSReplyHeader(req)) {
- responseHeaders['Access-Control-Allow-Origin'] = '*';
- }
- if (!filePath) {
- return serveError(req, res, 400, `Bad request.`, responseHeaders);
- }
- return serveFile(req, res, filePath, responseHeaders);
-}
-
-/**
- * @param {import('http').IncomingMessage} req
- * @param {import('http').ServerResponse} res
- */
-async function handleRoot(req, res) {
- let folderUri = { scheme: 'memfs', path: `/sample-folder` };
-
- const match = req.url && req.url.match(/\?([^#]+)/);
- if (match) {
- const qs = new URLSearchParams(match[1]);
-
- let gh = qs.get('gh');
- if (gh) {
- if (gh.startsWith('/')) {
- gh = gh.substr(1);
- }
-
- const [owner, repo, ...branch] = gh.split('/', 3);
- const ref = branch.join('/');
- folderUri = { scheme: 'github', authority: `${owner}+${repo}${ref ? `+${ref}` : ''}`, path: '/' };
- } else {
- let cs = qs.get('cs');
- if (cs) {
- if (cs.startsWith('/')) {
- cs = cs.substr(1);
- }
-
- const [owner, repo, ...branch] = cs.split('/');
- const ref = branch.join('/');
- folderUri = { scheme: 'codespace', authority: `${owner}+${repo}${ref ? `+${ref}` : ''}`, path: '/' };
- }
- }
- }
-
- const { extensions: builtInExtensions } = await builtInExtensionsPromise;
- const { extensions: additionalBuiltinExtensions, locations: staticLocations } = await commandlineProvidedExtensionsPromise;
-
- const dedupedBuiltInExtensions = [];
- for (const builtInExtension of builtInExtensions) {
- const extensionId = `${builtInExtension.packageJSON.publisher}.${builtInExtension.packageJSON.name}`;
- if (staticLocations[extensionId]) {
- fancyLog(`${ansiColors.magenta('BuiltIn extensions')}: Ignoring built-in ${extensionId} because it was overridden via --extension argument`);
- continue;
- }
-
- dedupedBuiltInExtensions.push(builtInExtension);
- }
-
- if (args.verbose) {
- fancyLog(`${ansiColors.magenta('BuiltIn extensions')}: ${dedupedBuiltInExtensions.map(e => path.basename(e.extensionPath)).join(', ')}`);
- fancyLog(`${ansiColors.magenta('Additional extensions')}: ${additionalBuiltinExtensions.map(e => typeof e === 'string' ? e : path.basename(e.path)).join(', ') || 'None'}`);
- }
-
- const openFileUrl = args['open-file'] ? url.parse(args['open-file'], true) : undefined;
- let selection;
- if (openFileUrl?.hash) {
- const rangeMatch = /L(?<startLineNumber>\d+)(?::(?<startColumn>\d+))?((?:-L(?<endLineNumber>\d+))(?::(?<endColumn>\d+))?)?/.exec(openFileUrl.hash);
- if (rangeMatch?.groups) {
- const { startLineNumber, startColumn, endLineNumber, endColumn } = rangeMatch.groups;
- const start = { line: parseInt(startLineNumber), column: startColumn ? (parseInt(startColumn) || 1) : 1 };
- const end = endLineNumber ? { line: parseInt(endLineNumber), column: endColumn ? (parseInt(endColumn) || 1) : 1 } : start;
- selection = { start, end }
- }
- }
- const webConfigJSON = {
- folderUri: folderUri,
- additionalBuiltinExtensions,
- defaultLayout: openFileUrl ? {
- force: true,
- editors: [{
- uri: {
- scheme: openFileUrl.protocol.substring(0, openFileUrl.protocol.length - 1),
- authority: openFileUrl.host,
- path: openFileUrl.path,
- },
- selection,
- }]
- } : undefined,
- settingsSyncOptions: args['enable-sync'] ? {
- enabled: true
- } : undefined
- };
- if (args['wrap-iframe']) {
- webConfigJSON._wrapWebWorkerExtHostInIframe = true;
- }
-
- const authSessionInfo = args['github-auth'] ? {
- id: uuid.v4(),
- providerId: 'github',
- accessToken: args['github-auth'],
- scopes: [['user:email'], ['repo']]
- } : undefined;
-
- const data = (await readFile(WEB_MAIN)).toString()
- .replace('{{WORKBENCH_WEB_CONFIGURATION}}', () => escapeAttribute(JSON.stringify(webConfigJSON))) // use a replace function to avoid that regexp replace patterns ($&, $0, ...) are applied
- .replace('{{WORKBENCH_BUILTIN_EXTENSIONS}}', () => escapeAttribute(JSON.stringify(dedupedBuiltInExtensions)))
- .replace('{{WORKBENCH_AUTH_SESSION}}', () => authSessionInfo ? escapeAttribute(JSON.stringify(authSessionInfo)) : '')
- .replace('{{WEBVIEW_ENDPOINT}}', '');
-
- const headers = {
- 'Content-Type': 'text/html',
- 'Content-Security-Policy': 'require-trusted-types-for \'script\';'
- };
- res.writeHead(200, headers);
- return res.end(data);
-}
-
-/**
- * Handle HTTP requests for /callback
- * @param {import('http').IncomingMessage} req
- * @param {import('http').ServerResponse} res
- * @param {import('url').UrlWithParsedQuery} parsedUrl
-*/
-async function handleCallback(req, res, parsedUrl) {
- const wellKnownKeys = ['vscode-requestId', 'vscode-scheme', 'vscode-authority', 'vscode-path', 'vscode-query', 'vscode-fragment'];
- const [requestId, vscodeScheme, vscodeAuthority, vscodePath, vscodeQuery, vscodeFragment] = wellKnownKeys.map(key => {
- const value = getFirstQueryValue(parsedUrl, key);
- if (value) {
- return decodeURIComponent(value);
- }
-
- return value;
- });
-
- if (!requestId) {
- res.writeHead(400, { 'Content-Type': 'text/plain' });
- return res.end(`Bad request.`);
- }
-
- // merge over additional query values that we got
- let query = vscodeQuery;
- let index = 0;
- getFirstQueryValues(parsedUrl, wellKnownKeys).forEach((value, key) => {
- if (!query) {
- query = '';
- }
-
- const prefix = (index++ === 0) ? '' : '&';
- query += `${prefix}${key}=${value}`;
- });
-
-
- // add to map of known callbacks
- mapCallbackUriToRequestId.set(requestId, JSON.stringify({ scheme: vscodeScheme || 'code-oss', authority: vscodeAuthority, path: vscodePath, query, fragment: vscodeFragment }));
- return serveFile(req, res, path.join(APP_ROOT, 'resources', 'web', 'callback.html'), { 'Content-Type': 'text/html' });
-}
-
-/**
- * Handle HTTP requests for /fetch-callback
- * @param {import('http').IncomingMessage} req
- * @param {import('http').ServerResponse} res
- * @param {import('url').UrlWithParsedQuery} parsedUrl
-*/
-async function handleFetchCallback(req, res, parsedUrl) {
- const requestId = getFirstQueryValue(parsedUrl, 'vscode-requestId');
- if (!requestId) {
- res.writeHead(400, { 'Content-Type': 'text/plain' });
- return res.end(`Bad request.`);
- }
-
- const knownCallbackUri = mapCallbackUriToRequestId.get(requestId);
- if (knownCallbackUri) {
- mapCallbackUriToRequestId.delete(requestId);
- }
-
- res.writeHead(200, { 'Content-Type': 'text/json' });
- return res.end(knownCallbackUri);
-}
-
-/**
- * @param {import('url').UrlWithParsedQuery} parsedUrl
- * @param {string} key
- * @returns {string | undefined}
-*/
-function getFirstQueryValue(parsedUrl, key) {
- const result = parsedUrl.query[key];
- return Array.isArray(result) ? result[0] : result;
-}
-
-/**
- * @param {import('url').UrlWithParsedQuery} parsedUrl
- * @param {string[] | undefined} ignoreKeys
- * @returns {Map<string, string>}
-*/
-function getFirstQueryValues(parsedUrl, ignoreKeys) {
- const queryValues = new Map();
-
- for (const key in parsedUrl.query) {
- if (ignoreKeys && ignoreKeys.indexOf(key) >= 0) {
- continue;
- }
-
- const value = getFirstQueryValue(parsedUrl, key);
- if (typeof value === 'string') {
- queryValues.set(key, value);
- }
- }
-
- return queryValues;
-}
-
-/**
- * @param {string} value
- */
-function escapeAttribute(value) {
- return value.replace(/"/g, '&quot;');
-}
-
-/**
- * @param {string} relativePath
- * @param {Object.<string, string>} locations
- * @returns {string | undefined}
-*/
-function getExtensionFilePath(relativePath, locations) {
- const firstSlash = relativePath.indexOf('/');
- if (firstSlash === -1) {
- return undefined;
- }
- const extensionId = relativePath.substr(0, firstSlash);
-
- const extensionPath = locations[extensionId];
- if (!extensionPath) {
- return undefined;
- }
- return path.join(extensionPath, relativePath.substr(firstSlash + 1));
-}
-
-/**
- * @param {import('http').IncomingMessage} req
- * @param {import('http').ServerResponse} res
- * @param {string} errorMessage
- */
-function serveError(req, res, errorCode, errorMessage, responseHeaders = Object.create(null)) {
- responseHeaders['Content-Type'] = 'text/plain';
- res.writeHead(errorCode, responseHeaders);
- res.end(errorMessage);
-}
-
-const textMimeType = {
- '.html': 'text/html',
- '.js': 'text/javascript',
- '.json': 'application/json',
- '.css': 'text/css',
- '.svg': 'image/svg+xml',
-};
-
-const mapExtToMediaMimes = {
- '.bmp': 'image/bmp',
- '.gif': 'image/gif',
- '.ico': 'image/x-icon',
- '.jpe': 'image/jpg',
- '.jpeg': 'image/jpg',
- '.jpg': 'image/jpg',
- '.png': 'image/png',
- '.tga': 'image/x-tga',
- '.tif': 'image/tiff',
- '.tiff': 'image/tiff',
- '.woff': 'application/font-woff'
-};
-
-/**
- * @param {string} forPath
- */
-function getMediaMime(forPath) {
- const ext = path.extname(forPath);
-
- return mapExtToMediaMimes[ext.toLowerCase()];
-}
-
-/**
- * @param {import('http').IncomingMessage} req
- * @param {import('http').ServerResponse} res
- * @param {string} filePath
- */
-async function serveFile(req, res, filePath, responseHeaders = Object.create(null)) {
- try {
-
- // Sanity checks
- filePath = path.normalize(filePath); // ensure no "." and ".."
-
- const stat = await util.promisify(fs.stat)(filePath);
-
- // Check if file modified since
- const etag = `W/"${[stat.ino, stat.size, stat.mtime.getTime()].join('-')}"`; // weak validator (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag)
- if (req.headers['if-none-match'] === etag) {
- res.writeHead(304);
- return res.end();
- }
-
- // Headers
- responseHeaders['Content-Type'] = textMimeType[path.extname(filePath)] || getMediaMime(filePath) || 'text/plain';
- responseHeaders['Etag'] = etag;
-
- res.writeHead(200, responseHeaders);
-
- // Data
- fs.createReadStream(filePath).pipe(res);
- } catch (error) {
- console.error(error.toString());
- responseHeaders['Content-Type'] = 'text/plain';
- res.writeHead(404, responseHeaders);
- return res.end('Not found');
- }
-}
-
-if (args.launch !== false) {
- opn(`${SCHEME}://${HOST}:${PORT}`);
-}