Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support contributes.jsonValidation VSCode API. #7560

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

- [task] fixed presentation.reveal & focus for detected tasks [#7548](https://github.com/eclipse-theia/theia/pull/7548)

- [json] support `contributes.jsonValidation` VSCode API. [#7545](https://github.com/eclipse-theia/theia/pull/7560)

Breaking changes:

- [core] `CommandRegistry.registerHandler` registers a new handler with a higher priority than previous [#7539](https://github.com/eclipse-theia/theia/pull/7539)
Expand All @@ -14,6 +16,7 @@ Use `PluginManager.configStorage` property instead. [#7265](https://github.com/e

## v1.0.0

- [core] `CommandRegistry#getAllHandlers` returns with the reversed order of handlers, so if a command has multiple handlers, any handler is considered to be more specific than the other subsequent handlers in the array. In other words, if `@theia/core` contributes a handler for a particular command and your extension also contributes a handler for the same command, the handler from your extension will have `0` index, and the handler from `@theia/core` will have `1` index when calling `getAllHandlers`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should not be here. How did you get it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oy probably via a rebase to update my local branch

- [core] added functionality to ensure that nodes are refreshed properly on tree expansion [#7400](https://github.com/eclipse-theia/theia/pull/7400)
- [core] added loading state for trees [#7249](https://github.com/eclipse-theia/theia/pull/7249)
- [core] added the ability to customize the layout of view-containers [#6655](https://github.com/eclipse-theia/theia/pull/6655)
Expand Down
19 changes: 12 additions & 7 deletions packages/json/src/browser/json-client-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import URI from '@theia/core/lib/common/uri';
import { JsonPreferences } from './json-preferences';
import { JsonSchemaStore } from '@theia/core/lib/browser/json-schema-store';
import { Endpoint } from '@theia/core/lib/browser';
import { JsonValidationContributionsRegistry } from './json-validation-registry';

@injectable()
export class JsonClientContribution extends BaseLanguageClientContribution {
Expand All @@ -42,18 +43,22 @@ export class JsonClientContribution extends BaseLanguageClientContribution {
@inject(Languages) protected readonly languages: Languages,
@inject(LanguageClientFactory) protected readonly languageClientFactory: LanguageClientFactory,
@inject(JsonPreferences) protected readonly preferences: JsonPreferences,
@inject(JsonSchemaStore) protected readonly jsonSchemaStore: JsonSchemaStore
) {
@inject(JsonSchemaStore) protected readonly jsonSchemaStore: JsonSchemaStore,
@inject(JsonValidationContributionsRegistry) protected readonly jsonValidationContributionsRegistry: JsonValidationContributionsRegistry
) {
super(workspace, languages, languageClientFactory);
this.initializeJsonSchemaAssociations();
}

protected updateSchemas(client: ILanguageClient): void {
const allConfigs = [...this.jsonSchemaStore.getJsonSchemaConfigurations()];
const config = this.preferences['json.schemas'];
if (config instanceof Array) {
allConfigs.push(...config);
}
const schemaStoreConfigs = this.jsonSchemaStore.getJsonSchemaConfigurations();
const pluginContributionConfigs = this.jsonValidationContributionsRegistry.getJsonValidations();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

such configs can be registered dynamically, i.e. a user install or uninstall new extension. registry should fire an event and contribution should trigger updateSchemas then

const preferencesConfigs = this.preferences['json.schemas'] instanceof Array ? this.preferences['json.schemas'] : [];

// The order of combining the schema configs is very important as it implies a precedence.
// Given multiple *identical** fileMatch properties, The **last** schema will take precedence.
// This means: schemaStore < pluginContribution < preferences
const allConfigs = [...schemaStoreConfigs, ...pluginContributionConfigs, ...preferencesConfigs];
const registry: { [pattern: string]: string[] } = {};
for (const s of allConfigs) {
if (s.fileMatch) {
Expand Down
2 changes: 2 additions & 0 deletions packages/json/src/browser/json-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ import { ContainerModule } from 'inversify';
import { LanguageClientContribution } from '@theia/languages/lib/browser';
import { JsonClientContribution } from './json-client-contribution';
import { bindJsonPreferences } from './json-preferences';
import { JsonValidationContributionsRegistry } from './json-validation-registry';

export default new ContainerModule(bind => {
bindJsonPreferences(bind);

bind(LanguageClientContribution).to(JsonClientContribution).inSingletonScope();
bind(JsonValidationContributionsRegistry).toSelf().inSingletonScope();
});
39 changes: 39 additions & 0 deletions packages/json/src/browser/json-validation-registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/********************************************************************************
* Copyright (c) 2020 SAP SE or an SAP affiliate company and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { injectable } from 'inversify';
import { Disposable } from '@theia/core/lib/common/disposable';
import { deepClone } from '@theia/core';
import { JsonSchemaConfiguration } from '@theia/core/lib/browser/json-schema-store';

@injectable()
/**
* Holds JSON Validation contributions from plugins / VSCode extensions.
* - https://code.visualstudio.com/api/references/contribution-points#contributes.jsonValidation
*/
export class JsonValidationContributionsRegistry {

protected readonly registry: JsonSchemaConfiguration[] = [];

registerJsonValidation(jsonValidationEntry: JsonSchemaConfiguration): Disposable {
akosyakov marked this conversation as resolved.
Show resolved Hide resolved
this.registry.push(jsonValidationEntry);
return Disposable.NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disposable.NULL is bogus, please use JsonSchemaStore.registerSchema instead. it has a proper logic to unregster configuration

Copy link
Member

@akosyakov akosyakov Apr 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bd82 It was not addressed, this should remove entry from this.registry and json language server should be notified about it as well

}

getJsonValidations(): JsonSchemaConfiguration[] {
return deepClone(this.registry);
}
}
3 changes: 3 additions & 0 deletions packages/plugin-ext/compile.tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
},
{
"path": "../callhierarchy/compile.tsconfig.json"
},
{
"path": "../json/compile.tsconfig.json"
}
]
}
1 change: 1 addition & 0 deletions packages/plugin-ext/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"@theia/editor": "^1.0.0",
"@theia/file-search": "^1.0.0",
"@theia/filesystem": "^1.0.0",
"@theia/json": "^1.0.0",
Copy link
Member

@akosyakov akosyakov Apr 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't need this dependency, we only need to register configuration in core json schema storage

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@benoitf @tolusha It goes against #6647, are you fine with it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@azatsarynnyy Do you know whether introducing such dependency will cause issues in Che? i.e. do you use json vscode built-in extensions already?

"@theia/languages": "^1.0.0",
"@theia/markers": "^1.0.0",
"@theia/messages": "^1.0.0",
Expand Down
12 changes: 12 additions & 0 deletions packages/plugin-ext/src/common/plugin-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export interface PluginPackageContribution {
keybindings?: PluginPackageKeybinding | PluginPackageKeybinding[];
debuggers?: PluginPackageDebuggersContribution[];
snippets: PluginPackageSnippetsContribution[];
jsonValidation?: PluginJsonValidationContribution[];
themes?: PluginThemeContribution[];
iconThemes?: PluginIconThemeContribution[];
colors?: PluginColorContribution[];
Expand Down Expand Up @@ -139,6 +140,11 @@ export interface PluginPackageSnippetsContribution {
path?: string;
}

export interface PluginJsonValidationContribution {
akosyakov marked this conversation as resolved.
Show resolved Hide resolved
fileMatch: string | string[],
url: string
}

export interface PluginColorContribution {
id?: string;
description?: string;
Expand Down Expand Up @@ -469,6 +475,7 @@ export interface PluginContribution {
keybindings?: Keybinding[];
debuggers?: DebuggerContribution[];
snippets?: SnippetContribution[];
jsonValidations?: JsonValidationContribution[];
themes?: ThemeContribution[];
iconThemes?: IconThemeContribution[];
colors?: ColorDefinition[];
Expand All @@ -483,6 +490,11 @@ export interface SnippetContribution {
language?: string
}

export interface JsonValidationContribution {
fileMatch: string,
url: string
}

export type UiTheme = 'vs' | 'vs-dark' | 'hc-black';

export interface ThemeContribution {
Expand Down
36 changes: 35 additions & 1 deletion packages/plugin-ext/src/hosted/node/scanners/scanner-theia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ import {
PluginCommand,
IconUrl,
ThemeContribution,
IconThemeContribution
IconThemeContribution,
JsonValidationContribution
} from '../../../common/plugin-protocol';
import * as fs from 'fs';
import * as path from 'path';
Expand Down Expand Up @@ -277,6 +278,12 @@ export class TheiaPluginScanner implements PluginScanner {
console.error(`Could not read '${rawPlugin.name}' contribution 'snippets'.`, rawPlugin.contributes!.snippets, err);
}

try {
contributions.jsonValidations = this.readJsonValidations(rawPlugin);
} catch (err) {
console.error(`Could not read '${rawPlugin.name}' contribution 'jsonValidation'.`, rawPlugin.contributes!.jsonValidation, err);
}

try {
contributions.themes = this.readThemes(rawPlugin);
} catch (err) {
Expand Down Expand Up @@ -413,6 +420,33 @@ export class TheiaPluginScanner implements PluginScanner {
return result;
}

protected readJsonValidations(pck: PluginPackage): JsonValidationContribution[] | undefined {
if (!pck.contributes || !pck.contributes.jsonValidation) {
return undefined;
}
const result: JsonValidationContribution[] = [];
const addSingleValidation = (fileMatch: string, url: string) => {
if (typeof fileMatch === 'string') {
result.push({
fileMatch: fileMatch,
url: url
});
}
};
for (const contribution of pck.contributes.jsonValidation) {
if (typeof contribution.url === 'string') {
if (typeof contribution.fileMatch === 'string') {
addSingleValidation(contribution.fileMatch, contribution.url);
} else if (Array.isArray(contribution.fileMatch)) {
contribution.fileMatch.forEach(fileMatchItem => {
addSingleValidation(fileMatchItem, contribution.url);
});
}
}
}
return result;
}

protected readJson<T>(filePath: string): T | undefined {
const content = this.readFileSync(filePath);
return content ? jsoncparser.parse(content, undefined, { disallowComments: false }) : undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { DebugSchemaUpdater } from '@theia/debug/lib/browser/debug-schema-update
import { MonacoThemingService } from '@theia/monaco/lib/browser/monaco-theming-service';
import { ColorRegistry } from '@theia/core/lib/browser/color-registry';
import { PluginIconThemeService } from './plugin-icon-theme-service';
import { JsonValidationContributionsRegistry } from '@theia/json/lib/browser/json-validation-registry';

@injectable()
export class PluginContributionHandler {
Expand Down Expand Up @@ -61,6 +62,9 @@ export class PluginContributionHandler {
@inject(MonacoSnippetSuggestProvider)
protected readonly snippetSuggestProvider: MonacoSnippetSuggestProvider;

@inject(JsonValidationContributionsRegistry)
protected readonly jsonValidationContributionsRegistry: JsonValidationContributionsRegistry;

@inject(CommandRegistry)
protected readonly commands: CommandRegistry;

Expand Down Expand Up @@ -254,6 +258,17 @@ export class PluginContributionHandler {
}
}

if (contributions.jsonValidations) {
for (const jsonValidation of contributions.jsonValidations) {
pushContribution(
`jsonValidation.${jsonValidation.url}`,
() => this.jsonValidationContributionsRegistry.registerJsonValidation( {
url: jsonValidation.url,
fileMatch: [jsonValidation.fileMatch]
}));
}
}

if (contributions.themes && contributions.themes.length) {
const pending = {};
for (const theme of contributions.themes) {
Expand Down