From 0da9e618e7f973cf64631f833496afdcffd68d45 Mon Sep 17 00:00:00 2001 From: mortalYoung Date: Tue, 10 May 2022 17:58:43 +0800 Subject: [PATCH 01/14] feat: create instanceService --- src/index.ts | 10 +- src/molecule.api.ts | 95 ------------ src/provider/create.ts | 167 ++++++++++++++++++++++ src/provider/index.tsx | 2 + src/services/instanceService.tsx | 66 +++++++++ stories/workbench/0-Workbench.stories.tsx | 16 ++- 6 files changed, 250 insertions(+), 106 deletions(-) create mode 100644 src/provider/create.ts create mode 100644 src/services/instanceService.tsx diff --git a/src/index.ts b/src/index.ts index 00d2859a1..372b5756d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,9 @@ -import * as molecule from './molecule.api'; +import * as moleculeAPI from './molecule.api'; -export { MoleculeProvider } from 'mo/provider'; -export type { IMoleculeProps } from 'mo/provider'; +import { molecule } from './provider/create'; export { Workbench } from 'mo/workbench/workbench'; -export { molecule }; +export { create } from 'mo/provider'; -export default molecule; +// TODO: put API into moleucle temporarily, should consider it +export default Object.assign(molecule, moleculeAPI); diff --git a/src/molecule.api.ts b/src/molecule.api.ts index 6d43aeaf6..ce3e87eab 100644 --- a/src/molecule.api.ts +++ b/src/molecule.api.ts @@ -1,6 +1,3 @@ -import 'reflect-metadata'; -import { container } from 'tsyringe'; - export * as event from 'mo/common/event'; export * as react from 'mo/react'; export * as component from 'mo/components'; @@ -11,95 +8,3 @@ export * from 'mo/workbench'; export * from 'mo/services'; export * as model from 'mo/model'; - -import { - ILayoutService, - LayoutService, - ActivityBarService, - IActivityBarService, - ExplorerService, - IExplorerService, - FolderTreeService, - IFolderTreeService, - SearchService, - ISearchService, - ISidebarService, - SidebarService, - IMenuBarService, - MenuBarService, - IStatusBarService, - StatusBarService, - EditorService, - IEditorService, - IPanelService, - PanelService, - INotificationService, - NotificationService, - IColorThemeService, - ColorThemeService, - ISettingsService, - SettingsService, - IProblemsService, - ProblemsService, - IEditorTreeService, - EditorTreeService, - BuiltinService, - ExtensionService, - IExtensionService, -} from 'mo/services'; - -import { ILocaleService, LocaleService } from 'mo/i18n'; - -/** - * The locale service - */ -export const i18n = container.resolve(LocaleService); - -/** - * The layout service - */ -export const layout = container.resolve(LayoutService); - -/** - * The activityBar service - */ -export const activityBar: IActivityBarService = - container.resolve(ActivityBarService); - -export const explorer: IExplorerService = - container.resolve(ExplorerService); - -export const folderTree: IFolderTreeService = - container.resolve(FolderTreeService); - -export const editorTree = - container.resolve(EditorTreeService); - -export const search = container.resolve(SearchService); -export const sidebar = container.resolve(SidebarService); -export const menuBar = container.resolve(MenuBarService); -export const editor = container.resolve(EditorService); -export const statusBar = container.resolve(StatusBarService); -export const panel = container.resolve(PanelService); -export const notification = - container.resolve(NotificationService); - -export const problems = container.resolve(ProblemsService); - -/** - * The ColorTheme service - */ -export const colorTheme = - container.resolve(ColorThemeService); - -/** - * The Settings service - */ -export const settings = container.resolve(SettingsService); - -export const builtin = container.resolve(BuiltinService); - -/** - * The Extension service - */ -export const extension = container.resolve(ExtensionService); diff --git a/src/provider/create.ts b/src/provider/create.ts new file mode 100644 index 000000000..be3e25e22 --- /dev/null +++ b/src/provider/create.ts @@ -0,0 +1,167 @@ +import { ILocaleService, LocaleService } from 'mo/i18n'; +import { IExtension } from 'mo/model'; +import { IMonacoService, MonacoService } from 'mo/monaco/monacoService'; +import { + ActivityBarService, + BuiltinService, + ColorThemeService, + EditorService, + EditorTreeService, + ExplorerService, + ExtensionService, + FolderTreeService, + IActivityBarService, + IBuiltinService, + IColorThemeService, + IEditorService, + IEditorTreeService, + IExplorerService, + IExtensionService, + IFolderTreeService, + ILayoutService, + IMenuBarService, + INotificationService, + IPanelService, + IProblemsService, + ISearchService, + ISettingsService, + ISidebarService, + IStatusBarService, + LayoutService, + MenuBarService, + NotificationService, + PanelService, + ProblemsService, + SearchService, + SettingsService, + SidebarService, + StatusBarService, +} from 'mo/services'; +import InstanceService from 'mo/services/instanceService'; +import { container, InjectionToken } from 'tsyringe'; + +export interface IConfigProps { + /** + * Molecule Extension instances, after the MoleculeProvider + * did mount, then handle it. + */ + extensions?: IExtension[]; + /** + * Specify a default locale Id, the Molecule built-in `zh-CN`, `en` two languages, and + * default locale Id is `en`. + */ + defaultLocale?: string; +} + +enum ServiceUuidKind { + monacoService = 'monacoService', + layout = 'layout', + i18n = 'i18n', + activityBar = 'activityBar', + explorer = 'explorer', + folderTree = 'folderTree', + editorTree = 'editorTree', + search = 'search', + sidebar = 'sidebar', + menuBar = 'menuBar', + editor = 'editor', + statusBar = 'statusBar', + panel = 'panel', + notification = 'notification', + problems = 'problems', + colorTheme = 'colorTheme', + settings = 'settings', + builtin = 'builtin', + extension = 'extension', +} + +export type IServiceCollection = { + [ServiceUuidKind.monacoService]: IMonacoService; + [ServiceUuidKind.layout]: ILayoutService; + [ServiceUuidKind.i18n]: ILocaleService; + [ServiceUuidKind.activityBar]: IActivityBarService; + [ServiceUuidKind.explorer]: IExplorerService; + [ServiceUuidKind.folderTree]: IFolderTreeService; + [ServiceUuidKind.editorTree]: IEditorTreeService; + [ServiceUuidKind.search]: ISearchService; + [ServiceUuidKind.sidebar]: ISidebarService; + [ServiceUuidKind.menuBar]: IMenuBarService; + [ServiceUuidKind.editor]: IEditorService; + [ServiceUuidKind.statusBar]: IStatusBarService; + [ServiceUuidKind.panel]: IPanelService; + [ServiceUuidKind.notification]: INotificationService; + [ServiceUuidKind.problems]: IProblemsService; + [ServiceUuidKind.colorTheme]: IColorThemeService; + [ServiceUuidKind.settings]: ISettingsService; + [ServiceUuidKind.builtin]: IBuiltinService; + [ServiceUuidKind.extension]: IExtensionService; +}; + +namespace stanalone { + let instance: InstanceService | null = null; + + // used for internal + const _services = {}; + // used for user + export const molecule: Partial = {}; + + function registerService( + Service: InjectionToken, + uuid: ServiceUuidKind + ) { + const service = container.resolve(Service); + _services[uuid] = service; + + molecule[uuid] = new Proxy({}, { + get: function (_, prop) { + if (!instance) { + console.warn( + new Error( + "Don't call service's methods before initialize the instance" + ) + ); + return () => {}; + } + + return service[prop]; + }, + }); + } + + registerService(MonacoService, ServiceUuidKind.monacoService); + registerService(LayoutService, ServiceUuidKind.layout); + registerService(LocaleService, ServiceUuidKind.i18n); + registerService(ActivityBarService, ServiceUuidKind.activityBar); + registerService(ExplorerService, ServiceUuidKind.explorer); + registerService(FolderTreeService, ServiceUuidKind.folderTree); + registerService(EditorTreeService, ServiceUuidKind.editorTree); + registerService(SearchService, ServiceUuidKind.search); + registerService(SidebarService, ServiceUuidKind.sidebar); + registerService(MenuBarService, ServiceUuidKind.menuBar); + registerService(EditorService, ServiceUuidKind.editor); + registerService(StatusBarService, ServiceUuidKind.statusBar); + registerService(PanelService, ServiceUuidKind.panel); + registerService(NotificationService, ServiceUuidKind.notification); + registerService(ProblemsService, ServiceUuidKind.problems); + registerService(ColorThemeService, ServiceUuidKind.colorTheme); + registerService(SettingsService, ServiceUuidKind.settings); + registerService(BuiltinService, ServiceUuidKind.builtin); + registerService(ExtensionService, ServiceUuidKind.extension); + + /** + * Create an instance + */ + export function create(config: IConfigProps) { + if (instance) { + return instance; + } + instance = new InstanceService(config, _services); + return instance; + } +} + +export default function create(config: IConfigProps) { + return stanalone.create(config); +} + +export const molecule = stanalone.molecule; diff --git a/src/provider/index.tsx b/src/provider/index.tsx index 84b9d21ac..1a07838e1 100644 --- a/src/provider/index.tsx +++ b/src/provider/index.tsx @@ -1 +1,3 @@ export * from 'mo/provider/molecule'; + +export { default as create } from './create'; diff --git a/src/services/instanceService.tsx b/src/services/instanceService.tsx new file mode 100644 index 000000000..500d15292 --- /dev/null +++ b/src/services/instanceService.tsx @@ -0,0 +1,66 @@ +import { ILocaleService } from 'mo/i18n'; +import { container } from 'tsyringe'; +import * as controllers from 'mo/controller'; +import type { Controller } from 'mo/react'; +import { defaultExtensions } from 'mo/extensions'; +import { GlobalEvent } from 'mo/common/event'; +import { IConfigProps, IServiceCollection } from 'mo/provider/create'; +import { ReactNode } from 'react'; + +interface IInstanceServiceProps { + render: (dom: any) => void; + onBeforeInit: (callback: () => void) => void; +} + +enum InstanceHookKind { + beforeInit = 'before.init', +} + +export default class InstanceService + extends GlobalEvent + implements IInstanceServiceProps +{ + private _services: IServiceCollection; + private _config = { + extensions: defaultExtensions, + defaultLocale: 'en', + }; + + constructor(config: IConfigProps, services: IServiceCollection) { + super(); + this._services = services; + + if (config.defaultLocale) { + const localeService: ILocaleService = this._services.i18n; + localeService.setCurrentLocale(config.defaultLocale); + + this._config.defaultLocale = config.defaultLocale; + } + + if (Array.isArray(config.extensions)) { + this._config.extensions.push(...config.extensions); + } + } + + public render = (workbench: ReactNode) => { + this.emit(InstanceHookKind.beforeInit); + + Object.keys(controllers).forEach((key) => { + const module = controllers[key]; + const controller = container.resolve(module); + controller.initView?.(); + }); + + this._services.extension.load(this._config.extensions); + + this._services.monacoService.initWorkspace( + this._services.layout.container! + ); + + return workbench; + }; + + public onBeforeInit = (callback: () => void) => { + this.subscribe(InstanceHookKind.beforeInit, callback); + }; +} diff --git a/stories/workbench/0-Workbench.stories.tsx b/stories/workbench/0-Workbench.stories.tsx index d1bf41059..3fa0541c9 100644 --- a/stories/workbench/0-Workbench.stories.tsx +++ b/stories/workbench/0-Workbench.stories.tsx @@ -1,14 +1,18 @@ import React from 'react'; -import { MoleculeProvider, Workbench } from 'mo'; +import molecule, { create, Workbench } from 'mo'; import 'mo/style/mo.scss'; import { customExtensions } from '../extensions'; import '../demo.scss'; -export const IDEDemo = () => ( - - - -); +// this line will console.warn a tip +console.log('molecule:', molecule.editor.isOpened(1)); + +const moInstance = create({ + extensions: customExtensions, + defaultLocale: 'en', +}); + +export const IDEDemo = () => moInstance.render(); IDEDemo.story = { name: 'Workbench', From 609153fff4372d95e8539c7ddd8cbce681adef86 Mon Sep 17 00:00:00 2001 From: mortalYoung Date: Tue, 10 May 2022 19:31:05 +0800 Subject: [PATCH 02/14] feat: improve the interface --- src/provider/create.ts | 4 +++- stories/workbench/0-Workbench.stories.tsx | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/provider/create.ts b/src/provider/create.ts index be3e25e22..3fce430b6 100644 --- a/src/provider/create.ts +++ b/src/provider/create.ts @@ -101,7 +101,7 @@ namespace stanalone { let instance: InstanceService | null = null; // used for internal - const _services = {}; + const _services = >{}; // used for user export const molecule: Partial = {}; @@ -114,6 +114,8 @@ namespace stanalone { molecule[uuid] = new Proxy({}, { get: function (_, prop) { + // Allow user to access `molecule.xxx`, but should forbid access `molecule.xxx.yyy()` + // Because there are some connects should use `molecule.xxx` directly exported from molecule if (!instance) { console.warn( new Error( diff --git a/stories/workbench/0-Workbench.stories.tsx b/stories/workbench/0-Workbench.stories.tsx index 3fa0541c9..7f713d44b 100644 --- a/stories/workbench/0-Workbench.stories.tsx +++ b/stories/workbench/0-Workbench.stories.tsx @@ -12,6 +12,10 @@ const moInstance = create({ defaultLocale: 'en', }); +moInstance.onBeforeInit(() => { + molecule.builtin.inactiveModule('activityBarData'); +}); + export const IDEDemo = () => moInstance.render(); IDEDemo.story = { From debf773ede418b046f1338e2bcd6b5def785cc52 Mon Sep 17 00:00:00 2001 From: mortalYoung Date: Wed, 11 May 2022 10:56:59 +0800 Subject: [PATCH 03/14] refactor: improve the inject initial values of localeService --- src/i18n/localeService.ts | 4 --- src/provider/create.ts | 2 +- src/services/instanceService.tsx | 31 +++++++++++++++++++---- stories/workbench/0-Workbench.stories.tsx | 2 +- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/i18n/localeService.ts b/src/i18n/localeService.ts index eaf529203..ad5243689 100644 --- a/src/i18n/localeService.ts +++ b/src/i18n/localeService.ts @@ -96,10 +96,6 @@ export class LocaleService extends Component implements ILocaleService { constructor() { super(); - /** - * TODO: It will then be removed accordingly - */ - this.initialize(BuiltInLocales); } public reset(): void { diff --git a/src/provider/create.ts b/src/provider/create.ts index 3fce430b6..856fc583d 100644 --- a/src/provider/create.ts +++ b/src/provider/create.ts @@ -115,7 +115,7 @@ namespace stanalone { molecule[uuid] = new Proxy({}, { get: function (_, prop) { // Allow user to access `molecule.xxx`, but should forbid access `molecule.xxx.yyy()` - // Because there are some connects should use `molecule.xxx` directly exported from molecule + // Because there are some connects should be used with `molecule.xxx` directly exported from molecule if (!instance) { console.warn( new Error( diff --git a/src/services/instanceService.tsx b/src/services/instanceService.tsx index 500d15292..456910984 100644 --- a/src/services/instanceService.tsx +++ b/src/services/instanceService.tsx @@ -1,4 +1,4 @@ -import { ILocaleService } from 'mo/i18n'; +import { ILocale } from 'mo/i18n'; import { container } from 'tsyringe'; import * as controllers from 'mo/controller'; import type { Controller } from 'mo/react'; @@ -6,14 +6,17 @@ import { defaultExtensions } from 'mo/extensions'; import { GlobalEvent } from 'mo/common/event'; import { IConfigProps, IServiceCollection } from 'mo/provider/create'; import { ReactNode } from 'react'; +import { IExtension } from 'mo/model'; interface IInstanceServiceProps { render: (dom: any) => void; onBeforeInit: (callback: () => void) => void; + onBeforeLoad: (callback: () => void) => void; } enum InstanceHookKind { beforeInit = 'before.init', + beforeLoad = 'before.load', } export default class InstanceService @@ -31,9 +34,6 @@ export default class InstanceService this._services = services; if (config.defaultLocale) { - const localeService: ILocaleService = this._services.i18n; - localeService.setCurrentLocale(config.defaultLocale); - this._config.defaultLocale = config.defaultLocale; } @@ -42,16 +42,33 @@ export default class InstanceService } } + public initialLocaleService = (languagesExts: IExtension[]) => { + const locales = languagesExts.reduce((pre, cur) => { + const languages = cur.contributes?.languages || []; + return pre.concat(languages); + }, [] as ILocale[]); + this._services.i18n.initialize(locales); + this._services.i18n.setCurrentLocale(this._config.defaultLocale); + }; + public render = (workbench: ReactNode) => { this.emit(InstanceHookKind.beforeInit); + // get all locales including builtin and custom locales + const [languages, others] = this._services.extension.splitLanguagesExts( + this._config.extensions + ); + this.initialLocaleService(languages); + + // resolve all controllers, and call `initView` to inject initial values into services Object.keys(controllers).forEach((key) => { const module = controllers[key]; const controller = container.resolve(module); controller.initView?.(); }); - this._services.extension.load(this._config.extensions); + this.emit(InstanceHookKind.beforeLoad); + this._services.extension.load(others); this._services.monacoService.initWorkspace( this._services.layout.container! @@ -63,4 +80,8 @@ export default class InstanceService public onBeforeInit = (callback: () => void) => { this.subscribe(InstanceHookKind.beforeInit, callback); }; + + public onBeforeLoad = (callback: () => void) => { + this.subscribe(InstanceHookKind.beforeLoad, callback); + }; } diff --git a/stories/workbench/0-Workbench.stories.tsx b/stories/workbench/0-Workbench.stories.tsx index 7f713d44b..c0bce11dc 100644 --- a/stories/workbench/0-Workbench.stories.tsx +++ b/stories/workbench/0-Workbench.stories.tsx @@ -9,7 +9,7 @@ console.log('molecule:', molecule.editor.isOpened(1)); const moInstance = create({ extensions: customExtensions, - defaultLocale: 'en', + defaultLocale: 'japanese', }); moInstance.onBeforeInit(() => { From e43d4d682c1beb3e151b8a3c2a4487a8f36cc676 Mon Sep 17 00:00:00 2001 From: mortalYoung Date: Wed, 11 May 2022 14:22:42 +0800 Subject: [PATCH 04/14] refactor: improve the localeService --- src/i18n/localeService.ts | 61 ++++++++++---------------------- src/model/settings.ts | 4 +-- src/services/instanceService.tsx | 10 ++++-- src/services/settingsService.ts | 2 +- 4 files changed, 29 insertions(+), 48 deletions(-) diff --git a/src/i18n/localeService.ts b/src/i18n/localeService.ts index ad5243689..9010b45e9 100644 --- a/src/i18n/localeService.ts +++ b/src/i18n/localeService.ts @@ -1,23 +1,17 @@ import { APP_PREFIX } from 'mo/common/const'; -import { - ILocale, - LocalizationEvent, - BuiltInLocales, - BuiltInDefault, -} from 'mo/i18n/localization'; +import logger from 'mo/common/logger'; +import { ILocale, LocalizationEvent } from 'mo/i18n/localization'; import { Component } from 'mo/react'; import { singleton } from 'tsyringe'; export interface ILocaleService { /** - * Initialize the locales data, and the default current locale language, - * this method first uses the cached `locale` in localStorage, then use the - * localeId argument, if both the values are null, finally apply the built-in BuiltInZhCN + * Initialize the locales data, and the current locale language, * @param locales * @param localeId */ - initialize(locales: ILocale[], localeId?: string): void; + initialize(locales: ILocale[], localeId: string): void; /** * Set the current locale language by id * @param id @@ -36,14 +30,6 @@ export interface ILocaleService { * @param id */ getLocale(id: string): ILocale | undefined; - /** - * Get the default locale - */ - getDefaultLocale(): ILocale; - /** - * Get the default locales; - */ - getDefaultLocales(): ILocale[]; /** * Add multiple local languages * @param locales @@ -91,7 +77,7 @@ export class LocaleService extends Component implements ILocaleService { state = {}; private static LOCALIZE_REPLACED_WORD = '${i}'; - private _locales: Map = new Map(); + private _locales = new Map(); private _current: ILocale | undefined; constructor() { @@ -104,37 +90,22 @@ export class LocaleService extends Component implements ILocaleService { this._locales.clear(); } - public getDefaultLocale(): ILocale { - return Object.assign({}, BuiltInDefault); - } - - public getDefaultLocales(): ILocale[] { - return BuiltInLocales.concat(); - } - public getLocales(): ILocale[] { return Array.from(this._locales.values()); } - public initialize(locales: ILocale[], localeId?: string) { + public initialize(locales: ILocale[], localeId: string) { this.addLocales(locales); - let finalLocale = BuiltInDefault!.id; - if (localeId) { - finalLocale = localeId; - } - const cachedLocaleId = localStorage.getItem(STORE_KEY); - if (cachedLocaleId) { - finalLocale = cachedLocaleId; + if (this._locales.get(localeId)) { + this._current = this._locales.get(localeId); + } else { + logger.warn(`Cannot initialize the locale with ${localeId}`); + this._current = this._locales.values().next().value; } - - this.setCurrentLocale(finalLocale); } public getCurrentLocale(): ILocale | undefined { - return ( - (this._current && Object.assign({}, this._current)) || - BuiltInDefault - ); + return this._current && Object.assign({}, this._current); } public getLocale(id: string | null): ILocale | undefined { @@ -145,8 +116,14 @@ export class LocaleService extends Component implements ILocaleService { public removeLocale(id: string): ILocale | undefined { const locale = this._locales.get(id); if (locale !== undefined) { + if (this._locales.size === 1) { + logger.error( + "You can't remove this Locale because there must have one locale at least" + ); + return undefined; + } if (this._current && this._current.id === locale.id) { - this._current = this.getDefaultLocale(); + this._current = this._locales.values().next().value; } this._locales.delete(id); return locale; diff --git a/src/model/settings.ts b/src/model/settings.ts index 88b4701e6..1d211d12e 100644 --- a/src/model/settings.ts +++ b/src/model/settings.ts @@ -20,9 +20,9 @@ export interface ISettings { export class SettingsModel implements ISettings { colorTheme: string; editor: IEditorOptions; - locale: string; + locale?: string; - constructor(colorTheme: string, editor: IEditorOptions, locale: string) { + constructor(colorTheme: string, editor: IEditorOptions, locale?: string) { this.colorTheme = colorTheme; this.editor = editor; this.locale = locale; diff --git a/src/services/instanceService.tsx b/src/services/instanceService.tsx index 456910984..0e62c6157 100644 --- a/src/services/instanceService.tsx +++ b/src/services/instanceService.tsx @@ -1,3 +1,4 @@ +import { ReactNode } from 'react'; import { ILocale } from 'mo/i18n'; import { container } from 'tsyringe'; import * as controllers from 'mo/controller'; @@ -5,8 +6,8 @@ import type { Controller } from 'mo/react'; import { defaultExtensions } from 'mo/extensions'; import { GlobalEvent } from 'mo/common/event'; import { IConfigProps, IServiceCollection } from 'mo/provider/create'; -import { ReactNode } from 'react'; import { IExtension } from 'mo/model'; +import { STORE_KEY } from 'mo/i18n/localeService'; interface IInstanceServiceProps { render: (dom: any) => void; @@ -47,8 +48,11 @@ export default class InstanceService const languages = cur.contributes?.languages || []; return pre.concat(languages); }, [] as ILocale[]); - this._services.i18n.initialize(locales); - this._services.i18n.setCurrentLocale(this._config.defaultLocale); + + this._services.i18n.initialize( + locales, + localStorage.getItem(STORE_KEY) || this._config.defaultLocale + ); }; public render = (workbench: ReactNode) => { diff --git a/src/services/settingsService.ts b/src/services/settingsService.ts index b4dab821f..513489682 100644 --- a/src/services/settingsService.ts +++ b/src/services/settingsService.ts @@ -107,7 +107,7 @@ export class SettingsService extends GlobalEvent implements ISettingsService { const editorOptions = this.editorService.getState().editorOptions; const theme = this.colorThemeService.getColorTheme(); const locale = this.localeService.getCurrentLocale(); - return new SettingsModel(theme.id, editorOptions!, locale!.id); + return new SettingsModel(theme.id, editorOptions!, locale?.id); } public getDefaultSettingsTab(): BuiltInSettingsTabType { From 0267544d19d6f9e261ee4b791061c0ed52db617c Mon Sep 17 00:00:00 2001 From: mortalYoung Date: Wed, 11 May 2022 15:35:32 +0800 Subject: [PATCH 05/14] test: update test cases --- src/extensions/__tests__/folderTree.test.tsx | 11 +- src/i18n/__tests__/localeService.test.ts | 134 +- src/i18n/localeService.ts | 3 +- .../__snapshots__/molecule.test.tsx.snap | 1278 ----------------- src/provider/__tests__/molecule.test.tsx | 87 +- src/provider/create.ts | 17 +- .../__tests__/settingsService.test.ts | 5 +- src/services/instanceService.tsx | 6 +- .../__tests__/localeNotification.test.tsx | 10 +- .../__tests__/notificationPane.test.tsx | 8 + src/workbench/panel/__tests__/panel.test.tsx | 8 + .../sidebar/__tests__/editorTree.test.tsx | 8 + 12 files changed, 150 insertions(+), 1425 deletions(-) delete mode 100644 src/provider/__tests__/__snapshots__/molecule.test.tsx.snap diff --git a/src/extensions/__tests__/folderTree.test.tsx b/src/extensions/__tests__/folderTree.test.tsx index e989f48a1..08df008d4 100644 --- a/src/extensions/__tests__/folderTree.test.tsx +++ b/src/extensions/__tests__/folderTree.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; import '@testing-library/jest-dom'; -import molecule, { MoleculeProvider, Workbench } from 'mo'; +import molecule, { create, Workbench } from 'mo'; import { cleanup, fireEvent, render } from '@testing-library/react'; import type { ITreeNodeItemProps } from 'mo/components'; import type { IEditorTab } from 'mo/model/workbench/editor'; @@ -35,11 +35,10 @@ describe('folderTree extension', () => { afterEach(cleanup); test('Execute the listener function of onUpdateFileName', () => { - const { getByRole } = render( - - - - ); + const container = create({ + extensions: [], + }).render(); + const { getByRole } = render(container); molecule.folderTree.setState({ folderTree: { data: mockTreeData } }); expect(molecule.folderTree.getState().folderTree?.data).toEqual( diff --git a/src/i18n/__tests__/localeService.test.ts b/src/i18n/__tests__/localeService.test.ts index 048de2f45..5ac84d49c 100644 --- a/src/i18n/__tests__/localeService.test.ts +++ b/src/i18n/__tests__/localeService.test.ts @@ -1,15 +1,27 @@ import 'reflect-metadata'; import { container } from 'tsyringe'; +import { expectLoggerErrorToBeCalled } from '@test/utils'; +import { ILocale } from '../localization'; import { LocaleService } from '..'; -import { BuiltInLocales, BuiltInDefault, ILocale } from '../localization'; describe('The Locale Service', () => { - const TestLocale = { + const TestLocale: ILocale = { id: 'test', source: new Map(), name: 'test', }; + // LocaleService is support to add an object source but ILocale is banned + const TestEnLocale: ILocale = { + id: 'en', + name: 'English', + source: { + // @ts-ignore + 'molecule.welcome': 'Welcome to Molecule', + 'test.id': 'hello ${i}', + }, + }; + afterEach(() => { localStorage.clear(); }); @@ -19,82 +31,72 @@ describe('The Locale Service', () => { expect(localeService).not.toBeUndefined(); }); - test('Reset the LocaleService', () => { + test('Initialize the locales with testLocale', () => { const localeService = new LocaleService(); - expect(localeService.getCurrentLocale()!.id).toBe(BuiltInDefault.id); - localeService.reset(); - expect(localeService.getCurrentLocale()!.id).toBe(BuiltInDefault.id); - }); + localeService.initialize([TestLocale], TestLocale.id); - test('Get default Locale', () => { - const localeService = new LocaleService(); - const defaultLocale = localeService.getDefaultLocale(); - expect(defaultLocale).toEqual(BuiltInDefault); - }); + expect(localeService.getCurrentLocale()?.id).toEqual(TestLocale.id); + expect(localeService.getLocales().length).toBe(1); - test('Get default Locales', () => { - const localeService = new LocaleService(); - const defaultLocale = localeService.getDefaultLocales(); - expect(defaultLocale).toEqual(BuiltInLocales); + localeService.reset(); + expectLoggerErrorToBeCalled(() => { + // @ts-ignore + localeService.initialize([TestEnLocale, TestLocale]); + }); }); - test('The size of Built-in Locales should be 3', () => { + test('Reset the LocaleService', () => { const localeService = new LocaleService(); - const locales = localeService.getLocales(); - expect(locales.length).toBe(3); - }); + expect(localeService.getCurrentLocale()).toBeUndefined(); - test('Initialize the locales', () => { - const localeService = new LocaleService(); - localeService.initialize([TestLocale]); - expect(localeService.getCurrentLocale()!.id).toEqual( - localeService.getDefaultLocale().id - ); - expect(localeService.getLocales().length).toBe(4); - localeService.initialize([], 'test'); - expect(localeService.getCurrentLocale()!.id).toEqual(BuiltInDefault.id); - // Clear the cached locale value - localStorage.clear(); - localeService.initialize([], 'test'); - expect(localeService.getCurrentLocale()!.id).toEqual('test'); - localeService.initialize([]); - // Get from the localStorage cache - expect(localeService.getCurrentLocale()!.id).toEqual('test'); + localeService.initialize([TestLocale], TestLocale.id); + expect(localeService.getCurrentLocale()).toEqual(TestLocale); + + localeService.reset(); + expect(localeService.getCurrentLocale()).toBeUndefined(); }); test('Get/Set current locale', () => { const localeService = new LocaleService(); - (localeService as any)._current = undefined; - expect(localeService.getCurrentLocale()).toBe(BuiltInDefault); - localeService.addLocales([TestLocale]); - localeService.setCurrentLocale(TestLocale.id); - expect(localeService.getCurrentLocale()!.id).toEqual(TestLocale.id); + expect(localeService.getCurrentLocale()).toBeUndefined(); + + localeService.initialize([TestLocale, TestEnLocale], TestLocale.id); + + expect(localeService.getCurrentLocale()?.id).toEqual(TestLocale.id); + localeService.setCurrentLocale(TestEnLocale.id); + expect(localeService.getCurrentLocale()?.id).toEqual(TestEnLocale.id); + // set an unknow locale will fail expect(localeService.setCurrentLocale('unknown')).toEqual(false); }); test('Add locales', () => { const localeService = new LocaleService(); - expect(localeService.getLocales().length).toBe(3); + expect(localeService.getLocales().length).toBe(0); + localeService.addLocales([TestLocale]); - expect(localeService.getLocales().length).toBe(4); + expect(localeService.getLocales().length).toBe(1); + localeService.addLocales([]); - expect(localeService.getLocales().length).toBe(4); + expect(localeService.getLocales().length).toBe(1); + // Add an existed locale localeService.addLocales([TestLocale]); - expect(localeService.getLocales().length).toBe(4); + expect(localeService.getLocales().length).toBe(1); }); test('Add an locale inherit the en', () => { const localeService = new LocaleService(); + localeService.initialize([TestEnLocale], TestEnLocale.id); + expect(TestLocale.source.size).toBe(0); - (TestLocale as ILocale).inherit = 'en'; + TestLocale.inherit = 'en'; localeService.addLocales([TestLocale]); expect(localeService.getLocale(TestLocale.id)?.source.size).not.toBe(0); // Inherit an not exist locale localeService.removeLocale(TestLocale.id); - (TestLocale as ILocale).inherit = 'unknown'; + TestLocale.inherit = 'unknown'; localeService.addLocales([TestLocale]); expect(localeService.getLocale(TestLocale.id)?.source.size).toBe(0); }); @@ -110,38 +112,47 @@ describe('The Locale Service', () => { test('Remove a locale', () => { const localeService = new LocaleService(); - localeService.addLocales([TestLocale]); + localeService.initialize([TestLocale, TestEnLocale], TestLocale.id); expect(localeService.getLocale(TestLocale.id)?.id).toEqual( TestLocale.id ); - localeService.removeLocale(TestLocale.id); + + const removedLocale = localeService.removeLocale(TestLocale.id); expect(localeService.getLocale(TestLocale.id)).toBeUndefined(); + expect(removedLocale).toEqual(TestLocale); + localeService.addLocales([TestLocale]); localeService.setCurrentLocale(TestLocale.id); //Remove the current locale - expect(localeService.getCurrentLocale()!.id).toEqual(TestLocale.id); + expect(localeService.getCurrentLocale()?.id).toEqual(TestLocale.id); localeService.removeLocale(TestLocale.id); - expect(localeService.getCurrentLocale()!.id).toEqual( - localeService.getDefaultLocale().id - ); + expect(localeService.getCurrentLocale()!.id).toEqual(TestEnLocale.id); // Remove an undefined expect(localeService.removeLocale(TestLocale.id)); + + expect(localeService.getLocales().length).toBe(1); + // The last one couldn't be removed + expect(localeService.removeLocale(TestEnLocale.id)).toBeFalsy(); }); test('Listen to the current locale change event', () => { - const target = 'zh-CN'; const localeService = new LocaleService(); const fn = jest.fn(); localeService.onChange(fn); - localeService.setCurrentLocale(target); + + localeService.initialize([TestLocale, TestEnLocale], TestLocale.id); + localeService.setCurrentLocale(TestEnLocale.id); + expect(fn).toBeCalledTimes(1); - expect(localeService.getCurrentLocale()!.id).toEqual(target); + expect(localeService.getCurrentLocale()!.id).toEqual(TestEnLocale.id); }); test('Localize the source key', () => { const localeService = new LocaleService(); + + localeService.initialize([TestLocale, TestEnLocale], TestEnLocale.id); let res = localeService.localize('test'); expect(res).toEqual(''); @@ -154,19 +165,10 @@ describe('The Locale Service', () => { res = localeService.localize('molecule.welcome', 'default'); expect(res).toEqual('Welcome to Molecule'); - const map = new Map(); - map.set('test.id', 'hello ${i}'); - const mockData = { - id: 'mock', - name: 'mock', - source: map, - }; - localeService.addLocales([mockData]); - localeService.setCurrentLocale(mockData.id); res = localeService.localize('test.id', '', 'world'); expect(res).toEqual('hello world'); - (localeService as any)._current = null; + localeService.setCurrentLocale(TestLocale.id); res = localeService.localize('molecule.welcome', 'default'); expect(res).toEqual('default'); }); diff --git a/src/i18n/localeService.ts b/src/i18n/localeService.ts index 9010b45e9..7c66ef47a 100644 --- a/src/i18n/localeService.ts +++ b/src/i18n/localeService.ts @@ -99,8 +99,7 @@ export class LocaleService extends Component implements ILocaleService { if (this._locales.get(localeId)) { this._current = this._locales.get(localeId); } else { - logger.warn(`Cannot initialize the locale with ${localeId}`); - this._current = this._locales.values().next().value; + logger.error(`Cannot initialize the locale with ${localeId}`); } } diff --git a/src/provider/__tests__/__snapshots__/molecule.test.tsx.snap b/src/provider/__tests__/__snapshots__/molecule.test.tsx.snap deleted file mode 100644 index ba13c3332..000000000 --- a/src/provider/__tests__/__snapshots__/molecule.test.tsx.snap +++ /dev/null @@ -1,1278 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Test MoleculeProvider Match The MoleculeProvider snapshot 1`] = ` - -
-
-
-
- - -
-
-
-
-
-
-
- -
-
-
-
-
-
-
    -
  • - -
    -
  • -
  • - -
  • -
-
    -
  • -
  • -
  • - -
  • -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-

- Explorer -

-
-
-
-
-
    -
  • - -
  • -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - - Open Editors - -
-
-
-
-
-
-
-
- - - Default Project Name - -
-
-
-
-
- you have not yet opened a folder - -
-
-
-
-
-
-
-
- - - Outline - -
-
-
-
-
-
-
-
-
-
-
-