Path: blob/main/src/vs/workbench/contrib/extensions/common/extensionQuery.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { IExtensionGalleryManifest } from '../../../../platform/extensionManagement/common/extensionGalleryManifest.js';6import { FilterType, SortBy } from '../../../../platform/extensionManagement/common/extensionManagement.js';7import { EXTENSION_CATEGORIES } from '../../../../platform/extensions/common/extensions.js';89export class Query {1011constructor(public value: string, public sortBy: string) {12this.value = value.trim();13}1415static suggestions(query: string, galleryManifest: IExtensionGalleryManifest | null): string[] {1617const commands = ['installed', 'updates', 'enabled', 'disabled', 'builtin'];18if (galleryManifest?.capabilities.extensionQuery?.filtering?.some(c => c.name === FilterType.Featured)) {19commands.push('featured');20}2122commands.push(...['mcp', 'popular', 'recommended', 'recentlyPublished', 'workspaceUnsupported', 'deprecated', 'sort']);23const isCategoriesEnabled = galleryManifest?.capabilities.extensionQuery?.filtering?.some(c => c.name === FilterType.Category);24if (isCategoriesEnabled) {25commands.push('category');26}2728commands.push(...['tag', 'ext', 'id', 'outdated', 'recentlyUpdated']);29const sortCommands = [];30if (galleryManifest?.capabilities.extensionQuery?.sorting?.some(c => c.name === SortBy.InstallCount)) {31sortCommands.push('installs');32}33if (galleryManifest?.capabilities.extensionQuery?.sorting?.some(c => c.name === SortBy.WeightedRating)) {34sortCommands.push('rating');35}36sortCommands.push('name', 'publishedDate', 'updateDate');3738const subcommands = {39'sort': sortCommands,40'category': isCategoriesEnabled ? EXTENSION_CATEGORIES.map(c => `"${c.toLowerCase()}"`) : [],41'tag': [''],42'ext': [''],43'id': ['']44} as const;4546const queryContains = (substr: string) => query.indexOf(substr) > -1;47const hasSort = subcommands.sort.some(subcommand => queryContains(`@sort:${subcommand}`));48const hasCategory = subcommands.category.some(subcommand => queryContains(`@category:${subcommand}`));4950return commands.flatMap(command => {51if (hasSort && command === 'sort' || hasCategory && command === 'category') {52return [];53}54if (command in subcommands) {55return (subcommands as Record<string, readonly string[]>)[command]56.map(subcommand => `@${command}:${subcommand}${subcommand === '' ? '' : ' '}`);57}58else {59return queryContains(`@${command}`) ? [] : [`@${command} `];60}61});62}6364static parse(value: string): Query {65let sortBy = '';66value = value.replace(/@sort:(\w+)(-\w*)?/g, (match, by: string, order: string) => {67sortBy = by;6869return '';70});71return new Query(value, sortBy);72}7374toString(): string {75let result = this.value;7677if (this.sortBy) {78result = `${result}${result ? ' ' : ''}@sort:${this.sortBy}`;79}80return result;81}8283isValid(): boolean {84return !/@outdated/.test(this.value);85}8687equals(other: Query): boolean {88return this.value === other.value && this.sortBy === other.sortBy;89}90}919293