Skip to content

Commit

Permalink
Load schema content contributed by other extensions (#451)
Browse files Browse the repository at this point in the history
* Load schema content contributed by other extensions

Signed-off-by: Yevhen Vydolob <[email protected]>

* Fix review comments

Signed-off-by: Yevhen Vydolob <[email protected]>

* update readme with way to disable code lens

Signed-off-by: Yevhen Vydolob <[email protected]>
  • Loading branch information
evidolob authored Mar 24, 2021
1 parent c011045 commit 3d82d61
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 8 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,12 @@ The following settings are supported:
- `yaml.schemas`: Helps you associate schemas with files in a glob pattern
- `yaml.schemaStore.enable`: When set to true the YAML language server will pull in all available schemas from [JSON Schema Store](http://schemastore.org/json/)
- `yaml.customTags`: Array of custom tags that the parser will validate against. It has two ways to be used. Either an item in the array is a custom tag such as "!Ref" and it will automatically map !Ref to scalar or you can specify the type of the object !Ref should be e.g. "!Ref sequence". The type of object can be either scalar (for strings and booleans), sequence (for arrays), mapping (for objects).
- `[yaml]`: VSCode-YAML adds default configuration for all yaml files. More specifically it converts tabs to spaces to ensure valid yaml, sets the tab size, and allows live typing autocompletion and formatting. These settings can be modified via the corresponding settings inside the `[yaml]` section in the settings:
- `[yaml]`: VSCode-YAML adds default configuration for all yaml files. More specifically it converts tabs to spaces to ensure valid yaml, sets the tab size, and allows live typing autocompletion and formatting, also allows code lens. These settings can be modified via the corresponding settings inside the `[yaml]` section in the settings:
- `editor.insertSpaces`
- `editor.tabSize`
- `editor.quickSuggestions`
- `editor.formatOnType`
- `editor.codeLens`

##### Adding custom tags

Expand Down
5 changes: 4 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,10 @@ export function activate(context: ExtensionContext): SchemaExtensionAPI {
// client can be deactivated on extension deactivation
context.subscriptions.push(disposable);
context.subscriptions.push(
workspace.registerTextDocumentContentProvider('json-schema', new JSONSchemaDocumentContentProvider(schemaCache))
workspace.registerTextDocumentContentProvider(
'json-schema',
new JSONSchemaDocumentContentProvider(schemaCache, schemaExtensionAPI)
)
);

findConflicts();
Expand Down
32 changes: 28 additions & 4 deletions src/json-schema-content-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,38 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { TextDocumentContentProvider, Uri, ProviderResult, workspace } from 'vscode';
import { TextDocumentContentProvider, Uri, workspace, window } from 'vscode';
import { xhr, configure as configureHttpRequests, getErrorStatusDescription, XHRResponse } from 'request-light';
import { JSONSchemaCache } from './json-schema-cache';
import { SchemaExtensionAPI } from './schema-extension-api';

export class JSONSchemaDocumentContentProvider implements TextDocumentContentProvider {
constructor(private readonly schemaCache: JSONSchemaCache) {}
provideTextDocumentContent(uri: Uri): ProviderResult<string> {
return getJsonSchemaContent(uri.toString().replace('json-schema://', 'https://'), this.schemaCache);
constructor(private readonly schemaCache: JSONSchemaCache, private readonly schemaApi: SchemaExtensionAPI) {}
async provideTextDocumentContent(uri: Uri): Promise<string> {
if (uri.fragment) {
const origUri = uri.fragment;
const schemaUri = Uri.parse(origUri);
// handle both 'http' and 'https'
if (origUri.startsWith('http')) {
return getJsonSchemaContent(origUri, this.schemaCache);
} else if (this.schemaApi.hasProvider(schemaUri.scheme)) {
let content = this.schemaApi.requestCustomSchemaContent(origUri);

content = await Promise.resolve(content);
// prettify JSON
if (content.indexOf('\n') === -1) {
content = JSON.stringify(JSON.parse(content), null, 2);
}

return content;
} else {
window.showErrorMessage(`Cannot Load content for: ${origUri}. Unknown schema: '${schemaUri.scheme}'`);
return null;
}
} else {
window.showErrorMessage(`Cannot Load content for: '${uri.toString()}' `);
return null;
}
}
}

Expand Down
8 changes: 6 additions & 2 deletions src/schema-extension-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { logToExtensionOutputChannel } from './extension';

interface SchemaContributorProvider {
readonly requestSchema: (resource: string) => string;
readonly requestSchemaContent: (uri: string) => string;
readonly requestSchemaContent: (uri: string) => Promise<string> | string;
readonly label?: string;
}

Expand Down Expand Up @@ -137,7 +137,7 @@ class SchemaExtensionAPI implements ExtensionAPI {
* @param {string} uri the schema uri returned from requestSchema.
* @returns {string} the schema content
*/
public requestCustomSchemaContent(uri: string): string {
public requestCustomSchemaContent(uri: string): Promise<string> | string {
if (uri) {
const _uri = URI.parse(uri);

Expand All @@ -154,6 +154,10 @@ class SchemaExtensionAPI implements ExtensionAPI {
public async modifySchemaContent(schemaModifications: SchemaAdditions | SchemaDeletions): Promise<void> {
return this._yamlClient.sendRequest(SchemaModificationNotification.type, schemaModifications);
}

public hasProvider(schema: string): boolean {
return this._customSchemaContributors[schema] !== undefined;
}
}

// constants
Expand Down
44 changes: 44 additions & 0 deletions test/json-shema-content-provider.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { getDocUri, activate } from './helper';
import * as assert from 'assert';

describe('Tests for JSON Schema content provider', () => {
const SCHEMA = 'myschema';
const schemaJSON = JSON.stringify({
type: 'object',
properties: {
version: {
type: 'string',
description: 'A stringy string string',
enum: ['test'],
},
},
});

function onRequestSchema1URI(resource: string): string | undefined {
if (resource.endsWith('completion.yaml') || resource.endsWith('basic.yaml')) {
return `${SCHEMA}://schema/porter`;
}
return undefined;
}

function onRequestSchema1Content(): string | undefined {
return schemaJSON;
}

it('should handle "json-schema" url', async () => {
const docUri = getDocUri('completion/completion.yaml');
const client = await activate(docUri);
client._customSchemaContributors = {};
client.registerContributor(SCHEMA, onRequestSchema1URI, onRequestSchema1Content);
const customUri = vscode.Uri.parse(`json-schema://some/url/schema.json#${SCHEMA}://some/path/schema.json`);
const doc = await vscode.workspace.openTextDocument(customUri);
const editor = await vscode.window.showTextDocument(doc);
assert.strictEqual(editor.document.getText(), JSON.stringify(JSON.parse(schemaJSON), null, 2));
client._customSchemaContributors = {};
});
});

0 comments on commit 3d82d61

Please sign in to comment.