diff --git a/Extension/ThirdPartyNotices.txt b/Extension/ThirdPartyNotices.txt index e7ba616c59..3dc5f2feb0 100644 --- a/Extension/ThirdPartyNotices.txt +++ b/Extension/ThirdPartyNotices.txt @@ -2429,6 +2429,7 @@ The notices below are from non-npm sources. - ANTLR (http://www.antlr2.org/) - C++11 Sublime Text Snippets (https://github.com/Rapptz/cpp-sublime-snippet) - Clang (https://clang.llvm.org/) +- editorconfig-core-js (https://github.com/editorconfig/editorconfig-core-js) - gcc-11/libgcc (https://packages.ubuntu.com/jammy/gcc-11-base) - Guidelines Support Library (https://github.com/Microsoft/GSL) - libc++ (https://libcxx.llvm.org/index.html) @@ -2677,6 +2678,31 @@ mechanisms: ========================================= END OF Clang NOTICES AND INFORMATION +%% editorconfig-core-js NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright © 2012 EditorConfig Team + +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. + +========================================= +END OF editorconfig-core-js NOTICES AND INFORMATION + %% gcc-9/libgcc NOTICES AND INFORMATION BEGIN HERE ========================================= The following runtime libraries are licensed under the terms of the diff --git a/Extension/package.json b/Extension/package.json index 733e2f4298..4f1f849f95 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -6517,7 +6517,6 @@ "devDependencies": { "@octokit/rest": "^20.1.1", "@types/glob": "^7.2.0", - "@types/minimatch": "^3.0.5", "@types/mocha": "^10.0.6", "@types/node": "^20.14.2", "@types/node-fetch": "^2.6.11", @@ -6569,7 +6568,7 @@ "comment-json": "^4.2.3", "escape-string-regexp": "^2.0.0", "glob": "^7.2.3", - "minimatch": "^3.0.5", + "minimatch": "^4.2.0", "mkdirp": "^3.0.1", "node-fetch": "^2.7.0", "node-loader": "^2.0.0", diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index fdc7d8ec0e..6dd00d741b 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -2577,7 +2577,8 @@ export class DefaultClient implements Client { } let foundGlobMatch: boolean = false; for (const assoc in assocs) { - if (minimatch(filePath, assoc)) { + const matcher = new minimatch.Minimatch(assoc); + if (matcher.match(filePath)) { foundGlobMatch = true; break; // Assoc matched a glob pattern. } diff --git a/Extension/src/LanguageServer/editorConfig.ts b/Extension/src/LanguageServer/editorConfig.ts index 21a73673c6..b5c8aa1db0 100644 --- a/Extension/src/LanguageServer/editorConfig.ts +++ b/Extension/src/LanguageServer/editorConfig.ts @@ -5,7 +5,9 @@ 'use strict'; import * as fs from 'fs'; +import { Minimatch } from 'minimatch'; import * as path from 'path'; +import { isWindows } from '../constants'; export const cachedEditorConfigSettings: Map = new Map(); @@ -61,13 +63,25 @@ export function mapWrapToEditorConfig(value: string | undefined): string { return "never"; } -function matchesSection(filePath: string, section: string): boolean { - const fileName: string = path.basename(filePath); - // Escape all regex special characters except '*' and '?'. - // Convert wildcards '*' to '.*' and '?' to '.'. - const sectionPattern = section.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*').replace(/\?/g, '.'); - const regex: RegExp = new RegExp(`^${sectionPattern}$`); - return regex.test(fileName); +export function matchesSection(pathPrefix: string, filePath: string, section: string): boolean { + // The following code is copied from: https://github.com/editorconfig/editorconfig-core-js + const matchOptions = { matchBase: true, dot: true }; + pathPrefix = pathPrefix.replace(/[?*+@!()|[\]{}]/g, '\\$&'); + pathPrefix = pathPrefix.replace(/^#/, '\\#'); + switch (section.indexOf('/')) { + case -1: + section = `**/${section}`; + break; + case 0: + section = section.substring(1); + break; + default: + break; + } + section = section.replace(/\\\\/g, '\\\\\\\\'); + section = section.replace(/\*\*/g, '{*,**/**/**}'); + const matcher = new Minimatch(`${pathPrefix}/${section}`, matchOptions); + return matcher.match(filePath); } function parseEditorConfigContent(content: string): Record { @@ -95,9 +109,9 @@ function parseEditorConfigContent(content: string): Record { let value: any = values.join('=').trim(); // Convert boolean-like and numeric values. - if (value.toLowerCase() === 'true') { + if (value === 'true') { value = true; - } else if (value.toLowerCase() === 'false') { + } else if (value === 'false') { value = false; } else if (!isNaN(Number(value))) { value = Number(value); @@ -123,6 +137,10 @@ function getEditorConfig(filePath: string): any { let currentDir: string = path.dirname(filePath); const rootDir: string = path.parse(currentDir).root; + if (isWindows) { + filePath = filePath.replace(/\\/g, '/'); + } + // Traverse from the file's directory to the root directory. for (; ;) { const editorConfigPath: string = path.join(currentDir, '.editorconfig'); @@ -138,9 +156,14 @@ function getEditorConfig(filePath: string): any { }; } + let currentDirForwardSlashes: string = currentDir; + if (isWindows) { + currentDirForwardSlashes = currentDir.replace(/\\/g, '/'); + } + // Match sections and combine configurations. Object.keys(configData).forEach((section: string) => { - if (section !== '*' && matchesSection(filePath, section)) { + if (section !== '*' && matchesSection(currentDirForwardSlashes, filePath, section)) { combinedConfig = { ...combinedConfig, ...configData[section] diff --git a/Extension/yarn.lock b/Extension/yarn.lock index 7a59a937de..377974a1ea 100644 --- a/Extension/yarn.lock +++ b/Extension/yarn.lock @@ -448,7 +448,7 @@ resolved "https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" integrity sha1-B1CLRXl8uB7D8nMBGwVM0HVe3co= -"@types/minimatch@^3.0.3", "@types/minimatch@^3.0.5": +"@types/minimatch@^3.0.3": version "3.0.5" resolved "https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" integrity sha1-EAHMXmo3BLg8I2An538vWOoBD0A= @@ -3278,6 +3278,13 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.3.tgz#b4dcece1d674dee104bb0fb833ebb85a78cbbca6" + integrity sha512-lIUdtK5hdofgCTu3aT0sOaHsYR37viUuIc0rwnnDXImbwFRcumyLMeZaM0t0I/fgxS6s6JMfu0rLD1Wz9pv1ng== + dependencies: + brace-expansion "^1.1.7" + minimatch@^5.0.1, minimatch@^5.1.0, minimatch@^5.1.6: version "5.1.6" resolved "https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"