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

application-package: refine configuration typings #9503

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
186 changes: 106 additions & 80 deletions dev-packages/application-package/src/application-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,27 @@

import type { BrowserWindowConstructorOptions } from 'electron';

/**
* Base configuration for the Theia application.
*/
export interface ApplicationConfig {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
readonly [key: string]: any;
}

/**
* Helper interface that generates two versions of an interface given two inputs:
* @param WithDefault key/values that may be left undefined but will be resolved to a default when missing.
* @param Rest key/values that may or may not be left undefined but will stay that way.
* @returns a pseudo-interface you can query 'resolved' or 'partial' to get different versions of the same interface.
*/
interface ConfigHelper<WithDefault extends object, Rest extends object> {
/** Query this field like `Config['partial']` to get the type with optional fields. */
partial: Partial<WithDefault> & Rest & ApplicationConfig
/** Query this field like `Config['resolved']` to get the type without undefined values for fields with defaults. */
resolved: Required<WithDefault> & Rest & ApplicationConfig
}

export interface NpmRegistryProps {

/**
Expand All @@ -36,77 +57,11 @@ export namespace NpmRegistryProps {
};
}

/**
* Representation of all backend and frontend related Theia extension and application properties.
*/
export interface ApplicationProps extends NpmRegistryProps {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
readonly [key: string]: any;

/**
* Whether the extension targets the browser or electron. Defaults to `browser`.
*/
readonly target: ApplicationProps.Target;

/**
* Frontend related properties.
*/
readonly frontend: Readonly<{ config: FrontendApplicationConfig }>;

/**
* Backend specific properties.
*/
readonly backend: Readonly<{ config: BackendApplicationConfig }>;

/**
* Generator specific properties.
*/
readonly generator: Readonly<{ config: GeneratorConfig }>;
}
export namespace ApplicationProps {
export enum ApplicationTarget {
browser = 'browser',
electron = 'electron'
};

export type Target = keyof typeof ApplicationTarget;

export const DEFAULT: ApplicationProps = {
...NpmRegistryProps.DEFAULT,
target: 'browser',
backend: {
config: {}
},
frontend: {
config: {
applicationName: 'Eclipse Theia',
defaultTheme: 'dark',
defaultIconTheme: 'none'
}
},
generator: {
config: {
preloadTemplate: ''
}
}
};

}

/**
* Base configuration for the Theia application.
*/
export interface ApplicationConfig {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
readonly [key: string]: any;
}

/**
* Application configuration for the frontend. The following properties will be injected into the `index.html`.
*/
export interface FrontendApplicationConfig extends ApplicationConfig {

export type FrontendApplicationConfig = _FrontendApplicationConfig['resolved'];
type _FrontendApplicationConfig = ConfigHelper<{
/**
* The default theme for the application. If not given, defaults to `dark`. If invalid theme is given, also defaults to `dark`.
*/
Expand All @@ -121,47 +76,118 @@ export interface FrontendApplicationConfig extends ApplicationConfig {
* The name of the application. `Eclipse Theia` by default.
*/
readonly applicationName: string;

}, {
/**
* Electron specific configuration.
*/
readonly electron?: Readonly<ElectronFrontendApplicationConfig>;
}>;
export namespace FrontendApplicationConfig {
export const DEFAULT: FrontendApplicationConfig = {
applicationName: 'Eclipse Theia',
defaultTheme: 'dark',
defaultIconTheme: 'none'
};
export type Partial = _FrontendApplicationConfig['partial'];
}

export interface ElectronFrontendApplicationConfig {

export type ElectronFrontendApplicationConfig = _ElectronFrontendApplicationConfig['resolved'];
type _ElectronFrontendApplicationConfig = ConfigHelper<{
/**
* If set to `true`, reloading the current browser window won't be possible with the `Ctrl/Cmd + R` keybinding.
* It is `false` by default. Has no effect if not in an electron environment.
*/
readonly disallowReloadKeybinding?: boolean;

readonly disallowReloadKeybinding: boolean;
}, {
/**
* Override or add properties to the electron `windowOptions`.
*/
readonly windowOptions?: BrowserWindowConstructorOptions;
}>;
export namespace ElectronFrontendApplicationConfig {
export const DEFAULT: ElectronFrontendApplicationConfig = {
disallowReloadKeybinding: false,
};
export type Partial = _ElectronFrontendApplicationConfig['partial'];
}

/**
* Application configuration for the backend.
*/
export interface BackendApplicationConfig extends ApplicationConfig {

export type BackendApplicationConfig = _BackendApplicationConfig['resolved'];
type _BackendApplicationConfig = ConfigHelper<{}, {
/**
* If true and in Electron mode, only one instance of the application is allowed to run at a time.
*/
singleInstance?: boolean;

readonly singleInstance?: boolean;
}>;
export namespace BackendApplicationConfig {
export const DEFAULT: BackendApplicationConfig = {};
export type Partial = _BackendApplicationConfig['partial'];
}

/**
* Configuration for the generator.
*/
export interface GeneratorConfig {

export type GeneratorConfig = _GeneratorConfig['resolved'];
type _GeneratorConfig = ConfigHelper<{
/**
* Template to use for extra preload content markup (file path or HTML)
* Template to use for extra preload content markup (file path or HTML). Defaults to `''`.
*/
readonly preloadTemplate: string;
}, {}>;
export namespace GeneratorConfig {
export const DEFAULT: GeneratorConfig = {
preloadTemplate: ''
};
export type Partial = _GeneratorConfig['partial'];
}

/**
* Representation of all backend and frontend related Theia extension and application properties.
*/
export interface ApplicationProps extends NpmRegistryProps {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
readonly [key: string]: any;

/**
* Whether the extension targets the browser or electron. Defaults to `browser`.
*/
readonly target: ApplicationProps.Target;

/**
* Frontend related properties.
*/
readonly frontend: Readonly<{ config: FrontendApplicationConfig }>;

/**
* Backend specific properties.
*/
readonly backend: Readonly<{ config: BackendApplicationConfig }>;

/**
* Generator specific properties.
*/
readonly generator: Readonly<{ config: GeneratorConfig }>;
}
export namespace ApplicationProps {
export enum ApplicationTarget {
browser = 'browser',
electron = 'electron'
};
export type Target = keyof typeof ApplicationTarget;
export const DEFAULT: ApplicationProps = {
...NpmRegistryProps.DEFAULT,
target: 'browser',
backend: {
config: BackendApplicationConfig.DEFAULT,
},
frontend: {
config: FrontendApplicationConfig.DEFAULT,
},
generator: {
config: GeneratorConfig.DEFAULT,
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,18 @@ export class FrontendApplicationConfigProvider {
return config;
}

static set(config: FrontendApplicationConfig): void {
static set(config: FrontendApplicationConfig.Partial): void {
if (FrontendApplicationConfigProvider.doGet() !== undefined) {
throw new Error('The configuration is already set.');
}
const resolved: FrontendApplicationConfig = {
...FrontendApplicationConfig.DEFAULT,
...config
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const globalObject = window as any;
const key = FrontendApplicationConfigProvider.KEY;
globalObject[key] = config;
globalObject[key] = resolved;
}

private static doGet(): FrontendApplicationConfig | undefined {
Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/node/backend-application-config-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,18 @@ export class BackendApplicationConfigProvider {
return config;
}

static set(config: BackendApplicationConfig): void {
static set(config: BackendApplicationConfig.Partial): void {
if (BackendApplicationConfigProvider.doGet() !== undefined) {
throw new Error('The configuration is already set.');
}
const resolved: BackendApplicationConfig = {
...BackendApplicationConfig.DEFAULT,
...config
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const globalObject = global as any;
const key = BackendApplicationConfigProvider.KEY;
globalObject[key] = config;
globalObject[key] = resolved;
}

private static doGet(): BackendApplicationConfig | undefined {
Expand Down