From bcd47c10d173a0c5cb174ab7451bb5133c4e9bec Mon Sep 17 00:00:00 2001 From: Anton Kosyakov Date: Wed, 16 Jun 2021 06:39:03 +0000 Subject: [PATCH] fix issues after 1.57.0 changes --- build/azure-pipelines/common/createBuild.js | 2 +- .../common/installPlaywright.js | 2 +- .../azure-pipelines/common/publish-webview.js | 4 +- build/azure-pipelines/common/releaseBuild.js | 2 +- build/darwin/create-universal-app.js | 2 +- build/lib/builtInExtensionsCG.js | 2 +- build/lib/compilation.js | 2 +- build/lib/eslint/code-import-patterns.js | 4 +- build/lib/eslint/code-layering.js | 8 +- .../code-no-nls-in-standalone-editor.js | 4 +- build/lib/eslint/code-no-standalone-editor.js | 4 +- build/lib/eslint/code-translation-remind.js | 4 +- build/lib/extensions.js | 4 +- build/lib/i18n.js | 2080 ++++++++--------- build/lib/layersChecker.js | 8 +- build/lib/nls.js | 6 +- build/lib/optimize.js | 4 +- build/lib/preLaunch.js | 2 +- build/lib/treeshaking.js | 3 - extensions/gitpod/src/extension.ts | 20 +- package.json | 4 +- remote/package.json | 2 +- remote/web/package.json | 2 +- remote/web/yarn.lock | 18 +- remote/yarn.lock | 75 +- src/vs/base/browser/dom.ts | 10 +- src/vs/code/browser/workbench/workbench.ts | 15 +- .../node/remoteTerminalChannelServer.ts | 83 +- src/vs/gitpod/node/server.ts | 26 +- .../gitpod/node/supervisorTerminalProcess.ts | 49 +- src/vs/workbench/browser/window.ts | 24 +- .../contrib/webview/browser/pre/main.js | 4 +- yarn.lock | 26 +- 33 files changed, 1315 insertions(+), 1190 deletions(-) diff --git a/build/azure-pipelines/common/createBuild.js b/build/azure-pipelines/common/createBuild.js index d0e950a50f7c8..afa150b910e67 100644 --- a/build/azure-pipelines/common/createBuild.js +++ b/build/azure-pipelines/common/createBuild.js @@ -40,7 +40,7 @@ async function main() { }; const client = new cosmos_1.CosmosClient({ endpoint: process.env['AZURE_DOCUMENTDB_ENDPOINT'], key: process.env['AZURE_DOCUMENTDB_MASTERKEY'] }); const scripts = client.database('builds').container(quality).scripts; - await (0, retry_1.retry)(() => scripts.storedProcedure('createBuild').execute('', [Object.assign(Object.assign({}, build), { _partitionKey: '' })])); + await retry_1.retry(() => scripts.storedProcedure('createBuild').execute('', [Object.assign(Object.assign({}, build), { _partitionKey: '' })])); } main().then(() => { console.log('Build successfully created'); diff --git a/build/azure-pipelines/common/installPlaywright.js b/build/azure-pipelines/common/installPlaywright.js index a0454fd69ab50..8321e71aab020 100644 --- a/build/azure-pipelines/common/installPlaywright.js +++ b/build/azure-pipelines/common/installPlaywright.js @@ -9,6 +9,6 @@ const retry_1 = require("./retry"); const { installBrowsersWithProgressBar } = require('playwright/lib/install/installer'); const playwrightPath = path.dirname(require.resolve('playwright')); async function install() { - await (0, retry_1.retry)(() => installBrowsersWithProgressBar(playwrightPath)); + await retry_1.retry(() => installBrowsersWithProgressBar(playwrightPath)); } install(); diff --git a/build/azure-pipelines/common/publish-webview.js b/build/azure-pipelines/common/publish-webview.js index e7d6f67e42d69..2780462412645 100644 --- a/build/azure-pipelines/common/publish-webview.js +++ b/build/azure-pipelines/common/publish-webview.js @@ -39,7 +39,7 @@ async function publish(commit, files) { .withFilter(new azure.ExponentialRetryPolicyFilter(20)); await assertContainer(blobService, commit); for (const file of files) { - const blobName = (0, path_1.basename)(file); + const blobName = path_1.basename(file); const blobExists = await doesBlobExist(blobService, commit, blobName); if (blobExists) { console.log(`Blob ${commit}, ${blobName} already exists, not publishing again.`); @@ -58,7 +58,7 @@ function main() { } const opts = minimist(process.argv.slice(2)); const [directory] = opts._; - const files = fileNames.map(fileName => (0, path_1.join)(directory, fileName)); + const files = fileNames.map(fileName => path_1.join(directory, fileName)); publish(commit, files).catch(err => { console.error(err); process.exit(1); diff --git a/build/azure-pipelines/common/releaseBuild.js b/build/azure-pipelines/common/releaseBuild.js index 7aceaa9907896..c2438ca9e9d23 100644 --- a/build/azure-pipelines/common/releaseBuild.js +++ b/build/azure-pipelines/common/releaseBuild.js @@ -39,7 +39,7 @@ async function main() { } console.log(`Releasing build ${commit}...`); const scripts = client.database('builds').container(quality).scripts; - await (0, retry_1.retry)(() => scripts.storedProcedure('releaseBuild').execute('', [commit])); + await retry_1.retry(() => scripts.storedProcedure('releaseBuild').execute('', [commit])); } main().then(() => { console.log('Build successfully released'); diff --git a/build/darwin/create-universal-app.js b/build/darwin/create-universal-app.js index 92609d0e6b131..d91064d41a609 100644 --- a/build/darwin/create-universal-app.js +++ b/build/darwin/create-universal-app.js @@ -23,7 +23,7 @@ async function main() { const outAppPath = path.join(buildDir, `VSCode-darwin-${arch}`, appName); const productJsonPath = path.resolve(outAppPath, 'Contents', 'Resources', 'app', 'product.json'); const infoPlistPath = path.resolve(outAppPath, 'Contents', 'Info.plist'); - await (0, vscode_universal_1.makeUniversalApp)({ + await vscode_universal_1.makeUniversalApp({ x64AppPath, arm64AppPath, x64AsarPath, diff --git a/build/lib/builtInExtensionsCG.js b/build/lib/builtInExtensionsCG.js index 435cfcf8035ba..679663724c8b4 100644 --- a/build/lib/builtInExtensionsCG.js +++ b/build/lib/builtInExtensionsCG.js @@ -25,7 +25,7 @@ async function downloadExtensionDetails(extension) { const promises = []; for (const fileName of contentFileNames) { promises.push(new Promise(resolve => { - (0, got_1.default)(`${repositoryContentBaseUrl}/${fileName}`) + got_1.default(`${repositoryContentBaseUrl}/${fileName}`) .then(response => { resolve({ fileName, body: response.rawBody }); }) diff --git a/build/lib/compilation.js b/build/lib/compilation.js index 6cc313c7f6eec..6f5d42bc61d52 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -18,7 +18,7 @@ const ansiColors = require("ansi-colors"); const os = require("os"); const replace = require('gulp-replace'); const watch = require('./watch'); -const reporter = (0, reporter_1.createReporter)(); +const reporter = reporter_1.createReporter(); function getTypeScriptCompilerOptions(src) { const rootDir = path.join(__dirname, `../../${src}`); let options = {}; diff --git a/build/lib/eslint/code-import-patterns.js b/build/lib/eslint/code-import-patterns.js index 97dd154b1d3e8..0d508d1d00e37 100644 --- a/build/lib/eslint/code-import-patterns.js +++ b/build/lib/eslint/code-import-patterns.js @@ -21,7 +21,7 @@ module.exports = new class { const configs = context.options; for (const config of configs) { if (minimatch(context.getFilename(), config.target)) { - return (0, utils_1.createImportRuleListener)((node, value) => this._checkImport(context, config, node, value)); + return utils_1.createImportRuleListener((node, value) => this._checkImport(context, config, node, value)); } } return {}; @@ -29,7 +29,7 @@ module.exports = new class { _checkImport(context, config, node, path) { // resolve relative paths if (path[0] === '.') { - path = (0, path_1.join)(context.getFilename(), path); + path = path_1.join(context.getFilename(), path); } let restrictions; if (typeof config.restrictions === 'string') { diff --git a/build/lib/eslint/code-layering.js b/build/lib/eslint/code-layering.js index bcb413d9db315..db591f789c72c 100644 --- a/build/lib/eslint/code-layering.js +++ b/build/lib/eslint/code-layering.js @@ -17,7 +17,7 @@ module.exports = new class { }; } create(context) { - const fileDirname = (0, path_1.dirname)(context.getFilename()); + const fileDirname = path_1.dirname(context.getFilename()); const parts = fileDirname.split(/\\|\//); const ruleArgs = context.options[0]; let config; @@ -39,11 +39,11 @@ module.exports = new class { // nothing return {}; } - return (0, utils_1.createImportRuleListener)((node, path) => { + return utils_1.createImportRuleListener((node, path) => { if (path[0] === '.') { - path = (0, path_1.join)((0, path_1.dirname)(context.getFilename()), path); + path = path_1.join(path_1.dirname(context.getFilename()), path); } - const parts = (0, path_1.dirname)(path).split(/\\|\//); + const parts = path_1.dirname(path).split(/\\|\//); for (let i = parts.length - 1; i >= 0; i--) { const part = parts[i]; if (config.allowed.has(part)) { diff --git a/build/lib/eslint/code-no-nls-in-standalone-editor.js b/build/lib/eslint/code-no-nls-in-standalone-editor.js index 36782a4b5bc2b..d8955507bedc9 100644 --- a/build/lib/eslint/code-no-nls-in-standalone-editor.js +++ b/build/lib/eslint/code-no-nls-in-standalone-editor.js @@ -20,10 +20,10 @@ module.exports = new class NoNlsInStandaloneEditorRule { || /vs(\/|\\)editor(\/|\\)editor.api/.test(fileName) || /vs(\/|\\)editor(\/|\\)editor.main/.test(fileName) || /vs(\/|\\)editor(\/|\\)editor.worker/.test(fileName)) { - return (0, utils_1.createImportRuleListener)((node, path) => { + return utils_1.createImportRuleListener((node, path) => { // resolve relative paths if (path[0] === '.') { - path = (0, path_1.join)(context.getFilename(), path); + path = path_1.join(context.getFilename(), path); } if (/vs(\/|\\)nls/.test(path)) { context.report({ diff --git a/build/lib/eslint/code-no-standalone-editor.js b/build/lib/eslint/code-no-standalone-editor.js index c57bd560bcf9b..d9d6bb55b872f 100644 --- a/build/lib/eslint/code-no-standalone-editor.js +++ b/build/lib/eslint/code-no-standalone-editor.js @@ -21,10 +21,10 @@ module.exports = new class NoNlsInStandaloneEditorRule { // the vs/editor folder is allowed to use the standalone editor return {}; } - return (0, utils_1.createImportRuleListener)((node, path) => { + return utils_1.createImportRuleListener((node, path) => { // resolve relative paths if (path[0] === '.') { - path = (0, path_1.join)(context.getFilename(), path); + path = path_1.join(context.getFilename(), path); } if (/vs(\/|\\)editor(\/|\\)standalone(\/|\\)/.test(path) || /vs(\/|\\)editor(\/|\\)common(\/|\\)standalone(\/|\\)/.test(path) diff --git a/build/lib/eslint/code-translation-remind.js b/build/lib/eslint/code-translation-remind.js index 30b63429521db..a276e7c0028aa 100644 --- a/build/lib/eslint/code-translation-remind.js +++ b/build/lib/eslint/code-translation-remind.js @@ -15,7 +15,7 @@ module.exports = new (_a = class TranslationRemind { }; } create(context) { - return (0, utils_1.createImportRuleListener)((node, path) => this._checkImport(context, node, path)); + return utils_1.createImportRuleListener((node, path) => this._checkImport(context, node, path)); } _checkImport(context, node, path) { if (path !== TranslationRemind.NLS_MODULE) { @@ -31,7 +31,7 @@ module.exports = new (_a = class TranslationRemind { let resourceDefined = false; let json; try { - json = (0, fs_1.readFileSync)('./build/lib/i18n.resources.json', 'utf8'); + json = fs_1.readFileSync('./build/lib/i18n.resources.json', 'utf8'); } catch (e) { console.error('[translation-remind rule]: File with resources to pull from Transifex was not found. Aborting translation resource check for newly defined workbench part/service.'); diff --git a/build/lib/extensions.js b/build/lib/extensions.js index f15ee5a93048e..d858ee4090639 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -144,7 +144,7 @@ function fromLocalWebpack(extensionPath, webpackConfigFileName) { console.error(packagedDependencies); result.emit('error', err); }); - return result.pipe((0, stats_1.createStatsStream)(path.basename(extensionPath))); + return result.pipe(stats_1.createStatsStream(path.basename(extensionPath))); } function fromLocalNormal(extensionPath) { const result = es.through(); @@ -162,7 +162,7 @@ function fromLocalNormal(extensionPath) { es.readArray(files).pipe(result); }) .catch(err => result.emit('error', err)); - return result.pipe((0, stats_1.createStatsStream)(path.basename(extensionPath))); + return result.pipe(stats_1.createStatsStream(path.basename(extensionPath))); } const baseHeaders = { 'X-Market-Client-Id': 'VSCode Build', diff --git a/build/lib/i18n.js b/build/lib/i18n.js index 4c7c5c32eb446..28489c08c2202 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -18,1146 +18,1146 @@ const ansiColors = require("ansi-colors"); const iconv = require("iconv-lite-umd"); const NUMBER_OF_CONCURRENT_DOWNLOADS = 4; function log(message, ...rest) { - fancyLog(ansiColors.green('[i18n]'), message, ...rest); + fancyLog(ansiColors.green('[i18n]'), message, ...rest); } exports.defaultLanguages = [ - { id: 'zh-tw', folderName: 'cht', translationId: 'zh-hant' }, - { id: 'zh-cn', folderName: 'chs', translationId: 'zh-hans' }, - { id: 'ja', folderName: 'jpn' }, - { id: 'ko', folderName: 'kor' }, - { id: 'de', folderName: 'deu' }, - { id: 'fr', folderName: 'fra' }, - { id: 'es', folderName: 'esn' }, - { id: 'ru', folderName: 'rus' }, - { id: 'it', folderName: 'ita' } + { id: 'zh-tw', folderName: 'cht', translationId: 'zh-hant' }, + { id: 'zh-cn', folderName: 'chs', translationId: 'zh-hans' }, + { id: 'ja', folderName: 'jpn' }, + { id: 'ko', folderName: 'kor' }, + { id: 'de', folderName: 'deu' }, + { id: 'fr', folderName: 'fra' }, + { id: 'es', folderName: 'esn' }, + { id: 'ru', folderName: 'rus' }, + { id: 'it', folderName: 'ita' } ]; // languages requested by the community to non-stable builds exports.extraLanguages = [ - { id: 'pt-br', folderName: 'ptb' }, - { id: 'hu', folderName: 'hun' }, - { id: 'tr', folderName: 'trk' } + { id: 'pt-br', folderName: 'ptb' }, + { id: 'hu', folderName: 'hun' }, + { id: 'tr', folderName: 'trk' } ]; // non built-in extensions also that are transifex and need to be part of the language packs exports.externalExtensionsWithTranslations = { - 'vscode-chrome-debug': 'msjsdiag.debugger-for-chrome', - 'vscode-node-debug': 'ms-vscode.node-debug', - 'vscode-node-debug2': 'ms-vscode.node-debug2' + 'vscode-chrome-debug': 'msjsdiag.debugger-for-chrome', + 'vscode-node-debug': 'ms-vscode.node-debug', + 'vscode-node-debug2': 'ms-vscode.node-debug2' }; var LocalizeInfo; (function (LocalizeInfo) { - function is(value) { - let candidate = value; - return Is.defined(candidate) && Is.string(candidate.key) && (Is.undef(candidate.comment) || (Is.array(candidate.comment) && candidate.comment.every(element => Is.string(element)))); - } - LocalizeInfo.is = is; + function is(value) { + let candidate = value; + return Is.defined(candidate) && Is.string(candidate.key) && (Is.undef(candidate.comment) || (Is.array(candidate.comment) && candidate.comment.every(element => Is.string(element)))); + } + LocalizeInfo.is = is; })(LocalizeInfo || (LocalizeInfo = {})); var BundledFormat; (function (BundledFormat) { - function is(value) { - if (Is.undef(value)) { - return false; - } - let candidate = value; - let length = Object.keys(value).length; - return length === 3 && Is.defined(candidate.keys) && Is.defined(candidate.messages) && Is.defined(candidate.bundles); - } - BundledFormat.is = is; + function is(value) { + if (Is.undef(value)) { + return false; + } + let candidate = value; + let length = Object.keys(value).length; + return length === 3 && Is.defined(candidate.keys) && Is.defined(candidate.messages) && Is.defined(candidate.bundles); + } + BundledFormat.is = is; })(BundledFormat || (BundledFormat = {})); var PackageJsonFormat; (function (PackageJsonFormat) { - function is(value) { - if (Is.undef(value) || !Is.object(value)) { - return false; - } - return Object.keys(value).every(key => { - let element = value[key]; - return Is.string(element) || (Is.object(element) && Is.defined(element.message) && Is.defined(element.comment)); - }); - } - PackageJsonFormat.is = is; + function is(value) { + if (Is.undef(value) || !Is.object(value)) { + return false; + } + return Object.keys(value).every(key => { + let element = value[key]; + return Is.string(element) || (Is.object(element) && Is.defined(element.message) && Is.defined(element.comment)); + }); + } + PackageJsonFormat.is = is; })(PackageJsonFormat || (PackageJsonFormat = {})); class Line { - constructor(indent = 0) { - this.buffer = []; - if (indent > 0) { - this.buffer.push(new Array(indent + 1).join(' ')); - } - } - append(value) { - this.buffer.push(value); - return this; - } - toString() { - return this.buffer.join(''); - } + constructor(indent = 0) { + this.buffer = []; + if (indent > 0) { + this.buffer.push(new Array(indent + 1).join(' ')); + } + } + append(value) { + this.buffer.push(value); + return this; + } + toString() { + return this.buffer.join(''); + } } exports.Line = Line; class TextModel { - constructor(contents) { - this._lines = contents.split(/\r\n|\r|\n/); - } - get lines() { - return this._lines; - } + constructor(contents) { + this._lines = contents.split(/\r\n|\r|\n/); + } + get lines() { + return this._lines; + } } class XLF { - constructor(project) { - this.project = project; - this.buffer = []; - this.files = Object.create(null); - this.numberOfMessages = 0; - } - toString() { - this.appendHeader(); - const files = Object.keys(this.files).sort(); - for (const file of files) { - this.appendNewLine(``, 2); - const items = this.files[file].sort((a, b) => { - return a.id < b.id ? -1 : a.id > b.id ? 1 : 0; - }); - for (const item of items) { - this.addStringItem(file, item); - } - this.appendNewLine(''); - } - this.appendFooter(); - return this.buffer.join('\r\n'); - } - addFile(original, keys, messages) { - if (keys.length === 0) { - console.log('No keys in ' + original); - return; - } - if (keys.length !== messages.length) { - throw new Error(`Unmatching keys(${keys.length}) and messages(${messages.length}).`); - } - this.numberOfMessages += keys.length; - this.files[original] = []; - let existingKeys = new Set(); - for (let i = 0; i < keys.length; i++) { - let key = keys[i]; - let realKey; - let comment; - if (Is.string(key)) { - realKey = key; - comment = undefined; - } - else if (LocalizeInfo.is(key)) { - realKey = key.key; - if (key.comment && key.comment.length > 0) { - comment = key.comment.map(comment => encodeEntities(comment)).join('\r\n'); - } - } - if (!realKey || existingKeys.has(realKey)) { - continue; - } - existingKeys.add(realKey); - let message = encodeEntities(messages[i]); - this.files[original].push({ id: realKey, message: message, comment: comment }); - } - } - addStringItem(file, item) { - if (!item.id || item.message === undefined || item.message === null) { - throw new Error(`No item ID or value specified: ${JSON.stringify(item)}. File: ${file}`); - } - if (item.message.length === 0) { - log(`Item with id ${item.id} in file ${file} has an empty message.`); - } - this.appendNewLine(``, 4); - this.appendNewLine(`${item.message}`, 6); - if (item.comment) { - this.appendNewLine(`${item.comment}`, 6); - } - this.appendNewLine('', 4); - } - appendHeader() { - this.appendNewLine('', 0); - this.appendNewLine('', 0); - } - appendFooter() { - this.appendNewLine('', 0); - } - appendNewLine(content, indent) { - let line = new Line(indent); - line.append(content); - this.buffer.push(line.toString()); - } + constructor(project) { + this.project = project; + this.buffer = []; + this.files = Object.create(null); + this.numberOfMessages = 0; + } + toString() { + this.appendHeader(); + const files = Object.keys(this.files).sort(); + for (const file of files) { + this.appendNewLine(``, 2); + const items = this.files[file].sort((a, b) => { + return a.id < b.id ? -1 : a.id > b.id ? 1 : 0; + }); + for (const item of items) { + this.addStringItem(file, item); + } + this.appendNewLine(''); + } + this.appendFooter(); + return this.buffer.join('\r\n'); + } + addFile(original, keys, messages) { + if (keys.length === 0) { + console.log('No keys in ' + original); + return; + } + if (keys.length !== messages.length) { + throw new Error(`Unmatching keys(${keys.length}) and messages(${messages.length}).`); + } + this.numberOfMessages += keys.length; + this.files[original] = []; + let existingKeys = new Set(); + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + let realKey; + let comment; + if (Is.string(key)) { + realKey = key; + comment = undefined; + } + else if (LocalizeInfo.is(key)) { + realKey = key.key; + if (key.comment && key.comment.length > 0) { + comment = key.comment.map(comment => encodeEntities(comment)).join('\r\n'); + } + } + if (!realKey || existingKeys.has(realKey)) { + continue; + } + existingKeys.add(realKey); + let message = encodeEntities(messages[i]); + this.files[original].push({ id: realKey, message: message, comment: comment }); + } + } + addStringItem(file, item) { + if (!item.id || item.message === undefined || item.message === null) { + throw new Error(`No item ID or value specified: ${JSON.stringify(item)}. File: ${file}`); + } + if (item.message.length === 0) { + log(`Item with id ${item.id} in file ${file} has an empty message.`); + } + this.appendNewLine(``, 4); + this.appendNewLine(`${item.message}`, 6); + if (item.comment) { + this.appendNewLine(`${item.comment}`, 6); + } + this.appendNewLine('', 4); + } + appendHeader() { + this.appendNewLine('', 0); + this.appendNewLine('', 0); + } + appendFooter() { + this.appendNewLine('', 0); + } + appendNewLine(content, indent) { + let line = new Line(indent); + line.append(content); + this.buffer.push(line.toString()); + } } exports.XLF = XLF; XLF.parsePseudo = function (xlfString) { - return new Promise((resolve) => { - let parser = new xml2js.Parser(); - let files = []; - parser.parseString(xlfString, function (_err, result) { - const fileNodes = result['xliff']['file']; - fileNodes.forEach(file => { - const originalFilePath = file.$.original; - const messages = {}; - const transUnits = file.body[0]['trans-unit']; - if (transUnits) { - transUnits.forEach((unit) => { - const key = unit.$.id; - const val = pseudify(unit.source[0]['_'].toString()); - if (key && val) { - messages[key] = decodeEntities(val); - } - }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: 'ps' }); - } - }); - resolve(files); - }); - }); + return new Promise((resolve) => { + let parser = new xml2js.Parser(); + let files = []; + parser.parseString(xlfString, function (_err, result) { + const fileNodes = result['xliff']['file']; + fileNodes.forEach(file => { + const originalFilePath = file.$.original; + const messages = {}; + const transUnits = file.body[0]['trans-unit']; + if (transUnits) { + transUnits.forEach((unit) => { + const key = unit.$.id; + const val = pseudify(unit.source[0]['_'].toString()); + if (key && val) { + messages[key] = decodeEntities(val); + } + }); + files.push({ messages: messages, originalFilePath: originalFilePath, language: 'ps' }); + } + }); + resolve(files); + }); + }); }; XLF.parse = function (xlfString) { - return new Promise((resolve, reject) => { - let parser = new xml2js.Parser(); - let files = []; - parser.parseString(xlfString, function (err, result) { - if (err) { - reject(new Error(`XLF parsing error: Failed to parse XLIFF string. ${err}`)); - } - const fileNodes = result['xliff']['file']; - if (!fileNodes) { - reject(new Error(`XLF parsing error: XLIFF file does not contain "xliff" or "file" node(s) required for parsing.`)); - } - fileNodes.forEach((file) => { - const originalFilePath = file.$.original; - if (!originalFilePath) { - reject(new Error(`XLF parsing error: XLIFF file node does not contain original attribute to determine the original location of the resource file.`)); - } - let language = file.$['target-language']; - if (!language) { - reject(new Error(`XLF parsing error: XLIFF file node does not contain target-language attribute to determine translated language.`)); - } - const messages = {}; - const transUnits = file.body[0]['trans-unit']; - if (transUnits) { - transUnits.forEach((unit) => { - const key = unit.$.id; - if (!unit.target) { - return; // No translation available - } - let val = unit.target[0]; - if (typeof val !== 'string') { - // We allow empty source values so support them for translations as well. - val = val._ ? val._ : ''; - } - if (!key) { - reject(new Error(`XLF parsing error: trans-unit ${JSON.stringify(unit, undefined, 0)} defined in file ${originalFilePath} is missing the ID attribute.`)); - return; - } - messages[key] = decodeEntities(val); - }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: language.toLowerCase() }); - } - }); - resolve(files); - }); - }); + return new Promise((resolve, reject) => { + let parser = new xml2js.Parser(); + let files = []; + parser.parseString(xlfString, function (err, result) { + if (err) { + reject(new Error(`XLF parsing error: Failed to parse XLIFF string. ${err}`)); + } + const fileNodes = result['xliff']['file']; + if (!fileNodes) { + reject(new Error(`XLF parsing error: XLIFF file does not contain "xliff" or "file" node(s) required for parsing.`)); + } + fileNodes.forEach((file) => { + const originalFilePath = file.$.original; + if (!originalFilePath) { + reject(new Error(`XLF parsing error: XLIFF file node does not contain original attribute to determine the original location of the resource file.`)); + } + let language = file.$['target-language']; + if (!language) { + reject(new Error(`XLF parsing error: XLIFF file node does not contain target-language attribute to determine translated language.`)); + } + const messages = {}; + const transUnits = file.body[0]['trans-unit']; + if (transUnits) { + transUnits.forEach((unit) => { + const key = unit.$.id; + if (!unit.target) { + return; // No translation available + } + let val = unit.target[0]; + if (typeof val !== 'string') { + // We allow empty source values so support them for translations as well. + val = val._ ? val._ : ''; + } + if (!key) { + reject(new Error(`XLF parsing error: trans-unit ${JSON.stringify(unit, undefined, 0)} defined in file ${originalFilePath} is missing the ID attribute.`)); + return; + } + messages[key] = decodeEntities(val); + }); + files.push({ messages: messages, originalFilePath: originalFilePath, language: language.toLowerCase() }); + } + }); + resolve(files); + }); + }); }; class Limiter { - constructor(maxDegreeOfParalellism) { - this.maxDegreeOfParalellism = maxDegreeOfParalellism; - this.outstandingPromises = []; - this.runningPromises = 0; - } - queue(factory) { - return new Promise((c, e) => { - this.outstandingPromises.push({ factory, c, e }); - this.consume(); - }); - } - consume() { - while (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) { - const iLimitedTask = this.outstandingPromises.shift(); - this.runningPromises++; - const promise = iLimitedTask.factory(); - promise.then(iLimitedTask.c).catch(iLimitedTask.e); - promise.then(() => this.consumed()).catch(() => this.consumed()); - } - } - consumed() { - this.runningPromises--; - this.consume(); - } + constructor(maxDegreeOfParalellism) { + this.maxDegreeOfParalellism = maxDegreeOfParalellism; + this.outstandingPromises = []; + this.runningPromises = 0; + } + queue(factory) { + return new Promise((c, e) => { + this.outstandingPromises.push({ factory, c, e }); + this.consume(); + }); + } + consume() { + while (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) { + const iLimitedTask = this.outstandingPromises.shift(); + this.runningPromises++; + const promise = iLimitedTask.factory(); + promise.then(iLimitedTask.c).catch(iLimitedTask.e); + promise.then(() => this.consumed()).catch(() => this.consumed()); + } + } + consumed() { + this.runningPromises--; + this.consume(); + } } exports.Limiter = Limiter; function sortLanguages(languages) { - return languages.sort((a, b) => { - return a.id < b.id ? -1 : (a.id > b.id ? 1 : 0); - }); + return languages.sort((a, b) => { + return a.id < b.id ? -1 : (a.id > b.id ? 1 : 0); + }); } function stripComments(content) { - /** - * First capturing group matches double quoted string - * Second matches single quotes string - * Third matches block comments - * Fourth matches line comments - */ - const regexp = /("(?:[^\\\"]*(?:\\.)?)*")|('(?:[^\\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g; - let result = content.replace(regexp, (match, _m1, _m2, m3, m4) => { - // Only one of m1, m2, m3, m4 matches - if (m3) { - // A block comment. Replace with nothing - return ''; - } - else if (m4) { - // A line comment. If it ends in \r?\n then keep it. - let length = m4.length; - if (length > 2 && m4[length - 1] === '\n') { - return m4[length - 2] === '\r' ? '\r\n' : '\n'; - } - else { - return ''; - } - } - else { - // We match a string - return match; - } - }); - return result; + /** + * First capturing group matches double quoted string + * Second matches single quotes string + * Third matches block comments + * Fourth matches line comments + */ + const regexp = /("(?:[^\\\"]*(?:\\.)?)*")|('(?:[^\\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g; + let result = content.replace(regexp, (match, _m1, _m2, m3, m4) => { + // Only one of m1, m2, m3, m4 matches + if (m3) { + // A block comment. Replace with nothing + return ''; + } + else if (m4) { + // A line comment. If it ends in \r?\n then keep it. + let length = m4.length; + if (length > 2 && m4[length - 1] === '\n') { + return m4[length - 2] === '\r' ? '\r\n' : '\n'; + } + else { + return ''; + } + } + else { + // We match a string + return match; + } + }); + return result; } function escapeCharacters(value) { - const result = []; - for (let i = 0; i < value.length; i++) { - const ch = value.charAt(i); - switch (ch) { - case '\'': - result.push('\\\''); - break; - case '"': - result.push('\\"'); - break; - case '\\': - result.push('\\\\'); - break; - case '\n': - result.push('\\n'); - break; - case '\r': - result.push('\\r'); - break; - case '\t': - result.push('\\t'); - break; - case '\b': - result.push('\\b'); - break; - case '\f': - result.push('\\f'); - break; - default: - result.push(ch); - } - } - return result.join(''); + const result = []; + for (let i = 0; i < value.length; i++) { + const ch = value.charAt(i); + switch (ch) { + case '\'': + result.push('\\\''); + break; + case '"': + result.push('\\"'); + break; + case '\\': + result.push('\\\\'); + break; + case '\n': + result.push('\\n'); + break; + case '\r': + result.push('\\r'); + break; + case '\t': + result.push('\\t'); + break; + case '\b': + result.push('\\b'); + break; + case '\f': + result.push('\\f'); + break; + default: + result.push(ch); + } + } + return result.join(''); } function processCoreBundleFormat(fileHeader, languages, json, emitter) { - let keysSection = json.keys; - let messageSection = json.messages; - let bundleSection = json.bundles; - let statistics = Object.create(null); - let defaultMessages = Object.create(null); - let modules = Object.keys(keysSection); - modules.forEach((module) => { - let keys = keysSection[module]; - let messages = messageSection[module]; - if (!messages || keys.length !== messages.length) { - emitter.emit('error', `Message for module ${module} corrupted. Mismatch in number of keys and messages.`); - return; - } - let messageMap = Object.create(null); - defaultMessages[module] = messageMap; - keys.map((key, i) => { - if (typeof key === 'string') { - messageMap[key] = messages[i]; - } - else { - messageMap[key.key] = messages[i]; - } - }); - }); - let languageDirectory = path.join(__dirname, '..', '..', '..', 'vscode-loc', 'i18n'); - if (!fs.existsSync(languageDirectory)) { - log(`No VS Code localization repository found. Looking at ${languageDirectory}`); - log(`To bundle translations please check out the vscode-loc repository as a sibling of the vscode repository.`); - } - let sortedLanguages = sortLanguages(languages); - sortedLanguages.forEach((language) => { - if (process.env['VSCODE_BUILD_VERBOSE']) { - log(`Generating nls bundles for: ${language.id}`); - } - statistics[language.id] = 0; - let localizedModules = Object.create(null); - let languageFolderName = language.translationId || language.id; - let i18nFile = path.join(languageDirectory, `vscode-language-pack-${languageFolderName}`, 'translations', 'main.i18n.json'); - let allMessages; - if (fs.existsSync(i18nFile)) { - let content = stripComments(fs.readFileSync(i18nFile, 'utf8')); - allMessages = JSON.parse(content); - } - modules.forEach((module) => { - let order = keysSection[module]; - let moduleMessage; - if (allMessages) { - moduleMessage = allMessages.contents[module]; - } - if (!moduleMessage) { - if (process.env['VSCODE_BUILD_VERBOSE']) { - log(`No localized messages found for module ${module}. Using default messages.`); - } - moduleMessage = defaultMessages[module]; - statistics[language.id] = statistics[language.id] + Object.keys(moduleMessage).length; - } - let localizedMessages = []; - order.forEach((keyInfo) => { - let key = null; - if (typeof keyInfo === 'string') { - key = keyInfo; - } - else { - key = keyInfo.key; - } - let message = moduleMessage[key]; - if (!message) { - if (process.env['VSCODE_BUILD_VERBOSE']) { - log(`No localized message found for key ${key} in module ${module}. Using default message.`); - } - message = defaultMessages[module][key]; - statistics[language.id] = statistics[language.id] + 1; - } - localizedMessages.push(message); - }); - localizedModules[module] = localizedMessages; - }); - Object.keys(bundleSection).forEach((bundle) => { - let modules = bundleSection[bundle]; - let contents = [ - fileHeader, - `define("${bundle}.nls.${language.id}", {` - ]; - modules.forEach((module, index) => { - contents.push(`\t"${module}": [`); - let messages = localizedModules[module]; - if (!messages) { - emitter.emit('error', `Didn't find messages for module ${module}.`); - return; - } - messages.forEach((message, index) => { - contents.push(`\t\t"${escapeCharacters(message)}${index < messages.length ? '",' : '"'}`); - }); - contents.push(index < modules.length - 1 ? '\t],' : '\t]'); - }); - contents.push('});'); - emitter.queue(new File({ path: bundle + '.nls.' + language.id + '.js', contents: Buffer.from(contents.join('\n'), 'utf-8') })); - }); - }); - Object.keys(statistics).forEach(key => { - let value = statistics[key]; - log(`${key} has ${value} untranslated strings.`); - }); - sortedLanguages.forEach(language => { - let stats = statistics[language.id]; - if (Is.undef(stats)) { - log(`\tNo translations found for language ${language.id}. Using default language instead.`); - } - }); + let keysSection = json.keys; + let messageSection = json.messages; + let bundleSection = json.bundles; + let statistics = Object.create(null); + let defaultMessages = Object.create(null); + let modules = Object.keys(keysSection); + modules.forEach((module) => { + let keys = keysSection[module]; + let messages = messageSection[module]; + if (!messages || keys.length !== messages.length) { + emitter.emit('error', `Message for module ${module} corrupted. Mismatch in number of keys and messages.`); + return; + } + let messageMap = Object.create(null); + defaultMessages[module] = messageMap; + keys.map((key, i) => { + if (typeof key === 'string') { + messageMap[key] = messages[i]; + } + else { + messageMap[key.key] = messages[i]; + } + }); + }); + let languageDirectory = path.join(__dirname, '..', '..', '..', 'vscode-loc', 'i18n'); + if (!fs.existsSync(languageDirectory)) { + log(`No VS Code localization repository found. Looking at ${languageDirectory}`); + log(`To bundle translations please check out the vscode-loc repository as a sibling of the vscode repository.`); + } + let sortedLanguages = sortLanguages(languages); + sortedLanguages.forEach((language) => { + if (process.env['VSCODE_BUILD_VERBOSE']) { + log(`Generating nls bundles for: ${language.id}`); + } + statistics[language.id] = 0; + let localizedModules = Object.create(null); + let languageFolderName = language.translationId || language.id; + let i18nFile = path.join(languageDirectory, `vscode-language-pack-${languageFolderName}`, 'translations', 'main.i18n.json'); + let allMessages; + if (fs.existsSync(i18nFile)) { + let content = stripComments(fs.readFileSync(i18nFile, 'utf8')); + allMessages = JSON.parse(content); + } + modules.forEach((module) => { + let order = keysSection[module]; + let moduleMessage; + if (allMessages) { + moduleMessage = allMessages.contents[module]; + } + if (!moduleMessage) { + if (process.env['VSCODE_BUILD_VERBOSE']) { + log(`No localized messages found for module ${module}. Using default messages.`); + } + moduleMessage = defaultMessages[module]; + statistics[language.id] = statistics[language.id] + Object.keys(moduleMessage).length; + } + let localizedMessages = []; + order.forEach((keyInfo) => { + let key = null; + if (typeof keyInfo === 'string') { + key = keyInfo; + } + else { + key = keyInfo.key; + } + let message = moduleMessage[key]; + if (!message) { + if (process.env['VSCODE_BUILD_VERBOSE']) { + log(`No localized message found for key ${key} in module ${module}. Using default message.`); + } + message = defaultMessages[module][key]; + statistics[language.id] = statistics[language.id] + 1; + } + localizedMessages.push(message); + }); + localizedModules[module] = localizedMessages; + }); + Object.keys(bundleSection).forEach((bundle) => { + let modules = bundleSection[bundle]; + let contents = [ + fileHeader, + `define("${bundle}.nls.${language.id}", {` + ]; + modules.forEach((module, index) => { + contents.push(`\t"${module}": [`); + let messages = localizedModules[module]; + if (!messages) { + emitter.emit('error', `Didn't find messages for module ${module}.`); + return; + } + messages.forEach((message, index) => { + contents.push(`\t\t"${escapeCharacters(message)}${index < messages.length ? '",' : '"'}`); + }); + contents.push(index < modules.length - 1 ? '\t],' : '\t]'); + }); + contents.push('});'); + emitter.queue(new File({ path: bundle + '.nls.' + language.id + '.js', contents: Buffer.from(contents.join('\n'), 'utf-8') })); + }); + }); + Object.keys(statistics).forEach(key => { + let value = statistics[key]; + log(`${key} has ${value} untranslated strings.`); + }); + sortedLanguages.forEach(language => { + let stats = statistics[language.id]; + if (Is.undef(stats)) { + log(`\tNo translations found for language ${language.id}. Using default language instead.`); + } + }); } function processNlsFiles(opts) { - return event_stream_1.through(function (file) { - let fileName = path.basename(file.path); - if (fileName === 'nls.metadata.json') { - let json = null; - if (file.isBuffer()) { - json = JSON.parse(file.contents.toString('utf8')); - } - else { - this.emit('error', `Failed to read component file: ${file.relative}`); - return; - } - if (BundledFormat.is(json)) { - processCoreBundleFormat(opts.fileHeader, opts.languages, json, this); - } - } - this.queue(file); - }); + return event_stream_1.through(function (file) { + let fileName = path.basename(file.path); + if (fileName === 'nls.metadata.json') { + let json = null; + if (file.isBuffer()) { + json = JSON.parse(file.contents.toString('utf8')); + } + else { + this.emit('error', `Failed to read component file: ${file.relative}`); + return; + } + if (BundledFormat.is(json)) { + processCoreBundleFormat(opts.fileHeader, opts.languages, json, this); + } + } + this.queue(file); + }); } exports.processNlsFiles = processNlsFiles; const editorProject = 'vscode-editor', workbenchProject = 'vscode-workbench', extensionsProject = 'vscode-extensions', setupProject = 'vscode-setup'; function getResource(sourceFile) { - let resource; - if (/^vs\/platform/.test(sourceFile)) { - return { name: 'vs/platform', project: editorProject }; - } - else if (/^vs\/editor\/contrib/.test(sourceFile)) { - return { name: 'vs/editor/contrib', project: editorProject }; - } - else if (/^vs\/editor/.test(sourceFile)) { - return { name: 'vs/editor', project: editorProject }; - } - else if (/^vs\/base/.test(sourceFile)) { - return { name: 'vs/base', project: editorProject }; - } - else if (/^vs\/code/.test(sourceFile)) { - return { name: 'vs/code', project: workbenchProject }; - } - else if (/^vs\/workbench\/contrib/.test(sourceFile)) { - resource = sourceFile.split('/', 4).join('/'); - return { name: resource, project: workbenchProject }; - } - else if (/^vs\/workbench\/services/.test(sourceFile)) { - resource = sourceFile.split('/', 4).join('/'); - return { name: resource, project: workbenchProject }; - } - else if (/^vs\/workbench/.test(sourceFile)) { - return { name: 'vs/workbench', project: workbenchProject }; - } - throw new Error(`Could not identify the XLF bundle for ${sourceFile}`); + let resource; + if (/^vs\/platform/.test(sourceFile)) { + return { name: 'vs/platform', project: editorProject }; + } + else if (/^vs\/editor\/contrib/.test(sourceFile)) { + return { name: 'vs/editor/contrib', project: editorProject }; + } + else if (/^vs\/editor/.test(sourceFile)) { + return { name: 'vs/editor', project: editorProject }; + } + else if (/^vs\/base/.test(sourceFile)) { + return { name: 'vs/base', project: editorProject }; + } + else if (/^vs\/code/.test(sourceFile)) { + return { name: 'vs/code', project: workbenchProject }; + } + else if (/^vs\/workbench\/contrib/.test(sourceFile)) { + resource = sourceFile.split('/', 4).join('/'); + return { name: resource, project: workbenchProject }; + } + else if (/^vs\/workbench\/services/.test(sourceFile)) { + resource = sourceFile.split('/', 4).join('/'); + return { name: resource, project: workbenchProject }; + } + else if (/^vs\/workbench/.test(sourceFile)) { + return { name: 'vs/workbench', project: workbenchProject }; + } + throw new Error(`Could not identify the XLF bundle for ${sourceFile}`); } exports.getResource = getResource; function createXlfFilesForCoreBundle() { - return event_stream_1.through(function (file) { - const basename = path.basename(file.path); - if (basename === 'nls.metadata.json') { - if (file.isBuffer()) { - const xlfs = Object.create(null); - const json = JSON.parse(file.contents.toString('utf8')); - for (let coreModule in json.keys) { - const projectResource = getResource(coreModule); - const resource = projectResource.name; - const project = projectResource.project; - const keys = json.keys[coreModule]; - const messages = json.messages[coreModule]; - if (keys.length !== messages.length) { - this.emit('error', `There is a mismatch between keys and messages in ${file.relative} for module ${coreModule}`); - return; - } - else { - let xlf = xlfs[resource]; - if (!xlf) { - xlf = new XLF(project); - xlfs[resource] = xlf; - } - xlf.addFile(`src/${coreModule}`, keys, messages); - } - } - for (let resource in xlfs) { - const xlf = xlfs[resource]; - const filePath = `${xlf.project}/${resource.replace(/\//g, '_')}.xlf`; - const xlfFile = new File({ - path: filePath, - contents: Buffer.from(xlf.toString(), 'utf8') - }); - this.queue(xlfFile); - } - } - else { - this.emit('error', new Error(`File ${file.relative} is not using a buffer content`)); - return; - } - } - else { - this.emit('error', new Error(`File ${file.relative} is not a core meta data file.`)); - return; - } - }); + return event_stream_1.through(function (file) { + const basename = path.basename(file.path); + if (basename === 'nls.metadata.json') { + if (file.isBuffer()) { + const xlfs = Object.create(null); + const json = JSON.parse(file.contents.toString('utf8')); + for (let coreModule in json.keys) { + const projectResource = getResource(coreModule); + const resource = projectResource.name; + const project = projectResource.project; + const keys = json.keys[coreModule]; + const messages = json.messages[coreModule]; + if (keys.length !== messages.length) { + this.emit('error', `There is a mismatch between keys and messages in ${file.relative} for module ${coreModule}`); + return; + } + else { + let xlf = xlfs[resource]; + if (!xlf) { + xlf = new XLF(project); + xlfs[resource] = xlf; + } + xlf.addFile(`src/${coreModule}`, keys, messages); + } + } + for (let resource in xlfs) { + const xlf = xlfs[resource]; + const filePath = `${xlf.project}/${resource.replace(/\//g, '_')}.xlf`; + const xlfFile = new File({ + path: filePath, + contents: Buffer.from(xlf.toString(), 'utf8') + }); + this.queue(xlfFile); + } + } + else { + this.emit('error', new Error(`File ${file.relative} is not using a buffer content`)); + return; + } + } + else { + this.emit('error', new Error(`File ${file.relative} is not a core meta data file.`)); + return; + } + }); } exports.createXlfFilesForCoreBundle = createXlfFilesForCoreBundle; function createXlfFilesForExtensions() { - let counter = 0; - let folderStreamEnded = false; - let folderStreamEndEmitted = false; - return event_stream_1.through(function (extensionFolder) { - const folderStream = this; - const stat = fs.statSync(extensionFolder.path); - if (!stat.isDirectory()) { - return; - } - let extensionName = path.basename(extensionFolder.path); - if (extensionName === 'node_modules') { - return; - } - counter++; - let _xlf; - function getXlf() { - if (!_xlf) { - _xlf = new XLF(extensionsProject); - } - return _xlf; - } - gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(event_stream_1.through(function (file) { - if (file.isBuffer()) { - const buffer = file.contents; - const basename = path.basename(file.path); - if (basename === 'package.nls.json') { - const json = JSON.parse(buffer.toString('utf8')); - const keys = Object.keys(json); - const messages = keys.map((key) => { - const value = json[key]; - if (Is.string(value)) { - return value; - } - else if (value) { - return value.message; - } - else { - return `Unknown message for key: ${key}`; - } - }); - getXlf().addFile(`extensions/${extensionName}/package`, keys, messages); - } - else if (basename === 'nls.metadata.json') { - const json = JSON.parse(buffer.toString('utf8')); - const relPath = path.relative(`.build/extensions/${extensionName}`, path.dirname(file.path)); - for (let file in json) { - const fileContent = json[file]; - getXlf().addFile(`extensions/${extensionName}/${relPath}/${file}`, fileContent.keys, fileContent.messages); - } - } - else { - this.emit('error', new Error(`${file.path} is not a valid extension nls file`)); - return; - } - } - }, function () { - if (_xlf) { - let xlfFile = new File({ - path: path.join(extensionsProject, extensionName + '.xlf'), - contents: Buffer.from(_xlf.toString(), 'utf8') - }); - folderStream.queue(xlfFile); - } - this.queue(null); - counter--; - if (counter === 0 && folderStreamEnded && !folderStreamEndEmitted) { - folderStreamEndEmitted = true; - folderStream.queue(null); - } - })); - }, function () { - folderStreamEnded = true; - if (counter === 0) { - folderStreamEndEmitted = true; - this.queue(null); - } - }); + let counter = 0; + let folderStreamEnded = false; + let folderStreamEndEmitted = false; + return event_stream_1.through(function (extensionFolder) { + const folderStream = this; + const stat = fs.statSync(extensionFolder.path); + if (!stat.isDirectory()) { + return; + } + let extensionName = path.basename(extensionFolder.path); + if (extensionName === 'node_modules') { + return; + } + counter++; + let _xlf; + function getXlf() { + if (!_xlf) { + _xlf = new XLF(extensionsProject); + } + return _xlf; + } + gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(event_stream_1.through(function (file) { + if (file.isBuffer()) { + const buffer = file.contents; + const basename = path.basename(file.path); + if (basename === 'package.nls.json') { + const json = JSON.parse(buffer.toString('utf8')); + const keys = Object.keys(json); + const messages = keys.map((key) => { + const value = json[key]; + if (Is.string(value)) { + return value; + } + else if (value) { + return value.message; + } + else { + return `Unknown message for key: ${key}`; + } + }); + getXlf().addFile(`extensions/${extensionName}/package`, keys, messages); + } + else if (basename === 'nls.metadata.json') { + const json = JSON.parse(buffer.toString('utf8')); + const relPath = path.relative(`.build/extensions/${extensionName}`, path.dirname(file.path)); + for (let file in json) { + const fileContent = json[file]; + getXlf().addFile(`extensions/${extensionName}/${relPath}/${file}`, fileContent.keys, fileContent.messages); + } + } + else { + this.emit('error', new Error(`${file.path} is not a valid extension nls file`)); + return; + } + } + }, function () { + if (_xlf) { + let xlfFile = new File({ + path: path.join(extensionsProject, extensionName + '.xlf'), + contents: Buffer.from(_xlf.toString(), 'utf8') + }); + folderStream.queue(xlfFile); + } + this.queue(null); + counter--; + if (counter === 0 && folderStreamEnded && !folderStreamEndEmitted) { + folderStreamEndEmitted = true; + folderStream.queue(null); + } + })); + }, function () { + folderStreamEnded = true; + if (counter === 0) { + folderStreamEndEmitted = true; + this.queue(null); + } + }); } exports.createXlfFilesForExtensions = createXlfFilesForExtensions; function createXlfFilesForIsl() { - return event_stream_1.through(function (file) { - let projectName, resourceFile; - if (path.basename(file.path) === 'messages.en.isl') { - projectName = setupProject; - resourceFile = 'messages.xlf'; - } - else { - throw new Error(`Unknown input file ${file.path}`); - } - let xlf = new XLF(projectName), keys = [], messages = []; - let model = new TextModel(file.contents.toString()); - let inMessageSection = false; - model.lines.forEach(line => { - if (line.length === 0) { - return; - } - let firstChar = line.charAt(0); - switch (firstChar) { - case ';': - // Comment line; - return; - case '[': - inMessageSection = '[Messages]' === line || '[CustomMessages]' === line; - return; - } - if (!inMessageSection) { - return; - } - let sections = line.split('='); - if (sections.length !== 2) { - throw new Error(`Badly formatted message found: ${line}`); - } - else { - let key = sections[0]; - let value = sections[1]; - if (key.length > 0 && value.length > 0) { - keys.push(key); - messages.push(value); - } - } - }); - const originalPath = file.path.substring(file.cwd.length + 1, file.path.split('.')[0].length).replace(/\\/g, '/'); - xlf.addFile(originalPath, keys, messages); - // Emit only upon all ISL files combined into single XLF instance - const newFilePath = path.join(projectName, resourceFile); - const xlfFile = new File({ path: newFilePath, contents: Buffer.from(xlf.toString(), 'utf-8') }); - this.queue(xlfFile); - }); + return event_stream_1.through(function (file) { + let projectName, resourceFile; + if (path.basename(file.path) === 'messages.en.isl') { + projectName = setupProject; + resourceFile = 'messages.xlf'; + } + else { + throw new Error(`Unknown input file ${file.path}`); + } + let xlf = new XLF(projectName), keys = [], messages = []; + let model = new TextModel(file.contents.toString()); + let inMessageSection = false; + model.lines.forEach(line => { + if (line.length === 0) { + return; + } + let firstChar = line.charAt(0); + switch (firstChar) { + case ';': + // Comment line; + return; + case '[': + inMessageSection = '[Messages]' === line || '[CustomMessages]' === line; + return; + } + if (!inMessageSection) { + return; + } + let sections = line.split('='); + if (sections.length !== 2) { + throw new Error(`Badly formatted message found: ${line}`); + } + else { + let key = sections[0]; + let value = sections[1]; + if (key.length > 0 && value.length > 0) { + keys.push(key); + messages.push(value); + } + } + }); + const originalPath = file.path.substring(file.cwd.length + 1, file.path.split('.')[0].length).replace(/\\/g, '/'); + xlf.addFile(originalPath, keys, messages); + // Emit only upon all ISL files combined into single XLF instance + const newFilePath = path.join(projectName, resourceFile); + const xlfFile = new File({ path: newFilePath, contents: Buffer.from(xlf.toString(), 'utf-8') }); + this.queue(xlfFile); + }); } exports.createXlfFilesForIsl = createXlfFilesForIsl; function pushXlfFiles(apiHostname, username, password) { - let tryGetPromises = []; - let updateCreatePromises = []; - return event_stream_1.through(function (file) { - const project = path.dirname(file.relative); - const fileName = path.basename(file.path); - const slug = fileName.substr(0, fileName.length - '.xlf'.length); - const credentials = `${username}:${password}`; - // Check if resource already exists, if not, then create it. - let promise = tryGetResource(project, slug, apiHostname, credentials); - tryGetPromises.push(promise); - promise.then(exists => { - if (exists) { - promise = updateResource(project, slug, file, apiHostname, credentials); - } - else { - promise = createResource(project, slug, file, apiHostname, credentials); - } - updateCreatePromises.push(promise); - }); - }, function () { - // End the pipe only after all the communication with Transifex API happened - Promise.all(tryGetPromises).then(() => { - Promise.all(updateCreatePromises).then(() => { - this.queue(null); - }).catch((reason) => { throw new Error(reason); }); - }).catch((reason) => { throw new Error(reason); }); - }); + let tryGetPromises = []; + let updateCreatePromises = []; + return event_stream_1.through(function (file) { + const project = path.dirname(file.relative); + const fileName = path.basename(file.path); + const slug = fileName.substr(0, fileName.length - '.xlf'.length); + const credentials = `${username}:${password}`; + // Check if resource already exists, if not, then create it. + let promise = tryGetResource(project, slug, apiHostname, credentials); + tryGetPromises.push(promise); + promise.then(exists => { + if (exists) { + promise = updateResource(project, slug, file, apiHostname, credentials); + } + else { + promise = createResource(project, slug, file, apiHostname, credentials); + } + updateCreatePromises.push(promise); + }); + }, function () { + // End the pipe only after all the communication with Transifex API happened + Promise.all(tryGetPromises).then(() => { + Promise.all(updateCreatePromises).then(() => { + this.queue(null); + }).catch((reason) => { throw new Error(reason); }); + }).catch((reason) => { throw new Error(reason); }); + }); } exports.pushXlfFiles = pushXlfFiles; function getAllResources(project, apiHostname, username, password) { - return new Promise((resolve, reject) => { - const credentials = `${username}:${password}`; - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resources`, - auth: credentials, - method: 'GET' - }; - const request = https.request(options, (res) => { - let buffer = []; - res.on('data', (chunk) => buffer.push(chunk)); - res.on('end', () => { - if (res.statusCode === 200) { - let json = JSON.parse(Buffer.concat(buffer).toString()); - if (Array.isArray(json)) { - resolve(json.map(o => o.slug)); - return; - } - reject(`Unexpected data format. Response code: ${res.statusCode}.`); - } - else { - reject(`No resources in ${project} returned no data. Response code: ${res.statusCode}.`); - } - }); - }); - request.on('error', (err) => { - reject(`Failed to query resources in ${project} with the following error: ${err}. ${options.path}`); - }); - request.end(); - }); + return new Promise((resolve, reject) => { + const credentials = `${username}:${password}`; + const options = { + hostname: apiHostname, + path: `/api/2/project/${project}/resources`, + auth: credentials, + method: 'GET' + }; + const request = https.request(options, (res) => { + let buffer = []; + res.on('data', (chunk) => buffer.push(chunk)); + res.on('end', () => { + if (res.statusCode === 200) { + let json = JSON.parse(Buffer.concat(buffer).toString()); + if (Array.isArray(json)) { + resolve(json.map(o => o.slug)); + return; + } + reject(`Unexpected data format. Response code: ${res.statusCode}.`); + } + else { + reject(`No resources in ${project} returned no data. Response code: ${res.statusCode}.`); + } + }); + }); + request.on('error', (err) => { + reject(`Failed to query resources in ${project} with the following error: ${err}. ${options.path}`); + }); + request.end(); + }); } function findObsoleteResources(apiHostname, username, password) { - let resourcesByProject = Object.create(null); - resourcesByProject[extensionsProject] = [].concat(exports.externalExtensionsWithTranslations); // clone - return event_stream_1.through(function (file) { - const project = path.dirname(file.relative); - const fileName = path.basename(file.path); - const slug = fileName.substr(0, fileName.length - '.xlf'.length); - let slugs = resourcesByProject[project]; - if (!slugs) { - resourcesByProject[project] = slugs = []; - } - slugs.push(slug); - this.push(file); - }, function () { - const json = JSON.parse(fs.readFileSync('./build/lib/i18n.resources.json', 'utf8')); - let i18Resources = [...json.editor, ...json.workbench].map((r) => r.project + '/' + r.name.replace(/\//g, '_')); - let extractedResources = []; - for (let project of [workbenchProject, editorProject]) { - for (let resource of resourcesByProject[project]) { - if (resource !== 'setup_messages') { - extractedResources.push(project + '/' + resource); - } - } - } - if (i18Resources.length !== extractedResources.length) { - console.log(`[i18n] Obsolete resources in file 'build/lib/i18n.resources.json': JSON.stringify(${i18Resources.filter(p => extractedResources.indexOf(p) === -1)})`); - console.log(`[i18n] Missing resources in file 'build/lib/i18n.resources.json': JSON.stringify(${extractedResources.filter(p => i18Resources.indexOf(p) === -1)})`); - } - let promises = []; - for (let project in resourcesByProject) { - promises.push(getAllResources(project, apiHostname, username, password).then(resources => { - let expectedResources = resourcesByProject[project]; - let unusedResources = resources.filter(resource => resource && expectedResources.indexOf(resource) === -1); - if (unusedResources.length) { - console.log(`[transifex] Obsolete resources in project '${project}': ${unusedResources.join(', ')}`); - } - })); - } - return Promise.all(promises).then(_ => { - this.push(null); - }).catch((reason) => { throw new Error(reason); }); - }); + let resourcesByProject = Object.create(null); + resourcesByProject[extensionsProject] = [].concat(exports.externalExtensionsWithTranslations); // clone + return event_stream_1.through(function (file) { + const project = path.dirname(file.relative); + const fileName = path.basename(file.path); + const slug = fileName.substr(0, fileName.length - '.xlf'.length); + let slugs = resourcesByProject[project]; + if (!slugs) { + resourcesByProject[project] = slugs = []; + } + slugs.push(slug); + this.push(file); + }, function () { + const json = JSON.parse(fs.readFileSync('./build/lib/i18n.resources.json', 'utf8')); + let i18Resources = [...json.editor, ...json.workbench].map((r) => r.project + '/' + r.name.replace(/\//g, '_')); + let extractedResources = []; + for (let project of [workbenchProject, editorProject]) { + for (let resource of resourcesByProject[project]) { + if (resource !== 'setup_messages') { + extractedResources.push(project + '/' + resource); + } + } + } + if (i18Resources.length !== extractedResources.length) { + console.log(`[i18n] Obsolete resources in file 'build/lib/i18n.resources.json': JSON.stringify(${i18Resources.filter(p => extractedResources.indexOf(p) === -1)})`); + console.log(`[i18n] Missing resources in file 'build/lib/i18n.resources.json': JSON.stringify(${extractedResources.filter(p => i18Resources.indexOf(p) === -1)})`); + } + let promises = []; + for (let project in resourcesByProject) { + promises.push(getAllResources(project, apiHostname, username, password).then(resources => { + let expectedResources = resourcesByProject[project]; + let unusedResources = resources.filter(resource => resource && expectedResources.indexOf(resource) === -1); + if (unusedResources.length) { + console.log(`[transifex] Obsolete resources in project '${project}': ${unusedResources.join(', ')}`); + } + })); + } + return Promise.all(promises).then(_ => { + this.push(null); + }).catch((reason) => { throw new Error(reason); }); + }); } exports.findObsoleteResources = findObsoleteResources; function tryGetResource(project, slug, apiHostname, credentials) { - return new Promise((resolve, reject) => { - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/?details`, - auth: credentials, - method: 'GET' - }; - const request = https.request(options, (response) => { - if (response.statusCode === 404) { - resolve(false); - } - else if (response.statusCode === 200) { - resolve(true); - } - else { - reject(`Failed to query resource ${project}/${slug}. Response: ${response.statusCode} ${response.statusMessage}`); - } - }); - request.on('error', (err) => { - reject(`Failed to get ${project}/${slug} on Transifex: ${err}`); - }); - request.end(); - }); + return new Promise((resolve, reject) => { + const options = { + hostname: apiHostname, + path: `/api/2/project/${project}/resource/${slug}/?details`, + auth: credentials, + method: 'GET' + }; + const request = https.request(options, (response) => { + if (response.statusCode === 404) { + resolve(false); + } + else if (response.statusCode === 200) { + resolve(true); + } + else { + reject(`Failed to query resource ${project}/${slug}. Response: ${response.statusCode} ${response.statusMessage}`); + } + }); + request.on('error', (err) => { + reject(`Failed to get ${project}/${slug} on Transifex: ${err}`); + }); + request.end(); + }); } function createResource(project, slug, xlfFile, apiHostname, credentials) { - return new Promise((_resolve, reject) => { - const data = JSON.stringify({ - 'content': xlfFile.contents.toString(), - 'name': slug, - 'slug': slug, - 'i18n_type': 'XLIFF' - }); - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resources`, - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(data) - }, - auth: credentials, - method: 'POST' - }; - let request = https.request(options, (res) => { - if (res.statusCode === 201) { - log(`Resource ${project}/${slug} successfully created on Transifex.`); - } - else { - reject(`Something went wrong in the request creating ${slug} in ${project}. ${res.statusCode}`); - } - }); - request.on('error', (err) => { - reject(`Failed to create ${project}/${slug} on Transifex: ${err}`); - }); - request.write(data); - request.end(); - }); + return new Promise((_resolve, reject) => { + const data = JSON.stringify({ + 'content': xlfFile.contents.toString(), + 'name': slug, + 'slug': slug, + 'i18n_type': 'XLIFF' + }); + const options = { + hostname: apiHostname, + path: `/api/2/project/${project}/resources`, + headers: { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(data) + }, + auth: credentials, + method: 'POST' + }; + let request = https.request(options, (res) => { + if (res.statusCode === 201) { + log(`Resource ${project}/${slug} successfully created on Transifex.`); + } + else { + reject(`Something went wrong in the request creating ${slug} in ${project}. ${res.statusCode}`); + } + }); + request.on('error', (err) => { + reject(`Failed to create ${project}/${slug} on Transifex: ${err}`); + }); + request.write(data); + request.end(); + }); } /** * The following link provides information about how Transifex handles updates of a resource file: * https://dev.befoolish.co/tx-docs/public/projects/updating-content#what-happens-when-you-update-files */ function updateResource(project, slug, xlfFile, apiHostname, credentials) { - return new Promise((resolve, reject) => { - const data = JSON.stringify({ content: xlfFile.contents.toString() }); - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/content`, - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(data) - }, - auth: credentials, - method: 'PUT' - }; - let request = https.request(options, (res) => { - if (res.statusCode === 200) { - res.setEncoding('utf8'); - let responseBuffer = ''; - res.on('data', function (chunk) { - responseBuffer += chunk; - }); - res.on('end', () => { - const response = JSON.parse(responseBuffer); - log(`Resource ${project}/${slug} successfully updated on Transifex. Strings added: ${response.strings_added}, updated: ${response.strings_added}, deleted: ${response.strings_added}`); - resolve(); - }); - } - else { - reject(`Something went wrong in the request updating ${slug} in ${project}. ${res.statusCode}`); - } - }); - request.on('error', (err) => { - reject(`Failed to update ${project}/${slug} on Transifex: ${err}`); - }); - request.write(data); - request.end(); - }); + return new Promise((resolve, reject) => { + const data = JSON.stringify({ content: xlfFile.contents.toString() }); + const options = { + hostname: apiHostname, + path: `/api/2/project/${project}/resource/${slug}/content`, + headers: { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(data) + }, + auth: credentials, + method: 'PUT' + }; + let request = https.request(options, (res) => { + if (res.statusCode === 200) { + res.setEncoding('utf8'); + let responseBuffer = ''; + res.on('data', function (chunk) { + responseBuffer += chunk; + }); + res.on('end', () => { + const response = JSON.parse(responseBuffer); + log(`Resource ${project}/${slug} successfully updated on Transifex. Strings added: ${response.strings_added}, updated: ${response.strings_added}, deleted: ${response.strings_added}`); + resolve(); + }); + } + else { + reject(`Something went wrong in the request updating ${slug} in ${project}. ${res.statusCode}`); + } + }); + request.on('error', (err) => { + reject(`Failed to update ${project}/${slug} on Transifex: ${err}`); + }); + request.write(data); + request.end(); + }); } function pullSetupXlfFiles(apiHostname, username, password, language, includeDefault) { - let setupResources = [{ name: 'setup_messages', project: workbenchProject }]; - if (includeDefault) { - setupResources.push({ name: 'setup_default', project: setupProject }); - } - return pullXlfFiles(apiHostname, username, password, language, setupResources); + let setupResources = [{ name: 'setup_messages', project: workbenchProject }]; + if (includeDefault) { + setupResources.push({ name: 'setup_default', project: setupProject }); + } + return pullXlfFiles(apiHostname, username, password, language, setupResources); } exports.pullSetupXlfFiles = pullSetupXlfFiles; function pullXlfFiles(apiHostname, username, password, language, resources) { - const credentials = `${username}:${password}`; - let expectedTranslationsCount = resources.length; - let translationsRetrieved = 0, called = false; - return event_stream_1.readable(function (_count, callback) { - // Mark end of stream when all resources were retrieved - if (translationsRetrieved === expectedTranslationsCount) { - return this.emit('end'); - } - if (!called) { - called = true; - const stream = this; - resources.map(function (resource) { - retrieveResource(language, resource, apiHostname, credentials).then((file) => { - if (file) { - stream.emit('data', file); - } - translationsRetrieved++; - }).catch(error => { throw new Error(error); }); - }); - } - callback(); - }); + const credentials = `${username}:${password}`; + let expectedTranslationsCount = resources.length; + let translationsRetrieved = 0, called = false; + return event_stream_1.readable(function (_count, callback) { + // Mark end of stream when all resources were retrieved + if (translationsRetrieved === expectedTranslationsCount) { + return this.emit('end'); + } + if (!called) { + called = true; + const stream = this; + resources.map(function (resource) { + retrieveResource(language, resource, apiHostname, credentials).then((file) => { + if (file) { + stream.emit('data', file); + } + translationsRetrieved++; + }).catch(error => { throw new Error(error); }); + }); + } + callback(); + }); } const limiter = new Limiter(NUMBER_OF_CONCURRENT_DOWNLOADS); function retrieveResource(language, resource, apiHostname, credentials) { - return limiter.queue(() => new Promise((resolve, reject) => { - const slug = resource.name.replace(/\//g, '_'); - const project = resource.project; - let transifexLanguageId = language.id === 'ps' ? 'en' : language.translationId || language.id; - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/translation/${transifexLanguageId}?file&mode=onlyreviewed`, - auth: credentials, - port: 443, - method: 'GET' - }; - console.log('[transifex] Fetching ' + options.path); - let request = https.request(options, (res) => { - let xlfBuffer = []; - res.on('data', (chunk) => xlfBuffer.push(chunk)); - res.on('end', () => { - if (res.statusCode === 200) { - resolve(new File({ contents: Buffer.concat(xlfBuffer), path: `${project}/${slug}.xlf` })); - } - else if (res.statusCode === 404) { - console.log(`[transifex] ${slug} in ${project} returned no data.`); - resolve(null); - } - else { - reject(`${slug} in ${project} returned no data. Response code: ${res.statusCode}.`); - } - }); - }); - request.on('error', (err) => { - reject(`Failed to query resource ${slug} with the following error: ${err}. ${options.path}`); - }); - request.end(); - })); + return limiter.queue(() => new Promise((resolve, reject) => { + const slug = resource.name.replace(/\//g, '_'); + const project = resource.project; + let transifexLanguageId = language.id === 'ps' ? 'en' : language.translationId || language.id; + const options = { + hostname: apiHostname, + path: `/api/2/project/${project}/resource/${slug}/translation/${transifexLanguageId}?file&mode=onlyreviewed`, + auth: credentials, + port: 443, + method: 'GET' + }; + console.log('[transifex] Fetching ' + options.path); + let request = https.request(options, (res) => { + let xlfBuffer = []; + res.on('data', (chunk) => xlfBuffer.push(chunk)); + res.on('end', () => { + if (res.statusCode === 200) { + resolve(new File({ contents: Buffer.concat(xlfBuffer), path: `${project}/${slug}.xlf` })); + } + else if (res.statusCode === 404) { + console.log(`[transifex] ${slug} in ${project} returned no data.`); + resolve(null); + } + else { + reject(`${slug} in ${project} returned no data. Response code: ${res.statusCode}.`); + } + }); + }); + request.on('error', (err) => { + reject(`Failed to query resource ${slug} with the following error: ${err}. ${options.path}`); + }); + request.end(); + })); } function prepareI18nFiles() { - let parsePromises = []; - return event_stream_1.through(function (xlf) { - let stream = this; - let parsePromise = XLF.parse(xlf.contents.toString()); - parsePromises.push(parsePromise); - parsePromise.then(resolvedFiles => { - resolvedFiles.forEach(file => { - let translatedFile = createI18nFile(file.originalFilePath, file.messages); - stream.queue(translatedFile); - }); - }); - }, function () { - Promise.all(parsePromises) - .then(() => { this.queue(null); }) - .catch(reason => { throw new Error(reason); }); - }); + let parsePromises = []; + return event_stream_1.through(function (xlf) { + let stream = this; + let parsePromise = XLF.parse(xlf.contents.toString()); + parsePromises.push(parsePromise); + parsePromise.then(resolvedFiles => { + resolvedFiles.forEach(file => { + let translatedFile = createI18nFile(file.originalFilePath, file.messages); + stream.queue(translatedFile); + }); + }); + }, function () { + Promise.all(parsePromises) + .then(() => { this.queue(null); }) + .catch(reason => { throw new Error(reason); }); + }); } exports.prepareI18nFiles = prepareI18nFiles; function createI18nFile(originalFilePath, messages) { - let result = Object.create(null); - result[''] = [ - '--------------------------------------------------------------------------------------------', - 'Copyright (c) Microsoft Corporation. All rights reserved.', - 'Licensed under the MIT License. See License.txt in the project root for license information.', - '--------------------------------------------------------------------------------------------', - 'Do not edit this file. It is machine generated.' - ]; - for (let key of Object.keys(messages)) { - result[key] = messages[key]; - } - let content = JSON.stringify(result, null, '\t'); - if (process.platform === 'win32') { - content = content.replace(/\n/g, '\r\n'); - } - return new File({ - path: path.join(originalFilePath + '.i18n.json'), - contents: Buffer.from(content, 'utf8') - }); + let result = Object.create(null); + result[''] = [ + '--------------------------------------------------------------------------------------------', + 'Copyright (c) Microsoft Corporation. All rights reserved.', + 'Licensed under the MIT License. See License.txt in the project root for license information.', + '--------------------------------------------------------------------------------------------', + 'Do not edit this file. It is machine generated.' + ]; + for (let key of Object.keys(messages)) { + result[key] = messages[key]; + } + let content = JSON.stringify(result, null, '\t'); + if (process.platform === 'win32') { + content = content.replace(/\n/g, '\r\n'); + } + return new File({ + path: path.join(originalFilePath + '.i18n.json'), + contents: Buffer.from(content, 'utf8') + }); } const i18nPackVersion = '1.0.0'; function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pseudo = false) { - let parsePromises = []; - let mainPack = { version: i18nPackVersion, contents: {} }; - let extensionsPacks = {}; - let errors = []; - return event_stream_1.through(function (xlf) { - let project = path.basename(path.dirname(path.dirname(xlf.relative))); - let resource = path.basename(xlf.relative, '.xlf'); - let contents = xlf.contents.toString(); - log(`Found ${project}: ${resource}`); - let parsePromise = pseudo ? XLF.parsePseudo(contents) : XLF.parse(contents); - parsePromises.push(parsePromise); - parsePromise.then(resolvedFiles => { - resolvedFiles.forEach(file => { - const path = file.originalFilePath; - const firstSlash = path.indexOf('/'); - if (project === extensionsProject) { - let extPack = extensionsPacks[resource]; - if (!extPack) { - extPack = extensionsPacks[resource] = { version: i18nPackVersion, contents: {} }; - } - const externalId = externalExtensions[resource]; - if (!externalId) { // internal extension: remove 'extensions/extensionId/' segnent - const secondSlash = path.indexOf('/', firstSlash + 1); - extPack.contents[path.substr(secondSlash + 1)] = file.messages; - } - else { - extPack.contents[path] = file.messages; - } - } - else { - mainPack.contents[path.substr(firstSlash + 1)] = file.messages; - } - }); - }).catch(reason => { - errors.push(reason); - }); - }, function () { - Promise.all(parsePromises) - .then(() => { - if (errors.length > 0) { - throw errors; - } - const translatedMainFile = createI18nFile('./main', mainPack); - resultingTranslationPaths.push({ id: 'vscode', resourceName: 'main.i18n.json' }); - this.queue(translatedMainFile); - for (let extension in extensionsPacks) { - const translatedExtFile = createI18nFile(`extensions/${extension}`, extensionsPacks[extension]); - this.queue(translatedExtFile); - const externalExtensionId = externalExtensions[extension]; - if (externalExtensionId) { - resultingTranslationPaths.push({ id: externalExtensionId, resourceName: `extensions/${extension}.i18n.json` }); - } - else { - resultingTranslationPaths.push({ id: `vscode.${extension}`, resourceName: `extensions/${extension}.i18n.json` }); - } - } - this.queue(null); - }) - .catch((reason) => { - this.emit('error', reason); - }); - }); + let parsePromises = []; + let mainPack = { version: i18nPackVersion, contents: {} }; + let extensionsPacks = {}; + let errors = []; + return event_stream_1.through(function (xlf) { + let project = path.basename(path.dirname(path.dirname(xlf.relative))); + let resource = path.basename(xlf.relative, '.xlf'); + let contents = xlf.contents.toString(); + log(`Found ${project}: ${resource}`); + let parsePromise = pseudo ? XLF.parsePseudo(contents) : XLF.parse(contents); + parsePromises.push(parsePromise); + parsePromise.then(resolvedFiles => { + resolvedFiles.forEach(file => { + const path = file.originalFilePath; + const firstSlash = path.indexOf('/'); + if (project === extensionsProject) { + let extPack = extensionsPacks[resource]; + if (!extPack) { + extPack = extensionsPacks[resource] = { version: i18nPackVersion, contents: {} }; + } + const externalId = externalExtensions[resource]; + if (!externalId) { // internal extension: remove 'extensions/extensionId/' segnent + const secondSlash = path.indexOf('/', firstSlash + 1); + extPack.contents[path.substr(secondSlash + 1)] = file.messages; + } + else { + extPack.contents[path] = file.messages; + } + } + else { + mainPack.contents[path.substr(firstSlash + 1)] = file.messages; + } + }); + }).catch(reason => { + errors.push(reason); + }); + }, function () { + Promise.all(parsePromises) + .then(() => { + if (errors.length > 0) { + throw errors; + } + const translatedMainFile = createI18nFile('./main', mainPack); + resultingTranslationPaths.push({ id: 'vscode', resourceName: 'main.i18n.json' }); + this.queue(translatedMainFile); + for (let extension in extensionsPacks) { + const translatedExtFile = createI18nFile(`extensions/${extension}`, extensionsPacks[extension]); + this.queue(translatedExtFile); + const externalExtensionId = externalExtensions[extension]; + if (externalExtensionId) { + resultingTranslationPaths.push({ id: externalExtensionId, resourceName: `extensions/${extension}.i18n.json` }); + } + else { + resultingTranslationPaths.push({ id: `vscode.${extension}`, resourceName: `extensions/${extension}.i18n.json` }); + } + } + this.queue(null); + }) + .catch((reason) => { + this.emit('error', reason); + }); + }); } exports.prepareI18nPackFiles = prepareI18nPackFiles; function prepareIslFiles(language, innoSetupConfig) { - let parsePromises = []; - return event_stream_1.through(function (xlf) { - let stream = this; - let parsePromise = XLF.parse(xlf.contents.toString()); - parsePromises.push(parsePromise); - parsePromise.then(resolvedFiles => { - resolvedFiles.forEach(file => { - let translatedFile = createIslFile(file.originalFilePath, file.messages, language, innoSetupConfig); - stream.queue(translatedFile); - }); - }).catch(reason => { - this.emit('error', reason); - }); - }, function () { - Promise.all(parsePromises) - .then(() => { this.queue(null); }) - .catch(reason => { - this.emit('error', reason); - }); - }); + let parsePromises = []; + return event_stream_1.through(function (xlf) { + let stream = this; + let parsePromise = XLF.parse(xlf.contents.toString()); + parsePromises.push(parsePromise); + parsePromise.then(resolvedFiles => { + resolvedFiles.forEach(file => { + let translatedFile = createIslFile(file.originalFilePath, file.messages, language, innoSetupConfig); + stream.queue(translatedFile); + }); + }).catch(reason => { + this.emit('error', reason); + }); + }, function () { + Promise.all(parsePromises) + .then(() => { this.queue(null); }) + .catch(reason => { + this.emit('error', reason); + }); + }); } exports.prepareIslFiles = prepareIslFiles; function createIslFile(originalFilePath, messages, language, innoSetup) { - let content = []; - let originalContent; - if (path.basename(originalFilePath) === 'Default') { - originalContent = new TextModel(fs.readFileSync(originalFilePath + '.isl', 'utf8')); - } - else { - originalContent = new TextModel(fs.readFileSync(originalFilePath + '.en.isl', 'utf8')); - } - originalContent.lines.forEach(line => { - if (line.length > 0) { - let firstChar = line.charAt(0); - if (firstChar === '[' || firstChar === ';') { - content.push(line); - } - else { - let sections = line.split('='); - let key = sections[0]; - let translated = line; - if (key) { - let translatedMessage = messages[key]; - if (translatedMessage) { - translated = `${key}=${translatedMessage}`; - } - } - content.push(translated); - } - } - }); - const basename = path.basename(originalFilePath); - const filePath = `${basename}.${language.id}.isl`; - const encoded = iconv.encode(Buffer.from(content.join('\r\n'), 'utf8').toString(), innoSetup.codePage); - return new File({ - path: filePath, - contents: Buffer.from(encoded), - }); + let content = []; + let originalContent; + if (path.basename(originalFilePath) === 'Default') { + originalContent = new TextModel(fs.readFileSync(originalFilePath + '.isl', 'utf8')); + } + else { + originalContent = new TextModel(fs.readFileSync(originalFilePath + '.en.isl', 'utf8')); + } + originalContent.lines.forEach(line => { + if (line.length > 0) { + let firstChar = line.charAt(0); + if (firstChar === '[' || firstChar === ';') { + content.push(line); + } + else { + let sections = line.split('='); + let key = sections[0]; + let translated = line; + if (key) { + let translatedMessage = messages[key]; + if (translatedMessage) { + translated = `${key}=${translatedMessage}`; + } + } + content.push(translated); + } + } + }); + const basename = path.basename(originalFilePath); + const filePath = `${basename}.${language.id}.isl`; + const encoded = iconv.encode(Buffer.from(content.join('\r\n'), 'utf8').toString(), innoSetup.codePage); + return new File({ + path: filePath, + contents: Buffer.from(encoded), + }); } function encodeEntities(value) { - let result = []; - for (let i = 0; i < value.length; i++) { - let ch = value[i]; - switch (ch) { - case '<': - result.push('<'); - break; - case '>': - result.push('>'); - break; - case '&': - result.push('&'); - break; - default: - result.push(ch); - } - } - return result.join(''); + let result = []; + for (let i = 0; i < value.length; i++) { + let ch = value[i]; + switch (ch) { + case '<': + result.push('<'); + break; + case '>': + result.push('>'); + break; + case '&': + result.push('&'); + break; + default: + result.push(ch); + } + } + return result.join(''); } function decodeEntities(value) { - return value.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); + return value.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); } function pseudify(message) { - return '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D'; + return '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D'; } diff --git a/build/lib/layersChecker.js b/build/lib/layersChecker.js index 3b9bd6fb9f476..147d038f50b88 100644 --- a/build/lib/layersChecker.js +++ b/build/lib/layersChecker.js @@ -199,7 +199,7 @@ const RULES = [ ] } ]; -const TS_CONFIG_PATH = (0, path_1.join)(__dirname, '../../', 'src', 'tsconfig.json'); +const TS_CONFIG_PATH = path_1.join(__dirname, '../../', 'src', 'tsconfig.json'); let hasErrors = false; function checkFile(program, sourceFile, rule) { checkNode(sourceFile); @@ -250,8 +250,8 @@ function checkFile(program, sourceFile, rule) { } function createProgram(tsconfigPath) { const tsConfig = ts.readConfigFile(tsconfigPath, ts.sys.readFile); - const configHostParser = { fileExists: fs_1.existsSync, readDirectory: ts.sys.readDirectory, readFile: file => (0, fs_1.readFileSync)(file, 'utf8'), useCaseSensitiveFileNames: process.platform === 'linux' }; - const tsConfigParsed = ts.parseJsonConfigFileContent(tsConfig.config, configHostParser, (0, path_1.resolve)((0, path_1.dirname)(tsconfigPath)), { noEmit: true }); + const configHostParser = { fileExists: fs_1.existsSync, readDirectory: ts.sys.readDirectory, readFile: file => fs_1.readFileSync(file, 'utf8'), useCaseSensitiveFileNames: process.platform === 'linux' }; + const tsConfigParsed = ts.parseJsonConfigFileContent(tsConfig.config, configHostParser, path_1.resolve(path_1.dirname(tsconfigPath)), { noEmit: true }); const compilerHost = ts.createCompilerHost(tsConfigParsed.options, true); return ts.createProgram(tsConfigParsed.fileNames, tsConfigParsed.options, compilerHost); } @@ -261,7 +261,7 @@ function createProgram(tsconfigPath) { const program = createProgram(TS_CONFIG_PATH); for (const sourceFile of program.getSourceFiles()) { for (const rule of RULES) { - if ((0, minimatch_1.match)([sourceFile.fileName], rule.target).length > 0) { + if (minimatch_1.match([sourceFile.fileName], rule.target).length > 0) { if (!rule.skip) { checkFile(program, sourceFile, rule); } diff --git a/build/lib/nls.js b/build/lib/nls.js index 8930b31e96c31..671a0afed438a 100644 --- a/build/lib/nls.js +++ b/build/lib/nls.js @@ -53,8 +53,8 @@ define([], [${wrap + lines.map(l => indent + l).join(',\n') + wrap}]);`; * Returns a stream containing the patched JavaScript and source maps. */ function nls() { - const input = (0, event_stream_1.through)(); - const output = input.pipe((0, event_stream_1.through)(function (f) { + const input = event_stream_1.through(); + const output = input.pipe(event_stream_1.through(function (f) { if (!f.sourceMap) { return this.emit('error', new Error(`File ${f.relative} does not have sourcemaps.`)); } @@ -72,7 +72,7 @@ function nls() { } _nls.patchFiles(f, typescript).forEach(f => this.emit('data', f)); })); - return (0, event_stream_1.duplex)(input, output); + return event_stream_1.duplex(input, output); } exports.nls = nls; function isImportNode(ts, node) { diff --git a/build/lib/optimize.js b/build/lib/optimize.js index 46ac035ae2046..762a1ac2b4f1d 100644 --- a/build/lib/optimize.js +++ b/build/lib/optimize.js @@ -96,7 +96,7 @@ function toConcatStream(src, bundledFileHeader, sources, dest, fileContentMapper return es.readArray(treatedSources) .pipe(useSourcemaps ? util.loadSourcemaps() : es.through()) .pipe(concat(dest)) - .pipe((0, stats_1.createStatsStream)(dest)); + .pipe(stats_1.createStatsStream(dest)); } function toBundleStream(src, bundledFileHeader, bundles, fileContentMapper) { return es.merge(bundles.map(function (bundle) { @@ -153,7 +153,7 @@ function optimizeTask(opts) { addComment: true, includeContent: true })) - .pipe(opts.languages && opts.languages.length ? (0, i18n_1.processNlsFiles)({ + .pipe(opts.languages && opts.languages.length ? i18n_1.processNlsFiles({ fileHeader: bundledFileHeader, languages: opts.languages }) : es.through()) diff --git a/build/lib/preLaunch.js b/build/lib/preLaunch.js index b1ecd53b5d906..1aecbe190487e 100644 --- a/build/lib/preLaunch.js +++ b/build/lib/preLaunch.js @@ -12,7 +12,7 @@ const yarn = process.platform === 'win32' ? 'yarn.cmd' : 'yarn'; const rootDir = path.resolve(__dirname, '..', '..'); function runProcess(command, args = []) { return new Promise((resolve, reject) => { - const child = (0, child_process_1.spawn)(command, args, { cwd: rootDir, stdio: 'inherit', env: process.env }); + const child = child_process_1.spawn(command, args, { cwd: rootDir, stdio: 'inherit', env: process.env }); child.on('exit', err => !err ? resolve() : process.exit(err !== null && err !== void 0 ? err : 1)); child.on('error', reject); }); diff --git a/build/lib/treeshaking.js b/build/lib/treeshaking.js index 55e7afc6aac2e..41cb33809b04d 100644 --- a/build/lib/treeshaking.js +++ b/build/lib/treeshaking.js @@ -477,9 +477,6 @@ function markNodes(ts, languageService, options) { } } function nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol) { - if (!symbol.declarations) { - return false; - } for (let i = 0, len = symbol.declarations.length; i < len; i++) { const declaration = symbol.declarations[i]; const declarationSourceFile = declaration.getSourceFile(); diff --git a/extensions/gitpod/src/extension.ts b/extensions/gitpod/src/extension.ts index 22409c8838fc9..cd873ddd06f2c 100644 --- a/extensions/gitpod/src/extension.ts +++ b/extensions/gitpod/src/extension.ts @@ -197,12 +197,8 @@ export async function activate(context: vscode.ExtensionContext) { await vscode.window.showErrorMessage(`Cannot capture workspace snapshot: ${err.toString()}`); } })); - const communityStatusBarItem = vscode.window.createStatusBarItem({ - id: 'gitpod.community', - name: 'Chat with us on Discourse', - alignment: vscode.StatusBarAlignment.Right, - priority: -100 - }); + const communityStatusBarItem = vscode.window.createStatusBarItem('gitpod.community', vscode.StatusBarAlignment.Right, -100); + communityStatusBarItem.name = 'Chat with us on Discourse'; context.subscriptions.push(communityStatusBarItem); communityStatusBarItem.text = '$(comment-discussion)'; communityStatusBarItem.tooltip = 'Chat with us on Discourse'; @@ -216,12 +212,8 @@ export async function activate(context: vscode.ExtensionContext) { } const listener = await pendingInstanceListener; - const extendTimeoutStatusBarItem = vscode.window.createStatusBarItem({ - id: 'gitpod.extendTimeout', - name: 'Click to extend the workspace timeout.', - alignment: vscode.StatusBarAlignment.Right, - priority: -100 - }); + const extendTimeoutStatusBarItem = vscode.window.createStatusBarItem('gitpod.extendTimeout', vscode.StatusBarAlignment.Right, -100); + extendTimeoutStatusBarItem.name = 'Click to extend the workspace timeout.'; context.subscriptions.push(extendTimeoutStatusBarItem); extendTimeoutStatusBarItem.text = '$(watch)'; extendTimeoutStatusBarItem.command = 'gitpod.ExtendTimeout'; @@ -676,7 +668,7 @@ export async function activate(context: vscode.ExtensionContext) { accessToken: data.accessToken }; } - function hasScopes(session: vscode.AuthenticationSession, scopes?: string[]): boolean { + function hasScopes(session: vscode.AuthenticationSession, scopes?: readonly string[]): boolean { return !scopes || scopes.every(scope => session.scopes.indexOf(scope) !== -1); } //#endregion @@ -773,7 +765,7 @@ export async function activate(context: vscode.ExtensionContext) { }; } - async function loginGitHub(scopes?: string[]): Promise { + async function loginGitHub(scopes?: readonly string[]): Promise { const getTokenRequest = new GetTokenRequest(); getTokenRequest.setKind('git'); getTokenRequest.setHost('github.com'); diff --git a/package.json b/package.json index 4e6e37f52908c..10c087a795c9c 100644 --- a/package.json +++ b/package.json @@ -57,8 +57,8 @@ "extensions-ci": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js extensions-ci" }, "dependencies": { - "@gitpod/local-app-api-grpcweb": "ak-vscode-tunnel-provider", - "@gitpod/supervisor-api-grpc": "main", + "@gitpod/local-app-api-grpcweb": "main", + "@gitpod/supervisor-api-grpc": "ak-vscode-update", "applicationinsights": "1.0.8", "chokidar": "3.5.1", "graceful-fs": "4.2.6", diff --git a/remote/package.json b/remote/package.json index 5c78160cacd82..a140f26d6fa2e 100644 --- a/remote/package.json +++ b/remote/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "dependencies": { - "@gitpod/supervisor-api-grpc": "main", + "@gitpod/supervisor-api-grpc": "ak-vscode-update", "applicationinsights": "1.0.8", "chokidar": "3.5.1", "cookie": "^0.4.0", diff --git a/remote/web/package.json b/remote/web/package.json index 510ef706bee25..b9c5705b656c1 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "dependencies": { - "@gitpod/local-app-api-grpcweb": "ak-vscode-tunnel-provider", + "@gitpod/local-app-api-grpcweb": "main", "iconv-lite-umd": "0.6.8", "jschardet": "3.0.0", "tas-client-umd": "0.1.4", diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 270bc1c2a76da..9acba318831af 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -2,19 +2,19 @@ # yarn lockfile v1 -"@gitpod/local-app-api-grpcweb@ak-vscode-tunnel-provider": - version "0.1.5-ak-vscode-tunnel-provider.26" - resolved "https://registry.yarnpkg.com/@gitpod/local-app-api-grpcweb/-/local-app-api-grpcweb-0.1.5-ak-vscode-tunnel-provider.26.tgz#16c4b8561f348a4279324ba586f6231fedd762f5" - integrity sha512-Ng8KcIb0sv5vrOwmjsqeuLCw8TCiU0H/misLdUHxgyJI+gPa01Thfmu42fIF7XWGAqnycg+bkzgu07oN7yQOsg== +"@gitpod/local-app-api-grpcweb@main": + version "0.1.5-main.943" + resolved "https://registry.yarnpkg.com/@gitpod/local-app-api-grpcweb/-/local-app-api-grpcweb-0.1.5-main.943.tgz#37d08d3d4336f86f816f2c1fc5503a5a4142e1e2" + integrity sha512-NJE0MXA0tZSUm5pl89OU14dm7qmuws65H4ci/VemiMcYQfB2Zh/CYqOwvb1dpp1RFd8zP03gptwWxesNxQzbEw== dependencies: - "@gitpod/supervisor-api-grpcweb" "0.1.5-ak-vscode-tunnel-provider.26" + "@gitpod/supervisor-api-grpcweb" "0.1.5-main.943" "@improbable-eng/grpc-web" "0.14.0" google-protobuf "^3.17.0" -"@gitpod/supervisor-api-grpcweb@0.1.5-ak-vscode-tunnel-provider.26": - version "0.1.5-ak-vscode-tunnel-provider.26" - resolved "https://registry.yarnpkg.com/@gitpod/supervisor-api-grpcweb/-/supervisor-api-grpcweb-0.1.5-ak-vscode-tunnel-provider.26.tgz#c7103afd3a90bda7f5117eb5be6e410a98645d23" - integrity sha512-CbvXviDOavaLquMW180f+gWTPP0R42gKqif7iPGsmtV+Yt2Py56LnpMmbi/BjmbuAY9KCHae3dwXRwroY4nF1A== +"@gitpod/supervisor-api-grpcweb@0.1.5-main.943": + version "0.1.5-main.943" + resolved "https://registry.yarnpkg.com/@gitpod/supervisor-api-grpcweb/-/supervisor-api-grpcweb-0.1.5-main.943.tgz#be7091e6b0c105f3143ac948784a6f955f8aa450" + integrity sha512-5P9u9FHb1Hn7gh9piyfmyR15JPFWU7FhsrPJ32VVyit8qnYEdkrnYALefTsKqdBIHrKc7bbPO23tIHxpzLO6UQ== "@improbable-eng/grpc-web@0.14.0": version "0.14.0" diff --git a/remote/yarn.lock b/remote/yarn.lock index e96b7ee161388..b71dbe46d3ef6 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@gitpod/supervisor-api-grpc@main": - version "0.1.5-main.828" - resolved "https://registry.yarnpkg.com/@gitpod/supervisor-api-grpc/-/supervisor-api-grpc-0.1.5-main.828.tgz#91925ed01584859a275a7f9e226565f6a3d4d06a" - integrity sha512-I1m5+YjFEsWJ1ZEKv2kRHm67OWEKa04gWv0uocyihOw3eteVFXWiJeQCUp02/pPecM7oE3KYoM8FNw6poKbzjg== +"@gitpod/supervisor-api-grpc@ak-vscode-update": + version "0.1.5-ak-vscode-update.2" + resolved "https://registry.yarnpkg.com/@gitpod/supervisor-api-grpc/-/supervisor-api-grpc-0.1.5-ak-vscode-update.2.tgz#461669b9d886268bd3efbed346bdb93d1f413289" + integrity sha512-QiZmNCnn32Gc4c9YJeDwJQ9Qz4JkkKQUwG5XZWYwwCNPqbdo/Of3H/Gn+DVFFbaHsIb9Kd547ItyyORccx+pcQ== dependencies: "@grpc/grpc-js" "^1.1.5" google-protobuf "^3.15.8" @@ -316,6 +316,33 @@ glob-parent@~5.1.0: dependencies: is-glob "^4.0.1" +google-auth-library@^6.1.1: + version "6.1.6" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-6.1.6.tgz#deacdcdb883d9ed6bac78bb5d79a078877fdf572" + integrity sha512-Q+ZjUEvLQj/lrVHF/IQwRo6p3s8Nc44Zk/DALsN+ac3T4HY/g/3rrufkgtl+nZ1TW7DNAw5cTChdVp4apUXVgQ== + dependencies: + arrify "^2.0.0" + base64-js "^1.3.0" + ecdsa-sig-formatter "^1.0.11" + fast-text-encoding "^1.0.0" + gaxios "^4.0.0" + gcp-metadata "^4.2.0" + gtoken "^5.0.4" + jws "^4.0.0" + lru-cache "^6.0.0" + +google-p12-pem@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-3.1.0.tgz#a1421b432fcc926812e3835289807170768a9885" + integrity sha512-JUtEHXL4DY/N+xhlm7TC3qL797RPAtk0ZGXNs3/gWyiDHYoA/8Rjes0pztkda+sZv4ej1EoO2KhWgW5V9KTrSQ== + dependencies: + node-forge "^0.10.0" + +google-protobuf@^3.15.8: + version "3.17.3" + resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.17.3.tgz#f87595073545a77946c8f0b67c302c5f7646d700" + integrity sha512-OVPzcSWIAJ+d5yiHyeaLrdufQtrvaBrF4JQg+z8ynTkbO3uFcujqXszTumqg1cGsAsjkWnI+M5B1xZ19yR4Wyg== + graceful-fs@4.2.6, graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.6" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" @@ -410,23 +437,6 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - -jschardet@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.0.0.tgz#898d2332e45ebabbdb6bf2feece9feea9a99e882" - integrity sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ== - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - is-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" @@ -445,10 +455,10 @@ js-yaml@^3.10.0: argparse "^1.0.7" esprima "^4.0.0" -jschardet@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.3.0.tgz#06e2636e16c8ada36feebbdc08aa34e6a9b3ff75" - integrity sha512-6I6xT7XN/7sBB7q8ObzKbmv5vN+blzLcboDE1BNEsEfmRXJValMxO6OIRT69ylPBRemS3rw6US+CMCar0OBc9g== +jschardet@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.0.0.tgz#898d2332e45ebabbdb6bf2feece9feea9a99e882" + integrity sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ== json-bigint@^1.0.0: version "1.0.0" @@ -525,6 +535,21 @@ node-addon-api@*: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239" integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw== +node-addon-api@^3.0.2: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + +node-fetch@^2.3.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + +node-forge@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" + integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== + node-pty@0.11.0-beta7: version "0.11.0-beta7" resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.11.0-beta7.tgz#aed0888b5032d96c54d8473455e6adfae3bbebbe" diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 0d7d376e2249e..2f0549c074f0e 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -1210,9 +1210,13 @@ export function windowOpenNoOpener(url: string): void { * See https://mathiasbynens.github.io/rel-noopener/ */ export function windowOpenNoOpenerWithSuccess(url: string): boolean { - // see https://github.com/gitpod-io/gitpod/issues/4266 - window.open(url, '_blank', 'noopener'); - return true; + const newTab = window.open(); + if (newTab) { + newTab.close(); + window.open(url, '_blank', 'noopener'); + return true; + } + return false; } export function animate(fn: () => void): IDisposable { diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts index 75328b2cf6bf9..d4a5a927acecd 100644 --- a/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts @@ -265,8 +265,7 @@ async function doStart(): Promise { return Disposable.None; } - const remotePort = location.protocol === 'https:' ? '443' : '80'; - const remoteAuthority = window.location.host + ':' + remotePort; + const remoteAuthority = window.location.host; const webWorkerExtensionHostEndpoint = new URL(document.baseURI); webWorkerExtensionHostEndpoint.host = 'extensions-' + webWorkerExtensionHostEndpoint.host; @@ -612,9 +611,11 @@ async function doStart(): Promise { webviewEndpoint: webviewEndpoint.toString(), webSocketFactory: { create: url => { + if (_state as any === 'terminated') { + throw new RemoteAuthorityResolverError('workspace stopped', RemoteAuthorityResolverErrorCode.NotAvailable); + } const codeServerUrl = new URL(url); codeServerUrl.protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; - codeServerUrl.port = remotePort; const socket = defaultWebSocketFactory.create(codeServerUrl.toString()); const onError = new Emitter(); socket.onError(e => { @@ -645,6 +646,14 @@ async function doStart(): Promise { } }, workspaceProvider, + resourceUriProvider: uri => { + return URI.from({ + scheme: 'https', + authority: remoteAuthority, + path: `/vscode-remote-resource`, + query: `path=${encodeURIComponent(uri.path)}` + }); + }, resolveExternalUri: async (uri) => { const localhost = extractLocalHostUriMetaDataForPortMapping(uri); if (!localhost) { diff --git a/src/vs/gitpod/node/remoteTerminalChannelServer.ts b/src/vs/gitpod/node/remoteTerminalChannelServer.ts index 02d337ee8f750..3071c4b0305ba 100644 --- a/src/vs/gitpod/node/remoteTerminalChannelServer.ts +++ b/src/vs/gitpod/node/remoteTerminalChannelServer.ts @@ -3,7 +3,7 @@ *--------------------------------------------------------------------------------------------*/ import { TaskStatus } from '@gitpod/supervisor-api-grpc/lib/status_pb'; -import { ListTerminalsRequest } from '@gitpod/supervisor-api-grpc/lib/terminal_pb'; +import { ListTerminalsRequest, TerminalTitleSource } from '@gitpod/supervisor-api-grpc/lib/terminal_pb'; import * as os from 'os'; import * as path from 'path'; import * as util from 'util'; @@ -17,11 +17,13 @@ import { getSystemShellSync } from 'vs/base/node/shell'; import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { supervisorDeadlines, supervisorMetadata, terminalServiceClient } from 'vs/gitpod/node/supervisor-client'; import { OpenSupervisorTerminalProcessOptions, SupervisorTerminalProcess } from 'vs/gitpod/node/supervisorTerminalProcess'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; import product from 'vs/platform/product/common/product'; import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment'; -import { IProcessDataEvent, IRawTerminalTabLayoutInfo, IShellLaunchConfig, ITerminalLaunchError, ITerminalsLayoutInfo, ITerminalTabLayoutInfoById } from 'vs/platform/terminal/common/terminal'; +import { IProcessDataEvent, IRawTerminalTabLayoutInfo, IRequestResolveVariablesEvent, IShellLaunchConfig, ITerminalLaunchError, ITerminalsLayoutInfo, ITerminalTabLayoutInfoById, TerminalIcon, TitleEventSource } from 'vs/platform/terminal/common/terminal'; import { IGetTerminalLayoutInfoArgs, IPtyHostProcessReplayEvent, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess'; +import { detectAvailableProfiles } from 'vs/platform/terminal/node/terminalProfiles'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable'; import { MergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableCollection'; @@ -29,7 +31,6 @@ import { deserializeEnvironmentVariableCollection } from 'vs/workbench/contrib/t import { ICreateTerminalProcessArguments, ICreateTerminalProcessResult, IWorkspaceFolderData } from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel'; import { IRemoteTerminalAttachTarget } from 'vs/workbench/contrib/terminal/common/terminal'; import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment'; import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver'; type TerminalOpenMode = 'split-top' | 'split-left' | 'split-right' | 'split-bottom' | 'tab-before' | 'tab-after'; @@ -125,10 +126,13 @@ export class RemoteTerminalChannelServer implements IServerChannel(); readonly onProcessTitleChanged = this._onProcessTitleChanged.event; + private readonly _onPtyHostRequestResolveVariables = new Emitter(); + readonly onPtyHostRequestResolveVariables = this._onPtyHostRequestResolveVariables.event; constructor( private rawURITransformerFactory: (remoteAuthority: string) => IRawURITransformer, - private logService: ILogService, + private readonly logService: ILogService, + private readonly configurationService: IConfigurationService, private synchingTasks: Promise> ) { } @@ -179,12 +183,24 @@ export class RemoteTerminalChannelServer implements IServerChannel void> = new Map(); + private _resolveVariables(text: string[]): Promise { + return new Promise(resolve => { + const id = ++this.lastResolveVariablesRequestId; + this._pendingResolveVariablesRequests.set(id, resolve); + this._onPtyHostRequestResolveVariables.fire({ id, originalText: text }); + }); + } + async acceptPtyHostResolvedVariables(id: number, resolved: string[]) { + const request = this._pendingResolveVariablesRequests.get(id); + if (request) { + request(resolved); + this._pendingResolveVariablesRequests.delete(id); + } else { + this.logService.warn(`Resolved variables received without matching request ${id}`); + } + } + private async createProcess(ctx: RemoteAgentConnectionContext, arg: any): Promise { const uriTranformer = new URITransformer(this.rawURITransformerFactory(ctx.remoteAuthority)); const args = transformIncomingURIs(arg as ICreateTerminalProcessArguments, uriTranformer); @@ -413,7 +461,7 @@ export class RemoteTerminalChannelServer implements IServerChannel { // see scanSingleExtension in src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts // TODO: read built nls file const translations = {}; - const input = new ExtensionScannerInput(product.version, product.commit, args.language, devMode, URI.revive(args.extensionLocation).fsPath, args.isBuiltin, false, translations); + const input = new ExtensionScannerInput(product.version, product.date, product.commit, args.language, devMode, URI.revive(args.extensionLocation).fsPath, args.isBuiltin, false, translations); const extension = await ExtensionScanner.scanSingleExtension(input, logService); if (!extension) { return undefined; @@ -404,10 +404,10 @@ async function main(): Promise { // see _scanInstalledExtensions in src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts // TODO: read built nls file const translations = {}; - let pendingSystem = ExtensionScanner.scanExtensions(new ExtensionScannerInput(product.version, product.commit, args.language, devMode, systemExtensionRoot, true, false, translations), logger); + let pendingSystem = ExtensionScanner.scanExtensions(new ExtensionScannerInput(product.version, product.date, product.commit, args.language, devMode, systemExtensionRoot, true, false, translations), logger); const builtInExtensions = product.builtInExtensions; if (devMode && builtInExtensions && builtInExtensions.length) { - pendingSystem = ExtensionScanner.mergeBuiltinExtensions(pendingSystem, ExtensionScanner.scanExtensions(new ExtensionScannerInput(product.version, product.commit, args.language, devMode, extraDevSystemExtensionsRoot, true, false, translations), logger, { + pendingSystem = ExtensionScanner.mergeBuiltinExtensions(pendingSystem, ExtensionScanner.scanExtensions(new ExtensionScannerInput(product.version, product.date, product.commit, args.language, devMode, extraDevSystemExtensionsRoot, true, false, translations), logger, { resolveExtensions: () => { const result: IExtensionReference[] = []; for (const extension of builtInExtensions) { @@ -417,10 +417,10 @@ async function main(): Promise { } })); } - const pendingUser = extensionsInstalled.then(() => ExtensionScanner.scanExtensions(new ExtensionScannerInput(product.version, product.commit, args.language, devMode, environmentService.extensionsPath, false, false, translations), logger)); + const pendingUser = extensionsInstalled.then(() => ExtensionScanner.scanExtensions(new ExtensionScannerInput(product.version, product.date, product.commit, args.language, devMode, environmentService.extensionsPath, false, false, translations), logger)); let pendingDev: Promise[] = []; if (args.extensionDevelopmentPath) { - pendingDev = args.extensionDevelopmentPath.map(devPath => ExtensionScanner.scanOneOrMultipleExtensions(new ExtensionScannerInput(product.version, product.commit, args.language, devMode, URI.revive(devPath).fsPath, false, true, translations), logger)); + pendingDev = args.extensionDevelopmentPath.map(devPath => ExtensionScanner.scanOneOrMultipleExtensions(new ExtensionScannerInput(product.version, product.date, product.commit, args.language, devMode, URI.revive(devPath).fsPath, false, true, translations), logger)); } const result: IExtensionDescription[] = []; const skipExtensions = new Set(args.skipExtensions.map(ExtensionIdentifier.toKey)); @@ -483,12 +483,6 @@ async function main(): Promise { return tasks; })(); - channelServer.registerChannel('remoteterminal', new RemoteTerminalChannelServer( - rawURITransformerFactory, - logService, - synchingTasks - )); - // see used APIs in src/vs/workbench/services/remote/common/remoteAgentFileSystemChannel.ts class RemoteFileSystem implements IServerChannel { protected readonly watchers = new Map { // Startup const instantiationService = new InstantiationService(services); instantiationService.invokeFunction(accessor => { + channelServer.registerChannel('remoteterminal', new RemoteTerminalChannelServer( + rawURITransformerFactory, + logService, + accessor.get(IConfigurationService), + synchingTasks + )); + const extensionManagementService = accessor.get(IExtensionManagementService); channelServer.registerChannel('extensions', new ExtensionManagementChannel(extensionManagementService, requestContext => new URITransformer(rawURITransformerFactory(requestContext)))); installInitialExtensions( @@ -701,9 +702,6 @@ async function main(): Promise { //#region headless if (pathname === '/vscode-remote-resource') { - if (parsedUrl.query['tkn'] !== connectionToken) { - return serveError(req, res, 403, 'Forbidden.'); - } const filePath = parsedUrl.query['path']; const fsPath = typeof filePath === 'string' && URI.from({ scheme: 'file', path: filePath }).fsPath; if (!fsPath) { diff --git a/src/vs/gitpod/node/supervisorTerminalProcess.ts b/src/vs/gitpod/node/supervisorTerminalProcess.ts index f3fc95ccb16a4..9eb04c5852b81 100644 --- a/src/vs/gitpod/node/supervisorTerminalProcess.ts +++ b/src/vs/gitpod/node/supervisorTerminalProcess.ts @@ -2,7 +2,7 @@ * Copyright (c) Typefox. All rights reserved. *--------------------------------------------------------------------------------------------*/ -import { GetTerminalRequest, ListenTerminalRequest, ListenTerminalResponse, OpenTerminalRequest, SetTerminalSizeRequest, ShutdownTerminalRequest, Terminal, TerminalSize, WriteTerminalRequest } from '@gitpod/supervisor-api-grpc/lib/terminal_pb'; +import { GetTerminalRequest, ListenTerminalRequest, ListenTerminalResponse, OpenTerminalRequest, SetTerminalSizeRequest, SetTerminalTitleRequest, ShutdownTerminalRequest, Terminal, TerminalSize, UpdateTerminalAnnotationsRequest, WriteTerminalRequest } from '@gitpod/supervisor-api-grpc/lib/terminal_pb'; import { status } from '@grpc/grpc-js'; import * as util from 'util'; import { Emitter, Event } from 'vs/base/common/event'; @@ -10,7 +10,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import * as platform from 'vs/base/common/platform'; import { supervisorDeadlines, supervisorMetadata, terminalServiceClient } from 'vs/gitpod/node/supervisor-client'; import { ILogService } from 'vs/platform/log/common/log'; -import { ITerminalChildProcess, ITerminalLaunchError, TerminalShellType } from 'vs/platform/terminal/common/terminal'; +import { ITerminalChildProcess, ITerminalLaunchError, TerminalIcon, TerminalShellType } from 'vs/platform/terminal/common/terminal'; import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering'; import { IPtyHostProcessReplayEvent } from 'vs/platform/terminal/common/terminalProcess'; import { TerminalRecorder } from 'vs/platform/terminal/common/terminalRecorder'; @@ -30,9 +30,9 @@ export class SupervisorTerminalProcess extends DisposableStore implements ITermi private exitCode: number | undefined; private closeTimeout: any; - syncState: Terminal.AsObject | undefined; + syncState: Terminal | undefined; get alias(): string | undefined { - return this.syncState?.alias; + return this.syncState?.getAlias(); } private readonly _recorder = new TerminalRecorder(0, 0); @@ -85,8 +85,8 @@ export class SupervisorTerminalProcess extends DisposableStore implements ITermi async start(): Promise { if (this.syncState) { - this._onProcessReady.fire({ pid: this.syncState.pid, cwd: this.syncState.currentWorkdir }); - this._onProcessTitleChanged.fire(this.syncState.title); + this._onProcessReady.fire({ pid: this.syncState.getPid(), cwd: this.syncState.getCurrentWorkdir() }); + this._onProcessTitleChanged.fire(this.syncState.getTitle()); this.triggerReplay(); this.listen(); return undefined; @@ -112,7 +112,7 @@ export class SupervisorTerminalProcess extends DisposableStore implements ITermi const response = await util.promisify(terminalServiceClient.open.bind(terminalServiceClient, request, supervisorMetadata, { deadline: Date.now() + supervisorDeadlines.long }))(); - this.syncState = response.getTerminal()!.toObject(); + this.syncState = response.getTerminal(); this.initialCwd = response.getTerminal()!.getCurrentWorkdir() || response.getTerminal()!.getInitialWorkdir(); this._onProcessReady.fire({ pid: response.getTerminal()!.getPid(), cwd: this.initialCwd }); @@ -364,4 +364,39 @@ export class SupervisorTerminalProcess extends DisposableStore implements ITermi this._onProcessReplay.fire(event); } + setTitle(title: string): void { + if (this['_isDisposed'] || !this.alias) { + return; + } + + const request = new SetTerminalTitleRequest(); + request.setAlias(this.alias); + request.setTitle(title); + terminalServiceClient.setTitle(request, supervisorMetadata, { deadline: Date.now() + supervisorDeadlines.short }, e => { + if (e && e.code !== status.NOT_FOUND) { + this.logService.error(`code server: ${this.id}:${this.alias} terminal: rename failed:`, e); + } + }); + } + + setIcon(icon: TerminalIcon, color?: string): void { + if (this['_isDisposed'] || !this.alias) { + return; + } + + const request = new UpdateTerminalAnnotationsRequest(); + request.setAlias(this.alias); + request.getChangedMap().set('icon', JSON.stringify(icon)); + if (color === undefined) { + request.getDeletedList().push('color'); + } else { + request.getChangedMap().set('color', color); + } + terminalServiceClient.updateAnnotations(request, supervisorMetadata, { deadline: Date.now() + supervisorDeadlines.short }, e => { + if (e && e.code !== status.NOT_FOUND) { + this.logService.error(`code server: ${this.id}:${this.alias} terminal: update icon failed:`, e); + } + }); + } + } diff --git a/src/vs/workbench/browser/window.ts b/src/vs/workbench/browser/window.ts index 05b9f806f35bf..6c6396a86d7ff 100644 --- a/src/vs/workbench/browser/window.ts +++ b/src/vs/workbench/browser/window.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { setFullscreen } from 'vs/base/browser/browser'; +import { isSafari, setFullscreen } from 'vs/base/browser/browser'; import { addDisposableListener, addDisposableThrottledListener, detectFullscreen, EventHelper, EventType, windowOpenNoOpenerWithSuccess, windowOpenNoOpener } from 'vs/base/browser/dom'; import { DomEmitter } from 'vs/base/browser/event'; import { timeout } from 'vs/base/common/async'; @@ -144,16 +144,20 @@ export class BrowserWindow extends Disposable { this.openerService.setDefaultExternalOpener({ openExternal: async (href: string) => { if (matchesScheme(href, Schemas.http) || matchesScheme(href, Schemas.https)) { - const opened = windowOpenNoOpenerWithSuccess(href); - if (!opened) { - const showResult = await this.dialogService.show(Severity.Warning, localize('unableToOpenExternal', "The browser interrupted the opening of a new tab or window. Press 'Open' to open it anyway."), - [localize('open', "Open"), localize('learnMore', "Learn More"), localize('cancel', "Cancel")], { cancelId: 2, detail: href }); - if (showResult.choice === 0) { - windowOpenNoOpener(href); - } - if (showResult.choice === 1) { - await this.openerService.open(URI.parse('https://aka.ms/allow-vscode-popup')); + if (isSafari) { + const opened = windowOpenNoOpenerWithSuccess(href); + if (!opened) { + const showResult = await this.dialogService.show(Severity.Warning, localize('unableToOpenExternal', "The browser interrupted the opening of a new tab or window. Press 'Open' to open it anyway."), + [localize('open', "Open"), localize('learnMore', "Learn More"), localize('cancel', "Cancel")], { cancelId: 2, detail: href }); + if (showResult.choice === 0) { + windowOpenNoOpener(href); + } + if (showResult.choice === 1) { + await this.openerService.open(URI.parse('https://aka.ms/allow-vscode-popup')); + } } + } else { + windowOpenNoOpener(href); } } else { this.lifecycleService.withExpectedUnload(() => window.location.href = href); diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js index 73555697d628b..6783684f433a8 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/main.js +++ b/src/vs/workbench/contrib/webview/browser/pre/main.js @@ -211,7 +211,9 @@ const workerReady = new Promise(async (resolve, reject) => { return reject(new Error('Service Workers are not enabled in browser. Webviews will not work.')); } - const swPath = `service-worker.js${self.location.search}`; + const swParams = new URLSearchParams(self.location.search); + const resourceBaseAuthority = swParams.get('vscode-resource-base-authority'); + const swPath = `service-worker.js?vscode-resource-base-authority=${encodeURIComponent(resourceBaseAuthority)}`; navigator.serviceWorker.register(swPath).then( async registration => { diff --git a/yarn.lock b/yarn.lock index d63194c39f731..40b28887de83c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -198,27 +198,27 @@ vscode-ws-jsonrpc "^0.2.0" ws "^5.2.2" -"@gitpod/local-app-api-grpcweb@ak-vscode-tunnel-provider": - version "0.1.5-ak-vscode-tunnel-provider.26" - resolved "https://registry.yarnpkg.com/@gitpod/local-app-api-grpcweb/-/local-app-api-grpcweb-0.1.5-ak-vscode-tunnel-provider.26.tgz#16c4b8561f348a4279324ba586f6231fedd762f5" - integrity sha512-Ng8KcIb0sv5vrOwmjsqeuLCw8TCiU0H/misLdUHxgyJI+gPa01Thfmu42fIF7XWGAqnycg+bkzgu07oN7yQOsg== +"@gitpod/local-app-api-grpcweb@main": + version "0.1.5-main.943" + resolved "https://registry.yarnpkg.com/@gitpod/local-app-api-grpcweb/-/local-app-api-grpcweb-0.1.5-main.943.tgz#37d08d3d4336f86f816f2c1fc5503a5a4142e1e2" + integrity sha512-NJE0MXA0tZSUm5pl89OU14dm7qmuws65H4ci/VemiMcYQfB2Zh/CYqOwvb1dpp1RFd8zP03gptwWxesNxQzbEw== dependencies: - "@gitpod/supervisor-api-grpcweb" "0.1.5-ak-vscode-tunnel-provider.26" + "@gitpod/supervisor-api-grpcweb" "0.1.5-main.943" "@improbable-eng/grpc-web" "0.14.0" google-protobuf "^3.17.0" -"@gitpod/supervisor-api-grpc@main": - version "0.1.5-main.836" - resolved "https://registry.yarnpkg.com/@gitpod/supervisor-api-grpc/-/supervisor-api-grpc-0.1.5-main.836.tgz#d346716136bf02a948eacbe2482dcfa0d4941b4f" - integrity sha512-kcJJzMsalQDjLTa6cKKejYeGRArqSaYFcyeGjO2BRn4+/iML9kTnP076BbjPtk5vFuVtLgetY8iFpn6kzuwNng== +"@gitpod/supervisor-api-grpc@ak-vscode-update": + version "0.1.5-ak-vscode-update.2" + resolved "https://registry.yarnpkg.com/@gitpod/supervisor-api-grpc/-/supervisor-api-grpc-0.1.5-ak-vscode-update.2.tgz#461669b9d886268bd3efbed346bdb93d1f413289" + integrity sha512-QiZmNCnn32Gc4c9YJeDwJQ9Qz4JkkKQUwG5XZWYwwCNPqbdo/Of3H/Gn+DVFFbaHsIb9Kd547ItyyORccx+pcQ== dependencies: "@grpc/grpc-js" "^1.1.5" google-protobuf "^3.15.8" -"@gitpod/supervisor-api-grpcweb@0.1.5-ak-vscode-tunnel-provider.26": - version "0.1.5-ak-vscode-tunnel-provider.26" - resolved "https://registry.yarnpkg.com/@gitpod/supervisor-api-grpcweb/-/supervisor-api-grpcweb-0.1.5-ak-vscode-tunnel-provider.26.tgz#c7103afd3a90bda7f5117eb5be6e410a98645d23" - integrity sha512-CbvXviDOavaLquMW180f+gWTPP0R42gKqif7iPGsmtV+Yt2Py56LnpMmbi/BjmbuAY9KCHae3dwXRwroY4nF1A== +"@gitpod/supervisor-api-grpcweb@0.1.5-main.943": + version "0.1.5-main.943" + resolved "https://registry.yarnpkg.com/@gitpod/supervisor-api-grpcweb/-/supervisor-api-grpcweb-0.1.5-main.943.tgz#be7091e6b0c105f3143ac948784a6f955f8aa450" + integrity sha512-5P9u9FHb1Hn7gh9piyfmyR15JPFWU7FhsrPJ32VVyit8qnYEdkrnYALefTsKqdBIHrKc7bbPO23tIHxpzLO6UQ== "@grpc/grpc-js@^1.1.5": version "1.3.2"