From efa285d98d44b12d30b53bde66e3ad7dbe2b171e Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Mon, 22 Oct 2018 13:21:57 -0700 Subject: [PATCH 01/17] feat: search provider foo --- src/extension/api/languageFeatures.ts | 1 + src/extension/api/search.ts | 9 +++++++++ src/extension/extensionHost.ts | 8 ++++++++ src/sourcegraph.d.ts | 4 ++++ 4 files changed, 22 insertions(+) create mode 100644 src/extension/api/search.ts diff --git a/src/extension/api/languageFeatures.ts b/src/extension/api/languageFeatures.ts index cb24164..be62a4b 100644 --- a/src/extension/api/languageFeatures.ts +++ b/src/extension/api/languageFeatures.ts @@ -14,6 +14,7 @@ import * as plain from '../../protocol/plainTypes' import { ProviderMap } from './common' import { ExtDocuments } from './documents' import { fromHover, fromLocation, toPosition } from './types' +import { CombineLatestOperator } from 'rxjs/internal/observable/combineLatest' /** @internal */ export interface ExtLanguageFeaturesAPI { diff --git a/src/extension/api/search.ts b/src/extension/api/search.ts new file mode 100644 index 0000000..2d10945 --- /dev/null +++ b/src/extension/api/search.ts @@ -0,0 +1,9 @@ +/** @internal */ +export interface ExtSearchFeaturesAPI {} + +/** @internal */ +export class ExtSearchFeatures implements ExtSearchFeaturesAPI { + public foo(): void { + console.log('FOO') + } +} diff --git a/src/extension/extensionHost.ts b/src/extension/extensionHost.ts index d1c4993..1ce81d7 100644 --- a/src/extension/extensionHost.ts +++ b/src/extension/extensionHost.ts @@ -8,6 +8,7 @@ import { ExtConfiguration } from './api/configuration' import { ExtContext } from './api/context' import { ExtDocuments } from './api/documents' import { ExtLanguageFeatures } from './api/languageFeatures' +import { ExtSearchFeatures } from './api/search' import { ExtWindows } from './api/windows' import { Location } from './types/location' import { Position } from './types/position' @@ -82,6 +83,9 @@ function createExtensionHandle(initData: InitData, connection: Connection): type const languageFeatures = new ExtLanguageFeatures(proxy('languageFeatures'), documents) handleRequests(connection, 'languageFeatures', languageFeatures) + const searchFeatures = new ExtSearchFeatures() + handleRequests(connection, 'searchFeatures', searchFeatures) + const commands = new ExtCommands(proxy('commands')) handleRequests(connection, 'commands', commands) @@ -129,6 +133,10 @@ function createExtensionHandle(initData: InitData, connection: Connection): type languageFeatures.registerReferenceProvider(selector, provider), }, + search: { + foo: () => searchFeatures.foo(), + }, + commands: { registerCommand: (command, callback) => commands.registerCommand({ command, callback }), executeCommand: (command, ...args) => commands.executeCommand(command, args), diff --git a/src/sourcegraph.d.ts b/src/sourcegraph.d.ts index 051f89c..bc14e99 100644 --- a/src/sourcegraph.d.ts +++ b/src/sourcegraph.d.ts @@ -717,6 +717,10 @@ declare module 'sourcegraph' { ): ProviderResult } + export namespace search { + export function foo(): void + } + export namespace languages { export function registerHoverProvider(selector: DocumentSelector, provider: HoverProvider): Unsubscribable From 5e4fe5bb076195416a6466344a7b548b015847de Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Mon, 22 Oct 2018 18:13:53 -0700 Subject: [PATCH 02/17] feat: can registerSearchProvider --- src/client/api/search.ts | 42 +++++++++++++++++++++++++++ src/client/controller.ts | 2 ++ src/client/providers/search.ts | 32 ++++++++++++++++++++ src/client/registries.ts | 2 ++ src/common/proxy.ts | 7 +++++ src/extension/api/languageFeatures.ts | 1 - src/extension/api/search.ts | 23 +++++++++++++-- src/extension/extensionHost.ts | 10 +++++-- src/sourcegraph.d.ts | 6 +++- 9 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 src/client/api/search.ts create mode 100644 src/client/providers/search.ts diff --git a/src/client/api/search.ts b/src/client/api/search.ts new file mode 100644 index 0000000..e64cf28 --- /dev/null +++ b/src/client/api/search.ts @@ -0,0 +1,42 @@ +import { from, Observable, Subscription } from 'rxjs' +import { ExtSearchFeaturesAPI } from 'src/extension/api/search' +import { Connection } from 'src/protocol/jsonrpc2/connection' +import { createProxyAndHandleRequests } from '../../common/proxy' +import { FeatureProviderRegistry } from '../providers/registry' +import { TransformQuerySignature } from '../providers/search' +import { SubscriptionMap } from './common' + +export interface SearchFeaturesAPI { + $registerSearchProvider(id: number): void + $unregister(id: number): void +} + +export class SearchFeatures implements SearchFeaturesAPI { + private subscriptions = new Subscription() + private registrations = new SubscriptionMap() + private proxy: ExtSearchFeaturesAPI + + constructor(connection: Connection, private searchRegistry: FeatureProviderRegistry<{}, TransformQuerySignature>) { + this.subscriptions.add(this.registrations) + + this.proxy = createProxyAndHandleRequests('searchFeatures', connection, this) + } + + public $registerSearchProvider(id: number): void { + this.registrations.add( + id, + this.searchRegistry.registerProvider( + {}, + (query: string): Observable => from(this.proxy.$transformQuery(id, query)) + ) + ) + } + + public $unregister(id: number): void { + this.registrations.remove(id) + } + + public unsubscribe(): void { + this.subscriptions.unsubscribe() + } +} diff --git a/src/client/controller.ts b/src/client/controller.ts index f4936bc..2918ad0 100644 --- a/src/client/controller.ts +++ b/src/client/controller.ts @@ -19,6 +19,7 @@ import { ClientConfiguration } from './api/configuration' import { ClientContext } from './api/context' import { ClientDocuments } from './api/documents' import { ClientLanguageFeatures } from './api/languageFeatures' +import { SearchFeatures } from './api/search' import { ClientWindows } from './api/windows' import { applyContextUpdate, EMPTY_CONTEXT } from './context/context' import { EMPTY_ENVIRONMENT, Environment } from './environment' @@ -268,6 +269,7 @@ export class Controller imp this.registries.textDocumentReferences ) ) + subscription.add(new SearchFeatures(client, this.registries.search)) subscription.add(new ClientCommands(client, this.registries.commands)) } diff --git a/src/client/providers/search.ts b/src/client/providers/search.ts new file mode 100644 index 0000000..e24353b --- /dev/null +++ b/src/client/providers/search.ts @@ -0,0 +1,32 @@ +import { Observable } from 'rxjs' +import { switchMap } from 'rxjs/operators' +import { FeatureProviderRegistry } from './registry' + +export type TransformQuerySignature = (query: string) => Observable +/** Provides hovers from all extensions. */ +export class SearchTransformProviderRegistry extends FeatureProviderRegistry<{}, TransformQuerySignature> { + public transformQuery(query: string): Observable { + return transformQuery(this.providers, query) + } +} + +/** + * Returns an observable that emits all providers' hovers whenever any of the last-emitted set of providers emits + * hovers. + * + * Most callers should use TextDocumentHoverProviderRegistry's getHover method, which uses the registered hover + * providers. + */ +export function transformQuery( + providers: Observable, + query: string +): Observable { + return providers.pipe( + switchMap(providers => { + if (providers.length === 0) { + return [null] + } + return providers[0](query) + }) + ) +} diff --git a/src/client/registries.ts b/src/client/registries.ts index c1decd0..ec78f95 100644 --- a/src/client/registries.ts +++ b/src/client/registries.ts @@ -7,6 +7,7 @@ import { ContributionRegistry } from './providers/contribution' import { TextDocumentDecorationProviderRegistry } from './providers/decoration' import { TextDocumentHoverProviderRegistry } from './providers/hover' import { TextDocumentLocationProviderRegistry, TextDocumentReferencesProviderRegistry } from './providers/location' +import { SearchTransformProviderRegistry } from './providers/search' /** * Registries is a container for all provider registries. @@ -25,4 +26,5 @@ export class Registries { public readonly textDocumentTypeDefinition = new TextDocumentLocationProviderRegistry() public readonly textDocumentHover = new TextDocumentHoverProviderRegistry() public readonly textDocumentDecoration = new TextDocumentDecorationProviderRegistry() + public readonly search = new SearchTransformProviderRegistry() } diff --git a/src/common/proxy.ts b/src/common/proxy.ts index aa50072..9697fd9 100644 --- a/src/common/proxy.ts +++ b/src/common/proxy.ts @@ -16,8 +16,12 @@ export function createProxy(call: (name: string, args: any[]) => any): any { return new Proxy(Object.create(null), { get: (target: any, name: string) => { if (!target[name] && name[0] === '$') { + console.log('intercepting name', name) target[name] = (...args: any[]) => call(name, args) + } else { + console.log('not intercepting', name) } + return target[name] }, }) @@ -36,7 +40,10 @@ export function handleRequests(connection: Connection, prefix: string, handler: for (const name of Object.getOwnPropertyNames(proto)) { const value = proto[name] if (name[0] === '$' && typeof value === 'function') { + console.log('registering request handler', name) connection.onRequest(`${prefix}/${name}`, (...args: any[]) => value.apply(handler, args[0])) + } else { + console.log('not registering', name) } } } diff --git a/src/extension/api/languageFeatures.ts b/src/extension/api/languageFeatures.ts index be62a4b..cb24164 100644 --- a/src/extension/api/languageFeatures.ts +++ b/src/extension/api/languageFeatures.ts @@ -14,7 +14,6 @@ import * as plain from '../../protocol/plainTypes' import { ProviderMap } from './common' import { ExtDocuments } from './documents' import { fromHover, fromLocation, toPosition } from './types' -import { CombineLatestOperator } from 'rxjs/internal/observable/combineLatest' /** @internal */ export interface ExtLanguageFeaturesAPI { diff --git a/src/extension/api/search.ts b/src/extension/api/search.ts index 2d10945..5cb80f6 100644 --- a/src/extension/api/search.ts +++ b/src/extension/api/search.ts @@ -1,9 +1,26 @@ +import { Unsubscribable } from 'rxjs' +import { SearchProvider } from 'sourcegraph' +import { SearchFeaturesAPI } from 'src/client/api/search' +import { ProviderMap } from './common' + /** @internal */ -export interface ExtSearchFeaturesAPI {} +export interface ExtSearchFeaturesAPI { + $transformQuery: (id: number, query: string) => Promise +} /** @internal */ export class ExtSearchFeatures implements ExtSearchFeaturesAPI { - public foo(): void { - console.log('FOO') + private registrations = new ProviderMap(id => this.proxy.$unregister(id)) + constructor(private proxy: SearchFeaturesAPI) {} + + public registerSearchProvider(provider: SearchProvider): Unsubscribable { + const { id, subscription } = this.registrations.add(provider) + this.proxy.$registerSearchProvider(id) + return subscription + } + + public $transformQuery(id: number, query: string): Promise { + const provider = this.registrations.get(id) + return Promise.resolve(provider.transformQuery(query)) } } diff --git a/src/extension/extensionHost.ts b/src/extension/extensionHost.ts index 1ce81d7..17c6017 100644 --- a/src/extension/extensionHost.ts +++ b/src/extension/extensionHost.ts @@ -66,7 +66,11 @@ function createExtensionHandle(initData: InitData, connection: Connection): type const sync = () => connection.sendRequest('ping') connection.onRequest('ping', () => 'pong') - const proxy = (prefix: string) => createProxy((name, args) => connection.sendRequest(`${prefix}/${name}`, args)) + const proxy = (prefix: string) => + createProxy((name, args) => { + console.log('proxy calling send request', name) + connection.sendRequest(`${prefix}/${name}`, args) + }) const context = new ExtContext(proxy('context')) handleRequests(connection, 'context', context) @@ -83,7 +87,7 @@ function createExtensionHandle(initData: InitData, connection: Connection): type const languageFeatures = new ExtLanguageFeatures(proxy('languageFeatures'), documents) handleRequests(connection, 'languageFeatures', languageFeatures) - const searchFeatures = new ExtSearchFeatures() + const searchFeatures = new ExtSearchFeatures(proxy('searchFeatures')) handleRequests(connection, 'searchFeatures', searchFeatures) const commands = new ExtCommands(proxy('commands')) @@ -134,7 +138,7 @@ function createExtensionHandle(initData: InitData, connection: Connection): type }, search: { - foo: () => searchFeatures.foo(), + registerSearchProvider: provider => searchFeatures.registerSearchProvider(provider), }, commands: { diff --git a/src/sourcegraph.d.ts b/src/sourcegraph.d.ts index bc14e99..b70d61b 100644 --- a/src/sourcegraph.d.ts +++ b/src/sourcegraph.d.ts @@ -717,8 +717,12 @@ declare module 'sourcegraph' { ): ProviderResult } + export interface SearchProvider { + transformQuery(query: string): ProviderResult + } + export namespace search { - export function foo(): void + export function registerSearchProvider(provider: SearchProvider): Unsubscribable } export namespace languages { From de15667e2a26c0033ecb7d482e0d84b7cc68837f Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Tue, 23 Oct 2018 09:46:09 -0700 Subject: [PATCH 03/17] fix: clean up --- src/common/proxy.ts | 6 ------ src/extension/extensionHost.ts | 6 +----- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/common/proxy.ts b/src/common/proxy.ts index 9697fd9..ed8ed87 100644 --- a/src/common/proxy.ts +++ b/src/common/proxy.ts @@ -16,10 +16,7 @@ export function createProxy(call: (name: string, args: any[]) => any): any { return new Proxy(Object.create(null), { get: (target: any, name: string) => { if (!target[name] && name[0] === '$') { - console.log('intercepting name', name) target[name] = (...args: any[]) => call(name, args) - } else { - console.log('not intercepting', name) } return target[name] @@ -40,10 +37,7 @@ export function handleRequests(connection: Connection, prefix: string, handler: for (const name of Object.getOwnPropertyNames(proto)) { const value = proto[name] if (name[0] === '$' && typeof value === 'function') { - console.log('registering request handler', name) connection.onRequest(`${prefix}/${name}`, (...args: any[]) => value.apply(handler, args[0])) - } else { - console.log('not registering', name) } } } diff --git a/src/extension/extensionHost.ts b/src/extension/extensionHost.ts index 17c6017..64520b9 100644 --- a/src/extension/extensionHost.ts +++ b/src/extension/extensionHost.ts @@ -66,11 +66,7 @@ function createExtensionHandle(initData: InitData, connection: Connection): type const sync = () => connection.sendRequest('ping') connection.onRequest('ping', () => 'pong') - const proxy = (prefix: string) => - createProxy((name, args) => { - console.log('proxy calling send request', name) - connection.sendRequest(`${prefix}/${name}`, args) - }) + const proxy = (prefix: string) => createProxy((name, args) => connection.sendRequest(`${prefix}/${name}`, args)) const context = new ExtContext(proxy('context')) handleRequests(connection, 'context', context) From f5fd2be41e2283f22d09fb3d0ac3c2832a1ef9ec Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Tue, 23 Oct 2018 16:58:13 -0700 Subject: [PATCH 04/17] feat: return original query if no providers --- src/client/providers/search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/providers/search.ts b/src/client/providers/search.ts index e24353b..e975a88 100644 --- a/src/client/providers/search.ts +++ b/src/client/providers/search.ts @@ -24,7 +24,7 @@ export function transformQuery( return providers.pipe( switchMap(providers => { if (providers.length === 0) { - return [null] + return [query] } return providers[0](query) }) From e10a9fc394c6b85ca0b93fa3c863443c6ecc287a Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Tue, 23 Oct 2018 17:50:12 -0700 Subject: [PATCH 05/17] docs: update docs --- src/client/providers/search.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/client/providers/search.ts b/src/client/providers/search.ts index e975a88..6a7e985 100644 --- a/src/client/providers/search.ts +++ b/src/client/providers/search.ts @@ -3,7 +3,8 @@ import { switchMap } from 'rxjs/operators' import { FeatureProviderRegistry } from './registry' export type TransformQuerySignature = (query: string) => Observable -/** Provides hovers from all extensions. */ + +/** Provides transformed queries from the first search extension. */ export class SearchTransformProviderRegistry extends FeatureProviderRegistry<{}, TransformQuerySignature> { public transformQuery(query: string): Observable { return transformQuery(this.providers, query) @@ -11,10 +12,10 @@ export class SearchTransformProviderRegistry extends FeatureProviderRegistry<{}, } /** - * Returns an observable that emits all providers' hovers whenever any of the last-emitted set of providers emits - * hovers. + * Returns an observable that emits the first provider's transformed query whenever any of the last-emitted set of providers emits + * a query. * - * Most callers should use TextDocumentHoverProviderRegistry's getHover method, which uses the registered hover + * Most callers should use SearchTransformProviderRegistry's getHover method, which uses the registered search * providers. */ export function transformQuery( From 25ca64bf0a7a424a33d36aa8a64e6e75d3f61ffa Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Wed, 24 Oct 2018 10:59:43 -0700 Subject: [PATCH 06/17] chore: rename SearchProvider to QueryTransformProvider --- src/client/api/search.ts | 4 ++-- src/extension/api/search.ts | 10 +++++----- src/extension/extensionHost.ts | 2 +- src/sourcegraph.d.ts | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/client/api/search.ts b/src/client/api/search.ts index e64cf28..d82aab4 100644 --- a/src/client/api/search.ts +++ b/src/client/api/search.ts @@ -7,7 +7,7 @@ import { TransformQuerySignature } from '../providers/search' import { SubscriptionMap } from './common' export interface SearchFeaturesAPI { - $registerSearchProvider(id: number): void + $registerQueryTransformProvider(id: number): void $unregister(id: number): void } @@ -22,7 +22,7 @@ export class SearchFeatures implements SearchFeaturesAPI { this.proxy = createProxyAndHandleRequests('searchFeatures', connection, this) } - public $registerSearchProvider(id: number): void { + public $registerQueryTransformProvider(id: number): void { this.registrations.add( id, this.searchRegistry.registerProvider( diff --git a/src/extension/api/search.ts b/src/extension/api/search.ts index 5cb80f6..8412e23 100644 --- a/src/extension/api/search.ts +++ b/src/extension/api/search.ts @@ -1,5 +1,5 @@ import { Unsubscribable } from 'rxjs' -import { SearchProvider } from 'sourcegraph' +import { QueryTransformProvider } from 'sourcegraph' import { SearchFeaturesAPI } from 'src/client/api/search' import { ProviderMap } from './common' @@ -10,17 +10,17 @@ export interface ExtSearchFeaturesAPI { /** @internal */ export class ExtSearchFeatures implements ExtSearchFeaturesAPI { - private registrations = new ProviderMap(id => this.proxy.$unregister(id)) + private registrations = new ProviderMap(id => this.proxy.$unregister(id)) constructor(private proxy: SearchFeaturesAPI) {} - public registerSearchProvider(provider: SearchProvider): Unsubscribable { + public registerQueryTransformProvider(provider: QueryTransformProvider): Unsubscribable { const { id, subscription } = this.registrations.add(provider) - this.proxy.$registerSearchProvider(id) + this.proxy.$registerQueryTransformProvider(id) return subscription } public $transformQuery(id: number, query: string): Promise { - const provider = this.registrations.get(id) + const provider = this.registrations.get(id) return Promise.resolve(provider.transformQuery(query)) } } diff --git a/src/extension/extensionHost.ts b/src/extension/extensionHost.ts index 64520b9..9a01b67 100644 --- a/src/extension/extensionHost.ts +++ b/src/extension/extensionHost.ts @@ -134,7 +134,7 @@ function createExtensionHandle(initData: InitData, connection: Connection): type }, search: { - registerSearchProvider: provider => searchFeatures.registerSearchProvider(provider), + registerQueryTransformProvider: provider => searchFeatures.registerQueryTransformProvider(provider), }, commands: { diff --git a/src/sourcegraph.d.ts b/src/sourcegraph.d.ts index b70d61b..749557a 100644 --- a/src/sourcegraph.d.ts +++ b/src/sourcegraph.d.ts @@ -717,12 +717,12 @@ declare module 'sourcegraph' { ): ProviderResult } - export interface SearchProvider { + export interface QueryTransformProvider { transformQuery(query: string): ProviderResult } export namespace search { - export function registerSearchProvider(provider: SearchProvider): Unsubscribable + export function registerQueryTransformProvider(provider: QueryTransformProvider): Unsubscribable } export namespace languages { From c76d18cc02328b8ffe72fa6e200e8a60271a35b5 Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Wed, 24 Oct 2018 18:21:03 -0700 Subject: [PATCH 07/17] fix: improve naming --- src/client/api/search.ts | 14 ++++---- src/client/controller.ts | 4 +-- src/client/providers/queryTransformer.ts | 45 ++++++++++++++++++++++++ src/client/providers/search.ts | 33 ----------------- src/client/registries.ts | 4 +-- src/extension/api/search.ts | 18 +++++----- src/extension/extensionHost.ts | 6 ++-- src/sourcegraph.d.ts | 4 +-- 8 files changed, 70 insertions(+), 58 deletions(-) create mode 100644 src/client/providers/queryTransformer.ts delete mode 100644 src/client/providers/search.ts diff --git a/src/client/api/search.ts b/src/client/api/search.ts index d82aab4..9b7d07e 100644 --- a/src/client/api/search.ts +++ b/src/client/api/search.ts @@ -1,20 +1,20 @@ import { from, Observable, Subscription } from 'rxjs' -import { ExtSearchFeaturesAPI } from 'src/extension/api/search' +import { ExtSearch } from 'src/extension/api/search' import { Connection } from 'src/protocol/jsonrpc2/connection' import { createProxyAndHandleRequests } from '../../common/proxy' +import { TransformQuerySignature } from '../providers/queryTransformer' import { FeatureProviderRegistry } from '../providers/registry' -import { TransformQuerySignature } from '../providers/search' import { SubscriptionMap } from './common' -export interface SearchFeaturesAPI { - $registerQueryTransformProvider(id: number): void +export interface SearchAPI { + $registerQueryTransformer(id: number): void $unregister(id: number): void } -export class SearchFeatures implements SearchFeaturesAPI { +export class Search implements SearchAPI { private subscriptions = new Subscription() private registrations = new SubscriptionMap() - private proxy: ExtSearchFeaturesAPI + private proxy: ExtSearch constructor(connection: Connection, private searchRegistry: FeatureProviderRegistry<{}, TransformQuerySignature>) { this.subscriptions.add(this.registrations) @@ -22,7 +22,7 @@ export class SearchFeatures implements SearchFeaturesAPI { this.proxy = createProxyAndHandleRequests('searchFeatures', connection, this) } - public $registerQueryTransformProvider(id: number): void { + public $registerQueryTransformer(id: number): void { this.registrations.add( id, this.searchRegistry.registerProvider( diff --git a/src/client/controller.ts b/src/client/controller.ts index 2918ad0..1afe818 100644 --- a/src/client/controller.ts +++ b/src/client/controller.ts @@ -19,7 +19,7 @@ import { ClientConfiguration } from './api/configuration' import { ClientContext } from './api/context' import { ClientDocuments } from './api/documents' import { ClientLanguageFeatures } from './api/languageFeatures' -import { SearchFeatures } from './api/search' +import { Search } from './api/search' import { ClientWindows } from './api/windows' import { applyContextUpdate, EMPTY_CONTEXT } from './context/context' import { EMPTY_ENVIRONMENT, Environment } from './environment' @@ -269,7 +269,7 @@ export class Controller imp this.registries.textDocumentReferences ) ) - subscription.add(new SearchFeatures(client, this.registries.search)) + subscription.add(new Search(client, this.registries.search)) subscription.add(new ClientCommands(client, this.registries.commands)) } diff --git a/src/client/providers/queryTransformer.ts b/src/client/providers/queryTransformer.ts new file mode 100644 index 0000000..e164c79 --- /dev/null +++ b/src/client/providers/queryTransformer.ts @@ -0,0 +1,45 @@ +import { Observable, of } from 'rxjs' +import { flatMap, map, switchMap } from 'rxjs/operators' +import { FeatureProviderRegistry } from './registry' + +export type TransformQuerySignature = (query: string) => Observable + +/** Provides transformed queries from the first search extension. */ +export class QueryTransformerRegistry extends FeatureProviderRegistry<{}, TransformQuerySignature> { + public transformQuery(query: string): Observable { + return transformQuery(this.providers, query) + } +} + +/** + * Returns an observable that emits all provider's transformed query whenever any of the last-emitted set of providers emits + * a query. + * + * Most callers should use QueryTransformerRegistry's transformQuery method, which uses the registered search + * providers. + */ +export function transformQuery( + providers: Observable, + query: string +): Observable { + return providers.pipe( + switchMap(providers => { + if (providers.length === 0) { + return [query] + } + // let currentQuery = providers[0](query).pipe(map(q => q)) + // for (const provider of providers) { + // const str = currentQuery.subscribe() + // currentQuery = provider() + // } + return providers.reduce( + (currentQuery, transformQuery) => + currentQuery.pipe( + flatMap(q => transformQuery(q).pipe(map(transformedQuery => transformedQuery || q))) + ), + of(query) + ) + // of(providers).pipe(reduce((accumulatedValue, currentProvider) => currentProvider(accumulatedValue)), providers[0](query))) + }) + ) +} diff --git a/src/client/providers/search.ts b/src/client/providers/search.ts deleted file mode 100644 index 6a7e985..0000000 --- a/src/client/providers/search.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Observable } from 'rxjs' -import { switchMap } from 'rxjs/operators' -import { FeatureProviderRegistry } from './registry' - -export type TransformQuerySignature = (query: string) => Observable - -/** Provides transformed queries from the first search extension. */ -export class SearchTransformProviderRegistry extends FeatureProviderRegistry<{}, TransformQuerySignature> { - public transformQuery(query: string): Observable { - return transformQuery(this.providers, query) - } -} - -/** - * Returns an observable that emits the first provider's transformed query whenever any of the last-emitted set of providers emits - * a query. - * - * Most callers should use SearchTransformProviderRegistry's getHover method, which uses the registered search - * providers. - */ -export function transformQuery( - providers: Observable, - query: string -): Observable { - return providers.pipe( - switchMap(providers => { - if (providers.length === 0) { - return [query] - } - return providers[0](query) - }) - ) -} diff --git a/src/client/registries.ts b/src/client/registries.ts index ec78f95..1eb20f3 100644 --- a/src/client/registries.ts +++ b/src/client/registries.ts @@ -7,7 +7,7 @@ import { ContributionRegistry } from './providers/contribution' import { TextDocumentDecorationProviderRegistry } from './providers/decoration' import { TextDocumentHoverProviderRegistry } from './providers/hover' import { TextDocumentLocationProviderRegistry, TextDocumentReferencesProviderRegistry } from './providers/location' -import { SearchTransformProviderRegistry } from './providers/search' +import { QueryTransformerRegistry } from './providers/queryTransformer' /** * Registries is a container for all provider registries. @@ -26,5 +26,5 @@ export class Registries { public readonly textDocumentTypeDefinition = new TextDocumentLocationProviderRegistry() public readonly textDocumentHover = new TextDocumentHoverProviderRegistry() public readonly textDocumentDecoration = new TextDocumentDecorationProviderRegistry() - public readonly search = new SearchTransformProviderRegistry() + public readonly search = new QueryTransformerRegistry() } diff --git a/src/extension/api/search.ts b/src/extension/api/search.ts index 8412e23..e7def54 100644 --- a/src/extension/api/search.ts +++ b/src/extension/api/search.ts @@ -1,26 +1,26 @@ import { Unsubscribable } from 'rxjs' -import { QueryTransformProvider } from 'sourcegraph' -import { SearchFeaturesAPI } from 'src/client/api/search' +import { QueryTransformerProvider } from 'sourcegraph' +import { SearchAPI } from 'src/client/api/search' import { ProviderMap } from './common' /** @internal */ -export interface ExtSearchFeaturesAPI { +export interface ExtSearchAPI { $transformQuery: (id: number, query: string) => Promise } /** @internal */ -export class ExtSearchFeatures implements ExtSearchFeaturesAPI { - private registrations = new ProviderMap(id => this.proxy.$unregister(id)) - constructor(private proxy: SearchFeaturesAPI) {} +export class ExtSearch implements ExtSearchAPI { + private registrations = new ProviderMap(id => this.proxy.$unregister(id)) + constructor(private proxy: SearchAPI) {} - public registerQueryTransformProvider(provider: QueryTransformProvider): Unsubscribable { + public registerQueryTransformer(provider: QueryTransformerProvider): Unsubscribable { const { id, subscription } = this.registrations.add(provider) - this.proxy.$registerQueryTransformProvider(id) + this.proxy.$registerQueryTransformer(id) return subscription } public $transformQuery(id: number, query: string): Promise { - const provider = this.registrations.get(id) + const provider = this.registrations.get(id) return Promise.resolve(provider.transformQuery(query)) } } diff --git a/src/extension/extensionHost.ts b/src/extension/extensionHost.ts index 9a01b67..d45048b 100644 --- a/src/extension/extensionHost.ts +++ b/src/extension/extensionHost.ts @@ -8,7 +8,7 @@ import { ExtConfiguration } from './api/configuration' import { ExtContext } from './api/context' import { ExtDocuments } from './api/documents' import { ExtLanguageFeatures } from './api/languageFeatures' -import { ExtSearchFeatures } from './api/search' +import { ExtSearch } from './api/search' import { ExtWindows } from './api/windows' import { Location } from './types/location' import { Position } from './types/position' @@ -83,7 +83,7 @@ function createExtensionHandle(initData: InitData, connection: Connection): type const languageFeatures = new ExtLanguageFeatures(proxy('languageFeatures'), documents) handleRequests(connection, 'languageFeatures', languageFeatures) - const searchFeatures = new ExtSearchFeatures(proxy('searchFeatures')) + const searchFeatures = new ExtSearch(proxy('searchFeatures')) handleRequests(connection, 'searchFeatures', searchFeatures) const commands = new ExtCommands(proxy('commands')) @@ -134,7 +134,7 @@ function createExtensionHandle(initData: InitData, connection: Connection): type }, search: { - registerQueryTransformProvider: provider => searchFeatures.registerQueryTransformProvider(provider), + registerQueryTransformer: provider => searchFeatures.registerQueryTransformer(provider), }, commands: { diff --git a/src/sourcegraph.d.ts b/src/sourcegraph.d.ts index 749557a..81ba84e 100644 --- a/src/sourcegraph.d.ts +++ b/src/sourcegraph.d.ts @@ -717,12 +717,12 @@ declare module 'sourcegraph' { ): ProviderResult } - export interface QueryTransformProvider { + export interface QueryTransformerProvider { transformQuery(query: string): ProviderResult } export namespace search { - export function registerQueryTransformProvider(provider: QueryTransformProvider): Unsubscribable + export function registerQueryTransformer(provider: QueryTransformerProvider): Unsubscribable } export namespace languages { From 8a1c7aa78c978337626afea8f588dcebe6c9b0d6 Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Wed, 24 Oct 2018 18:24:37 -0700 Subject: [PATCH 08/17] chore: add tests for queryTransformer --- src/client/providers/queryTransformer.test.ts | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 src/client/providers/queryTransformer.test.ts diff --git a/src/client/providers/queryTransformer.test.ts b/src/client/providers/queryTransformer.test.ts new file mode 100644 index 0000000..468b857 --- /dev/null +++ b/src/client/providers/queryTransformer.test.ts @@ -0,0 +1,66 @@ +import * as assert from 'assert' +import { of } from 'rxjs' +import { TestScheduler } from 'rxjs/testing' +import { transformQuery, TransformQuerySignature } from './queryTransformer' + +const scheduler = () => new TestScheduler((a, b) => assert.deepStrictEqual(a, b)) + +const FIXTURE_INPUT = 'foo' +const FIXTURE_RESULT_MERGED = 'foo bar' +const FIXTURE_RESULT = 'bar' + +describe('transformQuery', () => { + describe('0 providers', () => { + it('returns original query', () => + scheduler().run(({ cold, expectObservable }) => + expectObservable( + transformQuery(cold('-a-|', { a: [] }), FIXTURE_INPUT) + ).toBe('-a-|', { + a: FIXTURE_INPUT, + }) + )) + }) + + describe('1 provider', () => { + it('returns result from provider', () => + scheduler().run(({ cold, expectObservable }) => + expectObservable( + transformQuery( + cold('-a-|', { + a: [q => of(FIXTURE_RESULT)], + }), + FIXTURE_INPUT + ) + ).toBe('-a-|', { a: FIXTURE_RESULT }) + )) + }) + + describe('2 providers', () => { + it('returns a single query transformed by both providers', () => + scheduler().run(({ cold, expectObservable }) => + expectObservable( + transformQuery( + cold('-a-|', { + a: [q => of(q), q => of(`${q} ${FIXTURE_RESULT}`)], + }), + FIXTURE_INPUT + ) + ).toBe('-a-|', { a: FIXTURE_RESULT_MERGED }) + )) + }) + + describe('Multiple emissions', () => { + it('returns stream of results', () => + scheduler().run(({ cold, expectObservable }) => + expectObservable( + transformQuery( + cold('-a-b-|', { + a: [q => of(q)], + b: [q => of(FIXTURE_RESULT)], + }), + FIXTURE_INPUT + ) + ).toBe('-a-b-|', { a: FIXTURE_INPUT, b: FIXTURE_RESULT }) + )) + }) +}) From 39590b952d832f4f0faea27231af068f34fe4087 Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Wed, 24 Oct 2018 18:36:14 -0700 Subject: [PATCH 09/17] fix: remove commented chaining attempts --- src/client/providers/queryTransformer.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/client/providers/queryTransformer.ts b/src/client/providers/queryTransformer.ts index e164c79..665caa1 100644 --- a/src/client/providers/queryTransformer.ts +++ b/src/client/providers/queryTransformer.ts @@ -12,7 +12,7 @@ export class QueryTransformerRegistry extends FeatureProviderRegistry<{}, Transf } /** - * Returns an observable that emits all provider's transformed query whenever any of the last-emitted set of providers emits + * Returns an observable that emits a query transformed by all providers whenever any of the last-emitted set of providers emits * a query. * * Most callers should use QueryTransformerRegistry's transformQuery method, which uses the registered search @@ -27,11 +27,6 @@ export function transformQuery( if (providers.length === 0) { return [query] } - // let currentQuery = providers[0](query).pipe(map(q => q)) - // for (const provider of providers) { - // const str = currentQuery.subscribe() - // currentQuery = provider() - // } return providers.reduce( (currentQuery, transformQuery) => currentQuery.pipe( @@ -39,7 +34,6 @@ export function transformQuery( ), of(query) ) - // of(providers).pipe(reduce((accumulatedValue, currentProvider) => currentProvider(accumulatedValue)), providers[0](query))) }) ) } From 4847f2bd81be2daf439392ff7dcef982af616f0a Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Wed, 24 Oct 2018 18:45:54 -0700 Subject: [PATCH 10/17] fix: more renames and cleanup --- src/client/api/search.ts | 7 +++++-- src/client/controller.ts | 2 +- src/client/registries.ts | 2 +- src/common/proxy.ts | 1 - 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/client/api/search.ts b/src/client/api/search.ts index 9b7d07e..bb8a011 100644 --- a/src/client/api/search.ts +++ b/src/client/api/search.ts @@ -16,7 +16,10 @@ export class Search implements SearchAPI { private registrations = new SubscriptionMap() private proxy: ExtSearch - constructor(connection: Connection, private searchRegistry: FeatureProviderRegistry<{}, TransformQuerySignature>) { + constructor( + connection: Connection, + private queryTransformerRegistry: FeatureProviderRegistry<{}, TransformQuerySignature> + ) { this.subscriptions.add(this.registrations) this.proxy = createProxyAndHandleRequests('searchFeatures', connection, this) @@ -25,7 +28,7 @@ export class Search implements SearchAPI { public $registerQueryTransformer(id: number): void { this.registrations.add( id, - this.searchRegistry.registerProvider( + this.queryTransformerRegistry.registerProvider( {}, (query: string): Observable => from(this.proxy.$transformQuery(id, query)) ) diff --git a/src/client/controller.ts b/src/client/controller.ts index 1afe818..9ff66be 100644 --- a/src/client/controller.ts +++ b/src/client/controller.ts @@ -269,7 +269,7 @@ export class Controller imp this.registries.textDocumentReferences ) ) - subscription.add(new Search(client, this.registries.search)) + subscription.add(new Search(client, this.registries.queryTransformer)) subscription.add(new ClientCommands(client, this.registries.commands)) } diff --git a/src/client/registries.ts b/src/client/registries.ts index 1eb20f3..59e6640 100644 --- a/src/client/registries.ts +++ b/src/client/registries.ts @@ -26,5 +26,5 @@ export class Registries { public readonly textDocumentTypeDefinition = new TextDocumentLocationProviderRegistry() public readonly textDocumentHover = new TextDocumentHoverProviderRegistry() public readonly textDocumentDecoration = new TextDocumentDecorationProviderRegistry() - public readonly search = new QueryTransformerRegistry() + public readonly queryTransformer = new QueryTransformerRegistry() } diff --git a/src/common/proxy.ts b/src/common/proxy.ts index ed8ed87..aa50072 100644 --- a/src/common/proxy.ts +++ b/src/common/proxy.ts @@ -18,7 +18,6 @@ export function createProxy(call: (name: string, args: any[]) => any): any { if (!target[name] && name[0] === '$') { target[name] = (...args: any[]) => call(name, args) } - return target[name] }, }) From 13e53ba050261804898c0d086c8a314631b5e5c6 Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Wed, 24 Oct 2018 23:44:49 -0700 Subject: [PATCH 11/17] chore: add integration test --- src/integration-test/search.test.ts | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/integration-test/search.test.ts diff --git a/src/integration-test/search.test.ts b/src/integration-test/search.test.ts new file mode 100644 index 0000000..16ff881 --- /dev/null +++ b/src/integration-test/search.test.ts @@ -0,0 +1,46 @@ +import * as assert from 'assert' +import { take } from 'rxjs/operators' +import { integrationTestContext } from './helpers.test' + +describe('search (integration)', () => { + it('registers a query transformer', async () => { + const { clientController, extensionHost, ready } = await integrationTestContext() + + // Register the provider and call it + const unsubscribe = extensionHost.search.registerQueryTransformer({ transformQuery: () => 'bar' }) + await ready + assert.deepStrictEqual( + await clientController.registries.queryTransformer + .transformQuery('foo') + .pipe(take(1)) + .toPromise(), + 'bar' + ) + + // Unregister the provider and ensure it's removed + unsubscribe.unsubscribe() + assert.deepStrictEqual( + await clientController.registries.queryTransformer + .transformQuery('foo') + .pipe(take(1)) + .toPromise(), + 'foo' + ) + }) + + it('supports multiple query transformers', async () => { + const { clientController, extensionHost, ready } = await integrationTestContext() + + // Register the provider and call it + extensionHost.search.registerQueryTransformer({ transformQuery: q => `${q} bar` }) + extensionHost.search.registerQueryTransformer({ transformQuery: q => `${q} baz` }) + await ready + assert.deepStrictEqual( + await clientController.registries.queryTransformer + .transformQuery('foo') + .pipe(take(1)) + .toPromise(), + 'foo bar baz' + ) + }) +}) From 4bbef152809446f35607b59531d11a5db09f2f58 Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Fri, 26 Oct 2018 11:38:17 -0700 Subject: [PATCH 12/17] fix: address comments --- src/client/api/search.ts | 6 ++- src/client/providers/queryTransformer.test.ts | 14 ++++--- src/client/providers/queryTransformer.ts | 19 ++++----- src/extension/api/search.ts | 12 +++--- src/extension/extensionHost.ts | 6 +-- src/integration-test/search.test.ts | 6 +-- src/sourcegraph.d.ts | 40 +++++++++++++++---- 7 files changed, 64 insertions(+), 39 deletions(-) diff --git a/src/client/api/search.ts b/src/client/api/search.ts index bb8a011..22d1d30 100644 --- a/src/client/api/search.ts +++ b/src/client/api/search.ts @@ -6,11 +6,13 @@ import { TransformQuerySignature } from '../providers/queryTransformer' import { FeatureProviderRegistry } from '../providers/registry' import { SubscriptionMap } from './common' +/** @internal */ export interface SearchAPI { $registerQueryTransformer(id: number): void $unregister(id: number): void } +/** @internal */ export class Search implements SearchAPI { private subscriptions = new Subscription() private registrations = new SubscriptionMap() @@ -22,7 +24,7 @@ export class Search implements SearchAPI { ) { this.subscriptions.add(this.registrations) - this.proxy = createProxyAndHandleRequests('searchFeatures', connection, this) + this.proxy = createProxyAndHandleRequests('search', connection, this) } public $registerQueryTransformer(id: number): void { @@ -30,7 +32,7 @@ export class Search implements SearchAPI { id, this.queryTransformerRegistry.registerProvider( {}, - (query: string): Observable => from(this.proxy.$transformQuery(id, query)) + (query: string): Observable => from(this.proxy.$transformQuery(id, query)) ) ) } diff --git a/src/client/providers/queryTransformer.test.ts b/src/client/providers/queryTransformer.test.ts index 468b857..766b2e4 100644 --- a/src/client/providers/queryTransformer.test.ts +++ b/src/client/providers/queryTransformer.test.ts @@ -6,8 +6,9 @@ import { transformQuery, TransformQuerySignature } from './queryTransformer' const scheduler = () => new TestScheduler((a, b) => assert.deepStrictEqual(a, b)) const FIXTURE_INPUT = 'foo' -const FIXTURE_RESULT_MERGED = 'foo bar' const FIXTURE_RESULT = 'bar' +const FIXTURE_RESULT_TWO = 'qux' +const FIXTURE_RESULT_MERGED = 'foo bar qux' describe('transformQuery', () => { describe('0 providers', () => { @@ -41,7 +42,7 @@ describe('transformQuery', () => { expectObservable( transformQuery( cold('-a-|', { - a: [q => of(q), q => of(`${q} ${FIXTURE_RESULT}`)], + a: [q => of(`${q} ${FIXTURE_RESULT}`), q => of(`${q} ${FIXTURE_RESULT_TWO}`)], }), FIXTURE_INPUT ) @@ -55,12 +56,15 @@ describe('transformQuery', () => { expectObservable( transformQuery( cold('-a-b-|', { - a: [q => of(q)], - b: [q => of(FIXTURE_RESULT)], + a: [q => of(`${q} ${FIXTURE_RESULT}`)], + b: [q => of(`${q} ${FIXTURE_RESULT_TWO}`)], }), FIXTURE_INPUT ) - ).toBe('-a-b-|', { a: FIXTURE_INPUT, b: FIXTURE_RESULT }) + ).toBe('-a-b-|', { + a: `${FIXTURE_INPUT} ${FIXTURE_RESULT}`, + b: `${FIXTURE_INPUT} ${FIXTURE_RESULT_TWO}`, + }) )) }) }) diff --git a/src/client/providers/queryTransformer.ts b/src/client/providers/queryTransformer.ts index 665caa1..ae32f24 100644 --- a/src/client/providers/queryTransformer.ts +++ b/src/client/providers/queryTransformer.ts @@ -2,11 +2,11 @@ import { Observable, of } from 'rxjs' import { flatMap, map, switchMap } from 'rxjs/operators' import { FeatureProviderRegistry } from './registry' -export type TransformQuerySignature = (query: string) => Observable +export type TransformQuerySignature = (query: string) => Observable -/** Provides transformed queries from the first search extension. */ +/** Transforms search queries using registered query transformers from extensions. */ export class QueryTransformerRegistry extends FeatureProviderRegistry<{}, TransformQuerySignature> { - public transformQuery(query: string): Observable { + public transformQuery(query: string): Observable { return transformQuery(this.providers, query) } } @@ -15,13 +15,10 @@ export class QueryTransformerRegistry extends FeatureProviderRegistry<{}, Transf * Returns an observable that emits a query transformed by all providers whenever any of the last-emitted set of providers emits * a query. * - * Most callers should use QueryTransformerRegistry's transformQuery method, which uses the registered search - * providers. + * Most callers should use QueryTransformerRegistry's transformQuery method, which uses the registered query transformers + * */ -export function transformQuery( - providers: Observable, - query: string -): Observable { +export function transformQuery(providers: Observable, query: string): Observable { return providers.pipe( switchMap(providers => { if (providers.length === 0) { @@ -29,9 +26,7 @@ export function transformQuery( } return providers.reduce( (currentQuery, transformQuery) => - currentQuery.pipe( - flatMap(q => transformQuery(q).pipe(map(transformedQuery => transformedQuery || q))) - ), + currentQuery.pipe(flatMap(q => transformQuery(q).pipe(map(transformedQuery => transformedQuery)))), of(query) ) }) diff --git a/src/extension/api/search.ts b/src/extension/api/search.ts index e7def54..ea8863b 100644 --- a/src/extension/api/search.ts +++ b/src/extension/api/search.ts @@ -1,26 +1,26 @@ import { Unsubscribable } from 'rxjs' -import { QueryTransformerProvider } from 'sourcegraph' +import { QueryTransformer } from 'sourcegraph' import { SearchAPI } from 'src/client/api/search' import { ProviderMap } from './common' /** @internal */ export interface ExtSearchAPI { - $transformQuery: (id: number, query: string) => Promise + $transformQuery: (id: number, query: string) => Promise } /** @internal */ export class ExtSearch implements ExtSearchAPI { - private registrations = new ProviderMap(id => this.proxy.$unregister(id)) + private registrations = new ProviderMap(id => this.proxy.$unregister(id)) constructor(private proxy: SearchAPI) {} - public registerQueryTransformer(provider: QueryTransformerProvider): Unsubscribable { + public registerQueryTransformer(provider: QueryTransformer): Unsubscribable { const { id, subscription } = this.registrations.add(provider) this.proxy.$registerQueryTransformer(id) return subscription } - public $transformQuery(id: number, query: string): Promise { - const provider = this.registrations.get(id) + public $transformQuery(id: number, query: string): Promise { + const provider = this.registrations.get(id) return Promise.resolve(provider.transformQuery(query)) } } diff --git a/src/extension/extensionHost.ts b/src/extension/extensionHost.ts index d45048b..7bb8724 100644 --- a/src/extension/extensionHost.ts +++ b/src/extension/extensionHost.ts @@ -83,8 +83,8 @@ function createExtensionHandle(initData: InitData, connection: Connection): type const languageFeatures = new ExtLanguageFeatures(proxy('languageFeatures'), documents) handleRequests(connection, 'languageFeatures', languageFeatures) - const searchFeatures = new ExtSearch(proxy('searchFeatures')) - handleRequests(connection, 'searchFeatures', searchFeatures) + const search = new ExtSearch(proxy('search')) + handleRequests(connection, 'search', search) const commands = new ExtCommands(proxy('commands')) handleRequests(connection, 'commands', commands) @@ -134,7 +134,7 @@ function createExtensionHandle(initData: InitData, connection: Connection): type }, search: { - registerQueryTransformer: provider => searchFeatures.registerQueryTransformer(provider), + registerQueryTransformer: provider => search.registerQueryTransformer(provider), }, commands: { diff --git a/src/integration-test/search.test.ts b/src/integration-test/search.test.ts index 16ff881..cdc08df 100644 --- a/src/integration-test/search.test.ts +++ b/src/integration-test/search.test.ts @@ -17,7 +17,7 @@ describe('search (integration)', () => { 'bar' ) - // Unregister the provider and ensure it's removed + // Unregister the provider and ensure it's removed. unsubscribe.unsubscribe() assert.deepStrictEqual( await clientController.registries.queryTransformer @@ -33,14 +33,14 @@ describe('search (integration)', () => { // Register the provider and call it extensionHost.search.registerQueryTransformer({ transformQuery: q => `${q} bar` }) - extensionHost.search.registerQueryTransformer({ transformQuery: q => `${q} baz` }) + extensionHost.search.registerQueryTransformer({ transformQuery: q => `${q} qux` }) await ready assert.deepStrictEqual( await clientController.registries.queryTransformer .transformQuery('foo') .pipe(take(1)) .toPromise(), - 'foo bar baz' + 'foo bar qux' ) }) }) diff --git a/src/sourcegraph.d.ts b/src/sourcegraph.d.ts index 81ba84e..7e99c1f 100644 --- a/src/sourcegraph.d.ts +++ b/src/sourcegraph.d.ts @@ -717,14 +717,6 @@ declare module 'sourcegraph' { ): ProviderResult } - export interface QueryTransformerProvider { - transformQuery(query: string): ProviderResult - } - - export namespace search { - export function registerQueryTransformer(provider: QueryTransformerProvider): Unsubscribable - } - export namespace languages { export function registerHoverProvider(selector: DocumentSelector, provider: HoverProvider): Unsubscribable @@ -793,6 +785,38 @@ declare module 'sourcegraph' { ): Unsubscribable } + /** + * A query transformer changes a user's query before passing it to the search backend. + * Query transformers allow extensions to define new search query operators and syntax, + * for example, by replacing certain custom operators (e.g. `go.imports:`) with a regular expression. + * + */ + export interface QueryTransformer { + /** + * Transforms a search query into another, valid query. If there are no transformations to be made + * the original query is returned. + * + * @param query A search query provided by a client. + */ + transformQuery(query: string): string | Promise + } + + /** + * Search functionality can be augmented by extensions. Extensions can register query transformers + * to alter queries provided by users. + */ + export namespace search { + /** + * Registers a query transformer. + * + * Multiple transformers can be registered. In that case, all transformers will be executed + * and the result is a single query that has been altered by all transformers. + * + * @param provider A query transformer. + */ + export function registerQueryTransformer(provider: QueryTransformer): Unsubscribable + } + /** * Commands are functions that are implemented and registered by extensions. Extensions can invoke any command * (including commands registered by other extensions). The extension can also define contributions (in From c112fa70f3419660376fad5bdb072009b2f3e738 Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Fri, 26 Oct 2018 11:49:54 -0700 Subject: [PATCH 13/17] fix: remove unneeded internal tsdoc directives --- src/extension/api/search.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/extension/api/search.ts b/src/extension/api/search.ts index ea8863b..90f989e 100644 --- a/src/extension/api/search.ts +++ b/src/extension/api/search.ts @@ -3,12 +3,10 @@ import { QueryTransformer } from 'sourcegraph' import { SearchAPI } from 'src/client/api/search' import { ProviderMap } from './common' -/** @internal */ export interface ExtSearchAPI { $transformQuery: (id: number, query: string) => Promise } -/** @internal */ export class ExtSearch implements ExtSearchAPI { private registrations = new ProviderMap(id => this.proxy.$unregister(id)) constructor(private proxy: SearchAPI) {} From 61756bc2ecc91bbeba12343156d2a12294f484e3 Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Fri, 26 Oct 2018 13:15:49 -0700 Subject: [PATCH 14/17] fix: add string as transform query return type --- src/client/providers/queryTransformer.ts | 2 +- src/extension/api/search.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/client/providers/queryTransformer.ts b/src/client/providers/queryTransformer.ts index ae32f24..2621cb2 100644 --- a/src/client/providers/queryTransformer.ts +++ b/src/client/providers/queryTransformer.ts @@ -22,7 +22,7 @@ export function transformQuery(providers: Observable, return providers.pipe( switchMap(providers => { if (providers.length === 0) { - return [query] + return query } return providers.reduce( (currentQuery, transformQuery) => diff --git a/src/extension/api/search.ts b/src/extension/api/search.ts index 90f989e..13f674c 100644 --- a/src/extension/api/search.ts +++ b/src/extension/api/search.ts @@ -4,7 +4,7 @@ import { SearchAPI } from 'src/client/api/search' import { ProviderMap } from './common' export interface ExtSearchAPI { - $transformQuery: (id: number, query: string) => Promise + $transformQuery: (id: number, query: string) => string | Promise } export class ExtSearch implements ExtSearchAPI { @@ -17,8 +17,8 @@ export class ExtSearch implements ExtSearchAPI { return subscription } - public $transformQuery(id: number, query: string): Promise { + public $transformQuery(id: number, query: string): string | Promise { const provider = this.registrations.get(id) - return Promise.resolve(provider.transformQuery(query)) + return provider.transformQuery(query) } } From f1326e366f1c5538c90ae5dcbe290a4b2ddefe18 Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Fri, 26 Oct 2018 13:56:06 -0700 Subject: [PATCH 15/17] Revert "fix: add string as transform query return type" This reverts commit 61756bc2ecc91bbeba12343156d2a12294f484e3. --- src/client/providers/queryTransformer.ts | 2 +- src/extension/api/search.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/client/providers/queryTransformer.ts b/src/client/providers/queryTransformer.ts index 2621cb2..ae32f24 100644 --- a/src/client/providers/queryTransformer.ts +++ b/src/client/providers/queryTransformer.ts @@ -22,7 +22,7 @@ export function transformQuery(providers: Observable, return providers.pipe( switchMap(providers => { if (providers.length === 0) { - return query + return [query] } return providers.reduce( (currentQuery, transformQuery) => diff --git a/src/extension/api/search.ts b/src/extension/api/search.ts index 13f674c..90f989e 100644 --- a/src/extension/api/search.ts +++ b/src/extension/api/search.ts @@ -4,7 +4,7 @@ import { SearchAPI } from 'src/client/api/search' import { ProviderMap } from './common' export interface ExtSearchAPI { - $transformQuery: (id: number, query: string) => string | Promise + $transformQuery: (id: number, query: string) => Promise } export class ExtSearch implements ExtSearchAPI { @@ -17,8 +17,8 @@ export class ExtSearch implements ExtSearchAPI { return subscription } - public $transformQuery(id: number, query: string): string | Promise { + public $transformQuery(id: number, query: string): Promise { const provider = this.registrations.get(id) - return provider.transformQuery(query) + return Promise.resolve(provider.transformQuery(query)) } } From 480071bdaf81463b8890b956cb26b8cd8c25e696 Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Fri, 26 Oct 2018 14:46:57 -0700 Subject: [PATCH 16/17] fix: update docs --- src/sourcegraph.d.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sourcegraph.d.ts b/src/sourcegraph.d.ts index 7e99c1f..258dc89 100644 --- a/src/sourcegraph.d.ts +++ b/src/sourcegraph.d.ts @@ -786,10 +786,10 @@ declare module 'sourcegraph' { } /** - * A query transformer changes a user's query before passing it to the search backend. - * Query transformers allow extensions to define new search query operators and syntax, - * for example, by replacing certain custom operators (e.g. `go.imports:`) with a regular expression. + * A query transformer alters a user's search query before executing a search. * + * Query transformers allow extensions to define new search query operators and syntax, for example, + * by matching strings in a query (e.g. `go.imports:`) and replacing them with a regular expression or string. */ export interface QueryTransformer { /** @@ -802,8 +802,7 @@ declare module 'sourcegraph' { } /** - * Search functionality can be augmented by extensions. Extensions can register query transformers - * to alter queries provided by users. + * API for extensions to augment search functionality. */ export namespace search { /** From 4c57caee474fff019d621f7a86b1fb7edd31ed33 Mon Sep 17 00:00:00 2001 From: Farhan Attamimi Date: Fri, 26 Oct 2018 14:56:36 -0700 Subject: [PATCH 17/17] fix: docs --- src/sourcegraph.d.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sourcegraph.d.ts b/src/sourcegraph.d.ts index 258dc89..097ccf2 100644 --- a/src/sourcegraph.d.ts +++ b/src/sourcegraph.d.ts @@ -796,7 +796,7 @@ declare module 'sourcegraph' { * Transforms a search query into another, valid query. If there are no transformations to be made * the original query is returned. * - * @param query A search query provided by a client. + * @param query A search query. */ transformQuery(query: string): string | Promise } @@ -808,8 +808,9 @@ declare module 'sourcegraph' { /** * Registers a query transformer. * - * Multiple transformers can be registered. In that case, all transformers will be executed - * and the result is a single query that has been altered by all transformers. + * Multiple transformers can be registered. In that case, all transformations will be applied + * and the result is a single query that has been altered by all transformers. The order in + * which transfomers are applied is not defined. * * @param provider A query transformer. */