Improve documentation around the language client implementation (#368)

* Document the language client implementation
* Fix indentation
This commit is contained in:
Winston Liu 2021-01-20 11:45:44 -05:00 коммит произвёл GitHub
Родитель e0139d040f
Коммит fc10946963
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 122 добавлений и 105 удалений

80
package-lock.json сгенерированный
Просмотреть файл

@ -55,9 +55,9 @@
"dev": true
},
"@types/node": {
"version": "7.0.43",
"resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.43.tgz",
"integrity": "sha512-7scYwwfHNppXvH/9JzakbVxk0o0QUILVk1Lv64GRaxwPuGpnF1QBiwdvhDpLcymb8BpomQL3KYoWKq3wUdDMhQ==",
"version": "12.19.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.11.tgz",
"integrity": "sha512-bwVfNTFZOrGXyiQ6t4B9sZerMSShWNsGRw8tC5DY1qImUNczS9SjT4G6PnzjCnxsu5Ubj6xjL2lgwddkxtQl5w==",
"dev": true
},
"@types/q": {
@ -94,9 +94,9 @@
"dev": true
},
"@types/vscode": {
"version": "1.45.1",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.45.1.tgz",
"integrity": "sha512-0NO9qrrEJBO8FsqHCrFMgR2suKnwCsKBWvRSb2OzH5gs4i3QO5AhEMQYrSzDbU/wLPt7N617/rN9lPY213gmwg==",
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.52.0.tgz",
"integrity": "sha512-Kt3bvWzAvvF/WH9YEcrCICDp0Z7aHhJGhLJ1BxeyNP6yRjonWqWnAIh35/pXAjswAnWOABrYlF7SwXR9+1nnLA==",
"dev": true
},
"@types/webpack": {
@ -809,8 +809,7 @@
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"base": {
"version": "0.11.2",
@ -942,7 +941,6 @@
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -1377,8 +1375,7 @@
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"concat-stream": {
"version": "1.6.2",
@ -3253,7 +3250,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -5645,9 +5641,9 @@
"dev": true
},
"typescript": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.1.tgz",
"integrity": "sha512-cTmIDFW7O0IHbn1DPYjkiebHxwtCMU+eTy30ZtJNBPF9j2O1ITu5XH2YnBeVRKWHqF+3JQwWJv0Q0aUgX8W7IA==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
"integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==",
"dev": true
},
"underscore": {
@ -5947,32 +5943,54 @@
"integrity": "sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A=="
},
"vscode-languageclient": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-5.2.1.tgz",
"integrity": "sha512-7jrS/9WnV0ruqPamN1nE7qCxn0phkH5LjSgSp9h6qoJGoeAKzwKz/PF6M+iGA/aklx4GLZg1prddhEPQtuXI1Q==",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-7.0.0.tgz",
"integrity": "sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg==",
"requires": {
"semver": "^5.5.0",
"vscode-languageserver-protocol": "3.14.1"
"minimatch": "^3.0.4",
"semver": "^7.3.4",
"vscode-languageserver-protocol": "3.16.0"
},
"dependencies": {
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
},
"semver": {
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
"integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
"requires": {
"lru-cache": "^6.0.0"
}
},
"vscode-jsonrpc": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz",
"integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg=="
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz",
"integrity": "sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg=="
},
"vscode-languageserver-protocol": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz",
"integrity": "sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g==",
"version": "3.16.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz",
"integrity": "sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==",
"requires": {
"vscode-jsonrpc": "^4.0.0",
"vscode-languageserver-types": "3.14.0"
"vscode-jsonrpc": "6.0.0",
"vscode-languageserver-types": "3.16.0"
}
},
"vscode-languageserver-types": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz",
"integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A=="
"version": "3.16.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz",
"integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA=="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
},

Просмотреть файл

