mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
Merge branch 'main' into copilot/add-terminal-profile-for-agent
This commit is contained in:
@@ -1,76 +0,0 @@
|
||||
{
|
||||
"hydrated": false,
|
||||
"properties": {
|
||||
"helpUri": "https://eng.ms/docs/microsoft-security/security/azure-security/cloudai-security-fundamentals-engineering/security-integration/guardian-wiki/microsoft-guardian/general/suppressions"
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"suppressionSets": {
|
||||
"default": {
|
||||
"name": "default",
|
||||
"createdDate": "2025-03-17 11:52:32Z",
|
||||
"lastUpdatedDate": "2025-08-06 13:58:56Z"
|
||||
}
|
||||
},
|
||||
"results": {
|
||||
"216e2ac9cb596796224b47799f656570a01fa0d9b5f935608b47d15ab613c8e8": {
|
||||
"signature": "216e2ac9cb596796224b47799f656570a01fa0d9b5f935608b47d15ab613c8e8",
|
||||
"alternativeSignatures": [
|
||||
"07746898f43afab7cc50931b33154c2d9e1a35f82a649dbe8aecf785b3d5a813"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2025-03-17 11:52:32Z"
|
||||
},
|
||||
"77797a3e44634bb2994bd13ccc95ff4575bba474585dbd2cf3068a1c16bc0624": {
|
||||
"signature": "77797a3e44634bb2994bd13ccc95ff4575bba474585dbd2cf3068a1c16bc0624",
|
||||
"alternativeSignatures": [
|
||||
"4a6cb67bd4b401e9669c13a2162660aaefc0a94a4122e5b50c198414db545672"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2025-03-17 11:52:32Z"
|
||||
},
|
||||
"30418bcc5269eaeb2832a2404465784431d4e72a2af332320c2b1db4768902ad": {
|
||||
"signature": "30418bcc5269eaeb2832a2404465784431d4e72a2af332320c2b1db4768902ad",
|
||||
"alternativeSignatures": [
|
||||
"b7b9eb974d7d3a4ae14df8695ca5a62592c8c9d20b7eda70a6535d50cbda3e7f"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2025-03-17 11:52:32Z"
|
||||
},
|
||||
"9d60fae9db4b8d511637e4a0f902820fbabf962c64ce2b2b8c8ae54c0c06d3ab": {
|
||||
"signature": "9d60fae9db4b8d511637e4a0f902820fbabf962c64ce2b2b8c8ae54c0c06d3ab",
|
||||
"alternativeSignatures": [
|
||||
"d06382c4909cfa81370526b06d4c47ebdf4425fc0b36053d3f457d5cdf5df8a8"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2025-08-06 13:58:56Z"
|
||||
},
|
||||
"7f0626fd14d60d2810a8ddfc1e9fdf1563b991dc8e1ac5880eca42449f752e90": {
|
||||
"signature": "7f0626fd14d60d2810a8ddfc1e9fdf1563b991dc8e1ac5880eca42449f752e90",
|
||||
"alternativeSignatures": [
|
||||
"6d3dc1d67e5413347520202ce038daf52825c58099670688103db2661facf187"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2025-08-06 13:58:56Z"
|
||||
},
|
||||
"40121a40ac42fef69ebcb2b8c2ec7ee659c8d10bc7ab4e95d2a290a48b3d281f": {
|
||||
"signature": "40121a40ac42fef69ebcb2b8c2ec7ee659c8d10bc7ab4e95d2a290a48b3d281f",
|
||||
"alternativeSignatures": [
|
||||
"3f4bc3f870aa2c71232dd65907522d59a1964c148e373105dec71e0d3da9427f"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2025-08-06 13:58:56Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
**/extensions/markdown-language-features/media/**
|
||||
**/extensions/markdown-language-features/notebook-out/**
|
||||
**/extensions/markdown-math/notebook-out/**
|
||||
**/extensions/mermaid-chat-features/chat-webview-out/**
|
||||
**/extensions/notebook-renderers/renderer-out/index.js
|
||||
**/extensions/simple-browser/media/index.js
|
||||
**/extensions/terminal-suggest/src/completions/upstream/**
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as eslint from 'eslint';
|
||||
import { TSESTree } from '@typescript-eslint/utils';
|
||||
import * as ESTree from 'estree';
|
||||
import * as visitorKeys from 'eslint-visitor-keys';
|
||||
|
||||
export = new class NoObservableGetInReactiveContext implements eslint.Rule.RuleModule {
|
||||
meta: eslint.Rule.RuleMetaData = {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Disallow calling .get() on observables inside reactive contexts in favor of .read(undefined).',
|
||||
},
|
||||
fixable: 'code',
|
||||
};
|
||||
|
||||
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
|
||||
return {
|
||||
'CallExpression': (node: any) => {
|
||||
const callExpression = node as TSESTree.CallExpression;
|
||||
|
||||
if (!isReactiveFunctionWithReader(callExpression.callee)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const functionArg = callExpression.arguments.find(arg =>
|
||||
arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression'
|
||||
) as TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression | undefined;
|
||||
|
||||
if (!functionArg) {
|
||||
return;
|
||||
}
|
||||
|
||||
const readerName = getReaderParameterName(functionArg);
|
||||
if (!readerName) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkFunctionForObservableGetCalls(functionArg, readerName, context);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function checkFunctionForObservableGetCalls(
|
||||
fn: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,
|
||||
readerName: string,
|
||||
context: eslint.Rule.RuleContext
|
||||
) {
|
||||
const visited = new Set<TSESTree.Node>();
|
||||
|
||||
function traverse(node: TSESTree.Node) {
|
||||
if (visited.has(node)) {
|
||||
return;
|
||||
}
|
||||
visited.add(node);
|
||||
|
||||
if (node.type === 'CallExpression' && isObservableGetCall(node)) {
|
||||
// Flag .get() calls since we're always in a reactive context here
|
||||
context.report({
|
||||
node: node as any as ESTree.Node,
|
||||
message: `Observable '.get()' should not be used in reactive context. Use '.read(${readerName})' instead to properly track dependencies or '.read(undefined)' to be explicit about an untracked read.`,
|
||||
fix: (fixer) => {
|
||||
const memberExpression = node.callee as TSESTree.MemberExpression;
|
||||
return fixer.replaceText(node as any, `${context.getSourceCode().getText(memberExpression.object as any)}.read(undefined)`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
walkChildren(node, traverse);
|
||||
}
|
||||
|
||||
if (fn.body) {
|
||||
traverse(fn.body);
|
||||
}
|
||||
}
|
||||
|
||||
function isObservableGetCall(node: TSESTree.CallExpression): boolean {
|
||||
// Look for pattern: something.get()
|
||||
if (node.callee.type === 'MemberExpression' &&
|
||||
node.callee.property.type === 'Identifier' &&
|
||||
node.callee.property.name === 'get' &&
|
||||
node.arguments.length === 0) {
|
||||
|
||||
// This is a .get() call with no arguments, which is likely an observable
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const reactiveFunctions = new Set([
|
||||
'derived',
|
||||
'derivedDisposable',
|
||||
'derivedHandleChanges',
|
||||
'derivedOpts',
|
||||
'derivedWithSetter',
|
||||
'derivedWithStore',
|
||||
'autorun',
|
||||
'autorunOpts',
|
||||
'autorunHandleChanges',
|
||||
'autorunSelfDisposable',
|
||||
'autorunDelta',
|
||||
'autorunWithStore',
|
||||
'autorunWithStoreHandleChanges',
|
||||
'autorunIterableDelta'
|
||||
]);
|
||||
|
||||
function getReaderParameterName(fn: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression): string | null {
|
||||
if (fn.params.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const firstParam = fn.params[0];
|
||||
if (firstParam.type === 'Identifier') {
|
||||
// Accept any parameter name as a potential reader parameter
|
||||
// since reactive functions should always have the reader as the first parameter
|
||||
return firstParam.name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isReactiveFunctionWithReader(callee: TSESTree.Node): boolean {
|
||||
if (callee.type === 'Identifier') {
|
||||
return reactiveFunctions.has(callee.name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function walkChildren(node: TSESTree.Node, cb: (child: TSESTree.Node) => void) {
|
||||
const keys = visitorKeys.KEYS[node.type] || [];
|
||||
for (const key of keys) {
|
||||
const child = (node as any)[key];
|
||||
if (Array.isArray(child)) {
|
||||
for (const item of child) {
|
||||
if (item && typeof item === 'object' && item.type) {
|
||||
cb(item);
|
||||
}
|
||||
}
|
||||
} else if (child && typeof child === 'object' && child.type) {
|
||||
cb(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as eslint from 'eslint';
|
||||
import { TSESTree } from '@typescript-eslint/utils';
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
export = new class NoReaderAfterAwait implements eslint.Rule.RuleModule {
|
||||
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
|
||||
return {
|
||||
'CallExpression': (node: any) => {
|
||||
const callExpression = node as TSESTree.CallExpression;
|
||||
|
||||
if (!isFunctionWithReader(callExpression.callee)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const functionArg = callExpression.arguments.find(arg =>
|
||||
arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression'
|
||||
) as TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression | undefined;
|
||||
|
||||
if (!functionArg) {
|
||||
return;
|
||||
}
|
||||
|
||||
const readerName = getReaderParameterName(functionArg);
|
||||
if (!readerName) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkFunctionForAwaitBeforeReader(functionArg, readerName, context);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function checkFunctionForAwaitBeforeReader(
|
||||
fn: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,
|
||||
readerName: string,
|
||||
context: eslint.Rule.RuleContext
|
||||
) {
|
||||
const awaitPositions: { line: number; column: number }[] = [];
|
||||
const visited = new Set<TSESTree.Node>();
|
||||
|
||||
function collectPositions(node: TSESTree.Node) {
|
||||
if (visited.has(node)) {
|
||||
return;
|
||||
}
|
||||
visited.add(node);
|
||||
|
||||
if (node.type === 'AwaitExpression') {
|
||||
awaitPositions.push({
|
||||
line: node.loc?.start.line || 0,
|
||||
column: node.loc?.start.column || 0
|
||||
});
|
||||
} else if (node.type === 'CallExpression' && isReaderMethodCall(node, readerName)) {
|
||||
if (awaitPositions.length > 0) {
|
||||
const methodName = getMethodName(node);
|
||||
context.report({
|
||||
node: node as any as ESTree.Node,
|
||||
message: `Reader method '${methodName}' should not be called after 'await'. The reader becomes invalid after async operations.`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Safely traverse known node types only
|
||||
switch (node.type) {
|
||||
case 'BlockStatement':
|
||||
node.body.forEach(stmt => collectPositions(stmt));
|
||||
break;
|
||||
case 'ExpressionStatement':
|
||||
collectPositions(node.expression);
|
||||
break;
|
||||
case 'VariableDeclaration':
|
||||
node.declarations.forEach(decl => {
|
||||
if (decl.init) { collectPositions(decl.init); }
|
||||
});
|
||||
break;
|
||||
case 'AwaitExpression':
|
||||
if (node.argument) { collectPositions(node.argument); }
|
||||
break;
|
||||
case 'CallExpression':
|
||||
node.arguments.forEach(arg => collectPositions(arg));
|
||||
break;
|
||||
case 'IfStatement':
|
||||
collectPositions(node.test);
|
||||
collectPositions(node.consequent);
|
||||
if (node.alternate) { collectPositions(node.alternate); }
|
||||
break;
|
||||
case 'TryStatement':
|
||||
collectPositions(node.block);
|
||||
if (node.handler) { collectPositions(node.handler.body); }
|
||||
if (node.finalizer) { collectPositions(node.finalizer); }
|
||||
break;
|
||||
case 'ReturnStatement':
|
||||
if (node.argument) { collectPositions(node.argument); }
|
||||
break;
|
||||
case 'BinaryExpression':
|
||||
case 'LogicalExpression':
|
||||
collectPositions(node.left);
|
||||
collectPositions(node.right);
|
||||
break;
|
||||
case 'MemberExpression':
|
||||
collectPositions(node.object);
|
||||
if (node.computed) { collectPositions(node.property); }
|
||||
break;
|
||||
case 'AssignmentExpression':
|
||||
collectPositions(node.left);
|
||||
collectPositions(node.right);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fn.body) {
|
||||
collectPositions(fn.body);
|
||||
}
|
||||
}
|
||||
|
||||
function getMethodName(callExpression: TSESTree.CallExpression): string {
|
||||
if (callExpression.callee.type === 'MemberExpression' &&
|
||||
callExpression.callee.property.type === 'Identifier') {
|
||||
return callExpression.callee.property.name;
|
||||
}
|
||||
return 'read';
|
||||
}
|
||||
|
||||
function isReaderMethodCall(node: TSESTree.CallExpression, readerName: string): boolean {
|
||||
if (node.callee.type === 'MemberExpression') {
|
||||
// Pattern 1: reader.read() or reader.readObservable()
|
||||
if (node.callee.object.type === 'Identifier' &&
|
||||
node.callee.object.name === readerName &&
|
||||
node.callee.property.type === 'Identifier') {
|
||||
return ['read', 'readObservable'].includes(node.callee.property.name);
|
||||
}
|
||||
|
||||
// Pattern 2: observable.read(reader) or observable.readObservable(reader)
|
||||
if (node.callee.property.type === 'Identifier' &&
|
||||
['read', 'readObservable'].includes(node.callee.property.name)) {
|
||||
// Check if the reader is passed as the first argument
|
||||
return node.arguments.length > 0 &&
|
||||
node.arguments[0].type === 'Identifier' &&
|
||||
node.arguments[0].name === readerName;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const readerFunctions = new Set(['derived', 'autorun', 'autorunOpts', 'autorunHandleChanges', 'autorunSelfDisposable']);
|
||||
|
||||
function getReaderParameterName(fn: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression): string | null {
|
||||
if (fn.params.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const firstParam = fn.params[0];
|
||||
if (firstParam.type === 'Identifier') {
|
||||
return firstParam.name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isFunctionWithReader(callee: TSESTree.Node): boolean {
|
||||
if (callee.type === 'Identifier') {
|
||||
return readerFunctions.has(callee.name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// Test file to verify the code-no-observable-get-in-reactive-context ESLint rule works correctly
|
||||
|
||||
import { observableValue, derived, autorun } from '../../src/vs/base/common/observable.js';
|
||||
|
||||
export function testValidUsage() {
|
||||
const obs = observableValue('test', 0);
|
||||
|
||||
// Valid: Using .read(reader) in derived
|
||||
const validDerived = derived(reader => {
|
||||
const value = obs.read(reader);
|
||||
return value * 2;
|
||||
});
|
||||
|
||||
// Valid: Using .read(reader) in autorun
|
||||
autorun(rdr => {
|
||||
const value = validDerived.read(rdr);
|
||||
console.log('Value:', value);
|
||||
});
|
||||
|
||||
// Valid: Using .get() outside reactive context
|
||||
const outsideValue = obs.get();
|
||||
console.log('Outside value:', outsideValue);
|
||||
}
|
||||
|
||||
export function testInvalidUsage() {
|
||||
const obs = observableValue('test', 0);
|
||||
|
||||
// Invalid: Using .get() in derived instead of .read(reader)
|
||||
const invalidDerived = derived(rdr => {
|
||||
// This should use obs.read(reader) instead
|
||||
// eslint-disable-next-line local/code-no-observable-get-in-reactive-context
|
||||
const value = obs.get();
|
||||
// Use reader for something valid to avoid unused var warning
|
||||
const validValue = obs.read(rdr);
|
||||
|
||||
obs.read(undefined);
|
||||
|
||||
return value * 2 + validValue;
|
||||
});
|
||||
|
||||
// Invalid: Using .get() in autorun instead of .read(reader)
|
||||
autorun(reader => {
|
||||
// This should use invalidDerived.read(reader) instead
|
||||
// eslint-disable-next-line local/code-no-observable-get-in-reactive-context
|
||||
const value = invalidDerived.get();
|
||||
// Use reader for something valid to avoid unused var warning
|
||||
const validValue = obs.read(reader);
|
||||
console.log('Value:', value, validValue);
|
||||
});
|
||||
|
||||
// Invalid: Using .get() in derivedWithStore
|
||||
derived(reader => {
|
||||
// eslint-disable-next-line local/code-no-observable-get-in-reactive-context
|
||||
const value = obs.get();
|
||||
reader.store.add({ dispose: () => { } });
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
export function testComplexCases() {
|
||||
const obs1 = observableValue('test1', 0);
|
||||
const obs2 = observableValue('test2', 10);
|
||||
|
||||
// Invalid: Using .get() in conditional within derived
|
||||
derived(reader => {
|
||||
const initial = obs1.read(reader);
|
||||
|
||||
if (initial > 0) {
|
||||
// eslint-disable-next-line local/code-no-observable-get-in-reactive-context
|
||||
return obs2.get();
|
||||
}
|
||||
|
||||
return initial;
|
||||
});
|
||||
|
||||
// Invalid: Using .get() in nested function call within autorun
|
||||
autorun(reader => {
|
||||
const process = () => {
|
||||
// eslint-disable-next-line local/code-no-observable-get-in-reactive-context
|
||||
return obs1.get() + obs2.get();
|
||||
};
|
||||
|
||||
// Use reader for something valid to avoid unused var warning
|
||||
const validValue = obs1.read(reader);
|
||||
const result = process();
|
||||
console.log('Result:', result, validValue);
|
||||
});
|
||||
|
||||
// Invalid: Using .get() in try-catch within derived
|
||||
derived(reader => {
|
||||
try {
|
||||
// eslint-disable-next-line local/code-no-observable-get-in-reactive-context
|
||||
const value = obs1.get();
|
||||
// Use reader for something valid to avoid unused var warning
|
||||
const validValue = obs2.read(reader);
|
||||
return value * 2 + validValue;
|
||||
} catch (e) {
|
||||
return obs2.read(reader);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function testValidComplexCases() {
|
||||
const obs1 = observableValue('test1', 0);
|
||||
const obs2 = observableValue('test2', 10);
|
||||
|
||||
// Valid: Proper usage with .read(reader)
|
||||
derived(reader => {
|
||||
const value1 = obs1.read(reader);
|
||||
const value2 = obs2.read(undefined);
|
||||
|
||||
if (value1 > 0) {
|
||||
return value2;
|
||||
}
|
||||
|
||||
return value1;
|
||||
});
|
||||
|
||||
// Valid: Using .get() outside reactive context
|
||||
function processValues() {
|
||||
const val1 = obs1.get();
|
||||
const val2 = obs2.get();
|
||||
return val1 + val2;
|
||||
}
|
||||
|
||||
// Valid: Mixed usage - .read(reader) inside reactive, .get() outside
|
||||
autorun(reader => {
|
||||
const reactiveValue = obs1.read(reader);
|
||||
const outsideValue = processValues();
|
||||
console.log('Values:', reactiveValue, outsideValue);
|
||||
});
|
||||
}
|
||||
|
||||
export function testEdgeCases() {
|
||||
const obs = observableValue('test', 0);
|
||||
|
||||
// Valid: Function with no reader parameter
|
||||
derived(() => {
|
||||
const value = obs.get();
|
||||
return value;
|
||||
});
|
||||
|
||||
// Invalid: Function with differently named parameter (now also flagged)
|
||||
derived(_someOtherName => {
|
||||
// eslint-disable-next-line local/code-no-observable-get-in-reactive-context
|
||||
const value = obs.get();
|
||||
return value;
|
||||
});
|
||||
|
||||
// Invalid: Correctly named reader parameter
|
||||
derived(reader => {
|
||||
// eslint-disable-next-line local/code-no-observable-get-in-reactive-context
|
||||
const value = obs.get();
|
||||
// Use reader for something valid to avoid unused var warning
|
||||
const validValue = obs.read(reader);
|
||||
return value + validValue;
|
||||
});
|
||||
}
|
||||
|
||||
export function testQuickFixScenarios() {
|
||||
const obs = observableValue('test', 0);
|
||||
const obs2 = observableValue('test2', 10);
|
||||
|
||||
// These examples show what the quick fix should transform:
|
||||
|
||||
// Example 1: Simple case with 'reader' parameter name
|
||||
derived(_reader => {
|
||||
const value = obs.read(undefined); // This should be the auto-fix result
|
||||
return value;
|
||||
});
|
||||
|
||||
// Example 2: Different parameter name
|
||||
derived(rdr => {
|
||||
// Before fix: obs2.get()
|
||||
// After fix: obs2.read(rdr)
|
||||
const value = obs2.read(rdr); // This should be the auto-fix result
|
||||
return value;
|
||||
});
|
||||
|
||||
// Example 3: Complex expression
|
||||
derived(ctx => {
|
||||
// Before fix: (someCondition ? obs : obs2).get()
|
||||
// After fix: (someCondition ? obs : obs2).read(ctx)
|
||||
const someCondition = true;
|
||||
const value = (someCondition ? obs : obs2).read(ctx); // This should be the auto-fix result
|
||||
return value;
|
||||
});
|
||||
|
||||
// Example 4: Multiple calls in same function
|
||||
autorun(reader => {
|
||||
// Before fix: obs.get() and obs2.get()
|
||||
// After fix: obs.read(reader) and obs2.read(reader)
|
||||
const val1 = obs.read(reader); // This should be the auto-fix result
|
||||
const val2 = obs2.read(reader); // This should be the auto-fix result
|
||||
console.log(val1, val2);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// Test file to verify the code-no-reader-after-await ESLint rule works correctly
|
||||
|
||||
import { observableValue, derived, autorun } from '../../src/vs/base/common/observable.js';
|
||||
|
||||
export function testValidUsage() {
|
||||
const obs = observableValue('test', 0);
|
||||
|
||||
const validDerived = derived(reader => {
|
||||
const value = obs.read(reader);
|
||||
return value * 2;
|
||||
});
|
||||
|
||||
autorun(reader => {
|
||||
const value = validDerived.read(reader);
|
||||
console.log('Value:', value);
|
||||
});
|
||||
}
|
||||
|
||||
export function testInvalidUsage() {
|
||||
const obs = observableValue('test', 0);
|
||||
|
||||
const invalidDerived = derived(async reader => {
|
||||
await Promise.resolve();
|
||||
// eslint-disable-next-line local/code-no-reader-after-await
|
||||
const value = obs.read(reader);
|
||||
return value * 2;
|
||||
});
|
||||
|
||||
autorun(async reader => {
|
||||
await Promise.resolve();
|
||||
// eslint-disable-next-line local/code-no-reader-after-await
|
||||
const value = invalidDerived.read(reader);
|
||||
console.log('Value:', value);
|
||||
});
|
||||
|
||||
autorun(async reader => {
|
||||
await Promise.resolve();
|
||||
// eslint-disable-next-line local/code-no-reader-after-await
|
||||
const value = reader.readObservable(obs);
|
||||
console.log('Value:', value);
|
||||
});
|
||||
}
|
||||
|
||||
export function testComplexCases() {
|
||||
const obs = observableValue('test', 0);
|
||||
|
||||
derived(async reader => {
|
||||
const initial = obs.read(reader);
|
||||
|
||||
if (initial > 0) {
|
||||
await Promise.resolve();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line local/code-no-reader-after-await
|
||||
const final = obs.read(reader);
|
||||
return final;
|
||||
});
|
||||
|
||||
autorun(async reader => {
|
||||
try {
|
||||
await Promise.resolve();
|
||||
} catch (e) {
|
||||
} finally {
|
||||
// eslint-disable-next-line local/code-no-reader-after-await
|
||||
const value = obs.read(reader);
|
||||
console.log(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function testValidComplexCases() {
|
||||
const obs = observableValue('test', 0);
|
||||
|
||||
derived(async reader => {
|
||||
const value1 = obs.read(reader);
|
||||
const value2 = reader.readObservable(obs);
|
||||
const result = value1 + value2;
|
||||
await Promise.resolve(result);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
+1
-1
@@ -38,4 +38,4 @@ src/vs/workbench/services/workingCopy/** @bpasero
|
||||
|
||||
# ensure the API police is aware of changes to the vscode-dts file
|
||||
# this is only about the final API, not about proposed API changes
|
||||
src/vscode-dts/vscode.d.ts @jrieken @mjbvz
|
||||
src/vscode-dts/vscode.d.ts @jrieken @mjbvz @alexr00
|
||||
|
||||
@@ -61,8 +61,7 @@ You MUST check compilation output before running ANY script or declaring work co
|
||||
- Start the task if it's not already running in the background
|
||||
|
||||
### TypeScript validation steps
|
||||
- Use run test tool or `scripts/test.sh` (`scripts\test.bat` on Windows) for unit tests (add `--grep <pattern>` to filter tests)
|
||||
- Use `scripts/test-integration.sh` (or `scripts\test-integration.bat` on Windows) for integration tests
|
||||
- Use the run test tool if you need to run tests. If that tool is not available, then you can use `scripts/test.sh` (or `scripts\test.bat` on Windows) for unit tests (add `--grep <pattern>` to filter tests) or `scripts/test-integration.sh` (or `scripts\test-integration.bat` on Windows) for integration tests (integration tests end with .integrationTest.ts or are in /extensions/).
|
||||
- Use `npm run valid-layers-check` to check for layering issues
|
||||
|
||||
## Coding Guidelines
|
||||
@@ -92,7 +91,8 @@ We use tabs, not spaces.
|
||||
|
||||
- Use "double quotes" for strings shown to the user that need to be externalized (localized)
|
||||
- Use 'single quotes' otherwise
|
||||
- All strings visible to the user need to be externalized
|
||||
- All strings visible to the user need to be externalized using the `vs/nls` module
|
||||
- Externalized strings must not use string concatenation. Use placeholders instead (`{0}`).
|
||||
|
||||
### UI labels
|
||||
- Use title-style capitalization for command labels, buttons and menu items (each word is capitalized).
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
description: Guidelines for writing code using IDisposable
|
||||
---
|
||||
|
||||
Core symbols:
|
||||
* `IDisposable`
|
||||
* `dispose(): void` - dispose the object
|
||||
* `Disposable` (implements `IDisposable`) - base class for disposable objects
|
||||
* `this._store: DisposableStore`
|
||||
* `this._register<T extends IDisposable>(t: T): T`
|
||||
* Try to immediately register created disposables! E.g. `const someDisposable = this._register(new SomeDisposable())`
|
||||
* `DisposableStore` (implements `IDisposable`)
|
||||
* `add<T extends IDisposable>(t: T): T`
|
||||
* `clear()`
|
||||
* `toDisposable(fn: () => void): IDisposable` - helper to create a disposable from a function
|
||||
|
||||
* `MutableDisposable` (implements `IDisposable`)
|
||||
* `value: IDisposable | undefined`
|
||||
* `clear()`
|
||||
* A value that enters a mutable disposable (at least once) will be disposed the latest when the mutable disposable is disposed (or when the value is replaced or cleared).
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
applyTo: **
|
||||
description: This document describes how to deal with learnings that you make. (meta instruction)
|
||||
---
|
||||
|
||||
This document describes how to deal with learnings that you make.
|
||||
It is a meta-instruction file.
|
||||
|
||||
Structure of learnings:
|
||||
* Each instruction file has a "Learnings" section.
|
||||
* Each learning has a counter that indicates how often that learning was useful (initially 1).
|
||||
* Each learning has a 1-4 sentences description of the learning.
|
||||
|
||||
Example:
|
||||
```markdown
|
||||
## Learnings
|
||||
* Prefer `const` over `let` whenever possible (1)
|
||||
* Avoid `any` type (3)
|
||||
```
|
||||
|
||||
When the user tells you "learn!", you should:
|
||||
* extract a learning from the recent conversation
|
||||
* identify the problem that you created
|
||||
* identify why it was a problem
|
||||
* identify how you were told to fix it/how the user fixed it
|
||||
* create a learning (1-4 sentences) from that
|
||||
* Write this out to the user and reflect over these sentences
|
||||
* then, add the reflected learning to the "Learnings" section of the most appropriate instruction file
|
||||
|
||||
|
||||
Important: Whenever a learning was really useful, increase the counter!!
|
||||
When a learning was not useful and just caused more problems, decrease the counter.
|
||||
@@ -0,0 +1,72 @@
|
||||
---
|
||||
description: Guidelines for writing code using observables and deriveds.
|
||||
---
|
||||
|
||||
```ts
|
||||
class MyService extends Disposable {
|
||||
private _myData1 = observableValue(/* always put `this` here */ this, /* initial value*/ 0);
|
||||
private _myData2 = observableValue(/* always put `this` here */ this, /* initial value*/ 42);
|
||||
|
||||
// Deriveds can combine/derive from other observables/deriveds
|
||||
private _myDerivedData = derived(this, reader => {
|
||||
// Use observable.read(reader) to access the value and track the dependency.
|
||||
return this._myData1.read(reader) * this._myData2.read(reader);
|
||||
});
|
||||
|
||||
private _myDerivedDataWithLifetime = derived(this, reader => {
|
||||
// The reader.store will get cleared just before the derived is re-evaluated or gets unsubscribed.
|
||||
return reader.store.add(new SomeDisposable(this._myDerivedData.read(reader)));
|
||||
});
|
||||
|
||||
constructor() {
|
||||
this._register(autorun((reader) => { // like mobx autorun, they run immediately and on change
|
||||
const data = this._myData1.read(reader); // but you only get the data if you pass in the reader!
|
||||
|
||||
console.log(data);
|
||||
|
||||
// also has reader.store
|
||||
}))
|
||||
}
|
||||
|
||||
getData(): number {
|
||||
return this._myData1.get(); // use get if you don't have a reader, but try to avoid it since the dependency is not tracked.
|
||||
}
|
||||
|
||||
setData1() {
|
||||
this._myData1.set(42, undefined); // use set to update the value. The second paramater is the transaction, which is undefined here.
|
||||
}
|
||||
|
||||
setData2() {
|
||||
transaction(tx => {
|
||||
// you can use transaction to batch updates, so they are only notified once.
|
||||
// Whenever multiple observables are synchronously updated together, use transaction!
|
||||
this._myData1.set(42, tx);
|
||||
this._myData2.set(43, tx);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Most important symbols:
|
||||
* `observableValue`
|
||||
* `disposableObservableValue`
|
||||
* `derived`
|
||||
* `autorun`
|
||||
* `transaction`
|
||||
* `observableFromEvent`
|
||||
* `observableSignalFromEvent`
|
||||
* `observableSignal(...): IObservable<void>` - use `.trigger(tx)` to trigger a change
|
||||
|
||||
|
||||
* Check src\vs\base\common\observableInternal\index.ts for a list of all observable utitilies
|
||||
|
||||
|
||||
* Important learnings:
|
||||
* [1] Avoid glitches
|
||||
* [2] **Choose the right observable value type:**
|
||||
* Use `observableValue(owner, initialValue)` for regular values
|
||||
* Use `disposableObservableValue(owner, initialValue)` when storing disposable values - it automatically disposes the previous value when a new one is set, and disposes the current value when the observable itself is disposed (similar to `MutableDisposable` behavior)
|
||||
* [3] **Choose the right event observable pattern:**
|
||||
* Use `observableFromEvent(owner, event, valueComputer)` when you need to track a computed value that changes with the event, and you want updates only when the computed value actually changes
|
||||
* Use `observableSignalFromEvent(owner, event)` when you need to force re-computation every time the event fires, regardless of value stability. This is important when the computed value might not change but dependent computations need fresh context (e.g., workspace folder changes where the folder array reference might be the same but file path calculations need to be refreshed)
|
||||
@@ -0,0 +1,157 @@
|
||||
---
|
||||
description: Use when asked to consume workbench tree widgets in VS Code.
|
||||
---
|
||||
|
||||
# Workbench Tree Widgets Overview
|
||||
|
||||
**Location**: `src/vs/platform/list/browser/listService.ts`
|
||||
**Type**: Platform Services
|
||||
**Layer**: Platform
|
||||
|
||||
## Purpose
|
||||
|
||||
The Workbench Tree Widgets provide high-level, workbench-integrated tree components that extend the base tree implementations with VS Code-specific functionality like context menus, keyboard navigation, theming, accessibility, and dependency injection integration. These widgets serve as the primary tree components used throughout the VS Code workbench for file explorers, debug views, search results, and other hierarchical data presentations.
|
||||
|
||||
## Scope
|
||||
|
||||
### Included Functionality
|
||||
- **Context Integration**: Automatic context key management, focus handling, and VS Code theme integration
|
||||
- **Resource Navigation**: Built-in support for opening files and resources with proper editor integration
|
||||
- **Accessibility**: Complete accessibility provider integration with screen reader support
|
||||
- **Keyboard Navigation**: Smart keyboard navigation with search-as-you-type functionality
|
||||
- **Multi-selection**: Configurable multi-selection behavior with platform-appropriate modifier keys
|
||||
- **Dependency Injection**: Full integration with VS Code's service container for automatic service injection
|
||||
- **Configuration**: Automatic integration with user settings for tree behavior customization
|
||||
|
||||
### Integration Points
|
||||
- **IInstantiationService**: For service injection and component creation
|
||||
- **IContextKeyService**: For managing focus, selection, and tree state context keys
|
||||
- **IListService**: For registering trees and managing workbench list lifecycle
|
||||
- **IConfigurationService**: For reading tree configuration settings
|
||||
- **Resource Navigators**: For handling file/resource opening with proper editor integration
|
||||
|
||||
### Out of Scope
|
||||
- Low-level tree rendering and virtualization (handled by base tree classes)
|
||||
- Data management and async loading logic (provided by data sources)
|
||||
- Custom styling beyond workbench theming integration
|
||||
|
||||
## Architecture
|
||||
|
||||
### Key Classes & Interfaces
|
||||
|
||||
- **WorkbenchTreeInternals**: Encapsulates common workbench functionality across all tree types
|
||||
- **ResourceNavigator**: Handles file/resource opening with proper editor integration
|
||||
- **IOpenEvent**: Event interface for resource opening with editor options
|
||||
- **IWorkbench*TreeOptions**: Configuration interfaces extending base options with workbench features
|
||||
- **IResourceNavigatorOptions**: Configuration for resource opening behavior
|
||||
|
||||
### Key Files
|
||||
|
||||
- **`src/vs/platform/list/browser/listService.ts`**: Contains all workbench tree widget implementations, shared workbench functionality (`WorkbenchTreeInternals`), and configuration utilities
|
||||
- `src/vs/platform/list/browser/test/listService.test.ts`: Unit tests for workbench trees
|
||||
- **`src/vs/base/browser/ui/tree/objectTree.ts`**: Base implementation for static trees and compressible trees
|
||||
- `src/vs/base/test/browser/ui/tree/objectTree.test.ts`: Base tree tests
|
||||
- **`src/vs/base/browser/ui/tree/asyncDataTree.ts`**: Base implementation for async trees with lazy loading support
|
||||
- `src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts`: Async tree tests
|
||||
- **`src/vs/base/browser/ui/tree/dataTree.ts`**: Base implementation for data-driven trees with explicit data sources
|
||||
- `src/vs/base/test/browser/ui/tree/dataTree.test.ts`: Data tree tests
|
||||
- **`src/vs/base/browser/ui/tree/abstractTree.ts`**: Base tree foundation
|
||||
- **`src/vs/base/browser/ui/tree/tree.ts`**: Core interfaces and types
|
||||
|
||||
## Development Guidelines
|
||||
|
||||
### Choosing the Right Tree Widget
|
||||
|
||||
1. **WorkbenchObjectTree**: Use for simple, static hierarchical data that doesn't change frequently
|
||||
```typescript
|
||||
// Example: Timeline items, loaded scripts
|
||||
const tree = instantiationService.createInstance(
|
||||
WorkbenchObjectTree<TimelineItem, FuzzyScore>,
|
||||
'TimelineView', container, delegate, renderers, options
|
||||
);
|
||||
```
|
||||
|
||||
2. **WorkbenchAsyncDataTree**: Use for dynamic data that loads asynchronously
|
||||
```typescript
|
||||
// Example: Debug variables, file contents
|
||||
const tree = instantiationService.createInstance(
|
||||
WorkbenchAsyncDataTree<IStackFrame, IExpression, FuzzyScore>,
|
||||
'VariablesView', container, delegate, renderers, dataSource, options
|
||||
);
|
||||
```
|
||||
|
||||
3. **WorkbenchCompressible*Tree**: Use when you need path compression for deep hierarchies
|
||||
```typescript
|
||||
// Example: File explorer, call stack
|
||||
const tree = instantiationService.createInstance(
|
||||
WorkbenchCompressibleAsyncDataTree<ExplorerItem[], ExplorerItem, FuzzyScore>,
|
||||
'FileExplorer', container, delegate, compressionDelegate, renderers, dataSource, options
|
||||
);
|
||||
```
|
||||
|
||||
### Construction Pattern
|
||||
|
||||
**Always use IInstantiationService.createInstance()** to ensure proper dependency injection:
|
||||
|
||||
```typescript
|
||||
constructor(
|
||||
@IInstantiationService private instantiationService: IInstantiationService
|
||||
) {
|
||||
this.tree = this.instantiationService.createInstance(
|
||||
WorkbenchAsyncDataTree<TInput, T, TFilterData>,
|
||||
'UniqueTreeId', // Used for settings and context keys
|
||||
container, // DOM container element
|
||||
delegate, // IListVirtualDelegate for item height/template
|
||||
renderers, // Array of tree renderers
|
||||
dataSource, // Data source (async trees only)
|
||||
options // Tree configuration options
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Required Options
|
||||
|
||||
All workbench trees require an **accessibilityProvider**:
|
||||
```typescript
|
||||
const options: IWorkbenchAsyncDataTreeOptions<T, TFilterData> = {
|
||||
accessibilityProvider: {
|
||||
getAriaLabel: (element: T) => element.name,
|
||||
getRole: () => 'treeitem'
|
||||
}
|
||||
// ... other options
|
||||
};
|
||||
```
|
||||
|
||||
### Common Configuration Patterns
|
||||
|
||||
```typescript
|
||||
// Standard tree setup with search, identity, and navigation
|
||||
const options = {
|
||||
accessibilityProvider: new MyAccessibilityProvider(),
|
||||
identityProvider: { getId: (element) => element.id },
|
||||
keyboardNavigationLabelProvider: {
|
||||
getKeyboardNavigationLabel: (element) => element.name
|
||||
},
|
||||
multipleSelectionController: {
|
||||
isSelectionSingleChangeEvent: (e) => e.ctrlKey || e.metaKey,
|
||||
isSelectionRangeChangeEvent: (e) => e.shiftKey
|
||||
},
|
||||
overrideStyles: this.getLocationBasedColors().listOverrideStyles
|
||||
};
|
||||
```
|
||||
|
||||
### Lifecycle Management
|
||||
|
||||
- **Always register trees as disposables** in the containing component
|
||||
- **Use the tree's `setInput()` method** to provide initial data
|
||||
- **Always call `layout()` when the container initializes and when its size changes**
|
||||
- **Handle selection and open events** through the tree's event system
|
||||
|
||||
### Performance Considerations
|
||||
|
||||
- Use **compression** for deep hierarchies to reduce DOM nodes
|
||||
- Implement **efficient data sources** that avoid unnecessary data fetching
|
||||
- Consider **virtualization settings** for large datasets
|
||||
- Use **identity providers** for efficient updates and state preservation
|
||||
|
||||
---
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
mode: agent
|
||||
description: 'Help author a component specification for an agent.'
|
||||
tools: ['edit', 'search', 'usages', 'vscodeAPI', 'fetch', 'extensions', 'todos']
|
||||
---
|
||||
|
||||
<overview>
|
||||
Your goal is to create a component overview in markdown given the context provided by the user. The overview should include a brief description of the component, its main features, an architectural diagram and layout of important code files and their relationships. The purpose of this overview is to enable a developer to attach it to a feature request and ensure the agent has enough context to make correct code changes without breaking functionality.
|
||||
</overview>
|
||||
|
||||
<format>
|
||||
# [Component Name] Overview
|
||||
|
||||
**Location**: `src/vs/[path/to/component]`
|
||||
**Type**: [Service/Contribution/Extension/API/etc.]
|
||||
**Layer (if applicable)**: [base/platform/editor/workbench/code/server]
|
||||
|
||||
## Purpose
|
||||
|
||||
Brief description of what this component does and why it exists.
|
||||
|
||||
## Scope
|
||||
- What functionality is included
|
||||
- What is explicitly out of scope
|
||||
- Integration points with other components
|
||||
|
||||
## Architecture
|
||||
|
||||
### High-Level Design
|
||||
[Architectural diagram or description of key patterns used]
|
||||
|
||||
### Key Classes & Interfaces
|
||||
- **[ClassName]**: Brief description of responsibility
|
||||
- **[InterfaceName]**: Purpose and main methods
|
||||
- **[ServiceName]**: Service responsibilities
|
||||
|
||||
### Key Files
|
||||
List all the key files and a brief description of their purpose:
|
||||
- **`src/vs/[path/to/component]/[filename.ts]`**: [Purpose and main exports]
|
||||
- **`src/vs/[path/to/component]/[service.ts]`**: [Service implementation details]
|
||||
- **`src/vs/[path/to/component]/[contribution.ts]`**: [Workbench contributions]
|
||||
|
||||
## Development Guidelines
|
||||
|
||||
- Reserve a section for any specific development practices or patterns relevant to this component. These will be edited by a developer or agent as needed.
|
||||
|
||||
---
|
||||
</format>
|
||||
|
||||
<instructions>
|
||||
- **Create** a new overview file if one is not specified: `.components/[component-name].md`
|
||||
- **Fill** each section with component-specific details
|
||||
- **Gather** information from the attached context and use available tools if needed to complete your understanding
|
||||
- **Ask** the user for clarification if you cannot fill out a section with accurate information
|
||||
- **Use complete file paths** from repository root (e.g., `src/vs/workbench/services/example/browser/exampleService.ts`)
|
||||
- **Keep** descriptions concise but comprehensive
|
||||
- **Use file references** instead of code snippets when making references to code as otherwise the code may become outdated
|
||||
</instructions>
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
mode: agent
|
||||
description: 'Answer telemetry questions with data queries'
|
||||
tools: ['runInTerminal', 'search', 'extensions', 'githubRepo', 'todos', 'kusto_query']
|
||||
---
|
||||
|
||||
<overview>
|
||||
You are a Azure Data Explorer data analyst with expert knowledge in Kusto Query Language (KQL) and data analysis. Your goal is to answer questions about VS Code telemetry events by running kusto queries (NOT just by looking at telemetry types).
|
||||
</overview>
|
||||
|
||||
<workflow>
|
||||
1. Read `vscode-telemetry-docs/.github/copilot-instructions.md` to understand how to access VS Code's telemetry
|
||||
- If the `vscode-telemetry-docs` folder doesn't exist (just check your workspace_info, no extra tool call needed), run `npm run mixin-telemetry-docs` to clone the telemetry documentation.
|
||||
2. Analyze data using kusto queries: Don't just describe what could be queried - actually execute Kusto queries to provide real data and insights:
|
||||
- If the `kusto_query` tool doesn't exist (just check your provided tools, no need to run it!), install the `ms-azuretools.vscode-azure-mcp-server` VS Code extension
|
||||
- Use the appropriate Kusto cluster and database for the data type
|
||||
- Always include proper time filtering to limit data volume
|
||||
- Default to a rolling 28-day window if no specific timeframe is requested
|
||||
- Format and present the query results clearly to answer the user's question
|
||||
- Track progress of your kusto analysis using todos
|
||||
- If kusto queries keep failing (up to 3 repeated attempts of fixing parametersor queries), stop and inform the user.
|
||||
</workflow>
|
||||
|
||||
<kusto-best-practices>
|
||||
When writing Kusto queries, follow these best practices:
|
||||
- **Explore data efficiently.** Use 1d (1-day) time window and `sample` operator to quickly understand data shape and volume
|
||||
- **Aggregate usage in proper time windows.** When no specific timeframe is provided:
|
||||
- Default to a rolling 28-day window (standard practice in VS Code telemetry)
|
||||
- Use full day boundaries to avoid partial day data
|
||||
- Follow the time filtering patterns from the telemetry documentation
|
||||
- **Correctly map names and keys.** EventName is the prefix (`monacoworkbench/` for vscode) and lowercase event name. Properties/Measurements keys are lowercase. Any properties marked `isMeasurement` are in the Measurements bag.
|
||||
- **Parallelize queries when possible.** Run multiple independent queries as parallel tool calls to speed up analysis.
|
||||
</kusto-best-practices>
|
||||
|
||||
<format>
|
||||
Your response should include:
|
||||
- The actual Kusto query executed (formatted nicely)
|
||||
- Real query results with data to answer the user's question
|
||||
- Interpretation and analysis of the results
|
||||
- References to specific documentation files when applicable
|
||||
- Additional context or insights from the telemetry data
|
||||
</format>
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
mode: Plan
|
||||
tools: ['runCommands', 'runTasks', 'runNotebooks', 'search', 'new', 'usages', 'vscodeAPI', 'problems', 'testFailure', 'openSimpleBrowser', 'fetch', 'githubRepo', 'todos', 'runTests', 'get_issue', 'get_issue_comments', 'get_me', 'get_pull_request', 'get_pull_request_diff', 'get_pull_request_files']
|
||||
---
|
||||
|
||||
The user has given you a Github issue number. Use the `get_issue` to retrieve its details. Understand the issue and propose a solution to solve it.
|
||||
|
||||
NEVER share any thinking process or status updates before you have your solution.
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
mode: agent
|
||||
---
|
||||
|
||||
Read the changes introduced on the current branch, including BOTH:
|
||||
|
||||
1. Uncommitted workspace modifications (staged and unstaged)
|
||||
2. Committed changes that are on the current HEAD but not yet in the default upstream branch (e.g. `origin/main`)
|
||||
|
||||
Guidance:
|
||||
|
||||
- First, capture uncommitted diffs (equivalent of `git diff` and `git diff --cached`).
|
||||
- Then, determine the merge base with the default branch (assume `origin/main` unless configured otherwise) using `git merge-base HEAD origin/main` and diff (`git diff <merge-base>...HEAD`) to include committed-but-unpushed work.
|
||||
|
||||
After understanding all of these changes, read every instruction file under `.github/instructions` and assess whether any instruction is invalidated. If so, propose minimal, necessary wording updates. If no updates are needed, respond exactly with: `No updates needed`.
|
||||
|
||||
Be concise and conservative: only suggest changes that are absolutely necessary.
|
||||
@@ -0,0 +1,260 @@
|
||||
name: "Copilot Setup Steps"
|
||||
|
||||
# Automatically run the setup steps when they are changed to allow for easy validation, and
|
||||
# allow manual testing through the repository's "Actions" tab
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- .github/workflows/copilot-setup-steps.yml
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/copilot-setup-steps.yml
|
||||
|
||||
jobs:
|
||||
# The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
|
||||
copilot-setup-steps:
|
||||
runs-on: vscode-large-runners
|
||||
|
||||
# Set the permissions to the lowest permissions possible needed for your steps.
|
||||
# Copilot will be given its own token for its operations.
|
||||
permissions:
|
||||
# If you want to clone the repository as part of your setup steps, for example to install dependencies, you'll need the `contents: read` permission. If you don't clone the repository in your setup steps, Copilot will do this for you automatically after the steps complete.
|
||||
contents: read
|
||||
|
||||
# You can define any steps you want, and they will run before the agent starts.
|
||||
# If you do not check out your code, Copilot will do this for you.
|
||||
steps:
|
||||
- name: Checkout microsoft/vscode
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
|
||||
- name: Setup system services
|
||||
run: |
|
||||
set -e
|
||||
# Start X server
|
||||
./build/azure-pipelines/linux/apt-retry.sh sudo apt-get update
|
||||
./build/azure-pipelines/linux/apt-retry.sh sudo apt-get install -y pkg-config \
|
||||
xvfb \
|
||||
libgtk-3-0 \
|
||||
libxkbfile-dev \
|
||||
libkrb5-dev \
|
||||
libgbm1 \
|
||||
rpm
|
||||
sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb
|
||||
sudo chmod +x /etc/init.d/xvfb
|
||||
sudo update-rc.d xvfb defaults
|
||||
sudo service xvfb start
|
||||
|
||||
- name: Prepare node_modules cache key
|
||||
run: mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.js linux x64 $(node -p process.arch) > .build/packagelockhash
|
||||
|
||||
- name: Restore node_modules cache
|
||||
id: cache-node-modules
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: .build/node_modules_cache
|
||||
key: "node_modules-linux-${{ hashFiles('.build/packagelockhash') }}"
|
||||
|
||||
- name: Extract node_modules cache
|
||||
if: steps.cache-node-modules.outputs.cache-hit == 'true'
|
||||
run: tar -xzf .build/node_modules_cache/cache.tgz
|
||||
|
||||
- name: Install build dependencies
|
||||
if: steps.cache-node-modules.outputs.cache-hit != 'true'
|
||||
working-directory: build
|
||||
run: |
|
||||
set -e
|
||||
|
||||
for i in {1..5}; do # try 5 times
|
||||
npm ci && break
|
||||
if [ $i -eq 5 ]; then
|
||||
echo "Npm install failed too many times" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Npm install failed $i, trying again..."
|
||||
done
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.cache-node-modules.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
set -e
|
||||
|
||||
source ./build/azure-pipelines/linux/setup-env.sh
|
||||
|
||||
for i in {1..5}; do # try 5 times
|
||||
npm ci && break
|
||||
if [ $i -eq 5 ]; then
|
||||
echo "Npm install failed too many times" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Npm install failed $i, trying again..."
|
||||
done
|
||||
env:
|
||||
npm_config_arch: x64
|
||||
VSCODE_ARCH: x64
|
||||
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create node_modules archive
|
||||
if: steps.cache-node-modules.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
set -e
|
||||
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
|
||||
mkdir -p .build/node_modules_cache
|
||||
tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
|
||||
|
||||
- name: Create .build folder
|
||||
run: mkdir -p .build
|
||||
|
||||
- name: Prepare built-in extensions cache key
|
||||
run: node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash
|
||||
|
||||
- name: Restore built-in extensions cache
|
||||
id: cache-builtin-extensions
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
enableCrossOsArchive: true
|
||||
path: .build/builtInExtensions
|
||||
key: "builtin-extensions-${{ hashFiles('.build/builtindepshash') }}"
|
||||
|
||||
- name: Download built-in extensions
|
||||
if: steps.cache-builtin-extensions.outputs.cache-hit != 'true'
|
||||
run: node build/lib/builtInExtensions.js
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# - name: Transpile client and extensions
|
||||
# run: npm run gulp transpile-client-esbuild transpile-extensions
|
||||
|
||||
- name: Download Electron and Playwright
|
||||
run: |
|
||||
set -e
|
||||
|
||||
for i in {1..3}; do # try 3 times (matching retryCountOnTaskFailure: 3)
|
||||
if npm exec -- npm-run-all -lp "electron x64" "playwright-install"; then
|
||||
echo "Download successful on attempt $i"
|
||||
break
|
||||
fi
|
||||
|
||||
if [ $i -eq 3 ]; then
|
||||
echo "Download failed after 3 attempts" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Download failed on attempt $i, retrying..."
|
||||
sleep 5 # optional: add a small delay between retries
|
||||
done
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# - name: 🧪 Run unit tests (Electron)
|
||||
# if: ${{ inputs.electron_tests }}
|
||||
# timeout-minutes: 15
|
||||
# run: ./scripts/test.sh --tfs "Unit Tests"
|
||||
# env:
|
||||
# DISPLAY: ":10"
|
||||
|
||||
# - name: 🧪 Run unit tests (node.js)
|
||||
# if: ${{ inputs.electron_tests }}
|
||||
# timeout-minutes: 15
|
||||
# run: npm run test-node
|
||||
|
||||
# - name: 🧪 Run unit tests (Browser, Chromium)
|
||||
# if: ${{ inputs.browser_tests }}
|
||||
# timeout-minutes: 30
|
||||
# run: npm run test-browser-no-install -- --browser chromium --tfs "Browser Unit Tests"
|
||||
# env:
|
||||
# DEBUG: "*browser*"
|
||||
|
||||
# - name: Build integration tests
|
||||
# run: |
|
||||
# set -e
|
||||
# npm run gulp \
|
||||
# compile-extension:configuration-editing \
|
||||
# compile-extension:css-language-features-server \
|
||||
# compile-extension:emmet \
|
||||
# compile-extension:git \
|
||||
# compile-extension:github-authentication \
|
||||
# compile-extension:html-language-features-server \
|
||||
# compile-extension:ipynb \
|
||||
# compile-extension:notebook-renderers \
|
||||
# compile-extension:json-language-features-server \
|
||||
# compile-extension:markdown-language-features \
|
||||
# compile-extension-media \
|
||||
# compile-extension:microsoft-authentication \
|
||||
# compile-extension:typescript-language-features \
|
||||
# compile-extension:vscode-api-tests \
|
||||
# compile-extension:vscode-colorize-tests \
|
||||
# compile-extension:vscode-colorize-perf-tests \
|
||||
# compile-extension:vscode-test-resolver
|
||||
|
||||
# - name: 🧪 Run integration tests (Electron)
|
||||
# if: ${{ inputs.electron_tests }}
|
||||
# timeout-minutes: 20
|
||||
# run: ./scripts/test-integration.sh --tfs "Integration Tests"
|
||||
# env:
|
||||
# DISPLAY: ":10"
|
||||
|
||||
# - name: 🧪 Run integration tests (Browser, Chromium)
|
||||
# if: ${{ inputs.browser_tests }}
|
||||
# timeout-minutes: 20
|
||||
# run: ./scripts/test-web-integration.sh --browser chromium
|
||||
|
||||
# - name: 🧪 Run integration tests (Remote)
|
||||
# if: ${{ inputs.remote_tests }}
|
||||
# timeout-minutes: 20
|
||||
# run: ./scripts/test-remote-integration.sh
|
||||
# env:
|
||||
# DISPLAY: ":10"
|
||||
|
||||
# - name: Compile smoke tests
|
||||
# working-directory: test/smoke
|
||||
# run: npm run compile
|
||||
|
||||
# - name: Compile extensions for smoke tests
|
||||
# run: npm run gulp compile-extension-media
|
||||
|
||||
# - name: Diagnostics before smoke test run (processes, max_user_watches, number of opened file handles)
|
||||
# run: |
|
||||
# set -e
|
||||
# ps -ef
|
||||
# cat /proc/sys/fs/inotify/max_user_watches
|
||||
# lsof | wc -l
|
||||
# continue-on-error: true
|
||||
# if: always()
|
||||
|
||||
# - name: 🧪 Run smoke tests (Electron)
|
||||
# if: ${{ inputs.electron_tests }}
|
||||
# timeout-minutes: 20
|
||||
# run: npm run smoketest-no-compile -- --tracing
|
||||
# env:
|
||||
# DISPLAY: ":10"
|
||||
|
||||
# - name: 🧪 Run smoke tests (Browser, Chromium)
|
||||
# if: ${{ inputs.browser_tests }}
|
||||
# timeout-minutes: 20
|
||||
# run: npm run smoketest-no-compile -- --web --tracing --headless
|
||||
|
||||
# - name: 🧪 Run smoke tests (Remote)
|
||||
# if: ${{ inputs.remote_tests }}
|
||||
# timeout-minutes: 20
|
||||
# run: npm run smoketest-no-compile -- --remote --tracing
|
||||
# env:
|
||||
# DISPLAY: ":10"
|
||||
|
||||
# - name: Diagnostics after smoke test run (processes, max_user_watches, number of opened file handles)
|
||||
# run: |
|
||||
# set -e
|
||||
# ps -ef
|
||||
# cat /proc/sys/fs/inotify/max_user_watches
|
||||
# lsof | wc -l
|
||||
# continue-on-error: true
|
||||
# if: always()
|
||||
@@ -22,3 +22,4 @@ product.overrides.json
|
||||
*.snap.actual
|
||||
*.tsbuildinfo
|
||||
.vscode-test
|
||||
vscode-telemetry-docs/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
disturl="https://electronjs.org/headers"
|
||||
target="37.3.1"
|
||||
ms_build_id="12342881"
|
||||
ms_build_id="12404162"
|
||||
runtime="electron"
|
||||
build_from_source="true"
|
||||
legacy-peer-deps="true"
|
||||
|
||||
Vendored
+7
-4
@@ -211,9 +211,6 @@
|
||||
],
|
||||
|
||||
// --- Workbench ---
|
||||
"remote.extensionKind": {
|
||||
"msjsdiag.debugger-for-chrome": "workspace"
|
||||
},
|
||||
// "application.experimental.rendererProfiling": true, // https://github.com/microsoft/vscode/issues/265654
|
||||
|
||||
"editor.aiStats.enabled": true, // Team selfhosting on ai stats
|
||||
@@ -223,5 +220,11 @@
|
||||
"chat.promptFilesRecommendations": {
|
||||
"plan-fast": true,
|
||||
"plan-deep": true
|
||||
}
|
||||
},
|
||||
// Needed for kusto tool in data.prompt.md
|
||||
"azureMcp.enabledServices": [
|
||||
"kusto"
|
||||
],
|
||||
"azureMcp.serverMode": "all",
|
||||
"azureMcp.readOnly": true
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ parameters:
|
||||
default: false
|
||||
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
@@ -70,6 +72,19 @@ steps:
|
||||
displayName: Install build dependencies
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
mkdir -p .build/nodejs-musl
|
||||
NODE_VERSION=$(grep '^target=' remote/.npmrc | cut -d '"' -f 2)
|
||||
BUILD_ID=$(grep '^ms_build_id=' remote/.npmrc | cut -d '"' -f 2)
|
||||
gh release download "v${NODE_VERSION}-${BUILD_ID}" -R microsoft/vscode-node -p "node-v${NODE_VERSION}-linux-${VSCODE_ARCH}-musl.tar.gz" --dir .build/nodejs-musl --clobber
|
||||
tar -xzf ".build/nodejs-musl/node-v${NODE_VERSION}-linux-${VSCODE_ARCH}-musl.tar.gz" -C ".build/nodejs-musl" --strip-components=1
|
||||
rm ".build/nodejs-musl/node-v${NODE_VERSION}-linux-${VSCODE_ARCH}-musl.tar.gz"
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Download NodeJS MUSL
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
|
||||
@@ -88,6 +103,7 @@ steps:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
VSCODE_REMOTE_DEPENDENCIES_CONTAINER_NAME: vscodehub.azurecr.io/vscode-linux-build-agent:alpine-$(VSCODE_ARCH)
|
||||
VSCODE_HOST_MOUNT: "/mnt/vss/_work/1/s"
|
||||
VSCODE_NPMRC_PATH: $(NPMRC_PATH)
|
||||
displayName: Install dependencies
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
parameters:
|
||||
- name: channel
|
||||
type: string
|
||||
default: 1.85
|
||||
default: 1.88
|
||||
- name: targets
|
||||
default: []
|
||||
type: object
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
steps:
|
||||
- checkout: self
|
||||
fetchDepth: 1
|
||||
fetchTags: false
|
||||
displayName: Checkout microsoft/vscode
|
||||
@@ -18,9 +18,6 @@ parameters:
|
||||
- name: sbomPackageVersion
|
||||
type: string
|
||||
default: ""
|
||||
- name: isProduction
|
||||
type: boolean
|
||||
default: true
|
||||
- name: condition
|
||||
type: string
|
||||
default: succeeded()
|
||||
@@ -80,7 +77,6 @@ steps:
|
||||
targetPath: ${{ parameters.targetPath }}
|
||||
artifactName: $(ARTIFACT_NAME)
|
||||
sbomEnabled: ${{ parameters.sbomEnabled }}
|
||||
isProduction: ${{ parameters.isProduction }}
|
||||
${{ if ne(parameters.sbomBuildDropPath, '') }}:
|
||||
sbomBuildDropPath: ${{ parameters.sbomBuildDropPath }}
|
||||
${{ if ne(parameters.sbomPackageName, '') }}:
|
||||
|
||||
@@ -4,12 +4,19 @@
|
||||
{
|
||||
"file": [
|
||||
"src/vs/base/test/common/uri.test.ts",
|
||||
"src/vs/workbench/api/test/browser/extHostTelemetry.test.ts"
|
||||
"src/vs/workbench/api/test/browser/extHostTelemetry.test.ts",
|
||||
"src/vs/base/test/common/yaml.test.ts"
|
||||
],
|
||||
"_justification": "These are dummy credentials in tests."
|
||||
},
|
||||
{
|
||||
"file": [
|
||||
".build/linux/deb/amd64/code-amd64/usr/share/code/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
".build/linux/deb/amd64/code-amd64/usr/share/code/resources/app/extensions/emmet/dist/node/emmetNodeMain.js",
|
||||
".build/linux/deb/armhf/code-armhf/usr/share/code/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
".build/linux/deb/armhf/code-armhf/usr/share/code/resources/app/extensions/emmet/dist/node/emmetNodeMain.js",
|
||||
".build/linux/deb/arm64/code-arm64/usr/share/code/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
".build/linux/deb/arm64/code-arm64/usr/share/code/resources/app/extensions/emmet/dist/node/emmetNodeMain.js",
|
||||
".build/linux/rpm/x86_64/rpmbuild/BUILD/usr/share/code/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
".build/linux/rpm/x86_64/rpmbuild/BUILD/usr/share/code/resources/app/extensions/emmet/dist/node/emmetNodeMain.js",
|
||||
".build/linux/rpm/armv7hl/rpmbuild/BUILD/usr/share/code/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
@@ -33,6 +40,12 @@
|
||||
},
|
||||
{
|
||||
"file": [
|
||||
".build/linux/deb/amd64/code-insiders-amd64/usr/share/code-insiders/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
".build/linux/deb/amd64/code-insiders-amd64/usr/share/code-insiders/resources/app/extensions/emmet/dist/node/emmetNodeMain.js",
|
||||
".build/linux/deb/armhf/code-insiders-armhf/usr/share/code-insiders/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
".build/linux/deb/armhf/code-insiders-armhf/usr/share/code-insiders/resources/app/extensions/emmet/dist/node/emmetNodeMain.js",
|
||||
".build/linux/deb/arm64/code-insiders-arm64/usr/share/code-insiders/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
".build/linux/deb/arm64/code-insiders-arm64/usr/share/code-insiders/resources/app/extensions/emmet/dist/node/emmetNodeMain.js",
|
||||
".build/linux/rpm/x86_64/rpmbuild/BUILD/usr/share/code-insiders/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
".build/linux/rpm/x86_64/rpmbuild/BUILD/usr/share/code-insiders/resources/app/extensions/emmet/dist/node/emmetNodeMain.js",
|
||||
".build/linux/rpm/armv7hl/rpmbuild/BUILD/usr/share/code-insiders/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
@@ -56,6 +69,12 @@
|
||||
},
|
||||
{
|
||||
"file": [
|
||||
".build/linux/deb/amd64/code-exploration-amd64/usr/share/code-exploration/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
".build/linux/deb/amd64/code-exploration-amd64/usr/share/code-exploration/resources/app/extensions/emmet/dist/node/emmetNodeMain.js",
|
||||
".build/linux/deb/armhf/code-exploration-armhf/usr/share/code-exploration/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
".build/linux/deb/armhf/code-exploration-armhf/usr/share/code-exploration/resources/app/extensions/emmet/dist/node/emmetNodeMain.js",
|
||||
".build/linux/deb/arm64/code-exploration-arm64/usr/share/code-exploration/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
".build/linux/deb/arm64/code-exploration-arm64/usr/share/code-exploration/resources/app/extensions/emmet/dist/node/emmetNodeMain.js",
|
||||
".build/linux/rpm/x86_64/rpmbuild/BUILD/usr/share/code-exploration/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
".build/linux/rpm/x86_64/rpmbuild/BUILD/usr/share/code-exploration/resources/app/extensions/emmet/dist/node/emmetNodeMain.js",
|
||||
".build/linux/rpm/armv7hl/rpmbuild/BUILD/usr/share/code-exploration/resources/app/extensions/github-authentication/dist/extension.js",
|
||||
|
||||
@@ -12,6 +12,8 @@ parameters:
|
||||
default: false
|
||||
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
@@ -71,9 +73,7 @@ steps:
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/unsigned_vscode_cli_darwin_x64_cli.zip
|
||||
artifactName: unsigned_vscode_cli_darwin_x64_cli
|
||||
displayName: Publish unsigned_vscode_cli_darwin_x64_cli artifact
|
||||
sbomBuildDropPath: $(Build.ArtifactStagingDirectory)/cli
|
||||
sbomPackageName: "VS Code macOS x64 CLI (unsigned)"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
sbomEnabled: false
|
||||
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}:
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
@@ -81,6 +81,4 @@ steps:
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/unsigned_vscode_cli_darwin_arm64_cli.zip
|
||||
artifactName: unsigned_vscode_cli_darwin_arm64_cli
|
||||
displayName: Publish unsigned_vscode_cli_darwin_arm64_cli artifact
|
||||
sbomBuildDropPath: $(Build.ArtifactStagingDirectory)/cli
|
||||
sbomPackageName: "VS Code macOS arm64 CLI (unsigned)"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
sbomEnabled: false
|
||||
|
||||
@@ -5,6 +5,8 @@ parameters:
|
||||
type: boolean
|
||||
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
|
||||
@@ -132,7 +132,6 @@ steps:
|
||||
${{ else }}:
|
||||
artifactName: crash-dump-macos-$(VSCODE_ARCH)-${{ parameters.VSCODE_TEST_ARTIFACT_NAME }}-$(System.JobAttempt)
|
||||
displayName: "Publish Crash Reports"
|
||||
isProduction: false
|
||||
sbomEnabled: false
|
||||
continueOnError: true
|
||||
condition: failed()
|
||||
@@ -147,7 +146,6 @@ steps:
|
||||
${{ else }}:
|
||||
artifactName: node-modules-macos-$(VSCODE_ARCH)-${{ parameters.VSCODE_TEST_ARTIFACT_NAME }}-$(System.JobAttempt)
|
||||
displayName: "Publish Node Modules"
|
||||
isProduction: false
|
||||
sbomEnabled: false
|
||||
continueOnError: true
|
||||
condition: failed()
|
||||
@@ -160,7 +158,6 @@ steps:
|
||||
${{ else }}:
|
||||
artifactName: logs-macos-$(VSCODE_ARCH)-${{ parameters.VSCODE_TEST_ARTIFACT_NAME }}-$(System.JobAttempt)
|
||||
displayName: "Publish Log Files"
|
||||
isProduction: false
|
||||
sbomEnabled: false
|
||||
continueOnError: true
|
||||
condition: succeededOrFailed()
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
|
||||
@@ -17,6 +17,8 @@ parameters:
|
||||
default: ""
|
||||
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
|
||||
@@ -15,6 +15,8 @@ parameters:
|
||||
type: string
|
||||
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
|
||||
@@ -147,7 +147,6 @@ steps:
|
||||
${{ else }}:
|
||||
artifactName: crash-dump-linux-$(VSCODE_ARCH)-${{ parameters.VSCODE_TEST_ARTIFACT_NAME }}-$(System.JobAttempt)
|
||||
displayName: "Publish Crash Reports"
|
||||
isProduction: false
|
||||
sbomEnabled: false
|
||||
continueOnError: true
|
||||
condition: failed()
|
||||
@@ -162,7 +161,6 @@ steps:
|
||||
${{ else }}:
|
||||
artifactName: node-modules-linux-$(VSCODE_ARCH)-${{ parameters.VSCODE_TEST_ARTIFACT_NAME }}-$(System.JobAttempt)
|
||||
displayName: "Publish Node Modules"
|
||||
isProduction: false
|
||||
sbomEnabled: false
|
||||
continueOnError: true
|
||||
condition: failed()
|
||||
@@ -175,7 +173,6 @@ steps:
|
||||
${{ else }}:
|
||||
artifactName: logs-linux-$(VSCODE_ARCH)-${{ parameters.VSCODE_TEST_ARTIFACT_NAME }}-$(System.JobAttempt)
|
||||
displayName: "Publish Log Files"
|
||||
isProduction: false
|
||||
sbomEnabled: false
|
||||
continueOnError: true
|
||||
condition: succeededOrFailed()
|
||||
|
||||
@@ -22,6 +22,8 @@ parameters:
|
||||
default: ""
|
||||
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
|
||||
@@ -98,10 +98,7 @@ variables:
|
||||
- name: VSCODE_PRIVATE_BUILD
|
||||
value: ${{ ne(variables['Build.Repository.Uri'], 'https://github.com/microsoft/vscode.git') }}
|
||||
- name: NPM_REGISTRY
|
||||
${{ if in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') }}: # disable terrapin when in VSCODE_CIBUILD
|
||||
value: none
|
||||
${{ else }}:
|
||||
value: ${{ parameters.NPM_REGISTRY }}
|
||||
value: ${{ parameters.NPM_REGISTRY }}
|
||||
- name: CARGO_REGISTRY
|
||||
value: ${{ parameters.CARGO_REGISTRY }}
|
||||
- name: VSCODE_QUALITY
|
||||
@@ -194,13 +191,7 @@ extends:
|
||||
stages:
|
||||
- stage: Compile
|
||||
jobs:
|
||||
- job: Compile
|
||||
timeoutInMinutes: 90
|
||||
pool:
|
||||
name: AcesShared
|
||||
os: macOS
|
||||
steps:
|
||||
- template: build/azure-pipelines/product-compile.yml@self
|
||||
- template: build/azure-pipelines/product-compile.yml@self
|
||||
|
||||
- ${{ if or(eq(parameters.VSCODE_BUILD_LINUX, true),eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true),eq(parameters.VSCODE_BUILD_LINUX_ARM64, true),eq(parameters.VSCODE_BUILD_ALPINE, true),eq(parameters.VSCODE_BUILD_ALPINE_ARM64, true),eq(parameters.VSCODE_BUILD_MACOS, true),eq(parameters.VSCODE_BUILD_MACOS_ARM64, true),eq(parameters.VSCODE_BUILD_WIN32, true),eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }}:
|
||||
- stage: CompileCLI
|
||||
@@ -265,8 +256,7 @@ extends:
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}:
|
||||
- job: CLIMacOSX64
|
||||
pool:
|
||||
name: Azure Pipelines
|
||||
image: macOS-13
|
||||
name: AcesShared
|
||||
os: macOS
|
||||
variables:
|
||||
# todo@connor4312 to diagnose build flakes
|
||||
@@ -282,8 +272,7 @@ extends:
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_MACOS_ARM64, true)) }}:
|
||||
- job: CLIMacOSARM64
|
||||
pool:
|
||||
name: Azure Pipelines
|
||||
image: macOS-13
|
||||
name: AcesShared
|
||||
os: macOS
|
||||
variables:
|
||||
# todo@connor4312 to diagnose build flakes
|
||||
@@ -296,27 +285,17 @@ extends:
|
||||
VSCODE_BUILD_MACOS_ARM64: ${{ parameters.VSCODE_BUILD_MACOS_ARM64 }}
|
||||
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}:
|
||||
- job: CLIWindowsX64
|
||||
pool:
|
||||
name: 1es-windows-2022-x64
|
||||
os: windows
|
||||
steps:
|
||||
- template: build/azure-pipelines/win32/cli-build-win32.yml@self
|
||||
parameters:
|
||||
VSCODE_CHECK_ONLY: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
VSCODE_BUILD_WIN32: ${{ parameters.VSCODE_BUILD_WIN32 }}
|
||||
- template: build/azure-pipelines/win32/product-build-win32-cli.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: x64
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
VSCODE_CHECK_ONLY: ${{ variables.VSCODE_CIBUILD }}
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }}:
|
||||
- job: CLIWindowsARM64
|
||||
pool:
|
||||
name: 1es-windows-2022-x64
|
||||
os: windows
|
||||
steps:
|
||||
- template: build/azure-pipelines/win32/cli-build-win32.yml@self
|
||||
parameters:
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
VSCODE_BUILD_WIN32_ARM64: ${{ parameters.VSCODE_BUILD_WIN32_ARM64 }}
|
||||
- template: build/azure-pipelines/win32/product-build-win32-cli.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: arm64
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_COMPILE_ONLY, false)) }}:
|
||||
- stage: APIScan
|
||||
@@ -343,88 +322,44 @@ extends:
|
||||
os: windows
|
||||
jobs:
|
||||
- ${{ if eq(variables['VSCODE_CIBUILD'], true) }}:
|
||||
- job: WindowsElectronTests
|
||||
displayName: Electron Tests
|
||||
timeoutInMinutes: 50
|
||||
variables:
|
||||
VSCODE_ARCH: x64
|
||||
steps:
|
||||
- template: build/azure-pipelines/win32/product-build-win32.yml@self
|
||||
parameters:
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
VSCODE_ARCH: x64
|
||||
VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_TEST_ARTIFACT_NAME: electron
|
||||
VSCODE_RUN_ELECTRON_TESTS: true
|
||||
- job: WindowsBrowserTests
|
||||
displayName: Browser Tests
|
||||
timeoutInMinutes: 50
|
||||
variables:
|
||||
VSCODE_ARCH: x64
|
||||
steps:
|
||||
- template: build/azure-pipelines/win32/product-build-win32.yml@self
|
||||
parameters:
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
VSCODE_ARCH: x64
|
||||
VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_TEST_ARTIFACT_NAME: browser
|
||||
VSCODE_RUN_BROWSER_TESTS: true
|
||||
- job: WindowsRemoteTests
|
||||
displayName: Remote Tests
|
||||
timeoutInMinutes: 50
|
||||
variables:
|
||||
VSCODE_ARCH: x64
|
||||
steps:
|
||||
- template: build/azure-pipelines/win32/product-build-win32.yml@self
|
||||
parameters:
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
VSCODE_ARCH: x64
|
||||
VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_TEST_ARTIFACT_NAME: remote
|
||||
VSCODE_RUN_REMOTE_TESTS: true
|
||||
- template: build/azure-pipelines/win32/product-build-win32-ci.yml@self
|
||||
parameters:
|
||||
VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
VSCODE_TEST_SUITE: Electron
|
||||
- template: build/azure-pipelines/win32/product-build-win32-ci.yml@self
|
||||
parameters:
|
||||
VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
VSCODE_TEST_SUITE: Browser
|
||||
- template: build/azure-pipelines/win32/product-build-win32-ci.yml@self
|
||||
parameters:
|
||||
VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
VSCODE_TEST_SUITE: Remote
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_WIN32, true)) }}:
|
||||
- job: Windows
|
||||
timeoutInMinutes: 120
|
||||
variables:
|
||||
- template: build/azure-pipelines/win32/product-build-win32.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: x64
|
||||
templateContext:
|
||||
sdl:
|
||||
suppression:
|
||||
suppressionFile: $(Build.SourcesDirectory)\.config\guardian\.gdnsuppress
|
||||
steps:
|
||||
- template: build/azure-pipelines/win32/product-build-win32.yml@self
|
||||
parameters:
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
VSCODE_ARCH: x64
|
||||
VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_RUN_ELECTRON_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }}
|
||||
VSCODE_RUN_BROWSER_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }}
|
||||
VSCODE_RUN_REMOTE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }}
|
||||
|
||||
- job: WindowsCLISign
|
||||
timeoutInMinutes: 90
|
||||
steps:
|
||||
- template: build/azure-pipelines/win32/product-build-win32-cli-sign.yml@self
|
||||
parameters:
|
||||
VSCODE_BUILD_WIN32: ${{ parameters.VSCODE_BUILD_WIN32 }}
|
||||
VSCODE_BUILD_WIN32_ARM64: ${{ parameters.VSCODE_BUILD_WIN32_ARM64 }}
|
||||
VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
VSCODE_RUN_ELECTRON_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }}
|
||||
VSCODE_RUN_BROWSER_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }}
|
||||
VSCODE_RUN_REMOTE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }}
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }}:
|
||||
- job: WindowsARM64
|
||||
timeoutInMinutes: 90
|
||||
variables:
|
||||
- template: build/azure-pipelines/win32/product-build-win32.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: arm64
|
||||
templateContext:
|
||||
sdl:
|
||||
suppression:
|
||||
suppressionFile: $(Build.SourcesDirectory)\.config\guardian\.gdnsuppress
|
||||
steps:
|
||||
- template: build/azure-pipelines/win32/product-build-win32.yml@self
|
||||
parameters:
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
VSCODE_ARCH: arm64
|
||||
VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), or(eq(parameters.VSCODE_BUILD_WIN32, true), eq(parameters.VSCODE_BUILD_WIN32_ARM64, true))) }}:
|
||||
- template: build/azure-pipelines/win32/product-build-win32-cli-sign.yml@self
|
||||
parameters:
|
||||
VSCODE_BUILD_WIN32: ${{ parameters.VSCODE_BUILD_WIN32 }}
|
||||
VSCODE_BUILD_WIN32_ARM64: ${{ parameters.VSCODE_BUILD_WIN32_ARM64 }}
|
||||
|
||||
- ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_LINUX'], true)) }}:
|
||||
- stage: Linux
|
||||
@@ -676,6 +611,9 @@ extends:
|
||||
displayName: Publish Build
|
||||
steps:
|
||||
- template: build/azure-pipelines/product-publish.yml@self
|
||||
parameters:
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
VSCODE_SCHEDULEDBUILD: ${{ variables.VSCODE_SCHEDULEDBUILD }}
|
||||
|
||||
- ${{ if and(parameters.VSCODE_RELEASE, eq(variables['VSCODE_PRIVATE_BUILD'], false)) }}:
|
||||
- stage: ApproveRelease
|
||||
@@ -691,12 +629,10 @@ extends:
|
||||
- name: skipComponentGovernanceDetection
|
||||
value: true
|
||||
|
||||
- ${{ if or(and(parameters.VSCODE_RELEASE, eq(variables['VSCODE_PRIVATE_BUILD'], false)), and(in(parameters.VSCODE_QUALITY, 'insider', 'exploration'), eq(variables['VSCODE_SCHEDULEDBUILD'], true))) }}:
|
||||
- stage: Release
|
||||
dependsOn:
|
||||
- Publish
|
||||
- ${{ if and(parameters.VSCODE_RELEASE, eq(variables['VSCODE_PRIVATE_BUILD'], false)) }}:
|
||||
- ApproveRelease
|
||||
- ApproveRelease
|
||||
pool:
|
||||
name: 1es-ubuntu-22.04-x64
|
||||
os: linux
|
||||
|
||||
@@ -1,148 +1,157 @@
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
versionFilePath: .nvmrc
|
||||
jobs:
|
||||
- job: Compile
|
||||
timeoutInMinutes: 60
|
||||
pool:
|
||||
name: AcesShared
|
||||
os: macOS
|
||||
templateContext:
|
||||
outputs:
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/compilation.tar.gz
|
||||
artifactName: Compilation
|
||||
displayName: Publish compilation artifact
|
||||
isProduction: false
|
||||
sbomEnabled: false
|
||||
steps:
|
||||
- template: ./common/checkout.yml@self
|
||||
|
||||
- template: ./distro/download-distro.yml@self
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
versionFilePath: .nvmrc
|
||||
|
||||
- task: AzureKeyVault@2
|
||||
displayName: "Azure Key Vault: Get Secrets"
|
||||
inputs:
|
||||
azureSubscription: vscode
|
||||
KeyVaultName: vscode-build-secrets
|
||||
SecretsFilter: "github-distro-mixin-password"
|
||||
- template: ./distro/download-distro.yml@self
|
||||
|
||||
- script: node build/setup-npm-registry.js $NPM_REGISTRY
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Registry
|
||||
- task: AzureKeyVault@2
|
||||
displayName: "Azure Key Vault: Get Secrets"
|
||||
inputs:
|
||||
azureSubscription: vscode
|
||||
KeyVaultName: vscode-build-secrets
|
||||
SecretsFilter: "github-distro-mixin-password"
|
||||
|
||||
- script: mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.js compile $(node -p process.arch) > .build/packagelockhash
|
||||
displayName: Prepare node_modules cache key
|
||||
- script: node build/setup-npm-registry.js $NPM_REGISTRY
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Registry
|
||||
|
||||
- task: Cache@2
|
||||
inputs:
|
||||
key: '"node_modules" | .build/packagelockhash'
|
||||
path: .build/node_modules_cache
|
||||
cacheHitVar: NODE_MODULES_RESTORED
|
||||
displayName: Restore node_modules cache
|
||||
- script: mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.js compile $(node -p process.arch) > .build/packagelockhash
|
||||
displayName: Prepare node_modules cache key
|
||||
|
||||
- script: tar -xzf .build/node_modules_cache/cache.tgz
|
||||
condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Extract node_modules cache
|
||||
- task: Cache@2
|
||||
inputs:
|
||||
key: '"node_modules" | .build/packagelockhash'
|
||||
path: .build/node_modules_cache
|
||||
cacheHitVar: NODE_MODULES_RESTORED
|
||||
displayName: Restore node_modules cache
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
# Set the private NPM registry to the global npmrc file
|
||||
# so that authentication works for subfolders like build/, remote/, extensions/ etc
|
||||
# which does not have their own .npmrc file
|
||||
npm config set registry "$NPM_REGISTRY"
|
||||
echo "##vso[task.setvariable variable=NPMRC_PATH]$(npm config get userconfig)"
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM
|
||||
- script: tar -xzf .build/node_modules_cache/cache.tgz
|
||||
condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Extract node_modules cache
|
||||
|
||||
- task: npmAuthenticate@0
|
||||
inputs:
|
||||
workingFile: $(NPMRC_PATH)
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Authentication
|
||||
- script: |
|
||||
set -e
|
||||
# Set the private NPM registry to the global npmrc file
|
||||
# so that authentication works for subfolders like build/, remote/, extensions/ etc
|
||||
# which does not have their own .npmrc file
|
||||
npm config set registry "$NPM_REGISTRY"
|
||||
echo "##vso[task.setvariable variable=NPMRC_PATH]$(npm config get userconfig)"
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
- task: npmAuthenticate@0
|
||||
inputs:
|
||||
workingFile: $(NPMRC_PATH)
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Authentication
|
||||
|
||||
for i in {1..5}; do # try 5 times
|
||||
npm ci && break
|
||||
if [ $i -eq 5 ]; then
|
||||
echo "Npm install failed too many times" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Npm install failed $i, trying again..."
|
||||
done
|
||||
env:
|
||||
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Install dependencies
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
- script: |
|
||||
set -e
|
||||
|
||||
- script: node build/azure-pipelines/distro/mixin-npm
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Mixin distro node modules
|
||||
for i in {1..5}; do # try 5 times
|
||||
npm ci && break
|
||||
if [ $i -eq 5 ]; then
|
||||
echo "Npm install failed too many times" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Npm install failed $i, trying again..."
|
||||
done
|
||||
env:
|
||||
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Install dependencies
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
|
||||
mkdir -p .build/node_modules_cache
|
||||
tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Create node_modules archive
|
||||
- script: node build/azure-pipelines/distro/mixin-npm
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Mixin distro node modules
|
||||
|
||||
- script: node build/azure-pipelines/distro/mixin-quality
|
||||
displayName: Mixin distro quality
|
||||
- script: |
|
||||
set -e
|
||||
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
|
||||
mkdir -p .build/node_modules_cache
|
||||
tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Create node_modules archive
|
||||
|
||||
- template: common/install-builtin-extensions.yml@self
|
||||
- script: node build/azure-pipelines/distro/mixin-quality
|
||||
displayName: Mixin distro quality
|
||||
|
||||
- script: npm exec -- npm-run-all -lp core-ci extensions-ci hygiene eslint valid-layers-check define-class-fields-check vscode-dts-compile-check tsec-compile-check
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Compile & Hygiene
|
||||
- template: common/install-builtin-extensions.yml@self
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
npm run compile
|
||||
displayName: Compile smoke test suites (non-OSS)
|
||||
workingDirectory: test/smoke
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
- script: npm exec -- npm-run-all -lp core-ci extensions-ci hygiene eslint valid-layers-check define-class-fields-check vscode-dts-compile-check tsec-compile-check
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Compile & Hygiene
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
npm run compile
|
||||
displayName: Compile integration test suites (non-OSS)
|
||||
workingDirectory: test/integration/browser
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
- script: |
|
||||
set -e
|
||||
npm run compile
|
||||
displayName: Compile smoke test suites (non-OSS)
|
||||
workingDirectory: test/smoke
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- task: AzureCLI@2
|
||||
displayName: Fetch secrets
|
||||
inputs:
|
||||
azureSubscription: vscode
|
||||
scriptType: pscore
|
||||
scriptLocation: inlineScript
|
||||
addSpnToEnvironment: true
|
||||
inlineScript: |
|
||||
Write-Host "##vso[task.setvariable variable=AZURE_TENANT_ID]$env:tenantId"
|
||||
Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_ID]$env:servicePrincipalId"
|
||||
Write-Host "##vso[task.setvariable variable=AZURE_ID_TOKEN;issecret=true]$env:idToken"
|
||||
- script: |
|
||||
set -e
|
||||
npm run compile
|
||||
displayName: Compile integration test suites (non-OSS)
|
||||
workingDirectory: test/integration/browser
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
AZURE_STORAGE_ACCOUNT="vscodeweb" \
|
||||
AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \
|
||||
AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \
|
||||
AZURE_ID_TOKEN="$(AZURE_ID_TOKEN)" \
|
||||
node build/azure-pipelines/upload-sourcemaps
|
||||
displayName: Upload sourcemaps to Azure
|
||||
- task: AzureCLI@2
|
||||
displayName: Fetch secrets
|
||||
inputs:
|
||||
azureSubscription: vscode
|
||||
scriptType: pscore
|
||||
scriptLocation: inlineScript
|
||||
addSpnToEnvironment: true
|
||||
inlineScript: |
|
||||
Write-Host "##vso[task.setvariable variable=AZURE_TENANT_ID]$env:tenantId"
|
||||
Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_ID]$env:servicePrincipalId"
|
||||
Write-Host "##vso[task.setvariable variable=AZURE_ID_TOKEN;issecret=true]$env:idToken"
|
||||
|
||||
- script: ./build/azure-pipelines/common/extract-telemetry.sh
|
||||
displayName: Generate lists of telemetry events
|
||||
- script: |
|
||||
set -e
|
||||
AZURE_STORAGE_ACCOUNT="vscodeweb" \
|
||||
AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \
|
||||
AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \
|
||||
AZURE_ID_TOKEN="$(AZURE_ID_TOKEN)" \
|
||||
node build/azure-pipelines/upload-sourcemaps
|
||||
displayName: Upload sourcemaps to Azure
|
||||
|
||||
- script: tar -cz --exclude='.build/node_modules_cache' --exclude='.build/node_modules_list.txt' --exclude='.build/distro' -f $(Build.ArtifactStagingDirectory)/compilation.tar.gz $(ls -d .build out-* test/integration/browser/out test/smoke/out test/automation/out 2>/dev/null)
|
||||
displayName: Compress compilation artifact
|
||||
- script: ./build/azure-pipelines/common/extract-telemetry.sh
|
||||
displayName: Generate lists of telemetry events
|
||||
|
||||
- template: common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/compilation.tar.gz
|
||||
artifactName: Compilation
|
||||
displayName: Publish compilation artifact
|
||||
sbomEnabled: false
|
||||
- script: tar -cz --exclude='.build/node_modules_cache' --exclude='.build/node_modules_list.txt' --exclude='.build/distro' -f $(Build.ArtifactStagingDirectory)/compilation.tar.gz $(ls -d .build out-* test/integration/browser/out test/smoke/out test/automation/out 2>/dev/null)
|
||||
displayName: Compress compilation artifact
|
||||
|
||||
- script: npm run download-builtin-extensions-cg
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Download component details of built-in extensions
|
||||
- script: npm run download-builtin-extensions-cg
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Download component details of built-in extensions
|
||||
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
displayName: "Component Detection"
|
||||
inputs:
|
||||
sourceScanPath: $(Build.SourcesDirectory)
|
||||
alertWarningLevel: Medium
|
||||
continueOnError: true
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
displayName: "Component Detection"
|
||||
inputs:
|
||||
sourceScanPath: $(Build.SourcesDirectory)
|
||||
alertWarningLevel: Medium
|
||||
continueOnError: true
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
parameters:
|
||||
- name: VSCODE_QUALITY
|
||||
type: string
|
||||
- name: VSCODE_SCHEDULEDBUILD
|
||||
type: boolean
|
||||
|
||||
steps:
|
||||
- template: ./common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
@@ -93,3 +101,11 @@ steps:
|
||||
displayName: Publish the artifacts processed for this stage attempt
|
||||
sbomEnabled: false
|
||||
condition: always()
|
||||
|
||||
- ${{ if and(in(parameters.VSCODE_QUALITY, 'insider', 'exploration'), eq(parameters.VSCODE_SCHEDULEDBUILD, true)) }}:
|
||||
- script: node build/azure-pipelines/common/releaseBuild.js
|
||||
env:
|
||||
AZURE_TENANT_ID: "$(AZURE_TENANT_ID)"
|
||||
AZURE_CLIENT_ID: "$(AZURE_CLIENT_ID)"
|
||||
AZURE_ID_TOKEN: "$(AZURE_ID_TOKEN)"
|
||||
displayName: Release build
|
||||
|
||||
@@ -3,6 +3,8 @@ parameters:
|
||||
type: boolean
|
||||
|
||||
steps:
|
||||
- template: ./common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
parameters:
|
||||
- name: VSCODE_BUILD_WIN32
|
||||
type: boolean
|
||||
default: false
|
||||
- name: VSCODE_BUILD_WIN32_ARM64
|
||||
type: boolean
|
||||
default: false
|
||||
- name: VSCODE_CHECK_ONLY
|
||||
type: boolean
|
||||
default: false
|
||||
- name: VSCODE_QUALITY
|
||||
type: string
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
versionFilePath: .nvmrc
|
||||
|
||||
- template: ../cli/cli-apply-patches.yml@self
|
||||
|
||||
- task: Npm@1
|
||||
displayName: Download openssl prebuilt
|
||||
inputs:
|
||||
command: custom
|
||||
customCommand: pack @vscode-internal/openssl-prebuilt@0.0.11
|
||||
customRegistry: useFeed
|
||||
customFeed: "Monaco/openssl-prebuilt"
|
||||
workingDir: $(Build.ArtifactStagingDirectory)
|
||||
|
||||
- powershell: |
|
||||
mkdir $(Build.ArtifactStagingDirectory)/openssl
|
||||
tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.11.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl
|
||||
displayName: Extract openssl prebuilt
|
||||
|
||||
- template: ../cli/install-rust-win32.yml@self
|
||||
parameters:
|
||||
targets:
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}:
|
||||
- x86_64-pc-windows-msvc
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}:
|
||||
- aarch64-pc-windows-msvc
|
||||
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}:
|
||||
- template: ../cli/cli-compile.yml@self
|
||||
parameters:
|
||||
VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }}
|
||||
VSCODE_CLI_TARGET: x86_64-pc-windows-msvc
|
||||
VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_x64_cli
|
||||
VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }}
|
||||
VSCODE_CLI_ENV:
|
||||
OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-windows-static/lib
|
||||
OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-windows-static/include
|
||||
RUSTFLAGS: "-Ctarget-feature=+crt-static -Clink-args=/guard:cf -Clink-args=/CETCOMPAT"
|
||||
CFLAGS: "/guard:cf /Qspectre"
|
||||
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}:
|
||||
- template: ../cli/cli-compile.yml@self
|
||||
parameters:
|
||||
VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }}
|
||||
VSCODE_CLI_TARGET: aarch64-pc-windows-msvc
|
||||
VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_arm64_cli
|
||||
VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }}
|
||||
VSCODE_CLI_ENV:
|
||||
OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-windows-static/lib
|
||||
OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-windows-static/include
|
||||
RUSTFLAGS: "-C target-feature=+crt-static -Clink-args=/guard:cf -Clink-args=/CETCOMPAT:NO"
|
||||
CFLAGS: "/guard:cf /Qspectre"
|
||||
|
||||
- ${{ if not(parameters.VSCODE_CHECK_ONLY) }}:
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}:
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/unsigned_vscode_cli_win32_arm64_cli.zip
|
||||
artifactName: unsigned_vscode_cli_win32_arm64_cli
|
||||
displayName: Publish unsigned_vscode_cli_win32_arm64_cli artifact
|
||||
sbomBuildDropPath: $(Build.ArtifactStagingDirectory)/cli
|
||||
sbomPackageName: "VS Code Windows arm64 CLI (unsigned)"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}:
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/unsigned_vscode_cli_win32_x64_cli.zip
|
||||
artifactName: unsigned_vscode_cli_win32_x64_cli
|
||||
displayName: Publish unsigned_vscode_cli_win32_x64_cli artifact
|
||||
sbomBuildDropPath: $(Build.ArtifactStagingDirectory)/cli
|
||||
sbomPackageName: "VS Code Windows x64 CLI (unsigned)"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
@@ -0,0 +1,49 @@
|
||||
parameters:
|
||||
- name: VSCODE_CIBUILD
|
||||
type: boolean
|
||||
- name: VSCODE_QUALITY
|
||||
type: string
|
||||
- name: VSCODE_TEST_SUITE
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
- job: Windows${{ parameters.VSCODE_TEST_SUITE }}
|
||||
displayName: ${{ parameters.VSCODE_TEST_SUITE }} Tests
|
||||
timeoutInMinutes: 50
|
||||
variables:
|
||||
VSCODE_ARCH: x64
|
||||
templateContext:
|
||||
outputs:
|
||||
- output: pipelineArtifact
|
||||
targetPath: .build/crashes
|
||||
artifactName: crash-dump-windows-$(VSCODE_ARCH)-${{ lower(parameters.VSCODE_TEST_SUITE) }}-$(System.JobAttempt)
|
||||
displayName: Publish Crash Reports
|
||||
sbomEnabled: false
|
||||
isProduction: false
|
||||
condition: failed()
|
||||
- output: pipelineArtifact
|
||||
targetPath: node_modules
|
||||
artifactName: node-modules-windows-$(VSCODE_ARCH)-${{ lower(parameters.VSCODE_TEST_SUITE) }}-$(System.JobAttempt)
|
||||
displayName: Publish Node Modules
|
||||
sbomEnabled: false
|
||||
isProduction: false
|
||||
condition: failed()
|
||||
- output: pipelineArtifact
|
||||
targetPath: .build/logs
|
||||
artifactName: logs-windows-$(VSCODE_ARCH)-${{ lower(parameters.VSCODE_TEST_SUITE) }}-$(System.JobAttempt)
|
||||
displayName: Publish Log Files
|
||||
sbomEnabled: false
|
||||
isProduction: false
|
||||
condition: succeededOrFailed()
|
||||
steps:
|
||||
- template: ./steps/product-build-win32-compile.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: x64
|
||||
VSCODE_CIBUILD: ${{ parameters.VSCODE_CIBUILD }}
|
||||
VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }}
|
||||
${{ if eq(parameters.VSCODE_TEST_SUITE, 'Electron') }}:
|
||||
VSCODE_RUN_ELECTRON_TESTS: true
|
||||
${{ if eq(parameters.VSCODE_TEST_SUITE, 'Browser') }}:
|
||||
VSCODE_RUN_BROWSER_TESTS: true
|
||||
${{ if eq(parameters.VSCODE_TEST_SUITE, 'Remote') }}:
|
||||
VSCODE_RUN_REMOTE_TESTS: true
|
||||
@@ -4,56 +4,80 @@ parameters:
|
||||
- name: VSCODE_BUILD_WIN32_ARM64
|
||||
type: boolean
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
displayName: "Use Node.js"
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
versionFilePath: .nvmrc
|
||||
|
||||
- task: AzureKeyVault@2
|
||||
displayName: "Azure Key Vault: Get Secrets"
|
||||
inputs:
|
||||
azureSubscription: vscode
|
||||
KeyVaultName: vscode-build-secrets
|
||||
SecretsFilter: "github-distro-mixin-password"
|
||||
|
||||
- powershell: node build/setup-npm-registry.js $env:NPM_REGISTRY build
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Registry
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
# Set the private NPM registry to the global npmrc file
|
||||
# so that authentication works for subfolders like build/, remote/, extensions/ etc
|
||||
# which does not have their own .npmrc file
|
||||
exec { npm config set registry "$env:NPM_REGISTRY" }
|
||||
$NpmrcPath = (npm config get userconfig)
|
||||
echo "##vso[task.setvariable variable=NPMRC_PATH]$NpmrcPath"
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM
|
||||
|
||||
- task: npmAuthenticate@0
|
||||
inputs:
|
||||
workingFile: $(NPMRC_PATH)
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Authentication
|
||||
|
||||
- powershell: |
|
||||
. azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm ci }
|
||||
workingDirectory: build
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
retryCountOnTaskFailure: 5
|
||||
displayName: Install build dependencies
|
||||
|
||||
- template: ../cli/cli-win32-sign.yml@self
|
||||
parameters:
|
||||
VSCODE_CLI_ARTIFACTS:
|
||||
jobs:
|
||||
- job: WindowsCLISign
|
||||
timeoutInMinutes: 90
|
||||
templateContext:
|
||||
outputParentDirectory: $(Build.ArtifactStagingDirectory)
|
||||
outputs:
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}:
|
||||
- unsigned_vscode_cli_win32_x64_cli
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/vscode_cli_win32_x64_cli.zip
|
||||
artifactName: vscode_cli_win32_x64_cli
|
||||
displayName: Publish signed artifact with ID vscode_cli_win32_x64_cli
|
||||
sbomBuildDropPath: $(Build.BinariesDirectory)/sign/unsigned_vscode_cli_win32_x64_cli
|
||||
sbomPackageName: "VS Code Windows x64 CLI"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}:
|
||||
- unsigned_vscode_cli_win32_arm64_cli
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/vscode_cli_win32_arm64_cli.zip
|
||||
artifactName: vscode_cli_win32_arm64_cli
|
||||
displayName: Publish signed artifact with ID vscode_cli_win32_arm64_cli
|
||||
sbomBuildDropPath: $(Build.BinariesDirectory)/sign/unsigned_vscode_cli_win32_arm64_cli
|
||||
sbomPackageName: "VS Code Windows arm64 CLI"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
displayName: "Use Node.js"
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
versionFilePath: .nvmrc
|
||||
|
||||
- task: AzureKeyVault@2
|
||||
displayName: "Azure Key Vault: Get Secrets"
|
||||
inputs:
|
||||
azureSubscription: vscode
|
||||
KeyVaultName: vscode-build-secrets
|
||||
SecretsFilter: "github-distro-mixin-password"
|
||||
|
||||
- powershell: node build/setup-npm-registry.js $env:NPM_REGISTRY build
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Registry
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
# Set the private NPM registry to the global npmrc file
|
||||
# so that authentication works for subfolders like build/, remote/, extensions/ etc
|
||||
# which does not have their own .npmrc file
|
||||
exec { npm config set registry "$env:NPM_REGISTRY" }
|
||||
$NpmrcPath = (npm config get userconfig)
|
||||
echo "##vso[task.setvariable variable=NPMRC_PATH]$NpmrcPath"
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM
|
||||
|
||||
- task: npmAuthenticate@0
|
||||
inputs:
|
||||
workingFile: $(NPMRC_PATH)
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Authentication
|
||||
|
||||
- powershell: |
|
||||
. azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm ci }
|
||||
workingDirectory: build
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
retryCountOnTaskFailure: 5
|
||||
displayName: Install build dependencies
|
||||
|
||||
- template: ./steps/product-build-win32-cli-sign.yml@self
|
||||
parameters:
|
||||
VSCODE_CLI_ARTIFACTS:
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}:
|
||||
- unsigned_vscode_cli_win32_x64_cli
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}:
|
||||
- unsigned_vscode_cli_win32_arm64_cli
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
parameters:
|
||||
- name: VSCODE_ARCH
|
||||
type: string
|
||||
- name: VSCODE_CHECK_ONLY
|
||||
type: boolean
|
||||
default: false
|
||||
- name: VSCODE_QUALITY
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
- job: CLIWindows${{ upper(parameters.VSCODE_ARCH) }}
|
||||
pool:
|
||||
name: 1es-windows-2022-x64
|
||||
os: windows
|
||||
timeoutInMinutes: 30
|
||||
variables:
|
||||
VSCODE_ARCH: ${{ parameters.VSCODE_ARCH }}
|
||||
templateContext:
|
||||
outputs:
|
||||
- ${{ if not(parameters.VSCODE_CHECK_ONLY) }}:
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli.zip
|
||||
artifactName: unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli
|
||||
displayName: Publish unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli artifact
|
||||
sbomEnabled: false
|
||||
isProduction: false
|
||||
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
versionFilePath: .nvmrc
|
||||
|
||||
- template: ../cli/cli-apply-patches.yml@self
|
||||
|
||||
- task: Npm@1
|
||||
displayName: Download openssl prebuilt
|
||||
inputs:
|
||||
command: custom
|
||||
customCommand: pack @vscode-internal/openssl-prebuilt@0.0.11
|
||||
customRegistry: useFeed
|
||||
customFeed: "Monaco/openssl-prebuilt"
|
||||
workingDir: $(Build.ArtifactStagingDirectory)
|
||||
|
||||
- powershell: |
|
||||
mkdir $(Build.ArtifactStagingDirectory)/openssl
|
||||
tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.11.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl
|
||||
displayName: Extract openssl prebuilt
|
||||
|
||||
- template: ./steps/product-build-win32-install-rust.yml@self
|
||||
parameters:
|
||||
targets:
|
||||
- ${{ if eq(parameters.VSCODE_ARCH, 'x64') }}:
|
||||
- x86_64-pc-windows-msvc
|
||||
- ${{ if eq(parameters.VSCODE_ARCH, 'arm64') }}:
|
||||
- aarch64-pc-windows-msvc
|
||||
|
||||
- template: ../cli/cli-compile.yml@self
|
||||
parameters:
|
||||
VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }}
|
||||
${{ if eq(parameters.VSCODE_ARCH, 'x64') }}:
|
||||
VSCODE_CLI_TARGET: x86_64-pc-windows-msvc
|
||||
${{ if eq(parameters.VSCODE_ARCH, 'arm64') }}:
|
||||
VSCODE_CLI_TARGET: aarch64-pc-windows-msvc
|
||||
VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli
|
||||
VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }}
|
||||
VSCODE_CLI_ENV:
|
||||
OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/$(VSCODE_ARCH)-windows-static/lib
|
||||
OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/$(VSCODE_ARCH)-windows-static/include
|
||||
${{ if eq(parameters.VSCODE_ARCH, 'x64') }}:
|
||||
RUSTFLAGS: "-Ctarget-feature=+crt-static -Clink-args=/guard:cf -Clink-args=/CETCOMPAT"
|
||||
${{ if eq(parameters.VSCODE_ARCH, 'arm64') }}:
|
||||
RUSTFLAGS: "-Ctarget-feature=+crt-static -Clink-args=/guard:cf -Clink-args=/CETCOMPAT:NO"
|
||||
CFLAGS: "/guard:cf /Qspectre"
|
||||
@@ -1,10 +1,10 @@
|
||||
parameters:
|
||||
- name: VSCODE_QUALITY
|
||||
type: string
|
||||
- name: VSCODE_ARCH
|
||||
type: string
|
||||
- name: VSCODE_CIBUILD
|
||||
type: boolean
|
||||
- name: VSCODE_QUALITY
|
||||
type: string
|
||||
- name: VSCODE_RUN_ELECTRON_TESTS
|
||||
type: boolean
|
||||
default: false
|
||||
@@ -14,360 +14,90 @@ parameters:
|
||||
- name: VSCODE_RUN_REMOTE_TESTS
|
||||
type: boolean
|
||||
default: false
|
||||
- name: VSCODE_TEST_ARTIFACT_NAME
|
||||
type: string
|
||||
default: ""
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
versionFilePath: .nvmrc
|
||||
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: "3.x"
|
||||
addToPath: true
|
||||
|
||||
- template: ../distro/download-distro.yml@self
|
||||
|
||||
- task: AzureKeyVault@2
|
||||
displayName: "Azure Key Vault: Get Secrets"
|
||||
inputs:
|
||||
azureSubscription: vscode
|
||||
KeyVaultName: vscode-build-secrets
|
||||
SecretsFilter: "github-distro-mixin-password"
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: Compilation
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
displayName: Download compilation output
|
||||
|
||||
- task: ExtractFiles@1
|
||||
displayName: Extract compilation output
|
||||
inputs:
|
||||
archiveFilePatterns: "$(Build.ArtifactStagingDirectory)/compilation.tar.gz"
|
||||
cleanDestinationFolder: false
|
||||
|
||||
- powershell: node build/setup-npm-registry.js $env:NPM_REGISTRY
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Registry
|
||||
|
||||
- pwsh: |
|
||||
mkdir .build -ea 0
|
||||
node build/azure-pipelines/common/computeNodeModulesCacheKey.js win32 $(VSCODE_ARCH) $(node -p process.arch) > .build/packagelockhash
|
||||
displayName: Prepare node_modules cache key
|
||||
|
||||
- task: Cache@2
|
||||
inputs:
|
||||
key: '"node_modules" | .build/packagelockhash'
|
||||
path: .build/node_modules_cache
|
||||
cacheHitVar: NODE_MODULES_RESTORED
|
||||
displayName: Restore node_modules cache
|
||||
|
||||
- powershell: 7z.exe x .build/node_modules_cache/cache.7z -aoa
|
||||
condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Extract node_modules cache
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
# Set the private NPM registry to the global npmrc file
|
||||
# so that authentication works for subfolders like build/, remote/, extensions/ etc
|
||||
# which does not have their own .npmrc file
|
||||
exec { npm config set registry "$env:NPM_REGISTRY" }
|
||||
$NpmrcPath = (npm config get userconfig)
|
||||
echo "##vso[task.setvariable variable=NPMRC_PATH]$NpmrcPath"
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM
|
||||
|
||||
- task: npmAuthenticate@0
|
||||
inputs:
|
||||
workingFile: $(NPMRC_PATH)
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Authentication
|
||||
|
||||
# Remove once https://github.com/parcel-bundler/watcher/pull/202 is merged.
|
||||
- pwsh: |
|
||||
$includes = @'
|
||||
{
|
||||
'target_defaults': {
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
"msvs_settings": {
|
||||
"VCCLCompilerTool": {
|
||||
"AdditionalOptions": [
|
||||
"/guard:cf",
|
||||
"/w34244",
|
||||
"/w34267",
|
||||
]
|
||||
},
|
||||
"VCLinkerTool": {
|
||||
"AdditionalOptions": [
|
||||
"/guard:cf",
|
||||
]
|
||||
}
|
||||
}
|
||||
}]
|
||||
]
|
||||
}
|
||||
}
|
||||
'@
|
||||
|
||||
if (!(Test-Path "~/.gyp")) {
|
||||
mkdir "~/.gyp"
|
||||
}
|
||||
echo $includes > "~/.gyp/include.gypi"
|
||||
displayName: Create include.gypi
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm ci }
|
||||
env:
|
||||
npm_config_arch: $(VSCODE_ARCH)
|
||||
npm_config_foreground_scripts: "true"
|
||||
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
retryCountOnTaskFailure: 5
|
||||
displayName: Install dependencies
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
|
||||
- powershell: node build/azure-pipelines/distro/mixin-npm
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Mixin distro node modules
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt }
|
||||
exec { mkdir -Force .build/node_modules_cache }
|
||||
exec { 7z.exe a .build/node_modules_cache/cache.7z -mx3 `@.build/node_modules_list.txt }
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Create node_modules archive
|
||||
|
||||
- powershell: node build/azure-pipelines/distro/mixin-quality
|
||||
displayName: Mixin distro quality
|
||||
|
||||
- template: ../common/install-builtin-extensions.yml@self
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- powershell: node build\lib\policies win32
|
||||
displayName: Generate Group Policy definitions
|
||||
retryCountOnTaskFailure: 3
|
||||
|
||||
- ${{ if and(ne(parameters.VSCODE_CIBUILD, true), ne(parameters.VSCODE_QUALITY, 'exploration')) }}:
|
||||
- powershell: node build/win32/explorer-dll-fetcher .build/win32/appx
|
||||
displayName: Download Explorer dll
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm run gulp "vscode-win32-$(VSCODE_ARCH)-min-ci" }
|
||||
exec { npm run gulp "vscode-win32-$(VSCODE_ARCH)-inno-updater" }
|
||||
echo "##vso[task.setvariable variable=BUILT_CLIENT]true"
|
||||
echo "##vso[task.setvariable variable=CodeSigningFolderPath]$(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)"
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Build client
|
||||
|
||||
# Note: the appx prepare step has to follow Build client step since build step replaces the template
|
||||
# strings in the raw manifest file at resources/win32/appx/AppxManifest.xml and places it under
|
||||
# <build-out-dir>/appx/manifest, we need a separate step to prepare the appx package with the
|
||||
# final contents. In our case only the manifest file is bundled into the appx package.
|
||||
- ${{ if and(ne(parameters.VSCODE_CIBUILD, true), ne(parameters.VSCODE_QUALITY, 'exploration')) }}:
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
# Add Windows SDK to path
|
||||
$sdk = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64"
|
||||
$env:PATH = "$sdk;$env:PATH"
|
||||
$AppxName = if ('$(VSCODE_QUALITY)' -eq 'stable') { 'code' } else { 'code_insider' }
|
||||
makeappx pack /d "$(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)/appx/manifest" /p "$(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)/appx/${AppxName}_$(VSCODE_ARCH).appx" /nv
|
||||
# Remove the raw manifest folder
|
||||
Remove-Item -Path "$(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)/appx/manifest" -Recurse -Force
|
||||
displayName: Prepare appx package
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm run gulp "vscode-reh-win32-$(VSCODE_ARCH)-min-ci" }
|
||||
mv ..\vscode-reh-win32-$(VSCODE_ARCH) ..\vscode-server-win32-$(VSCODE_ARCH) # TODO@joaomoreno
|
||||
echo "##vso[task.setvariable variable=BUILT_SERVER]true"
|
||||
echo "##vso[task.setvariable variable=CodeSigningFolderPath]$(CodeSigningFolderPath),$(Agent.BuildDirectory)/vscode-server-win32-$(VSCODE_ARCH)"
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Build server
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm run gulp "vscode-reh-web-win32-$(VSCODE_ARCH)-min-ci" }
|
||||
mv ..\vscode-reh-web-win32-$(VSCODE_ARCH) ..\vscode-server-win32-$(VSCODE_ARCH)-web # TODO@joaomoreno
|
||||
echo "##vso[task.setvariable variable=BUILT_WEB]true"
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Build server (web)
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli
|
||||
patterns: "**"
|
||||
path: $(Build.ArtifactStagingDirectory)/cli
|
||||
displayName: Download VS Code CLI
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ArtifactName = (gci -Path "$(Build.ArtifactStagingDirectory)/cli" | Select-Object -last 1).FullName
|
||||
Expand-Archive -Path $ArtifactName -DestinationPath "$(Build.ArtifactStagingDirectory)/cli"
|
||||
$AppProductJson = Get-Content -Raw -Path "$(Agent.BuildDirectory)\VSCode-win32-$(VSCODE_ARCH)\resources\app\product.json" | ConvertFrom-Json
|
||||
$CliAppName = $AppProductJson.tunnelApplicationName
|
||||
$AppName = $AppProductJson.applicationName
|
||||
Move-Item -Path "$(Build.ArtifactStagingDirectory)/cli/$AppName.exe" -Destination "$(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/$CliAppName.exe"
|
||||
displayName: Move VS Code CLI
|
||||
|
||||
- task: UseDotNet@2
|
||||
inputs:
|
||||
version: 6.x
|
||||
|
||||
- task: EsrpCodeSigning@5
|
||||
inputs:
|
||||
UseMSIAuthentication: true
|
||||
ConnectedServiceName: vscode-esrp
|
||||
AppRegistrationClientId: $(ESRP_CLIENT_ID)
|
||||
AppRegistrationTenantId: $(ESRP_TENANT_ID)
|
||||
AuthAKVName: vscode-esrp
|
||||
AuthSignCertName: esrp-sign
|
||||
FolderPath: .
|
||||
Pattern: noop
|
||||
displayName: 'Install ESRP Tooling'
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
$EsrpCodeSigningTool = (gci -directory -filter EsrpCodeSigning_* $(Agent.RootDirectory)\_tasks | Select-Object -last 1).FullName
|
||||
$Version = (gci -directory $EsrpCodeSigningTool | Select-Object -last 1).FullName
|
||||
echo "##vso[task.setvariable variable=EsrpCliDllPath]$Version\net6.0\esrpcli.dll"
|
||||
displayName: Find ESRP CLI
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
mkdir -Force .build/node-cpuprofile
|
||||
exec { npx deemon --detach --wait -- npx zx build/azure-pipelines/win32/codesign.js }
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
NODE_DEBUG: "net,child_process"
|
||||
NODE_OPTIONS: "--report-filename=stdout --report-uncaught-exception --report-on-fatalerror --cpu-prof --cpu-prof-dir=.build/node-cpuprofile"
|
||||
displayName: ✍️ Codesign
|
||||
|
||||
- ${{ if or(eq(parameters.VSCODE_RUN_ELECTRON_TESTS, true), eq(parameters.VSCODE_RUN_BROWSER_TESTS, true), eq(parameters.VSCODE_RUN_REMOTE_TESTS, true)) }}:
|
||||
- template: product-build-win32-test.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: ${{ parameters.VSCODE_ARCH }}
|
||||
VSCODE_RUN_ELECTRON_TESTS: ${{ parameters.VSCODE_RUN_ELECTRON_TESTS }}
|
||||
VSCODE_RUN_BROWSER_TESTS: ${{ parameters.VSCODE_RUN_BROWSER_TESTS }}
|
||||
VSCODE_RUN_REMOTE_TESTS: ${{ parameters.VSCODE_RUN_REMOTE_TESTS }}
|
||||
VSCODE_TEST_ARTIFACT_NAME: ${{ parameters.VSCODE_TEST_ARTIFACT_NAME }}
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npx deemon --attach -- npx zx build/azure-pipelines/win32/codesign.js }
|
||||
condition: succeededOrFailed()
|
||||
env:
|
||||
NODE_DEBUG: "net,child_process"
|
||||
NODE_OPTIONS: "--report-filename=stdout --report-uncaught-exception --report-on-fatalerror --cpu-prof --cpu-prof-dir=.build/node-cpuprofile"
|
||||
displayName: "✍️ Post-job: Codesign"
|
||||
|
||||
- powershell: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$PackageJson = Get-Content -Raw -Path ..\VSCode-win32-$(VSCODE_ARCH)\resources\app\package.json | ConvertFrom-Json
|
||||
$Version = $PackageJson.version
|
||||
|
||||
$ClientArchivePath = ".build\win32-$(VSCODE_ARCH)\VSCode-win32-$(VSCODE_ARCH)-$Version.zip"
|
||||
$ServerArchivePath = ".build\win32-$(VSCODE_ARCH)\vscode-server-win32-$(VSCODE_ARCH).zip"
|
||||
$WebArchivePath = ".build\win32-$(VSCODE_ARCH)\vscode-server-win32-$(VSCODE_ARCH)-web.zip"
|
||||
|
||||
$SystemSetupPath = ".build\win32-$(VSCODE_ARCH)\system-setup\VSCodeSetup-$(VSCODE_ARCH)-$Version.exe"
|
||||
$UserSetupPath = ".build\win32-$(VSCODE_ARCH)\user-setup\VSCodeUserSetup-$(VSCODE_ARCH)-$Version.exe"
|
||||
|
||||
mv .build\win32-$(VSCODE_ARCH)\system-setup\VSCodeSetup.exe $SystemSetupPath
|
||||
mv .build\win32-$(VSCODE_ARCH)\user-setup\VSCodeSetup.exe $UserSetupPath
|
||||
|
||||
echo "##vso[task.setvariable variable=CLIENT_PATH]$ClientArchivePath"
|
||||
echo "##vso[task.setvariable variable=SERVER_PATH]$ServerArchivePath"
|
||||
echo "##vso[task.setvariable variable=WEB_PATH]$WebArchivePath"
|
||||
|
||||
echo "##vso[task.setvariable variable=SYSTEM_SETUP_PATH]$SystemSetupPath"
|
||||
echo "##vso[task.setvariable variable=USER_SETUP_PATH]$UserSetupPath"
|
||||
condition: succeededOrFailed()
|
||||
displayName: Move setup packages
|
||||
|
||||
- powershell: echo "##vso[task.setvariable variable=ARTIFACT_PREFIX]attempt$(System.JobAttempt)_"
|
||||
condition: and(succeededOrFailed(), notIn(variables['Agent.JobStatus'], 'Succeeded', 'SucceededWithIssues'))
|
||||
displayName: Generate artifact prefix
|
||||
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: .build/node-cpuprofile
|
||||
artifactName: $(ARTIFACT_PREFIX)node-cpuprofile-$(VSCODE_ARCH)
|
||||
displayName: Publish Codesign cpu profile
|
||||
sbomEnabled: false
|
||||
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: $(CLIENT_PATH)
|
||||
artifactName: $(ARTIFACT_PREFIX)vscode_client_win32_$(VSCODE_ARCH)_archive
|
||||
displayName: Publish archive
|
||||
sbomBuildDropPath: $(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)
|
||||
sbomPackageName: "VS Code Windows $(VSCODE_ARCH)"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
condition: and(succeededOrFailed(), ne(variables['CLIENT_PATH'], ''))
|
||||
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: $(SERVER_PATH)
|
||||
artifactName: $(ARTIFACT_PREFIX)vscode_server_win32_$(VSCODE_ARCH)_archive
|
||||
displayName: Publish server archive
|
||||
sbomBuildDropPath: $(Agent.BuildDirectory)/vscode-server-win32-$(VSCODE_ARCH)
|
||||
sbomPackageName: "VS Code Windows $(VSCODE_ARCH) Server"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
condition: and(succeededOrFailed(), ne(variables['SERVER_PATH'], ''))
|
||||
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: $(WEB_PATH)
|
||||
artifactName: $(ARTIFACT_PREFIX)vscode_web_win32_$(VSCODE_ARCH)_archive
|
||||
displayName: Publish web server archive
|
||||
sbomBuildDropPath: $(Agent.BuildDirectory)/vscode-server-win32-$(VSCODE_ARCH)-web
|
||||
sbomPackageName: "VS Code Windows $(VSCODE_ARCH) Web"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
condition: and(succeededOrFailed(), ne(variables['WEB_PATH'], ''))
|
||||
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: $(SYSTEM_SETUP_PATH)
|
||||
artifactName: $(ARTIFACT_PREFIX)vscode_client_win32_$(VSCODE_ARCH)_setup
|
||||
displayName: Publish system setup
|
||||
sbomBuildDropPath: $(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)
|
||||
sbomPackageName: "VS Code Windows $(VSCODE_ARCH) System Setup"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
condition: and(succeededOrFailed(), ne(variables['SYSTEM_SETUP_PATH'], ''))
|
||||
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: $(USER_SETUP_PATH)
|
||||
artifactName: $(ARTIFACT_PREFIX)vscode_client_win32_$(VSCODE_ARCH)_user-setup
|
||||
displayName: Publish user setup
|
||||
sbomBuildDropPath: $(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)
|
||||
sbomPackageName: "VS Code Windows $(VSCODE_ARCH) User Setup"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
condition: and(succeededOrFailed(), ne(variables['USER_SETUP_PATH'], ''))
|
||||
jobs:
|
||||
- job: Windows_${{ parameters.VSCODE_ARCH }}
|
||||
displayName: Windows${{ upper(parameters.VSCODE_ARCH) }}
|
||||
timeoutInMinutes: 90
|
||||
variables:
|
||||
VSCODE_ARCH: ${{ parameters.VSCODE_ARCH }}
|
||||
templateContext:
|
||||
outputParentDirectory: $(Build.SourcesDirectory)/.build/win32-$(VSCODE_ARCH)
|
||||
outputs:
|
||||
- ${{ if or(eq(parameters.VSCODE_RUN_ELECTRON_TESTS, true), eq(parameters.VSCODE_RUN_BROWSER_TESTS, true), eq(parameters.VSCODE_RUN_REMOTE_TESTS, true)) }}:
|
||||
- output: pipelineArtifact
|
||||
targetPath: .build/crashes
|
||||
artifactName: crash-dump-windows-$(VSCODE_ARCH)-$(System.JobAttempt)
|
||||
displayName: Publish Crash Reports
|
||||
sbomEnabled: false
|
||||
isProduction: false
|
||||
condition: failed()
|
||||
- output: pipelineArtifact
|
||||
targetPath: node_modules
|
||||
artifactName: node-modules-windows-$(VSCODE_ARCH)-$(System.JobAttempt)
|
||||
displayName: Publish Node Modules
|
||||
sbomEnabled: false
|
||||
isProduction: false
|
||||
condition: failed()
|
||||
- output: pipelineArtifact
|
||||
targetPath: .build/logs
|
||||
artifactName: logs-windows-$(VSCODE_ARCH)-$(System.JobAttempt)
|
||||
displayName: Publish Log Files
|
||||
sbomEnabled: false
|
||||
isProduction: false
|
||||
condition: succeededOrFailed()
|
||||
- output: pipelineArtifact
|
||||
targetPath: .build/node-cpuprofile
|
||||
artifactName: $(ARTIFACT_PREFIX)node-cpuprofile-$(VSCODE_ARCH)
|
||||
displayName: Publish Codesign cpu profile
|
||||
sbomEnabled: false
|
||||
isProduction: false
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(SYSTEM_SETUP_PATH)
|
||||
artifactName: $(ARTIFACT_PREFIX)vscode_client_win32_$(VSCODE_ARCH)_setup
|
||||
displayName: Publish system setup
|
||||
sbomBuildDropPath: $(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)
|
||||
sbomPackageName: "VS Code Windows $(VSCODE_ARCH) System Setup"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
condition: and(succeededOrFailed(), ne(variables['SYSTEM_SETUP_PATH'], ''))
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(USER_SETUP_PATH)
|
||||
artifactName: $(ARTIFACT_PREFIX)vscode_client_win32_$(VSCODE_ARCH)_user-setup
|
||||
displayName: Publish user setup
|
||||
sbomBuildDropPath: $(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)
|
||||
sbomPackageName: "VS Code Windows $(VSCODE_ARCH) User Setup"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
condition: and(succeededOrFailed(), ne(variables['USER_SETUP_PATH'], ''))
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(CLIENT_PATH)
|
||||
artifactName: $(ARTIFACT_PREFIX)vscode_client_win32_$(VSCODE_ARCH)_archive
|
||||
displayName: Publish archive
|
||||
sbomBuildDropPath: $(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)
|
||||
sbomPackageName: "VS Code Windows $(VSCODE_ARCH)"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
condition: and(succeededOrFailed(), ne(variables['CLIENT_PATH'], ''))
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(SERVER_PATH)
|
||||
artifactName: $(ARTIFACT_PREFIX)vscode_server_win32_$(VSCODE_ARCH)_archive
|
||||
displayName: Publish server archive
|
||||
sbomBuildDropPath: $(Agent.BuildDirectory)/vscode-server-win32-$(VSCODE_ARCH)
|
||||
sbomPackageName: "VS Code Windows $(VSCODE_ARCH) Server"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
condition: and(succeededOrFailed(), ne(variables['SERVER_PATH'], ''))
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(WEB_PATH)
|
||||
artifactName: $(ARTIFACT_PREFIX)vscode_web_win32_$(VSCODE_ARCH)_archive
|
||||
displayName: Publish web server archive
|
||||
sbomBuildDropPath: $(Agent.BuildDirectory)/vscode-server-win32-$(VSCODE_ARCH)-web
|
||||
sbomPackageName: "VS Code Windows $(VSCODE_ARCH) Web"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
condition: and(succeededOrFailed(), ne(variables['WEB_PATH'], ''))
|
||||
steps:
|
||||
- template: ./steps/product-build-win32-compile.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: ${{ parameters.VSCODE_ARCH }}
|
||||
VSCODE_CIBUILD: ${{ parameters.VSCODE_CIBUILD }}
|
||||
VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }}
|
||||
VSCODE_RUN_ELECTRON_TESTS: ${{ parameters.VSCODE_RUN_ELECTRON_TESTS }}
|
||||
VSCODE_RUN_BROWSER_TESTS: ${{ parameters.VSCODE_RUN_BROWSER_TESTS }}
|
||||
VSCODE_RUN_REMOTE_TESTS: ${{ parameters.VSCODE_RUN_REMOTE_TESTS }}
|
||||
|
||||
@@ -5,6 +5,8 @@ parameters:
|
||||
type: string
|
||||
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
|
||||
+5
-14
@@ -33,15 +33,15 @@ steps:
|
||||
displayName: Download artifact
|
||||
inputs:
|
||||
artifact: ${{ target }}
|
||||
path: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}
|
||||
path: $(Build.BinariesDirectory)/pkg/${{ target }}
|
||||
|
||||
- task: ExtractFiles@1
|
||||
displayName: Extract artifact
|
||||
inputs:
|
||||
archiveFilePatterns: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/*.zip
|
||||
destinationFolder: $(Build.ArtifactStagingDirectory)/sign/${{ target }}
|
||||
archiveFilePatterns: $(Build.BinariesDirectory)/pkg/${{ target }}/*.zip
|
||||
destinationFolder: $(Build.BinariesDirectory)/sign/${{ target }}
|
||||
|
||||
- powershell: node build\azure-pipelines\common\sign $env:EsrpCliDllPath sign-windows $(Build.ArtifactStagingDirectory)/sign "*.exe"
|
||||
- powershell: node build\azure-pipelines\common\sign $env:EsrpCliDllPath sign-windows $(Build.BinariesDirectory)/sign "*.exe"
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
displayName: ✍️ Codesign
|
||||
@@ -55,16 +55,7 @@ steps:
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Archive signed files
|
||||
inputs:
|
||||
rootFolderOrFile: $(Build.ArtifactStagingDirectory)/sign/${{ target }}
|
||||
rootFolderOrFile: $(Build.BinariesDirectory)/sign/${{ target }}
|
||||
includeRootFolder: false
|
||||
archiveType: zip
|
||||
archiveFile: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip
|
||||
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip
|
||||
artifactName: $(ASSET_ID)
|
||||
displayName: Publish signed artifact with ID $(ASSET_ID)
|
||||
sbomBuildDropPath: $(Build.ArtifactStagingDirectory)/sign/${{ target }}
|
||||
sbomPackageName: "VS Code Windows ${{ target }} CLI"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
@@ -0,0 +1,314 @@
|
||||
parameters:
|
||||
- name: VSCODE_ARCH
|
||||
type: string
|
||||
- name: VSCODE_CIBUILD
|
||||
type: boolean
|
||||
- name: VSCODE_QUALITY
|
||||
type: string
|
||||
- name: VSCODE_RUN_ELECTRON_TESTS
|
||||
type: boolean
|
||||
default: false
|
||||
- name: VSCODE_RUN_BROWSER_TESTS
|
||||
type: boolean
|
||||
default: false
|
||||
- name: VSCODE_RUN_REMOTE_TESTS
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
steps:
|
||||
- template: ../../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
versionFilePath: .nvmrc
|
||||
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: "3.x"
|
||||
addToPath: true
|
||||
|
||||
- template: ../../distro/download-distro.yml@self
|
||||
|
||||
- task: AzureKeyVault@2
|
||||
displayName: "Azure Key Vault: Get Secrets"
|
||||
inputs:
|
||||
azureSubscription: vscode
|
||||
KeyVaultName: vscode-build-secrets
|
||||
SecretsFilter: "github-distro-mixin-password"
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: Compilation
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
displayName: Download compilation output
|
||||
|
||||
- task: ExtractFiles@1
|
||||
displayName: Extract compilation output
|
||||
inputs:
|
||||
archiveFilePatterns: "$(Build.ArtifactStagingDirectory)/compilation.tar.gz"
|
||||
cleanDestinationFolder: false
|
||||
|
||||
- powershell: node build/setup-npm-registry.js $env:NPM_REGISTRY
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Registry
|
||||
|
||||
- pwsh: |
|
||||
mkdir .build -ea 0
|
||||
node build/azure-pipelines/common/computeNodeModulesCacheKey.js win32 $(VSCODE_ARCH) $(node -p process.arch) > .build/packagelockhash
|
||||
displayName: Prepare node_modules cache key
|
||||
|
||||
- task: Cache@2
|
||||
inputs:
|
||||
key: '"node_modules" | .build/packagelockhash'
|
||||
path: .build/node_modules_cache
|
||||
cacheHitVar: NODE_MODULES_RESTORED
|
||||
displayName: Restore node_modules cache
|
||||
|
||||
- powershell: 7z.exe x .build/node_modules_cache/cache.7z -aoa
|
||||
condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Extract node_modules cache
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
# Set the private NPM registry to the global npmrc file
|
||||
# so that authentication works for subfolders like build/, remote/, extensions/ etc
|
||||
# which does not have their own .npmrc file
|
||||
exec { npm config set registry "$env:NPM_REGISTRY" }
|
||||
$NpmrcPath = (npm config get userconfig)
|
||||
echo "##vso[task.setvariable variable=NPMRC_PATH]$NpmrcPath"
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM
|
||||
|
||||
- task: npmAuthenticate@0
|
||||
inputs:
|
||||
workingFile: $(NPMRC_PATH)
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Authentication
|
||||
|
||||
# Remove once https://github.com/parcel-bundler/watcher/pull/202 is merged.
|
||||
- pwsh: |
|
||||
$includes = @'
|
||||
{
|
||||
'target_defaults': {
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
"msvs_settings": {
|
||||
"VCCLCompilerTool": {
|
||||
"AdditionalOptions": [
|
||||
"/guard:cf",
|
||||
"/w34244",
|
||||
"/w34267",
|
||||
]
|
||||
},
|
||||
"VCLinkerTool": {
|
||||
"AdditionalOptions": [
|
||||
"/guard:cf",
|
||||
]
|
||||
}
|
||||
}
|
||||
}]
|
||||
]
|
||||
}
|
||||
}
|
||||
'@
|
||||
|
||||
if (!(Test-Path "~/.gyp")) {
|
||||
mkdir "~/.gyp"
|
||||
}
|
||||
echo $includes > "~/.gyp/include.gypi"
|
||||
displayName: Create include.gypi
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm ci }
|
||||
env:
|
||||
npm_config_arch: $(VSCODE_ARCH)
|
||||
npm_config_foreground_scripts: "true"
|
||||
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
retryCountOnTaskFailure: 5
|
||||
displayName: Install dependencies
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
|
||||
- powershell: node build/azure-pipelines/distro/mixin-npm
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Mixin distro node modules
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt }
|
||||
exec { mkdir -Force .build/node_modules_cache }
|
||||
exec { 7z.exe a .build/node_modules_cache/cache.7z -mx3 `@.build/node_modules_list.txt }
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Create node_modules archive
|
||||
|
||||
- powershell: node build/azure-pipelines/distro/mixin-quality
|
||||
displayName: Mixin distro quality
|
||||
|
||||
- template: ../../common/install-builtin-extensions.yml@self
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- powershell: node build\lib\policies win32
|
||||
displayName: Generate Group Policy definitions
|
||||
retryCountOnTaskFailure: 3
|
||||
|
||||
- ${{ if and(ne(parameters.VSCODE_CIBUILD, true), ne(parameters.VSCODE_QUALITY, 'exploration')) }}:
|
||||
- powershell: node build/win32/explorer-dll-fetcher .build/win32/appx
|
||||
displayName: Download Explorer dll
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm run gulp "vscode-win32-$(VSCODE_ARCH)-min-ci" }
|
||||
exec { npm run gulp "vscode-win32-$(VSCODE_ARCH)-inno-updater" }
|
||||
echo "##vso[task.setvariable variable=BUILT_CLIENT]true"
|
||||
echo "##vso[task.setvariable variable=CodeSigningFolderPath]$(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)"
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Build client
|
||||
|
||||
# Note: the appx prepare step has to follow Build client step since build step replaces the template
|
||||
# strings in the raw manifest file at resources/win32/appx/AppxManifest.xml and places it under
|
||||
# <build-out-dir>/appx/manifest, we need a separate step to prepare the appx package with the
|
||||
# final contents. In our case only the manifest file is bundled into the appx package.
|
||||
- ${{ if and(ne(parameters.VSCODE_CIBUILD, true), ne(parameters.VSCODE_QUALITY, 'exploration')) }}:
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
# Add Windows SDK to path
|
||||
$sdk = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64"
|
||||
$env:PATH = "$sdk;$env:PATH"
|
||||
$AppxName = if ('$(VSCODE_QUALITY)' -eq 'stable') { 'code' } else { 'code_insider' }
|
||||
makeappx pack /d "$(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)/appx/manifest" /p "$(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)/appx/${AppxName}_$(VSCODE_ARCH).appx" /nv
|
||||
# Remove the raw manifest folder
|
||||
Remove-Item -Path "$(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)/appx/manifest" -Recurse -Force
|
||||
displayName: Prepare appx package
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm run gulp "vscode-reh-win32-$(VSCODE_ARCH)-min-ci" }
|
||||
mv ..\vscode-reh-win32-$(VSCODE_ARCH) ..\vscode-server-win32-$(VSCODE_ARCH) # TODO@joaomoreno
|
||||
echo "##vso[task.setvariable variable=BUILT_SERVER]true"
|
||||
echo "##vso[task.setvariable variable=CodeSigningFolderPath]$(CodeSigningFolderPath),$(Agent.BuildDirectory)/vscode-server-win32-$(VSCODE_ARCH)"
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Build server
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm run gulp "vscode-reh-web-win32-$(VSCODE_ARCH)-min-ci" }
|
||||
mv ..\vscode-reh-web-win32-$(VSCODE_ARCH) ..\vscode-server-win32-$(VSCODE_ARCH)-web # TODO@joaomoreno
|
||||
echo "##vso[task.setvariable variable=BUILT_WEB]true"
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Build server (web)
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli
|
||||
patterns: "**"
|
||||
path: $(Build.ArtifactStagingDirectory)/cli
|
||||
displayName: Download VS Code CLI
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ArtifactName = (gci -Path "$(Build.ArtifactStagingDirectory)/cli" | Select-Object -last 1).FullName
|
||||
Expand-Archive -Path $ArtifactName -DestinationPath "$(Build.ArtifactStagingDirectory)/cli"
|
||||
$AppProductJson = Get-Content -Raw -Path "$(Agent.BuildDirectory)\VSCode-win32-$(VSCODE_ARCH)\resources\app\product.json" | ConvertFrom-Json
|
||||
$CliAppName = $AppProductJson.tunnelApplicationName
|
||||
$AppName = $AppProductJson.applicationName
|
||||
Move-Item -Path "$(Build.ArtifactStagingDirectory)/cli/$AppName.exe" -Destination "$(Agent.BuildDirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/$CliAppName.exe"
|
||||
displayName: Move VS Code CLI
|
||||
|
||||
- task: UseDotNet@2
|
||||
inputs:
|
||||
version: 6.x
|
||||
|
||||
- task: EsrpCodeSigning@5
|
||||
inputs:
|
||||
UseMSIAuthentication: true
|
||||
ConnectedServiceName: vscode-esrp
|
||||
AppRegistrationClientId: $(ESRP_CLIENT_ID)
|
||||
AppRegistrationTenantId: $(ESRP_TENANT_ID)
|
||||
AuthAKVName: vscode-esrp
|
||||
AuthSignCertName: esrp-sign
|
||||
FolderPath: .
|
||||
Pattern: noop
|
||||
displayName: 'Install ESRP Tooling'
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
$EsrpCodeSigningTool = (gci -directory -filter EsrpCodeSigning_* $(Agent.RootDirectory)\_tasks | Select-Object -last 1).FullName
|
||||
$Version = (gci -directory $EsrpCodeSigningTool | Select-Object -last 1).FullName
|
||||
echo "##vso[task.setvariable variable=EsrpCliDllPath]$Version\net6.0\esrpcli.dll"
|
||||
displayName: Find ESRP CLI
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
mkdir -Force .build/node-cpuprofile
|
||||
exec { npx deemon --detach --wait -- npx zx build/azure-pipelines/win32/codesign.js }
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
NODE_DEBUG: "net,child_process"
|
||||
NODE_OPTIONS: "--report-filename=stdout --report-uncaught-exception --report-on-fatalerror --cpu-prof --cpu-prof-dir=.build/node-cpuprofile"
|
||||
displayName: ✍️ Codesign
|
||||
|
||||
- ${{ if or(eq(parameters.VSCODE_RUN_ELECTRON_TESTS, true), eq(parameters.VSCODE_RUN_BROWSER_TESTS, true), eq(parameters.VSCODE_RUN_REMOTE_TESTS, true)) }}:
|
||||
- template: product-build-win32-test.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: ${{ parameters.VSCODE_ARCH }}
|
||||
VSCODE_RUN_ELECTRON_TESTS: ${{ parameters.VSCODE_RUN_ELECTRON_TESTS }}
|
||||
VSCODE_RUN_BROWSER_TESTS: ${{ parameters.VSCODE_RUN_BROWSER_TESTS }}
|
||||
VSCODE_RUN_REMOTE_TESTS: ${{ parameters.VSCODE_RUN_REMOTE_TESTS }}
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npx deemon --attach -- npx zx build/azure-pipelines/win32/codesign.js }
|
||||
condition: succeededOrFailed()
|
||||
env:
|
||||
NODE_DEBUG: "net,child_process"
|
||||
NODE_OPTIONS: "--report-filename=stdout --report-uncaught-exception --report-on-fatalerror --cpu-prof --cpu-prof-dir=.build/node-cpuprofile"
|
||||
displayName: "✍️ Post-job: Codesign"
|
||||
|
||||
- powershell: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$PackageJson = Get-Content -Raw -Path ..\VSCode-win32-$(VSCODE_ARCH)\resources\app\package.json | ConvertFrom-Json
|
||||
$Version = $PackageJson.version
|
||||
|
||||
$ClientArchivePath = ".build\win32-$(VSCODE_ARCH)\VSCode-win32-$(VSCODE_ARCH)-$Version.zip"
|
||||
$ServerArchivePath = ".build\win32-$(VSCODE_ARCH)\vscode-server-win32-$(VSCODE_ARCH).zip"
|
||||
$WebArchivePath = ".build\win32-$(VSCODE_ARCH)\vscode-server-win32-$(VSCODE_ARCH)-web.zip"
|
||||
|
||||
$SystemSetupPath = ".build\win32-$(VSCODE_ARCH)\system-setup\VSCodeSetup-$(VSCODE_ARCH)-$Version.exe"
|
||||
$UserSetupPath = ".build\win32-$(VSCODE_ARCH)\user-setup\VSCodeUserSetup-$(VSCODE_ARCH)-$Version.exe"
|
||||
|
||||
mv .build\win32-$(VSCODE_ARCH)\system-setup\VSCodeSetup.exe $SystemSetupPath
|
||||
mv .build\win32-$(VSCODE_ARCH)\user-setup\VSCodeSetup.exe $UserSetupPath
|
||||
|
||||
echo "##vso[task.setvariable variable=CLIENT_PATH]$ClientArchivePath"
|
||||
echo "##vso[task.setvariable variable=SERVER_PATH]$ServerArchivePath"
|
||||
echo "##vso[task.setvariable variable=WEB_PATH]$WebArchivePath"
|
||||
|
||||
echo "##vso[task.setvariable variable=SYSTEM_SETUP_PATH]$SystemSetupPath"
|
||||
echo "##vso[task.setvariable variable=USER_SETUP_PATH]$UserSetupPath"
|
||||
condition: succeededOrFailed()
|
||||
displayName: Move setup packages
|
||||
|
||||
- powershell: echo "##vso[task.setvariable variable=ARTIFACT_PREFIX]attempt$(System.JobAttempt)_"
|
||||
condition: and(succeededOrFailed(), notIn(variables['Agent.JobStatus'], 'Succeeded', 'SucceededWithIssues'))
|
||||
displayName: Generate artifact prefix
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
parameters:
|
||||
- name: channel
|
||||
type: string
|
||||
default: 1.85
|
||||
default: 1.88
|
||||
- name: targets
|
||||
default: []
|
||||
type: object
|
||||
-43
@@ -7,8 +7,6 @@ parameters:
|
||||
type: boolean
|
||||
- name: VSCODE_RUN_REMOTE_TESTS
|
||||
type: boolean
|
||||
- name: VSCODE_TEST_ARTIFACT_NAME
|
||||
type: string
|
||||
|
||||
steps:
|
||||
- powershell: npm exec -- npm-run-all -lp "electron $(VSCODE_ARCH)" "playwright-install"
|
||||
@@ -142,47 +140,6 @@ steps:
|
||||
continueOnError: true
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: .build\crashes
|
||||
${{ if eq(parameters.VSCODE_TEST_ARTIFACT_NAME, '') }}:
|
||||
artifactName: crash-dump-windows-$(VSCODE_ARCH)-$(System.JobAttempt)
|
||||
${{ else }}:
|
||||
artifactName: crash-dump-windows-$(VSCODE_ARCH)-${{ parameters.VSCODE_TEST_ARTIFACT_NAME }}-$(System.JobAttempt)
|
||||
isProduction: false
|
||||
sbomEnabled: false
|
||||
displayName: "Publish Crash Reports"
|
||||
continueOnError: true
|
||||
condition: failed()
|
||||
|
||||
# In order to properly symbolify above crash reports
|
||||
# (if any), we need the compiled native modules too
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: node_modules
|
||||
${{ if eq(parameters.VSCODE_TEST_ARTIFACT_NAME, '') }}:
|
||||
artifactName: node-modules-windows-$(VSCODE_ARCH)-$(System.JobAttempt)
|
||||
${{ else }}:
|
||||
artifactName: node-modules-windows-$(VSCODE_ARCH)-${{ parameters.VSCODE_TEST_ARTIFACT_NAME }}-$(System.JobAttempt)
|
||||
isProduction: false
|
||||
sbomEnabled: false
|
||||
displayName: "Publish Node Modules"
|
||||
continueOnError: true
|
||||
condition: failed()
|
||||
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: .build\logs
|
||||
${{ if eq(parameters.VSCODE_TEST_ARTIFACT_NAME, '') }}:
|
||||
artifactName: logs-windows-$(VSCODE_ARCH)-$(System.JobAttempt)
|
||||
${{ else }}:
|
||||
artifactName: logs-windows-$(VSCODE_ARCH)-${{ parameters.VSCODE_TEST_ARTIFACT_NAME }}-$(System.JobAttempt)
|
||||
isProduction: false
|
||||
sbomEnabled: false
|
||||
displayName: "Publish Log Files"
|
||||
continueOnError: true
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish Tests Results
|
||||
inputs:
|
||||
@@ -51,6 +51,7 @@ const compilations = [
|
||||
'extensions/markdown-math/tsconfig.json',
|
||||
'extensions/media-preview/tsconfig.json',
|
||||
'extensions/merge-conflict/tsconfig.json',
|
||||
'extensions/mermaid-chat-features/tsconfig.json',
|
||||
'extensions/terminal-suggest/tsconfig.json',
|
||||
'extensions/microsoft-authentication/tsconfig.json',
|
||||
'extensions/notebook-renderers/tsconfig.json',
|
||||
|
||||
@@ -510,11 +510,12 @@ function translatePackageJSON(packageJSON, packageNLSPath) {
|
||||
const extensionsPath = path_1.default.join(root, 'extensions');
|
||||
// Additional projects to run esbuild on. These typically build code for webviews
|
||||
const esbuildMediaScripts = [
|
||||
'ipynb/esbuild.mjs',
|
||||
'markdown-language-features/esbuild-notebook.mjs',
|
||||
'markdown-language-features/esbuild-preview.mjs',
|
||||
'markdown-math/esbuild.mjs',
|
||||
'mermaid-chat-features/esbuild-chat-webview.mjs',
|
||||
'notebook-renderers/esbuild.mjs',
|
||||
'ipynb/esbuild.mjs',
|
||||
'simple-browser/esbuild-preview.mjs',
|
||||
];
|
||||
async function webpackExtensions(taskName, isWatch, webpackConfigLocations) {
|
||||
|
||||
@@ -559,11 +559,12 @@ const extensionsPath = path.join(root, 'extensions');
|
||||
|
||||
// Additional projects to run esbuild on. These typically build code for webviews
|
||||
const esbuildMediaScripts = [
|
||||
'ipynb/esbuild.mjs',
|
||||
'markdown-language-features/esbuild-notebook.mjs',
|
||||
'markdown-language-features/esbuild-preview.mjs',
|
||||
'markdown-math/esbuild.mjs',
|
||||
'mermaid-chat-features/esbuild-chat-webview.mjs',
|
||||
'notebook-renderers/esbuild.mjs',
|
||||
'ipynb/esbuild.mjs',
|
||||
'simple-browser/esbuild-preview.mjs',
|
||||
];
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ const dirs = [
|
||||
'extensions/markdown-math',
|
||||
'extensions/media-preview',
|
||||
'extensions/merge-conflict',
|
||||
'extensions/mermaid-chat-features',
|
||||
'extensions/microsoft-authentication',
|
||||
'extensions/notebook-renderers',
|
||||
'extensions/npm',
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { execSync } from 'child_process';
|
||||
import { join, resolve } from 'path';
|
||||
import { existsSync, rmSync } from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const rootPath = resolve(fileURLToPath(import.meta.url), '..', '..', '..');
|
||||
const telemetryDocsPath = join(rootPath, 'vscode-telemetry-docs');
|
||||
const repoUrl = 'https://github.com/microsoft/vscode-telemetry-docs';
|
||||
|
||||
console.log('Cloning vscode-telemetry-docs repository...');
|
||||
|
||||
// Remove existing directory if it exists
|
||||
if (existsSync(telemetryDocsPath)) {
|
||||
console.log('Removing existing vscode-telemetry-docs directory...');
|
||||
rmSync(telemetryDocsPath, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
try {
|
||||
// Clone the repository (shallow clone of main branch only)
|
||||
console.log(`Cloning ${repoUrl} to ${telemetryDocsPath}...`);
|
||||
execSync(`git clone --depth 1 --branch main --single-branch ${repoUrl} vscode-telemetry-docs`, {
|
||||
cwd: rootPath,
|
||||
stdio: 'inherit'
|
||||
});
|
||||
|
||||
console.log('Successfully cloned vscode-telemetry-docs repository.');
|
||||
} catch (error) {
|
||||
console.error('Failed to clone vscode-telemetry-docs repository:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -56,7 +56,16 @@ function npmInstall(dir, opts) {
|
||||
if (process.env['npm_config_arch'] === 'arm64') {
|
||||
run('sudo', ['docker', 'run', '--rm', '--privileged', 'multiarch/qemu-user-static', '--reset', '-p', 'yes'], opts);
|
||||
}
|
||||
run('sudo', ['docker', 'run', '-e', 'GITHUB_TOKEN', '-v', `${process.env['VSCODE_HOST_MOUNT']}:/root/vscode`, '-v', `${process.env['VSCODE_HOST_MOUNT']}/.build/.netrc:/root/.netrc`, '-w', path.resolve('/root/vscode', dir), process.env['VSCODE_REMOTE_DEPENDENCIES_CONTAINER_NAME'], 'sh', '-c', `\"chown -R root:root ${path.resolve('/root/vscode', dir)} && npm i -g node-gyp-build && npm ci\"`], opts);
|
||||
run('sudo', [
|
||||
'docker', 'run',
|
||||
'-e', 'GITHUB_TOKEN',
|
||||
'-v', `${process.env['VSCODE_HOST_MOUNT']}:/root/vscode`,
|
||||
'-v', `${process.env['VSCODE_HOST_MOUNT']}/.build/.netrc:/root/.netrc`,
|
||||
'-v', `${process.env['VSCODE_NPMRC_PATH']}:/root/.npmrc`,
|
||||
'-w', path.resolve('/root/vscode', dir),
|
||||
process.env['VSCODE_REMOTE_DEPENDENCIES_CONTAINER_NAME'],
|
||||
'sh', '-c', `\"chown -R root:root ${path.resolve('/root/vscode', dir)} && export PATH="/root/vscode/.build/nodejs-musl/usr/local/bin:$PATH" && npm i -g node-gyp-build && npm ci\"`
|
||||
], opts);
|
||||
run('sudo', ['chown', '-R', `${userinfo.uid}:${userinfo.gid}`, `${path.resolve(root, dir)}`], opts);
|
||||
} else {
|
||||
log(dir, 'Installing dependencies...');
|
||||
|
||||
Generated
+2424
-156
File diff suppressed because it is too large
Load Diff
+6
-1
@@ -43,7 +43,7 @@
|
||||
"@types/xml2js": "0.0.33",
|
||||
"@vscode/iconv-lite-umd": "0.7.0",
|
||||
"@vscode/ripgrep": "^1.15.13",
|
||||
"@vscode/vsce": "2.20.1",
|
||||
"@vscode/vsce": "3.6.1",
|
||||
"ansi-colors": "^3.2.3",
|
||||
"byline": "^5.0.0",
|
||||
"debug": "^4.3.2",
|
||||
@@ -71,5 +71,10 @@
|
||||
"optionalDependencies": {
|
||||
"tree-sitter-typescript": "^0.23.2",
|
||||
"vscode-gulp-watch": "^5.0.3"
|
||||
},
|
||||
"overrides": {
|
||||
"path-scurry": {
|
||||
"lru-cache": "11.2.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ async function* getPackageLockFiles(dir) {
|
||||
*/
|
||||
async function setup(url, file) {
|
||||
let contents = await fs.readFile(file, 'utf8');
|
||||
contents = contents.replace(/https:\/\/registry\.[^.]+\.com\//g, url);
|
||||
contents = contents.replace(/https:\/\/registry\.[^.]+\.org\//g, url);
|
||||
await fs.writeFile(file, contents);
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -86,6 +86,8 @@ export default tseslint.config(
|
||||
'local/code-no-unexternalized-strings': 'warn',
|
||||
'local/code-must-use-super-dispose': 'warn',
|
||||
'local/code-declare-service-brand': 'warn',
|
||||
'local/code-no-reader-after-await': 'warn',
|
||||
'local/code-no-observable-get-in-reactive-context': 'warn',
|
||||
'local/code-no-deep-import-of-internal': ['error', { '.*Internal': true, 'searchExtTypesInternal': false }],
|
||||
'local/code-layering': [
|
||||
'warn',
|
||||
@@ -307,7 +309,8 @@ export default tseslint.config(
|
||||
'terminate',
|
||||
'trigger',
|
||||
'unregister',
|
||||
'write'
|
||||
'write',
|
||||
'commit'
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -824,6 +827,7 @@ export default tseslint.config(
|
||||
'string_decoder',
|
||||
'tas-client-umd',
|
||||
'tls',
|
||||
'undici',
|
||||
'undici-types',
|
||||
'url',
|
||||
'util',
|
||||
@@ -1421,6 +1425,7 @@ export default tseslint.config(
|
||||
{
|
||||
files: [
|
||||
'extensions/markdown-language-features/**/*.ts',
|
||||
'extensions/mermaid-chat-features/**/*.ts',
|
||||
'extensions/media-preview/**/*.ts',
|
||||
'extensions/simple-browser/**/*.ts',
|
||||
'extensions/typescript-language-features/**/*.ts',
|
||||
@@ -1441,6 +1446,10 @@ export default tseslint.config(
|
||||
'extensions/simple-browser/tsconfig.json',
|
||||
'extensions/simple-browser/preview-src/tsconfig.json',
|
||||
|
||||
// Mermaid chat features
|
||||
'extensions/mermaid-chat-features/tsconfig.json',
|
||||
'extensions/mermaid-chat-features/chat-webview-src/tsconfig.json',
|
||||
|
||||
// TypeScript
|
||||
'extensions/typescript-language-features/tsconfig.json',
|
||||
'extensions/typescript-language-features/web/tsconfig.json',
|
||||
|
||||
@@ -539,6 +539,7 @@ export class Model implements IRepositoryResolver, IBranchProtectionProviderRegi
|
||||
if (textEditor === undefined) {
|
||||
commands.executeCommand('setContext', 'git.activeResourceHasUnstagedChanges', false);
|
||||
commands.executeCommand('setContext', 'git.activeResourceHasStagedChanges', false);
|
||||
commands.executeCommand('setContext', 'git.activeResourceHasMergeConflicts', false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -546,6 +547,7 @@ export class Model implements IRepositoryResolver, IBranchProtectionProviderRegi
|
||||
if (!repository) {
|
||||
commands.executeCommand('setContext', 'git.activeResourceHasUnstagedChanges', false);
|
||||
commands.executeCommand('setContext', 'git.activeResourceHasStagedChanges', false);
|
||||
commands.executeCommand('setContext', 'git.activeResourceHasMergeConflicts', false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -553,9 +555,13 @@ export class Model implements IRepositoryResolver, IBranchProtectionProviderRegi
|
||||
.find(resource => pathEquals(resource.resourceUri.fsPath, textEditor.document.uri.fsPath));
|
||||
const workingTreeResource = repository.workingTreeGroup.resourceStates
|
||||
.find(resource => pathEquals(resource.resourceUri.fsPath, textEditor.document.uri.fsPath));
|
||||
const mergeChangesResource = repository.mergeGroup.resourceStates
|
||||
.find(resource => pathEquals(resource.resourceUri.fsPath, textEditor.document.uri.fsPath));
|
||||
const hasMergeConflicts = mergeChangesResource ? /^(<{7,}|={7,}|>{7,})/m.test(textEditor.document.getText()) : false;
|
||||
|
||||
commands.executeCommand('setContext', 'git.activeResourceHasStagedChanges', indexResource !== undefined);
|
||||
commands.executeCommand('setContext', 'git.activeResourceHasUnstagedChanges', workingTreeResource !== undefined);
|
||||
commands.executeCommand('setContext', 'git.activeResourceHasMergeConflicts', hasMergeConflicts);
|
||||
}
|
||||
|
||||
@sequentialize
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Disposable, EventEmitter, SourceControlHistoryItemRef, l10n, workspace, Uri, DiagnosticSeverity, env } from 'vscode';
|
||||
import { dirname, sep, relative } from 'path';
|
||||
import { dirname, normalize, sep, relative } from 'path';
|
||||
import { Readable } from 'stream';
|
||||
import { promises as fs, createReadStream } from 'fs';
|
||||
import byline from 'byline';
|
||||
@@ -299,10 +299,16 @@ function normalizePath(path: string): string {
|
||||
// Windows & Mac are currently being handled
|
||||
// as case insensitive file systems in VS Code.
|
||||
if (isWindows || isMacintosh) {
|
||||
return path.toLowerCase();
|
||||
path = path.toLowerCase();
|
||||
}
|
||||
|
||||
return path;
|
||||
// Remove trailing separator
|
||||
if (path.charAt(path.length - 1) === sep) {
|
||||
path = path.substring(0, path.length - 1);
|
||||
}
|
||||
|
||||
// Normalize the path
|
||||
return normalize(path);
|
||||
}
|
||||
|
||||
export function isDescendant(parent: string, descendant: string): boolean {
|
||||
@@ -310,11 +316,16 @@ export function isDescendant(parent: string, descendant: string): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Normalize the paths
|
||||
parent = normalizePath(parent);
|
||||
descendant = normalizePath(descendant);
|
||||
|
||||
// Ensure parent ends with separator
|
||||
if (parent.charAt(parent.length - 1) !== sep) {
|
||||
parent += sep;
|
||||
}
|
||||
|
||||
return normalizePath(descendant).startsWith(normalizePath(parent));
|
||||
return descendant.startsWith(parent);
|
||||
}
|
||||
|
||||
export function pathEquals(a: string, b: string): boolean {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
chat-webview-out
|
||||
@@ -0,0 +1,2 @@
|
||||
legacy-peer-deps="true"
|
||||
timeout=180000
|
||||
@@ -0,0 +1,8 @@
|
||||
src/**
|
||||
extension.webpack.config.js
|
||||
esbuild.*
|
||||
cgmanifest.json
|
||||
package-lock.json
|
||||
webpack.config.js
|
||||
tsconfig*.json
|
||||
.gitignore
|
||||
@@ -0,0 +1,5 @@
|
||||
# Mermaid Chat Features
|
||||
|
||||
**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled.
|
||||
|
||||
Adds basic [Mermaid.js](https://mermaid.js.org) diagram rendering to build-in chat.
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"registrations": [],
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import mermaid, { MermaidConfig } from 'mermaid';
|
||||
|
||||
function getMermaidTheme() {
|
||||
return document.body.classList.contains('vscode-dark') || document.body.classList.contains('vscode-high-contrast')
|
||||
? 'dark'
|
||||
: 'default';
|
||||
}
|
||||
|
||||
type State = {
|
||||
readonly diagramText: string;
|
||||
readonly theme: 'dark' | 'default';
|
||||
};
|
||||
|
||||
let state: State | undefined = undefined;
|
||||
|
||||
function init() {
|
||||
const diagram = document.querySelector('.mermaid');
|
||||
if (!diagram) {
|
||||
return;
|
||||
}
|
||||
|
||||
const theme = getMermaidTheme();
|
||||
state = {
|
||||
diagramText: diagram.textContent ?? '',
|
||||
theme
|
||||
};
|
||||
|
||||
const config: MermaidConfig = {
|
||||
startOnLoad: true,
|
||||
theme,
|
||||
};
|
||||
mermaid.initialize(config);
|
||||
}
|
||||
|
||||
function tryUpdate() {
|
||||
const newTheme = getMermaidTheme();
|
||||
if (state?.theme === newTheme) {
|
||||
return;
|
||||
}
|
||||
|
||||
const diagramNode = document.querySelector('.mermaid');
|
||||
if (!diagramNode || !(diagramNode instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
state = {
|
||||
diagramText: state?.diagramText ?? '',
|
||||
theme: newTheme
|
||||
};
|
||||
|
||||
// Re-render
|
||||
diagramNode.textContent = state?.diagramText ?? '';
|
||||
delete diagramNode.dataset.processed;
|
||||
|
||||
mermaid.initialize({
|
||||
theme: newTheme,
|
||||
});
|
||||
mermaid.run({
|
||||
nodes: [diagramNode]
|
||||
});
|
||||
}
|
||||
|
||||
// Update when theme changes
|
||||
new MutationObserver(() => {
|
||||
tryUpdate();
|
||||
}).observe(document.body, { attributes: true, attributeFilter: ['class'] });
|
||||
|
||||
init();
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"jsx": "react",
|
||||
"lib": [
|
||||
"ES2024",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
]
|
||||
}
|
||||
}
|
||||
+12
-5
@@ -2,10 +2,17 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// @ts-check
|
||||
import path from 'path';
|
||||
import { run } from '../esbuild-webview-common.mjs';
|
||||
|
||||
import { MarkdownToken } from '../../markdownCodec/tokens/markdownToken.js';
|
||||
const srcDir = path.join(import.meta.dirname, 'chat-webview-src');
|
||||
const outDir = path.join(import.meta.dirname, 'chat-webview-out');
|
||||
|
||||
/**
|
||||
* Base class for all tokens produced by the `MarkdownExtensionsDecoder`.
|
||||
*/
|
||||
export abstract class MarkdownExtensionsToken extends MarkdownToken { }
|
||||
run({
|
||||
entryPoints: [
|
||||
path.join(srcDir, 'index.ts'),
|
||||
],
|
||||
srcDir,
|
||||
outdir: outDir,
|
||||
}, process.argv);
|
||||
+8
-6
@@ -2,10 +2,12 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// @ts-check
|
||||
import { browser as withBrowserDefaults } from '../shared.webpack.config.mjs';
|
||||
|
||||
import { BaseToken } from '../base/baseToken.js';
|
||||
|
||||
/**
|
||||
* Common base token that all chatbot `prompt` tokens should inherit from.
|
||||
*/
|
||||
export abstract class PromptToken extends BaseToken { }
|
||||
export default withBrowserDefaults({
|
||||
context: import.meta.dirname,
|
||||
entry: {
|
||||
extension: './src/extension.ts'
|
||||
}
|
||||
});
|
||||
+11
-7
@@ -2,11 +2,15 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// @ts-check
|
||||
import withDefaults from '../shared.webpack.config.mjs';
|
||||
|
||||
import { BaseToken } from '../../baseToken.js';
|
||||
|
||||
/**
|
||||
* Common base token that all `markdown` tokens should
|
||||
* inherit from.
|
||||
*/
|
||||
export abstract class MarkdownToken extends BaseToken { }
|
||||
export default withDefaults({
|
||||
context: import.meta.dirname,
|
||||
resolve: {
|
||||
mainFields: ['module', 'main']
|
||||
},
|
||||
entry: {
|
||||
extension: './src/extension.ts',
|
||||
}
|
||||
});
|
||||
+1433
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"name": "marmaid-chat-features",
|
||||
"displayName": "%displayName%",
|
||||
"description": "%description%",
|
||||
"version": "1.0.0",
|
||||
"publisher": "vscode",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/vscode.git"
|
||||
},
|
||||
"aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255",
|
||||
"engines": {
|
||||
"vscode": "^1.104.0"
|
||||
},
|
||||
"enabledApiProposals": [
|
||||
"chatOutputRenderer"
|
||||
],
|
||||
"capabilities": {
|
||||
"virtualWorkspaces": true,
|
||||
"untrustedWorkspaces": {
|
||||
"supported": true
|
||||
}
|
||||
},
|
||||
"main": "./out/extension",
|
||||
"browser": "./dist/browser/extension",
|
||||
"activationEvents": [],
|
||||
"contributes": {
|
||||
"chatOutputRenderers": [
|
||||
{
|
||||
"viewType": "vscode.chatMermaidDiagram",
|
||||
"mimeTypes": [
|
||||
"text/vnd.mermaid"
|
||||
]
|
||||
}
|
||||
],
|
||||
"languageModelTools": [
|
||||
{
|
||||
"name": "renderMermaidDiagram",
|
||||
"displayName": "Mermaid Renderer",
|
||||
"toolReferenceName": "renderMermaidDiagram",
|
||||
"canBeReferencedInPrompt": true,
|
||||
"modelDescription": "Renders a Mermaid diagram from Mermaid.js markup.",
|
||||
"userDescription": "Render a Mermaid.js diagrams from markup.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"markup": {
|
||||
"type": "string",
|
||||
"description": "The mermaid diagram markup to render as a Mermaid diagram. This should only be the markup of the diagram. Do not include a wrapping code block."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "gulp compile-extension:mermaid-chat-features && npm run build-chat-webview",
|
||||
"watch": "npm run build-chat-webview && gulp watch-extension:mermaid-chat-features",
|
||||
"vscode:prepublish": "npm run build-ext && npm run build-chat-webview",
|
||||
"build-ext": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:mermaid-chat-features",
|
||||
"build-chat-webview": "node ./esbuild-chat-webview.mjs",
|
||||
"compile-web": "npx webpack-cli --config extension-browser.webpack.config --mode none",
|
||||
"watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/node": "^24"
|
||||
},
|
||||
"dependencies": {
|
||||
"dompurify": "^3.2.6",
|
||||
"mermaid": "^11.11.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"displayName": "Mermaid Chat Features",
|
||||
"description": "Adds Mermaid diagram support to built-in chats."
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
/**
|
||||
* View type that uniquely identifies the Mermaid chat output renderer.
|
||||
*/
|
||||
const viewType = 'vscode.chatMermaidDiagram';
|
||||
|
||||
/**
|
||||
* Mime type used to identify Mermaid diagram data in chat output.
|
||||
*/
|
||||
const mime = 'text/vnd.mermaid';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
// Register tools
|
||||
context.subscriptions.push(
|
||||
vscode.lm.registerTool<{ markup: string }>('renderMermaidDiagram', {
|
||||
invoke: async (options, _token) => {
|
||||
const sourceCode = options.input.markup;
|
||||
return writeMermaidToolOutput(sourceCode);
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
// Register the chat output renderer for Mermaid diagrams.
|
||||
// This will be invoked with the data generated by the tools.
|
||||
// It can also be invoked when rendering old Mermaid diagrams in the chat history.
|
||||
context.subscriptions.push(
|
||||
vscode.chat.registerChatOutputRenderer(viewType, {
|
||||
async renderChatOutput({ value }, webview, _ctx, _token) {
|
||||
const mermaidSource = new TextDecoder().decode(value);
|
||||
|
||||
// Set the options for the webview
|
||||
const mediaRoot = vscode.Uri.joinPath(context.extensionUri, 'chat-webview-out');
|
||||
webview.options = {
|
||||
enableScripts: true,
|
||||
localResourceRoots: [mediaRoot],
|
||||
};
|
||||
|
||||
// Set the HTML content for the webview
|
||||
const nonce = getNonce();
|
||||
const mermaidScript = vscode.Uri.joinPath(mediaRoot, 'index.js');
|
||||
|
||||
webview.html = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Mermaid Diagram</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src ${webview.cspSource} 'nonce-${nonce}'; style-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<pre class="mermaid">
|
||||
${escapeHtmlText(mermaidSource)}
|
||||
</pre>
|
||||
|
||||
<script type="module" nonce="${nonce}" src="${webview.asWebviewUri(mermaidScript)}"></script>
|
||||
</body>
|
||||
</html>`;
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
function writeMermaidToolOutput(sourceCode: string): vscode.LanguageModelToolResult {
|
||||
// Expose the source code as a tool result for the LM
|
||||
const result = new vscode.LanguageModelToolResult([
|
||||
new vscode.LanguageModelTextPart(sourceCode)
|
||||
]);
|
||||
|
||||
// And store custom data in the tool result details to indicate that a custom renderer should be used for it.
|
||||
// In this case we just store the source code as binary data.
|
||||
|
||||
// Add cast to use proposed API
|
||||
(result as vscode.ExtendedLanguageModelToolResult2).toolResultDetails2 = {
|
||||
mime,
|
||||
value: new TextEncoder().encode(sourceCode),
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function escapeHtmlText(str: string): string {
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function getNonce() {
|
||||
let text = '';
|
||||
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
for (let i = 0; i < 64; i++) {
|
||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
}
|
||||
return text;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"../../src/vscode-dts/vscode.d.ts",
|
||||
"../../src/vscode-dts/vscode.proposed.chatOutputRenderer.d.ts",
|
||||
"../../src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts",
|
||||
"../../src/vscode-dts/vscode.proposed.languageModelThinkingPart.d.ts",
|
||||
"../../src/vscode-dts/vscode.proposed.chatParticipantPrivate.d.ts"
|
||||
]
|
||||
}
|
||||
+7
-7
@@ -10,7 +10,7 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@azure/ms-rest-azure-env": "^2.0.0",
|
||||
"@azure/msal-node": "^3.7.3",
|
||||
"@azure/msal-node": "^3.7.4",
|
||||
"@azure/msal-node-extensions": "^1.5.22",
|
||||
"@vscode/extension-telemetry": "^0.9.8",
|
||||
"keytar": "file:./packageMocks/keytar",
|
||||
@@ -42,9 +42,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/msal-node": {
|
||||
"version": "3.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.7.3.tgz",
|
||||
"integrity": "sha512-MoJxkKM/YpChfq4g2o36tElyzNUMG8mfD6u8NbuaPAsqfGpaw249khAcJYNoIOigUzRw45OjXCOrexE6ImdUxg==",
|
||||
"version": "3.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.7.4.tgz",
|
||||
"integrity": "sha512-fjqvhrThwzzPvqhFOdkkGRJCHPQZTNijpceVy8QjcfQuH482tOVEjHyamZaioOhVtx+FK1u+eMpJA2Zz4U9LVg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@azure/msal-common": "15.12.0",
|
||||
@@ -71,9 +71,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/msal-node-runtime": {
|
||||
"version": "0.19.4",
|
||||
"resolved": "https://registry.npmjs.org/@azure/msal-node-runtime/-/msal-node-runtime-0.19.4.tgz",
|
||||
"integrity": "sha512-v90QdV/VKG6gvHx2bQp82yRCJ8IGG7OOk6gDQgbKvoHtOs7mSEz2CIqWydUpwCryJkUwgNfgMPAMoGhe/a4fOw==",
|
||||
"version": "0.19.5",
|
||||
"resolved": "https://registry.npmjs.org/@azure/msal-node-runtime/-/msal-node-runtime-0.19.5.tgz",
|
||||
"integrity": "sha512-0oBQgCcgOb+VwQ5k8OXShbuXCBU8FKKhpwnqWSBzzYWSFoYAtyad2zggl26ME4IKzN9telaOJPEEcsQOf/+3Ug==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@azure/ms-rest-azure-env": "^2.0.0",
|
||||
"@azure/msal-node": "^3.7.3",
|
||||
"@azure/msal-node": "^3.7.4",
|
||||
"@azure/msal-node-extensions": "^1.5.22",
|
||||
"@vscode/extension-telemetry": "^0.9.8",
|
||||
"keytar": "file:./packageMocks/keytar",
|
||||
|
||||
@@ -51,8 +51,8 @@ export class CachedPublicClientApplication implements ICachedPublicClientApplica
|
||||
|
||||
const loggerOptions = new MsalLoggerOptions(_logger, telemetryReporter);
|
||||
let broker: BrokerOptions | undefined;
|
||||
if (process.platform !== 'win32') {
|
||||
this._logger.info(`[${this._clientId}] Native Broker is only available on Windows`);
|
||||
if (process.platform !== 'win32' && process.platform !== 'darwin') {
|
||||
this._logger.info(`[${this._clientId}] Native Broker is only available on Windows and macOS`);
|
||||
} else if (workspace.getConfiguration('microsoft-authentication').get<'msal' | 'msal-no-broker'>('implementation') === 'msal-no-broker') {
|
||||
this._logger.info(`[${this._clientId}] Native Broker disabled via settings`);
|
||||
} else {
|
||||
|
||||
@@ -57,10 +57,10 @@
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "gulp compile-extension:markdown-language-features && npm run build-preview",
|
||||
"watch": "npm run build-preview && gulp watch-extension:markdown-language-features",
|
||||
"compile": "gulp compile-extension:simple-browser && npm run build-preview",
|
||||
"watch": "npm run build-preview && gulp watch-extension:simple-browser",
|
||||
"vscode:prepublish": "npm run build-ext && npm run build-preview",
|
||||
"build-ext": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:markdown-language-features ./tsconfig.json",
|
||||
"build-ext": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:simple-browser ./tsconfig.json",
|
||||
"build-preview": "node ./esbuild-preview.mjs",
|
||||
"compile-web": "npx webpack-cli --config extension-browser.webpack.config --mode none",
|
||||
"watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose"
|
||||
|
||||
@@ -306,7 +306,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
const cwd = result.cwd ?? terminal.shellIntegration?.cwd;
|
||||
if (cwd && (result.filesRequested || result.foldersRequested)) {
|
||||
const globPattern = createFileRegex(result.fileExtensions);
|
||||
const globPattern = createFileGlobPattern(result.fileExtensions);
|
||||
return new vscode.TerminalCompletionList(result.items, {
|
||||
filesRequested: result.filesRequested,
|
||||
foldersRequested: result.foldersRequested,
|
||||
@@ -564,17 +564,13 @@ export function sanitizeProcessEnvironment(env: Record<string, string>, ...prese
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Escapes regex special characters in a string
|
||||
function escapeRegExp(str: string): string {
|
||||
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
function createFileRegex(fileExtensions?: string[]): vscode.GlobPattern | undefined {
|
||||
function createFileGlobPattern(fileExtensions?: string[]): vscode.GlobPattern | undefined {
|
||||
if (!fileExtensions || fileExtensions.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
const exts = fileExtensions.map(ext => ext.startsWith('.') ? ext : '.' + ext);
|
||||
// Create a regex that matches any string ending with one of the extensions
|
||||
return `.*(${exts.map(ext => escapeRegExp(ext)).join('|')})$`;
|
||||
const exts = fileExtensions.map(ext => ext.startsWith('.') ? ext.slice(1) : ext);
|
||||
if (exts.length === 1) {
|
||||
return `**/*.${exts[0]}`;
|
||||
}
|
||||
return `**/*.{${exts.join(',')}}`;
|
||||
}
|
||||
|
||||
@@ -367,7 +367,7 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider<VsCodeCode
|
||||
let title = action.description;
|
||||
if (action.fixName === fixNames.classIncorrectlyImplementsInterface) {
|
||||
title = vscode.l10n.t('{0} with AI', action.description);
|
||||
message = `Implement the stubbed-out class members for ${document.getText(diagnostic.range)} with a useful implementation.`;
|
||||
message = vscode.l10n.t(`Implement the stubbed-out class members for ${document.getText(diagnostic.range)} with a useful implementation.`);
|
||||
expand = { kind: 'code-action', action };
|
||||
} else if (action.fixName === fixNames.fixClassDoesntImplementInheritedAbstractMember) {
|
||||
title = vscode.l10n.t('{0} with AI', action.description);
|
||||
|
||||
Generated
+57
-80
@@ -17,7 +17,7 @@
|
||||
"@vscode/deviceid": "^0.1.1",
|
||||
"@vscode/iconv-lite-umd": "0.7.0",
|
||||
"@vscode/policy-watcher": "^1.3.2",
|
||||
"@vscode/proxy-agent": "^0.33.0",
|
||||
"@vscode/proxy-agent": "^0.34.0",
|
||||
"@vscode/ripgrep": "^1.15.13",
|
||||
"@vscode/spdlog": "^0.15.2",
|
||||
"@vscode/sqlite3": "5.1.8-vscode",
|
||||
@@ -46,9 +46,10 @@
|
||||
"native-is-elevated": "0.7.0",
|
||||
"native-keymap": "^3.3.5",
|
||||
"native-watchdog": "^1.4.1",
|
||||
"node-pty": "^1.1.0-beta33",
|
||||
"node-pty": "1.1.0-beta35",
|
||||
"open": "^10.1.2",
|
||||
"tas-client-umd": "0.2.0",
|
||||
"undici": "^7.9.0",
|
||||
"v8-inspect-profiler": "^0.1.1",
|
||||
"vscode-oniguruma": "1.7.0",
|
||||
"vscode-regexpp": "^3.1.0",
|
||||
@@ -151,7 +152,7 @@
|
||||
"ts-node": "^10.9.1",
|
||||
"tsec": "0.2.7",
|
||||
"tslib": "^2.6.3",
|
||||
"typescript": "^6.0.0-dev.20250910",
|
||||
"typescript": "^6.0.0-dev.20250922",
|
||||
"typescript-eslint": "^8.39.0",
|
||||
"util": "^0.12.4",
|
||||
"webpack": "^5.94.0",
|
||||
@@ -2469,31 +2470,28 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview": {
|
||||
"version": "7.0.0-dev.20250910.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20250910.1.tgz",
|
||||
"integrity": "sha512-d4i1kHxvWfYDGIjah8PHkBdY+pts4jzEJ2g0xqqW6oz3eDmuwx3aeDwmcEXgqw/ClDLtdy0t3NjFSE4ysqGO1g==",
|
||||
"version": "7.0.0-dev.20250922.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20250922.1.tgz",
|
||||
"integrity": "sha512-B7svR7Fm4cLLL8ARBVc9Xx2KFcZuCkNsdR7LBZjSqaDM6am11XizhPORrI7x8rlVQ71CBoQVgOp/2/Bn3x+OgA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsgo": "bin/tsgo.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.6.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@typescript/native-preview-darwin-arm64": "7.0.0-dev.20250910.1",
|
||||
"@typescript/native-preview-darwin-x64": "7.0.0-dev.20250910.1",
|
||||
"@typescript/native-preview-linux-arm": "7.0.0-dev.20250910.1",
|
||||
"@typescript/native-preview-linux-arm64": "7.0.0-dev.20250910.1",
|
||||
"@typescript/native-preview-linux-x64": "7.0.0-dev.20250910.1",
|
||||
"@typescript/native-preview-win32-arm64": "7.0.0-dev.20250910.1",
|
||||
"@typescript/native-preview-win32-x64": "7.0.0-dev.20250910.1"
|
||||
"@typescript/native-preview-darwin-arm64": "7.0.0-dev.20250922.1",
|
||||
"@typescript/native-preview-darwin-x64": "7.0.0-dev.20250922.1",
|
||||
"@typescript/native-preview-linux-arm": "7.0.0-dev.20250922.1",
|
||||
"@typescript/native-preview-linux-arm64": "7.0.0-dev.20250922.1",
|
||||
"@typescript/native-preview-linux-x64": "7.0.0-dev.20250922.1",
|
||||
"@typescript/native-preview-win32-arm64": "7.0.0-dev.20250922.1",
|
||||
"@typescript/native-preview-win32-x64": "7.0.0-dev.20250922.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-darwin-arm64": {
|
||||
"version": "7.0.0-dev.20250910.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20250910.1.tgz",
|
||||
"integrity": "sha512-PcSdX+LDNSAsBCPcbLx01sE8kyNv48WAGlxtRptrXvgnY61O64FzqCr755pteGIGrEEEQ9qsmm5b68EdyMbqJQ==",
|
||||
"version": "7.0.0-dev.20250922.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20250922.1.tgz",
|
||||
"integrity": "sha512-R4sKE/cQYMGrmaz8OBnnseABdB6W0ZCQ9muHQnoxuyukf7m0wLLqvGNorQZSWVl9xQ7qNniXcZJlCKp4JmRr6w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2502,15 +2500,12 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20.6.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/@typescript/native-preview-darwin-x64": {
|
||||
"version": "7.0.0-dev.20250910.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20250910.1.tgz",
|
||||
"integrity": "sha512-iz4T7SmwoLczNxfIlEfb3WQSD/cpcybT27s0S/HOAJbrZRRDRT/RvNWLT9PI0aEVM7EGxHrPOExjWGErItGP/w==",
|
||||
"version": "7.0.0-dev.20250922.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20250922.1.tgz",
|
||||
"integrity": "sha512-Hhh+9e/75ZQxdatdA8TFKOKjPwqjXWNI2a8vswvMU6zOmiVYZoYaUGEGFhk0W1WPGnt/kZSM1Mb4a9nVaEwhZQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2519,15 +2514,12 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20.6.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/@typescript/native-preview-linux-arm": {
|
||||
"version": "7.0.0-dev.20250910.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20250910.1.tgz",
|
||||
"integrity": "sha512-LfxNhRNuxBjfGWsOn/aQ3j76E+ZyyvMcQOVYYyr/+5BG/2bCtKtKtLI+xZzxeaPL6yz3a+TTdO1RtT79z7IKGw==",
|
||||
"version": "7.0.0-dev.20250922.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20250922.1.tgz",
|
||||
"integrity": "sha512-4JbSk4B0SUo2c+S9YKGLAaMQXA16Pd9Cd7GLhMiABRtOLEHFDAaFmFbVoGYX5Dyicix711oziX/WAhD6nuC73A==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -2536,15 +2528,12 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20.6.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/@typescript/native-preview-linux-arm64": {
|
||||
"version": "7.0.0-dev.20250910.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20250910.1.tgz",
|
||||
"integrity": "sha512-ezy44eOONVCTKBbMNuswVXQJDH96vZz1UttTzCWoLjnxa5YLPoSxtdXLzqLDXFm9mznFkO55dq5brFc0yEcytQ==",
|
||||
"version": "7.0.0-dev.20250922.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20250922.1.tgz",
|
||||
"integrity": "sha512-Rw74z0tf0NEujnl0W58fQ5pbh8P1fr2ujQTMkQYz9WpH+hYuysQgcOiDEoht62CxtLHflexu3dUWJI8/LUPyHA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2553,15 +2542,12 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20.6.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/@typescript/native-preview-linux-x64": {
|
||||
"version": "7.0.0-dev.20250910.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20250910.1.tgz",
|
||||
"integrity": "sha512-pBmxFR9+C74QGzhDS8PRRBswQcnVFp2XD2J6oFfDcMmtsq8gFIlggAx3+k3fLysoH5gJDISsgjZr43IIcncpzQ==",
|
||||
"version": "7.0.0-dev.20250922.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20250922.1.tgz",
|
||||
"integrity": "sha512-lY6JAZgzeJxLwciC8Wc9l7OlDYwVbuo3JK+qHfLlyxu8h1Q3cGF5VMpgSlAj9CKLDQ0h4kDAecLLiEEOod78aw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2570,15 +2556,12 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20.6.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/@typescript/native-preview-win32-arm64": {
|
||||
"version": "7.0.0-dev.20250910.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20250910.1.tgz",
|
||||
"integrity": "sha512-qCJYqZ/utGR9OPGx0871Ov1djUZ9MAFtGKrtbgUwrwjfXLLGZHUDOmI9brfYQ2ruCxTKENk6IfWIAtY+zV6C2A==",
|
||||
"version": "7.0.0-dev.20250922.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20250922.1.tgz",
|
||||
"integrity": "sha512-pGzWqNx7x6Sqs20Ea5Xn/JC9eZ9Do6bu6K+dmfpewYYhwUv8jiOhh+fr9TJFZ8MlaZDTp9FclQIGpW+2MZ8UOw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2587,15 +2570,12 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20.6.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/@typescript/native-preview-win32-x64": {
|
||||
"version": "7.0.0-dev.20250910.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20250910.1.tgz",
|
||||
"integrity": "sha512-RPjV+ZypHeSz1Ky6wys52tXTYpYQ4fAqovC5ZZC+j+Lf8gEEcWXcmuJMEBN6vhTCvx1c6QdRtBBIYRrUHh/JEA==",
|
||||
"version": "7.0.0-dev.20250922.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20250922.1.tgz",
|
||||
"integrity": "sha512-RoNm3P69p5F/ZJ7O7nIoUJB0OVG5nGIEVzP/VF2lm8jBbDN8aCRNT+DkZrQvdXJEBg2fM0WrTzcik9KVXAyEag==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2604,10 +2584,7 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20.6.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/@vscode/deviceid": {
|
||||
"version": "0.1.1",
|
||||
@@ -3002,9 +2979,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vscode/proxy-agent": {
|
||||
"version": "0.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/proxy-agent/-/proxy-agent-0.33.0.tgz",
|
||||
"integrity": "sha512-pfGEfRySMAB0ZRk7NIiIpW5BWGMZvQCN6Jf30+uupl589P1cVQ+HD8WxFTxeJlz9wNyelJqAXzFt12IuB+D3Ew==",
|
||||
"version": "0.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/proxy-agent/-/proxy-agent-0.34.0.tgz",
|
||||
"integrity": "sha512-LrX5mb+0vgvGQ/1jLvpsd4tUzlCVYNjvu+vvPx+yV2AvyXXnRQj/Qom1Fiavw9Mfmxw3+AHfzZ73tXwTMCfEdQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tootallnate/once": "^3.0.0",
|
||||
@@ -12916,9 +12893,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-pty": {
|
||||
"version": "1.1.0-beta33",
|
||||
"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0-beta33.tgz",
|
||||
"integrity": "sha512-+BN2bT/KqO+fmCHnpFS99VMVJr7VUBCUa2VIBEw0oEvszkR7ri0kwD1lF91OeQToUJ2dXKA8j6scPjbO4eRWOQ==",
|
||||
"version": "1.1.0-beta35",
|
||||
"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0-beta35.tgz",
|
||||
"integrity": "sha512-dGKw3PtLj/+uiFWUODNjr3QMyNjxRB2JY372AN4uzonfb6ri23d4PMr4s6UoibiqsXOQ3elXRCdq1qDLd86J8Q==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -14335,9 +14312,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prebuild-install/node_modules/tar-fs": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz",
|
||||
"integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==",
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
|
||||
"integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chownr": "^1.1.1",
|
||||
@@ -16602,9 +16579,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tar-fs": {
|
||||
"version": "3.0.10",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.10.tgz",
|
||||
"integrity": "sha512-C1SwlQGNLe/jPNqapK8epDsXME7CAJR5RL3GcE6KWx1d9OUByzoHVcbu1VPI8tevg9H8Alae0AApHHFGzrD5zA==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz",
|
||||
"integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -17267,9 +17244,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "6.0.0-dev.20250910",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.0-dev.20250910.tgz",
|
||||
"integrity": "sha512-c8xZmVV/0FVlBoiRveyYSSs2jL0AHRZ3m2fUPgpY9ZFh7edYiWlBsZ7zPZIHzdNieuJ5ryYENw4pbRasp2Fo/w==",
|
||||
"version": "6.0.0-dev.20250922",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.0-dev.20250922.tgz",
|
||||
"integrity": "sha512-4jTznRR2W8ak4kgHlxhNEauwCS/O2O2AfS3yC+Y4VxkRDFIruwdcW4+UQflBJrLCFa42lhdAAMGl1td/99KTKg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
|
||||
+6
-4
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.105.0",
|
||||
"distro": "8103a60ed6fb457dbf0ba180a67be3341dce4a23",
|
||||
"distro": "35091a9a52c6140fcbee98e0829b9713aed0f6a0",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
@@ -38,6 +38,7 @@
|
||||
"7z": "7z",
|
||||
"update-grammars": "node build/npm/update-all-grammars.mjs",
|
||||
"update-localization-extension": "node build/npm/update-localization-extension.js",
|
||||
"mixin-telemetry-docs": "node build/npm/mixin-telemetry-docs.mjs",
|
||||
"smoketest": "node build/lib/preLaunch.js && cd test/smoke && npm run compile && node test/index.js",
|
||||
"smoketest-no-compile": "cd test/smoke && node test/index.js",
|
||||
"download-builtin-extensions": "node build/lib/builtInExtensions.js",
|
||||
@@ -77,7 +78,7 @@
|
||||
"@vscode/deviceid": "^0.1.1",
|
||||
"@vscode/iconv-lite-umd": "0.7.0",
|
||||
"@vscode/policy-watcher": "^1.3.2",
|
||||
"@vscode/proxy-agent": "^0.33.0",
|
||||
"@vscode/proxy-agent": "^0.34.0",
|
||||
"@vscode/ripgrep": "^1.15.13",
|
||||
"@vscode/spdlog": "^0.15.2",
|
||||
"@vscode/sqlite3": "5.1.8-vscode",
|
||||
@@ -106,9 +107,10 @@
|
||||
"native-is-elevated": "0.7.0",
|
||||
"native-keymap": "^3.3.5",
|
||||
"native-watchdog": "^1.4.1",
|
||||
"node-pty": "^1.1.0-beta33",
|
||||
"node-pty": "1.1.0-beta35",
|
||||
"open": "^10.1.2",
|
||||
"tas-client-umd": "0.2.0",
|
||||
"undici": "^7.9.0",
|
||||
"v8-inspect-profiler": "^0.1.1",
|
||||
"vscode-oniguruma": "1.7.0",
|
||||
"vscode-regexpp": "^3.1.0",
|
||||
@@ -211,7 +213,7 @@
|
||||
"ts-node": "^10.9.1",
|
||||
"tsec": "0.2.7",
|
||||
"tslib": "^2.6.3",
|
||||
"typescript": "^6.0.0-dev.20250910",
|
||||
"typescript": "^6.0.0-dev.20250922",
|
||||
"typescript-eslint": "^8.39.0",
|
||||
"util": "^0.12.4",
|
||||
"webpack": "^5.94.0",
|
||||
|
||||
Generated
+11
-11
@@ -13,7 +13,7 @@
|
||||
"@parcel/watcher": "parcel-bundler/watcher#1ca032aa8339260a8a3bcf825c3a1a71e3e43542",
|
||||
"@vscode/deviceid": "^0.1.1",
|
||||
"@vscode/iconv-lite-umd": "0.7.0",
|
||||
"@vscode/proxy-agent": "^0.33.0",
|
||||
"@vscode/proxy-agent": "^0.34.0",
|
||||
"@vscode/ripgrep": "^1.15.13",
|
||||
"@vscode/spdlog": "^0.15.2",
|
||||
"@vscode/tree-sitter-wasm": "^0.1.4",
|
||||
@@ -38,7 +38,7 @@
|
||||
"kerberos": "2.1.1",
|
||||
"minimist": "^1.2.8",
|
||||
"native-watchdog": "^1.4.1",
|
||||
"node-pty": "^1.1.0-beta33",
|
||||
"node-pty": "1.1.0-beta35",
|
||||
"tas-client-umd": "0.2.0",
|
||||
"vscode-oniguruma": "1.7.0",
|
||||
"vscode-regexpp": "^3.1.0",
|
||||
@@ -133,9 +133,9 @@
|
||||
"integrity": "sha512-bRRFxLfg5dtAyl5XyiVWz/ZBPahpOpPrNYnnHpOpUZvam4tKH35wdhP4Kj6PbM0+KdliOsPzbGWpkxcdpNB/sg=="
|
||||
},
|
||||
"node_modules/@vscode/proxy-agent": {
|
||||
"version": "0.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/proxy-agent/-/proxy-agent-0.33.0.tgz",
|
||||
"integrity": "sha512-pfGEfRySMAB0ZRk7NIiIpW5BWGMZvQCN6Jf30+uupl589P1cVQ+HD8WxFTxeJlz9wNyelJqAXzFt12IuB+D3Ew==",
|
||||
"version": "0.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/proxy-agent/-/proxy-agent-0.34.0.tgz",
|
||||
"integrity": "sha512-LrX5mb+0vgvGQ/1jLvpsd4tUzlCVYNjvu+vvPx+yV2AvyXXnRQj/Qom1Fiavw9Mfmxw3+AHfzZ73tXwTMCfEdQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tootallnate/once": "^3.0.0",
|
||||
@@ -842,9 +842,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-pty": {
|
||||
"version": "1.1.0-beta33",
|
||||
"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0-beta33.tgz",
|
||||
"integrity": "sha512-+BN2bT/KqO+fmCHnpFS99VMVJr7VUBCUa2VIBEw0oEvszkR7ri0kwD1lF91OeQToUJ2dXKA8j6scPjbO4eRWOQ==",
|
||||
"version": "1.1.0-beta35",
|
||||
"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0-beta35.tgz",
|
||||
"integrity": "sha512-dGKw3PtLj/+uiFWUODNjr3QMyNjxRB2JY372AN4uzonfb6ri23d4PMr4s6UoibiqsXOQ3elXRCdq1qDLd86J8Q==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1095,9 +1095,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tar-fs": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz",
|
||||
"integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==",
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
|
||||
"integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chownr": "^1.1.1",
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@
|
||||
"@parcel/watcher": "parcel-bundler/watcher#1ca032aa8339260a8a3bcf825c3a1a71e3e43542",
|
||||
"@vscode/deviceid": "^0.1.1",
|
||||
"@vscode/iconv-lite-umd": "0.7.0",
|
||||
"@vscode/proxy-agent": "^0.33.0",
|
||||
"@vscode/proxy-agent": "^0.34.0",
|
||||
"@vscode/ripgrep": "^1.15.13",
|
||||
"@vscode/spdlog": "^0.15.2",
|
||||
"@vscode/tree-sitter-wasm": "^0.1.4",
|
||||
@@ -33,7 +33,7 @@
|
||||
"kerberos": "2.1.1",
|
||||
"minimist": "^1.2.8",
|
||||
"native-watchdog": "^1.4.1",
|
||||
"node-pty": "^1.1.0-beta33",
|
||||
"node-pty": "1.1.0-beta35",
|
||||
"tas-client-umd": "0.2.0",
|
||||
"vscode-oniguruma": "1.7.0",
|
||||
"vscode-regexpp": "^3.1.0",
|
||||
|
||||
@@ -1602,7 +1602,7 @@ export async function triggerNotification(message: string, options?: { detail?:
|
||||
|
||||
const notification = new Notification(message, {
|
||||
body: options?.detail,
|
||||
requireInteraction: options?.sticky
|
||||
requireInteraction: options?.sticky,
|
||||
});
|
||||
|
||||
const onClick = new event.Emitter<void>();
|
||||
|
||||
@@ -16,7 +16,7 @@ import { FileAccess, Schemas } from '../common/network.js';
|
||||
import { cloneAndChange } from '../common/objects.js';
|
||||
import { dirname, resolvePath } from '../common/resources.js';
|
||||
import { escape } from '../common/strings.js';
|
||||
import { URI } from '../common/uri.js';
|
||||
import { URI, UriComponents } from '../common/uri.js';
|
||||
import * as DOM from './dom.js';
|
||||
import * as domSanitize from './domSanitize.js';
|
||||
import { convertTagToPlaintext } from './domSanitize.js';
|
||||
@@ -151,7 +151,7 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
|
||||
}
|
||||
|
||||
const renderedContent = document.createElement('div');
|
||||
const sanitizerConfig = getDomSanitizerConfig(markdown.isTrusted ?? false, options.sanitizerConfig ?? {});
|
||||
const sanitizerConfig = getDomSanitizerConfig(markdown, options.sanitizerConfig ?? {});
|
||||
domSanitize.safeSetInnerHtml(renderedContent, renderedMarkdown, sanitizerConfig);
|
||||
|
||||
// Rewrite links and images before potentially inserting them into the real dom
|
||||
@@ -437,12 +437,17 @@ function resolveWithBaseUri(baseUri: URI, href: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
type MdStrConfig = {
|
||||
readonly isTrusted?: boolean | MarkdownStringTrustedOptions;
|
||||
readonly baseUri?: UriComponents;
|
||||
};
|
||||
|
||||
function sanitizeRenderedMarkdown(
|
||||
renderedMarkdown: string,
|
||||
isTrusted: boolean | MarkdownStringTrustedOptions,
|
||||
originalMdStrConfig: MdStrConfig,
|
||||
options: MarkdownSanitizerConfig = {},
|
||||
): TrustedHTML {
|
||||
const sanitizerConfig = getDomSanitizerConfig(isTrusted, options);
|
||||
const sanitizerConfig = getDomSanitizerConfig(originalMdStrConfig, options);
|
||||
return domSanitize.sanitizeHtml(renderedMarkdown, sanitizerConfig);
|
||||
}
|
||||
|
||||
@@ -508,7 +513,8 @@ export const allowedMarkdownHtmlAttributes = Object.freeze<Array<string | domSan
|
||||
},
|
||||
]);
|
||||
|
||||
function getDomSanitizerConfig(isTrusted: boolean | MarkdownStringTrustedOptions, options: MarkdownSanitizerConfig): domSanitize.DomSanitizerConfig {
|
||||
function getDomSanitizerConfig(mdStrConfig: MdStrConfig, options: MarkdownSanitizerConfig): domSanitize.DomSanitizerConfig {
|
||||
const isTrusted = mdStrConfig.isTrusted ?? false;
|
||||
const allowedLinkSchemes = [
|
||||
Schemas.http,
|
||||
Schemas.https,
|
||||
@@ -542,6 +548,7 @@ function getDomSanitizerConfig(isTrusted: boolean | MarkdownStringTrustedOptions
|
||||
allowedLinkProtocols: {
|
||||
override: allowedLinkSchemes,
|
||||
},
|
||||
allowRelativeLinkPaths: !!mdStrConfig.baseUri,
|
||||
allowedMediaProtocols: {
|
||||
override: [
|
||||
Schemas.http,
|
||||
@@ -577,7 +584,7 @@ export function renderAsPlaintext(str: IMarkdownString | string, options?: {
|
||||
}
|
||||
|
||||
const html = marked.parse(value, { async: false, renderer: options?.includeCodeBlocksFences ? plainTextWithCodeBlocksRenderer.value : plainTextRenderer.value });
|
||||
return sanitizeRenderedMarkdown(html, /* isTrusted */ false, {})
|
||||
return sanitizeRenderedMarkdown(html, { isTrusted: false }, {})
|
||||
.toString()
|
||||
.replace(/&(#\d+|[a-zA-Z]+);/g, m => unescapeInfo.get(m) ?? m)
|
||||
.trim();
|
||||
|
||||
@@ -146,3 +146,61 @@ export function cancelOnDispose(store: DisposableStore): CancellationToken {
|
||||
store.add({ dispose() { source.cancel(); } });
|
||||
return source.token;
|
||||
}
|
||||
|
||||
/**
|
||||
* A pool that aggregates multiple cancellation tokens. The pool's own token
|
||||
* (accessible via `pool.token`) is cancelled only after every token added
|
||||
* to the pool has been cancelled. Adding tokens after the pool token has
|
||||
* been cancelled has no effect.
|
||||
*/
|
||||
export class CancellationTokenPool {
|
||||
|
||||
private readonly _source = new CancellationTokenSource();
|
||||
private readonly _listeners = new DisposableStore();
|
||||
|
||||
private _total: number = 0;
|
||||
private _cancelled: number = 0;
|
||||
private _isDone: boolean = false;
|
||||
|
||||
get token(): CancellationToken {
|
||||
return this._source.token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a token to the pool. If the token is already cancelled it is counted
|
||||
* immediately. Tokens added after the pool token has been cancelled are ignored.
|
||||
*/
|
||||
add(token: CancellationToken): void {
|
||||
if (this._isDone) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._total++;
|
||||
|
||||
if (token.isCancellationRequested) {
|
||||
this._cancelled++;
|
||||
this._check();
|
||||
return;
|
||||
}
|
||||
|
||||
const d = token.onCancellationRequested(() => {
|
||||
d.dispose();
|
||||
this._cancelled++;
|
||||
this._check();
|
||||
});
|
||||
this._listeners.add(d);
|
||||
}
|
||||
|
||||
private _check(): void {
|
||||
if (!this._isDone && this._total > 0 && this._total === this._cancelled) {
|
||||
this._isDone = true;
|
||||
this._listeners.dispose();
|
||||
this._source.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._listeners.dispose();
|
||||
this._source.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,11 +200,14 @@ export function parseHrefAndDimensions(href: string): { href: string; dimensions
|
||||
}
|
||||
|
||||
export function markdownCommandLink(command: { title: string; id: string; arguments?: unknown[] }, escapeTokens = true): string {
|
||||
const uri = URI.from({
|
||||
scheme: Schemas.command,
|
||||
path: command.id,
|
||||
query: command.arguments?.length ? encodeURIComponent(JSON.stringify(command.arguments)) : undefined,
|
||||
}).toString();
|
||||
|
||||
const uri = createCommandUri(command.id, ...(command.arguments || [])).toString();
|
||||
return `[${escapeTokens ? escapeMarkdownSyntaxTokens(command.title) : command.title}](${uri})`;
|
||||
}
|
||||
|
||||
export function createCommandUri(commandId: string, ...commandArgs: unknown[]): URI {
|
||||
return URI.from({
|
||||
scheme: Schemas.command,
|
||||
path: commandId,
|
||||
query: commandArgs.length ? encodeURIComponent(JSON.stringify(commandArgs)) : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -367,19 +367,36 @@ export function combinedDisposable(...disposables: IDisposable[]): IDisposable {
|
||||
return parent;
|
||||
}
|
||||
|
||||
class FunctionDisposable implements IDisposable {
|
||||
private _isDisposed: boolean;
|
||||
private readonly _fn: () => void;
|
||||
|
||||
constructor(fn: () => void) {
|
||||
this._isDisposed = false;
|
||||
this._fn = fn;
|
||||
trackDisposable(this);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
if (!this._fn) {
|
||||
throw new Error(`Unbound disposable context: Need to use an arrow function to preserve the value of this`);
|
||||
}
|
||||
this._isDisposed = true;
|
||||
markAsDisposed(this);
|
||||
this._fn();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a function that implements dispose into an {@link IDisposable}.
|
||||
*
|
||||
* @param fn Clean up function, guaranteed to be called only **once**.
|
||||
*/
|
||||
export function toDisposable(fn: () => void): IDisposable {
|
||||
const self = trackDisposable({
|
||||
dispose: createSingleCallFunction(() => {
|
||||
markAsDisposed(self);
|
||||
fn();
|
||||
})
|
||||
});
|
||||
return self;
|
||||
return new FunctionDisposable(fn);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -99,65 +99,6 @@ export function isPointWithinTriangle(
|
||||
return u >= 0 && v >= 0 && u + v < 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get a (pseudo)random integer from a provided `max`...[`min`] range.
|
||||
* Both `min` and `max` values are inclusive. The `min` value is optional (defaults to `0`).
|
||||
*
|
||||
* @throws in the next cases:
|
||||
* - if provided `min` or `max` is not a number
|
||||
* - if provided `min` or `max` is not finite
|
||||
* - if provided `min` is larger than `max` value
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* Specifying a `max` value only uses `0` as the `min` value by default:
|
||||
*
|
||||
* ```typescript
|
||||
* // get a random integer between 0 and 10
|
||||
* const randomInt = randomInt(10);
|
||||
*
|
||||
* assert(
|
||||
* randomInt >= 0,
|
||||
* 'Should be greater than or equal to 0.',
|
||||
* );
|
||||
*
|
||||
* assert(
|
||||
* randomInt <= 10,
|
||||
* 'Should be less than or equal to 10.',
|
||||
* );
|
||||
* ```
|
||||
* * Specifying both `max` and `min` values:
|
||||
*
|
||||
* ```typescript
|
||||
* // get a random integer between 5 and 8
|
||||
* const randomInt = randomInt(8, 5);
|
||||
*
|
||||
* assert(
|
||||
* randomInt >= 5,
|
||||
* 'Should be greater than or equal to 5.',
|
||||
* );
|
||||
*
|
||||
* assert(
|
||||
* randomInt <= 8,
|
||||
* 'Should be less than or equal to 8.',
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
export function randomInt(max: number, min: number = 0): number {
|
||||
assert(!isNaN(min), '"min" param is not a number.');
|
||||
assert(!isNaN(max), '"max" param is not a number.');
|
||||
|
||||
assert(isFinite(max), '"max" param is not finite.');
|
||||
assert(isFinite(min), '"min" param is not finite.');
|
||||
|
||||
assert(max > min, `"max"(${max}) param should be greater than "min"(${min}).`);
|
||||
|
||||
const delta = max - min;
|
||||
const randomFloat = delta * Math.random();
|
||||
|
||||
return Math.round(min + randomFloat);
|
||||
}
|
||||
|
||||
export function randomChance(p: number): boolean {
|
||||
assert(p >= 0 && p <= 1, 'p must be between 0 and 1');
|
||||
return Math.random() < p;
|
||||
|
||||
@@ -764,13 +764,11 @@ export async function fetchDynamicRegistration(serverMetadata: IAuthorizationSer
|
||||
redirect_uris: [
|
||||
'https://insiders.vscode.dev/redirect',
|
||||
'https://vscode.dev/redirect',
|
||||
'http://localhost/',
|
||||
'http://127.0.0.1/',
|
||||
// Added these for any server that might do
|
||||
// only exact match on the redirect URI even
|
||||
// though the spec says it should not care
|
||||
// about the port.
|
||||
`http://localhost:${DEFAULT_AUTH_FLOW_PORT}/`,
|
||||
`http://127.0.0.1:${DEFAULT_AUTH_FLOW_PORT}/`
|
||||
],
|
||||
scope: scopes?.join(AUTH_SCOPE_SEPARATOR),
|
||||
|
||||
@@ -278,3 +278,7 @@ export const isAndroid = !!(userAgent && userAgent.indexOf('Android') >= 0);
|
||||
export function isBigSurOrNewer(osVersion: string): boolean {
|
||||
return parseFloat(osVersion) >= 20;
|
||||
}
|
||||
|
||||
export function isTahoe(osVersion: string): boolean {
|
||||
return parseFloat(osVersion) === 25;
|
||||
}
|
||||
|
||||
@@ -379,6 +379,7 @@ export interface IDefaultChatAgent {
|
||||
readonly completionsRefreshTokenCommand: string;
|
||||
readonly chatRefreshTokenCommand: string;
|
||||
readonly generateCommitMessageCommand: string;
|
||||
readonly resolveMergeConflictsCommand: string;
|
||||
|
||||
readonly completionsAdvancedSetting: string;
|
||||
readonly completionsEnablementSetting: string;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { UriParts, IRawURITransformer, URITransformer, IURITransformer } from '../../../base/common/uriIpc.js';
|
||||
import { UriParts, IRawURITransformer, URITransformer, IURITransformer } from './uriIpc.js';
|
||||
|
||||
/**
|
||||
* ```
|
||||
@@ -0,0 +1,832 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Parses a simplified YAML-like input from a single string.
|
||||
* Supports objects, arrays, primitive types (string, number, boolean, null).
|
||||
* Tracks positions for error reporting and node locations.
|
||||
*
|
||||
* Limitations:
|
||||
* - No multi-line strings or block literals
|
||||
* - No anchors or references
|
||||
* - No complex types (dates, binary)
|
||||
* - No special handling for escape sequences in strings
|
||||
* - Indentation must be consistent (spaces only, no tabs)
|
||||
*
|
||||
* Notes:
|
||||
* - New line separators can be either "\n" or "\r\n". The input string is split into lines internally.
|
||||
*
|
||||
* @param input A string containing the YAML-like input
|
||||
* @param errors Array to collect parsing errors
|
||||
* @param options Parsing options
|
||||
* @returns The parsed representation (ObjectNode, ArrayNode, or primitive node)
|
||||
*/
|
||||
export function parse(input: string, errors: YamlParseError[] = [], options: ParseOptions = {}): YamlNode | undefined {
|
||||
// Normalize both LF and CRLF by splitting on either; CR characters are not retained as part of line text.
|
||||
// This keeps the existing line/character based lexer logic intact.
|
||||
const lines = input.length === 0 ? [] : input.split(/\r\n|\n/);
|
||||
const parser = new YamlParser(lines, errors, options);
|
||||
return parser.parse();
|
||||
}
|
||||
|
||||
export interface YamlParseError {
|
||||
readonly message: string;
|
||||
readonly start: Position;
|
||||
readonly end: Position;
|
||||
readonly code: string;
|
||||
}
|
||||
|
||||
export interface ParseOptions {
|
||||
readonly allowDuplicateKeys?: boolean;
|
||||
}
|
||||
|
||||
export interface Position {
|
||||
readonly line: number;
|
||||
readonly character: number;
|
||||
}
|
||||
|
||||
export interface YamlStringNode {
|
||||
readonly type: 'string';
|
||||
readonly value: string;
|
||||
readonly start: Position;
|
||||
readonly end: Position;
|
||||
}
|
||||
|
||||
export interface YamlNumberNode {
|
||||
readonly type: 'number';
|
||||
readonly value: number;
|
||||
readonly start: Position;
|
||||
readonly end: Position;
|
||||
}
|
||||
|
||||
export interface YamlBooleanNode {
|
||||
readonly type: 'boolean';
|
||||
readonly value: boolean;
|
||||
readonly start: Position;
|
||||
readonly end: Position;
|
||||
}
|
||||
|
||||
export interface YamlNullNode {
|
||||
readonly type: 'null';
|
||||
readonly value: null;
|
||||
readonly start: Position;
|
||||
readonly end: Position;
|
||||
}
|
||||
|
||||
export interface YamlObjectNode {
|
||||
readonly type: 'object';
|
||||
readonly properties: { key: YamlStringNode; value: YamlNode }[];
|
||||
readonly start: Position;
|
||||
readonly end: Position;
|
||||
}
|
||||
|
||||
export interface YamlArrayNode {
|
||||
readonly type: 'array';
|
||||
readonly items: YamlNode[];
|
||||
readonly start: Position;
|
||||
readonly end: Position;
|
||||
}
|
||||
|
||||
export type YamlNode = YamlStringNode | YamlNumberNode | YamlBooleanNode | YamlNullNode | YamlObjectNode | YamlArrayNode;
|
||||
|
||||
// Helper functions for position and node creation
|
||||
function createPosition(line: number, character: number): Position {
|
||||
return { line, character };
|
||||
}
|
||||
|
||||
// Specialized node creation functions using a more concise approach
|
||||
function createStringNode(value: string, start: Position, end: Position): YamlStringNode {
|
||||
return { type: 'string', value, start, end };
|
||||
}
|
||||
|
||||
function createNumberNode(value: number, start: Position, end: Position): YamlNumberNode {
|
||||
return { type: 'number', value, start, end };
|
||||
}
|
||||
|
||||
function createBooleanNode(value: boolean, start: Position, end: Position): YamlBooleanNode {
|
||||
return { type: 'boolean', value, start, end };
|
||||
}
|
||||
|
||||
function createNullNode(start: Position, end: Position): YamlNullNode {
|
||||
return { type: 'null', value: null, start, end };
|
||||
}
|
||||
|
||||
function createObjectNode(properties: { key: YamlStringNode; value: YamlNode }[], start: Position, end: Position): YamlObjectNode {
|
||||
return { type: 'object', start, end, properties };
|
||||
}
|
||||
|
||||
function createArrayNode(items: YamlNode[], start: Position, end: Position): YamlArrayNode {
|
||||
return { type: 'array', start, end, items };
|
||||
}
|
||||
|
||||
// Utility functions for parsing
|
||||
function isWhitespace(char: string): boolean {
|
||||
return char === ' ' || char === '\t';
|
||||
}
|
||||
|
||||
// Simplified number validation using regex
|
||||
function isValidNumber(value: string): boolean {
|
||||
return /^-?\d*\.?\d+$/.test(value);
|
||||
}
|
||||
|
||||
// Lexer/Tokenizer for YAML content
|
||||
class YamlLexer {
|
||||
private lines: string[];
|
||||
private currentLine: number = 0;
|
||||
private currentChar: number = 0;
|
||||
|
||||
constructor(lines: string[]) {
|
||||
this.lines = lines;
|
||||
}
|
||||
|
||||
getCurrentPosition(): Position {
|
||||
return createPosition(this.currentLine, this.currentChar);
|
||||
}
|
||||
|
||||
getCurrentLineNumber(): number {
|
||||
return this.currentLine;
|
||||
}
|
||||
|
||||
getCurrentCharNumber(): number {
|
||||
return this.currentChar;
|
||||
}
|
||||
|
||||
getCurrentLineText(): string {
|
||||
return this.currentLine < this.lines.length ? this.lines[this.currentLine] : '';
|
||||
}
|
||||
|
||||
savePosition(): { line: number; char: number } {
|
||||
return { line: this.currentLine, char: this.currentChar };
|
||||
}
|
||||
|
||||
restorePosition(pos: { line: number; char: number }): void {
|
||||
this.currentLine = pos.line;
|
||||
this.currentChar = pos.char;
|
||||
}
|
||||
|
||||
isAtEnd(): boolean {
|
||||
return this.currentLine >= this.lines.length;
|
||||
}
|
||||
|
||||
getCurrentChar(): string {
|
||||
if (this.isAtEnd() || this.currentChar >= this.lines[this.currentLine].length) {
|
||||
return '';
|
||||
}
|
||||
return this.lines[this.currentLine][this.currentChar];
|
||||
}
|
||||
|
||||
peek(offset: number = 1): string {
|
||||
const newChar = this.currentChar + offset;
|
||||
if (this.currentLine >= this.lines.length || newChar >= this.lines[this.currentLine].length) {
|
||||
return '';
|
||||
}
|
||||
return this.lines[this.currentLine][newChar];
|
||||
}
|
||||
|
||||
advance(): string {
|
||||
const char = this.getCurrentChar();
|
||||
if (this.currentChar >= this.lines[this.currentLine].length && this.currentLine < this.lines.length - 1) {
|
||||
this.currentLine++;
|
||||
this.currentChar = 0;
|
||||
} else {
|
||||
this.currentChar++;
|
||||
}
|
||||
return char;
|
||||
}
|
||||
|
||||
advanceLine(): void {
|
||||
this.currentLine++;
|
||||
this.currentChar = 0;
|
||||
}
|
||||
|
||||
skipWhitespace(): void {
|
||||
while (!this.isAtEnd() && this.currentChar < this.lines[this.currentLine].length && isWhitespace(this.getCurrentChar())) {
|
||||
this.advance();
|
||||
}
|
||||
}
|
||||
|
||||
skipToEndOfLine(): void {
|
||||
this.currentChar = this.lines[this.currentLine].length;
|
||||
}
|
||||
|
||||
getIndentation(): number {
|
||||
if (this.isAtEnd()) {
|
||||
return 0;
|
||||
}
|
||||
let indent = 0;
|
||||
for (let i = 0; i < this.lines[this.currentLine].length; i++) {
|
||||
if (this.lines[this.currentLine][i] === ' ') {
|
||||
indent++;
|
||||
} else if (this.lines[this.currentLine][i] === '\t') {
|
||||
indent += 4; // Treat tab as 4 spaces
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return indent;
|
||||
}
|
||||
|
||||
moveToNextNonEmptyLine(): void {
|
||||
while (this.currentLine < this.lines.length) {
|
||||
// First check current line from current position
|
||||
if (this.currentChar < this.lines[this.currentLine].length) {
|
||||
const remainingLine = this.lines[this.currentLine].substring(this.currentChar).trim();
|
||||
if (remainingLine.length > 0 && !remainingLine.startsWith('#')) {
|
||||
this.skipWhitespace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Move to next line and check from beginning
|
||||
this.currentLine++;
|
||||
this.currentChar = 0;
|
||||
|
||||
if (this.currentLine < this.lines.length) {
|
||||
const line = this.lines[this.currentLine].trim();
|
||||
if (line.length > 0 && !line.startsWith('#')) {
|
||||
this.skipWhitespace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parser class for handling YAML parsing
|
||||
class YamlParser {
|
||||
private lexer: YamlLexer;
|
||||
private errors: YamlParseError[];
|
||||
private options: ParseOptions;
|
||||
// Track nesting level of flow (inline) collections '[' ']' '{' '}'
|
||||
private flowLevel: number = 0;
|
||||
|
||||
constructor(lines: string[], errors: YamlParseError[], options: ParseOptions) {
|
||||
this.lexer = new YamlLexer(lines);
|
||||
this.errors = errors;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
addError(message: string, code: string, start: Position, end: Position): void {
|
||||
this.errors.push({ message, code, start, end });
|
||||
}
|
||||
|
||||
parseValue(expectedIndent?: number): YamlNode {
|
||||
this.lexer.skipWhitespace();
|
||||
|
||||
if (this.lexer.isAtEnd()) {
|
||||
const pos = this.lexer.getCurrentPosition();
|
||||
return createStringNode('', pos, pos);
|
||||
}
|
||||
|
||||
const char = this.lexer.getCurrentChar();
|
||||
|
||||
// Handle quoted strings
|
||||
if (char === '"' || char === `'`) {
|
||||
return this.parseQuotedString(char);
|
||||
}
|
||||
|
||||
// Handle inline arrays
|
||||
if (char === '[') {
|
||||
return this.parseInlineArray();
|
||||
}
|
||||
|
||||
// Handle inline objects
|
||||
if (char === '{') {
|
||||
return this.parseInlineObject();
|
||||
}
|
||||
|
||||
// Handle unquoted values
|
||||
return this.parseUnquotedValue();
|
||||
}
|
||||
|
||||
parseQuotedString(quote: string): YamlNode {
|
||||
const start = this.lexer.getCurrentPosition();
|
||||
this.lexer.advance(); // Skip opening quote
|
||||
|
||||
let value = '';
|
||||
while (!this.lexer.isAtEnd() && this.lexer.getCurrentChar() !== '' && this.lexer.getCurrentChar() !== quote) {
|
||||
value += this.lexer.advance();
|
||||
}
|
||||
|
||||
if (this.lexer.getCurrentChar() === quote) {
|
||||
this.lexer.advance(); // Skip closing quote
|
||||
}
|
||||
|
||||
const end = this.lexer.getCurrentPosition();
|
||||
return createStringNode(value, start, end);
|
||||
}
|
||||
|
||||
parseUnquotedValue(): YamlNode {
|
||||
const start = this.lexer.getCurrentPosition();
|
||||
let value = '';
|
||||
let endPos = start;
|
||||
|
||||
// Helper function to check for value terminators
|
||||
const isTerminator = (char: string): boolean => {
|
||||
if (char === '#') { return true; }
|
||||
// Comma, ']' and '}' only terminate inside flow collections
|
||||
if (this.flowLevel > 0 && (char === ',' || char === ']' || char === '}')) { return true; }
|
||||
return false;
|
||||
};
|
||||
|
||||
// Handle opening quote that might not be closed
|
||||
const firstChar = this.lexer.getCurrentChar();
|
||||
if (firstChar === '"' || firstChar === `'`) {
|
||||
value += this.lexer.advance();
|
||||
endPos = this.lexer.getCurrentPosition();
|
||||
while (!this.lexer.isAtEnd() && this.lexer.getCurrentChar() !== '') {
|
||||
const char = this.lexer.getCurrentChar();
|
||||
if (char === firstChar || isTerminator(char)) {
|
||||
break;
|
||||
}
|
||||
value += this.lexer.advance();
|
||||
endPos = this.lexer.getCurrentPosition();
|
||||
}
|
||||
} else {
|
||||
while (!this.lexer.isAtEnd() && this.lexer.getCurrentChar() !== '') {
|
||||
const char = this.lexer.getCurrentChar();
|
||||
if (isTerminator(char)) {
|
||||
break;
|
||||
}
|
||||
value += this.lexer.advance();
|
||||
endPos = this.lexer.getCurrentPosition();
|
||||
}
|
||||
}
|
||||
const trimmed = value.trimEnd();
|
||||
const diff = value.length - trimmed.length;
|
||||
if (diff) {
|
||||
endPos = createPosition(start.line, endPos.character - diff);
|
||||
}
|
||||
const finalValue = (firstChar === '"' || firstChar === `'`) ? trimmed.substring(1) : trimmed;
|
||||
return this.createValueNode(finalValue, start, endPos);
|
||||
}
|
||||
|
||||
private createValueNode(value: string, start: Position, end: Position): YamlNode {
|
||||
if (value === '') {
|
||||
return createStringNode('', start, start);
|
||||
}
|
||||
|
||||
// Boolean values
|
||||
if (value === 'true') {
|
||||
return createBooleanNode(true, start, end);
|
||||
}
|
||||
if (value === 'false') {
|
||||
return createBooleanNode(false, start, end);
|
||||
}
|
||||
|
||||
// Null values
|
||||
if (value === 'null' || value === '~') {
|
||||
return createNullNode(start, end);
|
||||
}
|
||||
|
||||
// Number values
|
||||
const numberValue = Number(value);
|
||||
if (!isNaN(numberValue) && isFinite(numberValue) && isValidNumber(value)) {
|
||||
return createNumberNode(numberValue, start, end);
|
||||
}
|
||||
|
||||
// Default to string
|
||||
return createStringNode(value, start, end);
|
||||
}
|
||||
|
||||
parseInlineArray(): YamlArrayNode {
|
||||
const start = this.lexer.getCurrentPosition();
|
||||
this.lexer.advance(); // Skip '['
|
||||
this.flowLevel++;
|
||||
|
||||
const items: YamlNode[] = [];
|
||||
|
||||
while (!this.lexer.isAtEnd()) {
|
||||
this.lexer.skipWhitespace();
|
||||
|
||||
// Handle end of array
|
||||
if (this.lexer.getCurrentChar() === ']') {
|
||||
this.lexer.advance();
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle end of line - continue to next line for multi-line arrays
|
||||
if (this.lexer.getCurrentChar() === '') {
|
||||
this.lexer.advanceLine();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse array item
|
||||
const item = this.parseValue();
|
||||
items.push(item);
|
||||
|
||||
this.lexer.skipWhitespace();
|
||||
|
||||
// Handle comma separator
|
||||
if (this.lexer.getCurrentChar() === ',') {
|
||||
this.lexer.advance();
|
||||
}
|
||||
}
|
||||
|
||||
const end = this.lexer.getCurrentPosition();
|
||||
this.flowLevel--;
|
||||
return createArrayNode(items, start, end);
|
||||
}
|
||||
|
||||
parseInlineObject(): YamlObjectNode {
|
||||
const start = this.lexer.getCurrentPosition();
|
||||
this.lexer.advance(); // Skip '{'
|
||||
this.flowLevel++;
|
||||
|
||||
const properties: { key: YamlStringNode; value: YamlNode }[] = [];
|
||||
|
||||
while (!this.lexer.isAtEnd()) {
|
||||
this.lexer.skipWhitespace();
|
||||
|
||||
// Handle end of object
|
||||
if (this.lexer.getCurrentChar() === '}') {
|
||||
this.lexer.advance();
|
||||
break;
|
||||
}
|
||||
|
||||
// Parse key - read until colon
|
||||
const keyStart = this.lexer.getCurrentPosition();
|
||||
let keyValue = '';
|
||||
|
||||
// Handle quoted keys
|
||||
if (this.lexer.getCurrentChar() === '"' || this.lexer.getCurrentChar() === `'`) {
|
||||
const quote = this.lexer.getCurrentChar();
|
||||
this.lexer.advance(); // Skip opening quote
|
||||
|
||||
while (!this.lexer.isAtEnd() && this.lexer.getCurrentChar() !== '' && this.lexer.getCurrentChar() !== quote) {
|
||||
keyValue += this.lexer.advance();
|
||||
}
|
||||
|
||||
if (this.lexer.getCurrentChar() === quote) {
|
||||
this.lexer.advance(); // Skip closing quote
|
||||
}
|
||||
} else {
|
||||
// Handle unquoted keys - read until colon
|
||||
while (!this.lexer.isAtEnd() && this.lexer.getCurrentChar() !== '' && this.lexer.getCurrentChar() !== ':') {
|
||||
keyValue += this.lexer.advance();
|
||||
}
|
||||
}
|
||||
|
||||
keyValue = keyValue.trim();
|
||||
const keyEnd = this.lexer.getCurrentPosition();
|
||||
const key = createStringNode(keyValue, keyStart, keyEnd);
|
||||
|
||||
this.lexer.skipWhitespace();
|
||||
|
||||
// Expect colon
|
||||
if (this.lexer.getCurrentChar() === ':') {
|
||||
this.lexer.advance();
|
||||
}
|
||||
|
||||
this.lexer.skipWhitespace();
|
||||
|
||||
// Parse value
|
||||
const value = this.parseValue();
|
||||
|
||||
properties.push({ key, value });
|
||||
|
||||
this.lexer.skipWhitespace();
|
||||
|
||||
// Handle comma separator
|
||||
if (this.lexer.getCurrentChar() === ',') {
|
||||
this.lexer.advance();
|
||||
}
|
||||
}
|
||||
|
||||
const end = this.lexer.getCurrentPosition();
|
||||
this.flowLevel--;
|
||||
return createObjectNode(properties, start, end);
|
||||
}
|
||||
|
||||
parseBlockArray(baseIndent: number): YamlArrayNode {
|
||||
const start = this.lexer.getCurrentPosition();
|
||||
const items: YamlNode[] = [];
|
||||
|
||||
while (!this.lexer.isAtEnd()) {
|
||||
this.lexer.moveToNextNonEmptyLine();
|
||||
|
||||
if (this.lexer.isAtEnd()) {
|
||||
break;
|
||||
}
|
||||
|
||||
const currentIndent = this.lexer.getIndentation();
|
||||
|
||||
// If indentation is less than expected, we're done with this array
|
||||
if (currentIndent < baseIndent) {
|
||||
break;
|
||||
}
|
||||
|
||||
this.lexer.skipWhitespace();
|
||||
|
||||
// Check for array item marker
|
||||
if (this.lexer.getCurrentChar() === '-') {
|
||||
this.lexer.advance(); // Skip '-'
|
||||
this.lexer.skipWhitespace();
|
||||
|
||||
const itemStart = this.lexer.getCurrentPosition();
|
||||
|
||||
// Check if this is a nested structure
|
||||
if (this.lexer.getCurrentChar() === '' || this.lexer.getCurrentChar() === '#') {
|
||||
// Empty item - check if next lines form a nested structure
|
||||
this.lexer.advanceLine();
|
||||
|
||||
if (!this.lexer.isAtEnd()) {
|
||||
const nextIndent = this.lexer.getIndentation();
|
||||
|
||||
if (nextIndent > currentIndent) {
|
||||
// Check if the next line starts with a dash (nested array) or has properties (nested object)
|
||||
this.lexer.skipWhitespace();
|
||||
if (this.lexer.getCurrentChar() === '-') {
|
||||
// It's a nested array
|
||||
const nestedArray = this.parseBlockArray(nextIndent);
|
||||
items.push(nestedArray);
|
||||
} else {
|
||||
// Check if it looks like an object property (has a colon)
|
||||
const currentLine = this.lexer.getCurrentLineText();
|
||||
const currentPos = this.lexer.getCurrentCharNumber();
|
||||
const remainingLine = currentLine.substring(currentPos);
|
||||
|
||||
if (remainingLine.includes(':') && !remainingLine.trim().startsWith('#')) {
|
||||
// It's a nested object
|
||||
const nestedObject = this.parseBlockObject(nextIndent, this.lexer.getCurrentCharNumber());
|
||||
items.push(nestedObject);
|
||||
} else {
|
||||
// Not a nested structure, create empty string
|
||||
items.push(createStringNode('', itemStart, itemStart));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No nested content, empty item
|
||||
items.push(createStringNode('', itemStart, itemStart));
|
||||
}
|
||||
} else {
|
||||
// End of input, empty item
|
||||
items.push(createStringNode('', itemStart, itemStart));
|
||||
}
|
||||
} else {
|
||||
// Parse the item value
|
||||
// Check if this is a multi-line object by looking for a colon and checking next lines
|
||||
const currentLine = this.lexer.getCurrentLineText();
|
||||
const currentPos = this.lexer.getCurrentCharNumber();
|
||||
const remainingLine = currentLine.substring(currentPos);
|
||||
|
||||
// Check if there's a colon on this line (indicating object properties)
|
||||
const hasColon = remainingLine.includes(':');
|
||||
|
||||
if (hasColon) {
|
||||
// Any line with a colon should be treated as an object
|
||||
// Parse as an object with the current item's indentation as the base
|
||||
const item = this.parseBlockObject(itemStart.character, itemStart.character);
|
||||
items.push(item);
|
||||
} else {
|
||||
// No colon, parse as regular value
|
||||
const item = this.parseValue();
|
||||
items.push(item);
|
||||
|
||||
// Skip to end of line
|
||||
while (!this.lexer.isAtEnd() && this.lexer.getCurrentChar() !== '' && this.lexer.getCurrentChar() !== '#') {
|
||||
this.lexer.advance();
|
||||
}
|
||||
this.lexer.advanceLine();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No dash found at expected indent level, break
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate end position based on the last item
|
||||
let end = start;
|
||||
if (items.length > 0) {
|
||||
const lastItem = items[items.length - 1];
|
||||
end = lastItem.end;
|
||||
} else {
|
||||
// If no items, end is right after the start
|
||||
end = createPosition(start.line, start.character + 1);
|
||||
}
|
||||
|
||||
return createArrayNode(items, start, end);
|
||||
}
|
||||
|
||||
parseBlockObject(baseIndent: number, baseCharPosition?: number): YamlObjectNode {
|
||||
const start = this.lexer.getCurrentPosition();
|
||||
const properties: { key: YamlStringNode; value: YamlNode }[] = [];
|
||||
const localKeysSeen = new Set<string>();
|
||||
|
||||
// For parsing from current position (inline object parsing)
|
||||
const fromCurrentPosition = baseCharPosition !== undefined;
|
||||
let firstIteration = true;
|
||||
|
||||
while (!this.lexer.isAtEnd()) {
|
||||
if (!firstIteration || !fromCurrentPosition) {
|
||||
this.lexer.moveToNextNonEmptyLine();
|
||||
}
|
||||
firstIteration = false;
|
||||
|
||||
if (this.lexer.isAtEnd()) {
|
||||
break;
|
||||
}
|
||||
|
||||
const currentIndent = this.lexer.getIndentation();
|
||||
|
||||
if (fromCurrentPosition) {
|
||||
// For current position parsing, check character position alignment
|
||||
this.lexer.skipWhitespace();
|
||||
const currentCharPosition = this.lexer.getCurrentCharNumber();
|
||||
|
||||
if (currentCharPosition < baseCharPosition) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// For normal block parsing, check indentation level
|
||||
if (currentIndent < baseIndent) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for incorrect indentation
|
||||
if (currentIndent > baseIndent) {
|
||||
const lineStart = createPosition(this.lexer.getCurrentLineNumber(), 0);
|
||||
const lineEnd = createPosition(this.lexer.getCurrentLineNumber(), this.lexer.getCurrentLineText().length);
|
||||
this.addError('Unexpected indentation', 'indentation', lineStart, lineEnd);
|
||||
|
||||
// Try to recover by treating it as a property anyway
|
||||
this.lexer.skipWhitespace();
|
||||
} else {
|
||||
this.lexer.skipWhitespace();
|
||||
}
|
||||
}
|
||||
|
||||
// Parse key
|
||||
const keyStart = this.lexer.getCurrentPosition();
|
||||
let keyValue = '';
|
||||
|
||||
while (!this.lexer.isAtEnd() && this.lexer.getCurrentChar() !== '' && this.lexer.getCurrentChar() !== ':') {
|
||||
keyValue += this.lexer.advance();
|
||||
}
|
||||
|
||||
keyValue = keyValue.trim();
|
||||
const keyEnd = this.lexer.getCurrentPosition();
|
||||
const key = createStringNode(keyValue, keyStart, keyEnd);
|
||||
|
||||
// Check for duplicate keys
|
||||
if (!this.options.allowDuplicateKeys && localKeysSeen.has(keyValue)) {
|
||||
this.addError(`Duplicate key '${keyValue}'`, 'duplicateKey', keyStart, keyEnd);
|
||||
}
|
||||
localKeysSeen.add(keyValue);
|
||||
|
||||
// Expect colon
|
||||
if (this.lexer.getCurrentChar() === ':') {
|
||||
this.lexer.advance();
|
||||
}
|
||||
|
||||
this.lexer.skipWhitespace();
|
||||
|
||||
// Determine if value is on same line or next line(s)
|
||||
let value: YamlNode;
|
||||
const valueStart = this.lexer.getCurrentPosition();
|
||||
|
||||
if (this.lexer.getCurrentChar() === '' || this.lexer.getCurrentChar() === '#') {
|
||||
// Value is on next line(s) or empty
|
||||
this.lexer.advanceLine();
|
||||
|
||||
// Check next line for nested content
|
||||
if (!this.lexer.isAtEnd()) {
|
||||
const nextIndent = this.lexer.getIndentation();
|
||||
|
||||
if (nextIndent > currentIndent) {
|
||||
// Nested content - determine if it's an object or array
|
||||
this.lexer.skipWhitespace();
|
||||
|
||||
if (this.lexer.getCurrentChar() === '-') {
|
||||
value = this.parseBlockArray(nextIndent);
|
||||
} else {
|
||||
value = this.parseBlockObject(nextIndent);
|
||||
}
|
||||
} else if (!fromCurrentPosition && nextIndent === currentIndent) {
|
||||
// Same indentation level - check if it's an array item
|
||||
this.lexer.skipWhitespace();
|
||||
|
||||
if (this.lexer.getCurrentChar() === '-') {
|
||||
value = this.parseBlockArray(currentIndent);
|
||||
} else {
|
||||
value = createStringNode('', valueStart, valueStart);
|
||||
}
|
||||
} else {
|
||||
value = createStringNode('', valueStart, valueStart);
|
||||
}
|
||||
} else {
|
||||
value = createStringNode('', valueStart, valueStart);
|
||||
}
|
||||
} else {
|
||||
// Value is on the same line
|
||||
value = this.parseValue();
|
||||
|
||||
// Skip any remaining content on this line (comments, etc.)
|
||||
while (!this.lexer.isAtEnd() && this.lexer.getCurrentChar() !== '' && this.lexer.getCurrentChar() !== '#') {
|
||||
if (isWhitespace(this.lexer.getCurrentChar())) {
|
||||
this.lexer.advance();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip to end of line if we hit a comment
|
||||
if (this.lexer.getCurrentChar() === '#') {
|
||||
this.lexer.skipToEndOfLine();
|
||||
}
|
||||
|
||||
// Move to next line for next iteration
|
||||
if (!this.lexer.isAtEnd() && this.lexer.getCurrentChar() === '') {
|
||||
this.lexer.advanceLine();
|
||||
}
|
||||
}
|
||||
|
||||
properties.push({ key, value });
|
||||
}
|
||||
|
||||
// Calculate the end position based on the last property
|
||||
let end = start;
|
||||
if (properties.length > 0) {
|
||||
const lastProperty = properties[properties.length - 1];
|
||||
end = lastProperty.value.end;
|
||||
}
|
||||
|
||||
return createObjectNode(properties, start, end);
|
||||
}
|
||||
|
||||
parse(): YamlNode | undefined {
|
||||
if (this.lexer.isAtEnd()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
this.lexer.moveToNextNonEmptyLine();
|
||||
|
||||
if (this.lexer.isAtEnd()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Determine the root structure type
|
||||
this.lexer.skipWhitespace();
|
||||
|
||||
if (this.lexer.getCurrentChar() === '-') {
|
||||
// Check if this is an array item or a negative number
|
||||
// Look at the character after the dash
|
||||
const nextChar = this.lexer.peek();
|
||||
if (nextChar === ' ' || nextChar === '\t' || nextChar === '' || nextChar === '#') {
|
||||
// It's an array item (dash followed by whitespace/end/comment)
|
||||
return this.parseBlockArray(0);
|
||||
} else {
|
||||
// It's likely a negative number or other value, treat as single value
|
||||
return this.parseValue();
|
||||
}
|
||||
} else if (this.lexer.getCurrentChar() === '[') {
|
||||
// Root is an inline array
|
||||
return this.parseInlineArray();
|
||||
} else if (this.lexer.getCurrentChar() === '{') {
|
||||
// Root is an inline object
|
||||
return this.parseInlineObject();
|
||||
} else {
|
||||
// Check if this looks like a key-value pair by looking for a colon
|
||||
// For single values, there shouldn't be a colon
|
||||
const currentLine = this.lexer.getCurrentLineText();
|
||||
const currentPos = this.lexer.getCurrentCharNumber();
|
||||
const remainingLine = currentLine.substring(currentPos);
|
||||
|
||||
// Check if there's a colon that's not inside quotes
|
||||
let hasColon = false;
|
||||
let inQuotes = false;
|
||||
let quoteChar = '';
|
||||
|
||||
for (let i = 0; i < remainingLine.length; i++) {
|
||||
const char = remainingLine[i];
|
||||
|
||||
if (!inQuotes && (char === '"' || char === `'`)) {
|
||||
inQuotes = true;
|
||||
quoteChar = char;
|
||||
} else if (inQuotes && char === quoteChar) {
|
||||
inQuotes = false;
|
||||
quoteChar = '';
|
||||
} else if (!inQuotes && char === ':') {
|
||||
hasColon = true;
|
||||
break;
|
||||
} else if (!inQuotes && char === '#') {
|
||||
// Comment starts, stop looking
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasColon) {
|
||||
// Root is an object
|
||||
return this.parseBlockObject(0);
|
||||
} else {
|
||||
// Root is a single value
|
||||
return this.parseValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -256,6 +256,27 @@ suite('MarkdownRenderer', () => {
|
||||
assert.strictEqual(result.innerHTML, `<p><a draggable="false" title="command:doFoo" href="" data-href="command:doFoo">command1</a> <a href="" data-href="command:doFoo">command2</a></p>`);
|
||||
});
|
||||
|
||||
test('Should remove relative links if there is no base url', () => {
|
||||
const md = new MarkdownString(`[text](./foo) <a href="./bar">bar</a>`, {
|
||||
isTrusted: true,
|
||||
supportHtml: true,
|
||||
});
|
||||
|
||||
const result = store.add(renderMarkdown(md)).element;
|
||||
assert.strictEqual(result.innerHTML, `<p>text bar</p>`);
|
||||
});
|
||||
|
||||
test('Should support relative links if baseurl is set', () => {
|
||||
const md = new MarkdownString(`[text](./foo) <a href="./bar">bar</a>`, {
|
||||
isTrusted: true,
|
||||
supportHtml: true,
|
||||
});
|
||||
md.baseUri = URI.parse('https://example.com/path/');
|
||||
|
||||
const result = store.add(renderMarkdown(md)).element;
|
||||
assert.strictEqual(result.innerHTML, `<p><a draggable="false" title="./foo" href="" data-href="https://example.com/path/foo">text</a> <a href="" data-href="https://example.com/path/bar">bar</a></p>`);
|
||||
});
|
||||
|
||||
suite('PlaintextMarkdownRender', () => {
|
||||
|
||||
test('test code, blockquote, heading, list, listitem, paragraph, table, tablerow, tablecell, strong, em, br, del, text are rendered plaintext', () => {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import assert from 'assert';
|
||||
import { CancellationToken, CancellationTokenSource } from '../../common/cancellation.js';
|
||||
import { CancellationToken, CancellationTokenSource, CancellationTokenPool } from '../../common/cancellation.js';
|
||||
import { ensureNoDisposablesAreLeakedInTestSuite } from './utils.js';
|
||||
|
||||
suite('CancellationToken', function () {
|
||||
@@ -125,3 +125,155 @@ suite('CancellationToken', function () {
|
||||
parent.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
suite('CancellationTokenPool', function () {
|
||||
|
||||
const store = ensureNoDisposablesAreLeakedInTestSuite();
|
||||
|
||||
test('empty pool token is not cancelled', function () {
|
||||
const pool = new CancellationTokenPool();
|
||||
store.add(pool);
|
||||
|
||||
assert.strictEqual(pool.token.isCancellationRequested, false);
|
||||
});
|
||||
|
||||
test('pool token cancels when all tokens are cancelled', function () {
|
||||
const pool = new CancellationTokenPool();
|
||||
store.add(pool);
|
||||
|
||||
const source1 = new CancellationTokenSource();
|
||||
const source2 = new CancellationTokenSource();
|
||||
const source3 = new CancellationTokenSource();
|
||||
|
||||
pool.add(source1.token);
|
||||
pool.add(source2.token);
|
||||
pool.add(source3.token);
|
||||
|
||||
assert.strictEqual(pool.token.isCancellationRequested, false);
|
||||
|
||||
source1.cancel();
|
||||
assert.strictEqual(pool.token.isCancellationRequested, false);
|
||||
|
||||
source2.cancel();
|
||||
assert.strictEqual(pool.token.isCancellationRequested, false);
|
||||
|
||||
source3.cancel();
|
||||
assert.strictEqual(pool.token.isCancellationRequested, true);
|
||||
|
||||
source1.dispose();
|
||||
source2.dispose();
|
||||
source3.dispose();
|
||||
});
|
||||
|
||||
test('pool token fires cancellation event when all tokens are cancelled', function () {
|
||||
return new Promise<void>(resolve => {
|
||||
const pool = new CancellationTokenPool();
|
||||
store.add(pool);
|
||||
|
||||
const source1 = new CancellationTokenSource();
|
||||
const source2 = new CancellationTokenSource();
|
||||
|
||||
pool.add(source1.token);
|
||||
pool.add(source2.token);
|
||||
|
||||
store.add(pool.token.onCancellationRequested(() => resolve()));
|
||||
|
||||
source1.cancel();
|
||||
source2.cancel();
|
||||
|
||||
source1.dispose();
|
||||
source2.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
test('adding already cancelled token counts immediately', function () {
|
||||
const pool = new CancellationTokenPool();
|
||||
store.add(pool);
|
||||
|
||||
const source1 = new CancellationTokenSource();
|
||||
const source2 = new CancellationTokenSource();
|
||||
|
||||
source1.cancel(); // Cancel before adding to pool
|
||||
|
||||
pool.add(source1.token);
|
||||
assert.strictEqual(pool.token.isCancellationRequested, true); // 1 of 1 cancelled, so pool is cancelled
|
||||
|
||||
pool.add(source2.token); // Adding after pool is done should have no effect
|
||||
assert.strictEqual(pool.token.isCancellationRequested, true);
|
||||
|
||||
source2.cancel(); // This should have no effect since pool is already done
|
||||
assert.strictEqual(pool.token.isCancellationRequested, true);
|
||||
|
||||
source1.dispose();
|
||||
source2.dispose();
|
||||
});
|
||||
|
||||
test('adding single already cancelled token cancels pool immediately', function () {
|
||||
const pool = new CancellationTokenPool();
|
||||
store.add(pool);
|
||||
|
||||
const source = new CancellationTokenSource();
|
||||
source.cancel();
|
||||
|
||||
pool.add(source.token);
|
||||
assert.strictEqual(pool.token.isCancellationRequested, true); // 1 of 1 cancelled
|
||||
|
||||
source.dispose();
|
||||
});
|
||||
|
||||
test('adding token after pool is done has no effect', function () {
|
||||
const pool = new CancellationTokenPool();
|
||||
store.add(pool);
|
||||
|
||||
const source1 = new CancellationTokenSource();
|
||||
const source2 = new CancellationTokenSource();
|
||||
|
||||
pool.add(source1.token);
|
||||
source1.cancel(); // Pool should be done now
|
||||
|
||||
assert.strictEqual(pool.token.isCancellationRequested, true);
|
||||
|
||||
// Adding another token should have no effect
|
||||
pool.add(source2.token);
|
||||
source2.cancel();
|
||||
|
||||
assert.strictEqual(pool.token.isCancellationRequested, true);
|
||||
|
||||
source1.dispose();
|
||||
source2.dispose();
|
||||
});
|
||||
|
||||
test('single token pool behaviour', function () {
|
||||
const pool = new CancellationTokenPool();
|
||||
store.add(pool);
|
||||
|
||||
const source = new CancellationTokenSource();
|
||||
pool.add(source.token);
|
||||
|
||||
assert.strictEqual(pool.token.isCancellationRequested, false);
|
||||
|
||||
source.cancel();
|
||||
assert.strictEqual(pool.token.isCancellationRequested, true);
|
||||
|
||||
source.dispose();
|
||||
});
|
||||
|
||||
test('pool with only cancelled tokens', function () {
|
||||
const pool = new CancellationTokenPool();
|
||||
store.add(pool);
|
||||
|
||||
const source1 = new CancellationTokenSource();
|
||||
const source2 = new CancellationTokenSource();
|
||||
|
||||
source1.cancel();
|
||||
source2.cancel();
|
||||
|
||||
pool.add(source1.token);
|
||||
pool.add(source2.token);
|
||||
|
||||
assert.strictEqual(pool.token.isCancellationRequested, true);
|
||||
|
||||
source1.dispose();
|
||||
source2.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -531,12 +531,6 @@ suite('Event', function () {
|
||||
// assert that all events are delivered in order
|
||||
assert.deepStrictEqual(listener2Events, ['e1', 'e2', 'e3']);
|
||||
});
|
||||
|
||||
test('Cannot read property \'_actual\' of undefined #142204', function () {
|
||||
const e = ds.add(new Emitter<number>());
|
||||
const dispo = e.event(() => { });
|
||||
dispo.dispose.call(undefined); // assert that disposable can be called with this
|
||||
});
|
||||
});
|
||||
|
||||
suite('AsyncEmitter', function () {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user