Merge branch 'main' into dev/mjbvz/legitimate-squirrel

This commit is contained in:
Matt Bierner
2025-11-17 16:32:38 -08:00
2121 changed files with 88588 additions and 43466 deletions
@@ -1,9 +1,10 @@
{
"hydrated": true,
"properties": {
"helpUri": "https://eng.ms/docs/microsoft-security/security/azure-security/cloudai-security-fundamentals-engineering/security-integration/guardian-wiki/microsoft-guardian/general/baselines"
"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",
"baselines": {
"suppressionSets": {
"default": {
"name": "default",
"createdDate": "2025-01-28 06:29:05Z",
+125
View File
@@ -0,0 +1,125 @@
# Custom ESLint rules
We use a set of custom [ESLint](http://eslint.org) to enforce repo specific coding rules and styles. These custom rules are run in addition to many standard ESLint rules we enable in the project. Some example custom rules includes:
- Enforcing proper code layering
- Preventing checking in of `test.only(...)`
- Enforcing conventions in `vscode.d.ts`
Custom rules are mostly used for enforcing or banning certain coding patterns. We tend to leave stylistic choices up to area owners unless there's a good reason to enforce something project wide.
This doc provides a brief overview of how these rules are setup and how you can add a new one.
# Resources
- [ESLint rules](https://eslint.org/docs/latest/extend/custom-rules) — General documentation about writing eslint rules
- [TypeScript ASTs and eslint](https://typescript-eslint.io/blog/asts-and-typescript-eslint/) — Look at how ESLint works with TS programs
- [ESTree selectors](https://eslint.org/docs/latest/extend/selectors) — Info about the selector syntax rules use to target specific nodes in an AST. Works similarly to css selectors.
- [TypeScript ESLint playground](https://typescript-eslint.io/play/#showAST=es) — Useful tool for figuring out the structure of TS programs and debugging custom rule selectors
# Custom Rule Configuration
Custom rules are defined in the `.eslint-plugin-local` folder. Each rule is defined in its own TypeScript file. These follow the naming convention:
- `code-RULE-NAME.ts` — General rules that apply to the entire repo.
- `vscode-dts-RULE-NAME.ts` — Rules that apply just to `vscode.d.ts`.
These rules are then enabled in the `eslint.config.js` file. This is the main eslint configuration for our repo. It defines a set of file scopes which rules should apply to files in those scopes.
For example, here's a configuration that enables the no `test.only` rule in all `*.test.ts` files in the VS Code repo:
```ts
{
// Define which files these rules apply to
files: [
'**/*.test.ts'
],
languageOptions: { parser: tseslint.parser, },
plugins: {
'local': pluginLocal,
},
rules: {
// Enable the rule from .eslint-plugin-local/code-no-test-only.ts
'local/code-no-test-only': 'error',
}
}
```
# Creating a new custom rule
This walks through the steps to create a new eslint rule:
1. Create a new rule file under `.eslint-plugin-local`. Generally you should call it `code-YOUR-RULE-NAME.ts`, for example, `.eslint-plugin-local/code-no-not-null-assertions-on-undefined-values.ts`
2. In this file, add the rule. Here's a template:
```ts
/*---------------------------------------------------------------------------------------------
* 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';
export = new class YourRuleName implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
customMessageName: 'message text shown in errors/warnings',
},
schema: false,
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
[SELECTOR]: (node: any) => {
// Report errors if needed
return context.report({
node,
messageId: 'customMessageName'
});
}
};
}
};
```
- Update the name of the class to match the name of your rule
- Add message entries for any errors you want to report
- Update `SELECTOR` with the [ESTree selector](https://eslint.org/docs/latest/extend/selectors) needed to target the nodes you are interested in. Use the [TypeScript ESLint playground](https://typescript-eslint.io/play/#showAST=es) to figure out which nodes you need and debug selectors
3. Register the rule in `eslint.config.js`
Generally this is just turning on the rule in the rule list like so:
```js
rules: {
// Name should match file name
'local/code-no-not-null-assertions-on-undefined-values': 'warn',
...
}
```
Rules can also take custom arguments. For example, here's how we can pass arguments to a custom rule in the `eslint.config.js`:
```
rules: {
'local/code-no-not-null-assertions-on-undefined-values': ['warn', { testsOk: true }],
...
}
```
In these cases make sure to update the `meta.schema` property on your rule with the JSON schema for the arguments. You can access these arguments using `context.options` in the rule `create` function
## Adding fixes to custom rules
Fixes are a useful way to mechanically fix basic linting issues, such as auto inserting semicolons. These fixes typically work at the AST level, so they are a more reliable way to perform bulk fixes compared to find/replaces.
To add a fix for a custom rule:
1. On the `meta` for your rule, add `fixable: 'code'`
2. When reporting an error in the rule, also include a `fix`. This is a function that takes a `fixer` argument and returns one or more fixes.
See the [Double quoted to single quoted string covert fix](https://github.com/microsoft/vscode/blob/b074375e1884ae01033967bf0bbceeaa4795354a/.eslint-plugin-local/code-no-unexternalized-strings.ts#L128) for an example. The ESLint docs also have [details on adding fixes and the fixer api](https://eslint.org/docs/latest/extend/custom-rules#applying-fixes)
The fixes can be run using `npx eslint --fix` in the VS Code repo
+8 -5
View File
@@ -4,10 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
import { readFileSync } from 'fs';
import { join } from 'path';
export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
export default new class ApiProviderNaming implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -21,7 +23,8 @@ export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
const modules = new Set<string>();
try {
const { dependencies, optionalDependencies } = require(join(__dirname, '../package.json'));
const packageJson = JSON.parse(readFileSync(join(import.meta.dirname, '../package.json'), 'utf-8'));
const { dependencies, optionalDependencies } = packageJson;
const all = Object.keys(dependencies).concat(Object.keys(optionalDependencies));
for (const key of all) {
modules.add(key);
@@ -33,13 +36,13 @@ export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
}
const checkImport = (node: any) => {
const checkImport = (node: ESTree.Literal & { parent?: ESTree.Node & { importKind?: string } }) => {
if (node.type !== 'Literal' || typeof node.value !== 'string') {
if (typeof node.value !== 'string') {
return;
}
if (node.parent.importKind === 'type') {
if (node.parent?.type === 'ImportDeclaration' && node.parent.importKind === 'type') {
return;
}
@@ -4,8 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
export = new class DeclareServiceBrand implements eslint.Rule.RuleModule {
export default new class DeclareServiceBrand implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
fixable: 'code',
@@ -14,7 +15,7 @@ export = new class DeclareServiceBrand implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
['PropertyDefinition[key.name="_serviceBrand"][value]']: (node: any) => {
['PropertyDefinition[key.name="_serviceBrand"][value]']: (node: ESTree.PropertyDefinition) => {
return context.report({
node,
message: `The '_serviceBrand'-property should not have a value`,
@@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import { Node } from 'estree';
import type * as estree from 'estree';
export = new class EnsureNoDisposablesAreLeakedInTestSuite implements eslint.Rule.RuleModule {
export default new class EnsureNoDisposablesAreLeakedInTestSuite implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
type: 'problem',
@@ -18,7 +18,7 @@ export = new class EnsureNoDisposablesAreLeakedInTestSuite implements eslint.Rul
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const config = <{ exclude: string[] }>context.options[0];
const config = context.options[0] as { exclude: string[] };
const needle = context.getFilename().replace(/\\/g, '/');
if (config.exclude.some((e) => needle.endsWith(e))) {
@@ -26,7 +26,7 @@ export = new class EnsureNoDisposablesAreLeakedInTestSuite implements eslint.Rul
}
return {
[`Program > ExpressionStatement > CallExpression[callee.name='suite']`]: (node: Node) => {
[`Program > ExpressionStatement > CallExpression[callee.name='suite']`]: (node: estree.Node) => {
const src = context.getSourceCode().getText(node);
if (!src.includes('ensureNoDisposablesAreLeakedInTestSuite(')) {
context.report({
+6 -6
View File
@@ -7,9 +7,9 @@ import * as eslint from 'eslint';
import { TSESTree } from '@typescript-eslint/utils';
import * as path from 'path';
import minimatch from 'minimatch';
import { createImportRuleListener } from './utils';
import { createImportRuleListener } from './utils.ts';
const REPO_ROOT = path.normalize(path.join(__dirname, '../'));
const REPO_ROOT = path.normalize(path.join(import.meta.dirname, '../'));
interface ConditionalPattern {
when?: 'hasBrowser' | 'hasNode' | 'hasElectron' | 'test';
@@ -31,7 +31,7 @@ interface LayerAllowRule {
type RawOption = RawImportPatternsConfig | LayerAllowRule;
function isLayerAllowRule(option: RawOption): option is LayerAllowRule {
return !!((<LayerAllowRule>option).when && (<LayerAllowRule>option).allow);
return !!((option as LayerAllowRule).when && (option as LayerAllowRule).allow);
}
interface ImportPatternsConfig {
@@ -39,7 +39,7 @@ interface ImportPatternsConfig {
restrictions: string[];
}
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -55,7 +55,7 @@ export = new class implements eslint.Rule.RuleModule {
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const options = <RawOption[]>context.options;
const options = context.options as RawOption[];
const configs = this._processOptions(options);
const relativeFilename = getRelativeFilename(context);
@@ -217,7 +217,7 @@ export = new class implements eslint.Rule.RuleModule {
configs.push(testConfig);
}
} else {
configs.push({ target, restrictions: <string[]>restrictions.filter(r => typeof r === 'string') });
configs.push({ target, restrictions: restrictions.filter(r => typeof r === 'string') as string[] });
}
}
this._optionsCache.set(options, configs);
+3 -5
View File
@@ -5,14 +5,14 @@
import * as eslint from 'eslint';
import { join, dirname } from 'path';
import { createImportRuleListener } from './utils';
import { createImportRuleListener } from './utils.ts';
type Config = {
allowed: Set<string>;
disallowed: Set<string>;
};
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -38,8 +38,7 @@ export = new class implements eslint.Rule.RuleModule {
const fileDirname = dirname(context.getFilename());
const parts = fileDirname.split(/\\|\//);
const ruleArgs = <Record<string, string[]>>context.options[0];
const ruleArgs = context.options[0] as Record<string, string[]>;
let config: Config | undefined;
for (let i = parts.length - 1; i >= 0; i--) {
if (ruleArgs[parts[i]]) {
@@ -91,4 +90,3 @@ export = new class implements eslint.Rule.RuleModule {
});
}
};
@@ -6,8 +6,9 @@
import * as eslint from 'eslint';
import { dirname, relative } from 'path';
import minimatch from 'minimatch';
import type * as ESTree from 'estree';
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -28,11 +29,11 @@ export = new class implements eslint.Rule.RuleModule {
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
let fileRelativePath = relative(dirname(__dirname), context.getFilename());
let fileRelativePath = relative(dirname(import.meta.dirname), context.getFilename());
if (!fileRelativePath.endsWith('/')) {
fileRelativePath += '/';
}
const ruleArgs = <Record<string, string[]>>context.options[0];
const ruleArgs = context.options[0] as Record<string, string[]>;
const matchingKey = Object.keys(ruleArgs).find(key => fileRelativePath.startsWith(key) || minimatch(fileRelativePath, key));
if (!matchingKey) {
@@ -43,8 +44,8 @@ export = new class implements eslint.Rule.RuleModule {
const restrictedFunctions = ruleArgs[matchingKey];
return {
FunctionDeclaration: (node: any) => {
const isTopLevel = node.parent.type === 'Program';
FunctionDeclaration: (node: ESTree.FunctionDeclaration & { parent?: ESTree.Node }) => {
const isTopLevel = node.parent?.type === 'Program';
const functionName = node.id.name;
if (isTopLevel && !restrictedFunctions.includes(node.id.name)) {
context.report({
@@ -53,10 +54,10 @@ export = new class implements eslint.Rule.RuleModule {
});
}
},
ExportNamedDeclaration(node: any) {
ExportNamedDeclaration(node: ESTree.ExportNamedDeclaration & { parent?: ESTree.Node }) {
if (node.declaration && node.declaration.type === 'FunctionDeclaration') {
const functionName = node.declaration.id.name;
const isTopLevel = node.parent.type === 'Program';
const isTopLevel = node.parent?.type === 'Program';
if (isTopLevel && !restrictedFunctions.includes(node.declaration.id.name)) {
context.report({
node,
+6 -5
View File
@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
const VALID_USES = new Set<TSESTree.AST_NODE_TYPES | undefined>([
@@ -11,22 +12,22 @@ const VALID_USES = new Set<TSESTree.AST_NODE_TYPES | undefined>([
TSESTree.AST_NODE_TYPES.VariableDeclarator,
]);
export = new class MustUseResults implements eslint.Rule.RuleModule {
export default new class MustUseResults implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
schema: false
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const config = <{ message: string; functions: string[] }[]>context.options[0];
const config = context.options[0] as { message: string; functions: string[] }[];
const listener: eslint.Rule.RuleListener = {};
for (const { message, functions } of config) {
for (const fn of functions) {
const query = `CallExpression[callee.property.name='${fn}'], CallExpression[callee.name='${fn}']`;
listener[query] = (node: any) => {
const cast: TSESTree.CallExpression = node;
if (!VALID_USES.has(cast.parent?.type)) {
listener[query] = (node: ESTree.Node) => {
const callExpression = node as TSESTree.CallExpression;
if (!VALID_USES.has(callExpression.parent?.type)) {
context.report({ node, message });
}
};
@@ -3,18 +3,20 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
export = new class NoAsyncSuite implements eslint.Rule.RuleModule {
export default new class NoAsyncSuite implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
function doesCallSuperDispose(node: any) {
function doesCallSuperDispose(node: TSESTree.MethodDefinition) {
if (!node.override) {
return;
}
const body = context.getSourceCode().getText(node);
const body = context.getSourceCode().getText(node as ESTree.Node);
if (body.includes('super.dispose')) {
return;
+1 -1
View File
@@ -6,7 +6,7 @@
import * as eslint from 'eslint';
import { TSESTree } from '@typescript-eslint/utils';
export = new class NoAnyCasts implements eslint.Rule.RuleModule {
export default new class NoAnyCasts implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
@@ -4,20 +4,16 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
export = new class NoDangerousTypeAssertions implements eslint.Rule.RuleModule {
export default new class NoDangerousTypeAssertions implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
// Disable in tests for now
if (context.getFilename().includes('.test')) {
return {};
}
return {
// Disallow type assertions on object literals: <T>{ ... } or {} as T
['TSTypeAssertion > ObjectExpression, TSAsExpression > ObjectExpression']: (node: any) => {
const objectNode = node as TSESTree.Node;
['TSTypeAssertion > ObjectExpression, TSAsExpression > ObjectExpression']: (node: ESTree.ObjectExpression) => {
const objectNode = node as TSESTree.ObjectExpression;
const parent = objectNode.parent as TSESTree.TSTypeAssertion | TSESTree.TSAsExpression;
if (
@@ -5,9 +5,9 @@
import * as eslint from 'eslint';
import { join, dirname } from 'path';
import { createImportRuleListener } from './utils';
import { createImportRuleListener } from './utils.ts';
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -28,8 +28,8 @@ export = new class implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const patterns = context.options[0] as Record<string, boolean>;
const internalModulePattern = Object.entries(patterns).map(([key, v]) => v ? key : undefined).filter(v => !!v);
const allowedPatterns = Object.entries(patterns).map(([key, v]) => !v ? key : undefined).filter(v => !!v);
const internalModulePattern = Object.entries(patterns).map(([key, v]) => v ? key : undefined).filter((v): v is string => !!v);
const allowedPatterns = Object.entries(patterns).map(([key, v]) => !v ? key : undefined).filter((v): v is string => !!v);
return createImportRuleListener((node, path) => {
const importerModuleDir = dirname(context.filename);
@@ -5,7 +5,7 @@
import * as eslint from 'eslint';
export = new class NoGlobalDocumentListener implements eslint.Rule.RuleModule {
export default new class NoGlobalDocumentListener implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
@@ -0,0 +1,60 @@
/*---------------------------------------------------------------------------------------------
* 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 type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
/**
* Disallows the use of the `in` operator in TypeScript code, except within
* type predicate functions (functions with `arg is Type` return types).
*
* The `in` operator can lead to runtime errors and type safety issues.
* Consider using Object.hasOwn(), hasOwnProperty(), or other safer patterns.
*
* Exception: Type predicate functions are allowed to use the `in` operator
* since they are the standard way to perform runtime type checking.
*/
export default new class NoInOperator implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
noInOperator: 'The "in" operator should not be used. Use type discriminator properties and classes instead or the `hasKey`-utility.',
},
schema: false,
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
function checkInOperator(inNode: ESTree.BinaryExpression) {
const node = inNode as TSESTree.BinaryExpression;
// Check if we're inside a type predicate function
const ancestors = context.sourceCode.getAncestors(node as ESTree.Node);
for (const ancestor of ancestors) {
if (ancestor.type === 'FunctionDeclaration' ||
ancestor.type === 'FunctionExpression' ||
ancestor.type === 'ArrowFunctionExpression') {
// Check if this function has a type predicate return type
// Type predicates have the form: `arg is SomeType`
if ((ancestor as { returnType?: any }).returnType?.typeAnnotation?.type === 'TSTypePredicate') {
// This is a type predicate function, allow the "in" operator
return;
}
}
}
context.report({
node,
messageId: 'noInOperator'
});
}
return {
['BinaryExpression[operator="in"]']: checkInOperator,
};
}
};
@@ -0,0 +1,90 @@
/*---------------------------------------------------------------------------------------------
* 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';
/**
* Prevents the use of template literals in localization function calls.
*
* vscode.l10n.t() and nls.localize() cannot handle string templating.
* Use placeholders instead: vscode.l10n.t('Message {0}', value)
*
* Examples:
* ❌ vscode.l10n.t(`Message ${value}`)
* ✅ vscode.l10n.t('Message {0}', value)
*
* ❌ nls.localize('key', `Message ${value}`)
* ✅ nls.localize('key', 'Message {0}', value)
*/
export default new class NoLocalizationTemplateLiterals implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
noTemplateLiteral: 'Template literals cannot be used in localization calls. Use placeholders like {0}, {1} instead.'
},
docs: {
description: 'Prevents template literals in vscode.l10n.t() and nls.localize() calls',
},
schema: false,
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
function checkCallExpression(node: TSESTree.CallExpression) {
const callee = node.callee;
let isLocalizationCall = false;
let isNlsLocalize = false;
// Check for vscode.l10n.t()
if (callee.type === 'MemberExpression') {
const object = callee.object;
const property = callee.property;
// vscode.l10n.t
if (object.type === 'MemberExpression') {
const outerObject = object.object;
const outerProperty = object.property;
if (outerObject.type === 'Identifier' && outerObject.name === 'vscode' &&
outerProperty.type === 'Identifier' && outerProperty.name === 'l10n' &&
property.type === 'Identifier' && property.name === 't') {
isLocalizationCall = true;
}
}
// l10n.t or nls.localize or any *.localize
if (object.type === 'Identifier' && property.type === 'Identifier') {
if (object.name === 'l10n' && property.name === 't') {
isLocalizationCall = true;
} else if (property.name === 'localize') {
isLocalizationCall = true;
isNlsLocalize = true;
}
}
}
if (!isLocalizationCall) {
return;
}
// For vscode.l10n.t(message, ...args) - check the first argument (message)
// For nls.localize(key, message, ...args) - check first two arguments (key and message)
const argsToCheck = isNlsLocalize ? 2 : 1;
for (let i = 0; i < argsToCheck && i < node.arguments.length; i++) {
const arg = node.arguments[i];
if (arg && arg.type === 'TemplateLiteral' && arg.expressions.length > 0) {
context.report({
node: arg,
messageId: 'noTemplateLiteral'
});
}
}
}
return {
CallExpression: (node: any) => checkCallExpression(node as TSESTree.CallExpression)
};
}
};
@@ -0,0 +1,128 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
import * as visitorKeys from 'eslint-visitor-keys';
import type * as ESTree from 'estree';
const MESSAGE_ID = 'noLocalizedModelDescription';
type NodeWithChildren = TSESTree.Node & {
[key: string]: TSESTree.Node | TSESTree.Node[] | null | undefined;
};
type PropertyKeyNode = TSESTree.Property['key'] | TSESTree.MemberExpression['property'];
type AssignmentTarget = TSESTree.AssignmentExpression['left'];
export default new class NoLocalizedModelDescriptionRule implements eslint.Rule.RuleModule {
meta: eslint.Rule.RuleMetaData = {
messages: {
[MESSAGE_ID]: 'modelDescription values describe behavior to the language model and must not use localized strings.'
},
type: 'problem',
schema: false
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const reportIfLocalized = (expression: TSESTree.Expression | null | undefined) => {
if (expression && containsLocalizedCall(expression)) {
context.report({ node: expression, messageId: MESSAGE_ID });
}
};
return {
Property: (node: ESTree.Property) => {
const propertyNode = node as TSESTree.Property;
if (!isModelDescriptionKey(propertyNode.key, propertyNode.computed)) {
return;
}
reportIfLocalized(propertyNode.value as TSESTree.Expression);
},
AssignmentExpression: (node: ESTree.AssignmentExpression) => {
const assignment = node as TSESTree.AssignmentExpression;
if (!isModelDescriptionAssignmentTarget(assignment.left)) {
return;
}
reportIfLocalized(assignment.right);
}
};
}
};
function isModelDescriptionKey(key: PropertyKeyNode, computed: boolean | undefined): boolean {
if (!computed && key.type === 'Identifier') {
return key.name === 'modelDescription';
}
if (key.type === 'Literal' && key.value === 'modelDescription') {
return true;
}
return false;
}
function isModelDescriptionAssignmentTarget(target: AssignmentTarget): target is TSESTree.MemberExpression {
if (target.type === 'MemberExpression') {
return isModelDescriptionKey(target.property, target.computed);
}
return false;
}
function containsLocalizedCall(expression: TSESTree.Expression): boolean {
let found = false;
const visit = (node: TSESTree.Node) => {
if (found) {
return;
}
if (isLocalizeCall(node)) {
found = true;
return;
}
for (const key of visitorKeys.KEYS[node.type] ?? []) {
const value = (node as NodeWithChildren)[key];
if (Array.isArray(value)) {
for (const child of value) {
if (child) {
visit(child);
if (found) {
return;
}
}
}
} else if (value) {
visit(value);
}
}
};
visit(expression);
return found;
}
function isLocalizeCall(node: TSESTree.Node): boolean {
if (node.type === 'CallExpression') {
return isLocalizeCallee(node.callee);
}
if (node.type === 'ChainExpression') {
return isLocalizeCall(node.expression);
}
return false;
}
function isLocalizeCallee(callee: TSESTree.CallExpression['callee']): boolean {
if (callee.type === 'Identifier') {
return callee.name === 'localize';
}
if (callee.type === 'MemberExpression') {
if (!callee.computed && callee.property.type === 'Identifier') {
return callee.property.name === 'localize';
}
if (callee.property.type === 'Literal' && callee.property.value === 'localize') {
return true;
}
}
return false;
}
@@ -4,8 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
export default new class ApiProviderNaming implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -17,13 +18,13 @@ export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
['PropertyDefinition PrivateIdentifier']: (node: any) => {
['PropertyDefinition PrivateIdentifier']: (node: ESTree.Node) => {
context.report({
node,
messageId: 'slow'
});
},
['MethodDefinition PrivateIdentifier']: (node: any) => {
['MethodDefinition PrivateIdentifier']: (node: ESTree.Node) => {
context.report({
node,
messageId: 'slow'
@@ -5,9 +5,9 @@
import * as eslint from 'eslint';
import { join } from 'path';
import { createImportRuleListener } from './utils';
import { createImportRuleListener } from './utils.ts';
export = new class NoNlsInStandaloneEditorRule implements eslint.Rule.RuleModule {
export default new class NoNlsInStandaloneEditorRule implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -6,9 +6,9 @@
import { TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
import * as visitorKeys from 'eslint-visitor-keys';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
export = new class NoObservableGetInReactiveContext implements eslint.Rule.RuleModule {
export default new class NoObservableGetInReactiveContext implements eslint.Rule.RuleModule {
meta: eslint.Rule.RuleMetaData = {
type: 'problem',
docs: {
@@ -19,7 +19,7 @@ export = new class NoObservableGetInReactiveContext implements eslint.Rule.RuleM
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
'CallExpression': (node: any) => {
'CallExpression': (node: ESTree.CallExpression) => {
const callExpression = node as TSESTree.CallExpression;
if (!isReactiveFunctionWithReader(callExpression.callee)) {
@@ -4,23 +4,24 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
/**
* Checks for potentially unsafe usage of `DisposableStore` / `MutableDisposable`.
*
* These have been the source of leaks in the past.
*/
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
function checkVariableDeclaration(inNode: any) {
function checkVariableDeclaration(inNode: ESTree.Node) {
context.report({
node: inNode,
message: `Use const for 'DisposableStore' to avoid leaks by accidental reassignment.`
});
}
function checkProperty(inNode: any) {
function checkProperty(inNode: ESTree.Node) {
context.report({
node: inNode,
message: `Use readonly for DisposableStore/MutableDisposable to avoid leaks through accidental reassignment.`
@@ -28,10 +29,10 @@ export = new class implements eslint.Rule.RuleModule {
}
return {
'VariableDeclaration[kind!="const"] NewExpression[callee.name="DisposableStore"]': checkVariableDeclaration,
'VariableDeclaration[kind!="const"] > VariableDeclarator > NewExpression[callee.name="DisposableStore"]': checkVariableDeclaration,
'PropertyDefinition[readonly!=true][typeAnnotation.typeAnnotation.typeName.name=/DisposableStore|MutableDisposable/]': checkProperty,
'PropertyDefinition[readonly!=true] NewExpression[callee.name=/DisposableStore|MutableDisposable/]': checkProperty,
'PropertyDefinition[readonly!=true] > NewExpression[callee.name=/DisposableStore|MutableDisposable/]': checkProperty,
};
}
};
@@ -5,11 +5,12 @@
import { TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
export = new class NoReaderAfterAwait implements eslint.Rule.RuleModule {
export default new class NoReaderAfterAwait implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
'CallExpression': (node: any) => {
'CallExpression': (node: ESTree.CallExpression) => {
const callExpression = node as TSESTree.CallExpression;
if (!isFunctionWithReader(callExpression.callee)) {
@@ -7,9 +7,9 @@ import { TSESTree } from '@typescript-eslint/typescript-estree';
import * as eslint from 'eslint';
import { dirname, join, relative } from 'path';
import minimatch from 'minimatch';
import { createImportRuleListener } from './utils';
import { createImportRuleListener } from './utils.ts';
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -30,11 +30,11 @@ export = new class implements eslint.Rule.RuleModule {
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
let fileRelativePath = relative(dirname(__dirname), context.getFilename());
let fileRelativePath = relative(dirname(import.meta.dirname), context.getFilename());
if (!fileRelativePath.endsWith('/')) {
fileRelativePath += '/';
}
const ruleArgs = <Record<string, string[]>>context.options[0];
const ruleArgs = context.options[0] as Record<string, string[]>;
const matchingKey = Object.keys(ruleArgs).find(key => fileRelativePath.startsWith(key) || minimatch(fileRelativePath, key));
if (!matchingKey) {
@@ -5,9 +5,9 @@
import * as eslint from 'eslint';
import { join } from 'path';
import { createImportRuleListener } from './utils';
import { createImportRuleListener } from './utils.ts';
export = new class NoNlsInStandaloneEditorRule implements eslint.Rule.RuleModule {
export default new class NoNlsInStandaloneEditorRule implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -4,20 +4,20 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
/**
* WORKAROUND for https://github.com/evanw/esbuild/issues/3823
*/
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
function checkProperty(inNode: any) {
function checkProperty(inNode: TSESTree.PropertyDefinition) {
const classDeclaration = context.sourceCode.getAncestors(inNode).find(node => node.type === 'ClassDeclaration');
const propertyDefinition = <TSESTree.PropertyDefinition>inNode;
const classDeclaration = context.sourceCode.getAncestors(inNode as ESTree.Node).find(node => node.type === 'ClassDeclaration');
const propertyDefinition = inNode;
if (!classDeclaration || !classDeclaration.id?.name) {
return;
@@ -3,8 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
function isCallExpression(node: TSESTree.Node): node is TSESTree.CallExpression {
return node.type === 'CallExpression';
@@ -14,13 +15,14 @@ function isFunctionExpression(node: TSESTree.Node): node is TSESTree.FunctionExp
return node.type.includes('FunctionExpression');
}
export = new class NoAsyncSuite implements eslint.Rule.RuleModule {
export default new class NoAsyncSuite implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
function hasAsyncSuite(node: any) {
if (isCallExpression(node) && node.arguments.length >= 2 && isFunctionExpression(node.arguments[1]) && node.arguments[1].async) {
function hasAsyncSuite(node: ESTree.Node) {
const tsNode = node as TSESTree.Node;
if (isCallExpression(tsNode) && tsNode.arguments.length >= 2 && isFunctionExpression(tsNode.arguments[1]) && tsNode.arguments[1].async) {
return context.report({
node: node,
node: tsNode,
message: 'suite factory function should never be async'
});
}
+3 -2
View File
@@ -4,12 +4,13 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
export = new class NoTestOnly implements eslint.Rule.RuleModule {
export default new class NoTestOnly implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
['MemberExpression[object.name=/^(test|suite)$/][property.name="only"]']: (node: any) => {
['MemberExpression[object.name=/^(test|suite)$/][property.name="only"]']: (node: ESTree.MemberExpression) => {
return context.report({
node,
message: 'only is a dev-time tool and CANNOT be pushed'
@@ -5,7 +5,7 @@
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
function isStringLiteral(node: TSESTree.Node | ESTree.Node | null | undefined): node is TSESTree.StringLiteral {
return !!node && node.type === AST_NODE_TYPES.Literal && typeof node.value === 'string';
@@ -15,7 +15,16 @@ function isDoubleQuoted(node: TSESTree.StringLiteral): boolean {
return node.raw[0] === '"' && node.raw[node.raw.length - 1] === '"';
}
export = new class NoUnexternalizedStrings implements eslint.Rule.RuleModule {
/**
* Enable bulk fixing double-quoted strings to single-quoted strings with the --fix eslint flag
*
* Disabled by default as this is often not the desired fix. Instead the string should be localized. However it is
* useful for bulk conversations of existing code.
*/
const enableDoubleToSingleQuoteFixes = false;
export default new class NoUnexternalizedStrings implements eslint.Rule.RuleModule {
private static _rNlsKeys = /^[_a-zA-Z0-9][ .\-_a-zA-Z0-9]*$/;
@@ -27,6 +36,7 @@ export = new class NoUnexternalizedStrings implements eslint.Rule.RuleModule {
badMessage: 'Message argument to \'{{message}}\' must be a string literal.'
},
schema: false,
fixable: enableDoubleToSingleQuoteFixes ? 'code' : undefined,
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
@@ -90,9 +100,7 @@ export = new class NoUnexternalizedStrings implements eslint.Rule.RuleModule {
function visitL10NCall(node: TSESTree.CallExpression) {
// localize(key, message)
const [messageNode] = (<TSESTree.CallExpression>node).arguments;
// remove message-argument from doubleQuoted list and make
const [messageNode] = (node as TSESTree.CallExpression).arguments; // remove message-argument from doubleQuoted list and make
// sure it is a string-literal
if (isStringLiteral(messageNode)) {
doubleQuotedStringLiterals.delete(messageNode);
@@ -112,7 +120,30 @@ export = new class NoUnexternalizedStrings implements eslint.Rule.RuleModule {
// (1)
// report all strings that are in double quotes
for (const node of doubleQuotedStringLiterals) {
context.report({ loc: node.loc, messageId: 'doubleQuoted' });
context.report({
loc: node.loc,
messageId: 'doubleQuoted',
fix: enableDoubleToSingleQuoteFixes ? (fixer) => {
// Get the raw string content, unescaping any escaped quotes
const content = (node as ESTree.SimpleLiteral).raw!
.slice(1, -1)
.replace(/(?<!\\)\\'/g, `'`)
.replace(/(?<!\\)\\"/g, `"`);
// If the escaped content contains a single quote, use template string instead
if (content.includes(`'`)
&& !content.includes('${') // Unless the content has a template expressions
&& !content.includes('`') // Or backticks which would need escaping
) {
const templateStr = `\`${content}\``;
return fixer.replaceText(node, templateStr);
}
// Otherwise prefer using a single-quoted string
const singleStr = `'${content.replace(/'/g, `\\'`)}'`;
return fixer.replaceText(node, singleStr);
} : undefined
});
}
for (const [key, values] of externalizedStringLiterals) {
@@ -11,15 +11,15 @@
* @author Michael Ficarra
*/
import * as eslint from 'eslint';
import { TSESTree } from '@typescript-eslint/utils';
import * as ESTree from 'estree';
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
export default {
meta: {
type: 'suggestion',
@@ -58,7 +58,7 @@ module.exports = {
allowTernary = config.allowTernary || false,
allowTaggedTemplates = config.allowTaggedTemplates || false;
/**
* @param node any node
* @returns whether the given node structurally represents a directive
@@ -68,7 +68,7 @@ module.exports = {
node.expression.type === 'Literal' && typeof node.expression.value === 'string';
}
/**
* @param predicate ([a] -> Boolean) the function used to make the determination
* @param list the input list
@@ -83,7 +83,7 @@ module.exports = {
return list.slice();
}
/**
* @param node a Program or BlockStatement node
* @returns the leading sequence of directive nodes in the given node's body
@@ -92,7 +92,7 @@ module.exports = {
return takeWhile(looksLikeDirective, node.body);
}
/**
* @param node any node
* @param ancestors the given node's ancestors
@@ -141,8 +141,8 @@ module.exports = {
return {
ExpressionStatement(node: TSESTree.ExpressionStatement) {
if (!isValidExpression(node.expression) && !isDirective(node, <TSESTree.Node[]>context.sourceCode.getAncestors(node))) {
context.report({ node: <ESTree.Node>node, message: `Expected an assignment or function call and instead saw an expression. ${node.expression}` });
if (!isValidExpression(node.expression) && !isDirective(node, context.sourceCode.getAncestors(node as ESTree.Node) as TSESTree.Node[])) {
context.report({ node: node as ESTree.Node, message: `Expected an assignment or function call and instead saw an expression. ${node.expression}` });
}
}
};
@@ -3,19 +3,18 @@
* 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 eslint from 'eslint';
/**
* Enforces that all parameter properties have an explicit access modifier (public, protected, private).
*
* This catches a common bug where a service is accidentally made public by simply writing: `readonly prop: Foo`
*/
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
function check(inNode: any) {
const node: TSESTree.TSParameterProperty = inNode;
function check(node: TSESTree.TSParameterProperty) {
// For now, only apply to injected services
const firstDecorator = node.decorators?.at(0);
@@ -28,7 +27,7 @@ export = new class implements eslint.Rule.RuleModule {
if (!node.accessibility) {
context.report({
node: inNode,
node: node,
message: 'Parameter properties must have an explicit access modifier.'
});
}
@@ -0,0 +1,146 @@
/*---------------------------------------------------------------------------------------------
* 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 type * as ESTree from 'estree';
/**
* Ensures that localization keys in policy blocks match the keys used in nls.localize() calls.
*
* For example, in a policy block with:
* ```
* localization: {
* description: {
* key: 'autoApprove2.description',
* value: nls.localize('autoApprove2.description', '...')
* }
* }
* ```
*
* The key property ('autoApprove2.description') must match the first argument
* to nls.localize() ('autoApprove2.description').
*/
export default new class PolicyLocalizationKeyMatch implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
mismatch: 'Localization key "{{keyValue}}" does not match the key used in nls.localize("{{localizeKey}}", ...). They must be identical.'
},
docs: {
description: 'Ensures that localization keys in policy blocks match the keys used in nls.localize() calls',
},
schema: false,
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
function checkLocalizationObject(node: ESTree.ObjectExpression) {
// Look for objects with structure: { key: '...', value: nls.localize('...', '...') }
let keyProperty: ESTree.Property | undefined;
let valueProperty: ESTree.Property | undefined;
for (const property of node.properties) {
if (property.type !== 'Property') {
continue;
}
const propertyKey = property.key;
if (propertyKey.type === 'Identifier') {
if (propertyKey.name === 'key') {
keyProperty = property;
} else if (propertyKey.name === 'value') {
valueProperty = property;
}
}
}
if (!keyProperty || !valueProperty) {
return;
}
// Extract the key value (should be a string literal)
let keyValue: string | undefined;
if (keyProperty.value.type === 'Literal' && typeof keyProperty.value.value === 'string') {
keyValue = keyProperty.value.value;
}
if (!keyValue) {
return;
}
// Check if value is a call to localize or any namespace's localize method
if (valueProperty.value.type === 'CallExpression') {
const callee = valueProperty.value.callee;
// Check if it's <anything>.localize or just localize
let isLocalizeCall = false;
if (callee.type === 'MemberExpression') {
const object = callee.object;
const property = callee.property;
if (object.type === 'Identifier' &&
property.type === 'Identifier' && property.name === 'localize') {
isLocalizeCall = true;
}
} else if (callee.type === 'Identifier' && callee.name === 'localize') {
// Direct localize() call
isLocalizeCall = true;
}
if (isLocalizeCall) {
// Get the first argument to localize (the key)
const args = valueProperty.value.arguments;
if (args.length > 0) {
const firstArg = args[0];
if (firstArg.type === 'Literal' && typeof firstArg.value === 'string') {
const localizeKey = firstArg.value;
// Compare the keys
if (keyValue !== localizeKey) {
context.report({
node: keyProperty.value,
messageId: 'mismatch',
data: {
keyValue,
localizeKey
}
});
}
}
}
}
}
}
function isInPolicyBlock(node: ESTree.Node): boolean {
// Walk up the AST to see if we're inside a policy object
const ancestors = context.sourceCode.getAncestors(node);
for (const ancestor of ancestors) {
if (ancestor.type === 'Property') {
// eslint-disable-next-line local/code-no-any-casts
const property = ancestor as any;
if (property.key && property.key.type === 'Identifier' && property.key.name === 'policy') {
return true;
}
}
}
return false;
}
return {
'ObjectExpression': (node: ESTree.ObjectExpression) => {
// Only check objects inside policy blocks
if (!isInPolicyBlock(node)) {
return;
}
// Check if this object has the pattern we're looking for
checkLocalizationObject(node);
}
};
}
};
@@ -6,10 +6,10 @@
import * as eslint from 'eslint';
import { TSESTree } from '@typescript-eslint/utils';
import { readFileSync } from 'fs';
import { createImportRuleListener } from './utils';
import { createImportRuleListener } from './utils.ts';
export = new class TranslationRemind implements eslint.Rule.RuleModule {
export default new class TranslationRemind implements eslint.Rule.RuleModule {
private static NLS_MODULE = 'vs/nls';
-25
View File
@@ -1,25 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// @ts-check
const glob = require('glob');
const path = require('path');
require('ts-node').register({
experimentalResolver: true,
transpileOnly: true,
compilerOptions: {
module: 'nodenext',
moduleResolution: 'nodenext',
}
});
// Re-export all .ts files as rules
/** @type {Record<string, import('@typescript-eslint/utils/dist/ts-eslint').LooseRuleDefinition>} */
const rules = {};
glob.sync(`${__dirname}/*.ts`).forEach((file) => {
rules[path.basename(file, '.ts')] = require(file);
});
exports.rules = rules;
+20
View File
@@ -0,0 +1,20 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import type { LooseRuleDefinition } from '@typescript-eslint/utils/ts-eslint';
import glob from 'glob';
import { createRequire } from 'module';
import path from 'path';
const require = createRequire(import.meta.url);
// Re-export all .ts files as rules
const rules: Record<string, LooseRuleDefinition> = {};
glob.sync(`${import.meta.dirname}/*.ts`)
.filter(file => !file.endsWith('index.ts') && !file.endsWith('utils.ts'))
.map(file => {
rules[path.basename(file, '.ts')] = require(file).default;
});
export { rules };
+5 -1
View File
@@ -1,3 +1,7 @@
{
"type": "commonjs"
"private": true,
"type": "module",
"scripts": {
"typecheck": "tsgo -p tsconfig.json --noEmit"
}
}
+11 -8
View File
@@ -4,23 +4,26 @@
"lib": [
"ES2024"
],
"module": "commonjs",
"esModuleInterop": true,
"alwaysStrict": true,
"allowJs": true,
"rootDir": ".",
"module": "esnext",
"allowImportingTsExtensions": true,
"erasableSyntaxOnly": true,
"noEmit": true,
"strict": true,
"exactOptionalPropertyTypes": false,
"useUnknownInCatchVariables": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"newLine": "lf",
"noEmit": true
"typeRoots": [
"."
]
},
"include": [
"**/*.ts",
"**/*.js"
"./**/*.ts",
],
"exclude": [
"node_modules/**"
"node_modules/**",
"./tests/**"
]
}
+9 -8
View File
@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
export function createImportRuleListener(validateImport: (node: TSESTree.Literal, value: string) => any): eslint.Rule.RuleListener {
@@ -16,24 +17,24 @@ export function createImportRuleListener(validateImport: (node: TSESTree.Literal
return {
// import ??? from 'module'
ImportDeclaration: (node: any) => {
_checkImport((<TSESTree.ImportDeclaration>node).source);
ImportDeclaration: (node: ESTree.ImportDeclaration) => {
_checkImport((node as TSESTree.ImportDeclaration).source);
},
// import('module').then(...) OR await import('module')
['CallExpression[callee.type="Import"][arguments.length=1] > Literal']: (node: any) => {
['CallExpression[callee.type="Import"][arguments.length=1] > Literal']: (node: TSESTree.Literal) => {
_checkImport(node);
},
// import foo = ...
['TSImportEqualsDeclaration > TSExternalModuleReference > Literal']: (node: any) => {
['TSImportEqualsDeclaration > TSExternalModuleReference > Literal']: (node: TSESTree.Literal) => {
_checkImport(node);
},
// export ?? from 'module'
ExportAllDeclaration: (node: any) => {
_checkImport((<TSESTree.ExportAllDeclaration>node).source);
ExportAllDeclaration: (node: ESTree.ExportAllDeclaration) => {
_checkImport((node as TSESTree.ExportAllDeclaration).source);
},
// export {foo} from 'module'
ExportNamedDeclaration: (node: any) => {
_checkImport((<TSESTree.ExportNamedDeclaration>node).source);
ExportNamedDeclaration: (node: ESTree.ExportNamedDeclaration) => {
_checkImport((node as TSESTree.ExportNamedDeclaration).source);
},
};
@@ -3,10 +3,10 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
export default new class ApiProviderNaming implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -18,10 +18,10 @@ export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
['TSInterfaceDeclaration[id.name=/.+Provider/] TSMethodSignature[key.name=/^(provide|resolve).+/]']: (node: any) => {
['TSInterfaceDeclaration[id.name=/.+Provider/] TSMethodSignature[key.name=/^(provide|resolve).+/]']: (node: TSESTree.Node) => {
let found = false;
for (const param of (<TSESTree.TSMethodSignature>node).params) {
for (const param of (node as TSESTree.TSMethodSignature).params) {
if (param.type === AST_NODE_TYPES.Identifier) {
found = found || param.name === 'token';
}
@@ -4,9 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/utils';
export = new class ApiLiteralOrTypes implements eslint.Rule.RuleModule {
export default new class ApiLiteralOrTypes implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#creating-objects' },
@@ -17,9 +18,9 @@ export = new class ApiLiteralOrTypes implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
['TSDeclareFunction Identifier[name=/create.*/]']: (node: any) => {
['TSDeclareFunction Identifier[name=/create.*/]']: (node: ESTree.Node) => {
const decl = <TSESTree.FunctionDeclaration>(<TSESTree.Identifier>node).parent;
const decl = (node as TSESTree.Identifier).parent as TSESTree.FunctionDeclaration;
if (decl.returnType?.typeAnnotation.type !== AST_NODE_TYPES.TSTypeReference) {
return;
@@ -4,9 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/utils';
export = new class ApiEventNaming implements eslint.Rule.RuleModule {
export default new class ApiEventNaming implements eslint.Rule.RuleModule {
private static _nameRegExp = /on(Did|Will)([A-Z][a-z]+)([A-Z][a-z]+)?/;
@@ -25,14 +26,14 @@ export = new class ApiEventNaming implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const config = <{ allowed: string[]; verbs: string[] }>context.options[0];
const config = context.options[0] as { allowed: string[]; verbs: string[] };
const allowed = new Set(config.allowed);
const verbs = new Set(config.verbs);
return {
['TSTypeAnnotation TSTypeReference Identifier[name="Event"]']: (node: any) => {
['TSTypeAnnotation TSTypeReference Identifier[name="Event"]']: (node: ESTree.Identifier) => {
const def = (<TSESTree.Identifier>node).parent?.parent?.parent;
const def = (node as TSESTree.Identifier).parent?.parent?.parent;
const ident = this.getIdent(def);
if (!ident) {
@@ -4,9 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
export = new class ApiInterfaceNaming implements eslint.Rule.RuleModule {
export default new class ApiInterfaceNaming implements eslint.Rule.RuleModule {
private static _nameRegExp = /^I[A-Z]/;
@@ -20,9 +21,9 @@ export = new class ApiInterfaceNaming implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
['TSInterfaceDeclaration Identifier']: (node: any) => {
['TSInterfaceDeclaration Identifier']: (node: ESTree.Identifier) => {
const name = (<TSESTree.Identifier>node).name;
const name = (node as TSESTree.Identifier).name;
if (ApiInterfaceNaming._nameRegExp.test(name)) {
context.report({
node,
@@ -3,10 +3,10 @@
* 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 eslint from 'eslint';
export = new class ApiLiteralOrTypes implements eslint.Rule.RuleModule {
export default new class ApiLiteralOrTypes implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#enums' },
@@ -16,8 +16,8 @@ export = new class ApiLiteralOrTypes implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
['TSTypeAnnotation TSUnionType']: (node: any) => {
if ((<TSESTree.TSUnionType>node).types.every(value => value.type === 'TSLiteralType')) {
['TSTypeAnnotation TSUnionType']: (node: TSESTree.TSUnionType) => {
if (node.types.every(value => value.type === 'TSLiteralType')) {
context.report({
node: node,
messageId: 'useEnum'
@@ -3,10 +3,10 @@
* 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 eslint from 'eslint';
export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
export default new class ApiProviderNaming implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -19,18 +19,18 @@ export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const config = <{ allowed: string[] }>context.options[0];
const config = context.options[0] as { allowed: string[] };
const allowed = new Set(config.allowed);
return {
['TSInterfaceDeclaration[id.name=/.+Provider/] TSMethodSignature']: (node: any) => {
const interfaceName = (<TSESTree.TSInterfaceDeclaration>(<TSESTree.Identifier>node).parent?.parent).id.name;
['TSInterfaceDeclaration[id.name=/.+Provider/] TSMethodSignature']: (node: TSESTree.Node) => {
const interfaceName = ((node as TSESTree.Identifier).parent?.parent as TSESTree.TSInterfaceDeclaration).id.name;
if (allowed.has(interfaceName)) {
// allowed
return;
}
const methodName = ((<TSESTree.TSMethodSignatureNonComputedName>node).key as TSESTree.Identifier).name;
const methodName = ((node as TSESTree.TSMethodSignatureNonComputedName).key as TSESTree.Identifier).name;
if (!ApiProviderNaming._providerFunctionNames.test(methodName)) {
context.report({
@@ -4,9 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
export = new class ApiTypeDiscrimination implements eslint.Rule.RuleModule {
export default new class ApiTypeDiscrimination implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines' },
@@ -18,8 +19,8 @@ export = new class ApiTypeDiscrimination implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
['TSPropertySignature[optional=false] TSTypeAnnotation TSLiteralType Literal']: (node: any) => {
const raw = String((<TSESTree.Literal>node).raw);
['TSPropertySignature[optional=false] TSTypeAnnotation TSLiteralType Literal']: (node: ESTree.Literal) => {
const raw = String((node as TSESTree.Literal).raw);
if (/^('|").*\1$/.test(raw)) {
@@ -5,8 +5,9 @@
import { TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
export = new class VscodeDtsUseExport implements eslint.Rule.RuleModule {
export default new class VscodeDtsUseExport implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -17,8 +18,8 @@ export = new class VscodeDtsUseExport implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
['TSModuleDeclaration :matches(TSInterfaceDeclaration, ClassDeclaration, VariableDeclaration, TSEnumDeclaration, TSTypeAliasDeclaration)']: (node: any) => {
const parent = (<TSESTree.Node>node).parent;
['TSModuleDeclaration :matches(TSInterfaceDeclaration, ClassDeclaration, VariableDeclaration, TSEnumDeclaration, TSTypeAliasDeclaration)']: (node: ESTree.Node) => {
const parent = (node as TSESTree.Node).parent;
if (parent && parent.type !== TSESTree.AST_NODE_TYPES.ExportNamedDeclaration) {
context.report({
node,
@@ -4,8 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
export = new class ApiEventNaming implements eslint.Rule.RuleModule {
export default new class ApiEventNaming implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -19,7 +20,7 @@ export = new class ApiEventNaming implements eslint.Rule.RuleModule {
return {
['TSTypeAnnotation TSTypeReference Identifier[name="Promise"]']: (node: any) => {
['TSTypeAnnotation TSTypeReference Identifier[name="Promise"]']: (node: ESTree.Identifier) => {
context.report({
node,
@@ -4,8 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
export = new class ApiVsCodeInComments implements eslint.Rule.RuleModule {
export default new class ApiVsCodeInComments implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -19,7 +20,7 @@ export = new class ApiVsCodeInComments implements eslint.Rule.RuleModule {
const sourceCode = context.getSourceCode();
return {
['Program']: (_node: any) => {
['Program']: (_node: ESTree.Program) => {
for (const comment of sourceCode.getAllComments()) {
if (comment.type !== 'Block') {
+29
View File
@@ -5,6 +5,7 @@ src/vs/base/common/glob.ts @bpasero
src/vs/base/common/oauth.ts @TylerLeonhardt
src/vs/base/common/path.ts @bpasero
src/vs/base/common/stream.ts @bpasero
src/vs/base/common/uri.ts @jrieken
src/vs/base/browser/domSanitize.ts @mjbvz
src/vs/base/browser/** @bpasero
src/vs/base/node/pfs.ts @bpasero
@@ -40,11 +41,20 @@ src/vs/platform/secrets/** @TylerLeonhardt
src/vs/platform/sharedProcess/** @bpasero
src/vs/platform/state/** @bpasero
src/vs/platform/storage/** @bpasero
src/vs/platform/terminal/electron-main/** @Tyriar
src/vs/platform/terminal/node/** @Tyriar
src/vs/platform/utilityProcess/** @bpasero
src/vs/platform/window/** @bpasero
src/vs/platform/windows/** @bpasero
src/vs/platform/workspace/** @bpasero
src/vs/platform/workspaces/** @bpasero
src/vs/platform/actions/common/menuService.ts @jrieken
src/vs/platform/instantiation/** @jrieken
# Editor Core
src/vs/editor/contrib/snippet/** @jrieken
src/vs/editor/contrib/suggest/** @jrieken
src/vs/editor/contrib/format/** @jrieken
# Bootstrap
src/bootstrap-cli.ts @bpasero
@@ -70,6 +80,7 @@ src/vs/workbench/services/chat/** @bpasero
src/vs/workbench/services/contextmenu/** @bpasero
src/vs/workbench/services/dialogs/** @alexr00 @bpasero
src/vs/workbench/services/editor/** @bpasero
src/vs/workbench/services/editor/common/customEditorLabelService.ts @benibenj
src/vs/workbench/services/environment/** @bpasero
src/vs/workbench/services/files/** @bpasero
src/vs/workbench/services/filesConfiguration/** @bpasero
@@ -102,12 +113,23 @@ src/vs/workbench/contrib/files/** @bpasero
src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @roblourens
src/vs/workbench/contrib/chat/browser/chatSetup.ts @bpasero
src/vs/workbench/contrib/chat/browser/chatStatus.ts @bpasero
src/vs/workbench/contrib/chat/browser/chatInputPart.ts @bpasero
src/vs/workbench/contrib/chat/browser/chatWidget.ts @bpasero
src/vs/workbench/contrib/chat/browser/chatManagement/chatUsageWidget.ts @bpasero
src/vs/workbench/contrib/chat/browser/chatManagement/media/chatUsageWidget.css @bpasero
src/vs/workbench/contrib/chat/browser/agentSessions/** @bpasero
src/vs/workbench/contrib/chat/browser/chatSessions/** @bpasero
src/vs/workbench/contrib/localization/** @TylerLeonhardt
src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts @TylerLeonhardt
src/vs/workbench/contrib/scm/** @lszomoru
src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts @alexr00 @joaomoreno
src/vs/workbench/contrib/preferences/** @rzhao271
# Build
build/azure-pipelines/** @lszomoru
build/lib/i18n.ts @TylerLeonhardt
resources/linux/debian/** @rzhao271
resources/linux/rpm/** @rzhao271
# Editor contrib
src/vs/editor/standalone/browser/quickInput/** @TylerLeonhardt
@@ -125,3 +147,10 @@ src/vs/workbench/api/browser/mainThreadSecretState.ts @TylerLeonhardt
# Extensions
extensions/microsoft-authentication/** @TylerLeonhardt
extensions/github-authentication/** @TylerLeonhardt
extensions/git/** @lszomoru
extensions/git-base/** @lszomoru
extensions/github/** @lszomoru
# Chat Editing, Inline Chat
src/vs/workbench/contrib/chat/browser/chatEditing/** @jrieken
src/vs/workbench/contrib/inlineChat/** @jrieken
+109
View File
@@ -0,0 +1,109 @@
---
name: Demonstrate
description: Agent for demonstrating VS Code features
target: github-copilot
tools: ['edit', 'search', 'vscode-playwright-mcp/*', 'github/github-mcp-server/*', 'usages', 'fetch', 'githubRepo', 'todos']
---
# Role and Objective
You are a QA testing agent. Your task is to explore and demonstrate the UI changes introduced in the current PR branch using vscode-playwright-mcp tools. Your interactions will be recorded and attached to the PR to showcase the changes visually.
# Core Requirements
## Setup Phase
1. Use GitHub MCP tools to get PR details (description, linked issues, comments)
2. Search the `microsoft/vscode-docs` repository for relevant documentation about the feature area
3. Examine changed files and commit messages to understand the scope
4. Identify what UI features or behaviors were modified
5. Start VS Code automation using `vscode_automation_start`
6. ALWAYS start by setting the setting `"chat.allowAnonymousAccess":true` using the `vscode_automation_settings_add_user_settings` tool. This will ensure that Chat works without requiring sign-in.
## Testing Phase
1. Use `browser_snapshot` to capture the current state
2. Execute the user workflows affected by the PR changes
## Demonstration Goals
- Show the new or modified UI in action
- Exercise the changed code paths through realistic user interactions
- Capture clear visual evidence of the improvements or changes
- Test edge cases or variations if applicable
# Important Guidelines
- Focus on DEMONSTRATING the changes, not verifying correctness
- You are NOT writing playwright tests - use the tools interactively to explore
- If the PR description or commits mention specific scenarios, prioritize testing those
- Make multiple passes if needed to capture different aspects of the changes
- You may make temporary modifications to facilitate better demonstration (e.g., adjusting settings, opening specific views)
## GitHub MCP Tools
**Prefer using GitHub MCP tools over `gh` CLI commands** - these provide structured data and better integration:
### Pull Request Tools
- `pull_request_read` - Get PR details, diff, status, files, reviews, and comments
- Use `method="get"` for PR metadata (title, description, labels, etc.)
- Use `method="get_diff"` for the full diff
- Use `method="get_files"` for list of changed files
- Use `method="get_reviews"` for review summaries
- Use `method="get_review_comments"` for line-specific review comments
- `search_pull_requests` - Search PRs with filters (author, state, etc.)
### Issue Tools
- `get_issue` - Get full issue details (description, labels, assignees, etc.)
- `get_issue_comments` - Get all comments on an issue
- `search_issues` - Search issues with filters
- `list_sub_issues` - Get sub-issues if using issue hierarchies
## Pointers for Controlling VS Code
- **Prefer `vscode_automation_*` tools over `browser_*` tools** when available - these are designed specifically for VS Code interactions and provide more reliable control. For example:
- `vscode_automation_chat_send_message` over using `browser_*` tools to send chat messages
- `vscode_automation_editor_type_text` over using `browser_*` tools to type in editors
If you are typing into a monaco input and you can't use the standard methods, follow this sequence:
**Monaco editors (used throughout VS Code) DO NOT work with standard Playwright methods like `.click()` on textareas or `.fill()` / `.type()`**
**YOU MUST follow this exact sequence:**
1. **Take a page snapshot** to identify the editor structure in the accessibility tree
2. **Find the parent `code` role element** that wraps the Monaco editor
- ❌ DO NOT click on `textarea` or `textbox` elements - these are overlaid by Monaco's rendering
- ✅ DO click on the `code` role element that is the parent container
3. **Click on the `code` element** to focus the editor - this properly delegates focus to Monaco's internal text handling
4. **Verify focus** by checking that the nested textbox element has the `[active]` attribute in a new snapshot
5. **Use `page.keyboard.press()` for EACH character individually** - standard Playwright `type()` or `fill()` methods don't work with Monaco editors since they intercept keyboard events at the page level
**Example:**
```js
// ❌ WRONG - this will fail with timeout
await page.locator('textarea').click();
await page.locator('textarea').fill('text');
// ✅ CORRECT
await page.locator('[role="code"]').click();
await page.keyboard.press('t');
await page.keyboard.press('e');
await page.keyboard.press('x');
await page.keyboard.press('t');
```
**Why this is required:** Monaco editors intercept keyboard events at the page level and use a virtualized rendering system. Clicking textareas directly or using `.fill()` bypasses Monaco's event handling, causing timeouts and failures.
# Workflow Pattern
1. Gather context:
- Retrieve PR details using GitHub MCP (description, linked issues, review comments)
- Search microsoft/vscode-docs for documentation on the affected feature areas
- Examine changed files and commit messages
2. Plan which user interactions will best showcase the changes
3. Start automation and navigate to the relevant area
4. Perform the interactions
5. Document what you're demonstrating as you go
6. Ensure the recording clearly shows the before/after or new functionality
7. **ALWAYS stop the automation** by calling `vscode_automation_stop` - this is REQUIRED whether you successfully demonstrated the feature or encountered issues that prevented testing
-35
View File
@@ -1,35 +0,0 @@
---
description: Research and draft an implementation plan
tools: ['executePrompt', 'usages', 'problems', 'githubRepo', 'github.vscode-pull-request-github/activePullRequest', 'search', 'github/github-mcp-server/get_issue', 'github/github-mcp-server/get_issue_comments', 'github/github-mcp-server/get_issue', 'github/github-mcp-server/get_issue_comments', 'fetch']
---
You are pairing with the user to create a clear, detailed, and actionable plan for the given task, iterating through a <workflow> of gathering context and drafting the plan for review.
<workflow>
Comprehensive context gathering for planning following <plan_research>:
1. Context gathering and research:
- MUST run `execute_prompt` tool: Instruct the agent to work autonomously without pausing for user feedback, following <plan_research> to gather context and writing a complete <plan_draft> to return to you.
- If `execute_prompt` tool is NOT available: Run <plan_research> via tools yourself.
2. Present the plan to the user for feedback and refinement:
- Highlights key areas of ambiguity with specific questions and suggestions.
- MANDATORY: Pause for user feedback!
- Handle feedback: Refine the plan after doing further context gathering and research.
</workflow>
<plan_research>
Comprehensive information gathering using read-only tools:
- Examine existing codebase structure, architecture, documentation, and dependencies
- Start with high-level code searches before reading specific files
- Prioritize parallel tool calls for efficiency
- Analyze gaps between current state and desired outcome
- Assess potential integration points and conflicts
</plan_research>
<plan_draft>
- Style:
- Clear, concise, non-repetitive, and high-signal; optimized for quick human review
- Rich in references to specific/related files, symbols, and documentation; while avoiding excessive code snippets
- Tailored to the task and context: Higher complexity requires more detail, higher ambiguity more alternative approaches, etc.
- Briefly summarize problem understanding and proposed technical approach
- Implementation plan broken down into clear, iterative steps as ordered markdown list
- Call out any steps that are too vague or ambiguous to act on
</plan_draft>
+10 -8
View File
@@ -17,6 +17,7 @@
"breadcrumbs": {"assign": ["jrieken"]},
"callhierarchy": {"assign": ["jrieken"]},
"chat-terminal": {"assign": ["Tyriar"]},
"chat-terminal-output-monitor": {"assign": ["meganrogge"]},
"chrome-devtools": {"assign": ["deepak1556"]},
"cloud-changes": {"assign": ["joyceerhl"]},
"code-cli": {"assign": ["connor4312"]},
@@ -112,7 +113,7 @@
"interactive-window": {"assign": ["amunger", "rebornix"]},
"ipc": {"assign": ["joaomoreno"]},
"issue-bot": {"assign": ["chrmarti"]},
"issue-reporter": {"assign": ["justschen"]},
"issue-reporter": {"assign": ["yoyokrazy"]},
"javascript": {"assign": ["mjbvz"]},
"json": {"assign": ["aeschli"]},
"json-sorting": {"assign": ["aiday-mar"]},
@@ -223,33 +224,34 @@
"terminal": {"assign": ["meganrogge"]},
"terminal-accessibility": {"assign": ["meganrogge"]},
"terminal-conpty": {"assign": ["meganrogge"]},
"terminal-editors": {"assign": ["Tyriar", "meganrogge"]},
"terminal-editors": {"assign": ["meganrogge"]},
"terminal-env-collection": {"assign": ["anthonykim1"]},
"terminal-external": {"assign": ["anthonykim1"]},
"terminal-find": {"assign": ["anthonykim1"]},
"terminal-inline-chat": {"assign": ["Tyriar", "meganrogge"]},
"terminal-input": {"assign": ["Tyriar", "meganrogge"]},
"terminal-input": {"assign": ["Tyriar"]},
"terminal-layout": {"assign": ["anthonykim1"]},
"terminal-ligatures": {"assign": ["Tyriar"]},
"terminal-links": {"assign": ["anthonykim1"]},
"terminal-local-echo": {"assign": ["anthonykim1"]},
"terminal-parser": {"assign": ["Tyriar"]},
"terminal-persistence": {"assign": ["Tyriar", "meganrogge"]},
"terminal-process": {"assign": ["Tyriar", "meganrogge"]},
"terminal-persistence": {"assign": ["Tyriar"]},
"terminal-process": {"assign": ["anthonykim1"]},
"terminal-profiles": {"assign": ["meganrogge"]},
"terminal-quick-fix": {"assign": ["meganrogge"]},
"terminal-rendering": {"assign": ["Tyriar"]},
"terminal-search": {"assign": ["Tyriar", "meganrogge"]},
"terminal-shell-bash": {"assign": ["anthonykim1"]},
"terminal-shell-cmd": {"assign": ["anthonykim1"]},
"terminal-shell-fish": {"assign": ["anthonykim1"]},
"terminal-shell-git-bash": {"assign": ["anthonykim1"]},
"terminal-shell-integration": {"assign": ["anthonykim1"]},
"terminal-shell-sh": {"assign": ["anthonykim1"]},
"terminal-shell-pwsh": {"assign": ["anthonykim1"]},
"terminal-shell-sh": {"assign": ["anthonykim1"]},
"terminal-shell-zsh": {"assign": ["anthonykim1"]},
"terminal-sticky-scroll": {"assign": ["anthonykim1"]},
"terminal-suggest": {"assign": ["meganrogge"]},
"terminal-tabs": {"assign": ["meganrogge"]},
"terminal-winpty": {"assign": ["Tyriar", "meganrogge"]},
"terminal-winpty": {"assign": ["anthonykim1"]},
"testing": {"assign": ["connor4312"]},
"themes": {"assign": ["aeschli"]},
"timeline": {"assign": ["lramos15"]},
+19 -2
View File
@@ -632,8 +632,9 @@
"removeLabel": "~capi",
"assign": [
"samvantran",
"thispaul"
]
"sharonlo"
],
"comment": "Thank you for creating this issue! Please provide one or more `requestIds` to help the platform team investigate. You can follow instructions [found here](https://github.com/microsoft/vscode/wiki/Copilot-Issues#language-model-requests-and-responses) to locate the `requestId` value.\n\nHappy Coding!"
},
{
"type": "label",
@@ -653,5 +654,21 @@
],
"action": "updateLabels",
"addLabel": "*edu"
},
{
"type": "label",
"name": "~agent-behavior",
"action": "close",
"reason": "not_planned",
"addLabel": "agent-behavior",
"removeLabel": "~agent-behavior",
"comment": "Unfortunately I think you are hitting a AI quality issue that is not actionable enough for us to track a bug. We would recommend that you try other available models and look at the [Tips and tricks for Copilot in VS Code](https://code.visualstudio.com/docs/copilot/copilot-tips-and-tricks) doc page.\n\nWe are constantly improving AI quality in every release, thank you for the feedback! If you believe this is a technical bug, we recommend you report a new issue including logs described on the [Copilot Issues](https://github.com/microsoft/vscode/wiki/Copilot-Issues) wiki page."
},
{
"type": "label",
"name": "~accessibility-sla",
"addLabel": "accessibility-sla",
"removeLabel": "~accessibility-sla",
"comment": "The Visual Studio and VS Code teams have an agreement with the Accessibility team that 3:1 contrast is enough for inside the editor."
}
]
+5 -5
View File
@@ -48,12 +48,10 @@ Each extension follows the standard VS Code extension structure with `package.js
## Validating TypeScript changes
You MUST check compilation output before running ANY script or declaring work complete!
MANDATORY: Always check the `VS Code - Build` watch task output via #runTasks/getTaskOutput for compilation errors before running ANY script or declaring work complete, then fix all compilation errors before moving forward.
1. **ALWAYS** check the `VS Code - Build` watch task output for compilation errors
2. **NEVER** run tests if there are compilation errors
3. **NEVER** use `npm run compile` to compile TypeScript files, always check task output
4. **FIX** all compilation errors before moving forward
- NEVER run tests if there are compilation errors
- NEVER use `npm run compile` to compile TypeScript files but call #runTasks/getTaskOutput instead
### TypeScript compilation steps
- Monitor the `VS Code - Build` task outputs for real-time compilation errors as you make changes
@@ -134,3 +132,5 @@ function f(x: number, y: string): void { }
- Use `describe` and `test` consistently with existing patterns
- If you create any temporary new files, scripts, or helper files for iteration, clean up these files by removing them at the end of the task
- Do not use `any` or `unknown` as the type for variables, parameters, or return values unless absolutely necessary. If they need type annotations, they should have proper types or interfaces defined.
- Never duplicate imports. Always reuse existing imports if they are present.
- Prefer regex capture groups with names over numbered capture groups.
+50
View File
@@ -0,0 +1,50 @@
---
agent: agent
tools: ['github/github-mcp-server/*', 'microsoft/azure-devops-mcp/*', 'todos']
---
# Role
You are the build champion for the VS Code team. Your task is to triage a {{build}} by following these steps:
# Instructions
1. Display the warning message written below.
2. Investigate the failing jobs of a given {{build}}.
- **Prioritize investigating failing unit test steps first** - these often reveal the root cause of failures
3. Find the most recent {{successful-build}} prior to the failed {{build}}, then identify the {{first-failing-build}} after the {{successful-build}}. Note the commit ids of {{successful-build}} and {{first-failing-build}}.
- Ensure the branch is the same for all builds involved.
4. Using the commit id between the two builds, identify all PRs that were merged in that range.
5. For each PR, analyze the changes to determine if they could have caused the failure.
6. Draft a minimal, succinct, inline-linked message including:
- Build URL
- Failing job URL
- Raw log URL
- GitHub compare view URL in the format: "GitHub Compare View <commit1>...<commit2>"
- List of possible root cause PRs. Ensure the PR numbers are linked to the actual PRs.
7. If no PRs seem to be the cause, suggest rerunning the failed tests and filing an issue on GitHub if the problem persists.
# Variables
- {{build}}: Provided by the user. If the build is provided as a github url, decode the build URL from it.
- {{successful-build}}: The most recent successful build prior to the failed {{build}}.
- {{first-failing-build}}: The first failing build after the {{successful-build}}.
## Guidelines
- Include links to relevant PRs, commits, and builds in your output.
- For now, ignore Component Governance Warnings
- Be minimal in your output, focusing on clarity and conciseness.
## Warning Message
<message>
**⚠️ Known Issues with Build Champion Agent ⚠️**
This agent should be used in parallel while investigating build failures, as it has some known issues:
1. **Double check the error discovered by the agent:** The agent often confuses missing `.build/logs` as an infrastructure issue. This is incorrect, as the missing logs are typically caused by test or build failures.
2. **Pay attention to the build numbers discovered by the agent:** The agent sometimes incorrectly finds the previous successful build.
3. **Double check the list of PRs:** The agent sometimes fails to list all PRs merged between builds. Use the github compare link provided.
**Please update this prompt file as you discover ways it can be improved.**
---
</message>
## Known Scenarios
### Expired Approval Step
If a build appears to have an elapsed time of 30 days, this indicates this build was meant to be a release build, but no one approved the release. There is no action needed in this scenario.
+1 -1
View File
@@ -1,5 +1,5 @@
---
mode: agent
agent: agent
tools: ['edit', 'search', 'runCommands', 'fetch', 'todos']
---
+1 -1
View File
@@ -1,5 +1,5 @@
---
mode: agent
agent: agent
description: 'Help author a component specification for an agent.'
tools: ['edit', 'search', 'usages', 'vscodeAPI', 'fetch', 'extensions', 'todos']
---
+2 -2
View File
@@ -1,7 +1,7 @@
---
mode: agent
agent: agent
description: 'Answer telemetry questions with data queries'
tools: ['runInTerminal', 'search', 'extensions', 'githubRepo', 'todos', 'kusto_query']
tools: ['search', 'runCommands/runInTerminal', 'Azure MCP/kusto_query', 'githubRepo', 'extensions', 'todos']
---
<overview>
+30
View File
@@ -0,0 +1,30 @@
---
agent: agent
description: 'Update doc comments'
tools: ['edit', 'search', 'new', 'runCommands', 'runTasks', 'usages', 'vscodeAPI', 'problems', 'changes', 'testFailure', 'openSimpleBrowser', 'fetch', 'githubRepo', 'extensions', 'todos', 'runTests']
---
# Role
You are an expert technical documentation editor specializing in public API documentation.
## Instructions
Review user's request and update code documentation comments in appropriate locations.
## Guidelines
- **Important** Do not, under any circumstances, change any of the public API naming or signatures.
- **Important** Fetch and review relevant code context (i.e. implementation source code) before making changes or adding comments.
- **Important** Do not use 'VS Code', 'Visual Studio Code' or similar product term anywhere in the comments (this causes lint errors).
- Follow American English grammar, orthography, and punctuation.
- Summary and description comments must use sentences if possible and end with a period.
- Use {@link \<symbol\>} where possible **and reasonable** to refer to code symbols.
- If a @link uses a custom label, keep it - for example: {@link Uri address} - do not remove the 'address' label.
- Use `code` formatting for code elements and keywords in comments, for example: `undefined`.
- Limit the maximum line length of comments to 120 characters.
## Cleanup Mode
If the user instructed you to "clean up" doc comments (e.g. by passing in "cleanup" as their prompt),
it is **very important** that you limit your changes to only fixing grammar, punctuation, formatting, and spelling mistakes.
**YOU MUST NOT** add new or remove or expand existing comments in cleanup mode.
+100
View File
@@ -0,0 +1,100 @@
---
agent: agent
tools: ['github/github-mcp-server/issue_read', 'github/github-mcp-server/list_issues', 'github/github-mcp-server/search_issues', 'runSubagent']
model: Claude Sonnet 4.5 (copilot)
description: 'Describe your issue...'
---
## Role
You are **FindIssue**, a focused GitHub issue investigator for this repository.
Your job is to locate any existing issues that match the user's natural-language description, while making your search process transparent.
## Objective
When the user describes a potential bug, crash, or feature request:
1. Search the repository for similar issues using parallel tool calls when possible
2. Display *every search query* attempted for transparency
3. Return the most relevant issues (open or closed) with short summaries
4. If nothing matches, provide a complete new issue template in a dedicated section
## Context
- Users may not phrase things the same way as existing issues.
- Always prefer **semantic relevance** and **clarity** over keyword quantity.
- Include **open** issues first, but consider **recently closed** ones when relevant.
## Workflow
1. **Interpret Input**
- Summarize the user's request in 1 line (you may restate it as a possible issue title)
- **Identify the specific context and component** (e.g., "chat window UI" vs "prompt file editor" vs "settings page")
- Derive 2 concise search queries using likely keywords or variations (avoid creating too many queries)
2. **Search**
- Run a subAgent that uses parallel tool calls of `github/github-mcp-server/search_issues` with `perPage: 5` and `owner: microsoft`.
- If no results, try variations:
* Remove UI-specific modifiers ("right click", "context menu")
* Substitute action verbs (hide→remove, dismiss→close)
* Remove platform/OS qualifiers
3. **Read & Analyze**
- **First evaluate search results by title, state, and labels only** - often sufficient to determine relevance
- **Only read full issue content** (via `github/github-mcp-server/issue_read`) **for the top 1-2 most promising matches** that you cannot confidently assess from title alone
- **Verify the issue context matches the user's context** - check if the issue is about the same UI component, file type, or workflow step
- Evaluate relevance based on:
* Core concept match (most important)
* Component/context match
* Action/behavior match (user's requested action may differ from issue's proposed solution)
- **If the issue mentions similar features but in a different context, mark it as "related" not "exact match"**
4. **Display Results**
- **First**, list the searches you performed, for transparency:
```
🔍 Searches performed:
- "DataLoader null pointer Windows"
- "NullReferenceException loader crash"
- "Windows DataLoader crash"
```
- **Then**, summarize results in a Markdown table with the following columns: #, Title, State, Relevance, Notes. Use emojis for state (🔓 Open, 🔒 Closed) and relevance (✅ Exact, 🔗 Related). **Important**: Ensure the issue numbers are direct links to the issues.
5. **Conclude**
- Matching context → recommend most relevant issue
- Different context → explain difference and suggest new issue
- Nothing found → suggest title and keywords for new issue
<output_style>
## Style
- Keep explanations short and scannable
- Use Markdown formatting (bullets, tables)
- Go straight to findings—no preamble
</output_style>
## Example
**User:**
> "I get an access violation when I close the app after running the renderer."
**Assistant:**
🔍 **Searches performed:**
- "renderer crash" (core concepts)
- "renderer exit crash" (core + action)
- "access violation renderer shutdown" (original phrasing)
- "renderer close segmentation fault" (synonym variation)
Found 2 similar issues:
| # | Title | State | Relevance | Notes |
|---|--------|--------|-----------|-------|
| #201 | Renderer crash on exit | 🔓 Open | ✅ Exact | Matches shutdown sequence and context |
| #178 | App closes unexpectedly after render | 🔒 Closed | 🔗 Related | Similar timing but fixed in v2.3 |
**You can comment on #201** as it matches your issue.
---
### 📝 Alternative: Suggested New Issue
**Title:**
Renderer access violation on app exit
**Description:**
The application crashes with an access violation error when closing after running the renderer. This occurs consistently during the shutdown sequence and prevents clean application termination.
**Keywords:**
`renderer`, `shutdown`, `access-violation`, `crash`
+2 -2
View File
@@ -1,6 +1,6 @@
---
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']
agent: Plan
tools: ['runCommands', 'runTasks', 'runNotebooks', 'search', 'new', 'usages', 'vscodeAPI', 'problems', 'testFailure', 'openSimpleBrowser', 'fetch', 'githubRepo', 'todos', 'runTests', 'github/get_issue', 'github/get_issue_comments', 'github/get_me', 'github/get_pull_request', 'github/get_pull_request_diff', 'github/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.
+1 -1
View File
@@ -1,5 +1,5 @@
---
mode: agent
agent: agent
description: 'Implement the plan'
tools: ['edit', 'runNotebooks', 'search', 'new', 'runCommands', 'runTasks', 'usages', 'vscodeAPI', 'problems', 'changes', 'testFailure', 'openSimpleBrowser', 'fetch', 'githubRepo', 'extensions', 'todos', 'runTests']
---
+1 -1
View File
@@ -1,5 +1,5 @@
---
mode: agent
agent: agent
description: 'Remove any usage of the any type in TypeScript files'
---
+5 -3
View File
@@ -1,7 +1,9 @@
---
mode: Plan
agent: Plan
description: Clarify before planning in more detail
---
Before doing your research look up related code (max 5 tool calls!) to get a high-level overview, then ask 3 clarifying questions. Once the user answered, go to *Context gathering and research*.
Before doing your research workflow, gather preliminary context using #runSubagent (instructed to use max 5 tool calls) to get a high-level overview.
Be extra detailed in your planning draft.
Then ask 3 clarifying questions and PAUSE for the user to answer them.
AFTER the user has answered, start the <workflow>. Add extra details to your planning draft.
+1 -1
View File
@@ -1,5 +1,5 @@
---
mode: Plan
agent: Plan
description: Iterate quicker on simple tasks
---
Planning for faster iteration: Research as usual, but draft a much more shorter implementation plan that focused on just the main steps
+2 -16
View File
@@ -1,19 +1,5 @@
---
mode: agent
agent: Plan
description: 'Start planning'
tools: ['runNotebooks/getNotebookSummary', 'runNotebooks/readNotebookCellOutput', 'search', 'runCommands/getTerminalOutput', 'runCommands/terminalSelection', 'runCommands/terminalLastCommand', 'github/github-mcp-server/get_issue', 'github/github-mcp-server/get_issue_comments', 'github/github-mcp-server/get_me', 'usages', 'vscodeAPI', 'problems', 'changes', 'testFailure', 'fetch', 'githubRepo', 'todos']
---
Your goal is to prepare a detailed plan to fix the bug or add the new feature, for this you first need to:
* Understand the context of the bug or feature by reading the issue description and comments.
* Understand the codebase by reading the relevant instruction files.
* If its a bug, then identify the root cause of the bug, and explain this to the user.
Based on your above understanding generate a plan to fix the bug or add the new feature.
Ensure the plan consists of a Markdown document that has the following sections:
* Overview: A brief description of the bug/feature.
* Root Cause: A detailed explanation of the root cause of the bug, including any relevant code snippets or references to the codebase. (only if it's a bug)
* Requirements: A list of requirements to resolve the bug or add the new feature.
* Implementation Steps: A detailed list of steps to implement the bug fix or new feature.
Remember, do not make any code edits, just generate a plan. Use thinking and reasoning skills to outline the steps needed to achieve the desired outcome.
Start planning.
-15
View File
@@ -1,15 +0,0 @@
---
mode: agent
description: 'Use playwright & automation tools to _see_ the code changes you have made'
tools: ['codebase', 'usages', 'vscodeAPI', 'problems', 'changes', 'testFailure', 'openSimpleBrowser', 'fetch', 'findTestFiles', 'searchResults', 'githubRepo', 'todos', 'runTests', 'editFiles', 'runNotebooks', 'search', 'new', 'runCommands', 'runTasks', 'vscode-playwright-mcp', 'get_commit', 'get_discussion', 'get_discussion_comments', 'get_issue', 'get_issue_comments']
---
You are being requested to visually confirm the code changes you are making using vscode-playwright-mcp.
You MUST run vscode_automation_start & browser_snapshot.
You MUST verify the bad behavior you are investigating using vscode-playwright-mcp.
You MUST verify the code changes you have made using vscode-playwright-mcp.
You MUST take before and after screenshots.
Remember, you are NOT writing playwright tests; instead, focus on using the tools to validate and explore the changes.
You MAY need to make multiple passes, iterating between making code changes and verifying them with the tools.
You MUST reload the window (`Developer: Reload Window` command) after making changes to ensure they are applied correctly.
You MAY make temporary changes to the code to facilitate testing and exploration. For example, using the quick pick in the Configure Display Language action as a scratch pad to add buttons to it.
+1 -1
View File
@@ -1,5 +1,5 @@
---
mode: agent
agent: agent
description: First Time Setup
tools: ['runCommands', 'runTasks/runTask', 'search', 'todos', 'fetch']
---
@@ -1,5 +1,5 @@
---
mode: agent
agent: agent
---
Read the changes introduced on the current branch, including BOTH:
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
with:
persist-credentials: false
- uses: actions/setup-node@v5
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
+4 -4
View File
@@ -27,7 +27,7 @@ jobs:
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
@@ -212,7 +212,7 @@ jobs:
if: always()
- name: Publish Crash Reports
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
if: failure()
continue-on-error: true
with:
@@ -223,7 +223,7 @@ jobs:
# In order to properly symbolify above crash reports
# (if any), we need the compiled native modules too
- name: Publish Node Modules
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
if: failure()
continue-on-error: true
with:
@@ -232,7 +232,7 @@ jobs:
if-no-files-found: ignore
- name: Publish Log Files
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
if: always()
continue-on-error: true
with:
+4 -4
View File
@@ -27,7 +27,7 @@ jobs:
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
@@ -258,7 +258,7 @@ jobs:
if: always()
- name: Publish Crash Reports
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
if: failure()
continue-on-error: true
with:
@@ -269,7 +269,7 @@ jobs:
# In order to properly symbolify above crash reports
# (if any), we need the compiled native modules too
- name: Publish Node Modules
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
if: failure()
continue-on-error: true
with:
@@ -278,7 +278,7 @@ jobs:
if-no-files-found: ignore
- name: Publish Log Files
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
if: always()
continue-on-error: true
with:
+4 -4
View File
@@ -16,7 +16,7 @@ jobs:
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
@@ -95,7 +95,7 @@ jobs:
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
@@ -167,7 +167,7 @@ jobs:
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
@@ -228,7 +228,7 @@ jobs:
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
+4 -4
View File
@@ -27,7 +27,7 @@ jobs:
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
@@ -249,7 +249,7 @@ jobs:
if: always()
- name: Publish Crash Reports
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
if: failure()
continue-on-error: true
with:
@@ -260,7 +260,7 @@ jobs:
# In order to properly symbolify above crash reports
# (if any), we need the compiled native modules too
- name: Publish Node Modules
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
if: failure()
continue-on-error: true
with:
@@ -269,7 +269,7 @@ jobs:
if-no-files-found: ignore
- name: Publish Log Files
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
if: always()
continue-on-error: true
with:
+2 -2
View File
@@ -24,7 +24,7 @@ jobs:
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
@@ -80,7 +80,7 @@ jobs:
run: .github/workflows/check-clean-git-state.sh
- name: Compile & Hygiene
run: npm exec -- npm-run-all -lp core-ci-pr extensions-ci-pr hygiene eslint valid-layers-check define-class-fields-check vscode-dts-compile-check tsec-compile-check
run: 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 test-build-scripts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
with:
persist-credentials: false
- uses: 'actions/setup-node@v5'
- uses: 'actions/setup-node@v6'
with:
node-version: 'lts/*'
+2 -3
View File
@@ -1,8 +1,7 @@
disturl="https://electronjs.org/headers"
target="37.6.0"
ms_build_id="12506819"
target="39.2.0"
ms_build_id="12791201"
runtime="electron"
build_from_source="true"
legacy-peer-deps="true"
timeout=180000
npm_config_node_gyp="node build/npm/gyp/node_modules/node-gyp/bin/node-gyp.js"
+1 -1
View File
@@ -1 +1 @@
22.19.0
22.20.0
+4
View File
@@ -79,6 +79,10 @@ const extensions = [
workspaceFolder: `extensions/vscode-api-tests/testworkspace.code-workspace`,
mocha: { timeout: 60_000 },
files: 'extensions/vscode-api-tests/out/workspace-tests/**/*.test.js',
},
{
label: 'git-base',
mocha: { timeout: 60_000 }
}
];
@@ -45,7 +45,7 @@ export async function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.tests.registerTestFollowupProvider({
async provideFollowup(_result, test, taskIndex, messageIndex, _token) {
return [{
title: '$(sparkle) Fix with Copilot',
title: '$(sparkle) Fix',
command: 'github.copilot.tests.fixTestFailure',
arguments: [{ source: 'peekFollowup', test, message: test.taskStates[taskIndex].messages[messageIndex] }]
}];
+25 -3
View File
@@ -588,11 +588,33 @@
]
},
{
"name": "Monaco Editor Playground",
"name": "Monaco Editor - Playground",
"type": "chrome",
"request": "launch",
"url": "http://localhost:5001",
"preLaunchTask": "Launch Http Server",
"url": "https://microsoft.github.io/monaco-editor/playground.html?source=http%3A%2F%2Flocalhost%3A5199%2Fbuild%2Fmonaco-editor-playground%2Findex.ts%3Fesm#example-creating-the-editor-hello-world",
"preLaunchTask": "Launch Monaco Editor Vite",
"presentation": {
"group": "monaco",
"order": 4
}
},
{
"name": "Monaco Editor - Self Contained Diff Editor",
"type": "chrome",
"request": "launch",
"url": "http://localhost:5199/build/monaco-editor-playground/index.html",
"preLaunchTask": "Launch Monaco Editor Vite",
"presentation": {
"group": "monaco",
"order": 4
}
},
{
"name": "Monaco Editor - Workbench",
"type": "chrome",
"request": "launch",
"url": "http://localhost:5199/build/monaco-editor-playground/workbench-vite.html",
"preLaunchTask": "Launch Monaco Editor Vite",
"presentation": {
"group": "monaco",
"order": 4
+1 -1
View File
@@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$REPO=repo:microsoft/vscode\n$MILESTONE=milestone:\"September 2025\""
"value": "$REPO=repo:microsoft/vscode\n$MILESTONE=milestone:\"October 2025\""
},
{
"kind": 1,
+1 -1
View File
@@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$MILESTONE=milestone:\"September 2025\""
"value": "$MILESTONE=milestone:\"October 2025\""
},
{
"kind": 1,
+2 -2
View File
@@ -7,12 +7,12 @@
{
"kind": 2,
"language": "github-issues",
"value": "$MILESTONE=milestone:\"September 2025\"\n\n$MINE=assignee:@me"
"value": "$MILESTONE=milestone:\"October 2025\"\n\n$MINE=assignee:@me"
},
{
"kind": 2,
"language": "github-issues",
"value": "$NOT_TEAM_MEMBERS=-author:aeschli -author:alexdima -author:alexr00 -author:AmandaSilver -author:bamurtaugh -author:bpasero -author:chrmarti -author:Chuxel -author:claudiaregio -author:connor4312 -author:dbaeumer -author:deepak1556 -author:devinvalenciano -author:digitarald -author:DonJayamanne -author:egamma -author:fiveisprime -author:ntrogh -author:hediet -author:isidorn -author:joaomoreno -author:jrieken -author:kieferrm -author:lramos15 -author:lszomoru -author:meganrogge -author:misolori -author:mjbvz -author:rebornix -author:roblourens -author:rzhao271 -author:sandy081 -author:sbatten -author:stevencl -author:TylerLeonhardt -author:Tyriar -author:weinand -author:amunger -author:karthiknadig -author:eleanorjboyd -author:Yoyokrazy -author:ulugbekna -author:aiday-mar -author:bhavyaus -author:justschen -author:benibenj -author:luabud -author:anthonykim1 -author:joshspicer -author:osortega -author:hawkticehurst -author:pierceboggan -author:benvillalobos -author:dileepyavan -author:dineshc-msft -author:dmitrivMS -author:eli-w-king -author:jo-oikawa -author:jruales -author:jytjyt05 -author:kycutler -author:mrleemurray -author:pwang347 -author:vijayupadya -author:bryanchen-d"
"value": "$NOT_TEAM_MEMBERS=-author:aeschli -author:alexdima -author:alexr00 -author:AmandaSilver -author:bamurtaugh -author:bpasero -author:chrmarti -author:Chuxel -author:claudiaregio -author:connor4312 -author:dbaeumer -author:deepak1556 -author:devinvalenciano -author:digitarald -author:DonJayamanne -author:egamma -author:fiveisprime -author:ntrogh -author:hediet -author:isidorn -author:joaomoreno -author:jrieken -author:kieferrm -author:lramos15 -author:lszomoru -author:meganrogge -author:misolori -author:mjbvz -author:rebornix -author:roblourens -author:rzhao271 -author:sandy081 -author:sbatten -author:stevencl -author:TylerLeonhardt -author:Tyriar -author:weinand -author:amunger -author:karthiknadig -author:eleanorjboyd -author:Yoyokrazy -author:ulugbekna -author:aiday-mar -author:bhavyaus -author:justschen -author:benibenj -author:luabud -author:anthonykim1 -author:joshspicer -author:osortega -author:hawkticehurst -author:pierceboggan -author:benvillalobos -author:dileepyavan -author:dineshc-msft -author:dmitrivMS -author:eli-w-king -author:jo-oikawa -author:jruales -author:jytjyt05 -author:kycutler -author:mrleemurray -author:pwang347 -author:vijayupadya -author:bryanchen-d -author:cwebster-99"
},
{
"kind": 1,
+1 -1
View File
@@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "// list of repos we work in\n$REPOS=repo:microsoft/lsprotocol repo:microsoft/monaco-editor repo:microsoft/vscode repo:microsoft/vscode-anycode repo:microsoft/vscode-autopep8 repo:microsoft/vscode-black-formatter repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release repo:microsoft/vscode-dev repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-flake8 repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-hexeditor repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-isort repo:microsoft/vscode-js-debug repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-l10n repo:microsoft/vscode-livepreview repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-mypy repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-pylint repo:microsoft/vscode-python repo:microsoft/vscode-python-debugger repo:microsoft/vscode-python-tools-extension-template repo:microsoft/vscode-references-view repo:microsoft/vscode-remote-release repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-unpkg repo:microsoft/vscode-vsce\n\n// current milestone name\n$MILESTONE=milestone:\"September 2025\"\n"
"value": "// list of repos we work in\n$REPOS=repo:microsoft/lsprotocol repo:microsoft/monaco-editor repo:microsoft/vscode repo:microsoft/vscode-anycode repo:microsoft/vscode-autopep8 repo:microsoft/vscode-black-formatter repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release repo:microsoft/vscode-dev repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-flake8 repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-hexeditor repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-isort repo:microsoft/vscode-js-debug repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-l10n repo:microsoft/vscode-livepreview repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-mypy repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-pylint repo:microsoft/vscode-python repo:microsoft/vscode-python-debugger repo:microsoft/vscode-python-tools-extension-template repo:microsoft/vscode-references-view repo:microsoft/vscode-remote-release repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-unpkg repo:microsoft/vscode-vsce\n\n// current milestone name\n$MILESTONE=milestone:\"October 2025\"\n"
},
{
"kind": 1,
+1 -1
View File
@@ -12,7 +12,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$repos=repo:microsoft/lsprotocol repo:microsoft/monaco-editor repo:microsoft/vscode repo:microsoft/vscode-anycode repo:microsoft/vscode-autopep8 repo:microsoft/vscode-black-formatter repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release repo:microsoft/vscode-dev repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-flake8 repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-hexeditor repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-isort repo:microsoft/vscode-js-debug repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-l10n repo:microsoft/vscode-livepreview repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-mypy repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-pylint repo:microsoft/vscode-python repo:microsoft/vscode-python-debugger repo:microsoft/vscode-python-tools-extension-template repo:microsoft/vscode-references-view repo:microsoft/vscode-remote-release repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-unpkg repo:microsoft/vscode-vsce\n$milestone=milestone:\"September 2025\"\n$closedRecently=closed:>2023-09-29"
"value": "$repos=repo:microsoft/lsprotocol repo:microsoft/monaco-editor repo:microsoft/vscode repo:microsoft/vscode-anycode repo:microsoft/vscode-autopep8 repo:microsoft/vscode-black-formatter repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release repo:microsoft/vscode-dev repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-flake8 repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-hexeditor repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-isort repo:microsoft/vscode-js-debug repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-l10n repo:microsoft/vscode-livepreview repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-mypy repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-pylint repo:microsoft/vscode-python repo:microsoft/vscode-python-debugger repo:microsoft/vscode-python-tools-extension-template repo:microsoft/vscode-references-view repo:microsoft/vscode-remote-release repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-unpkg repo:microsoft/vscode-vsce\n$milestone=milestone:\"October 2025\"\n$closedRecently=closed:>2023-09-29"
},
{
"kind": 1,
+1 -1
View File
@@ -2,7 +2,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$milestone=milestone:\"September 2025\""
"value": "$milestone=milestone:\"October 2025\""
},
{
"kind": 1,
File diff suppressed because it is too large Load Diff
+4 -16
View File
@@ -1,6 +1,6 @@
{
// --- Chat ---
// "inlineChat.enableV2": true,
"inlineChat.enableV2": true,
"chat.tools.terminal.autoApprove": {
"/^npm (test|lint|run compile)\\b/": true,
"/^npx tsc\\b.*--noEmit/": true,
@@ -9,7 +9,6 @@
"scripts/test-integration.bat": true,
"scripts/test-integration.sh": true,
},
// --- Editor ---
"editor.insertSpaces": false,
"editor.experimental.asyncTokenization": true,
@@ -18,7 +17,6 @@
// "editor.experimental.preferTreeSitter.typescript": true,
// "editor.experimental.preferTreeSitter.regex": true,
// "editor.experimental.preferTreeSitter.css": true,
// --- Language Specific ---
"[plaintext]": {
"files.insertFinalNewline": false
@@ -38,7 +36,6 @@
"[github-issues]": {
"editor.wordWrap": "on"
},
// --- Files ---
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
@@ -81,7 +78,6 @@
"build/npm/*.js": true,
"build/*.js": true
},
// --- Search ---
"search.exclude": {
"**/node_modules": true,
@@ -104,7 +100,6 @@
"build/loader.min": true,
"**/*.snap": true,
},
// --- TypeScript ---
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.preferences.importModuleSpecifier": "relative",
@@ -117,7 +112,6 @@
"vscode-notebook-renderer",
"src/vs/workbench/workbench.web.main.internal.ts"
],
// --- Languages ---
"json.schemas": [
{
@@ -134,7 +128,6 @@
}
],
"css.format.spaceAroundSelectorSeparator": true,
// --- Git ---
"git.ignoreLimitWarning": true,
"git.branchProtection": [
@@ -152,7 +145,6 @@
"ts": "warning",
"eslint": "warning"
},
// --- GitHub ---
"githubPullRequests.experimental.createView": true,
"githubPullRequests.assignCreated": "${user}",
@@ -162,7 +154,6 @@
],
"githubPullRequests.codingAgent.enabled": true,
"githubPullRequests.codingAgent.uiIntegration": true,
// --- Testing & Debugging ---
"testing.autoRun.mode": "rerun",
"debug.javascript.terminalOptions": {
@@ -176,7 +167,6 @@
"${workspaceFolder}/extensions/*/out/**/*.js",
]
},
// --- Coverage ---
"lcov.path": [
"./.build/coverage/lcov.info",
@@ -191,7 +181,6 @@
}
}
],
// --- Tools ---
"npm.exclude": "**/extensions/**",
"eslint.useFlatConfig": true,
@@ -210,13 +199,10 @@
"git",
"sash"
],
// --- Workbench ---
// "application.experimental.rendererProfiling": true, // https://github.com/microsoft/vscode/issues/265654
"editor.aiStats.enabled": true, // Team selfhosting on ai stats
"chat.emptyState.history.enabled": true,
"github.copilot.chat.advanced.taskTools.enabled": true,
"chat.promptFilesRecommendations": {
"plan-fast": true,
"plan-deep": true
@@ -226,5 +212,7 @@
"kusto"
],
"azureMcp.serverMode": "all",
"azureMcp.readOnly": true
"azureMcp.readOnly": true,
"chat.tools.terminal.outputLocation": "none",
"chat.agentSessionsViewLocation": "single-view"
}
+6 -6
View File
@@ -279,9 +279,12 @@
"detail": "node_modules/tsec/bin/tsec -p src/tsconfig.json --noEmit"
},
{
"label": "Launch Http Server",
"label": "Launch Monaco Editor Vite",
"type": "shell",
"command": "node_modules/.bin/ts-node -T ./scripts/playground-server",
"command": "npm run dev",
"options": {
"cwd": "./build/monaco-editor-playground/"
},
"isBackground": true,
"problemMatcher": {
"pattern": {
@@ -292,10 +295,7 @@
"beginsPattern": "never match",
"endsPattern": ".*"
}
},
"dependsOn": [
"Core - Build"
]
}
},
{
"label": "Launch MCP Server",
+1 -1
View File
@@ -54,7 +54,7 @@ Many of the core components and extensions to VS Code live in their own reposito
## Bundled Extensions
VS Code includes a set of built-in extensions located in the [extensions](extensions) folder, including grammars and snippets for many languages. Extensions that provide rich language support (code completion, Go to Definition) for a language have the suffix `language-features`. For example, the `json` extension provides coloring for `JSON` and the `json-language-features` extension provides rich language support for `JSON`.
VS Code includes a set of built-in extensions located in the [extensions](extensions) folder, including grammars and snippets for many languages. Extensions that provide rich language support (inline suggestions, Go to Definition) for a language have the suffix `language-features`. For example, the `json` extension provides coloring for `JSON` and the `json-language-features` extension provides rich language support for `JSON`.
## Development Container
+27 -573
View File
@@ -524,576 +524,30 @@ Title to copyright in this work will at all times remain with copyright holders.
---------------------------------------------------------
dompurify 3.1.7 - Apache 2.0
https://github.com/cure53/DOMPurify
DOMPurify
Copyright 2025 Dr.-Ing. Mario Heiderich, Cure53
DOMPurify is free software; you can redistribute it and/or modify it under the
terms of either:
a) the Apache License Version 2.0, or
b) the Mozilla Public License Version 2.0
-----------------------------------------------------------------------------
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-----------------------------------------------------------------------------
Mozilla Public License, version 2.0
1. Definitions
1.1. "Contributor"
means each individual or legal entity that creates, contributes to the
creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used by a
Contributor and that particular Contributors Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached the
notice in Exhibit A, the Executable Form of such Source Code Form, and
Modifications of such Source Code Form, in each case including portions
thereof.
1.5. "Incompatible With Secondary Licenses"
means
a. that the initial Contributor has attached the notice described in
Exhibit B to the Covered Software; or
b. that the Covered Software was made available under the terms of version
1.1 or earlier of the License, but not also under the terms of a
Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in a separate
file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible, whether at the
time of the initial grant or subsequently, any and all of the rights conveyed by
this License.
1.10. "Modifications"
means any of the following:
a. any file in Source Code Form that results from an addition to, deletion
from, or modification of the contents of Covered Software; or
b. any new file in Source Code Form that contains any Covered Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method, process,
and apparatus claims, in any patent Licensable by such Contributor that
would be infringed, but for the grant of the License, by the making,
using, selling, offering for sale, having made, import, or transfer of
either its Contributions or its Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU Lesser
General Public License, Version 2.1, the GNU Affero General Public
License, Version 3.0, or any later versions of those licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that controls, is
controlled by, or is under common control with You. For purposes of this
definition, "control" means (a) the power, direct or indirect, to cause
the direction or management of such entity, whether by contract or
otherwise, or (b) ownership of more than fifty percent (50%) of the
outstanding shares or beneficial ownership of such entity.
2. License Grants and Conditions
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
a. under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or as
part of a Larger Work; and
b. under Patent Claims of such Contributor to make, use, sell, offer for
sale, have made, import, and otherwise transfer either its Contributions
or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution become
effective for each Contribution on the date the Contributor first distributes
such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under this
License. No additional rights or licenses will be implied from the distribution
or licensing of Covered Software under this License. Notwithstanding Section
2.1(b) above, no patent license is granted by a Contributor:
a. for any code that a Contributor has removed from Covered Software; or
b. for infringements caused by: (i) Your and any other third partys
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
c. under Patent Claims infringed by Covered Software in the absence of its
Contributions.
This License does not grant any rights in the trademarks, service marks, or
logos of any Contributor (except as may be necessary to comply with the
notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this License
(see Section 10.2) or under the terms of a Secondary License (if permitted
under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its Contributions
are its original creation(s) or it has sufficient rights to grant the
rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under applicable
copyright doctrines of fair use, fair dealing, or other equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
Section 2.1.
3. Responsibilities
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under the
terms of this License. You must inform recipients that the Source Code Form
of the Covered Software is governed by the terms of this License, and how
they can obtain a copy of this License. You may not attempt to alter or
restrict the recipients rights in the Source Code Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
a. such Covered Software must also be made available in Source Code Form,
as described in Section 3.1, and You must inform recipients of the
Executable Form how they can obtain a copy of such Source Code Form by
reasonable means in a timely manner, at a charge no more than the cost
of distribution to the recipient; and
b. You may distribute such Executable Form under the terms of this License,
or sublicense it under different terms, provided that the license for
the Executable Form does not attempt to limit or alter the recipients
rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for the
Covered Software. If the Larger Work is a combination of Covered Software
with a work governed by one or more Secondary Licenses, and the Covered
Software is not Incompatible With Secondary Licenses, this License permits
You to additionally distribute such Covered Software under the terms of
such Secondary License(s), so that the recipient of the Larger Work may, at
their option, further distribute the Covered Software under the terms of
either this License or such Secondary License(s).
3.4. Notices
You may not remove or alter the substance of any license notices (including
copyright notices, patent notices, disclaimers of warranty, or limitations
of liability) contained within the Source Code Form of the Covered
Software, except that You may alter any license notices to the extent
required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on behalf
of any Contributor. You must make it absolutely clear that any such
warranty, support, indemnity, or liability obligation is offered by You
alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
If it is impossible for You to comply with any of the terms of this License
with respect to some or all of the Covered Software due to statute, judicial
order, or regulation then You must: (a) comply with the terms of this License
to the maximum extent possible; and (b) describe the limitations and the code
they affect. Such description must be placed in a text file included with all
distributions of the Covered Software under this License. Except to the
extent prohibited by statute or regulation, such description must be
sufficiently detailed for a recipient of ordinary skill to be able to
understand it.
5. Termination
5.1. The rights granted under this License will terminate automatically if You
fail to comply with any of its terms. However, if You become compliant,
then the rights granted under this License from a particular Contributor
are reinstated (a) provisionally, unless and until such Contributor
explicitly and finally terminates Your grants, and (b) on an ongoing basis,
if such Contributor fails to notify You of the non-compliance by some
reasonable means prior to 60 days after You have come back into compliance.
Moreover, Your grants from a particular Contributor are reinstated on an
ongoing basis if such Contributor notifies You of the non-compliance by
some reasonable means, this is the first time You have received notice of
non-compliance with this License from such Contributor, and You become
compliant prior to 30 days after Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions, counter-claims,
and cross-claims) alleging that a Contributor Version directly or
indirectly infringes any patent, then the rights granted to You by any and
all Contributors for the Covered Software under Section 2.1 of this License
shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
license agreements (excluding distributors and resellers) which have been
validly granted by You or Your distributors under this License prior to
termination shall survive termination.
6. Disclaimer of Warranty
Covered Software is provided under this License on an "as is" basis, without
warranty of any kind, either expressed, implied, or statutory, including,
without limitation, warranties that the Covered Software is free of defects,
merchantable, fit for a particular purpose or non-infringing. The entire
risk as to the quality and performance of the Covered Software is with You.
Should any Covered Software prove defective in any respect, You (not any
Contributor) assume the cost of any necessary servicing, repair, or
correction. This disclaimer of warranty constitutes an essential part of this
License. No use of any Covered Software is authorized under this License
except under this disclaimer.
7. Limitation of Liability
Under no circumstances and under no legal theory, whether tort (including
negligence), contract, or otherwise, shall any Contributor, or anyone who
distributes Covered Software as permitted above, be liable to You for any
direct, indirect, special, incidental, or consequential damages of any
character including, without limitation, damages for lost profits, loss of
goodwill, work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses, even if such party shall have been
informed of the possibility of such damages. This limitation of liability
shall not apply to liability for death or personal injury resulting from such
partys negligence to the extent applicable law prohibits such limitation.
Some jurisdictions do not allow the exclusion or limitation of incidental or
consequential damages, so this exclusion and limitation may not apply to You.
8. Litigation
Any litigation relating to this License may be brought only in the courts of
a jurisdiction where the defendant maintains its principal place of business
and such litigation shall be governed by laws of that jurisdiction, without
reference to its conflict-of-law provisions. Nothing in this Section shall
prevent a partys ability to bring cross-claims or counter-claims.
9. Miscellaneous
This License represents the complete agreement concerning the subject matter
hereof. If any provision of this License is held to be unenforceable, such
provision shall be reformed only to the extent necessary to make it
enforceable. Any law or regulation which provides that the language of a
contract shall be construed against the drafter shall not be used to construe
this License against a Contributor.
10. Versions of the License
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version of
the License under which You originally received the Covered Software, or
under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a modified
version of this License if you rename the license and remove any
references to the name of the license steward (except to note that such
modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file, then
You may include the notice in a location (such as a LICENSE file in a relevant
directory) where a recipient would be likely to look for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
This Source Code Form is "Incompatible
With Secondary Licenses", as defined by
the Mozilla Public License, v. 2.0.
dotenv-org/dotenv-vscode 0.26.0 - MIT License
https://github.com/dotenv-org/dotenv-vscode
MIT License
Copyright (c) 2022 Scott Motte
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---------------------------------------------------------
---------------------------------------------------------
@@ -1546,7 +1000,7 @@ SOFTWARE.
---------------------------------------------------------
jlelong/vscode-latex-basics 1.14.0 - MIT
jlelong/vscode-latex-basics 1.15.0 - MIT
https://github.com/jlelong/vscode-latex-basics
Copyright (c) vscode-latex-basics authors
@@ -1662,7 +1116,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SO
---------------------------------------------------------
language-docker 0.0.0 - Apache-2.0
language-docker 28.3.3 - Apache-2.0
https://github.com/moby/moby
Apache License
@@ -2823,7 +2277,7 @@ written authorization of the copyright holder.
---------------------------------------------------------
vscode-codicons 0.0.14 - MIT and Creative Commons Attribution 4.0
vscode-codicons 0.0.41 - MIT and Creative Commons Attribution 4.0
https://github.com/microsoft/vscode-codicons
Attribution 4.0 International
+1 -1
View File
@@ -1 +1 @@
2025-07-23T19:44:03.051Z
2025-11-13T05:15:29.922Z
+1
View File
@@ -1 +1,2 @@
*.js.map
lib/policies/policyDto.*
+2
View File
@@ -60,6 +60,8 @@ fsevents/test/**
!@vscode/tree-sitter-wasm/wasm/tree-sitter-regex.wasm
!@vscode/tree-sitter-wasm/wasm/tree-sitter-ini.wasm
!@vscode/tree-sitter-wasm/wasm/tree-sitter-css.wasm
!@vscode/tree-sitter-wasm/wasm/tree-sitter-powershell.wasm
!@vscode/tree-sitter-wasm/wasm/tree-sitter-bash.wasm
native-keymap/binding.gyp
native-keymap/build/**
@@ -34,6 +34,9 @@ jobs:
versionSource: fromFile
versionFilePath: .nvmrc
- ${{ if eq(parameters.VSCODE_QUALITY, 'insider') }}:
- template: ../common/bump-insiders-version.yml@self
- template: ../cli/cli-apply-patches.yml@self
- script: |
@@ -1,4 +1,6 @@
parameters:
- name: VSCODE_QUALITY
type: string
- name: VSCODE_ARCH
type: string
@@ -55,6 +57,9 @@ jobs:
versionSource: fromFile
versionFilePath: .nvmrc
- ${{ if eq(parameters.VSCODE_QUALITY, 'insider') }}:
- template: ../common/bump-insiders-version.yml@self
- template: ../distro/download-distro.yml@self
- task: AzureKeyVault@2
@@ -0,0 +1,23 @@
steps:
- script: |
set -e
BUILD_NAME="$(Build.BuildNumber)" # example "20251114.34 (insider)"
VSCODE_PATCH_VERSION="$(echo $BUILD_NAME | cut -d' ' -f1 | awk -F. '{printf "%s%03d", $1, $2}')"
VSCODE_MAJOR_MINOR_VERSION="$(node -p "require('./package.json').version.replace(/\.\d+$/, '')")"
VSCODE_INSIDERS_VERSION="${VSCODE_MAJOR_MINOR_VERSION}.${VSCODE_PATCH_VERSION}"
echo "Setting Insiders version to: $VSCODE_INSIDERS_VERSION"
node -e "require('fs').writeFileSync('package.json', JSON.stringify({...require('./package.json'), version: process.argv[1]}, null, 2))" $VSCODE_INSIDERS_VERSION
displayName: Override Insiders Version
condition: and(succeeded(), not(contains(variables['Agent.OS'], 'windows')))
- pwsh: |
$ErrorActionPreference = "Stop"
$buildName = "$(Build.BuildNumber)" # example "20251114.34 (insider)"
$buildParts = ($buildName -split ' ')[0] -split '\.'
$patchVersion = "{0}{1:000}" -f $buildParts[0], [int]$buildParts[1]
$majorMinorVersion = node -p "require('./package.json').version.replace(/\.\d+$/, '')"
$insidersVersion = "$majorMinorVersion.$patchVersion"
Write-Host "Setting Insiders version to: $insidersVersion"
node -e "require('fs').writeFileSync('package.json', JSON.stringify({...require('./package.json'), version: process.argv[1]}, null, 2))" $insidersVersion
displayName: Override Insiders Version
condition: and(succeeded(), contains(variables['Agent.OS'], 'windows'))
@@ -1,9 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const publish_1 = require("./publish");
const retry_1 = require("./retry");
async function getPipelineArtifacts() {
+4 -4
View File
@@ -1,12 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.printBanner = printBanner;
exports.streamProcessOutputAndCheckResult = streamProcessOutputAndCheckResult;
exports.spawnCodesignProcess = spawnCodesignProcess;
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.printBanner = printBanner;
exports.streamProcessOutputAndCheckResult = streamProcessOutputAndCheckResult;
exports.spawnCodesignProcess = spawnCodesignProcess;
const zx_1 = require("zx");
function printBanner(title) {
title = `${title} (${new Date().toISOString()})`;

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