@ -140,7 +140,7 @@
"@types/fs-extra": "4.0.5",
"@types/mocha": "5.2.5",
"@types/mustache": "0.8.32",
"@types/node": "7.0.43",
"@types/node": "^12.0.0",
"@types/q": "1.5.0",
"@types/underscore": "1.8.9",
"@types/vscode": "^1.45.1",
@ -150,7 +150,7 @@
"mocha": "5.2.0",
"ts-node": "7.0.1",
"tslint": "5.8.0",
"typescript": "3.3.1",
"typescript": "^4.1.0",
"vscode-azureextensiondev": "^0.4.0",
"vscode-test": "^1.3.0"
},
@ -167,7 +167,7 @@
"uuid": "^3.3.2",
"vscode-azureextensionui": "0.26.3",
"vscode-extension-telemetry": "0.0.18",
"vscode-languageclient": "5.2.1",
"vscode-languageclient": "^7.0.0",
"vscode-nls": "3.2.4",
"vscode-uri": "1.0.6"
},

Просмотреть файл

@ -78,7 +78,7 @@ export class ServiceConnectionHelper {
}
private async sleepForMilliSeconds(timeInMs: number) {
return new Promise((resolve) => {
return new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, timeInMs);

Просмотреть файл

@ -6,7 +6,7 @@
import * as path from 'path';
import * as vscode from 'vscode';
import { createTelemetryReporter, callWithTelemetryAndErrorHandling, IActionContext, AzureUserInput, registerUIExtensionVariables } from 'vscode-azureextensionui';
import * as languageclient from 'vscode-languageclient';
import * as languageclient from 'vscode-languageclient/node';
import { extensionVariables } from './configure/model/models';
import * as logger from './logger';
@ -62,38 +62,36 @@ async function activateYmlContributor(context: vscode.ExtensionContext) {
const initialSchemaAssociations = schemaAssociationService.getSchemaAssociation();
await client.onReady().then(() => {
//logger.log(`${JSON.stringify(initialSchemaAssociations)}`, 'SendInitialSchemaAssociation');
// Notify the server which schemas to use.
client.sendNotification(SchemaAssociationNotification.type, initialSchemaAssociations);
// TODO: Should we get rid of these events and handle other events like Ctrl + Space? See when this event gets fired and send updated schema on that event.
client.onRequest(CUSTOM_SCHEMA_REQUEST, (resource: any) => {
//logger.log('Custom schema request. Resource: ' + JSON.stringify(resource), 'CustomSchemaRequest');
// TODO: Can this return the location of the new schema file?
return schemaContributor.requestCustomSchema(resource); // TODO: Have a single instance for the extension but dont return a global from this namespace.
// Fired whenever the server is about to validate a YAML file (e.g. on content change),
// and allows us to return a custom schema to use for validation.
client.onRequest(CUSTOM_SCHEMA_REQUEST, (resource: string) => {
// TODO: Have a single instance for the extension but dont return a global from this namespace
return schemaContributor.requestCustomSchema(resource);
});
// TODO: Can we get rid of this? Never seems to happen.
client.onRequest(CUSTOM_CONTENT_REQUEST, (uri: any) => {
//logger.log('Custom content request.', 'CustomContentRequest');
// Fired whenever the server encounters a URI scheme that it doesn't recognize,
// and allows us to use the URI to determine the schema's content.
client.onRequest(CUSTOM_CONTENT_REQUEST, (uri: string) => {
return schemaContributor.requestCustomSchemaContent(uri);
});
})
.catch((reason) => {
logger.log(JSON.stringify(reason), 'ClientOnReadyError');
extensionVariables.reporter.sendTelemetryEvent('extension.languageserver.onReadyError', { 'reason': JSON.stringify(reason) });
});
}).catch((reason) => {
logger.log(JSON.stringify(reason), 'ClientOnReadyError');
extensionVariables.reporter.sendTelemetryEvent('extension.languageserver.onReadyError', { 'reason': JSON.stringify(reason) });
});
// TODO: Can we get rid of this since it's set in package.json?
vscode.languages.setLanguageConfiguration('azure-pipelines', { wordPattern: /("(?:[^\\\"]*(?:\\.)?)*"?)|[^\s{}\[\],:]+/ });
// when config changes, refresh the schema
vscode.workspace.onDidChangeConfiguration(e => {
schemaAssociationService.locateSchemaFile();
const newSchema = schemaAssociationService.getSchemaAssociation();
if (newSchema['*'][0] != initialSchemaAssociations['*'][0])
{
// Let the server know of any schema changes.
// TODO: move to schema-association-service?
vscode.workspace.onDidChangeConfiguration(event => {
if (event.affectsConfiguration('[azure-pipelines].customSchemaFile')) {
schemaAssociationService.locateSchemaFile();
const newSchema = schemaAssociationService.getSchemaAssociation();
vscode.window.showInformationMessage("Azure Pipelines schema changed. Restart VS Code to see the changes.");
// this _should_ cause the language server to refresh its config
// but that doesn't seem to be happening
@ -113,19 +111,17 @@ function getServerOptions(context: vscode.ExtensionContext): languageclient.Serv
function getClientOptions(): languageclient.LanguageClientOptions {
return {
// Register the server for plain text documents
// Register the server for Azure Pipelines documents
documentSelector: [
{ language: 'azure-pipelines', scheme: 'file' },
{ language: 'azure-pipelines', scheme: 'untitled' }
],
synchronize: {
// Synchronize the setting section 'languageServerExample' to the server
// TODO: Are these what settings we want to pass through to the server? Would be good to see this happening... And see initializeOptions. Maybe remove them?
// TODO: Switch to handling the workspace/configuration request
configurationSection: ['yaml', 'http.proxy', 'http.proxyStrictSSL'],
// Notify the server about file changes to '.clientrc files contain in the workspace
// Notify the server about file changes to YAML files in the workspace
fileEvents: [
vscode.workspace.createFileSystemWatcher('**/*.?(e)y?(a)ml'),
vscode.workspace.createFileSystemWatcher('**/*.json')
vscode.workspace.createFileSystemWatcher('**/*.?(e)y?(a)ml')
]
},
};

Просмотреть файл

@ -5,7 +5,7 @@
import * as path from 'path';
import * as vscode from 'vscode';
import * as languageclient from 'vscode-languageclient';
import * as languageclient from 'vscode-languageclient/node';
export interface ISchemaAssociationService {
getSchemaAssociation(): ISchemaAssociations;
@ -22,26 +22,35 @@ export class SchemaAssociationService implements ISchemaAssociationService {
this.locateSchemaFile();
}
// TODO: Should this inlined into getSchemaAssocations?
public locateSchemaFile() {
let alternateSchema = vscode.workspace.getConfiguration('[azure-pipelines]', null).get<string>('customSchemaFile');
let alternateSchema = vscode.workspace.getConfiguration('[azure-pipelines]').get<string>('customSchemaFile');
if (alternateSchema && !path.isAbsolute(alternateSchema)) {
alternateSchema = path.resolve(vscode.workspace.rootPath, alternateSchema);
alternateSchema = path.resolve(vscode.workspace.workspaceFolders[0].uri.fsPath, alternateSchema);
}
const schemaPath = alternateSchema || path.join(this.extensionPath, './service-schema.json');
this.schemaFilePath = vscode.Uri.file(schemaPath).toString();
}
// Looking at how the vscode-yaml extension does it, it looks like this is meant as a
// way for other extensions to hook into the validation process, not as something
// user-configurable.
// For our purposes, since we're only concerned with validating Azure Pipelines files,
// we don't need to worry about other extensions.
// TODO: We *could* make this configurable, but it'd probably make more sense to co-opt
// the existing yaml.schemas setting (and rename it to [azure-pipelines].schemas) that
// the server already looks for.
// That one is schema -> patterns, rather than pattern -> schemas.
public getSchemaAssociation(): ISchemaAssociations {
return { '*': [this.schemaFilePath] };
}
}
// TODO: Do we need this?
// Mapping of glob pattern -> schemas
export interface ISchemaAssociations {
[pattern: string]: string[];
}
// TODO: Do we need this?
export namespace SchemaAssociationNotification {
export const type: languageclient.NotificationType<ISchemaAssociations, any> = new languageclient.NotificationType('json/schemaAssociations');
export const type: languageclient.NotificationType<ISchemaAssociations> = new languageclient.NotificationType('json/schemaAssociations');
}

Просмотреть файл

@ -3,7 +3,6 @@
* Licensed under the MIT License.
*--------------------------------------------------------------------------------------------*/
import * as logger from './logger';
import Uri from 'vscode-uri'
interface SchemaContributorProvider {
@ -16,14 +15,15 @@ interface SchemaContributorProvider {
class SchemaContributor {
private _customSchemaContributors: { [index: string]: SchemaContributorProvider } = {};
/**
* Register a custom schema provider
*
* @param {string} the provider's name
* @param requestSchema the requestSchema function
* @param requestSchemaContent the requestSchemaContent function
* @returns {boolean}
*/
/**
* Register a custom schema provider.
* TODO: We might be able to use this to intelligently grab the schema for projects using Azure Repos.
*
* @param {string} schema the provider's name
* @param requestSchema the requestSchema function
* @param requestSchemaContent the requestSchemaContent function
* @returns {boolean}
*/
public registerContributor(schema: string,
requestSchema: (resource: string) => string,
requestSchemaContent: (uri: string) => string): boolean {
@ -43,42 +43,37 @@ class SchemaContributor {
return true;
}
// TODO: Rewrite comments.
/**
* Call requestSchema for each provider and find the first one who reports he can provide the schema.
*
* @param {string} resource
* @returns {string} the schema uri
*/
public requestCustomSchema(resource: string): string {
// TODO: This is what gets called on every request(I think), it's looking at the cached schema files. I think here is where we want to periodically
// check what's on the server. The code in schema-association-service.getSchemaAssociation()
// Check relationship with result of getSchemaAssociationFromYamlValidationNode. Does this load the files specified there? Make sure this code is needed.
/**
* Asks each schema provider whether it has a schema for the given resource,
* and returns the URI to the schema if it does.
*
* @param {string} resource the file to be validated
* @returns {string} the schema uri
*/
public requestCustomSchema(resource: string): string {
for (let customKey of Object.keys(this._customSchemaContributors)) {
const contributor = this._customSchemaContributors[customKey];
const uri = contributor.requestSchema(resource);
if (uri) {
return uri;
} else {
logger.log(`Uri NOT found for resource (${resource})`);
}
}
// TODO: This is currently the only way to fallback to the default schema provider.
// The upstream Red Hat server also falls back when receiving a falsy value,
// so sync with their changes and change this to return false or something.
throw `Unable to find custom schema for resource: '${resource}'`;
}
// TODO: Rewrite comments.
/**
* Call requestCustomSchemaContent for named provider and get the schema content.
*
* @param {string} uri the schema uri returned from requestSchema.
* @returns {string} the schema content
*/
/**
* If there is a schema provider that can handle the given URI,
* returns the schema content corresponding to the URI.
* TODO: If we stick to just local files and http(s), I doubt we need this.
*
* @param {string} uri the schema uri returned from requestSchema.
* @returns {string} the schema content
*/
public requestCustomSchemaContent(uri: string): string {
console.log('requestCustomSchemaContent');
if (uri) {
let _uri = Uri.parse(uri);
if (_uri.scheme && this._customSchemaContributors[_uri.scheme] &&
@ -94,9 +89,8 @@ class SchemaContributor {
// global instance
// TODO: Do this differently... why not instantiate? Static? Something else.
const schemaContributor = new SchemaContributor();
//schemaContributor.registerContributor("", "", "");
export const CUSTOM_SCHEMA_REQUEST = 'custom/schema/request';
export const CUSTOM_CONTENT_REQUEST = 'custom/schema/content';
export { schemaContributor } ;
export { schemaContributor } ;