Skip to content

Commit

Permalink
Merge pull request #156 from Vidminas/fix-relpaths
Browse files Browse the repository at this point in the history
Fix relative paths and schema changes
  • Loading branch information
JPinkney committed Jun 19, 2019
2 parents 9e87727 + 5df322e commit 8f4f75a
Show file tree
Hide file tree
Showing 6 changed files with 565 additions and 287 deletions.
13 changes: 10 additions & 3 deletions src/languageservice/services/jsonSchemaService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -539,9 +539,16 @@ export class JSONSchemaService implements IJSONSchemaService {
return this.promise.resolve(null);
};
if (this.customSchemaProvider) {
return this.customSchemaProvider(resource).then(schemaUri =>
this.loadSchema(schemaUri).then(unsolvedSchema => this.resolveSchemaContent(unsolvedSchema, schemaUri))).then(schema => schema, err =>
resolveSchema());
return this.customSchemaProvider(resource)
.then(schemaUri => {
if (!schemaUri) {
return resolveSchema();
}

this.loadSchema(schemaUri)
.then(unsolvedSchema => this.resolveSchemaContent(unsolvedSchema, schemaUri))
})
.then(schema => schema, err => resolveSchema());
} else {
return resolveSchema();
}
Expand Down
69 changes: 69 additions & 0 deletions src/languageservice/services/schemaRequestHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { URI } from 'vscode-uri';
import { IConnection } from 'vscode-languageserver';
import { xhr, XHRResponse, getErrorStatusDescription } from 'request-light';
import fs = require('fs');


import { VSCodeContentRequest, CustomSchemaContentRequest } from '../../requestTypes';
import { isRelativePath, relativeToAbsolutePath } from '../utils/paths';

/**
* Handles schema content requests given the schema URI
* @param uri can be a local file, vscode request, http(s) request or a custom request
*/
export const schemaRequestHandler = (connection: IConnection, uri: string): Thenable<string> => {
if (!uri) {
return Promise.reject('No schema specified');
}

// If the requested schema URI is a relative file path
// Convert it into a proper absolute path URI
if (isRelativePath(uri)) {
uri = relativeToAbsolutePath(this.workspaceFolders, this.workspaceRoot, uri);
}

const scheme = URI.parse(uri).scheme.toLowerCase();

// If the requested schema is a local file, read and return the file contents
if (scheme === 'file') {
const fsPath = URI.parse(uri).fsPath;

return new Promise<string>((c, e) => {
fs.readFile(fsPath, 'UTF-8', (err, result) =>
// If there was an error reading the file, return empty error message
// Otherwise return the file contents as a string
err ? e('') : c(result.toString())
);
});
}

// vscode schema content requests are forwarded to the client through LSP
// This is a non-standard LSP extension introduced by the JSON language server
// See https://github.com/microsoft/vscode/blob/master/extensions/json-language-features/server/README.md
if (scheme === 'vscode') {
return connection.sendRequest(VSCodeContentRequest.type, uri)
.then(responseText => responseText, error => error.message);
}

// HTTP(S) requests are sent and the response result is either the schema content or an error
if (scheme === 'http' || scheme === 'https') {
// If it's an HTTP(S) request to Microsoft Azure, log the request
if (uri.indexOf('//schema.management.azure.com/') !== -1) {
connection.telemetry.logEvent({
key: 'json.schema',
value: {
schemaURL: uri
}
});
}

// Send the HTTP(S) schema content request and return the result
const headers = { 'Accept-Encoding': 'gzip, deflate' };
return xhr({ url: uri, followRedirects: 5, headers })
.then(response => response.responseText,
(error: XHRResponse) => Promise.reject(error.responseText || getErrorStatusDescription(error.status) || error.toString()));
}

// Neither local file nor vscode, nor HTTP(S) schema request, so send it off as a custom request
return connection.sendRequest(CustomSchemaContentRequest.type, uri) as Thenable<string>;
};
32 changes: 32 additions & 0 deletions src/languageservice/utils/paths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { WorkspaceFolder } from 'vscode-languageserver';
import { join, normalize } from 'path';
import { URI } from 'vscode-uri';

export const isRelativePath = (path: string): boolean => {
const relativePathRegex = /^(((\.\.?)|([\w-\. ]+))(\/|\\\\?))*[\w-\. ]*\.[\w-]+$/i;
return relativePathRegex.test(path);
};

export const relativeToAbsolutePath = (workspaceFolders: WorkspaceFolder[], workspaceRoot: URI, uri: string): string => {
// Iterate through all of the workspace root folders
for (const folder of workspaceFolders) {
// If the requested schema URI specifies a workspace root folder
// Convert it into an absolute path with the appropriate root folder path
if (uri.startsWith(folder.name)) {
const pathToFolder = URI.parse(folder.uri).fsPath;
const withoutFolderPrefix = uri.split(folder.name);
withoutFolderPrefix.shift();

return URI.file(join(pathToFolder, withoutFolderPrefix.join())).toString();
}
}

// If a root folder was not specified, resolve the relative URI
// Against the location of the workspace file instead
if (workspaceRoot) {
return URI.file(join(workspaceRoot.fsPath, uri)).toString();
}

// Fallback in case nothing could be applied
return normalize(uri);
};
25 changes: 25 additions & 0 deletions src/requestTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { NotificationType, RequestType } from 'vscode-languageserver';

export namespace SchemaAssociationNotification {
export const type: NotificationType<{ }, { }> = new NotificationType('json/schemaAssociations');
}

export namespace DynamicCustomSchemaRequestRegistration {
export const type: NotificationType<{ }, { }> = new NotificationType('yaml/registerCustomSchemaRequest');
}

export namespace VSCodeContentRequest {
export const type: RequestType<{ }, { }, { }, { }> = new RequestType('vscode/content');
}

export namespace CustomSchemaContentRequest {
export const type: RequestType<{ }, { }, { }, { }> = new RequestType('custom/schema/content');
}

export namespace CustomSchemaRequest {
export const type: RequestType<{ }, { }, { }, { }> = new RequestType('custom/schema/request');
}

export namespace ColorSymbolRequest {
export const type: RequestType<{ }, { }, { }, { }> = new RequestType('json/colorSymbols');
}

0 comments on commit 8f4f75a

Please sign in to comment.