eslint: fix bracket notation in language extensions (#334771)

* eslint: enable no bracket notation rule

Enable code-no-bracket-notation-for-identifiers for JavaScript and TypeScript files while grandfathering the 509 files with existing violations in a CODEOWNERS-gated allowlist.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* eslint: update bracket allowlist owners

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* eslint: group bracket notation exclusions

Organize the existing baseline by feature area so cleanup can be tracked and assigned without changing the excluded file set.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* eslint: test no bracket notation rule

Add RuleTester coverage for valid accesses, diagnostics, and autofix edge cases. Preserve escaped string-literal property names by checking their raw source before reporting.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* eslint: fix bracket notation in language extensions

Replace identifier-safe bracket notation across language feature extensions and remove the completed group from the temporary allowlist.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Dmitriy Vasyura
2026-09-12 20:47:46 +00:00
committed by GitHub
co-authored by Copilot
parent b0240f6065
commit 3879d0e80f
17 changed files with 56 additions and 80 deletions
-24
View File
@@ -476,30 +476,6 @@ src/vs/platform/webContentExtractor/test/electron-main/webPageLoader.test.ts
src/vs/workbench/contrib/remote/browser/remoteStartEntry.ts
src/vs/workbench/contrib/remoteTunnel/test/electron-browser/remoteTunnel.contribution.test.ts
# Language feature extensions (22 files)
extensions/css-language-features/client/src/node/cssClientMain.ts
extensions/css-language-features/server/src/cssServer.ts
extensions/css-language-features/server/src/node/cssServerNodeMain.ts
extensions/emmet/src/abbreviationActions.ts
extensions/emmet/src/defaultCompletionProvider.ts
extensions/emmet/src/splitJoinTag.ts
extensions/emmet/src/util.ts
extensions/html-language-features/client/src/autoInsertion.ts
extensions/html-language-features/client/src/node/htmlClientMain.ts
extensions/html-language-features/server/src/modes/languageModes.ts
extensions/html-language-features/server/src/node/htmlServerNodeMain.ts
extensions/json-language-features/client/src/node/jsonClientMain.ts
extensions/json-language-features/server/src/node/jsonServerNodeMain.ts
extensions/markdown-language-features/src/extension.ts
extensions/markdown-language-features/src/languageFeatures/copyFiles/copyFiles.ts
extensions/markdown-language-features/src/languageFeatures/copyFiles/snippets.ts
extensions/markdown-language-features/src/markdownEngine.ts
extensions/merge-conflict/src/mergeDecorator.ts
extensions/typescript-language-features/src/logging/telemetry.ts
extensions/typescript-language-features/src/tsServer/serverProcess.electron.ts
extensions/typescript-language-features/src/typescriptServiceClient.ts
extensions/typescript-language-features/src/utils/platform.ts
# Git extension (6 files)
extensions/git/src/askpass-main.ts
extensions/git/src/askpassManager.ts
@@ -142,7 +142,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment)
let service = languageServices[document.languageId];
if (!service) {
connection.console.log('Document type is ' + document.languageId + ', using css instead.');
service = languageServices['css'];
service = languageServices.css;
}
return service;
}
+14 -14
View File
@@ -38,8 +38,8 @@ export async function wrapWithAbbreviation(args: any): Promise<boolean> {
const document = editor.document;
args = args || {};
if (!args['language']) {
args['language'] = document.languageId;
if (!args.language) {
args.language = document.languageId;
}
// we know it's not stylesheet due to the validate(false) call above
const syntax = getSyntaxFromArgs(args) || 'html';
@@ -249,8 +249,8 @@ export async function wrapWithAbbreviation(args: any): Promise<boolean> {
}
const prompt = vscode.l10n.t("Enter Abbreviation");
const inputAbbreviation = (args && args['abbreviation'])
? (args['abbreviation'] as string)
const inputAbbreviation = (args && args.abbreviation)
? (args.abbreviation as string)
: await vscode.window.showInputBox({ prompt, validateInput: inputChanged });
const changesWereMade = await makeChanges(inputAbbreviation, false);
@@ -285,10 +285,10 @@ export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined
}
args = args || {};
if (!args['language']) {
args['language'] = vscode.window.activeTextEditor.document.languageId;
if (!args.language) {
args.language = vscode.window.activeTextEditor.document.languageId;
} else {
const excludedLanguages = vscode.workspace.getConfiguration('emmet')['excludeLanguages'] ? vscode.workspace.getConfiguration('emmet')['excludeLanguages'] : [];
const excludedLanguages = vscode.workspace.getConfiguration('emmet').excludeLanguages ? vscode.workspace.getConfiguration('emmet').excludeLanguages : [];
if (excludedLanguages.includes(vscode.window.activeTextEditor.document.languageId)) {
return fallbackTab();
}
@@ -301,7 +301,7 @@ export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined
const editor = vscode.window.activeTextEditor;
// When tabbed on a non empty selection, do not treat it as an emmet abbreviation, and fallback to tab instead
if (vscode.workspace.getConfiguration('emmet')['triggerExpansionOnTab'] === true && editor.selections.find(x => !x.isEmpty)) {
if (vscode.workspace.getConfiguration('emmet').triggerExpansionOnTab === true && editor.selections.find(x => !x.isEmpty)) {
return fallbackTab();
}
@@ -357,7 +357,7 @@ export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined
return rootNode;
}
const usePartialParsing = vscode.workspace.getConfiguration('emmet')['optimizeStylesheetParsing'] === true;
const usePartialParsing = vscode.workspace.getConfiguration('emmet').optimizeStylesheetParsing === true;
if (editor.selections.length === 1 && isStyleSheet(editor.document.languageId) && usePartialParsing && editor.document.lineCount > 1000) {
rootNode = parsePartialStylesheet(editor.document, editor.selection.isReversed ? editor.selection.anchor : editor.selection.active);
} else {
@@ -418,7 +418,7 @@ export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined
}
function fallbackTab(): Thenable<boolean | undefined> {
if (vscode.workspace.getConfiguration('emmet')['triggerExpansionOnTab'] === true) {
if (vscode.workspace.getConfiguration('emmet').triggerExpansionOnTab === true) {
return vscode.commands.executeCommand('tab');
}
return Promise.resolve(true);
@@ -670,7 +670,7 @@ function expandAbbr(input: ExpandAbbreviationInput): string | undefined {
return line.replace(trimRegex, '').trim();
});
}
expandOptions['text'] = input.textToWrap;
expandOptions.text = input.textToWrap;
if (expandOptions.options) {
// Below fixes https://github.com/microsoft/vscode/issues/29898
@@ -701,9 +701,9 @@ function expandAbbr(input: ExpandAbbreviationInput): string | undefined {
export function getSyntaxFromArgs(args: { [x: string]: string }): string | undefined {
const mappedModes = getMappingForIncludedLanguages();
const language: string = args['language'];
const parentMode: string = args['parentMode'];
const excludedLanguages = vscode.workspace.getConfiguration('emmet')['excludeLanguages'] ? vscode.workspace.getConfiguration('emmet')['excludeLanguages'] : [];
const language: string = args.language;
const parentMode: string = args.parentMode;
const excludedLanguages = vscode.workspace.getConfiguration('emmet').excludeLanguages ? vscode.workspace.getConfiguration('emmet').excludeLanguages : [];
if (excludedLanguages.includes(language)) {
return;
}
@@ -42,7 +42,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
private provideCompletionItemsInternal(document: vscode.TextDocument, position: vscode.Position, context: vscode.CompletionContext): Thenable<vscode.CompletionList | undefined> | undefined {
const emmetConfig = vscode.workspace.getConfiguration('emmet');
const excludedLanguages = emmetConfig['excludeLanguages'] ? emmetConfig['excludeLanguages'] : [];
const excludedLanguages = emmetConfig.excludeLanguages ? emmetConfig.excludeLanguages : [];
if (excludedLanguages.includes(document.languageId)) {
return;
}
@@ -52,8 +52,8 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
const emmetMode = getEmmetMode((isSyntaxMapped ? mappedLanguages[document.languageId] : document.languageId), mappedLanguages, excludedLanguages);
if (!emmetMode
|| emmetConfig['showExpandedAbbreviation'] === 'never'
|| ((isSyntaxMapped || emmetMode === 'jsx') && emmetConfig['showExpandedAbbreviation'] !== 'always')) {
|| emmetConfig.showExpandedAbbreviation === 'never'
|| ((isSyntaxMapped || emmetMode === 'jsx') && emmetConfig.showExpandedAbbreviation !== 'always')) {
return;
}
@@ -135,7 +135,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
const offset = document.offsetAt(position);
if (isStyleSheet(document.languageId) && context.triggerKind !== vscode.CompletionTriggerKind.TriggerForIncompleteCompletions) {
validateLocation = true;
const usePartialParsing = vscode.workspace.getConfiguration('emmet')['optimizeStylesheetParsing'] === true;
const usePartialParsing = vscode.workspace.getConfiguration('emmet').optimizeStylesheetParsing === true;
rootNode = usePartialParsing && document.lineCount > 1000 ? parsePartialStylesheet(document, position) : <Stylesheet>getRootNode(document, true);
if (!rootNode) {
return;
@@ -200,7 +200,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
newItem.filterText = item.filterText;
newItem.sortText = item.sortText;
if (emmetConfig['showSuggestionsAsSnippets'] === true) {
if (emmetConfig.showSuggestionsAsSnippets === true) {
newItem.kind = vscode.CompletionItemKind.Snippet;
}
newItems.push(newItem);
+1 -1
View File
@@ -56,7 +56,7 @@ function getRangesToReplace(document: vscode.TextDocument, nodeToUpdate: HtmlFla
const emmetMode = getEmmetMode(document.languageId, {}, []) ?? '';
const emmetConfig = getEmmetConfiguration(emmetMode);
if (emmetMode && emmetConfig.syntaxProfiles[emmetMode] &&
(emmetConfig.syntaxProfiles[emmetMode]['selfClosingStyle'] === 'xhtml' || emmetConfig.syntaxProfiles[emmetMode]['self_closing_tag'] === 'xhtml')) {
(emmetConfig.syntaxProfiles[emmetMode].selfClosingStyle === 'xhtml' || emmetConfig.syntaxProfiles[emmetMode].self_closing_tag === 'xhtml')) {
textToReplaceWith = ' ' + textToReplaceWith;
}
}
+7 -7
View File
@@ -606,8 +606,8 @@ export function sameNodes(node1: FlatNode | undefined, node2: FlatNode | undefin
export function getEmmetConfiguration(syntax: string) {
const emmetConfig = vscode.workspace.getConfiguration('emmet');
const syntaxProfiles = Object.assign({}, emmetConfig['syntaxProfiles'] || {});
const preferences = Object.assign({}, emmetConfig['preferences'] || {});
const syntaxProfiles = Object.assign({}, emmetConfig.syntaxProfiles || {});
const preferences = Object.assign({}, emmetConfig.preferences || {});
// jsx, xml and xsl syntaxes need to have self closing tags unless otherwise configured by user
if (syntax === 'jsx' || syntax === 'xml' || syntax === 'xsl') {
syntaxProfiles[syntax] = syntaxProfiles[syntax] || {};
@@ -624,12 +624,12 @@ export function getEmmetConfiguration(syntax: string) {
return {
preferences,
showExpandedAbbreviation: emmetConfig['showExpandedAbbreviation'],
showAbbreviationSuggestions: emmetConfig['showAbbreviationSuggestions'],
showExpandedAbbreviation: emmetConfig.showExpandedAbbreviation,
showAbbreviationSuggestions: emmetConfig.showAbbreviationSuggestions,
syntaxProfiles,
variables: emmetConfig['variables'],
excludeLanguages: emmetConfig['excludeLanguages'],
showSuggestionsAsSnippets: emmetConfig['showSuggestionsAsSnippets']
variables: emmetConfig.variables,
excludeLanguages: emmetConfig.excludeLanguages,
showSuggestionsAsSnippets: emmetConfig.showSuggestionsAsSnippets
};
}
@@ -38,9 +38,9 @@ export function activateAutoInsertion(provider: (kind: 'autoQuote' | 'autoClose'
return;
}
const configurations = workspace.getConfiguration(undefined, document.uri);
isEnabled['autoQuote'] = configurations.get<boolean>('html.autoCreateQuotes') ?? false;
isEnabled['autoClose'] = configurations.get<boolean>('html.autoClosingTags') ?? false;
anyIsEnabled = isEnabled['autoQuote'] || isEnabled['autoClose'];
isEnabled.autoQuote = configurations.get<boolean>('html.autoCreateQuotes') ?? false;
isEnabled.autoClose = configurations.get<boolean>('html.autoClosingTags') ?? false;
anyIsEnabled = isEnabled.autoQuote || isEnabled.autoClose;
}
function onDidChangeTextDocument({ document, contentChanges, reason }: TextDocumentChangeEvent) {
@@ -58,9 +58,9 @@ export function activateAutoInsertion(provider: (kind: 'autoQuote' | 'autoClose'
const lastChange = contentChanges[contentChanges.length - 1];
if (lastChange.rangeLength === 0 && isSingleLine(lastChange.text)) {
const lastCharacter = lastChange.text[lastChange.text.length - 1];
if (isEnabled['autoQuote'] && lastCharacter === '=') {
if (isEnabled.autoQuote && lastCharacter === '=') {
doAutoInsert('autoQuote', document, lastChange);
} else if (isEnabled['autoClose'] && (lastCharacter === '>' || lastCharacter === '/')) {
} else if (isEnabled.autoClose && (lastCharacter === '>' || lastCharacter === '/')) {
doAutoInsert('autoClose', document, lastChange);
}
}
@@ -123,13 +123,13 @@ export function getLanguageModes(supportedLanguages: { [languageId: string]: boo
modelCaches.push(documentRegions);
let modes = Object.create(null);
modes['html'] = getHTMLMode(htmlLanguageService, workspace);
if (supportedLanguages['css']) {
modes['css'] = getCSSMode(cssLanguageService, documentRegions, workspace);
modes.html = getHTMLMode(htmlLanguageService, workspace);
if (supportedLanguages.css) {
modes.css = getCSSMode(cssLanguageService, documentRegions, workspace);
}
if (supportedLanguages['javascript']) {
modes['javascript'] = getJavaScriptMode(documentRegions, 'javascript', workspace);
modes['typescript'] = getJavaScriptMode(documentRegions, 'typescript', workspace);
if (supportedLanguages.javascript) {
modes.javascript = getJavaScriptMode(documentRegions, 'javascript', workspace);
modes.typescript = getJavaScriptMode(documentRegions, 'typescript', workspace);
}
return {
async updateDataProviders(dataProviders: IHTMLDataProvider[]): Promise<void> {
@@ -118,7 +118,7 @@ async function getSchemaRequestService(context: ExtensionContext, log: LogOutput
const response = await xhr({ url: uri, followRedirects: 5, headers });
if (cache) {
const etag = response.headers['etag'];
const etag = response.headers.etag;
if (typeof etag === 'string') {
log.trace(`[json schema cache] Storing schema ${uri} etag ${etag} in cache`);
await cache.putSchema(uri, etag, response.responseText);
@@ -101,7 +101,7 @@ function resolveCopyDestinationSetting(documentUri: vscode.Uri, fileName: string
]);
return outDest.replaceAll(/(?<escape>\\\$)|(?<!\\)\$\{(?<name>\w+)(?:\/(?<pattern>(?:\\\/|[^\}\/])+)\/(?<replacement>(?:\\\/|[^\}\/])*)\/)?\}/g, (match, _escape, name, pattern, replacement, _offset, _str, groups) => {
if (groups?.['escape']) {
if (groups?.escape) {
return '$';
}
@@ -8,7 +8,7 @@
*/
export function resolveSnippet(snippetString: string, vars: ReadonlyMap<string, string>): string {
return snippetString.replaceAll(/(?<escape>\\\$)|(?<!\\)\$\{(?<name>\w+)(?:\/(?<pattern>(?:\\\/|[^\}])+?)\/(?<replacement>(?:\\\/|[^\}])+?)\/)?\}/g, (match, _escape, name, pattern, replacement, _offset, _str, groups) => {
if (groups?.['escape']) {
if (groups?.escape) {
return '$';
}
@@ -30,9 +30,9 @@ const pluginSourceMap: MarkdownIt.PluginSimple = (md): void => {
});
// The 'html_block' renderer doesn't respect `attrs`. We need to insert a marker.
const originalHtmlBlockRenderer = md.renderer.rules['html_block'];
const originalHtmlBlockRenderer = md.renderer.rules.html_block;
if (originalHtmlBlockRenderer) {
md.renderer.rules['html_block'] = (tokens, idx, options, env, self) => (
md.renderer.rules.html_block = (tokens, idx, options, env, self) => (
`<div ${self.renderAttrs(tokens[idx])} ></div>\n` +
originalHtmlBlockRenderer(tokens, idx, options, env, self)
);
@@ -261,8 +261,8 @@ export class MarkdownItEngine implements IMdParser {
}
#addFencedRenderer(md: MarkdownIt): void {
const original = md.renderer.rules['fenced'];
md.renderer.rules['fenced'] = (tokens: MarkdownIt.Token[], idx: number, options, env, self) => {
const original = md.renderer.rules.fenced;
md.renderer.rules.fenced = (tokens: MarkdownIt.Token[], idx: number, options, env, self) => {
const token = tokens[idx];
if (token.map?.length) {
token.attrJoin('class', 'hljs');
@@ -101,7 +101,7 @@ export default class MergeDecorator implements vscode.Disposable {
outlineColor: new vscode.ThemeColor('merge.border')
});
this.decorations['splitter'] = vscode.window.createTextEditorDecorationType({
this.decorations.splitter = vscode.window.createTextEditorDecorationType({
color: new vscode.ThemeColor('editor.foreground'),
outlineStyle: 'solid',
outlineWidth: '1pt',
@@ -31,7 +31,7 @@ export class VSCodeTelemetryReporter implements TelemetryReporter {
"version" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
properties['version'] = this.clientVersionDelegate();
properties.version = this.clientVersionDelegate();
reporter.postEventObj(eventName, properties);
}
@@ -145,12 +145,12 @@ function generatePatchedEnv(env: any, modulePath: string, hasExecPath: boolean):
const newEnv = Object.assign({}, env);
if (!hasExecPath) {
newEnv['ELECTRON_RUN_AS_NODE'] = '1';
newEnv.ELECTRON_RUN_AS_NODE = '1';
}
newEnv['NODE_PATH'] = path.join(modulePath, '..', '..', '..');
newEnv.NODE_PATH = path.join(modulePath, '..', '..', '..');
// Ensure we always have a PATH set
newEnv['PATH'] = newEnv['PATH'] || process.env.PATH;
newEnv.PATH = newEnv.PATH || process.env.PATH;
return newEnv;
}
@@ -1190,13 +1190,13 @@ export default class TypeScriptServiceClient extends Disposable implements IType
switch (telemetryData.telemetryEventName) {
case 'typingsInstalled': {
const typingsInstalledPayload: Proto.TypingsInstalledTelemetryEventPayload = (telemetryData.payload as Proto.TypingsInstalledTelemetryEventPayload);
properties['installedPackages'] = typingsInstalledPayload.installedPackages;
properties.installedPackages = typingsInstalledPayload.installedPackages;
if (typeof typingsInstalledPayload.installSuccess === 'boolean') {
properties['installSuccess'] = typingsInstalledPayload.installSuccess.toString();
properties.installSuccess = typingsInstalledPayload.installSuccess.toString();
}
if (typeof typingsInstalledPayload.typingsInstallerVersion === 'string') {
properties['typingsInstallerVersion'] = typingsInstalledPayload.typingsInstallerVersion;
properties.typingsInstallerVersion = typingsInstalledPayload.typingsInstallerVersion;
}
break;
}
@@ -1220,7 +1220,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
// Add plugin data here
if (telemetryData.telemetryEventName === 'projectInfo') {
if (this.serverState.type === ServerState.Type.Running) {
this.serverState.updateTsserverVersion(properties['version']);
this.serverState.updateTsserverVersion(properties.version);
}
}
@@ -10,7 +10,7 @@ export function isWeb(): boolean {
}
export function isWebAndHasSharedArrayBuffers(): boolean {
return isWeb() && !!(globalThis as Record<string, unknown>)['crossOriginIsolated'];
return isWeb() && !!(globalThis as Record<string, unknown>).crossOriginIsolated;
}
export function supportsReadableByteStreams(): boolean {