Merge branch 'main' into notebook-serialization-worker

This commit is contained in:
Aaron Munger
2024-09-11 14:27:43 -07:00
committed by GitHub
360 changed files with 9371 additions and 4280 deletions
+4 -1
View File
@@ -693,6 +693,7 @@
"when": "hasNode",
"allow": [
"@parcel/watcher",
"@bpasero/watcher",
"@vscode/sqlite3",
"@vscode/vscode-languagedetection",
"@vscode/ripgrep",
@@ -846,7 +847,8 @@
"vs/platform/*/~",
"vs/editor/~",
"vs/editor/contrib/*/~",
"vs/editor/standalone/~"
"vs/editor/standalone/~",
"@vscode/tree-sitter-wasm" // type import
]
},
{
@@ -932,6 +934,7 @@
"tas-client-umd", // node module allowed even in /common/
"vscode-textmate", // node module allowed even in /common/
"@vscode/vscode-languagedetection", // node module allowed even in /common/
"@vscode/tree-sitter-wasm", // type import
{
"when": "hasBrowser",
"pattern": "@xterm/xterm"
+5 -5
View File
@@ -124,7 +124,7 @@
"languages-basic": {"assign": ["aeschli"]},
"languages-diagnostics": {"assign": ["jrieken"]},
"languages-guessing": {"assign": ["TylerLeonhardt"]},
"layout": {"assign": ["sbatten"]},
"layout": {"assign": ["benibenj"]},
"lcd-text-rendering": {"assign": []},
"list-widget": {"assign": ["joaomoreno"]},
"live-preview": {"assign": ["andreamah"]},
@@ -249,7 +249,7 @@
"timeline": {"assign": ["lramos15"]},
"timeline-git": {"assign": ["lszomoru"]},
"timeline-local-history": {"assign": ["bpasero"]},
"titlebar": {"assign": ["sbatten"]},
"titlebar": {"assign": ["benibenj"]},
"tokenization": {"assign": ["alexdima"]},
"touch/pointer": {"assign": []},
"trackpad/scroll": {"assign": []},
@@ -278,7 +278,7 @@
"workbench-cli": {"assign": ["bpasero"]},
"workbench-diagnostics": {"assign": ["Tyriar"]},
"workbench-dnd": {"assign": ["bpasero"]},
"workbench-editor-grid": {"assign": ["sbatten"]},
"workbench-editor-grid": {"assign": ["benibenj"]},
"workbench-editor-groups": {"assign": ["bpasero"]},
"workbench-editor-resolver": {"assign": ["lramos15"]},
"workbench-editors": {"assign": ["bpasero"]},
@@ -299,11 +299,11 @@
"workbench-tabs": {"assign": ["benibenj"]},
"workbench-touchbar": {"assign": ["bpasero"]},
"workbench-untitled-editors": {"assign": ["bpasero"]},
"workbench-views": {"assign": ["sbatten"]},
"workbench-views": {"assign": ["benibenj"]},
"workbench-welcome": {"assign": ["lramos15"]},
"workbench-window": {"assign": ["bpasero"]},
"workbench-workspace": {"assign": []},
"workbench-zen": {"assign": ["sbatten"]},
"workbench-zen": {"assign": ["benibenj"]},
"workspace-edit": {"assign": ["jrieken"]},
"workspace-symbols": {"assign": []},
"workspace-trust": {"assign": ["lszomoru", "sbatten"]},
@@ -8,6 +8,7 @@ import * as vscode from 'vscode';
import { TestCase, TestConstruct, TestSuite, VSCodeTest } from './testTree';
const suiteNames = new Set(['suite', 'flakySuite']);
const testNames = new Set(['test']);
export const enum Action {
Skip,
@@ -19,22 +20,19 @@ export const extractTestFromNode = (src: ts.SourceFile, node: ts.Node, parent: V
return Action.Recurse;
}
let lhs = node.expression;
if (isSkipCall(lhs)) {
const asSuite = identifyCall(node.expression, suiteNames);
const asTest = identifyCall(node.expression, testNames);
const either = asSuite || asTest;
if (either === IdentifiedCall.Skipped) {
return Action.Skip;
}
if (isPropertyCall(lhs) && lhs.name.text === 'only') {
lhs = lhs.expression;
if (either === IdentifiedCall.Nothing) {
return Action.Recurse;
}
const name = node.arguments[0];
const func = node.arguments[1];
if (!name || !ts.isIdentifier(lhs) || !ts.isStringLiteralLike(name)) {
return Action.Recurse;
}
if (!func) {
if (!name || !ts.isStringLiteralLike(name) || !func) {
return Action.Recurse;
}
@@ -46,23 +44,45 @@ export const extractTestFromNode = (src: ts.SourceFile, node: ts.Node, parent: V
);
const cparent = parent instanceof TestConstruct ? parent : undefined;
if (lhs.escapedText === 'test') {
// we know this is either a suite or a test because we checked for skipped/nothing above
if (asTest) {
return new TestCase(name.text, range, cparent);
}
if (suiteNames.has(lhs.escapedText.toString())) {
if (asSuite) {
return new TestSuite(name.text, range, cparent);
}
return Action.Recurse;
throw new Error('unreachable');
};
const enum IdentifiedCall {
Nothing,
Skipped,
IsThing,
}
const identifyCall = (lhs: ts.Node, needles: ReadonlySet<string>): IdentifiedCall => {
if (ts.isIdentifier(lhs)) {
return needles.has(lhs.escapedText || lhs.text) ? IdentifiedCall.IsThing : IdentifiedCall.Nothing;
}
if (isPropertyCall(lhs) && lhs.name.text === 'skip') {
return needles.has(lhs.expression.text) ? IdentifiedCall.Skipped : IdentifiedCall.Nothing;
}
if (ts.isParenthesizedExpression(lhs) && ts.isConditionalExpression(lhs.expression)) {
return Math.max(identifyCall(lhs.expression.whenTrue, needles), identifyCall(lhs.expression.whenFalse, needles));
}
return IdentifiedCall.Nothing;
};
const isPropertyCall = (
lhs: ts.LeftHandSideExpression
lhs: ts.Node
): lhs is ts.PropertyAccessExpression & { expression: ts.Identifier; name: ts.Identifier } =>
ts.isPropertyAccessExpression(lhs) &&
ts.isIdentifier(lhs.expression) &&
ts.isIdentifier(lhs.name);
const isSkipCall = (lhs: ts.LeftHandSideExpression) =>
isPropertyCall(lhs) && suiteNames.has(lhs.expression.text) && lhs.name.text === 'skip';
+6
View File
@@ -110,6 +110,12 @@ node-pty/third_party/**
@parcel/watcher/src/**
!@parcel/watcher/build/Release/*.node
@bpasero/watcher/binding.gyp
@bpasero/watcher/build/**
@bpasero/watcher/prebuilds/**
@bpasero/watcher/src/**
!@bpasero/watcher/build/Release/*.node
vsda/build/**
vsda/ci/**
vsda/src/**
@@ -1,7 +1,7 @@
parameters:
- name: channel
type: string
default: 1.77
default: 1.81
- name: targets
default: []
type: object
@@ -1,7 +1,7 @@
parameters:
- name: channel
type: string
default: 1.77
default: 1.81
- name: targets
default: []
type: object
-5
View File
@@ -101,7 +101,6 @@ const tasks = compilations.map(function (tsconfigFile) {
}
function createPipeline(build, emitError, transpileOnly) {
const nlsDev = require('vscode-nls-dev');
const tsb = require('./lib/tsb');
const sourcemaps = require('gulp-sourcemaps');
@@ -126,7 +125,6 @@ const tasks = compilations.map(function (tsconfigFile) {
.pipe(tsFilter)
.pipe(util.loadSourcemaps())
.pipe(compilation())
.pipe(build ? nlsDev.rewriteLocalizeCalls() : es.through())
.pipe(build ? util.stripSourceMappingURL() : es.through())
.pipe(sourcemaps.write('.', {
sourceMappingURL: !build ? null : f => `${baseUrl}/${f.relative}.map`,
@@ -136,9 +134,6 @@ const tasks = compilations.map(function (tsconfigFile) {
sourceRoot: '../src/',
}))
.pipe(tsFilter.restore)
.pipe(build ? nlsDev.bundleMetaDataFiles(headerId, headerOut) : es.through())
// Filter out *.nls.json file. We needed them only to bundle meta data file.
.pipe(filter(['**', '!**/*.nls.json'], { dot: true }))
.pipe(reporter.end(emitError));
return es.duplex(input, output);
+2 -1
View File
@@ -83,7 +83,8 @@ function nodeModules(destinationExe, destinationPdb, platform) {
// We don't build the prebuilt node files so we don't scan them
'!**/prebuilds/**/*.node',
// These are 3rd party modules that we should ignore
'!**/@parcel/watcher/**/*']))
'!**/@parcel/watcher/**/*',
'!**/@bpasero/watcher/**/*']))
.pipe(gulp.dest(destinationExe));
};
+1 -2
View File
@@ -16,7 +16,6 @@ const pkg = require('../package.json');
const product = require('../product.json');
const vfs = require('vinyl-fs');
const rcedit = require('rcedit');
const mkdirp = require('mkdirp');
const repoPath = path.dirname(__dirname);
const buildPath = (/** @type {string} */ arch) => path.join(path.dirname(repoPath), `VSCode-win32-${arch}`);
@@ -75,7 +74,7 @@ function buildWin32Setup(arch, target) {
const sourcePath = buildPath(arch);
const outputPath = setupDir(arch, target);
mkdirp.sync(outputPath);
fs.mkdirSync(outputPath, { recursive: true });
const originalProductJsonPath = path.join(sourcePath, 'resources/app/product.json');
const productJsonPath = path.join(outputPath, 'product.json');
+1 -2
View File
@@ -16,7 +16,6 @@ const vfs = require("vinyl-fs");
const ext = require("./extensions");
const fancyLog = require("fancy-log");
const ansiColors = require("ansi-colors");
const mkdirp = require('mkdirp');
const root = path.dirname(path.dirname(__dirname));
const productjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8'));
const builtInExtensions = productjson.builtInExtensions || [];
@@ -107,7 +106,7 @@ function readControlFile() {
}
}
function writeControlFile(control) {
mkdirp.sync(path.dirname(controlFilePath));
fs.mkdirSync(path.dirname(controlFilePath), { recursive: true });
fs.writeFileSync(controlFilePath, JSON.stringify(control, null, 2));
}
function getBuiltInExtensions() {
+1 -3
View File
@@ -15,8 +15,6 @@ import * as fancyLog from 'fancy-log';
import * as ansiColors from 'ansi-colors';
import { Stream } from 'stream';
const mkdirp = require('mkdirp');
export interface IExtensionDefinition {
name: string;
version: string;
@@ -147,7 +145,7 @@ function readControlFile(): IControlFile {
}
function writeControlFile(control: IControlFile): void {
mkdirp.sync(path.dirname(controlFilePath));
fs.mkdirSync(path.dirname(controlFilePath), { recursive: true });
fs.writeFileSync(controlFilePath, JSON.stringify(control, null, 2));
}
+6 -1
View File
@@ -51,7 +51,12 @@ function extractEditor(options) {
// Add extra .d.ts files from `node_modules/@types/`
if (Array.isArray(options.compilerOptions?.types)) {
options.compilerOptions.types.forEach((type) => {
options.typings.push(`../node_modules/@types/${type}/index.d.ts`);
if (type === '@webgpu/types') {
options.typings.push(`../node_modules/${type}/dist/index.d.ts`);
}
else {
options.typings.push(`../node_modules/@types/${type}/index.d.ts`);
}
});
}
const result = tss.shake(options);
+5 -1
View File
@@ -59,7 +59,11 @@ export function extractEditor(options: tss.ITreeShakingOptions & { destRoot: str
// Add extra .d.ts files from `node_modules/@types/`
if (Array.isArray(options.compilerOptions?.types)) {
options.compilerOptions.types.forEach((type: string) => {
options.typings.push(`../node_modules/@types/${type}/index.d.ts`);
if (type === '@webgpu/types') {
options.typings.push(`../node_modules/${type}/dist/index.d.ts`);
} else {
options.typings.push(`../node_modules/@types/${type}/index.d.ts`);
}
});
}
@@ -546,9 +546,9 @@
"--vscode-scmGraph-foreground1",
"--vscode-scmGraph-foreground2",
"--vscode-scmGraph-foreground3",
"--vscode-scmGraph-historyItemGroupBase",
"--vscode-scmGraph-historyItemGroupLocal",
"--vscode-scmGraph-historyItemGroupRemote",
"--vscode-scmGraph-historyItemBaseRefColor",
"--vscode-scmGraph-historyItemRefColor",
"--vscode-scmGraph-historyItemRemoteRefColor",
"--vscode-scmGraph-historyItemHoverAdditionsForeground",
"--vscode-scmGraph-historyItemHoverDefaultLabelBackground",
"--vscode-scmGraph-historyItemHoverDefaultLabelForeground",
@@ -881,4 +881,4 @@
"--widget-color",
"--text-link-decoration"
]
}
}
+8 -52
View File
@@ -31,7 +31,6 @@
"@types/mime": "0.0.29",
"@types/minimatch": "^3.0.3",
"@types/minimist": "^1.2.1",
"@types/mkdirp": "^1.0.1",
"@types/mocha": "^9.1.1",
"@types/node": "20.x",
"@types/pump": "^1.0.1",
@@ -54,7 +53,6 @@
"gulp-sort": "^2.0.0",
"jsonc-parser": "^2.3.0",
"mime": "^1.4.1",
"mkdirp": "^1.0.4",
"source-map": "0.6.1",
"ternary-stream": "^3.0.0",
"through2": "^4.0.2",
@@ -133,9 +131,10 @@
}
},
"node_modules/@azure/core-http": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.0.tgz",
"integrity": "sha512-BxI2SlGFPPz6J1XyZNIVUf0QZLBKFX+ViFjKOkzqD18J1zOINIQ8JSBKKr+i+v8+MB6LacL6Nn/sP/TE13+s2Q==",
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.4.tgz",
"integrity": "sha512-Fok9VVhMdxAFOtqiiAtg74fL0UJkt0z3D+ouUUxcRLzZNBioPRAMJFVxiWoJljYpXsRi4GDQHzQHDc9AiYaIUQ==",
"deprecated": "deprecating as we migrated to core v2",
"dev": true,
"dependencies": {
"@azure/abort-controller": "^1.0.0",
@@ -151,7 +150,7 @@
"tslib": "^2.2.0",
"tunnel": "^0.0.6",
"uuid": "^8.3.0",
"xml2js": "^0.4.19"
"xml2js": "^0.5.0"
},
"engines": {
"node": ">=14.0.0"
@@ -1123,15 +1122,6 @@
"integrity": "sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==",
"dev": true
},
"node_modules/@types/mkdirp": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.1.tgz",
"integrity": "sha512-HkGSK7CGAXncr8Qn/0VqNtExEE+PHMWb+qlR1faHMao7ng6P3tAaoWWBMdva0gL5h4zprjIO89GJOLXsMcDm1Q==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/mocha": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz",
@@ -1372,28 +1362,6 @@
"node": ">=10"
}
},
"node_modules/@vscode/vsce/node_modules/xml2js": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
"dev": true,
"dependencies": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/@vscode/vsce/node_modules/xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
"dev": true,
"engines": {
"node": ">=4.0"
}
},
"node_modules/@xmldom/xmldom": {
"version": "0.8.10",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
@@ -3374,18 +3342,6 @@
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
"devOptional": true
},
"node_modules/mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"dev": true,
"bin": {
"mkdirp": "bin/cmd.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/mkdirp-classic": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
@@ -4594,9 +4550,9 @@
"devOptional": true
},
"node_modules/xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
"dev": true,
"dependencies": {
"sax": ">=0.6.0",
-2
View File
@@ -25,7 +25,6 @@
"@types/mime": "0.0.29",
"@types/minimatch": "^3.0.3",
"@types/minimist": "^1.2.1",
"@types/mkdirp": "^1.0.1",
"@types/mocha": "^9.1.1",
"@types/node": "20.x",
"@types/pump": "^1.0.1",
@@ -48,7 +47,6 @@
"gulp-sort": "^2.0.0",
"jsonc-parser": "^2.3.0",
"mime": "^1.4.1",
"mkdirp": "^1.0.4",
"source-map": "0.6.1",
"ternary-stream": "^3.0.0",
"through2": "^4.0.2",
-27
View File
@@ -241,33 +241,6 @@
"CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
]
},
{
// Reason: The substack org has been deleted on GH
"name": "mkdirp",
"fullLicenseText": [
"Copyright 2010 James Halliday (mail@substack.net)",
"",
"This project is free software released under the MIT/X11 license:",
"",
"Permission is hereby granted, free of charge, to any person obtaining a copy",
"of this software and associated documentation files (the \"Software\"), to deal",
"in the Software without restriction, including without limitation the rights",
"to use, copy, modify, merge, publish, distribute, sublicense, and/or sell",
"copies of the Software, and to permit persons to whom the Software is",
"furnished to do so, subject to the following conditions:",
"",
"The above copyright notice and this permission notice shall be included in",
"all copies or substantial portions of the Software.",
"",
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR",
"IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,",
"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE",
"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER",
"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,",
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN",
"THE SOFTWARE."
]
},
{
// Reason: repo URI is wrong on crate, pending https://github.com/warp-tech/russh/pull/53
"name": "russh-cryptovec",
+1
View File
@@ -81,4 +81,5 @@ codegen-units = 1
[features]
default = []
vsda = []
vscode-encrypt = []
+1 -1
View File
@@ -723,7 +723,7 @@ impl Auth {
match &init_code_json.message {
Some(m) => self.log.result(m),
None => self.log.result(&format!(
None => self.log.result(format!(
"To grant access to the server, please log into {} and use code {}",
init_code_json.verification_uri, init_code_json.user_code
)),
+60 -13
View File
@@ -15,7 +15,7 @@ use std::time::{Duration, Instant};
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server};
use tokio::io::{AsyncBufReadExt, BufReader};
use tokio::pin;
use tokio::{pin, time};
use crate::async_pipe::{
get_socket_name, get_socket_rw_stream, listen_socket_rw_stream, AsyncPipe,
@@ -50,7 +50,7 @@ const SERVER_IDLE_TIMEOUT_SECS: u64 = 60 * 60;
/// (should be large enough to basically never happen)
const SERVER_ACTIVE_TIMEOUT_SECS: u64 = SERVER_IDLE_TIMEOUT_SECS * 24 * 30 * 12;
/// How long to cache the "latest" version we get from the update service.
const RELEASE_CACHE_SECS: u64 = 60 * 60;
const RELEASE_CHECK_INTERVAL: u64 = 60 * 60;
/// Number of bytes for the secret keys. See workbench.ts for their usage.
const SECRET_KEY_BYTES: usize = 32;
@@ -86,7 +86,11 @@ pub async fn serve_web(ctx: CommandContext, mut args: ServeWebArgs) -> Result<i3
}
}
let cm = ConnectionManager::new(&ctx, platform, args.clone());
let cm: Arc<ConnectionManager> = ConnectionManager::new(&ctx, platform, args.clone());
let update_check_interval = 3600;
cm.clone()
.start_update_checker(Duration::from_secs(update_check_interval));
let key = get_server_key_half(&ctx.paths);
let make_svc = move || {
let ctx = HandleContext {
@@ -175,7 +179,7 @@ async fn handle_proxied(ctx: &HandleContext, req: Request<Body>) -> Response<Bod
let release = if let Some((r, _)) = get_release_from_path(req.uri().path(), ctx.cm.platform) {
r
} else {
match ctx.cm.get_latest_release().await {
match ctx.cm.get_release_from_cache().await {
Ok(r) => r,
Err(e) => {
error!(ctx.log, "error getting latest version: {}", e);
@@ -538,21 +542,67 @@ impl ConnectionManager {
pub fn new(ctx: &CommandContext, platform: Platform, args: ServeWebArgs) -> Arc<Self> {
let base_path = normalize_base_path(args.server_base_path.as_deref().unwrap_or_default());
let cache = DownloadCache::new(ctx.paths.web_server_storage());
let target_kind = TargetKind::Web;
let quality = VSCODE_CLI_QUALITY.map_or(Quality::Stable, |q| match Quality::try_from(q) {
Ok(q) => q,
Err(_) => Quality::Stable,
});
let latest_version = tokio::sync::Mutex::new(cache.get().first().map(|latest_commit| {
(
Instant::now() - Duration::from_secs(RELEASE_CHECK_INTERVAL),
Release {
name: String::from("0.0.0"), // Version information not stored on cache
commit: latest_commit.clone(),
platform,
target: target_kind,
quality,
},
)
}));
Arc::new(Self {
platform,
args,
base_path,
log: ctx.log.clone(),
cache: DownloadCache::new(ctx.paths.web_server_storage()),
cache,
update_service: UpdateService::new(
ctx.log.clone(),
Arc::new(ReqwestSimpleHttp::with_client(ctx.http.clone())),
),
state: ConnectionStateMap::default(),
latest_version: tokio::sync::Mutex::default(),
latest_version,
})
}
// spawns a task that checks for updates every n seconds duration
pub fn start_update_checker(self: Arc<Self>, duration: Duration) {
tokio::spawn(async move {
let mut interval = time::interval(duration);
loop {
interval.tick().await;
if let Err(e) = self.get_latest_release().await {
warning!(self.log, "error getting latest version: {}", e);
}
}
});
}
// Returns the latest release from the cache, if one exists.
pub async fn get_release_from_cache(&self) -> Result<Release, CodeError> {
let latest = self.latest_version.lock().await;
if let Some((_, release)) = &*latest {
return Ok(release.clone());
}
drop(latest);
self.get_latest_release().await
}
/// Gets a connection to a server version
pub async fn get_connection(
&self,
@@ -571,11 +621,7 @@ impl ConnectionManager {
pub async fn get_latest_release(&self) -> Result<Release, CodeError> {
let mut latest = self.latest_version.lock().await;
let now = Instant::now();
if let Some((checked_at, release)) = &*latest {
if checked_at.elapsed() < Duration::from_secs(RELEASE_CACHE_SECS) {
return Ok(release.clone());
}
}
let target_kind = TargetKind::Web;
let quality = VSCODE_CLI_QUALITY
.ok_or_else(|| CodeError::UpdatesNotConfigured("no configured quality"))
@@ -585,13 +631,14 @@ impl ConnectionManager {
let release = self
.update_service
.get_latest_commit(self.platform, TargetKind::Web, quality)
.get_latest_commit(self.platform, target_kind, quality)
.await
.map_err(|e| CodeError::UpdateCheckFailed(e.to_string()));
// If the update service is unavailable and we have stale data, use that
if let (Err(e), Some((_, previous))) = (&release, &*latest) {
if let (Err(e), Some((_, previous))) = (&release, latest.clone()) {
warning!(self.log, "error getting latest release, using stale: {}", e);
*latest = Some((now, previous.clone()));
return Ok(previous.clone());
}
+7 -1
View File
@@ -20,6 +20,7 @@ const KEEP_LRU: usize = 5;
const STAGING_SUFFIX: &str = ".staging";
const RENAME_ATTEMPTS: u32 = 20;
const RENAME_DELAY: std::time::Duration = std::time::Duration::from_millis(200);
const PERSISTED_STATE_FILE_NAME: &str = "lru.json";
#[derive(Clone)]
pub struct DownloadCache {
@@ -30,11 +31,16 @@ pub struct DownloadCache {
impl DownloadCache {
pub fn new(path: PathBuf) -> DownloadCache {
DownloadCache {
state: PersistedState::new(path.join("lru.json")),
state: PersistedState::new(path.join(PERSISTED_STATE_FILE_NAME)),
path,
}
}
/// Gets the value stored on the state
pub fn get(&self) -> Vec<String> {
self.state.load()
}
/// Gets the download cache path. Names of cache entries can be formed by
/// joining them to the path.
pub fn path(&self) -> &Path {
+1 -1
View File
@@ -674,7 +674,7 @@ where
let write_line = |line: &str| -> std::io::Result<()> {
if let Some(mut f) = log_file.as_ref() {
f.write_all(line.as_bytes())?;
f.write_all(&[b'\n'])?;
f.write_all(b"\n")?;
}
if write_directly {
println!("{}", line);
@@ -4,7 +4,6 @@ tsconfig.json
out/**
extension.webpack.config.js
extension-browser.webpack.config.js
yarn.lock
package-lock.json
build/**
schemas/devContainer.codespaces.schema.json
@@ -11,10 +11,8 @@ server/tsconfig.json
server/test/**
server/bin/**
server/build/**
server/yarn.lock
server/package-lock.json
server/.npmignore
yarn.lock
package-lock.json
server/extension.webpack.config.js
extension.webpack.config.js
@@ -2,5 +2,4 @@ src/**
tsconfig.json
out/**
extension.webpack.config.js
yarn.lock
package-lock.json
@@ -2,6 +2,5 @@ src/**
tsconfig.json
out/**
extension.webpack.config.js
yarn.lock
package-lock.json
.vscode
-1
View File
@@ -7,6 +7,5 @@ extension.webpack.config.js
extension-browser.webpack.config.js
CONTRIBUTING.md
cgmanifest.json
yarn.lock
package-lock.json
.vscode
@@ -4,5 +4,4 @@ tsconfig.json
out/**
extension.webpack.config.js
extension-browser.webpack.config.js
yarn.lock
package-lock.json
-1
View File
@@ -4,5 +4,4 @@ out/**
tsconfig.json
build/**
extension.webpack.config.js
yarn.lock
package-lock.json
+2 -2
View File
@@ -3059,7 +3059,7 @@ export class CommandCenter {
@command('git.fetchRef', { repository: true })
async fetchRef(repository: Repository, ref?: string): Promise<void> {
ref = ref ?? repository?.historyProvider.currentHistoryItemGroup?.remote?.id;
ref = ref ?? repository?.historyProvider.currentHistoryItemRemoteRef?.id;
if (!repository || !ref) {
return;
}
@@ -3132,7 +3132,7 @@ export class CommandCenter {
@command('git.pullRef', { repository: true })
async pullRef(repository: Repository, ref?: string): Promise<void> {
ref = ref ?? repository?.historyProvider.currentHistoryItemGroup?.remote?.id;
ref = ref ?? repository?.historyProvider.currentHistoryItemRemoteRef?.id;
if (!repository || !ref) {
return;
}
+7 -6
View File
@@ -164,11 +164,11 @@ class GitIncomingChangesFileDecorationProvider implements FileDecorationProvider
constructor(private readonly repository: Repository) {
this.disposables.push(
window.registerFileDecorationProvider(this),
runAndSubscribeEvent(repository.historyProvider.onDidChangeCurrentHistoryItemGroup, () => this.onDidChangeCurrentHistoryItemGroup())
runAndSubscribeEvent(repository.historyProvider.onDidChangeCurrentHistoryItemRefs, () => this.onDidChangeCurrentHistoryItemRefs())
);
}
private async onDidChangeCurrentHistoryItemGroup(): Promise<void> {
private async onDidChangeCurrentHistoryItemRefs(): Promise<void> {
const newDecorations = new Map<string, FileDecoration>();
await this.collectIncomingChangesFileDecorations(newDecorations);
const uris = new Set([...this.decorations.keys()].concat([...newDecorations.keys()]));
@@ -218,18 +218,19 @@ class GitIncomingChangesFileDecorationProvider implements FileDecorationProvider
private async getIncomingChanges(): Promise<Change[]> {
try {
const historyProvider = this.repository.historyProvider;
const currentHistoryItemGroup = historyProvider.currentHistoryItemGroup;
const currentHistoryItemRef = historyProvider.currentHistoryItemRef;
const currentHistoryItemRemoteRef = historyProvider.currentHistoryItemRemoteRef;
if (!currentHistoryItemGroup?.remote) {
if (!currentHistoryItemRef || !currentHistoryItemRemoteRef) {
return [];
}
const ancestor = await historyProvider.resolveHistoryItemGroupCommonAncestor([currentHistoryItemGroup.id, currentHistoryItemGroup.remote.id]);
const ancestor = await historyProvider.resolveHistoryItemRefsCommonAncestor([currentHistoryItemRef.id, currentHistoryItemRemoteRef.id]);
if (!ancestor) {
return [];
}
const changes = await this.repository.diffBetween(ancestor, currentHistoryItemGroup.remote.id);
const changes = await this.repository.diffBetween(ancestor, currentHistoryItemRemoteRef.id);
return changes;
} catch (err) {
return [];
+202 -70
View File
@@ -4,36 +4,69 @@
*--------------------------------------------------------------------------------------------*/
import { Disposable, Event, EventEmitter, FileDecoration, FileDecorationProvider, SourceControlHistoryItem, SourceControlHistoryItemChange, SourceControlHistoryItemGroup, SourceControlHistoryOptions, SourceControlHistoryProvider, ThemeIcon, Uri, window, LogOutputChannel, SourceControlHistoryItemLabel } from 'vscode';
import { Disposable, Event, EventEmitter, FileDecoration, FileDecorationProvider, SourceControlHistoryItem, SourceControlHistoryItemChange, SourceControlHistoryOptions, SourceControlHistoryProvider, ThemeIcon, Uri, window, LogOutputChannel, SourceControlHistoryItemRef, l10n, SourceControlHistoryItemRefsChangeEvent } from 'vscode';
import { Repository, Resource } from './repository';
import { IDisposable, dispose } from './util';
import { IDisposable, deltaHistoryItemRefs, dispose } from './util';
import { toGitUri } from './uri';
import { Branch, LogOptions, RefType } from './api/git';
import { Branch, LogOptions, Ref, RefType } from './api/git';
import { emojify, ensureEmojis } from './emoji';
import { Commit } from './git';
function toSourceControlHistoryItemRef(ref: Ref): SourceControlHistoryItemRef {
switch (ref.type) {
case RefType.RemoteHead:
return {
id: `refs/remotes/${ref.name}`,
name: ref.name ?? '',
description: ref.commit ? l10n.t('Remote branch at {0}', ref.commit.substring(0, 8)) : undefined,
revision: ref.commit,
icon: new ThemeIcon('cloud'),
category: l10n.t('remote branches')
};
case RefType.Tag:
return {
id: `refs/tags/${ref.name}`,
name: ref.name ?? '',
description: ref.commit ? l10n.t('Tag at {0}', ref.commit.substring(0, 8)) : undefined,
revision: ref.commit,
icon: new ThemeIcon('tag'),
category: l10n.t('tags')
};
default:
return {
id: `refs/heads/${ref.name}`,
name: ref.name ?? '',
description: ref.commit ? ref.commit.substring(0, 8) : undefined,
revision: ref.commit,
icon: new ThemeIcon('git-branch'),
category: l10n.t('branches')
};
}
}
export class GitHistoryProvider implements SourceControlHistoryProvider, FileDecorationProvider, IDisposable {
private readonly _onDidChangeCurrentHistoryItemGroup = new EventEmitter<void>();
readonly onDidChangeCurrentHistoryItemGroup: Event<void> = this._onDidChangeCurrentHistoryItemGroup.event;
private readonly _onDidChangeDecorations = new EventEmitter<Uri[]>();
readonly onDidChangeFileDecorations: Event<Uri[]> = this._onDidChangeDecorations.event;
private _currentHistoryItemGroup: SourceControlHistoryItemGroup | undefined;
get currentHistoryItemGroup(): SourceControlHistoryItemGroup | undefined { return this._currentHistoryItemGroup; }
set currentHistoryItemGroup(value: SourceControlHistoryItemGroup | undefined) {
this._currentHistoryItemGroup = value;
this._onDidChangeCurrentHistoryItemGroup.fire();
}
private _currentHistoryItemRef: SourceControlHistoryItemRef | undefined;
get currentHistoryItemRef(): SourceControlHistoryItemRef | undefined { return this._currentHistoryItemRef; }
private _currentHistoryItemRemoteRef: SourceControlHistoryItemRef | undefined;
get currentHistoryItemRemoteRef(): SourceControlHistoryItemRef | undefined { return this._currentHistoryItemRemoteRef; }
private _currentHistoryItemBaseRef: SourceControlHistoryItemRef | undefined;
get currentHistoryItemBaseRef(): SourceControlHistoryItemRef | undefined { return this._currentHistoryItemBaseRef; }
private readonly _onDidChangeCurrentHistoryItemRefs = new EventEmitter<void>();
readonly onDidChangeCurrentHistoryItemRefs: Event<void> = this._onDidChangeCurrentHistoryItemRefs.event;
private readonly _onDidChangeHistoryItemRefs = new EventEmitter<SourceControlHistoryItemRefsChangeEvent>();
readonly onDidChangeHistoryItemRefs: Event<SourceControlHistoryItemRefsChangeEvent> = this._onDidChangeHistoryItemRefs.event;
private _HEAD: Branch | undefined;
private historyItemRefs: SourceControlHistoryItemRef[] = [];
private historyItemDecorations = new Map<string, FileDecoration>();
private historyItemLabels = new Map<string, ThemeIcon>([
['HEAD -> refs/heads/', new ThemeIcon('target')],
['tag: refs/tags/', new ThemeIcon('tag')],
['refs/heads/', new ThemeIcon('git-branch')],
['refs/remotes/', new ThemeIcon('cloud')],
]);
private disposables: Disposable[] = [];
@@ -45,53 +78,124 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec
private async onDidRunGitStatus(): Promise<void> {
if (!this.repository.HEAD) {
this.logger.trace('[GitHistoryProvider][onDidRunGitStatus] repository.HEAD is undefined');
this.currentHistoryItemGroup = undefined;
this._currentHistoryItemRef = this._currentHistoryItemRemoteRef = this._currentHistoryItemBaseRef = undefined;
this._onDidChangeCurrentHistoryItemRefs.fire();
return;
}
// Get the merge base of the current history item group
const mergeBase = await this.resolveHEADMergeBase();
let historyItemRefId = '';
let historyItemRefName = '';
// Handle tag, and detached commit
const currentHistoryItemGroupId =
this.repository.HEAD.name === undefined ?
this.repository.HEAD.commit :
this.repository.HEAD.type === RefType.Tag ?
`refs/tags/${this.repository.HEAD.name}` :
`refs/heads/${this.repository.HEAD.name}`;
switch (this.repository.HEAD.type) {
case RefType.Head: {
if (this.repository.HEAD.name !== undefined) {
// Branch
historyItemRefId = `refs/heads/${this.repository.HEAD.name}`;
historyItemRefName = this.repository.HEAD.name;
// Detached commit
const currentHistoryItemGroupName =
this.repository.HEAD.name ?? this.repository.HEAD.commit;
// Remote
this._currentHistoryItemRemoteRef = this.repository.HEAD.upstream ? {
id: `refs/remotes/${this.repository.HEAD.upstream.remote}/${this.repository.HEAD.upstream.name}`,
name: `${this.repository.HEAD.upstream.remote}/${this.repository.HEAD.upstream.name}`,
revision: this.repository.HEAD.upstream.commit,
icon: new ThemeIcon('cloud')
} : undefined;
this.currentHistoryItemGroup = {
id: currentHistoryItemGroupId ?? '',
name: currentHistoryItemGroupName ?? '',
// Base - compute only if the branch has changed
if (this._HEAD?.name !== this.repository.HEAD.name) {
const mergeBase = await this.resolveHEADMergeBase();
this._currentHistoryItemBaseRef = mergeBase &&
(mergeBase.remote !== this.repository.HEAD.upstream?.remote ||
mergeBase.name !== this.repository.HEAD.upstream?.name) ? {
id: `refs/remotes/${mergeBase.remote}/${mergeBase.name}`,
name: `${mergeBase.remote}/${mergeBase.name}`,
revision: mergeBase.commit
} : undefined;
}
} else {
// Detached commit
historyItemRefId = this.repository.HEAD.commit ?? '';
historyItemRefName = this.repository.HEAD.commit ?? '';
this._currentHistoryItemRemoteRef = undefined;
this._currentHistoryItemBaseRef = undefined;
}
break;
}
case RefType.Tag: {
// Tag
historyItemRefId = `refs/tags/${this.repository.HEAD.name}`;
historyItemRefName = this.repository.HEAD.name ?? this.repository.HEAD.commit ?? '';
this._currentHistoryItemRemoteRef = undefined;
this._currentHistoryItemBaseRef = undefined;
break;
}
}
this._HEAD = this.repository.HEAD;
this._currentHistoryItemRef = {
id: historyItemRefId,
name: historyItemRefName,
revision: this.repository.HEAD.commit,
remote: this.repository.HEAD.upstream ? {
id: `refs/remotes/${this.repository.HEAD.upstream.remote}/${this.repository.HEAD.upstream.name}`,
name: `${this.repository.HEAD.upstream.remote}/${this.repository.HEAD.upstream.name}`,
revision: this.repository.HEAD.upstream.commit
} : undefined,
base: mergeBase &&
(mergeBase.remote !== this.repository.HEAD.upstream?.remote ||
mergeBase.name !== this.repository.HEAD.upstream?.name) ? {
id: `refs/remotes/${mergeBase.remote}/${mergeBase.name}`,
name: `${mergeBase.remote}/${mergeBase.name}`,
revision: mergeBase.commit
} : undefined
icon: new ThemeIcon('target'),
};
this.logger.trace(`[GitHistoryProvider][onDidRunGitStatus] currentHistoryItemGroup: ${JSON.stringify(this.currentHistoryItemGroup)}`);
this._onDidChangeCurrentHistoryItemRefs.fire();
this.logger.trace(`[GitHistoryProvider][onDidRunGitStatus] currentHistoryItemRef: ${JSON.stringify(this._currentHistoryItemRef)}`);
this.logger.trace(`[GitHistoryProvider][onDidRunGitStatus] currentHistoryItemRemoteRef: ${JSON.stringify(this._currentHistoryItemRemoteRef)}`);
this.logger.trace(`[GitHistoryProvider][onDidRunGitStatus] currentHistoryItemBaseRef: ${JSON.stringify(this._currentHistoryItemBaseRef)}`);
// Refs (alphabetically)
const refs = await this.repository.getRefs({ sort: 'alphabetically' });
const historyItemRefs = refs.map(ref => toSourceControlHistoryItemRef(ref));
const delta = deltaHistoryItemRefs(this.historyItemRefs, historyItemRefs);
this._onDidChangeHistoryItemRefs.fire(delta);
this.historyItemRefs = historyItemRefs;
const deltaLog = {
added: delta.added.map(ref => ref.id),
modified: delta.modified.map(ref => ref.id),
removed: delta.removed.map(ref => ref.id)
};
this.logger.trace(`[GitHistoryProvider][onDidRunGitStatus] historyItemRefs: ${JSON.stringify(deltaLog)}`);
}
async provideHistoryItemRefs(): Promise<SourceControlHistoryItemRef[]> {
const refs = await this.repository.getRefs();
const branches: SourceControlHistoryItemRef[] = [];
const remoteBranches: SourceControlHistoryItemRef[] = [];
const tags: SourceControlHistoryItemRef[] = [];
for (const ref of refs) {
switch (ref.type) {
case RefType.RemoteHead:
remoteBranches.push(toSourceControlHistoryItemRef(ref));
break;
case RefType.Tag:
tags.push(toSourceControlHistoryItemRef(ref));
break;
default:
branches.push(toSourceControlHistoryItemRef(ref));
break;
}
}
return [...branches, ...remoteBranches, ...tags];
}
async provideHistoryItems(options: SourceControlHistoryOptions): Promise<SourceControlHistoryItem[]> {
if (!this.currentHistoryItemGroup || !options.historyItemGroupIds) {
if (!this.currentHistoryItemRef || !options.historyItemRefs) {
return [];
}
// Deduplicate refNames
const refNames = Array.from(new Set<string>(options.historyItemGroupIds));
const refNames = Array.from(new Set<string>(options.historyItemRefs));
let logOptions: LogOptions = { refNames, shortStats: true };
@@ -115,7 +219,7 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec
await ensureEmojis();
return commits.map(commit => {
const labels = this.resolveHistoryItemLabels(commit);
const references = this.resolveHistoryItemRefs(commit);
return {
id: commit.hash,
@@ -126,7 +230,7 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec
displayId: commit.hash.substring(0, 8),
timestamp: commit.authorDate?.getTime(),
statistics: commit.shortStat ?? { files: 0, insertions: 0, deletions: 0 },
labels: labels.length !== 0 ? labels : undefined
references: references.length !== 0 ? references : undefined
};
});
} catch (err) {
@@ -169,21 +273,21 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec
return historyItemChanges;
}
async resolveHistoryItemGroupCommonAncestor(historyItemGroupIds: string[]): Promise<string | undefined> {
async resolveHistoryItemRefsCommonAncestor(historyItemRefs: string[]): Promise<string | undefined> {
try {
if (historyItemGroupIds.length === 0) {
if (historyItemRefs.length === 0) {
// TODO@lszomoru - log
return undefined;
} else if (historyItemGroupIds.length === 1 && historyItemGroupIds[0] === this.currentHistoryItemGroup?.id) {
} else if (historyItemRefs.length === 1 && historyItemRefs[0] === this.currentHistoryItemRef?.id) {
// Remote
if (this.currentHistoryItemGroup.remote) {
const ancestor = await this.repository.getMergeBase(historyItemGroupIds[0], this.currentHistoryItemGroup.remote.id);
if (this.currentHistoryItemRemoteRef) {
const ancestor = await this.repository.getMergeBase(historyItemRefs[0], this.currentHistoryItemRemoteRef.id);
return ancestor;
}
// Base
if (this.currentHistoryItemGroup.base) {
const ancestor = await this.repository.getMergeBase(historyItemGroupIds[0], this.currentHistoryItemGroup.base.id);
if (this.currentHistoryItemBaseRef) {
const ancestor = await this.repository.getMergeBase(historyItemRefs[0], this.currentHistoryItemBaseRef.id);
return ancestor;
}
@@ -192,13 +296,13 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec
if (commits.length > 0) {
return commits[0].hash;
}
} else if (historyItemGroupIds.length > 1) {
const ancestor = await this.repository.getMergeBase(historyItemGroupIds[0], historyItemGroupIds[1], ...historyItemGroupIds.slice(2));
} else if (historyItemRefs.length > 1) {
const ancestor = await this.repository.getMergeBase(historyItemRefs[0], historyItemRefs[1], ...historyItemRefs.slice(2));
return ancestor;
}
}
catch (err) {
this.logger.error(`[GitHistoryProvider][resolveHistoryItemGroupCommonAncestor] Failed to resolve common ancestor for ${historyItemGroupIds.join(',')}: ${err}`);
this.logger.error(`[GitHistoryProvider][resolveHistoryItemRefsCommonAncestor] Failed to resolve common ancestor for ${historyItemRefs.join(',')}: ${err}`);
}
return undefined;
@@ -208,19 +312,47 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec
return this.historyItemDecorations.get(uri.toString());
}
private resolveHistoryItemLabels(commit: Commit): SourceControlHistoryItemLabel[] {
const labels: SourceControlHistoryItemLabel[] = [];
private resolveHistoryItemRefs(commit: Commit): SourceControlHistoryItemRef[] {
const references: SourceControlHistoryItemRef[] = [];
for (const label of commit.refNames) {
for (const [key, value] of this.historyItemLabels) {
if (label.startsWith(key)) {
labels.push({ title: label.substring(key.length), icon: value });
for (const ref of commit.refNames) {
switch (true) {
case ref.startsWith('HEAD -> refs/heads/'):
references.push({
id: ref.substring('HEAD -> '.length),
name: ref.substring('HEAD -> refs/heads/'.length),
revision: commit.hash,
icon: new ThemeIcon('target')
});
break;
case ref.startsWith('tag: refs/tags/'):
references.push({
id: ref.substring('tag: '.length),
name: ref.substring('tag: refs/tags/'.length),
revision: commit.hash,
icon: new ThemeIcon('tag')
});
break;
case ref.startsWith('refs/heads/'):
references.push({
id: ref,
name: ref.substring('refs/heads/'.length),
revision: commit.hash,
icon: new ThemeIcon('git-branch')
});
break;
case ref.startsWith('refs/remotes/'):
references.push({
id: ref,
name: ref.substring('refs/remotes/'.length),
revision: commit.hash,
icon: new ThemeIcon('cloud')
});
break;
}
}
}
return labels;
return references;
}
private async resolveHEADMergeBase(): Promise<Branch | undefined> {
+56 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event, Disposable, EventEmitter } from 'vscode';
import { Event, Disposable, EventEmitter, SourceControlHistoryItemRef } from 'vscode';
import { dirname, sep, relative } from 'path';
import { Readable } from 'stream';
import { promises as fs, createReadStream } from 'fs';
@@ -513,3 +513,58 @@ export namespace Versions {
return from(major, minor, patch, pre);
}
}
export function deltaHistoryItemRefs(before: SourceControlHistoryItemRef[], after: SourceControlHistoryItemRef[]): {
added: SourceControlHistoryItemRef[];
modified: SourceControlHistoryItemRef[];
removed: SourceControlHistoryItemRef[];
} {
if (before.length === 0) {
return { added: after, modified: [], removed: [] };
}
const added: SourceControlHistoryItemRef[] = [];
const modified: SourceControlHistoryItemRef[] = [];
const removed: SourceControlHistoryItemRef[] = [];
let beforeIdx = 0;
let afterIdx = 0;
while (true) {
if (beforeIdx === before.length) {
added.push(...after.slice(afterIdx));
break;
}
if (afterIdx === after.length) {
removed.push(...before.slice(beforeIdx));
break;
}
const beforeElement = before[beforeIdx];
const afterElement = after[afterIdx];
const result = beforeElement.id.localeCompare(afterElement.id);
if (result === 0) {
if (beforeElement.revision !== afterElement.revision) {
// modified
modified.push(afterElement);
}
beforeIdx += 1;
afterIdx += 1;
} else if (result < 0) {
// beforeElement is smaller -> before element removed
removed.push(beforeElement);
beforeIdx += 1;
} else if (result > 0) {
// beforeElement is greater -> after element added
added.push(afterElement);
afterIdx += 1;
}
}
return { added, modified, removed };
}
@@ -6,5 +6,4 @@ build/**
extension.webpack.config.js
extension-browser.webpack.config.js
tsconfig.json
yarn.lock
package-lock.json
+21 -4
View File
@@ -18,7 +18,9 @@ interface SessionData {
account?: {
label?: string;
displayName?: string;
id: string;
// Unfortunately, for some time the id was a number, so we need to support both.
// This can be removed once we are confident that all users have migrated to the new id.
id: string | number;
};
scopes: string[];
accessToken: string;
@@ -239,9 +241,14 @@ export class GitHubAuthenticationProvider implements vscode.AuthenticationProvid
return [];
}
// Unfortunately, we were using a number secretly for the account id for some time... this is due to a bad `any`.
// AuthenticationSession's account id is a string, so we need to detect when there is a number accountId and re-store
// the sessions to migrate away from the bad number usage.
// TODO@TylerLeonhardt: Remove this after we are confident that all users have migrated to the new id.
let seenNumberAccountId: boolean = false;
// TODO: eventually remove this Set because we should only have one session per set of scopes.
const scopesSeen = new Set<string>();
const sessionPromises = sessionData.map(async (session: SessionData) => {
const sessionPromises = sessionData.map(async (session: SessionData): Promise<vscode.AuthenticationSession | undefined> => {
// For GitHub scope list, order doesn't matter so we immediately sort the scopes
const scopesStr = [...session.scopes].sort().join(' ');
if (!this._supportsMultipleAccounts && scopesSeen.has(scopesStr)) {
@@ -262,13 +269,23 @@ export class GitHubAuthenticationProvider implements vscode.AuthenticationProvid
this._logger.trace(`Read the following session from the keychain with the following scopes: ${scopesStr}`);
scopesSeen.add(scopesStr);
let accountId: string;
if (session.account?.id) {
if (typeof session.account.id === 'number') {
seenNumberAccountId = true;
}
accountId = `${session.account.id}`;
} else {
accountId = userInfo?.id ?? '<unknown>';
}
return {
id: session.id,
account: {
label: session.account
? session.account.label ?? session.account.displayName ?? '<unknown>'
: userInfo?.accountName ?? '<unknown>',
id: session.account?.id ?? userInfo?.id ?? '<unknown>'
id: accountId
},
// we set this to session.scopes to maintain the original order of the scopes requested
// by the extension that called getSession()
@@ -283,7 +300,7 @@ export class GitHubAuthenticationProvider implements vscode.AuthenticationProvid
.filter(<T>(p?: T): p is T => Boolean(p));
this._logger.info(`Got ${verifiedSessions.length} verified sessions.`);
if (verifiedSessions.length !== sessionData.length) {
if (seenNumberAccountId || verifiedSessions.length !== sessionData.length) {
await this.storeSessions(verifiedSessions);
}
@@ -228,9 +228,9 @@ export class GitHubServer implements IGitHubServer {
if (result.ok) {
try {
const json = await result.json();
const json = await result.json() as { id: number; login: string };
this._logger.info('Got account info!');
return { id: json.id, accountName: json.login };
return { id: `${json.id}`, accountName: json.login };
} catch (e) {
this._logger.error(`Unexpected error parsing response from GitHub: ${e.message ?? e}`);
throw e;
-1
View File
@@ -4,5 +4,4 @@ out/**
build/**
extension.webpack.config.js
tsconfig.json
yarn.lock
package-lock.json
-1
View File
@@ -3,5 +3,4 @@ src/**
tsconfig.json
out/**
extension.webpack.config.js
yarn.lock
package-lock.json
-1
View File
@@ -2,5 +2,4 @@ src/**
tsconfig.json
out/**
extension.webpack.config.js
yarn.lock
package-lock.json
@@ -13,10 +13,8 @@ server/test/**
server/bin/**
server/build/**
server/lib/cgmanifest.json
server/yarn.lock
server/package-lock.json
server/.npmignore
yarn.lock
package-lock.json
server/extension.webpack.config.js
extension.webpack.config.js
-1
View File
@@ -5,7 +5,6 @@ out/**
tsconfig.json
extension.webpack.config.js
extension-browser.webpack.config.js
yarn.lock
package-lock.json
.gitignore
esbuild.js
-1
View File
@@ -2,5 +2,4 @@ src/**
tsconfig.json
out/**
extension.webpack.config.js
yarn.lock
package-lock.json
@@ -10,11 +10,9 @@ server/tsconfig.json
server/test/**
server/bin/**
server/build/**
server/yarn.lock
server/package-lock.json
server/.npmignore
server/README.md
yarn.lock
package-lock.json
CONTRIBUTING.md
server/extension.webpack.config.js
@@ -5,7 +5,6 @@ src/
test/
tsconfig.json
.gitignore
yarn.lock
package-lock.json
extension.webpack.config.js
vscode-json-languageserver-*.tgz
@@ -9,7 +9,6 @@ out/**
extension.webpack.config.js
extension-browser.webpack.config.js
cgmanifest.json
yarn.lock
package-lock.json
preview-src/**
webpack.config.js
-1
View File
@@ -4,7 +4,6 @@ extension-browser.webpack.config.js
extension.webpack.config.js
esbuild.js
cgmanifest.json
yarn.lock
package-lock.json
webpack.config.js
tsconfig.json
-1
View File
@@ -6,7 +6,6 @@ out/**
extension.webpack.config.js
extension-browser.webpack.config.js
cgmanifest.json
yarn.lock
package-lock.json
preview-src/**
webpack.config.js
@@ -12,6 +12,7 @@ html, body {
body img {
max-width: none;
max-height: none;
vertical-align: middle;
}
.container:focus {
@@ -31,20 +32,20 @@ body img {
box-sizing: border-box;
}
.container.image img {
.container.image .transparency-grid {
padding: 0;
background-position: 0 0, 8px 8px;
background-size: 16px 16px;
border: 1px solid var(--vscode-imagePreview-border);
}
.container.image img {
.container.image .transparency-grid {
background-image:
linear-gradient(45deg, rgb(230, 230, 230) 25%, transparent 25%, transparent 75%, rgb(230, 230, 230) 75%, rgb(230, 230, 230)),
linear-gradient(45deg, rgb(230, 230, 230) 25%, transparent 25%, transparent 75%, rgb(230, 230, 230) 75%, rgb(230, 230, 230));
}
.vscode-dark.container.image img {
.vscode-dark.container.image .transparency-grid {
background-image:
linear-gradient(45deg, rgb(20, 20, 20) 25%, transparent 25%, transparent 75%, rgb(20, 20, 20) 75%, rgb(20, 20, 20)),
linear-gradient(45deg, rgb(20, 20, 20) 25%, transparent 25%, transparent 75%, rgb(20, 20, 20) 75%, rgb(20, 20, 20));
@@ -54,13 +55,13 @@ body img {
image-rendering: pixelated;
}
.container img.scale-to-fit {
.container .transparency-grid.scale-to-fit {
max-width: calc(100% - 20px);
max-height: calc(100% - 20px);
object-fit: contain;
}
.container img {
.container .transparency-grid {
margin: auto;
}
@@ -76,6 +76,8 @@
// Elements
const container = document.body;
const transparencyGrid = document.createElement('div');
transparencyGrid.classList.add('transparency-grid');
const image = document.createElement('img');
function updateScale(newScale) {
@@ -85,7 +87,7 @@
if (newScale === 'fit') {
scale = 'fit';
image.classList.add('scale-to-fit');
transparencyGrid.classList.add('scale-to-fit');
image.classList.remove('pixelated');
// @ts-ignore Non-standard CSS property
image.style.zoom = 'normal';
@@ -292,7 +294,9 @@
document.body.classList.remove('loading');
document.body.classList.add('ready');
document.body.append(image);
document.body.append(transparencyGrid);
transparencyGrid.appendChild(image);
updateScale(scale);
-1
View File
@@ -3,5 +3,4 @@ tsconfig.json
out/**
extension.webpack.config.js
extension-browser.webpack.config.js
yarn.lock
package-lock.json
@@ -4,7 +4,6 @@ out/test/**
out/**
extension.webpack.config.js
extension-browser.webpack.config.js
yarn.lock
package-lock.json
src/**
.gitignore
@@ -7,6 +7,8 @@ import type { Disposable, Event } from 'vscode';
export interface ICachedPublicClientApplication extends Disposable {
initialize(): Promise<void>;
onDidAccountsChange: Event<{ added: AccountInfo[]; changed: AccountInfo[]; deleted: AccountInfo[] }>;
onDidRemoveLastAccount: Event<void>;
acquireTokenSilent(request: SilentFlowRequest): Promise<AuthenticationResult>;
acquireTokenInteractive(request: InteractiveRequest): Promise<AuthenticationResult>;
removeAccount(account: AccountInfo): Promise<void>;
@@ -16,6 +18,7 @@ export interface ICachedPublicClientApplication extends Disposable {
}
export interface ICachedPublicClientApplicationManager {
onDidAccountsChange: Event<{ added: AccountInfo[]; changed: AccountInfo[]; deleted: AccountInfo[] }>;
getOrCreate(clientId: string, authority: string): Promise<ICachedPublicClientApplication>;
getAll(): ICachedPublicClientApplication[];
}
@@ -48,15 +48,12 @@ export class MsalAuthProvider implements AuthenticationProvider {
private readonly _env: Environment = Environment.AzureCloud
) {
this._disposables = context.subscriptions;
this._publicClientManager = new CachedPublicClientApplicationManager(
context.globalState,
context.secrets,
this._logger,
(e) => this._handleAccountChange(e)
this._publicClientManager = new CachedPublicClientApplicationManager(context.globalState, context.secrets, this._logger);
this._disposables.push(
this._onDidChangeSessionsEmitter,
this._publicClientManager,
this._publicClientManager.onDidAccountsChange(e => this._handleAccountChange(e))
);
this._disposables.push(this._publicClientManager);
this._disposables.push(this._onDidChangeSessionsEmitter);
}
async initialize(): Promise<void> {
@@ -79,40 +76,43 @@ export class MsalAuthProvider implements AuthenticationProvider {
* See {@link onDidChangeSessions} for more information on how this is used.
* @param param0 Event that contains the added and removed accounts
*/
private _handleAccountChange({ added, deleted }: { added: AccountInfo[]; deleted: AccountInfo[] }) {
const process = (a: AccountInfo) => ({
// This shouldn't be needed
accessToken: '1234',
id: a.homeAccountId,
scopes: [],
account: {
id: a.homeAccountId,
label: a.username
},
idToken: a.idToken,
private _handleAccountChange({ added, changed, deleted }: { added: AccountInfo[]; changed: AccountInfo[]; deleted: AccountInfo[] }) {
this._onDidChangeSessionsEmitter.fire({
added: added.map(this.sessionFromAccountInfo),
changed: changed.map(this.sessionFromAccountInfo),
removed: deleted.map(this.sessionFromAccountInfo)
});
this._onDidChangeSessionsEmitter.fire({ added: added.map(process), changed: [], removed: deleted.map(process) });
}
//#region AuthenticationProvider methods
async getSessions(scopes: string[] | undefined, options?: AuthenticationGetSessionOptions): Promise<AuthenticationSession[]> {
const askingForAll = scopes === undefined;
const scopeData = new ScopeData(scopes);
this._logger.info('[getSessions]', scopes ? scopeData.scopeStr : 'all', 'starting');
if (!scopes) {
// Do NOT use `scopes` beyond this place in the code. Use `scopeData` instead.
// Do NOT use `scopes` beyond this place in the code. Use `scopeData` instead.
this._logger.info('[getSessions]', askingForAll ? '[all]' : `[${scopeData.scopeStr}]`, 'starting');
const allSessions: AuthenticationSession[] = [];
// This branch only gets called by Core for sign out purposes and initial population of the account menu. Since we are
// living in a world where a "session" from Core's perspective is an account, we return 1 session per account.
// See the large comment on `onDidChangeSessions` for more information.
if (askingForAll) {
const allSessionsForAccounts = new Map<string, AuthenticationSession>();
for (const cachedPca of this._publicClientManager.getAll()) {
const sessions = await this.getAllSessionsForPca(cachedPca, scopeData.originalScopes, scopeData.scopesToSend, options?.account);
allSessions.push(...sessions);
for (const account of cachedPca.accounts) {
if (allSessionsForAccounts.has(account.homeAccountId)) {
continue;
}
allSessionsForAccounts.set(account.homeAccountId, this.sessionFromAccountInfo(account));
}
}
const allSessions = Array.from(allSessionsForAccounts.values());
this._logger.info('[getSessions] [all]', `returned ${allSessions.length} session(s)`);
return allSessions;
}
const cachedPca = await this.getOrCreatePublicClientApplication(scopeData.clientId, scopeData.tenant);
const sessions = await this.getAllSessionsForPca(cachedPca, scopeData.originalScopes, scopeData.scopesToSend, options?.account);
this._logger.info(`[getSessions] returned ${sessions.length} sessions`);
this._logger.info(`[getSessions] [${scopeData.scopeStr}] returned ${sessions.length} session(s)`);
return sessions;
}
@@ -121,7 +121,7 @@ export class MsalAuthProvider implements AuthenticationProvider {
const scopeData = new ScopeData(scopes);
// Do NOT use `scopes` beyond this place in the code. Use `scopeData` instead.
this._logger.info('[createSession]', scopeData.scopeStr, 'starting');
this._logger.info('[createSession]', `[${scopeData.scopeStr}]`, 'starting');
const cachedPca = await this.getOrCreatePublicClientApplication(scopeData.clientId, scopeData.tenant);
let result: AuthenticationResult;
try {
@@ -169,32 +169,43 @@ export class MsalAuthProvider implements AuthenticationProvider {
}
}
const session = this.toAuthenticationSession(result, scopeData.originalScopes);
const session = this.sessionFromAuthenticationResult(result, scopeData.originalScopes);
this._telemetryReporter.sendLoginEvent(session.scopes);
this._logger.info('[createSession]', scopeData.scopeStr, 'returned session');
this._logger.info('[createSession]', `[${scopeData.scopeStr}]`, 'returned session');
// This is the only scenario in which we need to fire the _onDidChangeSessionsEmitter out of band...
// the badge flow (when the client passes no options in to getSession) will only remove a badge if a session
// was created that _matches the scopes_ that that badge requests. See `onDidChangeSessions` for more info.
// TODO: This should really be fixed in Core.
this._onDidChangeSessionsEmitter.fire({ added: [session], changed: [], removed: [] });
return session;
}
async removeSession(sessionId: string): Promise<void> {
this._logger.info('[removeSession]', sessionId, 'starting');
const promises = new Array<Promise<void>>();
for (const cachedPca of this._publicClientManager.getAll()) {
const accounts = cachedPca.accounts;
for (const account of accounts) {
if (account.homeAccountId === sessionId) {
this._telemetryReporter.sendLogoutEvent();
try {
await cachedPca.removeAccount(account);
} catch (e) {
this._telemetryReporter.sendLogoutFailedEvent();
throw e;
}
this._logger.info('[removeSession]', sessionId, 'removed session');
return;
promises.push(cachedPca.removeAccount(account));
this._logger.info(`[removeSession] [${sessionId}] [${cachedPca.clientId}] [${cachedPca.authority}] removing session...`);
}
}
}
this._logger.info('[removeSession]', sessionId, 'session not found');
if (!promises.length) {
this._logger.info('[removeSession]', sessionId, 'session not found');
return;
}
const results = await Promise.allSettled(promises);
for (const result of results) {
if (result.status === 'rejected') {
this._telemetryReporter.sendLogoutFailedEvent();
this._logger.error('[removeSession]', sessionId, 'error removing session', result.reason);
}
}
this._logger.info('[removeSession]', sessionId, `attempted to remove ${promises.length} sessions`);
}
//#endregion
@@ -217,7 +228,7 @@ export class MsalAuthProvider implements AuthenticationProvider {
for (const account of accounts) {
try {
const result = await cachedPca.acquireTokenSilent({ account, scopes: scopesToSend, redirectUri });
sessions.push(this.toAuthenticationSession(result, originalScopes));
sessions.push(this.sessionFromAuthenticationResult(result, originalScopes));
} catch (e) {
// If we can't get a token silently, the account is probably in a bad state so we should skip it
// MSAL will log this already, so we don't need to log it again
@@ -227,7 +238,7 @@ export class MsalAuthProvider implements AuthenticationProvider {
return sessions;
}
private toAuthenticationSession(result: AuthenticationResult, scopes: readonly string[]): AuthenticationSession & { idToken: string } {
private sessionFromAuthenticationResult(result: AuthenticationResult, scopes: readonly string[]): AuthenticationSession & { idToken: string } {
return {
accessToken: result.accessToken,
idToken: result.idToken,
@@ -239,4 +250,17 @@ export class MsalAuthProvider implements AuthenticationProvider {
scopes
};
}
private sessionFromAccountInfo(account: AccountInfo): AuthenticationSession {
return {
accessToken: '1234',
id: account.homeAccountId,
scopes: [],
account: {
id: account.homeAccountId,
label: account.username
},
idToken: account.idToken,
};
}
}
@@ -0,0 +1,148 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { PublicClientApplication, AccountInfo, Configuration, SilentFlowRequest, AuthenticationResult, InteractiveRequest } from '@azure/msal-node';
import { Disposable, Memento, SecretStorage, LogOutputChannel, window, ProgressLocation, l10n, EventEmitter } from 'vscode';
import { raceCancellationAndTimeoutError } from '../common/async';
import { SecretStorageCachePlugin } from '../common/cachePlugin';
import { MsalLoggerOptions } from '../common/loggerOptions';
import { ICachedPublicClientApplication } from '../common/publicClientCache';
export class CachedPublicClientApplication implements ICachedPublicClientApplication {
private _pca: PublicClientApplication;
private _accounts: AccountInfo[] = [];
private readonly _disposable: Disposable;
private readonly _loggerOptions = new MsalLoggerOptions(this._logger);
private readonly _secretStorageCachePlugin = new SecretStorageCachePlugin(
this._secretStorage,
// Include the prefix as a differentiator to other secrets
`pca:${JSON.stringify({ clientId: this._clientId, authority: this._authority })}`
);
private readonly _config: Configuration = {
auth: { clientId: this._clientId, authority: this._authority },
system: {
loggerOptions: {
correlationId: `${this._clientId}] [${this._authority}`,
loggerCallback: (level, message, containsPii) => this._loggerOptions.loggerCallback(level, message, containsPii),
}
},
cache: {
cachePlugin: this._secretStorageCachePlugin
}
};
/**
* We keep track of the last time an account was removed so we can recreate the PCA if we detect that an account was removed.
* This is due to MSAL-node not providing a way to detect when an account is removed from the cache. An internal issue has been
* filed to track this. If MSAL-node ever provides a way to detect this or handle this better in the Persistant Cache Plugin,
* we can remove this logic.
*/
private _lastCreated: Date;
//#region Events
private readonly _onDidAccountsChangeEmitter = new EventEmitter<{ added: AccountInfo[]; changed: AccountInfo[]; deleted: AccountInfo[] }>;
readonly onDidAccountsChange = this._onDidAccountsChangeEmitter.event;
private readonly _onDidRemoveLastAccountEmitter = new EventEmitter<void>();
readonly onDidRemoveLastAccount = this._onDidRemoveLastAccountEmitter.event;
//#endregion
constructor(
private readonly _clientId: string,
private readonly _authority: string,
private readonly _globalMemento: Memento,
private readonly _secretStorage: SecretStorage,
private readonly _logger: LogOutputChannel
) {
this._pca = new PublicClientApplication(this._config);
this._lastCreated = new Date();
this._disposable = Disposable.from(
this._registerOnSecretStorageChanged(),
this._onDidAccountsChangeEmitter,
this._onDidRemoveLastAccountEmitter
);
}
get accounts(): AccountInfo[] { return this._accounts; }
get clientId(): string { return this._clientId; }
get authority(): string { return this._authority; }
initialize(): Promise<void> {
return this._update();
}
dispose(): void {
this._disposable.dispose();
}
async acquireTokenSilent(request: SilentFlowRequest): Promise<AuthenticationResult> {
this._logger.debug(`[acquireTokenSilent] [${this._clientId}] [${this._authority}] [${request.scopes.join(' ')}]`);
const result = await this._pca.acquireTokenSilent(request);
if (result.account && !result.fromCache) {
this._onDidAccountsChangeEmitter.fire({ added: [], changed: [result.account], deleted: [] });
}
return result;
}
async acquireTokenInteractive(request: InteractiveRequest): Promise<AuthenticationResult> {
this._logger.debug(`[acquireTokenInteractive] [${this._clientId}] [${this._authority}] [${request.scopes?.join(' ')}] loopbackClientOverride: ${request.loopbackClient ? 'true' : 'false'}`);
return await window.withProgress(
{
location: ProgressLocation.Notification,
cancellable: true,
title: l10n.t('Signing in to Microsoft...')
},
(_process, token) => raceCancellationAndTimeoutError(
this._pca.acquireTokenInteractive(request),
token,
1000 * 60 * 5
)
);
}
removeAccount(account: AccountInfo): Promise<void> {
this._globalMemento.update(`lastRemoval:${this._clientId}:${this._authority}`, new Date());
return this._pca.getTokenCache().removeAccount(account);
}
private _registerOnSecretStorageChanged() {
return this._secretStorageCachePlugin.onDidChange(() => this._update());
}
private async _update() {
const before = this._accounts;
this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication update before: ${before.length}`);
// Dates are stored as strings in the memento
const lastRemovalDate = this._globalMemento.get<string>(`lastRemoval:${this._clientId}:${this._authority}`);
if (lastRemovalDate && this._lastCreated && Date.parse(lastRemovalDate) > this._lastCreated.getTime()) {
this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication removal detected... recreating PCA...`);
this._pca = new PublicClientApplication(this._config);
this._lastCreated = new Date();
}
const after = await this._pca.getAllAccounts();
this._accounts = after;
this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication update after: ${after.length}`);
const beforeSet = new Set(before.map(b => b.homeAccountId));
const afterSet = new Set(after.map(a => a.homeAccountId));
const added = after.filter(a => !beforeSet.has(a.homeAccountId));
const deleted = before.filter(b => !afterSet.has(b.homeAccountId));
if (added.length > 0 || deleted.length > 0) {
this._onDidAccountsChangeEmitter.fire({ added, changed: [], deleted });
this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication accounts changed. added: ${added.length}, deleted: ${deleted.length}`);
if (!after.length) {
this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication final account deleted. Firing event.`);
this._onDidRemoveLastAccountEmitter.fire();
}
}
this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication update complete`);
}
}
@@ -3,77 +3,84 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { AccountInfo, AuthenticationResult, Configuration, InteractiveRequest, PublicClientApplication, SilentFlowRequest } from '@azure/msal-node';
import { SecretStorageCachePlugin } from '../common/cachePlugin';
import { SecretStorage, LogOutputChannel, Disposable, SecretStorageChangeEvent, EventEmitter, Memento, window, ProgressLocation, l10n } from 'vscode';
import { MsalLoggerOptions } from '../common/loggerOptions';
import { AccountInfo } from '@azure/msal-node';
import { SecretStorage, LogOutputChannel, Disposable, EventEmitter, Memento, Event } from 'vscode';
import { ICachedPublicClientApplication, ICachedPublicClientApplicationManager } from '../common/publicClientCache';
import { raceCancellationAndTimeoutError } from '../common/async';
import { CachedPublicClientApplication } from './cachedPublicClientApplication';
export interface IPublicClientApplicationInfo {
clientId: string;
authority: string;
}
const _keyPrefix = 'pca:';
export class CachedPublicClientApplicationManager implements ICachedPublicClientApplicationManager {
// The key is the clientId and authority stringified
// The key is the clientId and authority JSON stringified
private readonly _pcas = new Map<string, CachedPublicClientApplication>();
private readonly _pcaDisposables = new Map<string, Disposable>();
private _initialized = false;
private _disposable: Disposable;
private _pcasSecretStorage: PublicClientApplicationsSecretStorage;
private readonly _onDidAccountsChangeEmitter = new EventEmitter<{ added: AccountInfo[]; changed: AccountInfo[]; deleted: AccountInfo[] }>();
readonly onDidAccountsChange = this._onDidAccountsChangeEmitter.event;
constructor(
private readonly _globalMemento: Memento,
private readonly _secretStorage: SecretStorage,
private readonly _logger: LogOutputChannel,
private readonly _accountChangeHandler: (e: { added: AccountInfo[]; deleted: AccountInfo[] }) => void
private readonly _logger: LogOutputChannel
) {
this._disposable = _secretStorage.onDidChange(e => this._handleSecretStorageChange(e));
this._pcasSecretStorage = new PublicClientApplicationsSecretStorage(_secretStorage);
this._disposable = Disposable.from(
this._pcasSecretStorage,
this._registerSecretStorageHandler(),
this._onDidAccountsChangeEmitter
);
}
private _registerSecretStorageHandler() {
return this._pcasSecretStorage.onDidChange(() => this._handleSecretStorageChange());
}
async initialize() {
this._logger.debug('[initialize] Initializing PublicClientApplicationManager');
const keys = await this._secretStorage.get('publicClientApplications');
let keys: string[] | undefined;
try {
keys = await this._pcasSecretStorage.get();
} catch (e) {
// data is corrupted
this._logger.error('[initialize] Error initializing PublicClientApplicationManager:', e);
await this._pcasSecretStorage.delete();
}
if (!keys) {
this._initialized = true;
return;
}
const promises = new Array<Promise<ICachedPublicClientApplication>>();
try {
for (const key of JSON.parse(keys) as string[]) {
try {
const { clientId, authority } = JSON.parse(key) as IPublicClientApplicationInfo;
// Load the PCA in memory
promises.push(this.getOrCreate(clientId, authority));
} catch (e) {
// ignore
}
for (const key of keys) {
try {
const { clientId, authority } = JSON.parse(key) as IPublicClientApplicationInfo;
// Load the PCA in memory
promises.push(this._doCreatePublicClientApplication(clientId, authority, key));
} catch (e) {
this._logger.error('[initialize] Error intitializing PCA:', key);
}
} catch (e) {
// data is corrupted
this._logger.error('[initialize] Error initializing PublicClientApplicationManager:', e);
await this._secretStorage.delete('publicClientApplications');
}
// TODO: should we do anything for when this fails?
await Promise.allSettled(promises);
const results = await Promise.allSettled(promises);
for (const result of results) {
if (result.status === 'rejected') {
this._logger.error('[initialize] Error getting PCA:', result.reason);
}
}
this._logger.debug('[initialize] PublicClientApplicationManager initialized');
this._initialized = true;
}
dispose() {
this._disposable.dispose();
Disposable.from(...this._pcas.values()).dispose();
Disposable.from(...this._pcaDisposables.values()).dispose();
}
async getOrCreate(clientId: string, authority: string): Promise<ICachedPublicClientApplication> {
if (!this._initialized) {
throw new Error('PublicClientApplicationManager not initialized');
}
// Use the clientId and authority as the key
const pcasKey = JSON.stringify({ clientId, authority });
let pca = this._pcas.get(pcasKey);
@@ -83,170 +90,127 @@ export class CachedPublicClientApplicationManager implements ICachedPublicClient
}
this._logger.debug(`[getOrCreate] [${clientId}] [${authority}] PublicClientApplicationManager cache miss, creating new PCA...`);
pca = new CachedPublicClientApplication(clientId, authority, this._globalMemento, this._secretStorage, this._accountChangeHandler, this._logger);
this._pcas.set(pcasKey, pca);
await pca.initialize();
pca = await this._doCreatePublicClientApplication(clientId, authority, pcasKey);
await this._storePublicClientApplications();
this._logger.debug(`[getOrCreate] [${clientId}] [${authority}] PublicClientApplicationManager PCA created`);
this._logger.debug(`[getOrCreate] [${clientId}] [${authority}] PCA created.`);
return pca;
}
private async _doCreatePublicClientApplication(clientId: string, authority: string, pcasKey: string) {
const pca = new CachedPublicClientApplication(clientId, authority, this._globalMemento, this._secretStorage, this._logger);
this._pcas.set(pcasKey, pca);
const disposable = Disposable.from(
pca,
pca.onDidAccountsChange(e => this._onDidAccountsChangeEmitter.fire(e)),
pca.onDidRemoveLastAccount(() => {
// The PCA has no more accounts, so we can dispose it so we're not keeping it
// around forever.
disposable.dispose();
this._pcas.delete(pcasKey);
this._logger.debug(`[_doCreatePublicClientApplication] [${clientId}] [${authority}] PCA disposed. Firing off storing of PCAs...`);
void this._storePublicClientApplications();
})
);
this._pcaDisposables.set(pcasKey, disposable);
// Intialize the PCA after the `onDidAccountsChange` is set so we get initial state.
await pca.initialize();
return pca;
}
getAll(): ICachedPublicClientApplication[] {
if (!this._initialized) {
throw new Error('PublicClientApplicationManager not initialized');
}
return Array.from(this._pcas.values());
}
private async _handleSecretStorageChange(e: SecretStorageChangeEvent) {
if (!e.key.startsWith(_keyPrefix)) {
return;
}
this._logger.debug(`[handleSecretStorageChange] PublicClientApplicationManager secret storage change: ${e.key}`);
const result = await this._secretStorage.get(e.key);
const pcasKey = e.key.split(_keyPrefix)[1];
// If the cache was deleted, or the PCA has zero accounts left, remove the PCA
if (!result || this._pcas.get(pcasKey)?.accounts.length === 0) {
this._logger.debug(`[handleSecretStorageChange] PublicClientApplicationManager removing PCA: ${pcasKey}`);
this._pcas.delete(pcasKey);
private async _handleSecretStorageChange() {
this._logger.debug(`[_handleSecretStorageChange] Handling PCAs secret storage change...`);
let result: string[] | undefined;
try {
result = await this._pcasSecretStorage.get();
} catch (_e) {
// The data in secret storage has been corrupted somehow so
// we store what we have in this window
await this._storePublicClientApplications();
this._logger.debug(`[handleSecretStorageChange] PublicClientApplicationManager PCA removed: ${pcasKey}`);
return;
}
if (!result) {
this._logger.debug(`[_handleSecretStorageChange] PCAs deleted in secret storage. Disposing all...`);
Disposable.from(...this._pcaDisposables.values()).dispose();
this._pcas.clear();
this._pcaDisposables.clear();
this._logger.debug(`[_handleSecretStorageChange] Finished PCAs secret storage change.`);
return;
}
// Load the PCA in memory if it's not already loaded
const { clientId, authority } = JSON.parse(pcasKey) as IPublicClientApplicationInfo;
this._logger.debug(`[handleSecretStorageChange] PublicClientApplicationManager loading PCA: ${pcasKey}`);
await this.getOrCreate(clientId, authority);
this._logger.debug(`[handleSecretStorageChange] PublicClientApplicationManager PCA loaded: ${pcasKey}`);
const pcaKeysFromStorage = new Set(result);
// Handle the deleted ones
for (const pcaKey of this._pcas.keys()) {
if (!pcaKeysFromStorage.delete(pcaKey)) {
// This PCA has been removed in another window
this._pcaDisposables.get(pcaKey)?.dispose();
this._pcaDisposables.delete(pcaKey);
this._pcas.delete(pcaKey);
this._logger.debug(`[_handleSecretStorageChange] Disposed PCA that was deleted in another window: ${pcaKey}`);
}
}
// Handle the new ones
for (const newPca of pcaKeysFromStorage) {
try {
const { clientId, authority } = JSON.parse(newPca);
this._logger.debug(`[_handleSecretStorageChange] [${clientId}] [${authority}] Creating new PCA that was created in another window...`);
await this._doCreatePublicClientApplication(clientId, authority, newPca);
this._logger.debug(`[_handleSecretStorageChange] [${clientId}] [${authority}] PCA created.`);
} catch (_e) {
// This really shouldn't happen, but should we do something about this?
this._logger.error(`Failed to parse new PublicClientApplication: ${newPca}`);
continue;
}
}
this._logger.debug('[_handleSecretStorageChange] Finished handling PCAs secret storage change.');
}
private async _storePublicClientApplications() {
await this._secretStorage.store(
'publicClientApplications',
JSON.stringify(Array.from(this._pcas.keys()))
);
private _storePublicClientApplications() {
return this._pcasSecretStorage.store(Array.from(this._pcas.keys()));
}
}
class CachedPublicClientApplication implements ICachedPublicClientApplication {
private _pca: PublicClientApplication;
class PublicClientApplicationsSecretStorage {
private static key = 'publicClientApplications';
private _accounts: AccountInfo[] = [];
private readonly _disposable: Disposable;
private _disposable: Disposable;
private readonly _loggerOptions = new MsalLoggerOptions(this._logger);
private readonly _secretStorageCachePlugin = new SecretStorageCachePlugin(
this._secretStorage,
// Include the prefix in the key so we can easily identify it later
`${_keyPrefix}${JSON.stringify({ clientId: this._clientId, authority: this._authority })}`
);
private readonly _config: Configuration = {
auth: { clientId: this._clientId, authority: this._authority },
system: {
loggerOptions: {
correlationId: `${this._clientId}] [${this._authority}`,
loggerCallback: (level, message, containsPii) => this._loggerOptions.loggerCallback(level, message, containsPii),
}
},
cache: {
cachePlugin: this._secretStorageCachePlugin
private readonly _onDidChangeEmitter = new EventEmitter<void>;
readonly onDidChange: Event<void> = this._onDidChangeEmitter.event;
constructor(private readonly _secretStorage: SecretStorage) {
this._disposable = Disposable.from(
this._onDidChangeEmitter,
this._secretStorage.onDidChange(e => {
if (e.key === PublicClientApplicationsSecretStorage.key) {
this._onDidChangeEmitter.fire();
}
})
);
}
async get(): Promise<string[] | undefined> {
const value = await this._secretStorage.get(PublicClientApplicationsSecretStorage.key);
if (!value) {
return undefined;
}
};
/**
* We keep track of the last time an account was removed so we can recreate the PCA if we detect that an account was removed.
* This is due to MSAL-node not providing a way to detect when an account is removed from the cache. An internal issue has been
* filed to track this. If MSAL-node ever provides a way to detect this or handle this better in the Persistant Cache Plugin,
* we can remove this logic.
*/
private _lastCreated: Date;
constructor(
private readonly _clientId: string,
private readonly _authority: string,
private readonly _globalMemento: Memento,
private readonly _secretStorage: SecretStorage,
private readonly _accountChangeHandler: (e: { added: AccountInfo[]; changed: AccountInfo[]; deleted: AccountInfo[] }) => void,
private readonly _logger: LogOutputChannel
) {
this._pca = new PublicClientApplication(this._config);
this._lastCreated = new Date();
this._disposable = this._registerOnSecretStorageChanged();
return JSON.parse(value);
}
get accounts(): AccountInfo[] { return this._accounts; }
get clientId(): string { return this._clientId; }
get authority(): string { return this._authority; }
initialize(): Promise<void> {
return this._update();
store(value: string[]): Thenable<void> {
return this._secretStorage.store(PublicClientApplicationsSecretStorage.key, JSON.stringify(value));
}
dispose(): void {
delete(): Thenable<void> {
return this._secretStorage.delete(PublicClientApplicationsSecretStorage.key);
}
dispose() {
this._disposable.dispose();
}
async acquireTokenSilent(request: SilentFlowRequest): Promise<AuthenticationResult> {
this._logger.debug(`[acquireTokenSilent] [${this._clientId}] [${this._authority}] [${request.scopes.join(' ')}]`);
const result = await this._pca.acquireTokenSilent(request);
if (result.account && !result.fromCache) {
this._accountChangeHandler({ added: [], changed: [result.account], deleted: [] });
}
return result;
}
async acquireTokenInteractive(request: InteractiveRequest): Promise<AuthenticationResult> {
this._logger.debug(`[acquireTokenInteractive] [${this._clientId}] [${this._authority}] [${request.scopes?.join(' ')}] loopbackClientOverride: ${request.loopbackClient ? 'true' : 'false'}`);
return await window.withProgress(
{
location: ProgressLocation.Notification,
cancellable: true,
title: l10n.t('Signing in to Microsoft...')
},
(_process, token) => raceCancellationAndTimeoutError(
this._pca.acquireTokenInteractive(request),
token,
1000 * 60 * 5
), // 5 minutes
);
}
removeAccount(account: AccountInfo): Promise<void> {
this._globalMemento.update(`lastRemoval:${this._clientId}:${this._authority}`, new Date());
return this._pca.getTokenCache().removeAccount(account);
}
private _registerOnSecretStorageChanged() {
return this._secretStorageCachePlugin.onDidChange(() => this._update());
}
private async _update() {
const before = this._accounts;
this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication update before: ${before.length}`);
// Dates are stored as strings in the memento
const lastRemovalDate = this._globalMemento.get<string>(`lastRemoval:${this._clientId}:${this._authority}`);
if (lastRemovalDate && this._lastCreated && Date.parse(lastRemovalDate) > this._lastCreated.getTime()) {
this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication removal detected... recreating PCA...`);
this._pca = new PublicClientApplication(this._config);
this._lastCreated = new Date();
}
const after = await this._pca.getAllAccounts();
this._accounts = after;
this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication update after: ${after.length}`);
const beforeSet = new Set(before.map(b => b.homeAccountId));
const afterSet = new Set(after.map(a => a.homeAccountId));
const added = after.filter(a => !beforeSet.has(a.homeAccountId));
const deleted = before.filter(b => !afterSet.has(b.homeAccountId));
if (added.length > 0 || deleted.length > 0) {
this._accountChangeHandler({ added, changed: [], deleted });
this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication accounts changed. added: ${added.length}, deleted: ${deleted.length}`);
}
this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication update complete`);
}
}
-1
View File
@@ -4,5 +4,4 @@ tsconfig.json
.vscode/**
extension.webpack.config.js
extension-browser.webpack.config.js
yarn.lock
package-lock.json
+11 -9
View File
@@ -193,15 +193,16 @@
}
},
"node_modules/micromatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
"integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"license": "MIT",
"dependencies": {
"braces": "^3.0.1",
"picomatch": "^2.0.5"
"braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
"node": ">=8"
"node": ">=8.6"
}
},
"node_modules/minimatch": {
@@ -252,9 +253,10 @@
}
},
"node_modules/picomatch": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"license": "MIT",
"engines": {
"node": ">=8.6"
},
+5 -4
View File
@@ -547,12 +547,13 @@
}
},
"node_modules/micromatch": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"license": "MIT",
"dependencies": {
"braces": "^3.0.2",
"braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -3,5 +3,4 @@ src/**
out/**
tsconfig.json
extension.webpack.config.js
yarn.lock
package-lock.json
-1
View File
@@ -3,5 +3,4 @@ src/**
out/**
tsconfig.json
*.webpack.config.js
yarn.lock
package-lock.json
-1
View File
@@ -3,6 +3,5 @@ out/**
tsconfig.json
extension.webpack.config.js
extension-browser.webpack.config.js
yarn.lock
package-lock.json
syntaxes/generateTMLanguage.js
+2 -13
View File
@@ -12,7 +12,6 @@ const path = require('path');
const fs = require('fs');
const merge = require('merge-options');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { NLSBundlePlugin } = require('vscode-nls-dev/lib/webpack-bundler');
const { DefinePlugin, optimize } = require('webpack');
const tsLoaderOptions = {
@@ -40,13 +39,6 @@ function withNodeDefaults(/**@type WebpackConfig & { context: string }*/extConfi
test: /\.ts$/,
exclude: /node_modules/,
use: [{
// vscode-nls-dev loader:
// * rewrite nls-calls
loader: 'vscode-nls-dev/lib/webpack-loader',
options: {
base: path.join(extConfig.context, 'src')
}
}, {
// configure TypeScript loader:
// * enable sources maps for end-to-end source maps
loader: 'ts-loader',
@@ -97,8 +89,7 @@ function nodePlugins(context) {
patterns: [
{ from: 'src', to: '.', globOptions: { ignore: ['**/test/**', '**/*.ts'] }, noErrorOnMissing: true }
]
}),
new NLSBundlePlugin(id)
})
];
}
/**
@@ -196,9 +187,7 @@ function browserPlugins(context) {
'process.platform': JSON.stringify('web'),
'process.env': JSON.stringify({}),
'process.env.BROWSER_ENV': JSON.stringify('true')
}),
// TODO: bring this back once vscode-nls-dev supports browser
// new NLSBundlePlugin(id)
})
];
}
-1
View File
@@ -8,7 +8,6 @@ extension.webpack.config.js
extension-browser.webpack.config.js
cgmanifest.json
.gitignore
yarn.lock
package-lock.json
preview-src/**
webpack.config.js
@@ -2,5 +2,4 @@ src/**
tsconfig.json
out/**
extension.webpack.config.js
yarn.lock
package-lock.json
@@ -8,5 +8,4 @@ tsconfig.json
extension.webpack.config.js
extension-browser.webpack.config.js
cgmanifest.json
yarn.lock
package-lock.json
+79 -595
View File
@@ -10,6 +10,7 @@
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@bpasero/watcher": "https://github.com/bpasero/watcher.git#5d29cc732a03c91ecc2c861940a240b01e765c65",
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
"@parcel/watcher": "2.1.0",
@@ -21,7 +22,7 @@
"@vscode/spdlog": "^0.15.0",
"@vscode/sqlite3": "5.1.6-vscode",
"@vscode/sudo-prompt": "9.3.1",
"@vscode/tree-sitter-wasm": "^0.0.2",
"@vscode/tree-sitter-wasm": "^0.0.3",
"@vscode/vscode-languagedetection": "1.0.21",
"@vscode/windows-mutex": "^0.5.0",
"@vscode/windows-process-tree": "^0.6.0",
@@ -84,6 +85,7 @@
"@vscode/test-web": "^0.0.56",
"@vscode/v8-heap-parser": "^0.1.0",
"@vscode/vscode-perf": "^0.0.14",
"@webgpu/types": "^0.1.44",
"ansi-colors": "^3.2.3",
"asar": "^3.0.3",
"chromium-pickle-js": "^0.2.0",
@@ -131,7 +133,6 @@
"mime": "^1.4.1",
"minimatch": "^3.0.4",
"minimist": "^1.2.6",
"mkdirp": "^1.0.4",
"mocha": "^10.2.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
@@ -156,7 +157,6 @@
"tslib": "^2.6.3",
"typescript": "^5.7.0-dev.20240903",
"util": "^0.12.4",
"vscode-nls-dev": "^3.3.1",
"webpack": "^5.94.0",
"webpack-cli": "^5.1.4",
"webpack-stream": "^7.0.0",
@@ -941,6 +941,44 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
"node_modules/@bpasero/watcher": {
"version": "2.4.2-alpha.0",
"resolved": "git+ssh://git@github.com/bpasero/watcher.git#5d29cc732a03c91ecc2c861940a240b01e765c65",
"integrity": "sha512-8AWyO22MDRxp6zAJxDWXGFCHtBoioaku+x/IQrDT3VADhBRAeCVp/47qCVrHFyU0ixo0m8KGDBN6MtxqsFFU2g==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"detect-libc": "^1.0.3",
"is-glob": "^4.0.3",
"micromatch": "^4.0.5",
"node-addon-api": "^7.0.0"
},
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@bpasero/watcher/node_modules/detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
"license": "Apache-2.0",
"bin": {
"detect-libc": "bin/detect-libc.js"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/@bpasero/watcher/node_modules/node-addon-api": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
"license": "MIT"
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
@@ -3167,9 +3205,9 @@
}
},
"node_modules/@vscode/tree-sitter-wasm": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.0.2.tgz",
"integrity": "sha512-N57MR/kt4jR0H/TXeDsVYeJmvvUiK7avow0fjy+/EeKcyNBJcM2BFhj4XOAaaMbhGsOcIeSvJFouRWctXI7sKw=="
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.0.3.tgz",
"integrity": "sha512-K5YmUdohFCavPqEzG2cUPcZ6555KE1qwMDCjkvSUSz+s+8Wro2xfg+syLq90y6Tq0ZSUVvpuX6yq6ukToeGaLg=="
},
"node_modules/@vscode/v8-heap-parser": {
"version": "0.1.0",
@@ -3414,6 +3452,12 @@
"@xtuc/long": "4.2.2"
}
},
"node_modules/@webgpu/types": {
"version": "0.1.44",
"resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.44.tgz",
"integrity": "sha512-JDpYJN5E/asw84LTYhKyvPpxGnD+bAKPtpW9Ilurf7cZpxaTbxkQcGwOd7jgB9BPBrTYQ+32ufo4HiuomTjHNQ==",
"dev": true
},
"node_modules/@webpack-cli/configtest": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz",
@@ -6699,119 +6743,6 @@
"node": ">=0.8.x"
}
},
"node_modules/execa": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
"dev": true,
"dependencies": {
"cross-spawn": "^6.0.0",
"get-stream": "^4.0.0",
"is-stream": "^1.1.0",
"npm-run-path": "^2.0.0",
"p-finally": "^1.0.0",
"signal-exit": "^3.0.0",
"strip-eof": "^1.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/execa/node_modules/cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"dev": true,
"dependencies": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
},
"engines": {
"node": ">=4.8"
}
},
"node_modules/execa/node_modules/get-stream": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
"dev": true,
"dependencies": {
"pump": "^3.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/execa/node_modules/path-key": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/execa/node_modules/pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"dev": true,
"dependencies": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"node_modules/execa/node_modules/semver": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
}
},
"node_modules/execa/node_modules/shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
"dev": true,
"dependencies": {
"shebang-regex": "^1.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/execa/node_modules/shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/execa/node_modules/signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
"dev": true
},
"node_modules/execa/node_modules/which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"dev": true,
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"which": "bin/which"
}
},
"node_modules/expand-brackets": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
@@ -8836,7 +8767,7 @@
"node_modules/gulp-cli/node_modules/ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8= sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
"integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@@ -8845,7 +8776,7 @@
"node_modules/gulp-cli/node_modules/camelcase": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
"integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo= sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==",
"integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@@ -8947,9 +8878,9 @@
"dev": true
},
"node_modules/gulp-cli/node_modules/yargs": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.1.tgz",
"integrity": "sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==",
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz",
"integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==",
"dev": true,
"dependencies": {
"camelcase": "^3.0.0",
@@ -8964,13 +8895,13 @@
"string-width": "^1.0.2",
"which-module": "^1.0.0",
"y18n": "^3.2.1",
"yargs-parser": "5.0.0-security.0"
"yargs-parser": "^5.0.1"
}
},
"node_modules/gulp-cli/node_modules/yargs-parser": {
"version": "5.0.0-security.0",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz",
"integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz",
"integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==",
"dev": true,
"dependencies": {
"camelcase": "^3.0.0",
@@ -9066,9 +8997,9 @@
}
},
"node_modules/gulp-eslint/node_modules/ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= sha512-wFUFA5bg5dviipbQQ32yOQhl6gcJaJXiHE7dvR8VYPG97+J/GNC5FKGepKdEDUFeXRzDxPF1X/Btc8L+v7oqIQ==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
"integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
"dev": true,
"engines": {
"node": ">=4"
@@ -9838,7 +9769,7 @@
"node_modules/gulp-plumber/node_modules/ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8= sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
"integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@@ -10389,7 +10320,7 @@
"node_modules/has-ansi/node_modules/ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8= sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
"integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@@ -10685,7 +10616,7 @@
"node_modules/husky/node_modules/ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8= sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
"integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@@ -10912,9 +10843,9 @@
}
},
"node_modules/inquirer/node_modules/ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
"dev": true,
"engines": {
"node": ">=6"
@@ -11045,9 +10976,9 @@
}
},
"node_modules/inquirer/node_modules/string-width/node_modules/ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= sha512-wFUFA5bg5dviipbQQ32yOQhl6gcJaJXiHE7dvR8VYPG97+J/GNC5FKGepKdEDUFeXRzDxPF1X/Btc8L+v7oqIQ==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
"integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
"dev": true,
"engines": {
"node": ">=4"
@@ -11119,15 +11050,6 @@
"node": ">= 12"
}
},
"node_modules/is": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/is/-/is-3.2.1.tgz",
"integrity": "sha1-0Kwq1V63sL7JJqUmb2xmKqqD3KU= sha512-NgGnzF+/wucMxle6i32obg/UjUqQruwlJUtjBpDEMXNq8vPLuaf28U4q+yes1I6J89FoErr7kDtBGICoNaY7rQ==",
"dev": true,
"engines": {
"node": "*"
}
},
"node_modules/is-absolute": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
@@ -12565,18 +12487,6 @@
"node": ">=0.10.0"
}
},
"node_modules/map-age-cleaner": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
"integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
"dev": true,
"dependencies": {
"p-defer": "^1.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/map-cache": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
@@ -12847,20 +12757,6 @@
"node": ">= 0.6"
}
},
"node_modules/mem": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
"integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
"dev": true,
"dependencies": {
"map-age-cleaner": "^0.1.1",
"mimic-fn": "^2.0.0",
"p-is-promise": "^2.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/memoizee": {
"version": "0.4.15",
"resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz",
@@ -12951,11 +12847,12 @@
}
},
"node_modules/micromatch": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"license": "MIT",
"dependencies": {
"braces": "^3.0.2",
"braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -13872,27 +13769,6 @@
"which": "bin/which"
}
},
"node_modules/npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
"integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
"dev": true,
"dependencies": {
"path-key": "^2.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/npm-run-path/node_modules/path-key": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/nth-check": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
@@ -14401,33 +14277,6 @@
"node": ">=8"
}
},
"node_modules/p-defer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
"integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/p-is-promise": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
"integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -17746,15 +17595,6 @@
"node": ">=0.10.0"
}
},
"node_modules/strip-eof": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -17971,9 +17811,9 @@
}
},
"node_modules/table/node_modules/ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
"dev": true,
"engines": {
"node": ">=6"
@@ -19258,362 +19098,6 @@
"node": ">= 0.10"
}
},
"node_modules/vscode-nls-dev": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/vscode-nls-dev/-/vscode-nls-dev-3.3.1.tgz",
"integrity": "sha512-fug18D7CXb8pv8JoQ0D0JmZaIYDQoKLiyZxkAy5P8Cln/FwlNsdzwQILDph62EdGY5pvsJ2Jd1T5qgHAExe/tg==",
"dev": true,
"dependencies": {
"ansi-colors": "^3.2.3",
"clone": "^2.1.1",
"event-stream": "^3.3.4",
"fancy-log": "^1.3.3",
"glob": "^7.1.2",
"iconv-lite": "^0.4.19",
"is": "^3.2.1",
"source-map": "^0.6.1",
"typescript": "^2.6.2",
"vinyl": "^2.1.0",
"xml2js": "^0.4.19",
"yargs": "^13.2.4"
},
"bin": {
"vscl": "lib/vscl.js"
}
},
"node_modules/vscode-nls-dev/node_modules/ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/vscode-nls-dev/node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"dependencies": {
"color-convert": "^1.9.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/vscode-nls-dev/node_modules/camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/vscode-nls-dev/node_modules/cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"dev": true,
"dependencies": {
"string-width": "^3.1.0",
"strip-ansi": "^5.2.0",
"wrap-ansi": "^5.1.0"
}
},
"node_modules/vscode-nls-dev/node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"dependencies": {
"color-name": "1.1.3"
}
},
"node_modules/vscode-nls-dev/node_modules/color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
},
"node_modules/vscode-nls-dev/node_modules/decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/vscode-nls-dev/node_modules/emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
"dev": true
},
"node_modules/vscode-nls-dev/node_modules/find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"dependencies": {
"locate-path": "^3.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/vscode-nls-dev/node_modules/glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/vscode-nls-dev/node_modules/invert-kv": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/vscode-nls-dev/node_modules/is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/vscode-nls-dev/node_modules/lcid": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
"integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
"dev": true,
"dependencies": {
"invert-kv": "^2.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/vscode-nls-dev/node_modules/locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"dev": true,
"dependencies": {
"p-locate": "^3.0.0",
"path-exists": "^3.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/vscode-nls-dev/node_modules/os-locale": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
"integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
"dev": true,
"dependencies": {
"execa": "^1.0.0",
"lcid": "^2.0.0",
"mem": "^4.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/vscode-nls-dev/node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"dependencies": {
"p-try": "^2.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/vscode-nls-dev/node_modules/p-locate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"dev": true,
"dependencies": {
"p-limit": "^2.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/vscode-nls-dev/node_modules/path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/vscode-nls-dev/node_modules/replace-ext": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz",
"integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==",
"dev": true,
"engines": {
"node": ">= 0.10"
}
},
"node_modules/vscode-nls-dev/node_modules/string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"dev": true,
"dependencies": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/vscode-nls-dev/node_modules/strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dev": true,
"dependencies": {
"ansi-regex": "^4.1.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/vscode-nls-dev/node_modules/typescript": {
"version": "2.9.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
"integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/vscode-nls-dev/node_modules/vinyl": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz",
"integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==",
"dev": true,
"dependencies": {
"clone": "^2.1.1",
"clone-buffer": "^1.0.0",
"clone-stats": "^1.0.0",
"cloneable-readable": "^1.0.0",
"remove-trailing-separator": "^1.0.1",
"replace-ext": "^1.0.0"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/vscode-nls-dev/node_modules/wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"dev": true,
"dependencies": {
"ansi-styles": "^3.2.0",
"string-width": "^3.0.0",
"strip-ansi": "^5.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/vscode-nls-dev/node_modules/xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"dev": true,
"dependencies": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/vscode-nls-dev/node_modules/xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
"dev": true,
"engines": {
"node": ">=4.0"
}
},
"node_modules/vscode-nls-dev/node_modules/y18n": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz",
"integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==",
"dev": true
},
"node_modules/vscode-nls-dev/node_modules/yargs": {
"version": "13.2.4",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz",
"integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==",
"dev": true,
"dependencies": {
"cliui": "^5.0.0",
"find-up": "^3.0.0",
"get-caller-file": "^2.0.1",
"os-locale": "^3.1.0",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^3.0.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^13.1.0"
}
},
"node_modules/vscode-nls-dev/node_modules/yargs-parser": {
"version": "13.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
"integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
"dev": true,
"dependencies": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
},
"node_modules/vscode-oniguruma": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
+7 -7
View File
@@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.94.0",
"distro": "1f99a7e25e381bc566d839c0259770ef5735d8ed",
"distro": "94e8178dbd2d80f72a25452eff94052eb9fbcf68",
"author": {
"name": "Microsoft Corporation"
},
@@ -28,11 +28,11 @@
"kill-watch-webd": "deemon --kill npm run watch-web",
"restart-watchd": "deemon --restart npm run watch",
"restart-watch-webd": "deemon --restart npm run watch-web",
"watch-client": "node ./node_modules/gulp/bin/gulp.js watch-client",
"watch-client-amd": "node ./node_modules/gulp/bin/gulp.js watch-client-amd",
"watch-client": "node --max-old-space-size=8192 ./node_modules/gulp/bin/gulp.js watch-client",
"watch-client-amd": "node --max-old-space-size=8192 ./node_modules/gulp/bin/gulp.js watch-client-amd",
"watch-clientd": "deemon npm run watch-client",
"kill-watch-clientd": "deemon --kill npm run watch-client",
"watch-extensions": "node ./node_modules/gulp/bin/gulp.js watch-extensions watch-extension-media",
"watch-extensions": "node --max-old-space-size=8192 ./node_modules/gulp/bin/gulp.js watch-extensions watch-extension-media",
"watch-extensionsd": "deemon npm run watch-extensions",
"kill-watch-extensionsd": "deemon --kill npm run watch-extensions",
"precommit": "node build/hygiene.js",
@@ -75,6 +75,7 @@
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
"@parcel/watcher": "2.1.0",
"@bpasero/watcher": "https://github.com/bpasero/watcher.git#5d29cc732a03c91ecc2c861940a240b01e765c65",
"@vscode/deviceid": "^0.1.1",
"@vscode/iconv-lite-umd": "0.7.0",
"@vscode/policy-watcher": "^1.1.4",
@@ -83,7 +84,7 @@
"@vscode/spdlog": "^0.15.0",
"@vscode/sqlite3": "5.1.6-vscode",
"@vscode/sudo-prompt": "9.3.1",
"@vscode/tree-sitter-wasm": "^0.0.2",
"@vscode/tree-sitter-wasm": "^0.0.3",
"@vscode/vscode-languagedetection": "1.0.21",
"@vscode/windows-mutex": "^0.5.0",
"@vscode/windows-process-tree": "^0.6.0",
@@ -146,6 +147,7 @@
"@vscode/test-web": "^0.0.56",
"@vscode/v8-heap-parser": "^0.1.0",
"@vscode/vscode-perf": "^0.0.14",
"@webgpu/types": "^0.1.44",
"ansi-colors": "^3.2.3",
"asar": "^3.0.3",
"chromium-pickle-js": "^0.2.0",
@@ -193,7 +195,6 @@
"mime": "^1.4.1",
"minimatch": "^3.0.4",
"minimist": "^1.2.6",
"mkdirp": "^1.0.4",
"mocha": "^10.2.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
@@ -218,7 +219,6 @@
"tslib": "^2.6.3",
"typescript": "^5.7.0-dev.20240903",
"util": "^0.12.4",
"vscode-nls-dev": "^3.3.1",
"webpack": "^5.94.0",
"webpack-cli": "^5.1.4",
"webpack-stream": "^7.0.0",
+43 -4
View File
@@ -8,6 +8,7 @@
"name": "vscode-reh",
"version": "0.0.0",
"dependencies": {
"@bpasero/watcher": "https://github.com/bpasero/watcher.git#5d29cc732a03c91ecc2c861940a240b01e765c65",
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
"@parcel/watcher": "2.1.0",
@@ -16,7 +17,7 @@
"@vscode/proxy-agent": "^0.23.0",
"@vscode/ripgrep": "^1.15.9",
"@vscode/spdlog": "^0.15.0",
"@vscode/tree-sitter-wasm": "^0.0.2",
"@vscode/tree-sitter-wasm": "^0.0.3",
"@vscode/vscode-languagedetection": "1.0.21",
"@vscode/windows-process-tree": "^0.6.0",
"@vscode/windows-registry": "^1.1.0",
@@ -44,6 +45,44 @@
"yazl": "^2.4.3"
}
},
"node_modules/@bpasero/watcher": {
"version": "2.4.2-alpha.0",
"resolved": "git+ssh://git@github.com/bpasero/watcher.git#5d29cc732a03c91ecc2c861940a240b01e765c65",
"integrity": "sha512-8AWyO22MDRxp6zAJxDWXGFCHtBoioaku+x/IQrDT3VADhBRAeCVp/47qCVrHFyU0ixo0m8KGDBN6MtxqsFFU2g==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"detect-libc": "^1.0.3",
"is-glob": "^4.0.3",
"micromatch": "^4.0.5",
"node-addon-api": "^7.0.0"
},
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@bpasero/watcher/node_modules/detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
"license": "Apache-2.0",
"bin": {
"detect-libc": "bin/detect-libc.js"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/@bpasero/watcher/node_modules/node-addon-api": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
"license": "MIT"
},
"node_modules/@microsoft/1ds-core-js": {
"version": "3.2.13",
"resolved": "https://registry.npmjs.org/@microsoft/1ds-core-js/-/1ds-core-js-3.2.13.tgz",
@@ -184,9 +223,9 @@
}
},
"node_modules/@vscode/tree-sitter-wasm": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.0.2.tgz",
"integrity": "sha512-N57MR/kt4jR0H/TXeDsVYeJmvvUiK7avow0fjy+/EeKcyNBJcM2BFhj4XOAaaMbhGsOcIeSvJFouRWctXI7sKw=="
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.0.3.tgz",
"integrity": "sha512-K5YmUdohFCavPqEzG2cUPcZ6555KE1qwMDCjkvSUSz+s+8Wro2xfg+syLq90y6Tq0ZSUVvpuX6yq6ukToeGaLg=="
},
"node_modules/@vscode/vscode-languagedetection": {
"version": "1.0.21",
+2 -1
View File
@@ -6,12 +6,13 @@
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
"@parcel/watcher": "2.1.0",
"@bpasero/watcher": "https://github.com/bpasero/watcher.git#5d29cc732a03c91ecc2c861940a240b01e765c65",
"@vscode/deviceid": "^0.1.1",
"@vscode/iconv-lite-umd": "0.7.0",
"@vscode/proxy-agent": "^0.23.0",
"@vscode/ripgrep": "^1.15.9",
"@vscode/spdlog": "^0.15.0",
"@vscode/tree-sitter-wasm": "^0.0.2",
"@vscode/tree-sitter-wasm": "^0.0.3",
"@vscode/vscode-languagedetection": "1.0.21",
"@vscode/windows-process-tree": "^0.6.0",
"@vscode/windows-registry": "^1.1.0",
+4 -4
View File
@@ -11,7 +11,7 @@
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
"@vscode/iconv-lite-umd": "0.7.0",
"@vscode/tree-sitter-wasm": "^0.0.2",
"@vscode/tree-sitter-wasm": "^0.0.3",
"@vscode/vscode-languagedetection": "1.0.21",
"@xterm/addon-clipboard": "0.2.0-beta.39",
"@xterm/addon-image": "0.9.0-beta.56",
@@ -74,9 +74,9 @@
"integrity": "sha512-bRRFxLfg5dtAyl5XyiVWz/ZBPahpOpPrNYnnHpOpUZvam4tKH35wdhP4Kj6PbM0+KdliOsPzbGWpkxcdpNB/sg=="
},
"node_modules/@vscode/tree-sitter-wasm": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.0.2.tgz",
"integrity": "sha512-N57MR/kt4jR0H/TXeDsVYeJmvvUiK7avow0fjy+/EeKcyNBJcM2BFhj4XOAaaMbhGsOcIeSvJFouRWctXI7sKw=="
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.0.3.tgz",
"integrity": "sha512-K5YmUdohFCavPqEzG2cUPcZ6555KE1qwMDCjkvSUSz+s+8Wro2xfg+syLq90y6Tq0ZSUVvpuX6yq6ukToeGaLg=="
},
"node_modules/@vscode/vscode-languagedetection": {
"version": "1.0.21",
+1 -1
View File
@@ -6,7 +6,7 @@
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
"@vscode/iconv-lite-umd": "0.7.0",
"@vscode/tree-sitter-wasm": "^0.0.2",
"@vscode/tree-sitter-wasm": "^0.0.3",
"@vscode/vscode-languagedetection": "1.0.21",
"@xterm/addon-clipboard": "0.2.0-beta.39",
"@xterm/addon-image": "0.9.0-beta.56",
@@ -125,6 +125,9 @@ elif [ -z "$(ldd --version 2>&1 | grep 'musl libc')" ]; then
elif [ -f /usr/lib/libc.so.6 ]; then
# Typical path
libc_path='/usr/lib/libc.so.6'
elif [ -f /lib64/libc.so.6 ]; then
# Typical path (OpenSUSE)
libc_path='/lib64/libc.so.6'
elif [ -f /usr/lib64/libc.so.6 ]; then
# Typical path
libc_path='/usr/lib64/libc.so.6'
+2 -1
View File
@@ -10,11 +10,12 @@
"isolatedModules": false,
"outDir": "../out/vs",
"types": [
"@webgpu/types",
"mocha",
"semver",
"sinon",
"winreg",
"trusted-types",
"winreg",
"wicg-file-system-access"
],
"plugins": [
+1
View File
@@ -3,6 +3,7 @@
"compilerOptions": {
"noEmit": true,
"types": [
"@webgpu/types",
"trusted-types",
"wicg-file-system-access"
],
+6 -3
View File
@@ -93,15 +93,18 @@ function getWorkerBootstrapUrl(label: string, workerScriptUrl: string, workerBas
}
}
// In below blob code, we are using JSON.stringify to ensure the passed
// in values are not breaking our script. The values may contain string
// terminating characters (such as ' or ").
const blob = new Blob([coalesce([
`/*${label}*/`,
workerBaseUrl ? `globalThis.MonacoEnvironment = { baseUrl: '${workerBaseUrl}' };` : undefined,
workerBaseUrl ? `globalThis.MonacoEnvironment = { baseUrl: ${JSON.stringify(workerBaseUrl)} };` : undefined,
`globalThis._VSCODE_NLS_MESSAGES = ${JSON.stringify(getNLSMessages())};`,
`globalThis._VSCODE_NLS_LANGUAGE = ${JSON.stringify(getNLSLanguage())};`,
`globalThis._VSCODE_FILE_ROOT = '${globalThis._VSCODE_FILE_ROOT}';`,
`globalThis._VSCODE_FILE_ROOT = ${JSON.stringify(globalThis._VSCODE_FILE_ROOT)};`,
`const ttPolicy = globalThis.trustedTypes?.createPolicy('defaultWorkerFactory', { createScriptURL: value => value });`,
`globalThis.workerttPolicy = ttPolicy;`,
isESM ? `await import(ttPolicy?.createScriptURL('${workerScriptUrl}') ?? '${workerScriptUrl}');` : `importScripts(ttPolicy?.createScriptURL('${workerScriptUrl}') ?? '${workerScriptUrl}');`, //
isESM ? `await import(ttPolicy?.createScriptURL(${JSON.stringify(workerScriptUrl)}) ?? ${JSON.stringify(workerScriptUrl)});` : `importScripts(ttPolicy?.createScriptURL(${JSON.stringify(workerScriptUrl)}) ?? ${JSON.stringify(workerScriptUrl)});`,
isESM ? `globalThis.postMessage({ type: 'vscode-worker-ready' });` : undefined, // in ESM signal we are ready after the async import
`/*${label}*/`
]).join('')], { type: 'application/javascript' });
+2 -2
View File
@@ -1951,10 +1951,10 @@ const defaultDomPurifyConfig = Object.freeze<dompurify.Config & { RETURN_TRUSTED
/**
* Sanitizes the given `value` and reset the given `node` with it.
*/
export function safeInnerHtml(node: HTMLElement, value: string): void {
export function safeInnerHtml(node: HTMLElement, value: string, extraDomPurifyConfig?: dompurify.Config): void {
const hook = hookDomPurifyHrefAndSrcSanitizer(defaultSafeProtocols);
try {
const html = dompurify.sanitize(value, defaultDomPurifyConfig);
const html = dompurify.sanitize(value, { ...defaultDomPurifyConfig, ...extraDomPurifyConfig });
node.innerHTML = html as unknown as string;
} finally {
hook.dispose();
+2 -3
View File
@@ -545,9 +545,8 @@ export function renderMarkdownAsPlaintext(markdown: IMarkdownString, withCodeBlo
value = `${value.substr(0, 100_000)}`;
}
const html = marked.parse(value, { async: false, renderer: withCodeBlocks ? plainTextWithCodeBlocksRenderer.value : plainTextRenderer.value }).replace(/&(#\d+|[a-zA-Z]+);/g, m => unescapeInfo.get(m) ?? m);
return sanitizeRenderedMarkdown({ isTrusted: false }, html).toString();
const html = marked.parse(value, { async: false, renderer: withCodeBlocks ? plainTextWithCodeBlocksRenderer.value : plainTextRenderer.value });
return sanitizeRenderedMarkdown({ isTrusted: false }, html).toString().replace(/&(#\d+|[a-zA-Z]+);/g, m => unescapeInfo.get(m) ?? m);
}
const unescapeInfo = new Map<string, string>([
+2 -2
View File
@@ -892,7 +892,7 @@ export class DefaultStyleController implements IStyleController {
}
if (styles.listActiveSelectionIconForeground) {
content.push(`.monaco-list${suffix}:focus .monaco-list-row.selected .codicon { color: ${styles.listActiveSelectionIconForeground}; }`);
content.push(`@layer monaco-list { .monaco-list${suffix}:focus .monaco-list-row.selected .codicon { color: ${styles.listActiveSelectionIconForeground}; } }`);
}
if (styles.listFocusAndSelectionBackground) {
@@ -915,7 +915,7 @@ export class DefaultStyleController implements IStyleController {
}
if (styles.listInactiveSelectionIconForeground) {
content.push(`.monaco-list${suffix} .monaco-list-row.focused .codicon { color: ${styles.listInactiveSelectionIconForeground}; }`);
content.push(`@layer monaco-list { .monaco-list${suffix} .monaco-list-row.focused .codicon { color: ${styles.listInactiveSelectionIconForeground}; } }`);
}
if (styles.listInactiveFocusBackground) {
@@ -3144,6 +3144,10 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
this.renderers.forEach(r => r.setModel(newModel));
this.stickyScrollController?.setModel(newModel);
this.focus.set([]);
this.selection.set([]);
this.anchor.set([]);
this.view.splice(0, oldModel.getListRenderCount(oldModel.rootRef));
this.model.refilter();
+1 -1
View File
@@ -32,7 +32,7 @@ export function groupBy<K extends string | number | symbol, V>(data: V[], groupF
return result;
}
export function diffSets<T>(before: Set<T>, after: Set<T>): { removed: T[]; added: T[] } {
export function diffSets<T>(before: ReadonlySet<T>, after: ReadonlySet<T>): { removed: T[]; added: T[] } {
const removed: T[] = [];
const added: T[] = [];
for (const element of before) {
+28 -1
View File
@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { CancellationToken } from './cancellation.js';
import { diffSets } from './collections.js';
import { onUnexpectedError } from './errors.js';
import { createSingleCallFunction } from './functional.js';
import { combinedDisposable, Disposable, DisposableMap, DisposableStore, IDisposable, toDisposable } from './lifecycle.js';
@@ -12,7 +13,6 @@ import { IObservable, IObserver } from './observable.js';
import { StopWatch } from './stopwatch.js';
import { MicrotaskDelay } from './symbols.js';
// -----------------------------------------------------------------------------------------------------------------------
// Uncomment the next line to print warnings whenever a listener is GC'ed without having been disposed. This is a LEAK.
// -----------------------------------------------------------------------------------------------------------------------
@@ -1791,3 +1791,30 @@ class ConstValueWithChangeEvent<T> implements IValueWithChangeEvent<T> {
constructor(readonly value: T) { }
}
/**
* @param handleItem Is called for each item in the set (but only the first time the item is seen in the set).
* The returned disposable is disposed if the item is no longer in the set.
*/
export function trackSetChanges<T>(getData: () => ReadonlySet<T>, onDidChangeData: Event<unknown>, handleItem: (d: T) => IDisposable): IDisposable {
const map = new DisposableMap<T, IDisposable>();
let oldData = new Set(getData());
for (const d of oldData) {
map.set(d, handleItem(d));
}
const store = new DisposableStore();
store.add(onDidChangeData(() => {
const newData = getData();
const diff = diffSets(oldData, newData);
for (const r of diff.removed) {
map.deleteAndDispose(r);
}
for (const a of diff.added) {
map.set(a, handleItem(a));
}
oldData = new Set(newData);
}));
store.add(map);
return store;
}
+5 -1
View File
@@ -6,8 +6,12 @@
import { IDisposable } from './lifecycle.js';
import { env } from './process.js';
function hotReloadDisabled() {
return true; // TODO@hediet fix hot reload.
}
export function isHotReloadEnabled(): boolean {
return env && !!env['VSCODE_DEV'];
return !hotReloadDisabled() && env && !!env['VSCODE_DEV'];
}
export function registerHotReloadHandler(handler: HotReloadHandler): IDisposable {
if (!isHotReloadEnabled()) {
+57
View File
@@ -875,3 +875,60 @@ export function mapsStrictEqualIgnoreOrder(a: Map<unknown, unknown>, b: Map<unkn
return true;
}
/**
* A map that is addressable with 2 separate keys. This is useful in high performance scenarios
* where creating a composite key is too expensive.
*/
export class TwoKeyMap<TFirst extends string | number, TSecond extends string | number, TValue> {
private _data: { [key: string | number]: { [key: string | number]: TValue | undefined } | undefined } = {};
public set(first: TFirst, second: TSecond, value: TValue): void {
if (!this._data[first]) {
this._data[first] = {};
}
this._data[first as string | number]![second] = value;
}
public get(first: TFirst, second: TSecond): TValue | undefined {
return this._data[first as string | number]?.[second];
}
public clear(): void {
this._data = {};
}
public *values(): IterableIterator<TValue> {
for (const first in this._data) {
for (const second in this._data[first]) {
const value = this._data[first]![second];
if (value) {
yield value;
}
}
}
}
}
/**
* A map that is addressable with 4 separate keys. This is useful in high performance scenarios
* where creating a composite key is too expensive.
*/
export class FourKeyMap<TFirst extends string | number, TSecond extends string | number, TThird extends string | number, TFourth extends string | number, TValue> {
private _data: TwoKeyMap<TFirst, TSecond, TwoKeyMap<TThird, TFourth, TValue>> = new TwoKeyMap();
public set(first: TFirst, second: TSecond, third: TThird, fourth: TFourth, value: TValue): void {
if (!this._data.get(first, second)) {
this._data.set(first, second, new TwoKeyMap());
}
this._data.get(first, second)!.set(third, fourth, value);
}
public get(first: TFirst, second: TSecond, third: TThird, fourth: TFourth): TValue | undefined {
return this._data.get(first, second)?.get(third, fourth);
}
public clear(): void {
this._data.clear();
}
}
+1 -69
View File
@@ -5,72 +5,4 @@
// This is a facade for the observable implementation. Only import from here!
export type {
IObservable,
IObserver,
IReader,
ISettable,
ISettableObservable,
ITransaction,
IChangeContext,
IChangeTracker,
} from './observableInternal/base.js';
export {
observableValue,
disposableObservableValue,
transaction,
subtransaction,
} from './observableInternal/base.js';
export {
derived,
derivedOpts,
derivedHandleChanges,
derivedWithStore,
} from './observableInternal/derived.js';
export {
autorun,
autorunDelta,
autorunHandleChanges,
autorunWithStore,
autorunOpts,
autorunWithStoreHandleChanges,
} from './observableInternal/autorun.js';
export type {
IObservableSignal,
} from './observableInternal/utils.js';
export {
constObservable,
debouncedObservable,
derivedObservableWithCache,
derivedObservableWithWritableCache,
keepObserved,
recomputeInitiallyAndOnChange,
observableFromEvent,
observableFromPromise,
observableSignal,
observableSignalFromEvent,
wasEventTriggeredRecently,
} from './observableInternal/utils.js';
export {
ObservableLazy,
ObservableLazyPromise,
ObservablePromise,
PromiseResult,
waitForState,
derivedWithCancellationToken,
} from './observableInternal/promise.js';
export {
observableValueOpts
} from './observableInternal/api.js';
import { ConsoleObservableLogger, setLogger } from './observableInternal/logging.js';
// Remove "//" in the next line to enable logging
const enableLogging = false
// || Boolean("true") // done "weirdly" so that a lint warning prevents you from pushing this
;
if (enableLogging) {
setLogger(new ConsoleObservableLogger());
}
export * from './observableInternal/index.js';
+3 -4
View File
@@ -3,10 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { EqualityComparer, strictEquals } from '../equals.js';
import { ISettableObservable } from '../observable.js';
import { ObservableValue } from './base.js';
import { IDebugNameData, DebugNameData } from './debugName.js';
import { ISettableObservable, ObservableValue } from './base.js';
import { DebugNameData, IDebugNameData } from './debugName.js';
import { EqualityComparer, strictEquals } from './commonFacade/deps.js';
import { LazyObservableValue } from './lazyObservableValue.js';
export function observableValueOpts<T, TChange = void>(
@@ -3,11 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { assertFn } from '../assert.js';
import { onBugIndicatingError } from '../errors.js';
import { DisposableStore, IDisposable, markAsDisposed, toDisposable, trackDisposable } from '../lifecycle.js';
import { IChangeContext, IObservable, IObserver, IReader } from './base.js';
import { DebugNameData, IDebugNameData } from './debugName.js';
import { assertFn, DisposableStore, IDisposable, markAsDisposed, onBugIndicatingError, toDisposable, trackDisposable } from './commonFacade/deps.js';
import { getLogger } from './logging.js';
/**
@@ -3,12 +3,11 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { strictEquals, EqualityComparer } from '../equals.js';
import { DisposableStore, IDisposable } from '../lifecycle.js';
import { keepObserved, recomputeInitiallyAndOnChange } from '../observable.js';
import { DebugNameData, DebugOwner, getFunctionName } from './debugName.js';
import { DisposableStore, EqualityComparer, IDisposable, strictEquals } from './commonFacade/deps.js';
import type { derivedOpts } from './derived.js';
import { getLogger } from './logging.js';
import { keepObserved, recomputeInitiallyAndOnChange } from './utils.js';
/**
* Represents an observable value.
@@ -3,10 +3,5 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.chat-inline-file-link-widget .monaco-icon-label {
display: inline-flex;
}
.chat-inline-file-link-widget .monaco-icon-label .monaco-highlighted-label {
white-space: normal;
}
export { CancellationError } from '../../errors.js';
export { CancellationToken, CancellationTokenSource } from '../../cancellation.js';
@@ -0,0 +1,10 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export { assertFn } from '../../assert.js';
export { type EqualityComparer, strictEquals } from '../../equals.js';
export { BugIndicatingError, onBugIndicatingError } from '../../errors.js';
export { Event, type IValueWithChangeEvent } from '../../event.js';
export { DisposableStore, type IDisposable, markAsDisposed, toDisposable, trackDisposable } from '../../lifecycle.js';
@@ -3,12 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { assertFn } from '../assert.js';
import { EqualityComparer, strictEquals } from '../equals.js';
import { onBugIndicatingError } from '../errors.js';
import { DisposableStore, IDisposable } from '../lifecycle.js';
import { BaseObservable, IChangeContext, IObservable, IObserver, IReader, ISettableObservable, ITransaction, _setDerivedOpts, } from './base.js';
import { DebugNameData, IDebugNameData, DebugOwner } from './debugName.js';
import { DebugNameData, DebugOwner, IDebugNameData } from './debugName.js';
import { DisposableStore, EqualityComparer, IDisposable, assertFn, onBugIndicatingError, strictEquals } from './commonFacade/deps.js';
import { getLogger } from './logging.js';
/**
@@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// This is a facade for the observable implementation. Only import from here!
export { observableValueOpts } from './api.js';
export { autorun, autorunDelta, autorunHandleChanges, autorunOpts, autorunWithStore, autorunWithStoreHandleChanges } from './autorun.js';
export { asyncTransaction, disposableObservableValue, globalTransaction, observableValue, subtransaction, transaction, TransactionImpl, type IChangeContext, type IChangeTracker, type IObservable, type IObserver, type IReader, type ISettable, type ISettableObservable, type ITransaction, } from './base.js';
export { derived, derivedDisposable, derivedHandleChanges, derivedOpts, derivedWithSetter, derivedWithStore } from './derived.js';
export { ObservableLazy, ObservableLazyPromise, ObservablePromise, PromiseResult, } from './promise.js';
export { derivedWithCancellationToken, waitForState } from './utilsCancellation.js';
export { constObservable, debouncedObservable, derivedConstOnceDefined, derivedObservableWithCache, derivedObservableWithWritableCache, keepObserved, latestChangedValue, mapObservableArrayCached, observableFromEvent, observableFromEventOpts, observableFromPromise, observableFromValueWithChangeEvent, observableSignal, observableSignalFromEvent, recomputeInitiallyAndOnChange, runOnChange, runOnChangeWithStore, signalFromObservable, ValueWithChangeEventFromObservable, wasEventTriggeredRecently, type IObservableSignal, } from './utils.js';
export { type DebugOwner } from './debugName.js';
import {
ConsoleObservableLogger,
setLogger
} from './logging.js';
// Remove "//" in the next line to enable logging
const enableLogging = false
// || Boolean("true") // done "weirdly" so that a lint warning prevents you from pushing this
;
if (enableLogging) {
setLogger(new ConsoleObservableLogger());
}
@@ -3,9 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { EqualityComparer } from '../equals.js';
import { ISettableObservable, ITransaction } from '../observable.js';
import { BaseObservable, IObserver, TransactionImpl } from './base.js';
import { EqualityComparer } from './commonFacade/deps.js';
import { BaseObservable, IObserver, ISettableObservable, ITransaction, TransactionImpl } from './base.js';
import { DebugNameData } from './debugName.js';
/**
@@ -2,13 +2,8 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { autorun } from './autorun.js';
import { IObservable, IReader, observableValue, transaction } from './base.js';
import { Derived, derived } from './derived.js';
import { CancellationToken, CancellationTokenSource } from '../cancellation.js';
import { DebugNameData, DebugOwner } from './debugName.js';
import { strictEquals } from '../equals.js';
import { CancellationError } from '../errors.js';
import { IObservable, observableValue, transaction } from './base.js';
import { derived } from './derived.js';
export class ObservableLazy<T> {
private readonly _value = observableValue<T | undefined>(this, undefined);
@@ -120,90 +115,3 @@ export class ObservableLazyPromise<T> {
return this._lazyValue.getValue().promise;
}
}
/**
* Resolves the promise when the observables state matches the predicate.
*/
export function waitForState<T>(observable: IObservable<T | null | undefined>): Promise<T>;
export function waitForState<T, TState extends T>(observable: IObservable<T>, predicate: (state: T) => state is TState, isError?: (state: T) => boolean | unknown | undefined, cancellationToken?: CancellationToken): Promise<TState>;
export function waitForState<T>(observable: IObservable<T>, predicate: (state: T) => boolean, isError?: (state: T) => boolean | unknown | undefined, cancellationToken?: CancellationToken): Promise<T>;
export function waitForState<T>(observable: IObservable<T>, predicate?: (state: T) => boolean, isError?: (state: T) => boolean | unknown | undefined, cancellationToken?: CancellationToken): Promise<T> {
if (!predicate) {
predicate = state => state !== null && state !== undefined;
}
return new Promise((resolve, reject) => {
let isImmediateRun = true;
let shouldDispose = false;
const stateObs = observable.map(state => {
/** @description waitForState.state */
return {
isFinished: predicate(state),
error: isError ? isError(state) : false,
state
};
});
const d = autorun(reader => {
/** @description waitForState */
const { isFinished, error, state } = stateObs.read(reader);
if (isFinished || error) {
if (isImmediateRun) {
// The variable `d` is not initialized yet
shouldDispose = true;
} else {
d.dispose();
}
if (error) {
reject(error === true ? state : error);
} else {
resolve(state);
}
}
});
if (cancellationToken) {
const dc = cancellationToken.onCancellationRequested(() => {
d.dispose();
dc.dispose();
reject(new CancellationError());
});
if (cancellationToken.isCancellationRequested) {
d.dispose();
dc.dispose();
reject(new CancellationError());
return;
}
}
isImmediateRun = false;
if (shouldDispose) {
d.dispose();
}
});
}
export function derivedWithCancellationToken<T>(computeFn: (reader: IReader, cancellationToken: CancellationToken) => T): IObservable<T>;
export function derivedWithCancellationToken<T>(owner: object, computeFn: (reader: IReader, cancellationToken: CancellationToken) => T): IObservable<T>;
export function derivedWithCancellationToken<T>(computeFnOrOwner: ((reader: IReader, cancellationToken: CancellationToken) => T) | object, computeFnOrUndefined?: ((reader: IReader, cancellationToken: CancellationToken) => T)): IObservable<T> {
let computeFn: (reader: IReader, store: CancellationToken) => T;
let owner: DebugOwner;
if (computeFnOrUndefined === undefined) {
computeFn = computeFnOrOwner as any;
owner = undefined;
} else {
owner = computeFnOrOwner;
computeFn = computeFnOrUndefined as any;
}
let cancellationTokenSource: CancellationTokenSource | undefined = undefined;
return new Derived(
new DebugNameData(owner, undefined, computeFn),
r => {
if (cancellationTokenSource) {
cancellationTokenSource.dispose(true);
}
cancellationTokenSource = new CancellationTokenSource();
return computeFn(r, cancellationTokenSource.token);
}, undefined,
undefined,
() => cancellationTokenSource?.dispose(),
strictEquals,
);
}
+19 -10
View File
@@ -3,15 +3,12 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event, IValueWithChangeEvent } from '../event.js';
import { DisposableStore, IDisposable, toDisposable } from '../lifecycle.js';
import { autorun, autorunOpts, autorunWithStoreHandleChanges } from './autorun.js';
import { BaseObservable, ConvenientObservable, IObservable, IObserver, IReader, ITransaction, _setKeepObserved, _setRecomputeInitiallyAndOnChange, observableValue, subtransaction, transaction } from './base.js';
import { DebugNameData, IDebugNameData, DebugOwner, getDebugName, } from './debugName.js';
import { DebugNameData, DebugOwner, IDebugNameData, getDebugName, } from './debugName.js';
import { BugIndicatingError, DisposableStore, EqualityComparer, Event, IDisposable, IValueWithChangeEvent, strictEquals, toDisposable } from './commonFacade/deps.js';
import { derived, derivedOpts } from './derived.js';
import { getLogger } from './logging.js';
import { BugIndicatingError } from '../errors.js';
import { EqualityComparer, strictEquals } from '../equals.js';
/**
* Represents an efficient observable whose value never changes.
@@ -301,6 +298,15 @@ class ObservableSignal<TChange> extends BaseObservable<void, TChange> implements
}
}
export function signalFromObservable<T>(owner: DebugOwner | undefined, observable: IObservable<T>): IObservable<void> {
return derivedOpts({
owner,
equalsFn: () => false,
}, reader => {
observable.read(reader);
});
}
/**
* @deprecated Use `debouncedObservable2` instead.
*/
@@ -619,7 +625,8 @@ export function derivedConstOnceDefined<T>(owner: DebugOwner, fn: (reader: IRead
type RemoveUndefined<T> = T extends undefined ? never : T;
export function runOnChange<T, TChange>(observable: IObservable<T, TChange>, cb: (value: T, deltas: RemoveUndefined<TChange>[]) => void): IDisposable {
export function runOnChange<T, TChange>(observable: IObservable<T, TChange>, cb: (value: T, previousValue: undefined | T, deltas: RemoveUndefined<TChange>[]) => void): IDisposable {
let _previousValue: T | undefined;
return autorunWithStoreHandleChanges({
createEmptyChangeSummary: () => ({ deltas: [] as RemoveUndefined<TChange>[], didChange: false }),
handleChange: (context, changeSummary) => {
@@ -634,17 +641,19 @@ export function runOnChange<T, TChange>(observable: IObservable<T, TChange>, cb:
},
}, (reader, changeSummary) => {
const value = observable.read(reader);
const previousValue = _previousValue;
if (changeSummary.didChange) {
cb(value, changeSummary.deltas);
_previousValue = value;
cb(value, previousValue, changeSummary.deltas);
}
});
}
export function runOnChangeWithStore<T, TChange>(observable: IObservable<T, TChange>, cb: (value: T, deltas: RemoveUndefined<TChange>[], store: DisposableStore) => void): IDisposable {
export function runOnChangeWithStore<T, TChange>(observable: IObservable<T, TChange>, cb: (value: T, previousValue: undefined | T, deltas: RemoveUndefined<TChange>[], store: DisposableStore) => void): IDisposable {
const store = new DisposableStore();
const disposable = runOnChange(observable, (value, deltas) => {
const disposable = runOnChange(observable, (value, previousValue: undefined | T, deltas) => {
store.clear();
cb(value, deltas, store);
cb(value, previousValue, deltas, store);
});
return {
dispose() {
@@ -0,0 +1,98 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IReader, IObservable } from './base.js';
import { DebugOwner, DebugNameData } from './debugName.js';
import { CancellationError, CancellationToken, CancellationTokenSource } from './commonFacade/cancellation.js';
import { Derived } from './derived.js';
import { strictEquals } from './commonFacade/deps.js';
import { autorun } from './autorun.js';
/**
* Resolves the promise when the observables state matches the predicate.
*/
export function waitForState<T>(observable: IObservable<T | null | undefined>): Promise<T>;
export function waitForState<T, TState extends T>(observable: IObservable<T>, predicate: (state: T) => state is TState, isError?: (state: T) => boolean | unknown | undefined, cancellationToken?: CancellationToken): Promise<TState>;
export function waitForState<T>(observable: IObservable<T>, predicate: (state: T) => boolean, isError?: (state: T) => boolean | unknown | undefined, cancellationToken?: CancellationToken): Promise<T>;
export function waitForState<T>(observable: IObservable<T>, predicate?: (state: T) => boolean, isError?: (state: T) => boolean | unknown | undefined, cancellationToken?: CancellationToken): Promise<T> {
if (!predicate) {
predicate = state => state !== null && state !== undefined;
}
return new Promise((resolve, reject) => {
let isImmediateRun = true;
let shouldDispose = false;
const stateObs = observable.map(state => {
/** @description waitForState.state */
return {
isFinished: predicate(state),
error: isError ? isError(state) : false,
state
};
});
const d = autorun(reader => {
/** @description waitForState */
const { isFinished, error, state } = stateObs.read(reader);
if (isFinished || error) {
if (isImmediateRun) {
// The variable `d` is not initialized yet
shouldDispose = true;
} else {
d.dispose();
}
if (error) {
reject(error === true ? state : error);
} else {
resolve(state);
}
}
});
if (cancellationToken) {
const dc = cancellationToken.onCancellationRequested(() => {
d.dispose();
dc.dispose();
reject(new CancellationError());
});
if (cancellationToken.isCancellationRequested) {
d.dispose();
dc.dispose();
reject(new CancellationError());
return;
}
}
isImmediateRun = false;
if (shouldDispose) {
d.dispose();
}
});
}
export function derivedWithCancellationToken<T>(computeFn: (reader: IReader, cancellationToken: CancellationToken) => T): IObservable<T>;
export function derivedWithCancellationToken<T>(owner: object, computeFn: (reader: IReader, cancellationToken: CancellationToken) => T): IObservable<T>;
export function derivedWithCancellationToken<T>(computeFnOrOwner: ((reader: IReader, cancellationToken: CancellationToken) => T) | object, computeFnOrUndefined?: ((reader: IReader, cancellationToken: CancellationToken) => T)): IObservable<T> {
let computeFn: (reader: IReader, store: CancellationToken) => T;
let owner: DebugOwner;
if (computeFnOrUndefined === undefined) {
computeFn = computeFnOrOwner as any;
owner = undefined;
} else {
owner = computeFnOrOwner;
computeFn = computeFnOrUndefined as any;
}
let cancellationTokenSource: CancellationTokenSource | undefined = undefined;
return new Derived(
new DebugNameData(owner, undefined, computeFn),
r => {
if (cancellationTokenSource) {
cancellationTokenSource.dispose(true);
}
cancellationTokenSource = new CancellationTokenSource();
return computeFn(r, cancellationTokenSource.token);
}, undefined,
undefined,
() => cancellationTokenSource?.dispose(),
strictEquals
);
}
+62 -2
View File
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import assert from 'assert';
import { BidirectionalMap, LinkedMap, LRUCache, mapsStrictEqualIgnoreOrder, MRUCache, ResourceMap, SetMap, Touch } from '../../common/map.js';
import { BidirectionalMap, FourKeyMap, LinkedMap, LRUCache, mapsStrictEqualIgnoreOrder, MRUCache, ResourceMap, SetMap, Touch, TwoKeyMap } from '../../common/map.js';
import { extUriIgnorePathCase } from '../../common/resources.js';
import { URI } from '../../common/uri.js';
import { ensureNoDisposablesAreLeakedInTestSuite } from './utils.js';
@@ -681,5 +681,65 @@ suite('SetMap', () => {
const setMap = new SetMap<string, number>();
assert.deepStrictEqual([...setMap.get('a')], []);
});
});
suite('TwoKeyMap', () => {
ensureNoDisposablesAreLeakedInTestSuite();
test('set and get', () => {
const map = new TwoKeyMap<string, string, number>();
map.set('a', 'b', 1);
map.set('a', 'c', 2);
map.set('b', 'c', 3);
assert.strictEqual(map.get('a', 'b'), 1);
assert.strictEqual(map.get('a', 'c'), 2);
assert.strictEqual(map.get('b', 'c'), 3);
assert.strictEqual(map.get('a', 'd'), undefined);
});
test('clear', () => {
const map = new TwoKeyMap<string, string, number>();
map.set('a', 'b', 1);
map.set('a', 'c', 2);
map.set('b', 'c', 3);
map.clear();
assert.strictEqual(map.get('a', 'b'), undefined);
assert.strictEqual(map.get('a', 'c'), undefined);
assert.strictEqual(map.get('b', 'c'), undefined);
});
test('values', () => {
const map = new TwoKeyMap<string, string, number>();
map.set('a', 'b', 1);
map.set('a', 'c', 2);
map.set('b', 'c', 3);
assert.deepStrictEqual(Array.from(map.values()), [1, 2, 3]);
});
});
suite('FourKeyMap', () => {
ensureNoDisposablesAreLeakedInTestSuite();
test('set and get', () => {
const map = new FourKeyMap<string, string, string, string, number>();
map.set('a', 'b', 'c', 'd', 1);
map.set('a', 'c', 'c', 'd', 2);
map.set('b', 'e', 'f', 'g', 3);
assert.strictEqual(map.get('a', 'b', 'c', 'd'), 1);
assert.strictEqual(map.get('a', 'c', 'c', 'd'), 2);
assert.strictEqual(map.get('b', 'e', 'f', 'g'), 3);
assert.strictEqual(map.get('a', 'b', 'c', 'a'), undefined);
});
test('clear', () => {
const map = new FourKeyMap<string, string, string, string, number>();
map.set('a', 'b', 'c', 'd', 1);
map.set('a', 'c', 'c', 'd', 2);
map.set('b', 'e', 'f', 'g', 3);
map.clear();
assert.strictEqual(map.get('a', 'b', 'c', 'd'), undefined);
assert.strictEqual(map.get('a', 'c', 'c', 'd'), undefined);
assert.strictEqual(map.get('b', 'e', 'f', 'g'), undefined);
});
});
+3 -4
View File
@@ -4,13 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import assert from 'assert';
import { setUnexpectedErrorHandler } from '../../common/errors.js';
import { Emitter, Event } from '../../common/event.js';
import { DisposableStore } from '../../common/lifecycle.js';
import { ISettableObservable, autorun, derived, ITransaction, observableFromEvent, observableValue, transaction, keepObserved, waitForState, autorunHandleChanges, observableSignal } from '../../common/observable.js';
import { BaseObservable, IObservable, IObserver } from '../../common/observableInternal/base.js';
import { derivedDisposable } from '../../common/observableInternal/derived.js';
import { autorun, autorunHandleChanges, derived, derivedDisposable, IObservable, IObserver, ISettableObservable, ITransaction, keepObserved, observableFromEvent, observableSignal, observableValue, transaction, waitForState } from '../../common/observable.js';
import { BaseObservable } from '../../common/observableInternal/base.js';
import { ensureNoDisposablesAreLeakedInTestSuite } from './utils.js';
import { setUnexpectedErrorHandler } from '../../common/errors.js';
suite('observables', () => {
const ds = ensureNoDisposablesAreLeakedInTestSuite();
+1 -5
View File
@@ -211,11 +211,7 @@ class CodeMain {
services.set(ILifecycleMainService, new SyncDescriptor(LifecycleMainService, undefined, false));
// Request
const networkLogger = loggerService.createLogger('network-main', {
name: localize('network-main', "Network (Main)"),
hidden: true
});
services.set(IRequestService, new SyncDescriptor(RequestService, [networkLogger], true));
services.set(IRequestService, new SyncDescriptor(RequestService, undefined, true));
// Themes
services.set(IThemeMainService, new SyncDescriptor(ThemeMainService));
@@ -270,11 +270,7 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter {
]);
// Request
const networkLogger = loggerService.createLogger('network-shared', {
name: localize('network-shared', "Network (Shared)"),
hidden: true,
});
const requestService = new RequestService(networkLogger, configurationService, environmentService, logService);
const requestService = new RequestService(configurationService, environmentService, logService);
services.set(IRequestService, requestService);
// Checksum
+1 -1
View File
@@ -117,7 +117,7 @@ export async function main(argv: string[]): Promise<any> {
// Extensions Management
else if (shouldSpawnCliProcess(args)) {
const cli = await import(['vs', 'code', 'node', 'cliProcessMain'].join('/') /* TODO@esm workaround to prevent esbuild from inlining this */);
const cli = await import(['./cliProcessMain.js'].join('/') /* TODO@esm workaround to prevent esbuild from inlining this */);
await cli.main(args);
return;

Some files were not shown because too many files have changed in this diff Show More