Skip to content

Commit

Permalink
[plugin] fix #4621: apply only valid configurations as schemas
Browse files Browse the repository at this point in the history
Signed-off-by: Anton Kosyakov <anton.kosyakov@typefox.io>
  • Loading branch information
akosyakov committed Mar 21, 2019
1 parent 16d526d commit 6a07cec
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 129 deletions.
72 changes: 5 additions & 67 deletions packages/core/src/browser/preferences/preference-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ import { ContributionProvider, bindContributionProvider, escapeRegExpCharacters,
import { PreferenceScope } from './preference-scope';
import { PreferenceProvider, PreferenceProviderPriority, PreferenceProviderDataChange } from './preference-provider';

import {
PreferenceSchema, PreferenceSchemaProperties, PreferenceDataSchema, PreferenceItem, PreferenceSchemaProperty, PreferenceDataProperty, JsonType
} from '../../common/preferences/preference-schema';
export { PreferenceSchema, PreferenceSchemaProperties, PreferenceDataSchema, PreferenceItem, PreferenceSchemaProperty, PreferenceDataProperty, JsonType };

// tslint:disable:no-any
// tslint:disable:forin

Expand All @@ -28,73 +33,6 @@ export interface PreferenceContribution {
readonly schema: PreferenceSchema;
}

export interface PreferenceSchema {
[name: string]: any,
scope?: 'application' | 'window' | 'resource' | PreferenceScope,
overridable?: boolean;
properties: PreferenceSchemaProperties
}
export namespace PreferenceSchema {
export function getDefaultScope(schema: PreferenceSchema): PreferenceScope {
let defaultScope: PreferenceScope = PreferenceScope.Workspace;
if (!PreferenceScope.is(schema.scope)) {
defaultScope = PreferenceScope.fromString(<string>schema.scope) || PreferenceScope.Workspace;
} else {
defaultScope = schema.scope;
}
return defaultScope;
}
}

export interface PreferenceSchemaProperties {
[name: string]: PreferenceSchemaProperty
}

export interface PreferenceDataSchema {
[name: string]: any,
scope?: PreferenceScope,
properties: {
[name: string]: PreferenceDataProperty
}
patternProperties: {
[name: string]: PreferenceDataProperty
};
}

export interface PreferenceItem {
type?: JsonType | JsonType[];
minimum?: number;
default?: any;
enum?: string[];
items?: PreferenceItem;
properties?: { [name: string]: PreferenceItem };
additionalProperties?: object;
[name: string]: any;
overridable?: boolean;
}

export interface PreferenceSchemaProperty extends PreferenceItem {
description?: string;
scope?: 'application' | 'window' | 'resource' | PreferenceScope;
}

export interface PreferenceDataProperty extends PreferenceItem {
description?: string;
scope?: PreferenceScope;
}
export namespace PreferenceDataProperty {
export function fromPreferenceSchemaProperty(schemaProps: PreferenceSchemaProperty, defaultScope: PreferenceScope = PreferenceScope.Workspace): PreferenceDataProperty {
if (!schemaProps.scope) {
schemaProps.scope = defaultScope;
} else if (typeof schemaProps.scope === 'string') {
return Object.assign(schemaProps, { scope: PreferenceScope.fromString(schemaProps.scope) || defaultScope });
}
return <PreferenceDataProperty>schemaProps;
}
}

export type JsonType = 'string' | 'array' | 'number' | 'integer' | 'object' | 'boolean' | 'null';

export function bindPreferenceSchemaProvider(bind: interfaces.Bind): void {
bind(PreferenceSchemaProvider).toSelf().inSingletonScope();
bindContributionProvider(bind, PreferenceContribution);
Expand Down
51 changes: 2 additions & 49 deletions packages/core/src/browser/preferences/preference-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,52 +14,5 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

// tslint:disable:no-any

export enum PreferenceScope {
Default,
User,
Workspace,
Folder
}

export namespace PreferenceScope {
export function is(scope: any): scope is PreferenceScope {
return typeof scope === 'number' && getScopes().findIndex(s => s === scope) >= 0;
}

export function getScopes(): PreferenceScope[] {
return Object.keys(PreferenceScope)
.filter(k => typeof PreferenceScope[k as any] === 'string')
.map(v => <PreferenceScope>Number(v));
}

export function getReversedScopes(): PreferenceScope[] {
return getScopes().reverse();
}

export function getScopeNames(scope?: PreferenceScope): string[] {
const names: string[] = [];
const allNames = Object.keys(PreferenceScope)
.filter(k => typeof PreferenceScope[k as any] === 'number');
if (scope) {
for (const name of allNames) {
if ((<any>PreferenceScope)[name] <= scope) {
names.push(name);
}
}
}
return names;
}

export function fromString(strScope: string): PreferenceScope | undefined {
switch (strScope) {
case 'application':
return PreferenceScope.User;
case 'window':
return PreferenceScope.Workspace;
case 'resource':
return PreferenceScope.Folder;
}
}
}
import { PreferenceScope } from '../../common/preferences/preference-scope';
export { PreferenceScope };
94 changes: 94 additions & 0 deletions packages/core/src/common/preferences/preference-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/********************************************************************************
* Copyright (C) 2019 Ericsson 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
********************************************************************************/

// tslint:disable:no-any

import { PreferenceScope } from './preference-scope';

export interface PreferenceSchema {
[name: string]: any,
scope?: 'application' | 'window' | 'resource' | PreferenceScope,
overridable?: boolean;
properties: PreferenceSchemaProperties
}
export namespace PreferenceSchema {
export function is(obj: Object | undefined): obj is PreferenceSchema {
return !!obj && ('properties' in obj) && PreferenceSchemaProperties.is((<any>obj)['properties']);
}
export function getDefaultScope(schema: PreferenceSchema): PreferenceScope {
let defaultScope: PreferenceScope = PreferenceScope.Workspace;
if (!PreferenceScope.is(schema.scope)) {
defaultScope = PreferenceScope.fromString(<string>schema.scope) || PreferenceScope.Workspace;
} else {
defaultScope = schema.scope;
}
return defaultScope;
}
}

export interface PreferenceSchemaProperties {
[name: string]: PreferenceSchemaProperty
}
export namespace PreferenceSchemaProperties {
export function is(obj: Object | undefined): obj is PreferenceSchemaProperties {
return !!obj && typeof obj === 'object';
}
}

export interface PreferenceDataSchema {
[name: string]: any,
scope?: PreferenceScope,
properties: {
[name: string]: PreferenceDataProperty
}
patternProperties: {
[name: string]: PreferenceDataProperty
};
}

export interface PreferenceItem {
type?: JsonType | JsonType[];
minimum?: number;
default?: any;
enum?: string[];
items?: PreferenceItem;
properties?: { [name: string]: PreferenceItem };
additionalProperties?: object;
[name: string]: any;
overridable?: boolean;
}

export interface PreferenceSchemaProperty extends PreferenceItem {
description?: string;
scope?: 'application' | 'window' | 'resource' | PreferenceScope;
}

export interface PreferenceDataProperty extends PreferenceItem {
description?: string;
scope?: PreferenceScope;
}
export namespace PreferenceDataProperty {
export function fromPreferenceSchemaProperty(schemaProps: PreferenceSchemaProperty, defaultScope: PreferenceScope = PreferenceScope.Workspace): PreferenceDataProperty {
if (!schemaProps.scope) {
schemaProps.scope = defaultScope;
} else if (typeof schemaProps.scope === 'string') {
return Object.assign(schemaProps, { scope: PreferenceScope.fromString(schemaProps.scope) || defaultScope });
}
return <PreferenceDataProperty>schemaProps;
}
}

export type JsonType = 'string' | 'array' | 'number' | 'integer' | 'object' | 'boolean' | 'null';
65 changes: 65 additions & 0 deletions packages/core/src/common/preferences/preference-scope.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/********************************************************************************
* Copyright (C) 2019 Ericsson 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
********************************************************************************/

// tslint:disable:no-any

export enum PreferenceScope {
Default,
User,
Workspace,
Folder
}

export namespace PreferenceScope {
export function is(scope: any): scope is PreferenceScope {
return typeof scope === 'number' && getScopes().findIndex(s => s === scope) >= 0;
}

export function getScopes(): PreferenceScope[] {
return Object.keys(PreferenceScope)
.filter(k => typeof PreferenceScope[k as any] === 'string')
.map(v => <PreferenceScope>Number(v));
}

export function getReversedScopes(): PreferenceScope[] {
return getScopes().reverse();
}

export function getScopeNames(scope?: PreferenceScope): string[] {
const names: string[] = [];
const allNames = Object.keys(PreferenceScope)
.filter(k => typeof PreferenceScope[k as any] === 'number');
if (scope) {
for (const name of allNames) {
if ((<any>PreferenceScope)[name] <= scope) {
names.push(name);
}
}
}
return names;
}

export function fromString(strScope: string): PreferenceScope | undefined {
switch (strScope) {
case 'application':
return PreferenceScope.User;
case 'window':
return PreferenceScope.Workspace;
case 'resource':
return PreferenceScope.Folder;
}
}
}
8 changes: 4 additions & 4 deletions packages/plugin-ext/src/common/plugin-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ import { RPCProtocol } from '../api/rpc-protocol';
import { Disposable } from '@theia/core/lib/common/disposable';
import { LogPart, KeysToAnyValues, KeysToKeysToAnyValue } from './types';
import { CharacterPair, CommentRule, PluginAPIFactory, Plugin } from '../api/plugin-api';
// FIXME get rid of browser code in backend
import { PreferenceSchema, PreferenceSchemaProperties } from '@theia/core/lib/browser/preferences';
import { ExtPluginApi } from './plugin-ext-api-contribution';
import { IJSONSchema, IJSONSchemaSnippet } from '@theia/core/lib/common/json-schema';
import { RecursivePartial } from '@theia/core/lib/common/types';
import { PreferenceSchema, PreferenceSchemaProperties } from '@theia/core/lib/common/preferences/preference-schema';

export const hostedServicePath = '/services/hostedPlugin';

Expand Down Expand Up @@ -55,8 +55,8 @@ export interface PluginPackage {
* This interface describes a package.json contribution section object.
*/
export interface PluginPackageContribution {
configuration?: PreferenceSchema;
configurationDefaults?: PreferenceSchemaProperties;
configuration?: RecursivePartial<PreferenceSchema>;
configurationDefaults?: RecursivePartial<PreferenceSchemaProperties>;
languages?: PluginPackageLanguageContribution[];
grammars?: PluginPackageGrammarsContribution[];
viewsContainers?: { [location: string]: PluginPackageViewContainer[] };
Expand Down
17 changes: 8 additions & 9 deletions packages/plugin-ext/src/hosted/node/scanners/scanner-theia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ import * as jsoncparser from 'jsonc-parser';
import { IJSONSchema } from '@theia/core/lib/common/json-schema';
import { deepClone } from '@theia/core/lib/common/objects';
import { FileUri } from '@theia/core/lib/node/file-uri';
import { PreferenceSchema, PreferenceSchemaProperties } from '@theia/core/lib/common/preferences/preference-schema';
import { RecursivePartial } from '@theia/core/lib/common/types';

namespace nls {
export function localize(key: string, _default: string) {
Expand Down Expand Up @@ -115,11 +117,12 @@ export class TheiaPluginScanner implements PluginScanner {
}

const contributions: PluginContribution = {};
if (rawPlugin.contributes!.configuration) {
const config = this.readConfiguration(rawPlugin.contributes.configuration!, rawPlugin.packagePath);
if (rawPlugin.contributes.configuration) {
const config = this.readConfiguration(rawPlugin.contributes.configuration, rawPlugin.packagePath);
contributions.configuration = config;
}
contributions.configurationDefaults = rawPlugin.contributes.configurationDefaults;
const configurationDefaults = rawPlugin.contributes.configurationDefaults;
contributions.configurationDefaults = PreferenceSchemaProperties.is(configurationDefaults) ? configurationDefaults : undefined;

if (rawPlugin.contributes!.languages) {
const languages = this.readLanguages(rawPlugin.contributes.languages!, rawPlugin.packagePath);
Expand Down Expand Up @@ -235,12 +238,8 @@ export class TheiaPluginScanner implements PluginScanner {
}

// tslint:disable-next-line:no-any
private readConfiguration(rawConfiguration: any, pluginPath: string): any {
return {
type: rawConfiguration.type,
title: rawConfiguration.title,
properties: rawConfiguration.properties
};
private readConfiguration(rawConfiguration: RecursivePartial<PreferenceSchema>, pluginPath: string): PreferenceSchema | undefined {
return PreferenceSchema.is(rawConfiguration) ? rawConfiguration : undefined;
}

private readKeybinding(rawKeybinding: PluginPackageKeybinding): Keybinding {
Expand Down

0 comments on commit 6a07cec

Please sign in to comment.