From 3340fa89eab63413a00335f52a81d6cfa20dd2e5 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 27 Apr 2022 20:34:26 +0800 Subject: [PATCH] refactor: add @opensumi/ide-utils module (#784) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: add @opensumi/ide-utils module * fix: module and function ref path * test: move utils test to utils module * chore: upgrade to 2.16.6 version * refactor: use common OperatingSystem define on platform and os file * chore: remove useless utils * test: fix unit test * test: use ResourceLoader on jsdom to make platform correctly * chore: make @opensumi/ide-utils to be public package * chore: merge cancelToken defined * chore: fix function ref * chore: add userAgent environment in jsdom * chore: add prettierPath config * chore: update jest.config.js * test: add more arrays unit test * chore: use v8 coverageProvider * chore: use babel provider * chore: add codecov.yml * chore: update utils version Co-authored-by: 野声 --- codecov.yml | 8 + configs/ts/references/tsconfig.utils.json | 8 + configs/ts/tsconfig.build.json | 3 + configs/ts/tsconfig.resolve.json | 2 + jest.config.js | 14 +- jest.setup.node.js | 12 +- .../addons/src/browser/file-drop.service.ts | 7 +- .../comments/src/browser/comments.service.ts | 6 +- packages/components/package.json | 1 + .../src/recycle-tree/RecycleTree.tsx | 56 +- .../src/recycle-tree/basic/tree-service.ts | 3 +- .../src/recycle-tree/prompt/PromptHandle.ts | 5 +- .../components/src/recycle-tree/tree/Tree.ts | 3 +- .../src/recycle-tree/tree/TreeNode.ts | 60 +- .../tree/decoration/CompositeDecoration.ts | 3 +- .../tree/decoration/Decoration.ts | 3 +- .../tree/decoration/DecorationManager.ts | 3 +- .../src/recycle-tree/tree/model/TreeModel.ts | 3 +- .../tree/model/treeState/TreeStateManager.ts | 5 +- .../tree/model/treeState/TreeStateWatcher.ts | 2 +- .../src/recycle-tree/types/watcher.ts | 2 +- packages/components/src/utils/cancellation.ts | 132 -- packages/components/src/utils/disposable.ts | 161 -- packages/components/src/utils/event.ts | 732 ------- packages/components/src/utils/index.ts | 11 +- packages/components/src/utils/iterator.ts | 19 - packages/components/src/utils/linkedList.ts | 145 -- packages/components/src/utils/os.ts | 19 - packages/components/src/utils/path.ts | 1825 ----------------- packages/components/src/utils/process.ts | 28 - packages/connection/package.json | 1 - .../__tests__/utils/json.test.ts | 0 packages/core-browser/package.json | 1 + .../src/application/application.service.ts | 11 +- .../src/components/actions/index.tsx | 4 +- packages/core-browser/src/core-preferences.ts | 3 +- packages/core-browser/src/dom/index.ts | 2 +- .../core-browser/src/encoding-registry.ts | 16 +- packages/core-browser/src/keyboard/keys.ts | 2 +- .../src/menu/next/ctxmenu-service.ts | 3 +- .../src/menu/next/menu.interface.ts | 6 +- .../src/menu/next/menubar-service.ts | 3 +- .../menu/next/renderer/ctxmenu/electron.ts | 12 +- .../src/menu/next/toolbar-action.service.ts | 2 +- .../core-browser/src/preferences/index.ts | 1 + .../src/preferences/preference-provider.ts | 13 +- .../src/preferences/preference-proxy.ts | 2 +- .../src/preferences/preference-service.ts | 106 +- .../core-browser/src/preferences/types.ts | 102 + .../src/progress/progress.service.tsx | 6 +- .../src/quick-open/recent-files.ts | 2 +- .../src/services/label-service.ts | 5 +- .../src/services/status-bar-service.ts | 3 +- .../src/toolbar/toolbar.popover.registry.ts | 3 +- .../src/toolbar/toolbar.registry.ts | 6 +- packages/core-browser/src/utils/index.ts | 1 + .../src/utils/json.ts | 0 .../core-browser/src/utils/react-hooks.ts | 3 +- .../core-browser/src/window/window.service.ts | 6 +- .../core-common/__tests__/event-bus.test.ts | 12 +- .../__tests__/hash-calculate.test.ts | 2 +- .../__tests__/utils/arrays.test.ts | 108 - .../core-common/__tests__/utils/paths.test.ts | 43 - .../__tests__/utils/strings.test.ts | 470 ----- packages/core-common/package.json | 7 +- packages/core-common/src/arrays.ts | 628 ------ packages/core-common/src/command.ts | 3 +- .../core-common/src/{utils => }/comparers.ts | 6 +- packages/core-common/src/const/index.ts | 2 +- packages/core-common/src/electron.ts | 3 +- .../src/event-bus/event-bus-types.ts | 4 +- .../core-common/src/event-bus/event-bus.ts | 3 +- .../src/event-bus/event-decorator.ts | 2 +- .../src/hash-calculate/hash-calculate.ts | 3 +- packages/core-common/src/index.ts | 20 +- .../src/keyboard/keyboard-layout-provider.ts | 2 +- packages/core-common/src/keyboard/keymap.ts | 2 +- packages/core-common/src/localize.ts | 5 +- packages/core-common/src/log.ts | 2 +- .../core-common/src/{utils => }/markdown.ts | 2 +- packages/core-common/src/menu.ts | 3 +- packages/core-common/src/problem-matcher.ts | 4 +- packages/core-common/src/problem-pattern.ts | 4 +- packages/core-common/src/reference.ts | 4 +- packages/core-common/src/reporter.ts | 2 +- packages/core-common/src/storage.ts | 5 +- packages/core-common/src/task-definition.ts | 5 +- packages/core-common/src/types/application.ts | 8 +- .../core-common/src/types/authentication.ts | 3 +- packages/core-common/src/types/common.ts | 4 +- packages/core-common/src/types/extension.ts | 3 +- packages/core-common/src/types/file-watch.ts | 2 +- packages/core-common/src/types/file.ts | 2 +- packages/core-common/src/types/index.ts | 1 + packages/core-common/src/types/markdown.ts | 2 +- .../src/types/markers/markers-manager.ts | 8 +- .../core-common/src/types/markers/markers.ts | 2 +- packages/core-common/src/utils/index.ts | 14 - packages/core-common/src/utils/ipc.ts | 3 +- packages/core-common/src/utils/paths.ts | 353 ---- .../core-electron-main/src/bootstrap/types.ts | 2 +- .../src/bootstrap/window.ts | 13 +- .../common-module/credential.server.test.ts | 3 +- .../__tests__/common-module/index.test.ts | 2 +- .../src/common-module/common.server.ts | 4 +- .../debug/src/browser/debug-link-detector.ts | 19 +- .../debug/src/browser/debug-schema-updater.ts | 4 +- packages/debug/src/browser/debugUtils.ts | 4 +- .../editor/debug-editor-contribution.ts | 14 +- .../editor/debug-expression-provider.ts | 9 +- .../editor/debug-hover-tree.model.service.ts | 5 +- .../console/debug-console-filter.model.ts | 3 +- .../console/debug-console-filter.service.ts | 6 +- .../debug-console-tree.model.service.ts | 4 +- .../watch/debug-watch-tree.model.service.ts | 3 +- .../src/browser/decorationsService.ts | 8 +- .../editor/src/browser/breadcrumb/default.ts | 5 +- .../editor/src/browser/breadcrumb/index.ts | 3 +- packages/editor/src/browser/component.ts | 1 - .../editor-document-model-service.ts | 3 +- .../src/browser/editor-collection.service.ts | 4 +- .../editor/src/browser/editor.contribution.ts | 2 +- packages/editor/src/browser/feature.ts | 4 +- .../src/browser/fs-resource/fs-editor-doc.ts | 8 +- .../src/browser/fs-resource/fs-resource.ts | 9 +- .../editor/src/browser/grid/grid.service.ts | 2 +- .../language/language-status.service.ts | 3 +- .../callHierarchy/callHierarchy.service.ts | 4 +- .../typeHierarchy/typeHierarchy.service.ts | 5 +- .../src/browser/preference/converter.ts | 4 +- .../editor/src/browser/resource.service.ts | 4 +- .../editor/src/browser/untitled-resource.ts | 6 +- .../src/browser/workbench-editor.service.ts | 4 +- packages/editor/src/common/language.ts | 5 +- .../electron-basic/__tests__/index.test.ts | 3 +- .../src/browser/header/header.tsx | 14 +- .../src/browser/storage-path.ts | 5 +- .../extension-storage/src/browser/storage.ts | 14 +- .../extension/__tests__/browser/index.test.ts | 4 +- .../api/vscode/ext.host.terminal.test.ts | 8 +- .../src/browser/activation.service.ts | 2 +- .../components/extension-portal-root.tsx | 2 +- .../src/browser/extension-view.service.ts | 4 +- .../src/browser/extension-worker.service.ts | 5 +- packages/extension/src/browser/extension.ts | 6 +- .../extension/src/browser/metadata.service.ts | 3 +- .../src/browser/sumi-browser/index.ts | 4 +- .../src/browser/sumi-browser/types.ts | 5 +- .../vscode/api/main.thread.api.webview.ts | 3 +- .../vscode/api/main.thread.commands.ts | 4 +- .../vscode/api/main.thread.decoration.ts | 2 +- .../vscode/api/main.thread.file-system.ts | 3 +- .../vscode/api/main.thread.language.ts | 4 +- .../src/browser/vscode/api/main.thread.scm.ts | 4 +- .../vscode/contributes/customEditors.tsx | 3 +- .../browser/vscode/contributes/debuggers.ts | 4 +- .../browser/vscode/contributes/keybindings.ts | 7 +- .../vscode/contributes/localization.ts | 4 +- .../vscode/contributes/problemMatchers.ts | 4 +- .../vscode/contributes/problemPatterns.ts | 5 +- .../extension/src/common/vscode/converter.ts | 89 +- .../src/common/vscode/custom-editor.ts | 3 +- .../extension/src/common/vscode/ext-types.ts | 3 +- .../extension/src/common/vscode/extension.ts | 4 +- packages/extension/src/common/vscode/glob.ts | 1 - packages/extension/src/common/vscode/index.ts | 1 - packages/extension/src/common/vscode/paths.ts | 1 - .../extension/src/common/vscode/treeview.ts | 2 +- .../src/hosted/api/sumi/ext.host.webview.ts | 5 +- .../hosted/api/vscode/debug/ext.host.debug.ts | 5 +- .../hosted/api/vscode/doc/doc-manager.host.ts | 4 +- .../hosted/api/vscode/ext.host.api.command.ts | 5 +- .../src/hosted/api/vscode/ext.host.command.ts | 15 +- .../api/vscode/ext.host.custom-editor.ts | 11 +- .../hosted/api/vscode/ext.host.decoration.ts | 12 +- .../hosted/api/vscode/ext.host.extensions.ts | 2 +- .../api/vscode/ext.host.file-system-event.ts | 5 +- .../src/hosted/api/vscode/ext.host.scm.ts | 6 +- .../src/hosted/api/vscode/ext.host.tests.ts | 35 +- .../hosted/api/vscode/ext.host.treeview.ts | 3 +- .../hosted/api/vscode/ext.host.workspace.ts | 9 +- .../vscode/language/linked-editing-range.ts | 4 +- .../hosted/api/vscode/language/selection.ts | 4 +- .../src/hosted/api/vscode/language/util.ts | 3 +- .../src/hosted/api/worker/worker.ext-types.ts | 2 +- packages/extension/src/hosted/ext.host.ts | 4 +- .../extension/src/hosted/ext.process-base.ts | 3 +- .../extension/src/node/merge-contributes.ts | 4 +- .../__tests__/browser/resource.test.ts | 15 +- .../src/node/file-search.service.ts | 5 +- .../browser/file-service-client.test.ts | 3 +- .../file-service/__tests__/node/index.test.ts | 3 - .../src/browser/file-service-client.ts | 22 +- .../browser/shadow-file-system.provider.ts | 4 +- .../src/common/file-service-client.ts | 7 +- .../src/common/mocks/file-service-client.ts | 5 +- .../src/common/mocks/file-system-provider.ts | 3 +- .../src/node/disk-file-system.provider.ts | 9 +- packages/file-service/src/node/encoding.ts | 3 +- .../src/node/file-service-watcher.ts | 16 +- .../file-service/src/node/file-service.ts | 16 +- .../browser/file-tree-contribution.test.ts | 4 +- .../browser/file-tree-model.service.test.ts | 4 +- .../browser/file-tree.service.test.ts | 4 +- .../src/browser/dialog/file-dialog.view.tsx | 8 +- .../browser/dialog/window-dialog.service.tsx | 2 +- .../src/browser/file-tree-contribution.ts | 3 +- .../src/browser/file-tree-node.tsx | 4 +- .../src/browser/file-tree.service.ts | 13 +- .../browser/services/file-tree-api.service.ts | 7 +- .../browser/services/file-tree-dnd.service.ts | 4 +- .../services/file-tree-model.service.ts | 16 +- .../main-layout/src/browser/views-registry.ts | 2 +- .../main-layout/src/browser/welcome.view.tsx | 3 +- .../src/browser/markers-filter.model.ts | 17 +- .../markers/src/browser/markers-tree.view.tsx | 5 +- packages/markers/src/browser/markers.model.ts | 4 +- packages/markers/src/common/match.ts | 30 +- packages/markers/src/common/types.ts | 3 +- .../monaco-enhance/src/browser/zone-widget.ts | 4 +- .../__mocks__/monaco.context-key.service.ts | 4 +- .../monaco/__mocks__/monaco/common/uri.ts | 3 +- .../monaco/__mocks__/monaco/common/util.ts | 2 +- .../monaco-snippet-suggest-provider.ts | 6 +- .../monaco/src/browser/monaco.keycode-map.ts | 3 +- .../monaco/src/browser/schema-registry.ts | 2 +- .../services/opened-editor-model.service.ts | 4 +- .../services/opened-editor-tree.service.ts | 5 +- .../browser/services/outline-model.service.ts | 4 +- .../src/browser/output-link.provider.ts | 32 +- packages/output/src/browser/output.channel.ts | 12 +- packages/overlay/src/browser/dialog.view.tsx | 4 +- .../src/browser/preference-contribution.ts | 3 +- .../browser/preference-settings.service.ts | 3 +- .../components/highlight-label/index.tsx | 4 +- .../browser/remote.opener.service.test.ts | 3 +- .../remote-opener/src/node/opener.service.ts | 2 +- .../dirty-diff/dirty-diff-model.test.ts | 4 +- .../dirty-diff/dirty-diff-widget.test.ts | 4 +- .../__tests__/browser/scm-activity.test.ts | 22 +- packages/scm/__tests__/scm-test-util.ts | 3 +- .../browser/components/scm-resource-input.tsx | 8 +- .../components/scm-resource-tree/index.tsx | 2 +- .../scm-resource-tree/scm-tree-api.ts | 14 +- .../scm-tree-model.service.ts | 9 +- .../scm-resource-tree/scm-tree-node.ts | 9 +- .../scm-resource-tree/scm-tree-node.view.tsx | 3 +- .../scm-resource-tree/scm-tree.service.ts | 3 +- .../dirty-diff/dirty-diff-controller.ts | 2 +- .../dirty-diff/dirty-diff-decorator.ts | 3 +- .../browser/dirty-diff/dirty-diff-model.ts | 17 +- .../browser/dirty-diff/dirty-diff-widget.ts | 6 +- packages/scm/src/browser/dirty-diff/index.ts | 4 +- packages/scm/src/browser/scm-activity.ts | 10 +- packages/scm/src/browser/scm-menu.ts | 3 +- packages/scm/src/browser/scm-model.ts | 11 +- packages/scm/src/browser/scm-util.ts | 4 +- packages/scm/src/browser/scm.contribution.ts | 4 +- packages/scm/src/common/scm.service.ts | 5 +- packages/scm/src/common/scm.ts | 4 +- packages/search/src/browser/search.service.ts | 35 +- packages/search/src/common/content-search.ts | 16 +- .../search/src/node/content-search.service.ts | 4 +- .../file-provider/browser-fs-provider.ts | 19 +- .../file-provider/ext-fs-provider.ts | 3 +- .../file-provider/index.contribution.ts | 7 +- .../overrides/browser-common-server.ts | 7 +- packages/storage/src/browser/storage-path.ts | 5 +- .../storage/src/browser/storage.service.ts | 5 +- packages/task/src/browser/parser.ts | 4 +- packages/task/src/browser/task-config.ts | 6 +- packages/task/src/browser/task.service.ts | 3 +- .../task/src/browser/terminal-task-system.ts | 10 +- packages/task/src/common/task.ts | 4 +- .../terminal-next/__tests__/browser/inject.ts | 12 +- .../validated-local-link-provider.test.ts | 3 +- .../__tests__/browser/mock.service.ts | 7 +- .../browser/terminal.service.test.ts | 5 +- .../environmentVariableCollection.test.ts | 4 +- .../src/browser/links/link-manager.ts | 9 +- .../links/validated-local-link-provider.ts | 3 +- .../src/browser/terminal.client.ts | 7 +- .../src/browser/terminal.input.ts | 2 +- .../src/browser/terminal.internal.service.ts | 6 +- .../src/browser/terminal.profile.internal.ts | 8 +- .../src/browser/terminal.profile.ts | 3 +- .../src/browser/terminal.service.ts | 9 +- packages/terminal-next/src/browser/xterm.ts | 1 - .../src/common/environmentVariable.ts | 5 +- .../common/environmentVariableCollection.ts | 9 +- packages/terminal-next/src/common/profile.ts | 3 +- packages/terminal-next/src/common/pty.ts | 5 +- packages/terminal-next/src/common/service.ts | 5 +- packages/terminal-next/src/node/pty.ts | 4 +- packages/terminal-next/src/node/shell.ts | 3 +- .../src/node/terminal.profile.service.ts | 5 +- .../src/node/terminal.service.client.ts | 9 +- .../testing/src/browser/test-decorations.ts | 5 +- .../src/browser/test-tree-view.model.ts | 4 +- .../src/browser/test.result.service.ts | 5 +- packages/testing/src/common/testingStates.ts | 4 +- packages/theme/src/browser/icon-theme-data.ts | 2 +- packages/theme/src/browser/icon.service.ts | 4 +- packages/theme/src/browser/theme-data.ts | 2 +- packages/theme/src/common/color.ts | 2 +- .../__tests__/arrary.test.ts | 173 +- .../__tests__/async.test.ts | 4 +- .../utils => utils/__tests__}/buffer.test.ts | 10 +- .../__tests__/cancellation.test.ts | 0 .../__tests__/charCode.test.ts | 0 .../__tests__/character-classifier.test.ts | 0 .../__tests__}/decorators.test.ts | 2 +- .../__tests__/encodings.test.ts | 2 +- .../__tests__/event.test.ts | 0 .../__tests__/filters.test.ts | 0 .../utils => utils/__tests__}/glob.test.ts | 140 +- .../__tests__/map.test.ts | 0 .../__tests__}/marshalling.test.ts | 2 +- .../utils => utils/__tests__}/objects.test.ts | 2 +- .../__tests__/path.test.ts | 8 +- .../__tests__/process.test.ts | 0 .../__tests__/uri.test.ts | 0 .../__tests__/uuid.test.ts | 0 packages/utils/package.json | 26 + .../src/utils => utils/src}/ansi.ts | 0 .../src/utils => utils/src}/arrays.ts | 226 +- packages/{core-common => utils}/src/async.ts | 26 +- .../src/utils => utils/src}/buffer.ts | 4 +- packages/{core-common => utils}/src/cache.ts | 0 .../src/cancellation.ts | 0 .../{core-common => utils}/src/charCode.ts | 0 .../src/character-classifier.ts | 0 .../src/const/encoding.ts} | 0 packages/utils/src/const/index.ts | 1 + packages/{core-common => utils}/src/date.ts | 2 +- .../src/utils => utils/src}/decorators.ts | 0 .../{core-common => utils}/src/disposable.ts | 0 .../index.ts => utils/src/encoding.ts} | 4 +- packages/{core-common => utils}/src/errors.ts | 0 packages/{core-common => utils}/src/event.ts | 0 .../src/utils => utils/src}/file-uri.ts | 5 +- .../{core-common => utils}/src/filters.ts | 6 +- .../{core-common => utils}/src/functional.ts | 0 .../src/utils => utils/src}/glob.ts | 46 +- .../src/utils => utils/src}/hash.ts | 0 packages/utils/src/index.ts | 40 + .../{core-common => utils}/src/iterator.ts | 0 .../{core-common => utils}/src/lifecycle.ts | 0 .../{core-common => utils}/src/linked-list.ts | 0 .../src/linked-text.ts} | 2 +- packages/utils/src/lru-map.ts | 133 ++ packages/{core-common => utils}/src/map.ts | 0 .../src/utils => utils/src}/marshalling.ts | 4 +- .../src/utils => utils/src}/objects.ts | 0 .../src/utils => utils/src}/os.ts | 42 +- packages/{core-common => utils}/src/path.ts | 63 +- .../{core-common => utils}/src/platform.ts | 15 +- .../{core-common => utils}/src/process.ts | 1 - .../{core-common => utils}/src/progress.ts | 2 +- .../src/utils => utils/src}/promise-util.ts | 0 .../{core-common => utils}/src/sequence.ts | 0 .../src/utils => utils/src}/strings.ts | 9 +- .../src/utils => utils/src}/types.ts | 0 packages/{core-common => utils}/src/uint.ts | 0 packages/{core-common => utils}/src/uri.ts | 2 +- packages/{core-common => utils}/src/uuid.ts | 0 .../webview/src/browser/webview.service.ts | 4 +- .../src/browser/refactor-preview.tsx | 7 +- .../src/browser/workspace-service.ts | 4 +- tools/template/package.json | 4 +- 370 files changed, 1593 insertions(+), 6126 deletions(-) create mode 100644 codecov.yml create mode 100644 configs/ts/references/tsconfig.utils.json delete mode 100644 packages/components/src/utils/cancellation.ts delete mode 100644 packages/components/src/utils/disposable.ts delete mode 100644 packages/components/src/utils/event.ts delete mode 100644 packages/components/src/utils/iterator.ts delete mode 100644 packages/components/src/utils/linkedList.ts delete mode 100644 packages/components/src/utils/os.ts delete mode 100644 packages/components/src/utils/path.ts delete mode 100644 packages/components/src/utils/process.ts rename packages/{core-common => core-browser}/__tests__/utils/json.test.ts (100%) create mode 100644 packages/core-browser/src/preferences/types.ts rename packages/{core-common => core-browser}/src/utils/json.ts (100%) delete mode 100644 packages/core-common/__tests__/utils/arrays.test.ts delete mode 100644 packages/core-common/__tests__/utils/paths.test.ts delete mode 100644 packages/core-common/__tests__/utils/strings.test.ts delete mode 100644 packages/core-common/src/arrays.ts rename packages/core-common/src/{utils => }/comparers.ts (97%) rename packages/core-common/src/{utils => }/markdown.ts (74%) delete mode 100644 packages/core-common/src/utils/index.ts delete mode 100644 packages/core-common/src/utils/paths.ts delete mode 100644 packages/extension/src/common/vscode/glob.ts delete mode 100644 packages/extension/src/common/vscode/paths.ts rename packages/{core-common => utils}/__tests__/arrary.test.ts (60%) rename packages/{core-common => utils}/__tests__/async.test.ts (100%) rename packages/{core-common/__tests__/utils => utils/__tests__}/buffer.test.ts (89%) rename packages/{core-common => utils}/__tests__/cancellation.test.ts (100%) rename packages/{core-common => utils}/__tests__/charCode.test.ts (100%) rename packages/{core-common => utils}/__tests__/character-classifier.test.ts (100%) rename packages/{core-common/__tests__/utils => utils/__tests__}/decorators.test.ts (98%) rename packages/{core-common => utils}/__tests__/encodings.test.ts (97%) rename packages/{core-common => utils}/__tests__/event.test.ts (100%) rename packages/{core-common => utils}/__tests__/filters.test.ts (100%) rename packages/{core-common/__tests__/utils => utils/__tests__}/glob.test.ts (86%) rename packages/{core-common => utils}/__tests__/map.test.ts (100%) rename packages/{core-common/__tests__/utils => utils/__tests__}/marshalling.test.ts (96%) rename packages/{core-common/__tests__/utils => utils/__tests__}/objects.test.ts (95%) rename packages/{core-common => utils}/__tests__/path.test.ts (99%) rename packages/{core-common => utils}/__tests__/process.test.ts (100%) rename packages/{core-common => utils}/__tests__/uri.test.ts (100%) rename packages/{core-common => utils}/__tests__/uuid.test.ts (100%) create mode 100644 packages/utils/package.json rename packages/{core-common/src/utils => utils/src}/ansi.ts (100%) rename packages/{core-common/src/utils => utils/src}/arrays.ts (52%) rename packages/{core-common => utils}/src/async.ts (96%) rename packages/{core-common/src/utils => utils/src}/buffer.ts (98%) rename packages/{core-common => utils}/src/cache.ts (100%) rename packages/{core-common => utils}/src/cancellation.ts (100%) rename packages/{core-common => utils}/src/charCode.ts (100%) rename packages/{core-common => utils}/src/character-classifier.ts (100%) rename packages/{core-common/src/const/encodings.ts => utils/src/const/encoding.ts} (100%) create mode 100644 packages/utils/src/const/index.ts rename packages/{core-common => utils}/src/date.ts (90%) rename packages/{core-common/src/utils => utils/src}/decorators.ts (100%) rename packages/{core-common => utils}/src/disposable.ts (100%) rename packages/{core-common/src/encoding/index.ts => utils/src/encoding.ts} (96%) rename packages/{core-common => utils}/src/errors.ts (100%) rename packages/{core-common => utils}/src/event.ts (100%) rename packages/{core-common/src/utils => utils/src}/file-uri.ts (94%) rename packages/{core-common => utils}/src/filters.ts (99%) rename packages/{core-common => utils}/src/functional.ts (100%) rename packages/{core-common/src/utils => utils/src}/glob.ts (94%) rename packages/{core-common/src/utils => utils/src}/hash.ts (100%) create mode 100644 packages/utils/src/index.ts rename packages/{core-common => utils}/src/iterator.ts (100%) rename packages/{core-common => utils}/src/lifecycle.ts (100%) rename packages/{core-common => utils}/src/linked-list.ts (100%) rename packages/{core-common/src/linkedText.ts => utils/src/linked-text.ts} (97%) create mode 100644 packages/utils/src/lru-map.ts rename packages/{core-common => utils}/src/map.ts (100%) rename packages/{core-common/src/utils => utils/src}/marshalling.ts (97%) rename packages/{core-common/src/utils => utils/src}/objects.ts (100%) rename packages/{core-common/src/utils => utils/src}/os.ts (69%) rename packages/{core-common => utils}/src/path.ts (96%) rename packages/{core-common => utils}/src/platform.ts (89%) rename packages/{core-common => utils}/src/process.ts (99%) rename packages/{core-common => utils}/src/progress.ts (97%) rename packages/{core-common/src/utils => utils/src}/promise-util.ts (100%) rename packages/{core-common => utils}/src/sequence.ts (100%) rename packages/{core-common/src/utils => utils/src}/strings.ts (99%) rename packages/{core-common/src/utils => utils/src}/types.ts (100%) rename packages/{core-common => utils}/src/uint.ts (100%) rename packages/{core-common => utils}/src/uri.ts (99%) rename packages/{core-common => utils}/src/uuid.ts (100%) diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000000..d4ed5b5622 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,8 @@ +coverage: + status: + project: + default: + target: auto + # allow coverage to drop by this amount and still post success + threshold: 0.5% + if_ci_failed: error diff --git a/configs/ts/references/tsconfig.utils.json b/configs/ts/references/tsconfig.utils.json new file mode 100644 index 0000000000..4650e5627d --- /dev/null +++ b/configs/ts/references/tsconfig.utils.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.base.json", + "compilerOptions": { + "rootDir": "../../../packages/utils/src", + "outDir": "../../../packages/utils/lib" + }, + "include": ["../../../packages/utils/src"] +} diff --git a/configs/ts/tsconfig.build.json b/configs/ts/tsconfig.build.json index e95364700b..ee89973b3c 100644 --- a/configs/ts/tsconfig.build.json +++ b/configs/ts/tsconfig.build.json @@ -1,5 +1,8 @@ { "references": [ + { + "path": "./references/tsconfig.utils.json" + }, { "path": "./references/tsconfig.core-common.json" }, diff --git a/configs/ts/tsconfig.resolve.json b/configs/ts/tsconfig.resolve.json index 795b546997..a02bdff2ad 100644 --- a/configs/ts/tsconfig.resolve.json +++ b/configs/ts/tsconfig.resolve.json @@ -3,6 +3,8 @@ "compilerOptions": { "baseUrl": "..", "paths": { + "@opensumi/ide-utils": ["../packages/utils/src/index.ts"], + "@opensumi/ide-utils/lib/*": ["../packages/utils/src/*"], "@opensumi/ide-addons": ["../packages/addons/src/index.ts"], "@opensumi/ide-addons/lib/*": ["../packages/addons/src/*"], "@opensumi/ide-comments": ["../packages/comments/src/index.ts"], diff --git a/jest.config.js b/jest.config.js index b63ebbb935..44e054e850 100644 --- a/jest.config.js +++ b/jest.config.js @@ -35,24 +35,15 @@ const baseConfig = { '/packages/quick-open/entry', // 终端渲染测试暂时不跟随单元测试 '/packages/terminal-next/__tests__/browser/render.test.ts', - // components utils 均引用自 @opensumi/ide-core-common 模块,无须重复测试 - // 后续统一至 @opensumi/ide-utils 模块 - '/packages/components/src/utils', ], modulePathIgnorePatterns: ['/dist/'], coveragePathIgnorePatterns: [ '/dist/', '/node_modules/', - '/__test__/', '/mocks/', '/tools/template/', '/tools/workspace/', - '/packages/status-bar/entry', '/packages/startup/entry', - '/packages/quick-open/entry', - // components 下的 utils 均引用自 @opensumi/ide-core-common 模块,无须重复测试 - // 后续统一至 @opensumi/ide-utils 模块 - '/packages/components/src/utils', ], coverageThreshold: { global: { @@ -78,7 +69,7 @@ module.exports = { // 有个 webview 的 case 应该放在 electron 下测,也会被第一条规则匹配到 // - packages/webview/__tests__/webview/webview.channel.test.ts '**/packages/*/__test?(s)__/!(browser)/**/?(*.)+(spec|test).[jt]s?(x)', - '**/packages/{core-common,core-electron-main,core-node,electron-basic}/__tests__/**/?(*.)+(spec|test).[jt]s?(x)', + '**/packages/{core-common,core-electron-main,core-node,electron-basic,utils}/__tests__/**/?(*.)+(spec|test).[jt]s?(x)', // exclude 的要放最后 '!**/packages/{components,core-browser}/__tests__/**', ], @@ -93,6 +84,9 @@ module.exports = { `, runScripts: 'dangerously', url: 'http://localhost/?id=1', + userAgent: `Mozilla/5.0 (${ + process.platform === 'darwin' ? 'Macintosh' : process.platform === 'win32' ? 'Windows' : 'Linux' + }) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/v16.7.0`, }, setupFiles: ['./jest.setup.jsdom.js'], testMatch: [ diff --git a/jest.setup.node.js b/jest.setup.node.js index f1080e4091..8f477e68e2 100644 --- a/jest.setup.node.js +++ b/jest.setup.node.js @@ -1,4 +1,12 @@ -const { JSDOM } = require('jsdom'); +const { JSDOM, ResourceLoader } = require('jsdom'); + +const resourceLoader = new ResourceLoader({ + strictSSL: false, + userAgent: `Mozilla/5.0 (${ + process.platform === 'darwin' ? 'Macintosh' : process.platform === 'win32' ? 'Windows' : 'Linux' + }) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/v16.7.0`, +}); + const jsdom = new JSDOM('
', { // https://github.com/jsdom/jsdom#basic-options // 禁用掉 resources: usable, 采用 jsdom 默认策略不加载 subresources @@ -6,6 +14,8 @@ const jsdom = new JSDOM('
', { // resources: 'usable', runScripts: 'dangerously', url: 'http://localhost/?id=1', + // 保障 `platform.ts` 中 isLinux 等平台信息判断准确性 + resources: resourceLoader, }); global.document = jsdom.window.document; let text = ''; diff --git a/packages/addons/src/browser/file-drop.service.ts b/packages/addons/src/browser/file-drop.service.ts index 0a1ba91430..d0d566d3ee 100644 --- a/packages/addons/src/browser/file-drop.service.ts +++ b/packages/addons/src/browser/file-drop.service.ts @@ -1,11 +1,12 @@ import { Injectable, Autowired } from '@opensumi/di'; -import { Path } from '@opensumi/ide-components/lib/utils/path'; -import { Uri, formatLocalize } from '@opensumi/ide-core-browser/lib'; +import { formatLocalize } from '@opensumi/ide-core-browser'; import { IStatusBarService, StatusBarAlignment, StatusBarEntryAccessor } from '@opensumi/ide-core-browser/lib/services'; -import { WithEventBus } from '@opensumi/ide-core-common/lib'; +import { WithEventBus, Uri, path } from '@opensumi/ide-core-common'; import { FileTreeDropEvent } from '@opensumi/ide-core-common/lib/types/dnd'; import { IFileServiceClient } from '@opensumi/ide-file-service/lib/common'; +const { Path } = path; + import { IFileDropFrontendService, IFileDropBackendService, diff --git a/packages/comments/src/browser/comments.service.ts b/packages/comments/src/browser/comments.service.ts index 1c453215ff..f738c347fa 100644 --- a/packages/comments/src/browser/comments.service.ts +++ b/packages/comments/src/browser/comments.service.ts @@ -17,9 +17,9 @@ import { IDisposable, positionToRange, Deferred, + path, + LRUCache, } from '@opensumi/ide-core-browser'; -import { LRUCache } from '@opensumi/ide-core-common/lib/map'; -import { dirname } from '@opensumi/ide-core-common/lib/path'; import { IEditor } from '@opensumi/ide-editor'; import { IEditorDecorationCollectionService, @@ -46,6 +46,8 @@ import { import { CommentsPanel } from './comments-panel.view'; import { CommentsThread } from './comments-thread'; +const { dirname } = path; + @Injectable() export class CommentsService extends Disposable implements ICommentsService { @Autowired(INJECTOR_TOKEN) diff --git a/packages/components/package.json b/packages/components/package.json index f7a9c80321..39b0fe042e 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -17,6 +17,7 @@ "dependencies": { "@ant-design/icons": "^4.6.4", "@types/react-window": "^1.8.5", + "@opensumi/ide-utils": "2.17.0", "fuzzy": "^0.1.3", "lodash": "^4.17.15", "raf": "^3.4.1", diff --git a/packages/components/src/recycle-tree/RecycleTree.tsx b/packages/components/src/recycle-tree/RecycleTree.tsx index 682592a8e2..5a29dd63ae 100644 --- a/packages/components/src/recycle-tree/RecycleTree.tsx +++ b/packages/components/src/recycle-tree/RecycleTree.tsx @@ -2,8 +2,17 @@ import fuzzy from 'fuzzy'; import React from 'react'; import { FixedSizeList, VariableSizeList, shouldComponentUpdate, ListProps } from 'react-window'; +import { + DisposableCollection, + Emitter, + Event, + Disposable, + CancellationTokenSource, + CancellationToken, + Throttler, +} from '@opensumi/ide-utils'; + import { ScrollbarsVirtualList } from '../scrollbars'; -import { DisposableCollection, Emitter, Event, Disposable, CancellationTokenSource, CancellationToken } from '../utils'; import { RenamePromptHandle, PromptHandle } from './prompt'; import { NewPromptHandle } from './prompt/NewPromptHandle'; @@ -286,8 +295,7 @@ export class RecycleTree extends React.Component { private willUpdateTasks = 0; - private updateTimer; - private updateTime = 0; + private queueUpdateThrottler: Throttler = new Throttler(); // 批量更新Tree节点 private doBatchUpdate = (() => { @@ -376,52 +384,12 @@ export class RecycleTree extends React.Component { }; })(); - // FIXME: 待 @opensumi/ide-utils 合入后可合并逻辑至 Throttler.queue private batchUpdate = () => { this.willUpdateTasks++; - this.queueUpdatePromise = this.queueUpdate(this.doBatchUpdate); + this.queueUpdatePromise = this.queueUpdateThrottler.queue(this.doBatchUpdate); return this.queueUpdatePromise; }; - private queueUpdate(promiseFactory: () => Promise) { - if (this.activePromise) { - this.queuedPromiseFactory = promiseFactory; - - if (!this.queuedPromise) { - const onComplete = () => { - this.queuedPromise = null; - - const result = this.queueUpdate(this.queuedPromiseFactory!); - this.queuedPromiseFactory = null; - - return result; - }; - - this.queuedPromise = new Promise((c) => { - this.activePromise!.then(onComplete, onComplete).then(c); - }); - } - return new Promise((c, e) => { - this.queuedPromise!.then(c, e); - }); - } - - this.activePromise = promiseFactory(); - - return new Promise((c, e) => { - this.activePromise!.then( - (result: any) => { - this.activePromise = null; - c(result); - }, - (err: any) => { - this.activePromise = null; - e(err); - }, - ); - }); - } - private getNewPromptInsertIndex(startIndex: number, parent: CompositeTreeNode) { const { root } = this.props.model; let insertIndex: number = startIndex + 1; diff --git a/packages/components/src/recycle-tree/basic/tree-service.ts b/packages/components/src/recycle-tree/basic/tree-service.ts index 093996ffad..9759ab827a 100644 --- a/packages/components/src/recycle-tree/basic/tree-service.ts +++ b/packages/components/src/recycle-tree/basic/tree-service.ts @@ -1,4 +1,5 @@ -import { DisposableCollection, Emitter } from '../../utils'; +import { DisposableCollection, Emitter } from '@opensumi/ide-utils'; + import { TreeModel, Tree, Decoration, DecorationsManager } from '../tree'; import { TreeNodeEvent } from '../types'; diff --git a/packages/components/src/recycle-tree/prompt/PromptHandle.ts b/packages/components/src/recycle-tree/prompt/PromptHandle.ts index ab18de60e4..8e7e2a7bc6 100644 --- a/packages/components/src/recycle-tree/prompt/PromptHandle.ts +++ b/packages/components/src/recycle-tree/prompt/PromptHandle.ts @@ -1,5 +1,6 @@ +import { DisposableCollection, Emitter, Event, IAsyncResult } from '@opensumi/ide-utils'; + import { bindInputElement, ProxiedInputProp } from '../../input'; -import { DisposableCollection, Emitter, Event, IAsyncResult } from '../../utils'; const delay = (ms) => new Promise((res) => setTimeout(res, ms)); @@ -171,7 +172,7 @@ export abstract class PromptHandle { return; } // 获取最顶层的父级焦点容器 - let element = this.focusPrevActiveElement(); + const element = this.focusPrevActiveElement(); this._destroyed = true; this.$.removeEventListener('click', this.handleClick); this.$.removeEventListener('keyup', this.handleKeyup); diff --git a/packages/components/src/recycle-tree/tree/Tree.ts b/packages/components/src/recycle-tree/tree/Tree.ts index 43555c9575..c318153f7a 100644 --- a/packages/components/src/recycle-tree/tree/Tree.ts +++ b/packages/components/src/recycle-tree/tree/Tree.ts @@ -1,4 +1,5 @@ -import { Emitter, DisposableCollection } from '../../utils'; +import { Emitter, DisposableCollection } from '@opensumi/ide-utils'; + import { ITreeNodeOrCompositeTreeNode, ITree, ICompositeTreeNode } from '../types'; import { TreeNode, CompositeTreeNode } from './TreeNode'; diff --git a/packages/components/src/recycle-tree/tree/TreeNode.ts b/packages/components/src/recycle-tree/tree/TreeNode.ts index fd316df366..cb27c09adf 100644 --- a/packages/components/src/recycle-tree/tree/TreeNode.ts +++ b/packages/components/src/recycle-tree/tree/TreeNode.ts @@ -1,5 +1,14 @@ /* eslint-disable @typescript-eslint/prefer-for-of */ -import { Event, Emitter, DisposableCollection, Path, CancellationToken, CancellationTokenSource } from '../../utils'; +import { + Event, + Emitter, + DisposableCollection, + path, + CancellationToken, + CancellationTokenSource, + Throttler, +} from '@opensumi/ide-utils'; + import { IWatcherCallback, IWatchTerminator, @@ -18,6 +27,7 @@ import { IAccessibilityInformation, } from '../types'; +const { Path } = path; /** * 裁剪数组 * @@ -349,9 +359,7 @@ export class CompositeTreeNode extends TreeNode implements ICompositeTreeNode { private _branchSize: number; private _flattenedBranch: number[] | null; - private activeRefreshPromise: Promise | null; - private queuedRefreshPromise: Promise | null; - private queuedRefreshPromiseFactory: ((token?: CancellationToken) => Promise) | null; + private refreshThrottler: Throttler = new Throttler(); private _lock = false; @@ -1414,54 +1422,12 @@ export class CompositeTreeNode extends TreeNode implements ICompositeTreeNode { } else { token = state.refreshCancelToken.token; } - await this.queue(this.doRefresh.bind(this), token); + await this.refreshThrottler.queue(async () => this.doRefresh(token)); TreeNode.setGlobalTreeState(this.path, { isRefreshing: false, }); } - private async queue(promiseFactory: (token?: CancellationToken) => Promise, token?: CancellationToken) { - if (this.activeRefreshPromise) { - this.queuedRefreshPromiseFactory = promiseFactory; - - if (!this.queuedRefreshPromise) { - const onComplete = () => { - if (token?.isCancellationRequested) { - return async () => {}; - } - this.queuedRefreshPromise = null; - const result = this.queue(() => this.queuedRefreshPromiseFactory!(token)); - this.queuedRefreshPromiseFactory = null; - - return result; - }; - - this.queuedRefreshPromise = new Promise((resolve) => { - this.activeRefreshPromise?.then(onComplete, onComplete).then(resolve); - }); - } - - return new Promise((c, e) => { - this.queuedRefreshPromise?.then(c, e); - }); - } - - this.activeRefreshPromise = promiseFactory(token); - - return new Promise((c, e) => { - this.activeRefreshPromise?.then( - (result: any) => { - this.activeRefreshPromise = null; - c(result); - }, - (err: any) => { - this.activeRefreshPromise = null; - e(err); - }, - ); - }); - } - private async doRefresh(token?: CancellationToken) { const paths = this.getAllExpandedNodePath(); await this.refreshTreeNodeByPaths(paths, true, token); diff --git a/packages/components/src/recycle-tree/tree/decoration/CompositeDecoration.ts b/packages/components/src/recycle-tree/tree/decoration/CompositeDecoration.ts index 6591ec666c..955ef456f9 100644 --- a/packages/components/src/recycle-tree/tree/decoration/CompositeDecoration.ts +++ b/packages/components/src/recycle-tree/tree/decoration/CompositeDecoration.ts @@ -1,4 +1,5 @@ -import { DisposableCollection } from '../../../utils'; +import { DisposableCollection } from '@opensumi/ide-utils'; + import { ITreeNodeOrCompositeTreeNode } from '../../types'; import { Decoration, TargetMatchMode, IDecorationEventData } from './Decoration'; diff --git a/packages/components/src/recycle-tree/tree/decoration/Decoration.ts b/packages/components/src/recycle-tree/tree/decoration/Decoration.ts index 2da0fd5cf6..a59fdc6e8c 100644 --- a/packages/components/src/recycle-tree/tree/decoration/Decoration.ts +++ b/packages/components/src/recycle-tree/tree/decoration/Decoration.ts @@ -1,4 +1,5 @@ -import { IDisposable, Disposable, Emitter } from '../../../utils'; +import { IDisposable, Disposable, Emitter } from '@opensumi/ide-utils'; + import { ITreeNode, ICompositeTreeNode } from '../../types'; import { TreeNode } from '../TreeNode'; diff --git a/packages/components/src/recycle-tree/tree/decoration/DecorationManager.ts b/packages/components/src/recycle-tree/tree/decoration/DecorationManager.ts index 77b12ad2c7..5321c94270 100644 --- a/packages/components/src/recycle-tree/tree/decoration/DecorationManager.ts +++ b/packages/components/src/recycle-tree/tree/decoration/DecorationManager.ts @@ -1,4 +1,5 @@ -import { IDisposable, DisposableCollection } from '../../../utils'; +import { IDisposable, DisposableCollection } from '@opensumi/ide-utils'; + import { TreeNodeEvent, ITreeNodeOrCompositeTreeNode } from '../../types'; import { TreeNode, CompositeTreeNode } from '../TreeNode'; diff --git a/packages/components/src/recycle-tree/tree/model/TreeModel.ts b/packages/components/src/recycle-tree/tree/model/TreeModel.ts index c2a427a2f0..d2fedc4220 100644 --- a/packages/components/src/recycle-tree/tree/model/TreeModel.ts +++ b/packages/components/src/recycle-tree/tree/model/TreeModel.ts @@ -1,4 +1,5 @@ -import { Event, Emitter } from '../../../utils'; +import { Event, Emitter } from '@opensumi/ide-utils'; + import { ICompositeTreeNode, TreeNodeEvent } from '../../types'; import { CompositeTreeNode, TreeNode } from '../TreeNode'; diff --git a/packages/components/src/recycle-tree/tree/model/treeState/TreeStateManager.ts b/packages/components/src/recycle-tree/tree/model/treeState/TreeStateManager.ts index 9bc7599605..67847e6e28 100644 --- a/packages/components/src/recycle-tree/tree/model/treeState/TreeStateManager.ts +++ b/packages/components/src/recycle-tree/tree/model/treeState/TreeStateManager.ts @@ -1,9 +1,12 @@ -import { Event, Emitter, Path } from '../../../../utils'; +import { Event, Emitter, path } from '@opensumi/ide-utils'; + import { TreeNodeEvent, ITreeNodeOrCompositeTreeNode } from '../../../types'; import { CompositeTreeNode, TreeNode } from '../../TreeNode'; import { ISerializableState } from './types'; +const { Path } = path; + export enum Operation { SetExpanded = 1, SetCollapsed, diff --git a/packages/components/src/recycle-tree/tree/model/treeState/TreeStateWatcher.ts b/packages/components/src/recycle-tree/tree/model/treeState/TreeStateWatcher.ts index 0248230ab7..dfb19953b0 100644 --- a/packages/components/src/recycle-tree/tree/model/treeState/TreeStateWatcher.ts +++ b/packages/components/src/recycle-tree/tree/model/treeState/TreeStateWatcher.ts @@ -1,4 +1,4 @@ -import { Event, Emitter, IDisposable, DisposableCollection } from '../../../../utils'; +import { Event, Emitter, IDisposable, DisposableCollection } from '@opensumi/ide-utils'; import { TreeStateManager, IPathChange, IExpansionStateChange } from './TreeStateManager'; import { ISerializableState, TreeStateWatcherChangeType as TreeStateChangeType } from './types'; diff --git a/packages/components/src/recycle-tree/types/watcher.ts b/packages/components/src/recycle-tree/types/watcher.ts index 9acf91b737..69a126e2c2 100644 --- a/packages/components/src/recycle-tree/types/watcher.ts +++ b/packages/components/src/recycle-tree/types/watcher.ts @@ -1,4 +1,4 @@ -import { IDisposable } from '../../utils'; +import { IDisposable } from '@opensumi/ide-utils'; import { ITreeNode, ICompositeTreeNode, ITreeNodeOrCompositeTreeNode } from './tree-node'; diff --git a/packages/components/src/utils/cancellation.ts b/packages/components/src/utils/cancellation.ts deleted file mode 100644 index 18b4f1733d..0000000000 --- a/packages/components/src/utils/cancellation.ts +++ /dev/null @@ -1,132 +0,0 @@ -// Modify from @opensumi/ide-core-common/src/cancellation.ts - -import { IDisposable } from './disposable'; -import { Emitter, Event } from './event'; - -export interface CancellationToken { - readonly isCancellationRequested: boolean; - /** - * An event emitted when cancellation is requested - * @event - */ - readonly onCancellationRequested: Event; -} - -const shortcutEvent = Object.freeze(function (callback, context?): IDisposable { - const handle = setTimeout(callback.bind(context), 0); - return { - dispose() { - clearTimeout(handle); - }, - }; -} as Event); - -export namespace CancellationToken { - export function isCancellationToken(thing: any): thing is CancellationToken { - if (thing === CancellationToken.None || thing === CancellationToken.Cancelled) { - return true; - } - if (thing instanceof MutableToken) { - return true; - } - if (!thing || typeof thing !== 'object') { - return false; - } - return ( - typeof (thing as CancellationToken).isCancellationRequested === 'boolean' && - typeof (thing as CancellationToken).onCancellationRequested === 'function' - ); - } - - export const None: CancellationToken = Object.freeze({ - isCancellationRequested: false, - onCancellationRequested: Event.None, - }); - - export const Cancelled: CancellationToken = Object.freeze({ - isCancellationRequested: true, - onCancellationRequested: shortcutEvent, - }); -} - -class MutableToken implements CancellationToken { - private _isCancelled = false; - private _emitter: Emitter | null = null; - - public cancel() { - if (!this._isCancelled) { - this._isCancelled = true; - if (this._emitter) { - this._emitter.fire(undefined); - this.dispose(); - } - } - } - - get isCancellationRequested(): boolean { - return this._isCancelled; - } - - get onCancellationRequested(): Event { - if (this._isCancelled) { - return shortcutEvent; - } - if (!this._emitter) { - this._emitter = new Emitter(); - } - return this._emitter.event; - } - - public dispose(): void { - if (this._emitter) { - this._emitter.dispose(); - this._emitter = null; - } - } -} - -export class CancellationTokenSource { - private _token?: CancellationToken = undefined; - private _parentListener?: IDisposable = undefined; - - constructor(parent?: CancellationToken) { - this._parentListener = parent && parent.onCancellationRequested(this.cancel, this); - } - - get token(): CancellationToken { - if (!this._token) { - // be lazy and create the token only when - // actually needed - this._token = new MutableToken(); - } - return this._token; - } - - cancel(): void { - if (!this._token) { - // save an object by returning the default - // cancelled token when cancellation happens - // before someone asks for the token - this._token = CancellationToken.Cancelled; - } else if (this._token instanceof MutableToken) { - // actually cancel - this._token.cancel(); - } - } - - dispose(cancel = false): void { - if (cancel) { - this.cancel(); - } - if (this._parentListener) { - this._parentListener.dispose(); - } - if (!this._token) { - // ensure to initialize with an empty token if we had none - this._token = CancellationToken.None; - } else if (this._token instanceof MutableToken) { - // actually dispose - this._token.dispose(); - } - } -} diff --git a/packages/components/src/utils/disposable.ts b/packages/components/src/utils/disposable.ts deleted file mode 100644 index 159523e97e..0000000000 --- a/packages/components/src/utils/disposable.ts +++ /dev/null @@ -1,161 +0,0 @@ -// Modify from @opensumi/ide-core-common/src/disposable.ts -import { Event, Emitter } from './event'; - -export interface IDisposable { - /** - * Dispose this object. - */ - dispose(): void; -} - -export class Disposable implements IDisposable { - protected readonly disposables: IDisposable[] = []; - protected readonly onDisposeEmitter = new Emitter(); - - constructor(...toDispose: IDisposable[]) { - toDispose.forEach((d) => this.addDispose(d)); - } - - static create(func: () => void): IDisposable { - return { - dispose: func, - }; - } - - static NULL = Disposable.create(() => {}); - - static None = Object.freeze({ dispose() {} }); - - get onDispose(): Event { - return this.onDisposeEmitter.event; - } - - protected checkDisposed(): void { - if (this.disposed && !this.disposingElements) { - this.onDisposeEmitter.fire(undefined); - } - } - - get disposed(): boolean { - return this.disposables.length === 0; - } - - private disposingElements = false; - dispose(): void { - if (this.disposed || this.disposingElements) { - return; - } - this.disposingElements = true; - while (!this.disposed) { - try { - this.disposables.pop()!.dispose(); - } catch (e) { - // eslint-disable-next-line no-console - console.error(e); - } - } - this.disposingElements = false; - this.checkDisposed(); - } - - addDispose(disposable: IDisposable): IDisposable; - addDispose(disposable: IDisposable[]): IDisposable[]; - addDispose(disposable: IDisposable | IDisposable[]): IDisposable | IDisposable[] { - if (Array.isArray(disposable)) { - const disposables = disposable; - return disposables.map((disposable) => this.addDispose(disposable)); - } else { - return this.add(disposable); - } - } - - protected registerDispose(disposable: T): T { - if ((disposable as any as Disposable) === this) { - throw new Error('Cannot register a disposable on itself!'); - } - - this.add(disposable); - return disposable; - } - - private add(disposable: IDisposable): IDisposable { - const disposables = this.disposables; - disposables.push(disposable); - const originalDispose = disposable.dispose.bind(disposable); - const toRemove = Disposable.create(() => { - const index = disposables.indexOf(disposable); - if (index !== -1) { - disposables.splice(index, 1); - } - this.checkDisposed(); - }); - disposable.dispose = () => { - toRemove.dispose(); - originalDispose(); - }; - return toRemove; - } -} - -export class DisposableCollection implements IDisposable { - protected readonly disposables: IDisposable[] = []; - protected readonly onDisposeEmitter = new Emitter(); - - constructor(...toDispose: IDisposable[]) { - toDispose.forEach((d) => this.push(d)); - } - - get onDispose(): Event { - return this.onDisposeEmitter.event; - } - - protected checkDisposed(): void { - if (this.disposed && !this.disposingElements) { - this.onDisposeEmitter.fire(undefined); - } - } - - get disposed(): boolean { - return this.disposables.length === 0; - } - - private disposingElements = false; - dispose(): void { - if (this.disposed || this.disposingElements) { - return; - } - this.disposingElements = true; - while (!this.disposed) { - try { - this.disposables.pop()!.dispose(); - } catch (e) { - // eslint-disable-next-line no-console - console.error(e); - } - } - this.disposingElements = false; - this.checkDisposed(); - } - - push(disposable: IDisposable): IDisposable { - const disposables = this.disposables; - disposables.push(disposable); - const originalDispose = disposable.dispose.bind(disposable); - const toRemove = Disposable.create(() => { - const index = disposables.indexOf(disposable); - if (index !== -1) { - disposables.splice(index, 1); - } - this.checkDisposed(); - }); - disposable.dispose = () => { - toRemove.dispose(); - originalDispose(); - }; - return toRemove; - } - - pushAll(disposables: IDisposable[]): IDisposable[] { - return disposables.map((disposable) => this.push(disposable)); - } -} diff --git a/packages/components/src/utils/event.ts b/packages/components/src/utils/event.ts deleted file mode 100644 index 365eec4ec8..0000000000 --- a/packages/components/src/utils/event.ts +++ /dev/null @@ -1,732 +0,0 @@ -// Modify from @opensumi/ide-core-common/src/event.ts -import { IDisposable } from './disposable'; -import { LinkedList } from './linkedList'; - -/** - * To an event a function with one or zero parameters - * can be subscribed. The event is the subscriber function itself. - */ -export type Event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]) => IDisposable; - -export namespace Event { - const _disposable = { dispose() {} }; - export const None: Event = () => _disposable; - - /** - * Given an event, returns another event which only fires once. - */ - export function once(event: Event): Event { - return (listener, thisArgs = null, disposables?) => { - // we need this, in case the event fires during the listener call - let didFire = false; - const result = event( - (e) => { - if (didFire) { - return; - } else if (result) { - result.dispose(); - } else { - didFire = true; - } - - return listener.call(thisArgs, e); - }, - null, - disposables, - ); - - if (didFire) { - result.dispose(); - } - - return result; - }; - } - - /** - * Given an event and a `map` function, returns another event which maps each element - * throught the mapping function. - */ - export function map(event: Event, map: (i: I) => O): Event { - return snapshot((listener, thisArgs = null, disposables?) => - event((i) => listener.call(thisArgs, map(i)), null, disposables), - ); - } - - /** - * Given an event and an `each` function, returns another identical event and calls - * the `each` function per each element. - */ - export function forEach(event: Event, each: (i: I) => void): Event { - return snapshot((listener, thisArgs = null, disposables?) => - event( - (i) => { - each(i); - listener.call(thisArgs, i); - }, - null, - disposables, - ), - ); - } - - /** - * Given an event and a `filter` function, returns another event which emits those - * elements for which the `filter` function returns `true`. - */ - export function filter(event: Event, filter: (e: T) => boolean): Event; - export function filter(event: Event, filter: (e: T | R) => e is R): Event; - export function filter(event: Event, filter: (e: T) => boolean): Event { - return snapshot((listener, thisArgs = null, disposables?) => - event((e) => filter(e) && listener.call(thisArgs, e), null, disposables), - ); - } - - /** - * Given an event, returns the same event but typed as `Event`. - */ - export function signal(event: Event): Event { - return event as Event as Event; - } - - /** - * Given an event and a `merge` function, returns another event which maps each element - * and the cummulative result throught the `merge` function. Similar to `map`, but with memory. - */ - export function reduce(event: Event, merge: (last: O | undefined, event: I) => O, initial?: O): Event { - let output: O | undefined = initial; - - return map(event, (e) => { - output = merge(output, e); - return output; - }); - } - - /** - * Given a chain of event processing functions (filter, map, etc), each - * function will be invoked per event & per listener. Snapshotting an event - * chain allows each function to be invoked just once per event. - */ - export function snapshot(event: Event): Event { - let listener: IDisposable; - const emitter = new Emitter({ - onFirstListenerAdd() { - listener = event(emitter.fire, emitter); - }, - onLastListenerRemove() { - listener.dispose(); - }, - }); - - return emitter.event; - } - - /** - * Debounces the provided event, given a `merge` function. - * - * @param event The input event. - * @param merge The reducing function. - * @param delay The debouncing delay in millis. - * @param leading Whether the event should fire in the leading phase of the timeout. - * @param leakWarningThreshold The leak warning threshold override. - */ - export function debounce( - event: Event, - merge: (last: T | undefined, event: T) => T, - delay?: number, - leading?: boolean, - leakWarningThreshold?: number, - ): Event; - export function debounce( - event: Event, - merge: (last: O | undefined, event: I) => O, - delay?: number, - leading?: boolean, - leakWarningThreshold?: number, - ): Event; - export function debounce( - event: Event, - merge: (last: O | undefined, event: I) => O, - delay = 100, - leading = false, - leakWarningThreshold?: number, - ): Event { - let subscription: IDisposable; - let output: O | undefined; - let handle: any; - let numDebouncedCalls = 0; - - const emitter = new Emitter({ - leakWarningThreshold, - onFirstListenerAdd() { - subscription = event((cur) => { - numDebouncedCalls++; - output = merge(output, cur); - - if (leading && !handle) { - emitter.fire(output); - } - - clearTimeout(handle); - handle = setTimeout(() => { - const _output = output; - output = undefined; - handle = undefined; - if (!leading || numDebouncedCalls > 1) { - emitter.fire(_output!); - } - - numDebouncedCalls = 0; - }, delay); - }); - }, - onLastListenerRemove() { - subscription.dispose(); - }, - }); - - return emitter.event; - } - - /** - * Given an event, it returns another event which fires only once and as soon as - * the input event emits. The event data is the number of millis it took for the - * event to fire. - */ - export function stopwatch(event: Event): Event { - const start = new Date().getTime(); - return map(once(event), (_) => new Date().getTime() - start); - } - - /** - * Given an event, it returns another event which fires only when the event - * element changes. - */ - export function latch(event: Event): Event { - let firstCall = true; - let cache: T; - - return filter(event, (value) => { - const shouldEmit = firstCall || value !== cache; - firstCall = false; - cache = value; - return shouldEmit; - }); - } - - /** - * Buffers the provided event until a first listener comes - * along, at which point fire all the events at once and - * pipe the event from then on. - * - * ```typescript - * const emitter = new Emitter(); - * const event = emitter.event; - * const bufferedEvent = buffer(event); - * - * emitter.fire(1); - * emitter.fire(2); - * emitter.fire(3); - * // nothing... - * - * const listener = bufferedEvent(num => console.log(num)); - * // 1, 2, 3 - * - * emitter.fire(4); - * // 4 - * ``` - */ - export function buffer(event: Event, nextTick = false, _buffer: T[] = []): Event { - let buffer: T[] | null = _buffer.slice(); - - let listener: IDisposable | null = event((e) => { - if (buffer) { - buffer.push(e); - } else { - emitter.fire(e); - } - }); - - const flush = () => { - if (buffer) { - buffer.forEach((e) => emitter.fire(e)); - } - buffer = null; - }; - - const emitter = new Emitter({ - onFirstListenerAdd() { - if (!listener) { - listener = event((e) => emitter.fire(e)); - } - }, - - onFirstListenerDidAdd() { - if (buffer) { - if (nextTick) { - setTimeout(flush); - } else { - flush(); - } - } - }, - - onLastListenerRemove() { - if (listener) { - listener.dispose(); - } - listener = null; - }, - }); - - return emitter.event; - } - - export interface IChainableEvent { - event: Event; - map(fn: (i: T) => O): IChainableEvent; - forEach(fn: (i: T) => void): IChainableEvent; - filter(fn: (e: T) => boolean): IChainableEvent; - reduce(merge: (last: R | undefined, event: T) => R, initial?: R): IChainableEvent; - latch(): IChainableEvent; - on(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable; - once(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable; - } - - class ChainableEvent implements IChainableEvent { - constructor(readonly event: Event) {} - - map(fn: (i: T) => O): IChainableEvent { - return new ChainableEvent(map(this.event, fn)); - } - - forEach(fn: (i: T) => void): IChainableEvent { - return new ChainableEvent(forEach(this.event, fn)); - } - - filter(fn: (e: T) => boolean): IChainableEvent { - return new ChainableEvent(filter(this.event, fn)); - } - - reduce(merge: (last: R | undefined, event: T) => R, initial?: R): IChainableEvent { - return new ChainableEvent(reduce(this.event, merge, initial)); - } - - latch(): IChainableEvent { - return new ChainableEvent(latch(this.event)); - } - - on(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[]) { - return this.event(listener, thisArgs, disposables); - } - - once(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[]) { - return once(this.event)(listener, thisArgs, disposables); - } - } - - export function chain(event: Event): IChainableEvent { - return new ChainableEvent(event); - } - - export interface NodeEventEmitter { - on(event: string | symbol, listener: () => void): this; - removeListener(event: string | symbol, listener: () => void): this; - } - - export function fromNodeEventEmitter( - emitter: NodeEventEmitter, - eventName: string, - map: (...args: any[]) => T = (id) => id, - ): Event { - const fn = (...args: any[]) => result.fire(map(...args)); - const onFirstListenerAdd = () => emitter.on(eventName, fn); - const onLastListenerRemove = () => emitter.removeListener(eventName, fn); - const result = new Emitter({ onFirstListenerAdd, onLastListenerRemove }); - - return result.event; - } - - export function fromPromise(promise: Promise): Event { - const emitter = new Emitter(); - let shouldEmit = false; - - promise - .then(undefined, () => null) - .then(() => { - if (!shouldEmit) { - setTimeout(() => emitter.fire(undefined), 0); - } else { - emitter.fire(undefined); - } - }); - - shouldEmit = true; - return emitter.event; - } - - export function toPromise(event: Event): Promise { - return new Promise((c) => once(event)(c)); - } -} - -type Listener = [(e: T) => void, any] | ((e: T) => void); - -export interface EmitterOptions { - onFirstListenerAdd?: (emitter: Emitter) => void; - onFirstListenerDidAdd?: (emitter: Emitter) => void; - onListenerDidAdd?: (emitter: Emitter, listener: (e: any) => any, args: any) => void; - onLastListenerRemove?: (emitter: Emitter) => void; - leakWarningThreshold?: number; -} - -let _globalLeakWarningThreshold = -1; -export function setGlobalLeakWarningThreshold(n: number): IDisposable { - const oldValue = _globalLeakWarningThreshold; - _globalLeakWarningThreshold = n; - return { - dispose() { - _globalLeakWarningThreshold = oldValue; - }, - }; -} - -class LeakageMonitor { - private _stacks: Map | undefined; - private _warnCountdown = 0; - - constructor(readonly customThreshold?: number, readonly name: string = Math.random().toString(18).slice(2, 5)) {} - - dispose(): void { - if (this._stacks) { - this._stacks.clear(); - } - } - - check(listenerCount: number): undefined | (() => void) { - let threshold = _globalLeakWarningThreshold; - if (typeof this.customThreshold === 'number') { - threshold = this.customThreshold; - } - - if (threshold <= 0 || listenerCount < threshold) { - return undefined; - } - - if (!this._stacks) { - this._stacks = new Map(); - } - const stack = new Error().stack!.split('\n').slice(3).join('\n'); - const count = this._stacks.get(stack) || 0; - this._stacks.set(stack, count + 1); - this._warnCountdown -= 1; - - if (this._warnCountdown <= 0) { - // only warn on first exceed and then every time the limit - // is exceeded by 50% again - this._warnCountdown = threshold * 0.5; - - // find most frequent listener and print warning - let topStack = ''; - let topCount = 0; - this._stacks.forEach((count, stack) => { - if (!topStack || topCount < count) { - topStack = stack; - topCount = count; - } - }); - // eslint-disable-next-line no-console - console.warn( - `[${this.name}] potential listener LEAK detected, having ${listenerCount} listeners already. MOST frequent listener (${topCount}):`, - ); - // eslint-disable-next-line no-console - console.warn(topStack); - } - - return () => { - const count = this._stacks!.get(stack) || 0; - this._stacks!.set(stack, count - 1); - }; - } -} - -/** - * The Emitter can be used to expose an Event to the public - * to fire it from the insides. - * Sample: - class Document { - - private _onDidChange = new Emitter<(value:string)=>any>(); - - public onDidChange = this._onDidChange.event; - - // getter-style - // get onDidChange(): Event<(value:string)=>any> { - // return this._onDidChange.event; - // } - - private _doIt() { - //... - this._onDidChange.fire(value); - } - } - */ - -export interface IAsyncResult { - err?: Error; - result?: T; -} -export class Emitter { - private static readonly _noop = () => {}; - - private readonly _options?: EmitterOptions; - private readonly _leakageMon?: LeakageMonitor; - private _disposed = false; - private _event?: Event; - private _deliveryQueue?: LinkedList<[Listener, T]>; - protected _listeners?: LinkedList>; - - constructor(options?: EmitterOptions) { - this._options = options; - this._leakageMon = - _globalLeakWarningThreshold > 0 - ? new LeakageMonitor(this._options && this._options.leakWarningThreshold) - : undefined; - } - - /** - * For the public to allow to subscribe - * to events from this Emitter - */ - get event(): Event { - if (!this._event) { - this._event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]) => { - if (!this._listeners) { - this._listeners = new LinkedList(); - } - - const firstListener = this._listeners.isEmpty(); - - if (firstListener && this._options && this._options.onFirstListenerAdd) { - this._options.onFirstListenerAdd(this); - } - - const remove = this._listeners.push(!thisArgs ? listener : [listener, thisArgs]); - - if (firstListener && this._options && this._options.onFirstListenerDidAdd) { - this._options.onFirstListenerDidAdd(this); - } - - if (this._options && this._options.onListenerDidAdd) { - this._options.onListenerDidAdd(this, listener, thisArgs); - } - - // check and record this emitter for potential leakage - let removeMonitor: (() => void) | undefined; - if (this._leakageMon) { - removeMonitor = this._leakageMon.check(this._listeners.size); - } - - const result = { - dispose: () => { - if (removeMonitor) { - removeMonitor(); - } - result.dispose = Emitter._noop; - if (!this._disposed) { - remove(); - if (this._options && this._options.onLastListenerRemove) { - const hasListeners = this._listeners && !this._listeners.isEmpty(); - if (!hasListeners) { - this._options.onLastListenerRemove(this); - } - } - } - }, - } as IDisposable; - if (Array.isArray(disposables)) { - disposables.push(result); - } - - return result; - }; - } - return this._event; - } - - /** - * To be kept private to fire an event to - * subscribers - */ - fire(event: T): void { - if (this._listeners) { - // put all [listener,event]-pairs into delivery queue - // then emit all event. an inner/nested event might be - // the driver of this - - if (!this._deliveryQueue) { - this._deliveryQueue = new LinkedList(); - } - - for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) { - this._deliveryQueue.push([e.value, event]); - } - - while (this._deliveryQueue.size > 0) { - const [listener, event] = this._deliveryQueue.shift()!; - if (typeof listener === 'function') { - listener.call(undefined, event); - } else { - listener[0].call(listener[1], event); - } - } - } - } - - /** - * 发送一个异步事件,等待所有监听器返回,并收集返回值 - * @param e - * @param timeout - */ - async fireAndAwait(event: T, timeout = 2000): Promise>> { - if (this._listeners) { - if (!this._deliveryQueue) { - this._deliveryQueue = new LinkedList(); - } - - for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) { - this._deliveryQueue.push([e.value, event]); - } - - const promises: Promise>[] = []; - - const timeoutPromise = new Promise>((resolve) => { - setTimeout(() => { - resolve({ - err: new Error('timeout'), - }); - }, timeout); - }); - while (this._deliveryQueue.size > 0) { - const [listener, event] = this._deliveryQueue.shift()!; - const promise: Promise> = (async () => { - try { - if (typeof listener === 'function') { - return { - result: (await listener.call(undefined, event)) as any, - }; - } else { - return { - result: (await listener[0].call(listener[1], event)) as any, - }; - } - } catch (e) { - return { - err: e, - }; - } - })(); - promises.push(Promise.race([timeoutPromise, promise])); - } - return Promise.all(promises); - } else { - return []; - } - } - - get listenerSize() { - return this._listeners ? this._listeners.size : 0; - } - - dispose() { - if (this._listeners) { - this._listeners.clear(); - } - if (this._deliveryQueue) { - this._deliveryQueue.clear(); - } - if (this._leakageMon) { - this._leakageMon.dispose(); - } - this._disposed = true; - } -} - -export class PauseableEmitter extends Emitter { - private _isPaused = 0; - private _eventQueue = new LinkedList(); - private _mergeFn?: (input: T[]) => T; - - constructor(options?: EmitterOptions & { merge?: (input: T[]) => T }) { - super(options); - this._mergeFn = options && options.merge; - } - - pause(): void { - this._isPaused++; - } - - resume(): void { - if (this._isPaused !== 0 && --this._isPaused === 0) { - if (this._mergeFn) { - // use the merge function to create a single composite - // event. make a copy in case firing pauses this emitter - const events = this._eventQueue.toArray(); - this._eventQueue.clear(); - super.fire(this._mergeFn(events)); - } else { - // no merging, fire each event individually and test - // that this emitter isn't paused halfway through - while (!this._isPaused && this._eventQueue.size !== 0) { - super.fire(this._eventQueue.shift()!); - } - } - } - } - - fire(event: T): void { - if (this._listeners) { - if (this._isPaused !== 0) { - this._eventQueue.push(event); - } else { - super.fire(event); - } - } - } -} - -export interface WaitUntilEvent { - waitUntil(thenable: Promise): void; -} - -export namespace WaitUntilEvent { - export async function fire( - emitter: Emitter, - event: Pick>, - timeout?: number, - ): Promise { - const waitables: Promise[] = []; - const asyncEvent = Object.assign(event, { - waitUntil: (thenable: Promise) => { - if (Object.isFrozen(waitables)) { - throw new Error('waitUntil cannot be called asynchronously.'); - } - waitables.push(thenable); - }, - }) as T; - emitter.fire(asyncEvent); - // Asynchronous calls to `waitUntil` should fail. - Object.freeze(waitables); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - delete asyncEvent['waitUntil']; - if (!waitables.length) { - return; - } - if (timeout !== undefined) { - await Promise.race([Promise.all(waitables), new Promise((resolve) => setTimeout(resolve, timeout))]); - } else { - await Promise.all(waitables); - } - } -} diff --git a/packages/components/src/utils/index.ts b/packages/components/src/utils/index.ts index 710b225fe5..9d32ac1746 100644 --- a/packages/components/src/utils/index.ts +++ b/packages/components/src/utils/index.ts @@ -1,10 +1,5 @@ export * from './deprecated'; -export * from './disposable'; -export * from './event'; -export * from './iterator'; -export * from './linkedList'; export * from './warning'; -export * from './os'; -export * from './process'; -export * from './path'; -export * from './cancellation'; +export * from './type'; +export * from './motion'; +export * from './raf'; diff --git a/packages/components/src/utils/iterator.ts b/packages/components/src/utils/iterator.ts deleted file mode 100644 index 5026f67668..0000000000 --- a/packages/components/src/utils/iterator.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* --------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -export interface IteratorDefinedResult { - readonly done: false; - readonly value: T; -} -export interface IteratorUndefinedResult { - readonly done: true; - readonly value: undefined; -} -export const FIN: IteratorUndefinedResult = { done: true, value: undefined }; -export type IteratorResult = IteratorDefinedResult | IteratorUndefinedResult; - -export interface Iterator { - next(): IteratorResult; -} diff --git a/packages/components/src/utils/linkedList.ts b/packages/components/src/utils/linkedList.ts deleted file mode 100644 index 040cb568cd..0000000000 --- a/packages/components/src/utils/linkedList.ts +++ /dev/null @@ -1,145 +0,0 @@ -// Modify from @opensumi/ide-core-common/src/linkedList.ts -import { Iterator, IteratorResult, FIN } from './iterator'; - -class Node { - static readonly Undefined = new Node(undefined); - - element: E; - next: Node; - prev: Node; - - constructor(element: E) { - this.element = element; - this.next = Node.Undefined; - this.prev = Node.Undefined; - } -} - -export class LinkedList { - private _first: Node = Node.Undefined; - private _last: Node = Node.Undefined; - private _size = 0; - - get size(): number { - return this._size; - } - - isEmpty(): boolean { - return this._first === Node.Undefined; - } - - clear(): void { - this._first = Node.Undefined; - this._last = Node.Undefined; - this._size = 0; - } - - unshift(element: E): () => void { - return this._insert(element, false); - } - - push(element: E): () => void { - return this._insert(element, true); - } - - private _insert(element: E, atTheEnd: boolean): () => void { - const newNode = new Node(element); - if (this._first === Node.Undefined) { - this._first = newNode; - this._last = newNode; - } else if (atTheEnd) { - // push - const oldLast = this._last!; - this._last = newNode; - newNode.prev = oldLast; - oldLast.next = newNode; - } else { - // unshift - const oldFirst = this._first; - this._first = newNode; - newNode.next = oldFirst; - oldFirst.prev = newNode; - } - this._size += 1; - - let didRemove = false; - return () => { - if (!didRemove) { - didRemove = true; - this._remove(newNode); - } - }; - } - - shift(): E | undefined { - if (this._first === Node.Undefined) { - return undefined; - } else { - const res = this._first.element; - this._remove(this._first); - return res; - } - } - - pop(): E | undefined { - if (this._last === Node.Undefined) { - return undefined; - } else { - const res = this._last.element; - this._remove(this._last); - return res; - } - } - - private _remove(node: Node): void { - if (node.prev !== Node.Undefined && node.next !== Node.Undefined) { - // middle - const anchor = node.prev; - anchor.next = node.next; - node.next.prev = anchor; - } else if (node.prev === Node.Undefined && node.next === Node.Undefined) { - // only node - this._first = Node.Undefined; - this._last = Node.Undefined; - } else if (node.next === Node.Undefined) { - // last - this._last = this._last!.prev!; - this._last.next = Node.Undefined; - } else if (node.prev === Node.Undefined) { - // first - this._first = this._first!.next!; - this._first.prev = Node.Undefined; - } - - // done - this._size -= 1; - } - - iterator(): Iterator { - let element: { done: false; value: E }; - let node = this._first; - return { - next(): IteratorResult { - if (node === Node.Undefined) { - return FIN; - } - - if (!element) { - element = { done: false, value: node.element }; - } else { - element.value = node.element; - } - node = node.next; - return element; - }, - }; - } - - toArray(): E[] { - const result: E[] = []; - for (let node = this._first; node !== Node.Undefined; node = node.next) { - result.push(node.element); - } - return result; - } -} diff --git a/packages/components/src/utils/os.ts b/packages/components/src/utils/os.ts deleted file mode 100644 index aeee492479..0000000000 --- a/packages/components/src/utils/os.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Modify from @opensumi/ide-core-common/src/os.ts -function is(userAgent: string, platform: string): boolean { - if (global.hasOwnProperty('platform')) { - return (global as any).platform === platform; - } - if (typeof process !== 'undefined' && (process.platform as any) !== 'browser') { - return process.platform === platform; - } - if (typeof navigator !== 'undefined') { - if (navigator.userAgent && navigator.userAgent.indexOf(userAgent) >= 0) { - return true; - } - } - return false; -} - -export const isWindows = is('Windows', 'win32'); -export const isOSX = is('Mac', 'darwin'); -export const isLinux = is('Linux', 'linux'); diff --git a/packages/components/src/utils/path.ts b/packages/components/src/utils/path.ts deleted file mode 100644 index 52d5a69aec..0000000000 --- a/packages/components/src/utils/path.ts +++ /dev/null @@ -1,1825 +0,0 @@ -// Modify from @opensumi/ide-core-common/src/path.ts -import { isWindows } from './os'; -import { Process } from './process'; - -const SystemPathSeparatorRegex = isWindows ? /\\/g : /\//g; -/** - * On POSIX: - * ┌──────────────────────┬────────────┐ - * │ dir │ base │ - * ├──────┬ ├──────┬─────┤ - * │ root │ │ name │ ext │ - * " / home/user/dir / file .txt " - * └──────┴───────────────┴──────┴─────┘ - * - * On Windows: - * ┌──────────────────────┬────────────┐ - * │ dir │ base │ - * ├──────┬ ├──────┬─────┤ - * │ root │ │ name │ ext │ - * " /c: / home/user/dir / file .txt " - * └──────┴───────────────┴──────┴─────┘ - */ -export class Path { - static separator: '/' = '/'; - - static isDrive(segment: string): boolean { - return segment.endsWith(':'); - } - - static splitPath(path: string): string[] { - return path.split(Path.separator).filter((path) => !!path); - } - - static isRelative(path: string): boolean { - return !path.startsWith(Path.separator); - } - - static pathDepth(path: string): number { - return path.split(Path.separator).length; - } - /** - * vscode-uri always normalizes drive letters to lower case: - * https://github.com/Microsoft/vscode-uri/blob/b1d3221579f97f28a839b6f996d76fc45e9964d8/src/index.ts#L1025 - * Theia path should be adjusted to this. - */ - static normalizeDrive(path: string): string { - // lower-case windows drive letters in /C:/fff or C:/fff - if (path.length >= 3 && path.charCodeAt(0) === 47 /* '/' */ && path.charCodeAt(2) === 58 /* ':' */) { - const code = path.charCodeAt(1); - if (code >= 65 /* A */ && code <= 90 /* Z */) { - path = `/${String.fromCharCode(code + 32)}:${path.substr(3)}`; // "/c:".length === 3 - } - } else if (path.length >= 2 && path.charCodeAt(1) === 58 /* ':' */) { - const code = path.charCodeAt(0); - if (code >= 65 /* A */ && code <= 90 /* Z */) { - path = `${String.fromCharCode(code + 32)}:${path.substr(2)}`; // "/c:".length === 3 - } - } - return path; - } - - readonly isAbsolute: boolean; - readonly isRoot: boolean; - readonly root: Path | undefined; - readonly base: string; - readonly name: string; - readonly ext: string; - - private _dir!: Path; - private readonly raw: string; - - /** - * The raw should be normalized, meaning that only '/' is allowed as a path separator. - */ - constructor(raw: string) { - raw = raw.replace(SystemPathSeparatorRegex, Path.separator); - this.raw = Path.normalizeDrive(raw); - const firstIndex = raw.indexOf(Path.separator); - const lastIndex = raw.lastIndexOf(Path.separator); - this.isAbsolute = firstIndex === 0; - this.base = lastIndex === -1 ? raw : raw.substr(lastIndex + 1); - this.isRoot = this.isAbsolute && firstIndex === lastIndex && (!this.base || Path.isDrive(this.base)); - this.root = this.computeRoot(); - - const extIndex = this.base.lastIndexOf('.'); - // 处理无后缀文件或者 dot 打头的无后缀文件 - // file like 'a/b/c/test' - if (extIndex === -1) { - this.name = this.base; - this.ext = ''; - } else if (extIndex === 0) { - // dot file like `a/b/c/.eslintrc` - this.name = this.base; - this.ext = ''; - } else { - this.name = this.base.substr(0, extIndex); - this.ext = this.base.substr(extIndex); - } - } - - protected computeRoot(): Path | undefined { - // '/' -> '/' - // '/c:' -> '/c:' - if (this.isRoot) { - return this; - } - // 'foo/bar' -> `undefined` - if (!this.isAbsolute) { - return undefined; - } - const index = this.raw.indexOf(Path.separator, Path.separator.length); - if (index === -1) { - // '/foo/bar' -> '/' - return new Path(Path.separator); - } - // '/c:/foo/bar' -> '/c:' - // '/foo/bar' -> '/' - return new Path(this.raw.substr(0, index)).root; - } - - get dir(): Path { - if (this._dir === undefined) { - this._dir = this.computeDir(); - } - return this._dir; - } - - protected computeDir(): Path { - if (this.isRoot) { - return this; - } - const lastIndex = this.raw.lastIndexOf(Path.separator); - if (lastIndex === -1) { - return this; - } - if (this.isAbsolute) { - const firstIndex = this.raw.indexOf(Path.separator); - if (firstIndex === lastIndex) { - return new Path(this.raw.substr(0, firstIndex + 1)); - } - } - return new Path(this.raw.substr(0, lastIndex)); - } - - join(...paths: string[]): Path { - const code = this.raw.charCodeAt(0); - const isWindows = isWindowsDeviceRoot(code); - - /** - * 只针对 IDE 后端运行在 Windows 的情况 - * join('C:\\path\\to\\file', 'path/to/other') === 'C:\\path\\to\\file\\path\\to\\other' - */ - if (isWindows) { - return new Path(win32.join(this.raw, ...paths)); - } - - const relativePath = paths.filter((s) => !!s).join(Path.separator); - if (!relativePath) { - return this; - } - - if (this.raw.endsWith(Path.separator) || relativePath.startsWith(Path.separator)) { - return new Path(posix.join(this.raw, relativePath)); - } - return new Path(posix.join(this.raw, Path.separator, relativePath)); - } - - toString(): string { - return this.raw; - } - - relative(path: Path): Path | undefined { - if (this.raw === path.raw) { - return new Path(''); - } - if (!this.raw || !path.raw) { - return undefined; - } - const raw = this.base ? this.raw + Path.separator : this.raw; - if (!path.raw.startsWith(raw)) { - return undefined; - } - const relativePath = path.raw.substr(raw.length); - return new Path(relativePath); - } - - isEqualOrParent(path: Path): boolean { - return !!this.relative(path); - } - - isEqual(path: Path): boolean { - return this.raw === path.raw; - } - - relativity(path: Path): number { - const relative = this.relative(path); - if (relative) { - const relativeStr = relative.toString(); - if (relativeStr === '') { - return 0; - } - return relativeStr.split(Path.separator).length; - } - return -1; - } -} - -const CHAR_UPPERCASE_A = 65; /* A */ -const CHAR_LOWERCASE_A = 97; /* a */ -const CHAR_UPPERCASE_Z = 90; /* Z */ -const CHAR_LOWERCASE_Z = 122; /* z */ -const CHAR_DOT = 46; /* . */ -const CHAR_FORWARD_SLASH = 47; /* / */ -const CHAR_BACKWARD_SLASH = 92; /* \ */ -const CHAR_COLON = 58; /* : */ -const CHAR_QUESTION_MARK = 63; /* ? */ - -class ErrorInvalidArgType extends Error { - code: 'ERR_INVALID_ARG_TYPE'; - constructor(name: string, expected: string, actual: any) { - // determiner: 'must be' or 'must not be' - let determiner; - if (typeof expected === 'string' && expected.indexOf('not ') === 0) { - determiner = 'must not be'; - expected = expected.replace(/^not /, ''); - } else { - determiner = 'must be'; - } - - const type = name.indexOf('.') !== -1 ? 'property' : 'argument'; - let msg = `The "${name}" ${type} ${determiner} of type ${expected}`; - - msg += `. Received type ${typeof actual}`; - super(msg); - } -} - -function validateString(value: string, name: string) { - if (typeof value !== 'string') { - throw new ErrorInvalidArgType(name, 'string', value); - } -} - -function isPathSeparator(code?: number | undefined) { - return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; -} - -function isPosixPathSeparator(code?: number | undefined): boolean { - return code === CHAR_FORWARD_SLASH; -} - -function isWindowsDeviceRoot(code: number) { - return ( - (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z) - ); -} - -// Resolves . and .. elements in a path with directory names -function normalizeString( - path: string, - allowAboveRoot: boolean, - separator: string, - isPathSeparator: (code?: number) => boolean, -) { - let res = ''; - let lastSegmentLength = 0; - let lastSlash = -1; - let dots = 0; - let code; - for (let i = 0; i <= path.length; ++i) { - if (i < path.length) { - code = path.charCodeAt(i); - } else if (isPathSeparator(code)) { - break; - } else { - code = CHAR_FORWARD_SLASH; - } - - if (isPathSeparator(code)) { - if (lastSlash === i - 1 || dots === 1) { - // NOOP - } else if (lastSlash !== i - 1 && dots === 2) { - if ( - res.length < 2 || - lastSegmentLength !== 2 || - res.charCodeAt(res.length - 1) !== CHAR_DOT || - res.charCodeAt(res.length - 2) !== CHAR_DOT - ) { - if (res.length > 2) { - const lastSlashIndex = res.lastIndexOf(separator); - if (lastSlashIndex === -1) { - res = ''; - lastSegmentLength = 0; - } else { - res = res.slice(0, lastSlashIndex); - lastSegmentLength = res.length - 1 - res.lastIndexOf(separator); - } - lastSlash = i; - dots = 0; - continue; - } else if (res.length === 2 || res.length === 1) { - res = ''; - lastSegmentLength = 0; - lastSlash = i; - dots = 0; - continue; - } - } - if (allowAboveRoot) { - if (res.length > 0) { - res += `${separator}..`; - } else { - res = '..'; - } - lastSegmentLength = 2; - } - } else { - if (res.length > 0) { - res += separator + path.slice(lastSlash + 1, i); - } else { - res = path.slice(lastSlash + 1, i); - } - lastSegmentLength = i - lastSlash - 1; - } - lastSlash = i; - dots = 0; - } else if (code === CHAR_DOT && dots !== -1) { - ++dots; - } else { - dots = -1; - } - } - return res; -} - -function _format(sep: string, pathObject: ParsedPath) { - const dir = pathObject.dir || pathObject.root; - const base = pathObject.base || (pathObject.name || '') + (pathObject.ext || ''); - if (!dir) { - return base; - } - if (dir === pathObject.root) { - return dir + base; - } - return dir + sep + base; -} - -interface ParsedPath { - root: string; - dir: string; - base: string; - ext: string; - name: string; -} - -export interface IPath { - normalize(path: string): string; - isAbsolute(path: string): boolean; - join(...paths: string[]): string; - resolve(...pathSegments: string[]): string; - relative(from: string, to: string): string; - dirname(path: string): string; - basename(path: string, ext?: string): string; - extname(path: string): string; - format(pathObject: ParsedPath): string; - parse(path: string): ParsedPath; - toNamespacedPath(path: string): string; - sep: '\\' | '/'; - delimiter: string; - win32: IPath | null; - posix: IPath | null; -} - -export const win32: IPath = { - // path.resolve([from ...], to) - resolve(...pathSegments: string[]): string { - let resolvedDevice = ''; - let resolvedTail = ''; - let resolvedAbsolute = false; - - for (let i = pathSegments.length - 1; i >= -1; i--) { - let path; - if (i >= 0) { - path = pathSegments[i]; - } else if (!resolvedDevice) { - path = process.cwd(); - } else { - // Windows has the concept of drive-specific current working - // directories. If we've resolved a drive letter but not yet an - // absolute path, get cwd for that drive, or the process cwd if - // the drive cwd is not available. We're sure the device is not - // a UNC path at this points, because UNC paths are always absolute. - path = process.env['=' + resolvedDevice] || process.cwd(); - - // Verify that a cwd was found and that it actually points - // to our drive. If not, default to the drive's root. - if (path === undefined || path.slice(0, 3).toLowerCase() !== resolvedDevice.toLowerCase() + '\\') { - path = resolvedDevice + '\\'; - } - } - - validateString(path, 'path'); - - // Skip empty entries - if (path.length === 0) { - continue; - } - - const len = path.length; - let rootEnd = 0; - let device = ''; - let isAbsolute = false; - const code = path.charCodeAt(0); - - // Try to match a root - if (len > 1) { - if (isPathSeparator(code)) { - // Possible UNC root - - // If we started with a separator, we know we at least have an - // absolute path of some kind (UNC or otherwise) - isAbsolute = true; - - if (isPathSeparator(path.charCodeAt(1))) { - // Matched double path separator at beginning - let j = 2; - let last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) { - break; - } - } - if (j < len && j !== last) { - const firstPart = path.slice(last, j); - // Matched! - last = j; - // Match 1 or more path separators - for (; j < len; ++j) { - if (!isPathSeparator(path.charCodeAt(j))) { - break; - } - } - if (j < len && j !== last) { - // Matched! - last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) { - break; - } - } - if (j === len) { - // We matched a UNC root only - - device = '\\\\' + firstPart + '\\' + path.slice(last); - rootEnd = j; - } else if (j !== last) { - // We matched a UNC root with leftovers - - device = '\\\\' + firstPart + '\\' + path.slice(last, j); - rootEnd = j; - } - } - } - } else { - rootEnd = 1; - } - } else if (isWindowsDeviceRoot(code)) { - // Possible device root - - if (path.charCodeAt(1) === CHAR_COLON) { - device = path.slice(0, 2); - rootEnd = 2; - if (len > 2) { - if (isPathSeparator(path.charCodeAt(2))) { - // Treat separator following drive name as an absolute path - // indicator - isAbsolute = true; - rootEnd = 3; - } - } - } - } - } else if (isPathSeparator(code)) { - // `path` contains just a path separator - rootEnd = 1; - isAbsolute = true; - } - - if (device.length > 0 && resolvedDevice.length > 0 && device.toLowerCase() !== resolvedDevice.toLowerCase()) { - // This path points to another device so it is not applicable - continue; - } - - if (resolvedDevice.length === 0 && device.length > 0) { - resolvedDevice = device; - } - if (!resolvedAbsolute) { - resolvedTail = path.slice(rootEnd) + '\\' + resolvedTail; - resolvedAbsolute = isAbsolute; - } - - if (resolvedDevice.length > 0 && resolvedAbsolute) { - break; - } - } - - // At this point the path should be resolved to a full absolute path, - // but handle relative paths to be safe (might happen when process.cwd() - // fails) - - // Normalize the tail path - resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\', isPathSeparator); - - return resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail || '.'; - }, - - normalize(path: string): string { - validateString(path, 'path'); - const len = path.length; - if (len === 0) { - return '.'; - } - let rootEnd = 0; - let device; - let isAbsolute = false; - const code = path.charCodeAt(0); - - // Try to match a root - if (len > 1) { - if (isPathSeparator(code)) { - // Possible UNC root - - // If we started with a separator, we know we at least have an absolute - // path of some kind (UNC or otherwise) - isAbsolute = true; - - if (isPathSeparator(path.charCodeAt(1))) { - // Matched double path separator at beginning - let j = 2; - let last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) { - break; - } - } - if (j < len && j !== last) { - const firstPart = path.slice(last, j); - // Matched! - last = j; - // Match 1 or more path separators - for (; j < len; ++j) { - if (!isPathSeparator(path.charCodeAt(j))) { - break; - } - } - if (j < len && j !== last) { - // Matched! - last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) { - break; - } - } - if (j === len) { - // We matched a UNC root only - // Return the normalized version of the UNC root since there - // is nothing left to process - - return '\\\\' + firstPart + '\\' + path.slice(last) + '\\'; - } else if (j !== last) { - // We matched a UNC root with leftovers - - device = '\\\\' + firstPart + '\\' + path.slice(last, j); - rootEnd = j; - } - } - } - } else { - rootEnd = 1; - } - } else if (isWindowsDeviceRoot(code)) { - // Possible device root - - if (path.charCodeAt(1) === CHAR_COLON) { - device = path.slice(0, 2); - rootEnd = 2; - if (len > 2) { - if (isPathSeparator(path.charCodeAt(2))) { - // Treat separator following drive name as an absolute path - // indicator - isAbsolute = true; - rootEnd = 3; - } - } - } - } - } else if (isPathSeparator(code)) { - // `path` contains just a path separator, exit early to avoid unnecessary - // work - return '\\'; - } - - let tail; - if (rootEnd < len) { - tail = normalizeString(path.slice(rootEnd), !isAbsolute, '\\', isPathSeparator); - } else { - tail = ''; - } - if (tail.length === 0 && !isAbsolute) { - tail = '.'; - } - if (tail.length > 0 && isPathSeparator(path.charCodeAt(len - 1))) { - tail += '\\'; - } - if (device === undefined) { - if (isAbsolute) { - if (tail.length > 0) { - return '\\' + tail; - } else { - return '\\'; - } - } else if (tail.length > 0) { - return tail; - } else { - return ''; - } - } else if (isAbsolute) { - if (tail.length > 0) { - return device + '\\' + tail; - } else { - return device + '\\'; - } - } else if (tail.length > 0) { - return device + tail; - } else { - return device; - } - }, - - isAbsolute(path: string): boolean { - validateString(path, 'path'); - const len = path.length; - if (len === 0) { - return false; - } - - const code = path.charCodeAt(0); - if (isPathSeparator(code)) { - return true; - } else if (isWindowsDeviceRoot(code)) { - // Possible device root - - if (len > 2 && path.charCodeAt(1) === CHAR_COLON) { - if (isPathSeparator(path.charCodeAt(2))) { - return true; - } - } - } - return false; - }, - - join(...paths: string[]): string { - if (paths.length === 0) { - return '.'; - } - - let joined; - let firstPart: string | undefined; - // eslint-disable-next-line @typescript-eslint/prefer-for-of - for (let i = 0; i < paths.length; ++i) { - const arg = paths[i]; - validateString(arg, 'path'); - if (arg.length > 0) { - if (joined === undefined) { - joined = firstPart = arg; - } else { - joined += '\\' + arg; - } - } - } - - if (joined === undefined) { - return '.'; - } - - // Make sure that the joined path doesn't start with two slashes, because - // normalize() will mistake it for an UNC path then. - // - // This step is skipped when it is very clear that the user actually - // intended to point at an UNC path. This is assumed when the first - // non-empty string arguments starts with exactly two slashes followed by - // at least one more non-slash character. - // - // Note that for normalize() to treat a path as an UNC path it needs to - // have at least 2 components, so we don't filter for that here. - // This means that the user can use join to construct UNC paths from - // a server name and a share name; for example: - // path.join('//server', 'share') -> '\\\\server\\share\\') - let needsReplace = true; - let slashCount = 0; - if (typeof firstPart === 'string' && isPathSeparator(firstPart.charCodeAt(0))) { - ++slashCount; - const firstLen = firstPart.length; - if (firstLen > 1) { - if (isPathSeparator(firstPart.charCodeAt(1))) { - ++slashCount; - if (firstLen > 2) { - if (isPathSeparator(firstPart.charCodeAt(2))) { - ++slashCount; - } else { - // We matched a UNC path in the first part - needsReplace = false; - } - } - } - } - } - if (needsReplace) { - // Find any more consecutive slashes we need to replace - for (; slashCount < joined.length; ++slashCount) { - if (!isPathSeparator(joined.charCodeAt(slashCount))) { - break; - } - } - - // Replace the slashes if needed - if (slashCount >= 2) { - joined = '\\' + joined.slice(slashCount); - } - } - - return win32.normalize(joined); - }, - - // It will solve the relative path from `from` to `to`, for instance: - // from = 'C:\\orandea\\test\\aaa' - // to = 'C:\\orandea\\impl\\bbb' - // The output of the function should be: '..\\..\\impl\\bbb' - relative(from: string, to: string): string { - validateString(from, 'from'); - validateString(to, 'to'); - - if (from === to) { - return ''; - } - - const fromOrig = win32.resolve(from); - const toOrig = win32.resolve(to); - - if (fromOrig === toOrig) { - return ''; - } - - from = fromOrig.toLowerCase(); - to = toOrig.toLowerCase(); - - if (from === to) { - return ''; - } - - // Trim any leading backslashes - let fromStart = 0; - for (; fromStart < from.length; ++fromStart) { - if (from.charCodeAt(fromStart) !== CHAR_BACKWARD_SLASH) { - break; - } - } - // Trim trailing backslashes (applicable to UNC paths only) - let fromEnd = from.length; - for (; fromEnd - 1 > fromStart; --fromEnd) { - if (from.charCodeAt(fromEnd - 1) !== CHAR_BACKWARD_SLASH) { - break; - } - } - const fromLen = fromEnd - fromStart; - - // Trim any leading backslashes - let toStart = 0; - for (; toStart < to.length; ++toStart) { - if (to.charCodeAt(toStart) !== CHAR_BACKWARD_SLASH) { - break; - } - } - // Trim trailing backslashes (applicable to UNC paths only) - let toEnd = to.length; - for (; toEnd - 1 > toStart; --toEnd) { - if (to.charCodeAt(toEnd - 1) !== CHAR_BACKWARD_SLASH) { - break; - } - } - const toLen = toEnd - toStart; - - // Compare paths to find the longest common path from root - const length = fromLen < toLen ? fromLen : toLen; - let lastCommonSep = -1; - let i = 0; - for (; i <= length; ++i) { - if (i === length) { - if (toLen > length) { - if (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) { - // We get here if `from` is the exact base path for `to`. - // For example: from='C:\\foo\\bar'; to='C:\\foo\\bar\\baz' - return toOrig.slice(toStart + i + 1); - } else if (i === 2) { - // We get here if `from` is the device root. - // For example: from='C:\\'; to='C:\\foo' - return toOrig.slice(toStart + i); - } - } - if (fromLen > length) { - if (from.charCodeAt(fromStart + i) === CHAR_BACKWARD_SLASH) { - // We get here if `to` is the exact base path for `from`. - // For example: from='C:\\foo\\bar'; to='C:\\foo' - lastCommonSep = i; - } else if (i === 2) { - // We get here if `to` is the device root. - // For example: from='C:\\foo\\bar'; to='C:\\' - lastCommonSep = 3; - } - } - break; - } - const fromCode = from.charCodeAt(fromStart + i); - const toCode = to.charCodeAt(toStart + i); - if (fromCode !== toCode) { - break; - } else if (fromCode === CHAR_BACKWARD_SLASH) { - lastCommonSep = i; - } - } - - // We found a mismatch before the first common path separator was seen, so - // return the original `to`. - if (i !== length && lastCommonSep === -1) { - return toOrig; - } - - let out = ''; - if (lastCommonSep === -1) { - lastCommonSep = 0; - } - // Generate the relative path based on the path difference between `to` and - // `from` - for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { - if (i === fromEnd || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) { - if (out.length === 0) { - out += '..'; - } else { - out += '\\..'; - } - } - } - - // Lastly, append the rest of the destination (`to`) path that comes after - // the common path parts - if (out.length > 0) { - return out + toOrig.slice(toStart + lastCommonSep, toEnd); - } else { - toStart += lastCommonSep; - if (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) { - ++toStart; - } - return toOrig.slice(toStart, toEnd); - } - }, - - toNamespacedPath(path: string): string { - // Note: this will *probably* throw somewhere. - if (typeof path !== 'string') { - return path; - } - - if (path.length === 0) { - return ''; - } - - const resolvedPath = win32.resolve(path); - - if (resolvedPath.length >= 3) { - if (resolvedPath.charCodeAt(0) === CHAR_BACKWARD_SLASH) { - // Possible UNC root - - if (resolvedPath.charCodeAt(1) === CHAR_BACKWARD_SLASH) { - const code = resolvedPath.charCodeAt(2); - if (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) { - // Matched non-long UNC root, convert the path to a long UNC path - return '\\\\?\\UNC\\' + resolvedPath.slice(2); - } - } - } else if (isWindowsDeviceRoot(resolvedPath.charCodeAt(0))) { - // Possible device root - - if (resolvedPath.charCodeAt(1) === CHAR_COLON && resolvedPath.charCodeAt(2) === CHAR_BACKWARD_SLASH) { - // Matched device root, convert the path to a long UNC path - return '\\\\?\\' + resolvedPath; - } - } - } - - return path; - }, - - dirname(path: string): string { - validateString(path, 'path'); - const len = path.length; - if (len === 0) { - return '.'; - } - let rootEnd = -1; - let end = -1; - let matchedSlash = true; - let offset = 0; - const code = path.charCodeAt(0); - - // Try to match a root - if (len > 1) { - if (isPathSeparator(code)) { - // Possible UNC root - - rootEnd = offset = 1; - - if (isPathSeparator(path.charCodeAt(1))) { - // Matched double path separator at beginning - let j = 2; - let last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) { - break; - } - } - if (j < len && j !== last) { - // Matched! - last = j; - // Match 1 or more path separators - for (; j < len; ++j) { - if (!isPathSeparator(path.charCodeAt(j))) { - break; - } - } - if (j < len && j !== last) { - // Matched! - last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) { - break; - } - } - if (j === len) { - // We matched a UNC root only - return path; - } - if (j !== last) { - // We matched a UNC root with leftovers - - // Offset by 1 to include the separator after the UNC root to - // treat it as a "normal root" on top of a (UNC) root - rootEnd = offset = j + 1; - } - } - } - } - } else if (isWindowsDeviceRoot(code)) { - // Possible device root - - if (path.charCodeAt(1) === CHAR_COLON) { - rootEnd = offset = 2; - if (len > 2) { - if (isPathSeparator(path.charCodeAt(2))) { - rootEnd = offset = 3; - } - } - } - } - } else if (isPathSeparator(code)) { - // `path` contains just a path separator, exit early to avoid - // unnecessary work - return path; - } - - for (let i = len - 1; i >= offset; --i) { - if (isPathSeparator(path.charCodeAt(i))) { - if (!matchedSlash) { - end = i; - break; - } - } else { - // We saw the first non-path separator - matchedSlash = false; - } - } - - if (end === -1) { - if (rootEnd === -1) { - return '.'; - } else { - end = rootEnd; - } - } - return path.slice(0, end); - }, - - basename(path: string, ext?: string): string { - if (ext !== undefined) { - validateString(ext, 'ext'); - } - validateString(path, 'path'); - let start = 0; - let end = -1; - let matchedSlash = true; - let i; - - // Check for a drive letter prefix so as not to mistake the following - // path separator as an extra separator at the end of the path that can be - // disregarded - if (path.length >= 2) { - const drive = path.charCodeAt(0); - if (isWindowsDeviceRoot(drive)) { - if (path.charCodeAt(1) === CHAR_COLON) { - start = 2; - } - } - } - - if (ext !== undefined && ext.length > 0 && ext.length <= path.length) { - if (ext.length === path.length && ext === path) { - return ''; - } - let extIdx = ext.length - 1; - let firstNonSlashEnd = -1; - for (i = path.length - 1; i >= start; --i) { - const code = path.charCodeAt(i); - if (isPathSeparator(code)) { - // If we reached a path separator that was not part of a set of path - // separators at the end of the string, stop now - if (!matchedSlash) { - start = i + 1; - break; - } - } else { - if (firstNonSlashEnd === -1) { - // We saw the first non-path separator, remember this index in case - // we need it if the extension ends up not matching - matchedSlash = false; - firstNonSlashEnd = i + 1; - } - if (extIdx >= 0) { - // Try to match the explicit extension - if (code === ext.charCodeAt(extIdx)) { - if (--extIdx === -1) { - // We matched the extension, so mark this as the end of our path - // component - end = i; - } - } else { - // Extension does not match, so our result is the entire path - // component - extIdx = -1; - end = firstNonSlashEnd; - } - } - } - } - - if (start === end) { - end = firstNonSlashEnd; - } else if (end === -1) { - end = path.length; - } - return path.slice(start, end); - } else { - for (i = path.length - 1; i >= start; --i) { - if (isPathSeparator(path.charCodeAt(i))) { - // If we reached a path separator that was not part of a set of path - // separators at the end of the string, stop now - if (!matchedSlash) { - start = i + 1; - break; - } - } else if (end === -1) { - // We saw the first non-path separator, mark this as the end of our - // path component - matchedSlash = false; - end = i + 1; - } - } - - if (end === -1) { - return ''; - } - return path.slice(start, end); - } - }, - - extname(path: string): string { - validateString(path, 'path'); - let start = 0; - let startDot = -1; - let startPart = 0; - let end = -1; - let matchedSlash = true; - // Track the state of characters (if any) we see before our first dot and - // after any path separator we find - let preDotState = 0; - - // Check for a drive letter prefix so as not to mistake the following - // path separator as an extra separator at the end of the path that can be - // disregarded - - if (path.length >= 2 && path.charCodeAt(1) === CHAR_COLON && isWindowsDeviceRoot(path.charCodeAt(0))) { - start = startPart = 2; - } - - for (let i = path.length - 1; i >= start; --i) { - const code = path.charCodeAt(i); - if (isPathSeparator(code)) { - // If we reached a path separator that was not part of a set of path - // separators at the end of the string, stop now - if (!matchedSlash) { - startPart = i + 1; - break; - } - continue; - } - if (end === -1) { - // We saw the first non-path separator, mark this as the end of our - // extension - matchedSlash = false; - end = i + 1; - } - if (code === CHAR_DOT) { - // If this is our first dot, mark it as the start of our extension - if (startDot === -1) { - startDot = i; - } else if (preDotState !== 1) { - preDotState = 1; - } - } else if (startDot !== -1) { - // We saw a non-dot and non-path separator before our dot, so we should - // have a good chance at having a non-empty extension - preDotState = -1; - } - } - - if ( - startDot === -1 || - end === -1 || - // We saw a non-dot character immediately before the dot - preDotState === 0 || - // The (right-most) trimmed path component is exactly '..' - (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) - ) { - return ''; - } - return path.slice(startDot, end); - }, - - format(pathObject): string { - if (pathObject === null || typeof pathObject !== 'object') { - throw new ErrorInvalidArgType('pathObject', 'Object', pathObject); - } - - return _format('\\', pathObject); - }, - - parse(path) { - validateString(path, 'path'); - - const ret = { root: '', dir: '', base: '', ext: '', name: '' }; - if (path.length === 0) { - return ret; - } - - const len = path.length; - let rootEnd = 0; - let code = path.charCodeAt(0); - - // Try to match a root - if (len > 1) { - if (isPathSeparator(code)) { - // Possible UNC root - - rootEnd = 1; - if (isPathSeparator(path.charCodeAt(1))) { - // Matched double path separator at beginning - let j = 2; - let last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) { - break; - } - } - if (j < len && j !== last) { - // Matched! - last = j; - // Match 1 or more path separators - for (; j < len; ++j) { - if (!isPathSeparator(path.charCodeAt(j))) { - break; - } - } - if (j < len && j !== last) { - // Matched! - last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) { - break; - } - } - if (j === len) { - // We matched a UNC root only - - rootEnd = j; - } else if (j !== last) { - // We matched a UNC root with leftovers - - rootEnd = j + 1; - } - } - } - } - } else if (isWindowsDeviceRoot(code)) { - // Possible device root - - if (path.charCodeAt(1) === CHAR_COLON) { - rootEnd = 2; - if (len > 2) { - if (isPathSeparator(path.charCodeAt(2))) { - if (len === 3) { - // `path` contains just a drive root, exit early to avoid - // unnecessary work - ret.root = ret.dir = path; - return ret; - } - rootEnd = 3; - } - } else { - // `path` contains just a drive root, exit early to avoid - // unnecessary work - ret.root = ret.dir = path; - return ret; - } - } - } - } else if (isPathSeparator(code)) { - // `path` contains just a path separator, exit early to avoid - // unnecessary work - ret.root = ret.dir = path; - return ret; - } - - if (rootEnd > 0) { - ret.root = path.slice(0, rootEnd); - } - - let startDot = -1; - let startPart = rootEnd; - let end = -1; - let matchedSlash = true; - let i = path.length - 1; - - // Track the state of characters (if any) we see before our first dot and - // after any path separator we find - let preDotState = 0; - - // Get non-dir info - for (; i >= rootEnd; --i) { - code = path.charCodeAt(i); - if (isPathSeparator(code)) { - // If we reached a path separator that was not part of a set of path - // separators at the end of the string, stop now - if (!matchedSlash) { - startPart = i + 1; - break; - } - continue; - } - if (end === -1) { - // We saw the first non-path separator, mark this as the end of our - // extension - matchedSlash = false; - end = i + 1; - } - if (code === CHAR_DOT) { - // If this is our first dot, mark it as the start of our extension - if (startDot === -1) { - startDot = i; - } else if (preDotState !== 1) { - preDotState = 1; - } - } else if (startDot !== -1) { - // We saw a non-dot and non-path separator before our dot, so we should - // have a good chance at having a non-empty extension - preDotState = -1; - } - } - - if ( - startDot === -1 || - end === -1 || - // We saw a non-dot character immediately before the dot - preDotState === 0 || - // The (right-most) trimmed path component is exactly '..' - (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) - ) { - if (end !== -1) { - ret.base = ret.name = path.slice(startPart, end); - } - } else { - ret.name = path.slice(startPart, startDot); - ret.base = path.slice(startPart, end); - ret.ext = path.slice(startDot, end); - } - - // If the directory is the root, use the entire root as the `dir` including - // the trailing slash if any (`C:\abc` -> `C:\`). Otherwise, strip out the - // trailing slash (`C:\abc\def` -> `C:\abc`). - if (startPart > 0 && startPart !== rootEnd) { - ret.dir = path.slice(0, startPart - 1); - } else { - ret.dir = ret.root; - } - - return ret; - }, - - sep: '\\', - delimiter: ';', - win32: null, - posix: null, -}; - -export const posix: IPath = { - // path.resolve([from ...], to) - resolve(...pathSegments: string[]): string { - let resolvedPath = ''; - let resolvedAbsolute = false; - - for (let i = pathSegments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - let path; - if (i >= 0) { - path = pathSegments[i]; - } else { - path = process.cwd(); - } - - validateString(path, 'path'); - - // Skip empty entries - if (path.length === 0) { - continue; - } - - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; - } - - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) - - // Normalize the path - resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/', isPosixPathSeparator); - - if (resolvedAbsolute) { - if (resolvedPath.length > 0) { - return '/' + resolvedPath; - } else { - return '/'; - } - } else if (resolvedPath.length > 0) { - return resolvedPath; - } else { - return '.'; - } - }, - - normalize(path: string): string { - validateString(path, 'path'); - - if (path.length === 0) { - return '.'; - } - - const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; - const trailingSeparator = path.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH; - - // Normalize the path - path = normalizeString(path, !isAbsolute, '/', isPosixPathSeparator); - - if (path.length === 0 && !isAbsolute) { - path = '.'; - } - if (path.length > 0 && trailingSeparator) { - path += '/'; - } - - if (isAbsolute) { - return '/' + path; - } - return path; - }, - - isAbsolute(path: string): boolean { - validateString(path, 'path'); - return path.length > 0 && path.charCodeAt(0) === CHAR_FORWARD_SLASH; - }, - - join(...paths: string[]): string { - if (paths.length === 0) { - return '.'; - } - let joined; - for (let i = 0; i < paths.length; ++i) { - const arg = arguments[i]; - validateString(arg, 'path'); - if (arg.length > 0) { - if (joined === undefined) { - joined = arg; - } else { - joined += '/' + arg; - } - } - } - if (joined === undefined) { - return '.'; - } - return posix.normalize(joined); - }, - - relative(from: string, to: string): string { - validateString(from, 'from'); - validateString(to, 'to'); - - if (from === to) { - return ''; - } - - from = posix.resolve(from); - to = posix.resolve(to); - - if (from === to) { - return ''; - } - - // Trim any leading backslashes - let fromStart = 1; - for (; fromStart < from.length; ++fromStart) { - if (from.charCodeAt(fromStart) !== CHAR_FORWARD_SLASH) { - break; - } - } - const fromEnd = from.length; - const fromLen = fromEnd - fromStart; - - // Trim any leading backslashes - let toStart = 1; - for (; toStart < to.length; ++toStart) { - if (to.charCodeAt(toStart) !== CHAR_FORWARD_SLASH) { - break; - } - } - const toEnd = to.length; - const toLen = toEnd - toStart; - - // Compare paths to find the longest common path from root - const length = fromLen < toLen ? fromLen : toLen; - let lastCommonSep = -1; - let i = 0; - for (; i <= length; ++i) { - if (i === length) { - if (toLen > length) { - if (to.charCodeAt(toStart + i) === CHAR_FORWARD_SLASH) { - // We get here if `from` is the exact base path for `to`. - // For example: from='/foo/bar'; to='/foo/bar/baz' - return to.slice(toStart + i + 1); - } else if (i === 0) { - // We get here if `from` is the root - // For example: from='/'; to='/foo' - return to.slice(toStart + i); - } - } else if (fromLen > length) { - if (from.charCodeAt(fromStart + i) === CHAR_FORWARD_SLASH) { - // We get here if `to` is the exact base path for `from`. - // For example: from='/foo/bar/baz'; to='/foo/bar' - lastCommonSep = i; - } else if (i === 0) { - // We get here if `to` is the root. - // For example: from='/foo'; to='/' - lastCommonSep = 0; - } - } - break; - } - const fromCode = from.charCodeAt(fromStart + i); - const toCode = to.charCodeAt(toStart + i); - if (fromCode !== toCode) { - break; - } else if (fromCode === CHAR_FORWARD_SLASH) { - lastCommonSep = i; - } - } - - let out = ''; - // Generate the relative path based on the path difference between `to` - // and `from` - for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { - if (i === fromEnd || from.charCodeAt(i) === CHAR_FORWARD_SLASH) { - if (out.length === 0) { - out += '..'; - } else { - out += '/..'; - } - } - } - - // Lastly, append the rest of the destination (`to`) path that comes after - // the common path parts - if (out.length > 0) { - return out + to.slice(toStart + lastCommonSep); - } else { - toStart += lastCommonSep; - if (to.charCodeAt(toStart) === CHAR_FORWARD_SLASH) { - ++toStart; - } - return to.slice(toStart); - } - }, - - toNamespacedPath(path: string): string { - // Non-op on posix systems - return path; - }, - - dirname(path: string): string { - validateString(path, 'path'); - if (path.length === 0) { - return '.'; - } - const hasRoot = path.charCodeAt(0) === CHAR_FORWARD_SLASH; - let end = -1; - let matchedSlash = true; - for (let i = path.length - 1; i >= 1; --i) { - if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) { - if (!matchedSlash) { - end = i; - break; - } - } else { - // We saw the first non-path separator - matchedSlash = false; - } - } - - if (end === -1) { - return hasRoot ? '/' : '.'; - } - if (hasRoot && end === 1) { - return '//'; - } - return path.slice(0, end); - }, - - basename(path: string, ext?: string): string { - if (ext !== undefined) { - validateString(ext, 'ext'); - } - validateString(path, 'path'); - - let start = 0; - let end = -1; - let matchedSlash = true; - let i; - - if (ext !== undefined && ext.length > 0 && ext.length <= path.length) { - if (ext.length === path.length && ext === path) { - return ''; - } - let extIdx = ext.length - 1; - let firstNonSlashEnd = -1; - for (i = path.length - 1; i >= 0; --i) { - const code = path.charCodeAt(i); - if (code === CHAR_FORWARD_SLASH) { - // If we reached a path separator that was not part of a set of path - // separators at the end of the string, stop now - if (!matchedSlash) { - start = i + 1; - break; - } - } else { - if (firstNonSlashEnd === -1) { - // We saw the first non-path separator, remember this index in case - // we need it if the extension ends up not matching - matchedSlash = false; - firstNonSlashEnd = i + 1; - } - if (extIdx >= 0) { - // Try to match the explicit extension - if (code === ext.charCodeAt(extIdx)) { - if (--extIdx === -1) { - // We matched the extension, so mark this as the end of our path - // component - end = i; - } - } else { - // Extension does not match, so our result is the entire path - // component - extIdx = -1; - end = firstNonSlashEnd; - } - } - } - } - - if (start === end) { - end = firstNonSlashEnd; - } else if (end === -1) { - end = path.length; - } - return path.slice(start, end); - } else { - for (i = path.length - 1; i >= 0; --i) { - if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) { - // If we reached a path separator that was not part of a set of path - // separators at the end of the string, stop now - if (!matchedSlash) { - start = i + 1; - break; - } - } else if (end === -1) { - // We saw the first non-path separator, mark this as the end of our - // path component - matchedSlash = false; - end = i + 1; - } - } - - if (end === -1) { - return ''; - } - return path.slice(start, end); - } - }, - - extname(path: string): string { - validateString(path, 'path'); - let startDot = -1; - let startPart = 0; - let end = -1; - let matchedSlash = true; - // Track the state of characters (if any) we see before our first dot and - // after any path separator we find - let preDotState = 0; - for (let i = path.length - 1; i >= 0; --i) { - const code = path.charCodeAt(i); - if (code === CHAR_FORWARD_SLASH) { - // If we reached a path separator that was not part of a set of path - // separators at the end of the string, stop now - if (!matchedSlash) { - startPart = i + 1; - break; - } - continue; - } - if (end === -1) { - // We saw the first non-path separator, mark this as the end of our - // extension - matchedSlash = false; - end = i + 1; - } - if (code === CHAR_DOT) { - // If this is our first dot, mark it as the start of our extension - if (startDot === -1) { - startDot = i; - } else if (preDotState !== 1) { - preDotState = 1; - } - } else if (startDot !== -1) { - // We saw a non-dot and non-path separator before our dot, so we should - // have a good chance at having a non-empty extension - preDotState = -1; - } - } - - if ( - startDot === -1 || - end === -1 || - // We saw a non-dot character immediately before the dot - preDotState === 0 || - // The (right-most) trimmed path component is exactly '..' - (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) - ) { - return ''; - } - return path.slice(startDot, end); - }, - - format(pathObject): string { - if (pathObject === null || typeof pathObject !== 'object') { - throw new ErrorInvalidArgType('pathObject', 'Object', pathObject); - } - - return _format('/', pathObject); - }, - - parse(path: string): ParsedPath { - validateString(path, 'path'); - - const ret = { root: '', dir: '', base: '', ext: '', name: '' }; - if (path.length === 0) { - return ret; - } - const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; - let start; - if (isAbsolute) { - ret.root = '/'; - start = 1; - } else { - start = 0; - } - let startDot = -1; - let startPart = 0; - let end = -1; - let matchedSlash = true; - let i = path.length - 1; - - // Track the state of characters (if any) we see before our first dot and - // after any path separator we find - let preDotState = 0; - - // Get non-dir info - for (; i >= start; --i) { - const code = path.charCodeAt(i); - if (code === CHAR_FORWARD_SLASH) { - // If we reached a path separator that was not part of a set of path - // separators at the end of the string, stop now - if (!matchedSlash) { - startPart = i + 1; - break; - } - continue; - } - if (end === -1) { - // We saw the first non-path separator, mark this as the end of our - // extension - matchedSlash = false; - end = i + 1; - } - if (code === CHAR_DOT) { - // If this is our first dot, mark it as the start of our extension - if (startDot === -1) { - startDot = i; - } else if (preDotState !== 1) { - preDotState = 1; - } - } else if (startDot !== -1) { - // We saw a non-dot and non-path separator before our dot, so we should - // have a good chance at having a non-empty extension - preDotState = -1; - } - } - - if ( - startDot === -1 || - end === -1 || - // We saw a non-dot character immediately before the dot - preDotState === 0 || - // The (right-most) trimmed path component is exactly '..' - (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) - ) { - if (end !== -1) { - if (startPart === 0 && isAbsolute) { - ret.base = ret.name = path.slice(1, end); - } else { - ret.base = ret.name = path.slice(startPart, end); - } - } - } else { - if (startPart === 0 && isAbsolute) { - ret.name = path.slice(1, startDot); - ret.base = path.slice(1, end); - } else { - ret.name = path.slice(startPart, startDot); - ret.base = path.slice(startPart, end); - } - ret.ext = path.slice(startDot, end); - } - - if (startPart > 0) { - ret.dir = path.slice(0, startPart - 1); - } else if (isAbsolute) { - ret.dir = '/'; - } - - return ret; - }, - - sep: '/', - delimiter: ':', - win32: null, - posix: null, -}; - -posix.win32 = win32.win32 = win32; -posix.posix = win32.posix = posix; - -export const normalize = process.platform === 'win32' ? win32.normalize : posix.normalize; -export const isAbsolute = process.platform === 'win32' ? win32.isAbsolute : posix.isAbsolute; -export const join = process.platform === 'win32' ? win32.join : posix.join; -export const resolve = process.platform === 'win32' ? win32.resolve : posix.resolve; -export const relative = process.platform === 'win32' ? win32.relative : posix.relative; -export const dirname = process.platform === 'win32' ? win32.dirname : posix.dirname; -export const basename = process.platform === 'win32' ? win32.basename : posix.basename; -export const extname = process.platform === 'win32' ? win32.extname : posix.extname; -export const format = process.platform === 'win32' ? win32.format : posix.format; -export const parse = process.platform === 'win32' ? win32.parse : posix.parse; -export const toNamespacedPath = process.platform === 'win32' ? win32.toNamespacedPath : posix.toNamespacedPath; -export const sep = process.platform === 'win32' ? win32.sep : posix.sep; -export const delimiter = process.platform === 'win32' ? win32.delimiter : posix.delimiter; diff --git a/packages/components/src/utils/process.ts b/packages/components/src/utils/process.ts deleted file mode 100644 index db7afc5e7d..0000000000 --- a/packages/components/src/utils/process.ts +++ /dev/null @@ -1,28 +0,0 @@ -// Modify from @opensumi/ide-core-common/src/process.ts -import { isWindows, isOSX } from './os'; - -interface IProcess { - platform: string; - env: object; - cwd(): string; -} - -declare const process: IProcess; -const safeProcess: IProcess = - typeof process === 'undefined' - ? { - cwd(): string { - return '/'; - }, - env: Object.create(null), - get platform(): string { - return isWindows ? 'win32' : isOSX ? 'darwin' : 'linux'; - }, - } - : process; - -export namespace Process { - export const cwd = safeProcess.cwd; - export const env = safeProcess.env; - export const platform = safeProcess.platform; -} diff --git a/packages/connection/package.json b/packages/connection/package.json index 39f998a4ae..401c923f6f 100644 --- a/packages/connection/package.json +++ b/packages/connection/package.json @@ -19,7 +19,6 @@ "@opensumi/ide-core-common": "2.17.0", "@opensumi/vscode-jsonrpc": "^8.0.0-next.2", "path-match": "^1.2.4", - "shortid": "^2.2.14", "ws": "^7.2.0" }, "devDependencies": { diff --git a/packages/core-common/__tests__/utils/json.test.ts b/packages/core-browser/__tests__/utils/json.test.ts similarity index 100% rename from packages/core-common/__tests__/utils/json.test.ts rename to packages/core-browser/__tests__/utils/json.test.ts diff --git a/packages/core-browser/package.json b/packages/core-browser/package.json index 3b0f90ae0d..f2263932c1 100644 --- a/packages/core-browser/package.json +++ b/packages/core-browser/package.json @@ -48,6 +48,7 @@ "react-window": "^1.8.5", "reconnecting-websocket": "^4.2.0", "resize-observer-polyfill": "1.5.1", + "strip-json-comments": "3.0.1", "vscode-languageserver-protocol": "^3.14.1", "vscode-textmate": "5.4.0" } diff --git a/packages/core-browser/src/application/application.service.ts b/packages/core-browser/src/application/application.service.ts index 83b42cac3b..b639d47f1e 100644 --- a/packages/core-browser/src/application/application.service.ts +++ b/packages/core-browser/src/application/application.service.ts @@ -1,5 +1,12 @@ import { Injectable, Autowired } from '@opensumi/di'; -import { OS, IApplicationService, CommonServerPath, ICommonServer, Deferred } from '@opensumi/ide-core-common'; +import { + OS, + OperatingSystem, + IApplicationService, + CommonServerPath, + ICommonServer, + Deferred, +} from '@opensumi/ide-core-common'; import { AppConfig } from '../react-providers'; @@ -11,7 +18,7 @@ export class ApplicationService implements IApplicationService { @Autowired(AppConfig) private readonly appConfig: AppConfig; - private _backendOS: OS.Type; + private _backendOS: OperatingSystem; private _initialized = new Deferred(); diff --git a/packages/core-browser/src/components/actions/index.tsx b/packages/core-browser/src/components/actions/index.tsx index d725de988d..39551c27ad 100644 --- a/packages/core-browser/src/components/actions/index.tsx +++ b/packages/core-browser/src/components/actions/index.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { Button, CheckBox, Icon } from '@opensumi/ide-components'; import { ClickParam, Menu } from '@opensumi/ide-components/lib/menu'; -import { mnemonicButtonLabel } from '@opensumi/ide-core-common/lib/utils/strings'; +import { strings } from '@opensumi/ide-core-common'; import { MenuNode, @@ -31,7 +31,7 @@ const MenuAction: React.FC<{ // 这里遵循 native menu 的原则,保留一个 icon 位置
{data.checked ? : null}
-
{data.label ? mnemonicButtonLabel(data.label, true) : ''}
+
{data.label ? strings.mnemonicButtonLabel(data.label, true) : ''}
{data.keybinding ?
{data.keybinding}
: null} {hasSubmenu ? ( diff --git a/packages/core-browser/src/core-preferences.ts b/packages/core-browser/src/core-preferences.ts index e5fdcc69a0..2ea729d189 100644 --- a/packages/core-browser/src/core-preferences.ts +++ b/packages/core-browser/src/core-preferences.ts @@ -1,6 +1,5 @@ import { Injector } from '@opensumi/di'; -import { localize, getAvailableLanguages, isElectronRenderer, isWindows } from '@opensumi/ide-core-common'; -import { SUPPORTED_ENCODINGS } from '@opensumi/ide-core-common/lib/const'; +import { localize, getAvailableLanguages, isElectronRenderer, SUPPORTED_ENCODINGS } from '@opensumi/ide-core-common'; import { createPreferenceProxy, PreferenceProxy, PreferenceService, PreferenceSchema } from './preferences'; diff --git a/packages/core-browser/src/dom/index.ts b/packages/core-browser/src/dom/index.ts index c4642f2e2e..8175ed7a0e 100644 --- a/packages/core-browser/src/dom/index.ts +++ b/packages/core-browser/src/dom/index.ts @@ -1,5 +1,5 @@ import { Disposable, Emitter, Event as BaseEvent, IDisposable } from '@opensumi/ide-core-common'; -import { isWebKit } from '@opensumi/ide-core-common/lib/platform'; +import { isWebKit } from '@opensumi/ide-core-common'; export const EventType = { // Mouse diff --git a/packages/core-browser/src/encoding-registry.ts b/packages/core-browser/src/encoding-registry.ts index 78db5990e6..3d27d77aab 100644 --- a/packages/core-browser/src/encoding-registry.ts +++ b/packages/core-browser/src/encoding-registry.ts @@ -7,8 +7,7 @@ // based on https://github.com/microsoft/vscode/blob/04c36be045a94fee58e5f8992d3e3fd980294a84/src/vs/workbench/services/textfile/browser/textFileService.ts#L491 import { Injectable, Autowired } from '@opensumi/di'; -import { URI, Disposable, IDisposable } from '@opensumi/ide-core-common'; -import { UTF8, encodingExists } from '@opensumi/ide-core-common/lib/encoding'; +import { URI, Disposable, IDisposable, UTF8, encodingExists } from '@opensumi/ide-core-common'; import { PreferenceService } from './preferences'; import { getLanguageIdFromMonaco } from './services/label-service'; @@ -46,12 +45,13 @@ export class EncodingRegistry { } else if (preferredEncoding) { fileEncoding = preferredEncoding; // preferred encoding comes second } else { - fileEncoding = this.preferenceService.get( - 'files.encoding', - undefined, - resource.toString(), - getLanguageIdFromMonaco(resource)!, - )!; + fileEncoding = + this.preferenceService.get( + 'files.encoding', + undefined, + resource.toString(), + getLanguageIdFromMonaco(resource) || undefined, + ) || ''; } if (!fileEncoding || !encodingExists(fileEncoding)) { diff --git a/packages/core-browser/src/keyboard/keys.ts b/packages/core-browser/src/keyboard/keys.ts index e6bc48b1e2..19e348ae62 100644 --- a/packages/core-browser/src/keyboard/keys.ts +++ b/packages/core-browser/src/keyboard/keys.ts @@ -16,7 +16,7 @@ // Some code copied and modified from https://github.com/eclipse-theia/theia/tree/v1.14.0/packages/core/src/browser/keyboard/keys.ts import { isOSX } from '@opensumi/ide-core-common'; -import { isWindows } from '@opensumi/ide-core-common/lib/platform'; +import { isWindows } from '@opensumi/ide-core-common'; import { KeyCode as KeyCodeEnum } from '@opensumi/monaco-editor-core/esm/vs/base/common/keyCodes'; export type KeySequence = KeyCode[]; diff --git a/packages/core-browser/src/menu/next/ctxmenu-service.ts b/packages/core-browser/src/menu/next/ctxmenu-service.ts index a30457355e..2057f95fd4 100644 --- a/packages/core-browser/src/menu/next/ctxmenu-service.ts +++ b/packages/core-browser/src/menu/next/ctxmenu-service.ts @@ -1,6 +1,5 @@ import { Autowired, Injectable, Optional, INJECTOR_TOKEN, Injector } from '@opensumi/di'; -import { IDisposable, Disposable } from '@opensumi/ide-core-common/lib/disposable'; -import { Event, Emitter } from '@opensumi/ide-core-common/lib/event'; +import { IDisposable, Disposable, Event, Emitter } from '@opensumi/ide-core-common'; import { IContextKeyService } from '../../context-key'; diff --git a/packages/core-browser/src/menu/next/menu.interface.ts b/packages/core-browser/src/menu/next/menu.interface.ts index f9bbc9c6fd..fc2a2e0c81 100644 --- a/packages/core-browser/src/menu/next/menu.interface.ts +++ b/packages/core-browser/src/menu/next/menu.interface.ts @@ -1,7 +1,5 @@ import { Autowired, Injectable, Optional } from '@opensumi/di'; -import { CommandRegistry, CommandService, Command, isOSX } from '@opensumi/ide-core-common'; -import { IDisposable } from '@opensumi/ide-core-common/lib/disposable'; -import { Event } from '@opensumi/ide-core-common/lib/event'; +import { CommandRegistry, CommandService, Command, IDisposable, isMacintosh, Event } from '@opensumi/ide-core-common'; import { IContextKeyService } from '../../context-key'; import { KeybindingRegistry } from '../../keybinding'; @@ -100,7 +98,7 @@ export class MenuItemNode extends MenuNode { const isKeyCombination = Array.isArray(highPriorityKeybinding.resolved) && highPriorityKeybinding.resolved.length > 1; - let keybinding = this.keybindings.acceleratorFor(highPriorityKeybinding, isOSX ? '' : '+').join(' '); + let keybinding = this.keybindings.acceleratorFor(highPriorityKeybinding, isMacintosh ? '' : '+').join(' '); if (isKeyCombination) { keybinding = `[${keybinding}]`; } diff --git a/packages/core-browser/src/menu/next/menubar-service.ts b/packages/core-browser/src/menu/next/menubar-service.ts index c0b42fce44..b9c2af75fc 100644 --- a/packages/core-browser/src/menu/next/menubar-service.ts +++ b/packages/core-browser/src/menu/next/menubar-service.ts @@ -1,6 +1,5 @@ import { Injectable, Autowired } from '@opensumi/di'; -import { IDisposable, Disposable } from '@opensumi/ide-core-common/lib/disposable'; -import { Event, Emitter } from '@opensumi/ide-core-common/lib/event'; +import { IDisposable, Disposable, Event, Emitter } from '@opensumi/ide-core-common'; import { IMenubarItem, IMenuRegistry, MenuNode } from './base'; import { generateMergedCtxMenu } from './menu-util'; diff --git a/packages/core-browser/src/menu/next/renderer/ctxmenu/electron.ts b/packages/core-browser/src/menu/next/renderer/ctxmenu/electron.ts index ea3f3aeb43..d92015eec1 100644 --- a/packages/core-browser/src/menu/next/renderer/ctxmenu/electron.ts +++ b/packages/core-browser/src/menu/next/renderer/ctxmenu/electron.ts @@ -1,6 +1,6 @@ import { Injectable, Autowired } from '@opensumi/di'; -import { Disposable, INativeMenuTemplate, CommandService, IElectronMainMenuService } from '@opensumi/ide-core-common'; -import { mnemonicButtonLabel } from '@opensumi/ide-core-common/lib/utils/strings'; +import { INativeMenuTemplate, CommandService, IElectronMainMenuService } from '@opensumi/ide-core-common'; +import { strings, Disposable } from '@opensumi/ide-core-common'; import { electronEnv } from '../../../../utils'; import { MenuNode } from '../../base'; @@ -33,7 +33,7 @@ export class ElectronMenuFactory extends Disposable { if (menuNode.id === SubmenuItemNode.ID) { const submenuTemplate = this.getTemplate(menuNode.children, map, context); return { - label: `${mnemonicButtonLabel(menuNode.label, true)}`, + label: `${strings.mnemonicButtonLabel(menuNode.label, true)}`, submenu: Array.isArray(submenuTemplate) && submenuTemplate.length ? submenuTemplate : undefined, }; } else { @@ -41,7 +41,9 @@ export class ElectronMenuFactory extends Disposable { return { type: menuNode.checked ? 'checkbox' : undefined, checked: menuNode.checked ? menuNode.checked : false, - label: `${mnemonicButtonLabel(menuNode.label, true)} ${menuNode.isKeyCombination ? menuNode.keybinding : ''}`, + label: `${strings.mnemonicButtonLabel(menuNode.label, true)} ${ + menuNode.isKeyCombination ? menuNode.keybinding : '' + }`, id: menuNode.id, action: true, role: menuNode.nativeRole, @@ -185,7 +187,7 @@ export class ElectronMenuBarService implements IElectronMenuBarService { const templates = this.factory.getTemplate(menuNodes, this.menuBarActions); if (templates && templates.length > 0) { const template: INativeMenuTemplate = { - label: mnemonicButtonLabel(item.label, true), + label: strings.mnemonicButtonLabel(item.label, true), submenu: templates, }; if (item.nativeRole) { diff --git a/packages/core-browser/src/menu/next/toolbar-action.service.ts b/packages/core-browser/src/menu/next/toolbar-action.service.ts index 654cd5df5e..1f81257ecb 100644 --- a/packages/core-browser/src/menu/next/toolbar-action.service.ts +++ b/packages/core-browser/src/menu/next/toolbar-action.service.ts @@ -1,5 +1,5 @@ import { Injectable, Autowired } from '@opensumi/di'; -import { IDisposable, Disposable } from '@opensumi/ide-core-common/lib/disposable'; +import { IDisposable, Disposable } from '@opensumi/ide-core-common'; import { IToolbarRegistry, createToolbarActionBtn } from '../../toolbar'; import { createToolbarActionSelect } from '../../toolbar/components/select'; diff --git a/packages/core-browser/src/preferences/index.ts b/packages/core-browser/src/preferences/index.ts index 5f68ee9f9f..1677ec96de 100644 --- a/packages/core-browser/src/preferences/index.ts +++ b/packages/core-browser/src/preferences/index.ts @@ -5,4 +5,5 @@ export * from './preference-scope'; export * from './preference-service'; export * from './preference-proxy'; export * from './early-preferences'; +export * from './types'; export * from './settings'; diff --git a/packages/core-browser/src/preferences/preference-provider.ts b/packages/core-browser/src/preferences/preference-provider.ts index a6eae6818b..8f4e5eef0e 100644 --- a/packages/core-browser/src/preferences/preference-provider.ts +++ b/packages/core-browser/src/preferences/preference-provider.ts @@ -6,14 +6,15 @@ import { Event, URI, Deferred, - JSONUtils, - JSONValue, isEmptyObject, FileStat, } from '@opensumi/ide-core-common'; import { PreferenceScope } from '@opensumi/ide-core-common/lib/preferences/preference-scope'; +import { JSONUtils, JSONValue } from '../utils'; + import { getExternalPreferenceProvider, getAllExternalProviders } from './early-preferences'; +import { PreferenceResolveResult } from './types'; export interface IResolvedPreferences { default: { [key: string]: any }; languageSpecific: { @@ -41,14 +42,6 @@ export interface ILanguagePreferenceProviderDataChanges { }; } -export interface PreferenceResolveResult { - configUri?: URI; - value?: T; - scope?: PreferenceScope; - // 是否存在来自针对语言的设置 - languageSpecific?: boolean; -} - function transformReverse(delegates: { [delegated: string]: { delegateTo: string; diff --git a/packages/core-browser/src/preferences/preference-proxy.ts b/packages/core-browser/src/preferences/preference-proxy.ts index b8c824c8ff..a9210c708f 100644 --- a/packages/core-browser/src/preferences/preference-proxy.ts +++ b/packages/core-browser/src/preferences/preference-proxy.ts @@ -1,7 +1,7 @@ import { Disposable, Event, isObject, isUndefined, PreferenceScope } from '@opensumi/ide-core-common'; import { PreferenceSchema } from './preference-contribution'; -import { PreferenceService } from './preference-service'; +import { PreferenceService } from './types'; export interface PreferenceChangeEvent { readonly preferenceName: keyof T; diff --git a/packages/core-browser/src/preferences/preference-service.ts b/packages/core-browser/src/preferences/preference-service.ts index b28c86b735..0ea8fda04e 100644 --- a/packages/core-browser/src/preferences/preference-service.ts +++ b/packages/core-browser/src/preferences/preference-service.ts @@ -1,35 +1,29 @@ import { Injectable, Autowired } from '@opensumi/di'; import { Deferred, - Event, Emitter, DisposableCollection, - IDisposable, Disposable, URI, isUndefined, isEmptyObject, + objects, LRUMap, - deepClone, } from '@opensumi/ide-core-common'; import { PreferenceConfigurations } from './preference-configurations'; import { PreferenceSchemaProvider } from './preference-contribution'; +import { PreferenceProvider, PreferenceProviderDataChange, PreferenceProviderDataChanges } from './preference-provider'; +import { PreferenceScope } from './preference-scope'; import { - PreferenceProvider, - PreferenceProviderDataChange, - PreferenceProviderDataChanges, + PreferenceChange, + PreferenceChanges, + PreferenceProviderProvider, PreferenceResolveResult, -} from './preference-provider'; -import { PreferenceScope } from './preference-scope'; + PreferenceService, +} from './types'; -export interface PreferenceChange { - readonly preferenceName: string; - readonly newValue?: any; - readonly oldValue?: any; - readonly scope: PreferenceScope; - affects(resourceUri?: string): boolean; -} +const { deepClone } = objects; export class PreferenceChangeImpl implements PreferenceChange { constructor(private change: PreferenceProviderDataChange) {} @@ -54,88 +48,6 @@ export class PreferenceChangeImpl implements PreferenceChange { } } -export interface PreferenceChanges { - [preferenceName: string]: PreferenceChange; -} -export const PreferenceService = Symbol('PreferenceService'); - -export interface PreferenceService extends IDisposable { - readonly ready: Promise; - /** - * 获取一个配置的值 - * @param preferenceName 配置名称 - * @param defaultValue 默认值 - * @param resourceUri 资源路径 - * @param overrideIdentifier 一般指语言偏好设置 - */ - get(preferenceName: string, defaultValue: T, resourceUri?: string, overrideIdentifier?: string): T; - get(preferenceName: string, defaultValue?: T, resourceUri?: string, overrideIdentifier?: string): T | undefined; - - /** - * 是否一个配置在指定 scope 存在针对语言的配置 - * @param preferenceName 配置名称 - * @param overrideIdentifier 语言 - * @param resourceUri 资源路径 - */ - hasLanguageSpecific(preferenceName: any, overrideIdentifier: string, resourceUri: string): boolean; - - /** - * 设置一个配置的值 - * @param preferenceName 偏好名称 - * @param value 设置值 - * @param scope 目标scope级别 如 User, Workspace - * @param resourceUri 资源路径 - * @param overrideIdentifier 一般指语言偏好设置 - */ - set( - preferenceName: string, - value: any, - scope?: PreferenceScope, - resourceUri?: string, - overrideIdentifier?: string, - ): Promise; - - onPreferenceChanged: Event; - - onPreferencesChanged: Event; - - onLanguagePreferencesChanged: Event<{ overrideIdentifier: string; changes: PreferenceChanges }>; - - inspect( - preferenceName: string, - resourceUri?: string, - language?: string, - ): - | { - preferenceName: string; - defaultValue: T | undefined; - globalValue: T | undefined; // User Preference - workspaceValue: T | undefined; // Workspace Preference - workspaceFolderValue: T | undefined; // Folder Preference - } - | undefined; - - getProvider(scope: PreferenceScope): PreferenceProvider | undefined; - - resolve( - preferenceName: string, - defaultValue?: T, - resourceUri?: string, - language?: string, - untilScope?: PreferenceScope, - ): PreferenceResolveResult; - - /** - * 都走 onPreferenceChanged 再用if判断性能太差了 - * TODO: 将只监听一个偏好的使用这个方法 - * @param preferenceName - */ - onSpecificPreferenceChange(preferenceName, listener: (change: PreferenceChange) => void): IDisposable; -} - -export const PreferenceProviderProvider = Symbol('PreferenceProviderProvider'); -export type PreferenceProviderProvider = (scope: PreferenceScope, uri?: URI) => PreferenceProvider; - @Injectable() export class PreferenceServiceImpl implements PreferenceService { protected readonly onPreferenceChangedEmitter = new Emitter(); diff --git a/packages/core-browser/src/preferences/types.ts b/packages/core-browser/src/preferences/types.ts new file mode 100644 index 0000000000..ff4ec0c999 --- /dev/null +++ b/packages/core-browser/src/preferences/types.ts @@ -0,0 +1,102 @@ +import { URI, IDisposable, Event } from '@opensumi/ide-core-common'; + +import { PreferenceProvider } from './preference-provider'; +import { PreferenceScope } from './preference-scope'; + +export interface PreferenceChange { + readonly preferenceName: string; + readonly newValue?: any; + readonly oldValue?: any; + readonly scope: PreferenceScope; + affects(resourceUri?: string): boolean; +} + +export interface PreferenceResolveResult { + configUri?: URI; + value?: T; + scope?: PreferenceScope; + // 是否存在来自针对语言的设置 + languageSpecific?: boolean; +} + +export interface PreferenceChanges { + [preferenceName: string]: PreferenceChange; +} +export const PreferenceService = Symbol('PreferenceService'); + +export interface PreferenceService extends IDisposable { + readonly ready: Promise; + /** + * 获取一个配置的值 + * @param preferenceName 配置名称 + * @param defaultValue 默认值 + * @param resourceUri 资源路径 + * @param overrideIdentifier 一般指语言偏好设置 + */ + get(preferenceName: string, defaultValue: T, resourceUri?: string, overrideIdentifier?: string): T; + get(preferenceName: string, defaultValue?: T, resourceUri?: string, overrideIdentifier?: string): T | undefined; + + /** + * 是否一个配置在指定 scope 存在针对语言的配置 + * @param preferenceName 配置名称 + * @param overrideIdentifier 语言 + * @param resourceUri 资源路径 + */ + hasLanguageSpecific(preferenceName: any, overrideIdentifier: string, resourceUri: string): boolean; + + /** + * 设置一个配置的值 + * @param preferenceName 偏好名称 + * @param value 设置值 + * @param scope 目标scope级别 如 User, Workspace + * @param resourceUri 资源路径 + * @param overrideIdentifier 一般指语言偏好设置 + */ + set( + preferenceName: string, + value: any, + scope?: PreferenceScope, + resourceUri?: string, + overrideIdentifier?: string, + ): Promise; + + onPreferenceChanged: Event; + + onPreferencesChanged: Event; + + onLanguagePreferencesChanged: Event<{ overrideIdentifier: string; changes: PreferenceChanges }>; + + inspect( + preferenceName: string, + resourceUri?: string, + language?: string, + ): + | { + preferenceName: string; + defaultValue: T | undefined; + globalValue: T | undefined; // User Preference + workspaceValue: T | undefined; // Workspace Preference + workspaceFolderValue: T | undefined; // Folder Preference + } + | undefined; + + getProvider(scope: PreferenceScope): PreferenceProvider | undefined; + + resolve( + preferenceName: string, + defaultValue?: T, + resourceUri?: string, + language?: string, + untilScope?: PreferenceScope, + ): PreferenceResolveResult; + + /** + * 都走 onPreferenceChanged 再用if判断性能太差了 + * TODO: 将只监听一个偏好的使用这个方法 + * @param preferenceName + */ + onSpecificPreferenceChange(preferenceName, listener: (change: PreferenceChange) => void): IDisposable; +} + +export const PreferenceProviderProvider = Symbol('PreferenceProviderProvider'); +export type PreferenceProviderProvider = (scope: PreferenceScope, uri?: URI) => PreferenceProvider; diff --git a/packages/core-browser/src/progress/progress.service.tsx b/packages/core-browser/src/progress/progress.service.tsx index 6f8c29eff4..948bdc0ff5 100644 --- a/packages/core-browser/src/progress/progress.service.tsx +++ b/packages/core-browser/src/progress/progress.service.tsx @@ -17,15 +17,15 @@ import { IProgressStep, ProgressLocation, Progress, - format, + strings, CommandService, Disposable, Emitter, Event, toDisposable, dispose, + parseLinkedText, } from '@opensumi/ide-core-common'; -import { parseLinkedText } from '@opensumi/ide-core-common/lib/linkedText'; import { timeout, IDisposable, IOpenerService, toMarkdown } from '..'; import { open } from '../components'; @@ -36,6 +36,8 @@ import { ProgressIndicator } from './progress-indicator'; import { IProgressService, IProgressIndicator, IProgressRunner } from '.'; +const { format } = strings; + @Injectable() export class ProgressService implements IProgressService { @Autowired(INJECTOR_TOKEN) diff --git a/packages/core-browser/src/quick-open/recent-files.ts b/packages/core-browser/src/quick-open/recent-files.ts index db1d8f4658..aa6b40fd18 100644 --- a/packages/core-browser/src/quick-open/recent-files.ts +++ b/packages/core-browser/src/quick-open/recent-files.ts @@ -1,7 +1,7 @@ import { Injectable, Autowired } from '@opensumi/di'; import { OnEvent, FileChangeType, IPosition } from '@opensumi/ide-core-common'; +import { WithEventBus } from '@opensumi/ide-core-common/lib/event-bus'; -import { WithEventBus } from '..'; import { RecentStorage } from '../common/common.storage'; import { FilesChangeEvent } from '../fs'; diff --git a/packages/core-browser/src/services/label-service.ts b/packages/core-browser/src/services/label-service.ts index 97d3646782..27e9aca766 100644 --- a/packages/core-browser/src/services/label-service.ts +++ b/packages/core-browser/src/services/label-service.ts @@ -4,13 +4,13 @@ import { Autowired, Injectable } from '@opensumi/di'; import { URI, Emitter, - addElement, IDisposable, - LRUMap, + arrays, Event, WithEventBus, BasicEvent, Disposable, + LRUMap, } from '@opensumi/ide-core-common'; import type { IModelService } from '@opensumi/monaco-editor-core/esm/vs/editor/common/services/modelService'; import type { IModeService } from '@opensumi/monaco-editor-core/esm/vs/editor/common/services/modeService'; @@ -19,6 +19,7 @@ import { StaticServices } from '@opensumi/monaco-editor-core/esm/vs/editor/stand import { getIcon } from '../style/icon/icon'; +const { addElement } = arrays; /** * Data URI related helpers. diff --git a/packages/core-browser/src/services/status-bar-service.ts b/packages/core-browser/src/services/status-bar-service.ts index 0035dd7588..fd12de6510 100644 --- a/packages/core-browser/src/services/status-bar-service.ts +++ b/packages/core-browser/src/services/status-bar-service.ts @@ -1,4 +1,5 @@ -import { IDisposable, IMarkdownString, IThemeColor, StatusBarHoverCommand } from '@opensumi/ide-core-common'; +import { IMarkdownString, IThemeColor, StatusBarHoverCommand } from '@opensumi/ide-core-common'; +import { IDisposable } from '@opensumi/ide-core-common'; import { IMenu } from '../menu/next'; diff --git a/packages/core-browser/src/toolbar/toolbar.popover.registry.ts b/packages/core-browser/src/toolbar/toolbar.popover.registry.ts index 98abc4ad87..b861222be1 100644 --- a/packages/core-browser/src/toolbar/toolbar.popover.registry.ts +++ b/packages/core-browser/src/toolbar/toolbar.popover.registry.ts @@ -1,8 +1,7 @@ import React from 'react'; import { Injectable } from '@opensumi/di'; -import { Disposable } from '@opensumi/ide-components/lib/utils'; -import { Emitter, Event } from '@opensumi/ide-core-common'; +import { Emitter, Event, Disposable } from '@opensumi/ide-core-common'; import { IToolbarPopoverRegistry } from './types'; diff --git a/packages/core-browser/src/toolbar/toolbar.registry.ts b/packages/core-browser/src/toolbar/toolbar.registry.ts index 5ed7f6d259..7ff63dabc2 100644 --- a/packages/core-browser/src/toolbar/toolbar.registry.ts +++ b/packages/core-browser/src/toolbar/toolbar.registry.ts @@ -2,7 +2,6 @@ import { Injectable, Autowired } from '@opensumi/di'; import { IDisposable, Emitter, WithEventBus, ContributionProvider, Domain } from '@opensumi/ide-core-common'; import { ClientAppContribution } from '../common'; -import { PreferenceService } from '../preferences'; import { IToolbarRegistry, @@ -47,10 +46,7 @@ export class NextToolbarRegistryImpl extends WithEventBus implements IToolbarReg private _onActionAdded: Emitter = new Emitter(); @Autowired(ToolBarActionContribution) - contributions: ContributionProvider; - - @Autowired(PreferenceService) - preferenceService: PreferenceService; + private readonly contributions: ContributionProvider; private _inited = false; diff --git a/packages/core-browser/src/utils/index.ts b/packages/core-browser/src/utils/index.ts index 1ebe4ad3e5..374bfd3e21 100644 --- a/packages/core-browser/src/utils/index.ts +++ b/packages/core-browser/src/utils/index.ts @@ -3,3 +3,4 @@ export * from './electron'; export * from './react-hooks'; export * from './icon'; export * from './parse'; +export * from './json'; diff --git a/packages/core-common/src/utils/json.ts b/packages/core-browser/src/utils/json.ts similarity index 100% rename from packages/core-common/src/utils/json.ts rename to packages/core-browser/src/utils/json.ts diff --git a/packages/core-browser/src/utils/react-hooks.ts b/packages/core-browser/src/utils/react-hooks.ts index 9936f3194f..6bebe5d75d 100644 --- a/packages/core-browser/src/utils/react-hooks.ts +++ b/packages/core-browser/src/utils/react-hooks.ts @@ -3,10 +3,11 @@ import { useState, useEffect, DependencyList } from 'react'; import { Disposable, DisposableStore, IDisposable } from '@opensumi/ide-core-common'; -import { PreferenceService, useInjectable } from '..'; import { MenuNode } from '../menu/next/base'; import { generateInlineActions } from '../menu/next/menu-util'; import { IMenu, IMenuSeparator, IContextMenu } from '../menu/next/menu.interface'; +import { PreferenceService } from '../preferences/types'; +import { useInjectable } from '../react-hooks/injectable-hooks'; export function useDebounce(value, delay) { const [denouncedValue, setDenouncedValue] = useState(value); diff --git a/packages/core-browser/src/window/window.service.ts b/packages/core-browser/src/window/window.service.ts index ed61f4b0dc..50c8db8bc9 100644 --- a/packages/core-browser/src/window/window.service.ts +++ b/packages/core-browser/src/window/window.service.ts @@ -13,9 +13,6 @@ export class WindowService implements IWindowService { @Autowired(INJECTOR_TOKEN) private readonly injector: Injector; - @Autowired(IExternalUriService) - private readonly externalUriService: IExternalUriService; - @Autowired(AppConfig) private readonly appConfig: AppConfig; @@ -29,7 +26,8 @@ export class WindowService implements IWindowService { return undefined; } else { if (options?.external) { - url = this.externalUriService.resolveExternalUri(new URI(url)).toString(true); + const externalUriService = this.injector.get(IExternalUriService); + url = externalUriService.resolveExternalUri(new URI(url)).toString(true); } const newWindow = window.open(url); if (newWindow === null) { diff --git a/packages/core-common/__tests__/event-bus.test.ts b/packages/core-common/__tests__/event-bus.test.ts index ead219bf4f..3f4aa15d1f 100644 --- a/packages/core-common/__tests__/event-bus.test.ts +++ b/packages/core-common/__tests__/event-bus.test.ts @@ -6,7 +6,7 @@ describe('event-bus', () => { class AEvent extends BasicEvent {} class BEvent extends BasicEvent {} - it('event bus 能够正常执行', () => { + it('event bus work', () => { const eventBus = new EventBusImpl(); const spyA = jest.fn(); eventBus.on(AEvent, spyA); @@ -25,7 +25,7 @@ describe('event-bus', () => { expect(spyB).toBeCalledWith(bEvent); }); - it('event bus fireAndAwait能够正常执行', async () => { + it('event bus fireAndAwait should be work', async () => { const eventBus = new EventBusImpl(); const spyA = jest.fn(); eventBus.on(AEvent, spyA); @@ -50,7 +50,7 @@ describe('event-bus', () => { expect(res[2].result).toBeUndefined; }); - it('event bus 能够多次触发', () => { + it('event bus can be triggered multiple times', () => { const eventBus = new EventBusImpl(); const spy = jest.fn(); eventBus.on(AEvent, spy); @@ -71,13 +71,13 @@ describe('event-bus', () => { expect(spy).toBeCalledWith(b1); }); - it('没有注册监听函数的时候,fire 不会报错', () => { + it('fire will not report an error when no listener function is registered', () => { const eventBus = new EventBusImpl(); const a1 = new AEvent(1); eventBus.fire(a1); }); - it('使用 Decorator 去监听事件变化', () => { + it('use Decorator to listen for event changes', () => { const spy = jest.fn(); class ResizeEvent extends BasicEvent {} const resizeEvent = new ResizeEvent(1); @@ -116,7 +116,7 @@ describe('event-bus', () => { expect(spy).toBeCalledWith(resizeEvent); }); - it('event bus once 只能触发一次', () => { + it('event bus once can only be triggered once', () => { const eventBus = new EventBusImpl(); const spy = jest.fn(); eventBus.once(AEvent, spy); diff --git a/packages/core-common/__tests__/hash-calculate.test.ts b/packages/core-common/__tests__/hash-calculate.test.ts index 95c7240f17..b743c0693b 100644 --- a/packages/core-common/__tests__/hash-calculate.test.ts +++ b/packages/core-common/__tests__/hash-calculate.test.ts @@ -1,4 +1,4 @@ -import { Injectable, Injector } from '@opensumi/di'; +import { Injector } from '@opensumi/di'; import { IHashCalculateService, HashCalculateServiceImpl } from '../src/hash-calculate/hash-calculate'; diff --git a/packages/core-common/__tests__/utils/arrays.test.ts b/packages/core-common/__tests__/utils/arrays.test.ts deleted file mode 100644 index 708e49ef18..0000000000 --- a/packages/core-common/__tests__/utils/arrays.test.ts +++ /dev/null @@ -1,108 +0,0 @@ -// copied from https://github.com/microsoft/vscode/blob/master/src/vs/base/test/common/async.test.ts -// converted by [jest-codemods](https://github.com/skovhus/jest-codemods) - -/* --------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import * as arrays from '../../src/utils/arrays'; - -function deepStrictEqual(a, b) { - expect(a).toEqual(b); -} - -function strictEqual(a, b) { - expect(a).toBe(b); -} - -describe('Arrays', () => { - test('sortedDiff', () => { - function compare(a: number, b: number): number { - return a - b; - } - - let d = arrays.sortedDiff([1, 2, 4], [], compare); - deepStrictEqual(d, [{ start: 0, deleteCount: 3, toInsert: [] }]); - - d = arrays.sortedDiff([], [1, 2, 4], compare); - deepStrictEqual(d, [{ start: 0, deleteCount: 0, toInsert: [1, 2, 4] }]); - - d = arrays.sortedDiff([1, 2, 4], [1, 2, 4], compare); - deepStrictEqual(d, []); - - d = arrays.sortedDiff([1, 2, 4], [2, 3, 4, 5], compare); - deepStrictEqual(d, [ - { start: 0, deleteCount: 1, toInsert: [] }, - { start: 2, deleteCount: 0, toInsert: [3] }, - { start: 3, deleteCount: 0, toInsert: [5] }, - ]); - - d = arrays.sortedDiff([2, 3, 4, 5], [1, 2, 4], compare); - deepStrictEqual(d, [ - { start: 0, deleteCount: 0, toInsert: [1] }, - { start: 1, deleteCount: 1, toInsert: [] }, - { start: 3, deleteCount: 1, toInsert: [] }, - ]); - - d = arrays.sortedDiff([1, 3, 5, 7], [5, 9, 11], compare); - deepStrictEqual(d, [ - { start: 0, deleteCount: 2, toInsert: [] }, - { start: 3, deleteCount: 1, toInsert: [9, 11] }, - ]); - - d = arrays.sortedDiff([1, 3, 7], [5, 9, 11], compare); - deepStrictEqual(d, [{ start: 0, deleteCount: 3, toInsert: [5, 9, 11] }]); - }); - - test('distinct', () => { - function compare(a: string): string { - return a; - } - - deepStrictEqual(arrays.distinct(['32', '4', '5'], compare), ['32', '4', '5']); - deepStrictEqual(arrays.distinct(['32', '4', '5', '4'], compare), ['32', '4', '5']); - deepStrictEqual(arrays.distinct(['32', 'constructor', '5', '1'], compare), ['32', 'constructor', '5', '1']); - deepStrictEqual(arrays.distinct(['32', 'constructor', 'proto', 'proto', 'constructor'], compare), [ - '32', - 'constructor', - 'proto', - ]); - deepStrictEqual(arrays.distinct(['32', '4', '5', '32', '4', '5', '32', '4', '5', '5'], compare), ['32', '4', '5']); - }); - - test('coalesce', () => { - const a: Array = arrays.coalesce([null, 1, null, 2, 3]); - strictEqual(a.length, 3); - strictEqual(a[0], 1); - strictEqual(a[1], 2); - strictEqual(a[2], 3); - - arrays.coalesce([null, 1, null, undefined, undefined, 2, 3]); - strictEqual(a.length, 3); - strictEqual(a[0], 1); - strictEqual(a[1], 2); - strictEqual(a[2], 3); - - let b: number[] = []; - b[10] = 1; - b[20] = 2; - b[30] = 3; - b = arrays.coalesce(b); - strictEqual(b.length, 3); - strictEqual(b[0], 1); - strictEqual(b[1], 2); - strictEqual(b[2], 3); - - let sparse: number[] = []; - sparse[0] = 1; - sparse[1] = 1; - sparse[17] = 1; - sparse[1000] = 1; - sparse[1001] = 1; - - strictEqual(sparse.length, 1002); - - sparse = arrays.coalesce(sparse); - strictEqual(sparse.length, 5); - }); -}); diff --git a/packages/core-common/__tests__/utils/paths.test.ts b/packages/core-common/__tests__/utils/paths.test.ts deleted file mode 100644 index ccd5fd7b51..0000000000 --- a/packages/core-common/__tests__/utils/paths.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { URI } from '../../src/uri'; -import * as paths from '../../src/utils/paths'; - -describe('paths', () => { - // 测试 uri#toString 传入 skipEncoding#true 时 - // path 部分和 `uri.path` 的 toString 结果是保持一致的 - describe('toString', () => { - it('uri with path', () => { - const uri1 = URI.file('test.ts'); - expect(uri1.withoutScheme().toString(true)).toBe(uri1.path.toString()); - - const uri2 = URI.from({ - scheme: 'git', - authority: 'github.com', - path: '/test1.ts', - }); - - expect(uri2.withoutScheme().toString(true)).toContain(uri2.path.toString()); - }); - - it('uri with path and query', () => { - const uri1 = URI.from({ - scheme: 'file', - authority: '', - path: 'test.ts', - query: 'a=1', - fragment: 'hash', - }); - - expect(uri1.withoutScheme().toString(true)).toContain(uri1.path.toString()); - - const uri2 = URI.from({ - scheme: 'git', - authority: 'github.com', - path: '/test1.ts', - query: 'a=1', - fragment: 'hash', - }); - - expect(uri2.withoutScheme().toString(true)).toContain(uri2.path.toString()); - }); - }); -}); diff --git a/packages/core-common/__tests__/utils/strings.test.ts b/packages/core-common/__tests__/utils/strings.test.ts deleted file mode 100644 index b7abe18ef3..0000000000 --- a/packages/core-common/__tests__/utils/strings.test.ts +++ /dev/null @@ -1,470 +0,0 @@ -// copied from https://github.com/microsoft/vscode/blob/master/src/vs/base/test/common/strings.test.ts -// converted by [jest-codemods](https://github.com/skovhus/jest-codemods) - -/* --------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import * as strings from '../../src/utils/strings'; - -describe('Strings', () => { - test('equalsIgnoreCase', () => { - expect(strings.equalsIgnoreCase('', '')).toBeTruthy(); - expect(!strings.equalsIgnoreCase('', '1')).toBeTruthy(); - expect(!strings.equalsIgnoreCase('1', '')).toBeTruthy(); - - expect(strings.equalsIgnoreCase('a', 'a')).toBeTruthy(); - expect(strings.equalsIgnoreCase('abc', 'Abc')).toBeTruthy(); - expect(strings.equalsIgnoreCase('abc', 'ABC')).toBeTruthy(); - expect(strings.equalsIgnoreCase('Höhenmeter', 'HÖhenmeter')).toBeTruthy(); - expect(strings.equalsIgnoreCase('ÖL', 'Öl')).toBeTruthy(); - }); - - test('beginsWithIgnoreCase', () => { - expect(strings.startsWithIgnoreCase('', '')).toBeTruthy(); - expect(!strings.startsWithIgnoreCase('', '1')).toBeTruthy(); - expect(strings.startsWithIgnoreCase('1', '')).toBeTruthy(); - - expect(strings.startsWithIgnoreCase('a', 'a')).toBeTruthy(); - expect(strings.startsWithIgnoreCase('abc', 'Abc')).toBeTruthy(); - expect(strings.startsWithIgnoreCase('abc', 'ABC')).toBeTruthy(); - expect(strings.startsWithIgnoreCase('Höhenmeter', 'HÖhenmeter')).toBeTruthy(); - expect(strings.startsWithIgnoreCase('ÖL', 'Öl')).toBeTruthy(); - - expect(strings.startsWithIgnoreCase('alles klar', 'a')).toBeTruthy(); - expect(strings.startsWithIgnoreCase('alles klar', 'A')).toBeTruthy(); - expect(strings.startsWithIgnoreCase('alles klar', 'alles k')).toBeTruthy(); - expect(strings.startsWithIgnoreCase('alles klar', 'alles K')).toBeTruthy(); - expect(strings.startsWithIgnoreCase('alles klar', 'ALLES K')).toBeTruthy(); - expect(strings.startsWithIgnoreCase('alles klar', 'alles klar')).toBeTruthy(); - expect(strings.startsWithIgnoreCase('alles klar', 'ALLES KLAR')).toBeTruthy(); - - expect(!strings.startsWithIgnoreCase('alles klar', ' ALLES K')).toBeTruthy(); - expect(!strings.startsWithIgnoreCase('alles klar', 'ALLES K ')).toBeTruthy(); - expect(!strings.startsWithIgnoreCase('alles klar', 'öALLES K ')).toBeTruthy(); - expect(!strings.startsWithIgnoreCase('alles klar', ' ')).toBeTruthy(); - expect(!strings.startsWithIgnoreCase('alles klar', 'ö')).toBeTruthy(); - }); - - test('compareIgnoreCase', () => { - function assertCompareIgnoreCase(a: string, b: string, recurse = true): void { - let actual = strings.compareIgnoreCase(a, b); - actual = actual > 0 ? 1 : actual < 0 ? -1 : actual; - - let expected = strings.compare(a.toLowerCase(), b.toLowerCase()); - expected = expected > 0 ? 1 : expected < 0 ? -1 : expected; - expect(actual).toEqual(expected); - - if (recurse) { - assertCompareIgnoreCase(b, a, false); - } - } - - assertCompareIgnoreCase('', ''); - assertCompareIgnoreCase('abc', 'ABC'); - assertCompareIgnoreCase('abc', 'ABc'); - assertCompareIgnoreCase('abc', 'ABcd'); - assertCompareIgnoreCase('abc', 'abcd'); - assertCompareIgnoreCase('foo', 'föo'); - assertCompareIgnoreCase('Code', 'code'); - assertCompareIgnoreCase('Code', 'cöde'); - - assertCompareIgnoreCase('B', 'a'); - assertCompareIgnoreCase('a', 'B'); - assertCompareIgnoreCase('b', 'a'); - assertCompareIgnoreCase('a', 'b'); - - assertCompareIgnoreCase('aa', 'ab'); - assertCompareIgnoreCase('aa', 'aB'); - assertCompareIgnoreCase('aa', 'aA'); - assertCompareIgnoreCase('a', 'aa'); - assertCompareIgnoreCase('ab', 'aA'); - assertCompareIgnoreCase('O', '/'); - }); - - test('format', () => { - expect(strings.format('Foo Bar')).toBe('Foo Bar'); - expect(strings.format('Foo {0} Bar')).toBe('Foo {0} Bar'); - expect(strings.format('Foo {0} Bar', 'yes')).toBe('Foo yes Bar'); - expect(strings.format('Foo {0} Bar {0}', 'yes')).toBe('Foo yes Bar yes'); - expect(strings.format('Foo {0} Bar {1}{2}', 'yes')).toBe('Foo yes Bar {1}{2}'); - expect(strings.format('Foo {0} Bar {1}{2}', 'yes', undefined)).toBe('Foo yes Bar undefined{2}'); - expect(strings.format('Foo {0} Bar {1}{2}', 'yes', 5, false)).toBe('Foo yes Bar 5false'); - expect(strings.format('Foo {0} Bar. {1}', '(foo)', '.test')).toBe('Foo (foo) Bar. .test'); - }); - - test('overlap', () => { - expect(strings.overlap('foobar', 'arr, I am a priate')).toEqual(2); - expect(strings.overlap('no', 'overlap')).toEqual(1); - expect(strings.overlap('no', '0verlap')).toEqual(0); - expect(strings.overlap('nothing', '')).toEqual(0); - expect(strings.overlap('', 'nothing')).toEqual(0); - expect(strings.overlap('full', 'full')).toEqual(4); - expect(strings.overlap('full', 'fulloverlap')).toEqual(4); - }); - test('lcut', () => { - expect(strings.lcut('foo bar', 0)).toBe(''); - expect(strings.lcut('foo bar', 1)).toBe('bar'); - expect(strings.lcut('foo bar', 3)).toBe('bar'); - expect(strings.lcut('foo bar', 4)).toBe('bar'); // Leading whitespace trimmed - expect(strings.lcut('foo bar', 5)).toBe('foo bar'); - expect(strings.lcut('test string 0.1.2.3', 3)).toBe('2.3'); - - expect(strings.lcut('', 10)).toBe(''); - expect(strings.lcut('a', 10)).toBe('a'); - }); - - test('pad', () => { - expect(strings.pad(1, 0)).toBe('1'); - expect(strings.pad(1, 1)).toBe('1'); - expect(strings.pad(1, 2)).toBe('01'); - expect(strings.pad(0, 2)).toBe('00'); - }); - - test('escape', () => { - expect(strings.escape('')).toBe(''); - expect(strings.escape('foo')).toBe('foo'); - expect(strings.escape('foo bar')).toBe('foo bar'); - expect(strings.escape('')).toBe('<foo bar>'); - expect(strings.escape('Hello')).toBe('<foo>Hello</foo>'); - }); - - test('startsWith', () => { - expect(strings.startsWith('foo', 'f')).toBeTruthy(); - expect(strings.startsWith('foo', 'fo')).toBeTruthy(); - expect(strings.startsWith('foo', 'foo')).toBeTruthy(); - expect(!strings.startsWith('foo', 'o')).toBeTruthy(); - expect(!strings.startsWith('', 'f')).toBeTruthy(); - expect(strings.startsWith('foo', '')).toBeTruthy(); - expect(strings.startsWith('', '')).toBeTruthy(); - }); - - test('endsWith', () => { - expect(strings.endsWith('foo', 'o')).toBeTruthy(); - expect(strings.endsWith('foo', 'oo')).toBeTruthy(); - expect(strings.endsWith('foo', 'foo')).toBeTruthy(); - expect(strings.endsWith('foo bar foo', 'foo')).toBeTruthy(); - expect(!strings.endsWith('foo', 'f')).toBeTruthy(); - expect(!strings.endsWith('', 'f')).toBeTruthy(); - expect(strings.endsWith('foo', '')).toBeTruthy(); - expect(strings.endsWith('', '')).toBeTruthy(); - expect(strings.endsWith('/', '/')).toBeTruthy(); - }); - - test('ltrim', () => { - expect(strings.ltrim('foo', 'f')).toBe('oo'); - expect(strings.ltrim('foo', 'o')).toBe('foo'); - expect(strings.ltrim('http://www.test.de', 'http://')).toBe('www.test.de'); - expect(strings.ltrim('/foo/', '/')).toBe('foo/'); - expect(strings.ltrim('//foo/', '/')).toBe('foo/'); - expect(strings.ltrim('/', '')).toBe('/'); - expect(strings.ltrim('/', '/')).toBe(''); - expect(strings.ltrim('///', '/')).toBe(''); - expect(strings.ltrim('', '')).toBe(''); - expect(strings.ltrim('', '/')).toBe(''); - }); - - test('rtrim', () => { - expect(strings.rtrim('foo', 'o')).toBe('f'); - expect(strings.rtrim('foo', 'f')).toBe('foo'); - expect(strings.rtrim('http://www.test.de', '.de')).toBe('http://www.test'); - expect(strings.rtrim('/foo/', '/')).toBe('/foo'); - expect(strings.rtrim('/foo//', '/')).toBe('/foo'); - expect(strings.rtrim('/', '')).toBe('/'); - expect(strings.rtrim('/', '/')).toBe(''); - expect(strings.rtrim('///', '/')).toBe(''); - expect(strings.rtrim('', '')).toBe(''); - expect(strings.rtrim('', '/')).toBe(''); - }); - - test('trim', () => { - expect(strings.trim(' foo ')).toBe('foo'); - expect(strings.trim(' foo')).toBe('foo'); - expect(strings.trim('bar ')).toBe('bar'); - expect(strings.trim(' ')).toBe(''); - expect(strings.trim('foo bar', 'bar')).toBe('foo '); - }); - - test('multiRightTrim', () => { - expect(strings.multiRightTrim(' foo ,', [','])).toBe(' foo '); - expect(strings.multiRightTrim('foo;,', [',', ';'])).toBe('foo'); - expect(strings.multiRightTrim('/path/to/a.java;', [';'])).toBe('/path/to/a.java'); - expect(strings.multiRightTrim('/path/to/a.ts,', [','])).toBe('/path/to/a.ts'); - }); - - test('trimWhitespace', () => { - expect(' foo '.trim()).toBe('foo'); - expect(' foo '.trim()).toBe('foo'); - expect(' foo'.trim()).toBe('foo'); - expect('bar '.trim()).toBe('bar'); - expect(' '.trim()).toBe(''); - expect(' '.trim()).toBe(''); - }); - - test('repeat', () => { - expect(strings.repeat(' ', 4)).toBe(' '); - expect(strings.repeat(' ', 1)).toBe(' '); - expect(strings.repeat(' ', 0)).toBe(''); - expect(strings.repeat('abc', 2)).toBe('abcabc'); - }); - - test('lastNonWhitespaceIndex', () => { - expect(strings.lastNonWhitespaceIndex('abc \t \t ')).toBe(2); - expect(strings.lastNonWhitespaceIndex('abc')).toBe(2); - expect(strings.lastNonWhitespaceIndex('abc\t')).toBe(2); - expect(strings.lastNonWhitespaceIndex('abc ')).toBe(2); - expect(strings.lastNonWhitespaceIndex('abc \t \t ')).toBe(2); - expect(strings.lastNonWhitespaceIndex('abc \t \t abc \t \t ')).toBe(11); - expect(strings.lastNonWhitespaceIndex('abc \t \t abc \t \t ', 8)).toBe(2); - expect(strings.lastNonWhitespaceIndex(' \t \t ')).toBe(-1); - }); - - test('containsRTL', () => { - expect(strings.containsRTL('a')).toEqual(false); - expect(strings.containsRTL('')).toEqual(false); - expect(strings.containsRTL(strings.UTF8_BOM_CHARACTER + 'a')).toEqual(false); - expect(strings.containsRTL('hello world!')).toEqual(false); - expect(strings.containsRTL('a📚📚b')).toEqual(false); - expect(strings.containsRTL('هناك حقيقة مثبتة منذ زمن طويل')).toEqual(true); - expect(strings.containsRTL('זוהי עובדה מבוססת שדעתו')).toEqual(true); - }); - - test('containsEmoji', () => { - expect(strings.containsEmoji('a')).toEqual(false); - expect(strings.containsEmoji('')).toEqual(false); - expect(strings.containsEmoji(strings.UTF8_BOM_CHARACTER + 'a')).toEqual(false); - expect(strings.containsEmoji('hello world!')).toEqual(false); - expect(strings.containsEmoji('هناك حقيقة مثبتة منذ زمن طويل')).toEqual(false); - expect(strings.containsEmoji('זוהי עובדה מבוססת שדעתו')).toEqual(false); - - expect(strings.containsEmoji('a📚📚b')).toEqual(true); - expect(strings.containsEmoji('1F600 # 😀 grinning face')).toEqual(true); - expect(strings.containsEmoji('1F47E # 👾 alien monster')).toEqual(true); - expect(strings.containsEmoji('1F467 1F3FD # 👧🏽 girl: medium skin tone')).toEqual(true); - expect(strings.containsEmoji('26EA # ⛪ church')).toEqual(true); - expect(strings.containsEmoji('231B # ⌛ hourglass')).toEqual(true); - expect(strings.containsEmoji('2702 # ✂ scissors')).toEqual(true); - expect(strings.containsEmoji('1F1F7 1F1F4 # 🇷🇴 Romania')).toEqual(true); - }); - - test('isBasicASCII', () => { - function assertIsBasicASCII(str: string, expected: boolean): void { - expect(strings.isBasicASCII(str)).toEqual(expected); - } - assertIsBasicASCII('abcdefghijklmnopqrstuvwxyz', true); - assertIsBasicASCII('ABCDEFGHIJKLMNOPQRSTUVWXYZ', true); - assertIsBasicASCII('1234567890', true); - assertIsBasicASCII('`~!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?', true); - assertIsBasicASCII(' ', true); - assertIsBasicASCII('\t', true); - assertIsBasicASCII('\n', true); - assertIsBasicASCII('\r', true); - - let ALL = '\r\t\n'; - for (let i = 32; i < 127; i++) { - ALL += String.fromCharCode(i); - } - assertIsBasicASCII(ALL, true); - - assertIsBasicASCII(String.fromCharCode(31), false); - assertIsBasicASCII(String.fromCharCode(127), false); - assertIsBasicASCII('ü', false); - assertIsBasicASCII('a📚📚b', false); - }); - - test('createRegExp', () => { - // Empty - expect(() => strings.createRegExp('', false)).toThrow(); - - // Escapes appropriately - expect(strings.createRegExp('abc', false).source).toEqual('abc'); - expect(strings.createRegExp('([^ ,.]*)', false).source).toEqual('\\(\\[\\^ ,\\.\\]\\*\\)'); - expect(strings.createRegExp('([^ ,.]*)', true).source).toEqual('([^ ,.]*)'); - - // Whole word - expect(strings.createRegExp('abc', false, { wholeWord: true }).source).toEqual('\\babc\\b'); - expect(strings.createRegExp('abc', true, { wholeWord: true }).source).toEqual('\\babc\\b'); - expect(strings.createRegExp(' abc', true, { wholeWord: true }).source).toEqual(' abc\\b'); - expect(strings.createRegExp('abc ', true, { wholeWord: true }).source).toEqual('\\babc '); - expect(strings.createRegExp(' abc ', true, { wholeWord: true }).source).toEqual(' abc '); - - const regExpWithoutFlags = strings.createRegExp('abc', true); - expect(!regExpWithoutFlags.global).toBeTruthy(); - expect(regExpWithoutFlags.ignoreCase).toBeTruthy(); - expect(!regExpWithoutFlags.multiline).toBeTruthy(); - - const regExpWithFlags = strings.createRegExp('abc', true, { global: true, matchCase: true, multiline: true }); - expect(regExpWithFlags.global).toBeTruthy(); - expect(!regExpWithFlags.ignoreCase).toBeTruthy(); - expect(regExpWithFlags.multiline).toBeTruthy(); - }); - - test('regExpContainsBackreference', () => { - expect(strings.regExpContainsBackreference('foo \\5 bar')).toBeTruthy(); - expect(strings.regExpContainsBackreference('\\2')).toBeTruthy(); - expect(strings.regExpContainsBackreference('(\\d)(\\n)(\\1)')).toBeTruthy(); - expect(strings.regExpContainsBackreference('(A).*?\\1')).toBeTruthy(); - expect(strings.regExpContainsBackreference('\\\\\\1')).toBeTruthy(); - expect(strings.regExpContainsBackreference('foo \\\\\\1')).toBeTruthy(); - - expect(!strings.regExpContainsBackreference('')).toBeTruthy(); - expect(!strings.regExpContainsBackreference('\\\\1')).toBeTruthy(); - expect(!strings.regExpContainsBackreference('foo \\\\1')).toBeTruthy(); - expect(!strings.regExpContainsBackreference('(A).*?\\\\1')).toBeTruthy(); - expect(!strings.regExpContainsBackreference('foo \\d1 bar')).toBeTruthy(); - expect(!strings.regExpContainsBackreference('123')).toBeTruthy(); - }); - - test('getLeadingWhitespace', () => { - expect(strings.getLeadingWhitespace(' foo')).toEqual(' '); - expect(strings.getLeadingWhitespace(' foo', 2)).toEqual(''); - expect(strings.getLeadingWhitespace(' foo', 1, 1)).toEqual(''); - expect(strings.getLeadingWhitespace(' foo', 0, 1)).toEqual(' '); - expect(strings.getLeadingWhitespace(' ')).toEqual(' '); - expect(strings.getLeadingWhitespace(' ', 1)).toEqual(' '); - expect(strings.getLeadingWhitespace(' ', 0, 1)).toEqual(' '); - expect(strings.getLeadingWhitespace('\t\tfunction foo(){', 0, 1)).toEqual('\t'); - expect(strings.getLeadingWhitespace('\t\tfunction foo(){', 0, 2)).toEqual('\t\t'); - }); - - test('fuzzyContains', () => { - expect(!strings.fuzzyContains(undefined!, null!)).toBeTruthy(); - expect(!strings.fuzzyContains('', '')).toBeTruthy(); - expect(strings.fuzzyContains('hello world', 'h')).toBeTruthy(); - expect(!strings.fuzzyContains('hello world', 'q')).toBeTruthy(); - expect(strings.fuzzyContains('hello world', 'hw')).toBeTruthy(); - expect(strings.fuzzyContains('hello world', 'horl')).toBeTruthy(); - expect(strings.fuzzyContains('hello world', 'd')).toBeTruthy(); - expect(!strings.fuzzyContains('hello world', 'wh')).toBeTruthy(); - expect(!strings.fuzzyContains('d', 'dd')).toBeTruthy(); - }); - - test('startsWithUTF8BOM', () => { - expect(strings.startsWithUTF8BOM(strings.UTF8_BOM_CHARACTER)).toBeTruthy(); - expect(strings.startsWithUTF8BOM(strings.UTF8_BOM_CHARACTER + 'a')).toBeTruthy(); - expect(strings.startsWithUTF8BOM(strings.UTF8_BOM_CHARACTER + 'aaaaaaaaaa')).toBeTruthy(); - expect(!strings.startsWithUTF8BOM(' ' + strings.UTF8_BOM_CHARACTER)).toBeTruthy(); - expect(!strings.startsWithUTF8BOM('foo')).toBeTruthy(); - expect(!strings.startsWithUTF8BOM('')).toBeTruthy(); - }); - - test('stripUTF8BOM', () => { - expect(strings.stripUTF8BOM(strings.UTF8_BOM_CHARACTER)).toEqual(''); - expect(strings.stripUTF8BOM(strings.UTF8_BOM_CHARACTER + 'foobar')).toEqual('foobar'); - expect(strings.stripUTF8BOM('foobar' + strings.UTF8_BOM_CHARACTER)).toEqual('foobar' + strings.UTF8_BOM_CHARACTER); - expect(strings.stripUTF8BOM('abc')).toEqual('abc'); - expect(strings.stripUTF8BOM('')).toEqual(''); - }); - - test('containsUppercaseCharacter', () => { - [ - [null, false], - ['', false], - ['foo', false], - ['föö', false], - ['ناك', false], - ['מבוססת', false], - ['😀', false], - ['(#@()*&%()@*#&09827340982374}{:">?> { - expect(strings.containsUppercaseCharacter(str as string)).toEqual(result); - }); - }); - - test('containsUppercaseCharacter (ignoreEscapedChars)', () => { - [ - ['\\Woo', false], - ['f\\S\\S', false], - ['foo', false], - - ['Foo', true], - ].forEach(([str, result]) => { - expect(strings.containsUppercaseCharacter(str as string, true)).toEqual(result); - }); - }); - - test('uppercaseFirstLetter', () => { - [ - ['', ''], - ['foo', 'Foo'], - ['f', 'F'], - ['123', '123'], - ['.a', '.a'], - ].forEach(([inStr, result]) => { - expect(strings.uppercaseFirstLetter(inStr)).toEqual(result); - }); - }); - - test('getNLines', () => { - expect(strings.getNLines('', 5)).toEqual(''); - expect(strings.getNLines('foo', 5)).toEqual('foo'); - expect(strings.getNLines('foo\nbar', 5)).toEqual('foo\nbar'); - expect(strings.getNLines('foo\nbar', 2)).toEqual('foo\nbar'); - - expect(strings.getNLines('foo\nbar', 1)).toEqual('foo'); - expect(strings.getNLines('foo\nbar')).toEqual('foo'); - expect(strings.getNLines('foo\nbar\nsomething', 2)).toEqual('foo\nbar'); - expect(strings.getNLines('foo', 0)).toEqual(''); - }); - - test('removeAccents', () => { - expect(strings.removeAccents('joào')).toEqual('joao'); - expect(strings.removeAccents('joáo')).toEqual('joao'); - expect(strings.removeAccents('joâo')).toEqual('joao'); - expect(strings.removeAccents('joäo')).toEqual('joao'); - // assert.equal(strings.removeAccents('joæo'), 'joao'); // not an accent - expect(strings.removeAccents('joão')).toEqual('joao'); - expect(strings.removeAccents('joåo')).toEqual('joao'); - expect(strings.removeAccents('joåo')).toEqual('joao'); - expect(strings.removeAccents('joāo')).toEqual('joao'); - - expect(strings.removeAccents('fôo')).toEqual('foo'); - expect(strings.removeAccents('föo')).toEqual('foo'); - expect(strings.removeAccents('fòo')).toEqual('foo'); - expect(strings.removeAccents('fóo')).toEqual('foo'); - // assert.equal(strings.removeAccents('fœo'), 'foo'); - // assert.equal(strings.removeAccents('føo'), 'foo'); - expect(strings.removeAccents('fōo')).toEqual('foo'); - expect(strings.removeAccents('fõo')).toEqual('foo'); - - expect(strings.removeAccents('andrè')).toEqual('andre'); - expect(strings.removeAccents('andré')).toEqual('andre'); - expect(strings.removeAccents('andrê')).toEqual('andre'); - expect(strings.removeAccents('andrë')).toEqual('andre'); - expect(strings.removeAccents('andrē')).toEqual('andre'); - expect(strings.removeAccents('andrė')).toEqual('andre'); - expect(strings.removeAccents('andrę')).toEqual('andre'); - - expect(strings.removeAccents('hvîc')).toEqual('hvic'); - expect(strings.removeAccents('hvïc')).toEqual('hvic'); - expect(strings.removeAccents('hvíc')).toEqual('hvic'); - expect(strings.removeAccents('hvīc')).toEqual('hvic'); - expect(strings.removeAccents('hvįc')).toEqual('hvic'); - expect(strings.removeAccents('hvìc')).toEqual('hvic'); - - expect(strings.removeAccents('ûdo')).toEqual('udo'); - expect(strings.removeAccents('üdo')).toEqual('udo'); - expect(strings.removeAccents('ùdo')).toEqual('udo'); - expect(strings.removeAccents('údo')).toEqual('udo'); - expect(strings.removeAccents('ūdo')).toEqual('udo'); - - expect(strings.removeAccents('heÿ')).toEqual('hey'); - - // assert.equal(strings.removeAccents('gruß'), 'grus'); - expect(strings.removeAccents('gruś')).toEqual('grus'); - expect(strings.removeAccents('gruš')).toEqual('grus'); - - expect(strings.removeAccents('çool')).toEqual('cool'); - expect(strings.removeAccents('ćool')).toEqual('cool'); - expect(strings.removeAccents('čool')).toEqual('cool'); - - expect(strings.removeAccents('ñice')).toEqual('nice'); - expect(strings.removeAccents('ńice')).toEqual('nice'); - }); -}); diff --git a/packages/core-common/package.json b/packages/core-common/package.json index 61a7dd8acb..aa23030928 100644 --- a/packages/core-common/package.json +++ b/packages/core-common/package.json @@ -18,11 +18,8 @@ }, "dependencies": { "@opensumi/di": "^1.1.0", - "iconv-lite": "^0.6.0", - "jschardet": "3.0.0", - "shortid": "^2.2.14", - "strip-json-comments": "3.0.1", - "vscode-uri": "^3.0.2" + "@opensumi/ide-utils": "2.17.0", + "jschardet": "3.0.0" }, "devDependencies": { "@opensumi/ide-dev-tool": "^1.3.1" diff --git a/packages/core-common/src/arrays.ts b/packages/core-common/src/arrays.ts deleted file mode 100644 index 4df0b4f13e..0000000000 --- a/packages/core-common/src/arrays.ts +++ /dev/null @@ -1,628 +0,0 @@ -/* --------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -// Some code copied and modified from https://github.com/microsoft/vscode/blob/1.44.0/src/vs/base/common/arrays.ts - -import { CancellationToken } from './cancellation'; -import { canceled } from './errors'; -import { ISplice } from './sequence'; - -/** - * Returns the last element of an array. - * @param array The array. - * @param n Which element from the end (default is zero). - */ -export function tail(array: ArrayLike, n = 0): T { - return array[array.length - (1 + n)]; -} - -export function tail2(arr: T[]): [T[], T] { - if (arr.length === 0) { - throw new Error('Invalid tail call'); - } - - return [arr.slice(0, arr.length - 1), arr[arr.length - 1]]; -} - -export function equals( - one: ReadonlyArray | undefined, - other: ReadonlyArray | undefined, - itemEquals: (a: T, b: T) => boolean = (a, b) => a === b, -): boolean { - if (one === other) { - return true; - } - - if (!one || !other) { - return false; - } - - if (one.length !== other.length) { - return false; - } - - for (let i = 0, len = one.length; i < len; i++) { - if (!itemEquals(one[i], other[i])) { - return false; - } - } - - return true; -} - -export function binarySearch(array: ReadonlyArray, key: T, comparator: (op1: T, op2: T) => number): number { - let low = 0; - let high = array.length - 1; - - while (low <= high) { - const mid = ((low + high) / 2) | 0; - const comp = comparator(array[mid], key); - if (comp < 0) { - low = mid + 1; - } else if (comp > 0) { - high = mid - 1; - } else { - return mid; - } - } - return -(low + 1); -} - -/** - * Takes a sorted array and a function p. The array is sorted in such a way that all elements where p(x) is false - * are located before all elements where p(x) is true. - * @returns the least x for which p(x) is true or array.length if no element fullfills the given function. - */ -export function findFirstInSorted(array: ReadonlyArray, p: (x: T) => boolean): number { - let low = 0; - let high = array.length; - if (high === 0) { - return 0; // no children - } - while (low < high) { - const mid = Math.floor((low + high) / 2); - if (p(array[mid])) { - high = mid; - } else { - low = mid + 1; - } - } - return low; -} - -type Compare = (a: T, b: T) => number; - -/** - * Like `Array#sort` but always stable. Usually runs a little slower `than Array#sort` - * so only use this when actually needing stable sort. - */ -export function mergeSort(data: T[], compare: Compare): T[] { - _sort(data, compare, 0, data.length - 1, []); - return data; -} - -function _merge(a: T[], compare: Compare, lo: number, mid: number, hi: number, aux: T[]): void { - let leftIdx = lo; - let rightIdx = mid + 1; - for (let i = lo; i <= hi; i++) { - aux[i] = a[i]; - } - for (let i = lo; i <= hi; i++) { - if (leftIdx > mid) { - // left side consumed - a[i] = aux[rightIdx++]; - } else if (rightIdx > hi) { - // right side consumed - a[i] = aux[leftIdx++]; - } else if (compare(aux[rightIdx], aux[leftIdx]) < 0) { - // right element is less -> comes first - a[i] = aux[rightIdx++]; - } else { - // left element comes first (less or equal) - a[i] = aux[leftIdx++]; - } - } -} - -function _sort(a: T[], compare: Compare, lo: number, hi: number, aux: T[]) { - if (hi <= lo) { - return; - } - const mid = (lo + (hi - lo) / 2) | 0; - _sort(a, compare, lo, mid, aux); - _sort(a, compare, mid + 1, hi, aux); - if (compare(a[mid], a[mid + 1]) <= 0) { - // left and right are sorted and if the last-left element is less - // or equals than the first-right element there is nothing else - // to do - return; - } - _merge(a, compare, lo, mid, hi, aux); -} - -export function groupBy(data: ReadonlyArray, compare: (a: T, b: T) => number): T[][] { - const result: T[][] = []; - let currentGroup: T[] | undefined; - for (const element of mergeSort(data.slice(0), compare)) { - if (!currentGroup || compare(currentGroup[0], element) !== 0) { - currentGroup = [element]; - result.push(currentGroup); - } else { - currentGroup.push(element); - } - } - return result; -} - -interface IMutableSplice extends ISplice { - deleteCount: number; -} - -/** - * Diffs two *sorted* arrays and computes the splices which apply the diff. - */ -export function sortedDiff( - before: ReadonlyArray, - after: ReadonlyArray, - compare: (a: T, b: T) => number, -): ISplice[] { - const result: IMutableSplice[] = []; - - function pushSplice(start: number, deleteCount: number, toInsert: T[]): void { - if (deleteCount === 0 && toInsert.length === 0) { - return; - } - - const latest = result[result.length - 1]; - - if (latest && latest.start + latest.deleteCount === start) { - latest.deleteCount += deleteCount; - latest.toInsert.push(...toInsert); - } else { - result.push({ start, deleteCount, toInsert }); - } - } - - let beforeIdx = 0; - let afterIdx = 0; - - while (true) { - if (beforeIdx === before.length) { - pushSplice(beforeIdx, 0, after.slice(afterIdx)); - break; - } - if (afterIdx === after.length) { - pushSplice(beforeIdx, before.length - beforeIdx, []); - break; - } - - const beforeElement = before[beforeIdx]; - const afterElement = after[afterIdx]; - const n = compare(beforeElement, afterElement); - if (n === 0) { - // equal - beforeIdx += 1; - afterIdx += 1; - } else if (n < 0) { - // beforeElement is smaller -> before element removed - pushSplice(beforeIdx, 1, []); - beforeIdx += 1; - } else if (n > 0) { - // beforeElement is greater -> after element added - pushSplice(beforeIdx, 0, [afterElement]); - afterIdx += 1; - } - } - - return result; -} - -/** - * Takes two *sorted* arrays and computes their delta (removed, added elements). - * Finishes in `Math.min(before.length, after.length)` steps. - */ -export function delta( - before: ReadonlyArray, - after: ReadonlyArray, - compare: (a: T, b: T) => number, -): { removed: T[]; added: T[] } { - const splices = sortedDiff(before, after, compare); - const removed: T[] = []; - const added: T[] = []; - - for (const splice of splices) { - removed.push(...before.slice(splice.start, splice.start + splice.deleteCount)); - added.push(...splice.toInsert); - } - - return { removed, added }; -} - -/** - * Returns the top N elements from the array. - * - * Faster than sorting the entire array when the array is a lot larger than N. - * - * @param array The unsorted array. - * @param compare A sort function for the elements. - * @param n The number of elements to return. - * @return The first n elemnts from array when sorted with compare. - */ -export function top(array: ReadonlyArray, compare: (a: T, b: T) => number, n: number): T[] { - if (n === 0) { - return []; - } - const result = array.slice(0, n).sort(compare); - topStep(array, compare, result, n, array.length); - return result; -} - -/** - * Asynchronous variant of `top()` allowing for splitting up work in batches between which the event loop can run. - * - * Returns the top N elements from the array. - * - * Faster than sorting the entire array when the array is a lot larger than N. - * - * @param array The unsorted array. - * @param compare A sort function for the elements. - * @param n The number of elements to return. - * @param batch The number of elements to examine before yielding to the event loop. - * @return The first n elemnts from array when sorted with compare. - */ -export function topAsync( - array: T[], - compare: (a: T, b: T) => number, - n: number, - batch: number, - token?: CancellationToken, -): Promise { - if (n === 0) { - return Promise.resolve([]); - } - - return new Promise((resolve, reject) => { - (async () => { - const o = array.length; - const result = array.slice(0, n).sort(compare); - for (let i = n, m = Math.min(n + batch, o); i < o; i = m, m = Math.min(m + batch, o)) { - if (i > n) { - await new Promise((resolve) => setTimeout(resolve)); // nextTick() would starve I/O. - } - if (token && token.isCancellationRequested) { - throw canceled(); - } - topStep(array, compare, result, i, m); - } - return result; - })().then(resolve, reject); - }); -} - -function topStep(array: ReadonlyArray, compare: (a: T, b: T) => number, result: T[], i: number, m: number): void { - for (const n = result.length; i < m; i++) { - const element = array[i]; - if (compare(element, result[n - 1]) < 0) { - result.pop(); - const j = findFirstInSorted(result, (e) => compare(element, e) < 0); - result.splice(j, 0, element); - } - } -} - -/** - * @returns a new array with all falsy values removed. The original array IS NOT modified. - */ -export function coalesce(array: ReadonlyArray): T[] { - if (!array) { - return array; - } - return array.filter((e) => !!e) as T[]; -} - -/** - * Remove all falsey values from `array`. The original array IS modified. - */ -export function coalesceInPlace(array: Array): void { - if (!array) { - return; - } - let to = 0; - // eslint-disable-next-line @typescript-eslint/prefer-for-of - for (let i = 0; i < array.length; i++) { - if (array[i]) { - array[to] = array[i]; - to += 1; - } - } - array.length = to; -} - -/** - * Moves the element in the array for the provided positions. - */ -export function move(array: any[], from: number, to: number): void { - array.splice(to, 0, array.splice(from, 1)[0]); -} - -/** - * @returns false if the provided object is an array and not empty. - */ -export function isFalsyOrEmpty(obj: any): boolean { - return !Array.isArray(obj) || obj.length === 0; -} - -/** - * @returns True if the provided object is an array and has at least one element. - */ -export function isNonEmptyArray(obj: T[] | undefined | null): obj is T[]; -export function isNonEmptyArray(obj: readonly T[] | undefined | null): obj is readonly T[]; -export function isNonEmptyArray(obj: T[] | readonly T[] | undefined | null): obj is T[] | readonly T[] { - return Array.isArray(obj) && obj.length > 0; -} - -/** - * Removes duplicates from the given array. The optional keyFn allows to specify - * how elements are checked for equalness by returning a unique string for each. - */ -export function distinct(array: ReadonlyArray, keyFn?: (t: T) => string): T[] { - if (!keyFn) { - return array.filter((element, position) => array.indexOf(element) === position); - } - - const seen: { [key: string]: boolean } = Object.create(null); - return array.filter((elem) => { - const key = keyFn(elem); - if (seen[key]) { - return false; - } - - seen[key] = true; - - return true; - }); -} - -export function distinctES6(array: ReadonlyArray): T[] { - const seen = new Set(); - return array.filter((element) => { - if (seen.has(element)) { - return false; - } - - seen.add(element); - return true; - }); -} - -export function uniqueFilter(keyFn: (t: T) => string): (t: T) => boolean { - const seen: { [key: string]: boolean } = Object.create(null); - - return (element) => { - const key = keyFn(element); - - if (seen[key]) { - return false; - } - - seen[key] = true; - return true; - }; -} - -export function lastIndex(array: ReadonlyArray, fn: (item: T) => boolean): number { - for (let i = array.length - 1; i >= 0; i--) { - const element = array[i]; - - if (fn(element)) { - return i; - } - } - - return -1; -} - -export function firstIndex(array: ReadonlyArray, fn: (item: T) => boolean): number { - for (let i = 0; i < array.length; i++) { - const element = array[i]; - - if (fn(element)) { - return i; - } - } - - return -1; -} - -export function first(array: ReadonlyArray, fn: (item: T) => boolean, notFoundValue: T): T; -export function first(array: ReadonlyArray, fn: (item: T) => boolean): T | undefined; -export function first( - array: ReadonlyArray, - fn: (item: T) => boolean, - notFoundValue: T | undefined = undefined, -): T | undefined { - const index = firstIndex(array, fn); - return index < 0 ? notFoundValue : array[index]; -} - -export function commonPrefixLength( - one: ReadonlyArray, - other: ReadonlyArray, - equals: (a: T, b: T) => boolean = (a, b) => a === b, -): number { - let result = 0; - - for (let i = 0, len = Math.min(one.length, other.length); i < len && equals(one[i], other[i]); i++) { - result++; - } - - return result; -} - -export function flatten(arr: T[][]): T[] { - return ([] as T[]).concat(...arr); -} - -export function range(to: number): number[]; -export function range(arg: number, to?: number): number[] { - let from = typeof to === 'number' ? arg : 0; - - if (typeof to === 'number') { - from = arg; - } else { - from = 0; - to = arg; - } - - const result: number[] = []; - - if (from <= to) { - for (let i = from; i < to; i++) { - result.push(i); - } - } else { - for (let i = from; i > to; i--) { - result.push(i); - } - } - - return result; -} - -export function fill(num: number, value: T, arr: T[] = []): T[] { - for (let i = 0; i < num; i++) { - arr[i] = value; - } - - return arr; -} - -export function index(array: ReadonlyArray, indexer: (t: T) => string): { [key: string]: T }; -export function index( - array: ReadonlyArray, - indexer: (t: T) => string, - merger?: (t: T, r: R) => R, -): { [key: string]: R }; -export function index( - array: ReadonlyArray, - indexer: (t: T) => string, - merger: (t: T, r: R) => R = (t) => t as any, -): { [key: string]: R } { - return array.reduce((r, t) => { - const key = indexer(t); - r[key] = merger(t, r[key]); - return r; - }, Object.create(null)); -} - -/** - * Inserts an element into an array. Returns a function which, when - * called, will remove that element from the array. - */ -export function insert(array: T[], element: T): () => void { - array.push(element); - - return () => { - const index = array.indexOf(element); - if (index > -1) { - array.splice(index, 1); - } - }; -} - -/** - * Insert `insertArr` inside `target` at `insertIndex`. - * Please don't touch unless you understand https://jsperf.com/inserting-an-array-within-an-array - */ -export function arrayInsert(target: T[], insertIndex: number, insertArr: T[]): T[] { - const before = target.slice(0, insertIndex); - const after = target.slice(insertIndex); - return before.concat(insertArr, after); -} - -/** - * Uses Fisher-Yates shuffle to shuffle the given array - */ -export function shuffle(array: T[], _seed?: number): void { - let rand: () => number; - - if (typeof _seed === 'number') { - let seed = _seed; - // Seeded random number generator in JS. Modified from: - // https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript - rand = () => { - const x = Math.sin(seed++) * 179426549; // throw away most significant digits and reduce any potential bias - return x - Math.floor(x); - }; - } else { - rand = Math.random; - } - - for (let i = array.length - 1; i > 0; i -= 1) { - const j = Math.floor(rand() * (i + 1)); - const temp = array[i]; - array[i] = array[j]; - array[j] = temp; - } -} - -/** - * Pushes an element to the start of the array, if found. - */ -export function pushToStart(arr: T[], value: T): void { - const index = arr.indexOf(value); - - if (index > -1) { - arr.splice(index, 1); - arr.unshift(value); - } -} - -/** - * Pushes an element to the end of the array, if found. - */ -export function pushToEnd(arr: T[], value: T): void { - const index = arr.indexOf(value); - - if (index > -1) { - arr.splice(index, 1); - arr.push(value); - } -} - -export function find( - arr: ArrayLike, - predicate: (value: T, index: number, arr: ArrayLike) => any, -): T | undefined { - for (let i = 0; i < arr.length; i++) { - const element = arr[i]; - if (predicate(element, i, arr)) { - return element; - } - } - - return undefined; -} - -export function mapArrayOrNot(items: T | T[], fn: (_: T) => U): U | U[] { - return Array.isArray(items) ? items.map(fn) : fn(items); -} - -export function asArray(x: T | T[]): T[] { - return Array.isArray(x) ? x : [x]; -} - -/** - * Returns the first mapped value of the array which is not undefined. - */ -export function mapFind(array: Iterable, mapFn: (value: T) => R | undefined): R | undefined { - for (const value of array) { - const mapped = mapFn(value); - if (mapped !== undefined) { - return mapped; - } - } - - return undefined; -} diff --git a/packages/core-common/src/command.ts b/packages/core-common/src/command.ts index e427c7a52d..d3a4ca70a4 100644 --- a/packages/core-common/src/command.ts +++ b/packages/core-common/src/command.ts @@ -1,8 +1,7 @@ import { Autowired, Injectable } from '@opensumi/di'; +import { Disposable, IDisposable, MaybePromise } from '@opensumi/ide-utils'; -import { MaybePromise } from './async'; import { ContributionProvider } from './contribution-provider'; -import { Disposable, IDisposable } from './disposable'; import { replaceLocalizePlaceholder } from './localize'; import { getDebugLogger } from './log'; import { IExtensionInfo } from './types'; diff --git a/packages/core-common/src/utils/comparers.ts b/packages/core-common/src/comparers.ts similarity index 97% rename from packages/core-common/src/utils/comparers.ts rename to packages/core-common/src/comparers.ts index 7878da8ee1..0c2b34820e 100644 --- a/packages/core-common/src/utils/comparers.ts +++ b/packages/core-common/src/comparers.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Some code copied and modified from https://github.com/microsoft/vscode/blob/1.44.0/src/vs/base/common/comparers.ts -import { IRange } from '..'; -import { IdleValue } from '../async'; -import { sep } from '../path'; +import { path, IdleValue } from '@opensumi/ide-utils'; +import { IRange } from './types'; +const { sep } = path; const intlFileNameCollator: IdleValue<{ collator: Intl.Collator; collatorIsNumeric: boolean }> = new IdleValue(() => { const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }); return { diff --git a/packages/core-common/src/const/index.ts b/packages/core-common/src/const/index.ts index c4fc5b0297..2b2fe9a83d 100644 --- a/packages/core-common/src/const/index.ts +++ b/packages/core-common/src/const/index.ts @@ -1 +1 @@ -export * from './encodings'; +export * from './application'; diff --git a/packages/core-common/src/electron.ts b/packages/core-common/src/electron.ts index 64b4078985..624c442afa 100644 --- a/packages/core-common/src/electron.ts +++ b/packages/core-common/src/electron.ts @@ -1,6 +1,7 @@ import Electron from 'electron'; -import { IDisposable } from './disposable'; +import { IDisposable } from '@opensumi/ide-utils'; + import { ExtensionCandidate } from './types'; export interface IElectronMainApi { diff --git a/packages/core-common/src/event-bus/event-bus-types.ts b/packages/core-common/src/event-bus/event-bus-types.ts index 691966e9af..69a7e2679d 100644 --- a/packages/core-common/src/event-bus/event-bus-types.ts +++ b/packages/core-common/src/event-bus/event-bus-types.ts @@ -1,6 +1,6 @@ +import { IAsyncResult, IDisposable } from '@opensumi/ide-utils'; + import { ConstructorOf } from '../declare'; -import { IDisposable } from '../disposable'; -import { IAsyncResult } from '../event'; export interface IEventFireOpts { nextTick?: boolean; diff --git a/packages/core-common/src/event-bus/event-bus.ts b/packages/core-common/src/event-bus/event-bus.ts index 2371cadbf0..39bc8462f3 100644 --- a/packages/core-common/src/event-bus/event-bus.ts +++ b/packages/core-common/src/event-bus/event-bus.ts @@ -1,12 +1,11 @@ import { Injectable } from '@opensumi/di'; +import { Emitter, IAsyncResult, Event } from '@opensumi/ide-utils'; import { ConstructorOf } from '../declare'; -import { Emitter, IAsyncResult, Event } from '../event'; import { BasicEvent } from './basic-event'; import { IEventBus, IEventListener, IEventFireOpts, IAsyncEventFireOpts } from './event-bus-types'; - @Injectable() export class EventBusImpl implements IEventBus { private emitterMap = new Map>(); diff --git a/packages/core-common/src/event-bus/event-decorator.ts b/packages/core-common/src/event-bus/event-decorator.ts index 28e159820e..0519eb8535 100644 --- a/packages/core-common/src/event-bus/event-decorator.ts +++ b/packages/core-common/src/event-bus/event-decorator.ts @@ -1,7 +1,7 @@ import { Autowired } from '@opensumi/di'; +import { Disposable } from '@opensumi/ide-utils'; import { ConstructorOf } from '../declare'; -import { Disposable } from '../disposable'; import { BasicEvent } from './basic-event'; import { IEventBus } from './event-bus-types'; diff --git a/packages/core-common/src/hash-calculate/hash-calculate.ts b/packages/core-common/src/hash-calculate/hash-calculate.ts index a386dbbfaf..ca41b3617a 100644 --- a/packages/core-common/src/hash-calculate/hash-calculate.ts +++ b/packages/core-common/src/hash-calculate/hash-calculate.ts @@ -1,6 +1,5 @@ import { Injectable } from '@opensumi/di'; - -import { memoize } from '../utils'; +import { memoize } from '@opensumi/ide-utils'; import { lockedCreate } from './lockedCreate'; import wasmJson from './md5.wasm.json'; diff --git a/packages/core-common/src/index.ts b/packages/core-common/src/index.ts index d4a7041cb8..5b4f9e3cac 100644 --- a/packages/core-common/src/index.ts +++ b/packages/core-common/src/index.ts @@ -2,46 +2,32 @@ export * from './di-helper'; export * from './event-bus'; export * from './contribution-provider'; export * from './declare'; -export * from './disposable'; export * from './reference'; export * from './module'; -export * from './uri'; -export * from './event'; export * from './command'; export * from './menu'; export * from './localize'; -export * from './async'; -export * from './utils'; -export * from './uuid'; export * from './types'; export * from './application-props'; export * from './application-error'; -export * from './cancellation'; -export * from './functional'; export * from './preferences'; -export * from './charCode'; export * from './storage'; export * from './network'; -export * from './date'; export * from './log'; export * from './json-schema'; export * from './reporter'; export * from './connection'; -export * from './storage'; +export * from './comparers'; export * from './range'; -export * from './progress'; export * from './problem-pattern'; export * from './problem-matcher'; export * from './task-definition'; -export * from './errors'; export * from './node/port'; export * from './line-text'; -export * from './filters'; -export * from './character-classifier'; -export * from './cache'; export * from './keyboard'; export * from './theme'; export * from './env'; export * from './credential'; export * from './crypto'; -export * from './iterator'; +export * from './markdown'; +export * from '@opensumi/ide-utils'; diff --git a/packages/core-common/src/keyboard/keyboard-layout-provider.ts b/packages/core-common/src/keyboard/keyboard-layout-provider.ts index 6951c01ab4..2753bfcde3 100644 --- a/packages/core-common/src/keyboard/keyboard-layout-provider.ts +++ b/packages/core-common/src/keyboard/keyboard-layout-provider.ts @@ -15,7 +15,7 @@ ********************************************************************************/ // Some code copied and modified from https://github.com/eclipse-theia/theia/tree/v1.14.0/packages/core/src/browser/keyboard/browser-keyboard-layout-provider.ts -import { Event } from '../event'; +import { Event } from '@opensumi/ide-utils'; import { KeymapInfo } from './keymap'; diff --git a/packages/core-common/src/keyboard/keymap.ts b/packages/core-common/src/keyboard/keymap.ts index ce5f44b5f9..75b0cd3a97 100644 --- a/packages/core-common/src/keyboard/keymap.ts +++ b/packages/core-common/src/keyboard/keymap.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { isLinux, isWindows } from '../utils/os'; +import { isLinux, isWindows } from '@opensumi/ide-utils'; // https://github.com/microsoft/node-native-keymap/blob/master/index.d.ts diff --git a/packages/core-common/src/localize.ts b/packages/core-common/src/localize.ts index 1afbf54f97..09a70d58b6 100644 --- a/packages/core-common/src/localize.ts +++ b/packages/core-common/src/localize.ts @@ -1,5 +1,6 @@ -import { CaseInsensitiveMap } from './map'; -import { format, mnemonicButtonLabel } from './utils/strings'; +import { strings, CaseInsensitiveMap } from '@opensumi/ide-utils'; + +const { format, mnemonicButtonLabel } = strings; export type ILocalizationKey = string; // ts不支持symbol作为key diff --git a/packages/core-common/src/log.ts b/packages/core-common/src/log.ts index 1cf2d23ad0..39c1841d17 100644 --- a/packages/core-common/src/log.ts +++ b/packages/core-common/src/log.ts @@ -1,5 +1,5 @@ /* eslint-disable no-console */ -import { Event } from './event'; +import { Event } from '@opensumi/ide-utils'; export enum LogLevel { Verbose, diff --git a/packages/core-common/src/utils/markdown.ts b/packages/core-common/src/markdown.ts similarity index 74% rename from packages/core-common/src/utils/markdown.ts rename to packages/core-common/src/markdown.ts index 2928857d7f..8e404ed953 100644 --- a/packages/core-common/src/utils/markdown.ts +++ b/packages/core-common/src/markdown.ts @@ -1,4 +1,4 @@ -import { IMarkdownString } from '../types/markdown'; +import { IMarkdownString } from './types/markdown'; export function toMarkdownString(str: string, opts?: Omit): IMarkdownString { return { diff --git a/packages/core-common/src/menu.ts b/packages/core-common/src/menu.ts index 0fad988e90..bab0485dff 100644 --- a/packages/core-common/src/menu.ts +++ b/packages/core-common/src/menu.ts @@ -1,4 +1,5 @@ -import { IDisposable } from './disposable'; +import { IDisposable } from '@opensumi/ide-utils'; + import { IElectronMainApi } from './electron'; export interface INativeMenuTemplate { diff --git a/packages/core-common/src/problem-matcher.ts b/packages/core-common/src/problem-matcher.ts index 660a9bf376..0f8b0d02be 100644 --- a/packages/core-common/src/problem-matcher.ts +++ b/packages/core-common/src/problem-matcher.ts @@ -16,9 +16,8 @@ // Some code copied and modified from https://github.com/eclipse-theia/theia/tree/v1.14.0/packages/task/src/browser/task-problem-matcher-registry.ts import { Injectable, Autowired } from '@opensumi/di'; +import { URI, Emitter, DisposableCollection, Disposable, IDisposable } from '@opensumi/ide-utils'; -import { DisposableCollection, Disposable, IDisposable } from './disposable'; -import { Emitter } from './event'; import { IProblemPatternRegistry, ApplyToKind, @@ -28,7 +27,6 @@ import { ProblemPattern, WatchingPattern, } from './problem-pattern'; -import { URI } from './uri'; export interface WatchingMatcherContribution { // If set to true the background monitor is in active mode when the task starts. diff --git a/packages/core-common/src/problem-pattern.ts b/packages/core-common/src/problem-pattern.ts index 6c76e4c23e..c93c163605 100644 --- a/packages/core-common/src/problem-pattern.ts +++ b/packages/core-common/src/problem-pattern.ts @@ -18,11 +18,9 @@ import { Diagnostic } from 'vscode'; import { Injectable } from '@opensumi/di'; +import { isArray, isString, IDisposable, Disposable, DisposableCollection, URI } from '@opensumi/ide-utils'; -import { IDisposable, Disposable, DisposableCollection } from './disposable'; import { ProblemMatcher } from './problem-matcher'; -import { URI } from './uri'; -import { isArray, isString } from './utils/types'; export enum ApplyToKind { allDocuments, diff --git a/packages/core-common/src/reference.ts b/packages/core-common/src/reference.ts index 990dea8062..4fc58a3814 100644 --- a/packages/core-common/src/reference.ts +++ b/packages/core-common/src/reference.ts @@ -1,6 +1,4 @@ -import { MaybePromise } from './async'; -import { Disposable } from './disposable'; -import { Emitter, Event } from './event'; +import { Emitter, Event, Disposable, MaybePromise } from '@opensumi/ide-utils'; export interface IRef { instance: T; diff --git a/packages/core-common/src/reporter.ts b/packages/core-common/src/reporter.ts index ff20afe52f..17d9ebb3b6 100644 --- a/packages/core-common/src/reporter.ts +++ b/packages/core-common/src/reporter.ts @@ -1,6 +1,6 @@ import { Injectable, Inject } from '@opensumi/di'; +import { IDisposable } from '@opensumi/ide-utils'; -import { IDisposable } from './disposable'; import { getDebugLogger } from './log'; import { IReporterService, diff --git a/packages/core-common/src/storage.ts b/packages/core-common/src/storage.ts index 4dd71225d9..cc2d6124da 100644 --- a/packages/core-common/src/storage.ts +++ b/packages/core-common/src/storage.ts @@ -1,10 +1,7 @@ import { Injectable, Autowired } from '@opensumi/di'; +import { IDisposable, MaybePromise, Event, URI } from '@opensumi/ide-utils'; -import { MaybePromise } from './async'; import { ContributionProvider } from './contribution-provider'; -import { IDisposable } from './disposable'; -import { Event } from './event'; -import { URI } from './uri'; export const StorageProvider = Symbol('StorageProvider'); export type StorageProvider = (storageId: URI) => Promise; diff --git a/packages/core-common/src/task-definition.ts b/packages/core-common/src/task-definition.ts index cb14811896..b3f84dc7f6 100644 --- a/packages/core-common/src/task-definition.ts +++ b/packages/core-common/src/task-definition.ts @@ -1,10 +1,11 @@ import { Injectable } from '@opensumi/di'; +import { objects, IDisposable, Disposable } from '@opensumi/ide-utils'; -import { IDisposable, Disposable } from './disposable'; import { IJSONSchemaMap, IJSONSchema } from './json-schema'; import { formatLocalize } from './localize'; import { IStringDictionary } from './types/string'; -import { deepClone } from './utils/objects'; + +const { deepClone } = objects; interface TaskDefinition { extensionId: string; diff --git a/packages/core-common/src/types/application.ts b/packages/core-common/src/types/application.ts index 7a276ad509..998420b5e4 100644 --- a/packages/core-common/src/types/application.ts +++ b/packages/core-common/src/types/application.ts @@ -1,14 +1,14 @@ -import { OS } from '../utils'; +import { OperatingSystem } from '@opensumi/ide-utils'; export const IApplicationService = Symbol('IApplicationService'); export interface IApplicationService { /** 前端 OS */ - frontendOS: OS.Type; + frontendOS: OperatingSystem; /** 后端 OS */ - backendOS: OS.Type; + backendOS: OperatingSystem; /** * 获取后端 OS */ - getBackendOS(): Promise; + getBackendOS(): Promise; } diff --git a/packages/core-common/src/types/authentication.ts b/packages/core-common/src/types/authentication.ts index 59075d16d3..7ba8ff4b46 100644 --- a/packages/core-common/src/types/authentication.ts +++ b/packages/core-common/src/types/authentication.ts @@ -1,5 +1,4 @@ -import { IDisposable } from '../disposable'; -import { Event } from '../event'; +import { IDisposable, Event } from '@opensumi/ide-utils'; export const noAccountsId = 'authentication.noAccounts'; diff --git a/packages/core-common/src/types/common.ts b/packages/core-common/src/types/common.ts index adf09660b9..9b9a89a12a 100644 --- a/packages/core-common/src/types/common.ts +++ b/packages/core-common/src/types/common.ts @@ -1,4 +1,4 @@ -import { OS } from '../utils'; +import { OperatingSystem } from '@opensumi/ide-utils'; export const CommonServerPath = 'CommonServerPath'; @@ -8,5 +8,5 @@ export interface ICommonServer { /** * 获取后端 OS */ - getBackendOS(): Promise; + getBackendOS(): Promise; } diff --git a/packages/core-common/src/types/extension.ts b/packages/core-common/src/types/extension.ts index 6ad998c577..0cb30cca95 100644 --- a/packages/core-common/src/types/extension.ts +++ b/packages/core-common/src/types/extension.ts @@ -1,5 +1,6 @@ +import { Uri } from '@opensumi/ide-utils'; + import { BasicEvent } from '../event-bus'; -import { Uri } from '../uri'; export class ExtensionCandidate { path: string; diff --git a/packages/core-common/src/types/file-watch.ts b/packages/core-common/src/types/file-watch.ts index d831427c7b..c526422206 100644 --- a/packages/core-common/src/types/file-watch.ts +++ b/packages/core-common/src/types/file-watch.ts @@ -1,4 +1,4 @@ -import { URI } from '../'; +import { URI } from '@opensumi/ide-utils'; export interface FileSystemWatcherServer { /** * 根据给定参数启动文件监听 diff --git a/packages/core-common/src/types/file.ts b/packages/core-common/src/types/file.ts index d747f541eb..940b71fc76 100644 --- a/packages/core-common/src/types/file.ts +++ b/packages/core-common/src/types/file.ts @@ -1,4 +1,4 @@ -import { Event, Uri } from '..'; +import { Event, Uri } from '@opensumi/ide-utils'; import { FileChangeEvent } from './file-watch'; diff --git a/packages/core-common/src/types/index.ts b/packages/core-common/src/types/index.ts index acb164d62f..6ad84ebe27 100644 --- a/packages/core-common/src/types/index.ts +++ b/packages/core-common/src/types/index.ts @@ -12,3 +12,4 @@ export * from './authentication'; export * from './accessibility'; export * from './statusbar'; export * from './markdown'; +export * from './editor'; diff --git a/packages/core-common/src/types/markdown.ts b/packages/core-common/src/types/markdown.ts index 54a25e7cd8..734681371a 100644 --- a/packages/core-common/src/types/markdown.ts +++ b/packages/core-common/src/types/markdown.ts @@ -1,4 +1,4 @@ -import { UriComponents } from '../uri'; +import { UriComponents } from '@opensumi/ide-utils'; export interface IMarkdownString { value: string; diff --git a/packages/core-common/src/types/markers/markers-manager.ts b/packages/core-common/src/types/markers/markers-manager.ts index 391f1c8aaf..6b39b08daf 100644 --- a/packages/core-common/src/types/markers/markers-manager.ts +++ b/packages/core-common/src/types/markers/markers-manager.ts @@ -1,11 +1,13 @@ import { Injectable } from '@opensumi/di'; +import { Emitter, Event, IDisposable, arrays } from '@opensumi/ide-utils'; -import { isFalsyOrEmpty } from '../../arrays'; -import { IDisposable } from '../../disposable'; -import { Emitter, MapMap, Event, WithEventBus } from '../../index'; +import { WithEventBus } from '../../event-bus'; +import { MapMap } from './markers'; import { IMarker, IMarkerData, MarkerStatistics, MarkerSeverity } from './markers'; +const { isFalsyOrEmpty } = arrays; + export interface IBaseMarkerManager { /** * 更新markers diff --git a/packages/core-common/src/types/markers/markers.ts b/packages/core-common/src/types/markers/markers.ts index 66c4177ac3..d086897b19 100644 --- a/packages/core-common/src/types/markers/markers.ts +++ b/packages/core-common/src/types/markers/markers.ts @@ -1,4 +1,4 @@ -import { isEmptyObject } from '../../utils/types'; +import { isEmptyObject } from '@opensumi/ide-utils'; export interface MapMap { [key: string]: { [key: string]: V }; diff --git a/packages/core-common/src/utils/index.ts b/packages/core-common/src/utils/index.ts deleted file mode 100644 index 263b5d59d9..0000000000 --- a/packages/core-common/src/utils/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -export * from './promise-util'; -export * from './json'; -export * from './objects'; -export * from './arrays'; -export * from './strings'; -export * from './os'; -export * from './types'; -export * from './marshalling'; -export * from './comparers'; -export * from './decorators'; -export * from './file-uri'; -export * from './paths'; -export * from './ansi'; -export * from './markdown'; diff --git a/packages/core-common/src/utils/ipc.ts b/packages/core-common/src/utils/ipc.ts index 49bf1311a1..4f4b3032d7 100644 --- a/packages/core-common/src/utils/ipc.ts +++ b/packages/core-common/src/utils/ipc.ts @@ -3,8 +3,7 @@ import { join, dirname } from 'path'; import { ensureDirSync, ensureDir } from 'fs-extra'; -import { isWindows } from '../platform'; -import { uuid } from '../uuid'; +import { isWindows, uuid } from '@opensumi/ide-utils'; export function normalizedIpcHandlerPath(name: string, uuidSuffix = false, ipcPath = tmpdir()) { let handler: string; diff --git a/packages/core-common/src/utils/paths.ts b/packages/core-common/src/utils/paths.ts deleted file mode 100644 index 78e05d5a69..0000000000 --- a/packages/core-common/src/utils/paths.ts +++ /dev/null @@ -1,353 +0,0 @@ -/* --------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -// Some code copied and modified from https://github.com/Microsoft/vscode/blob/bf7ac9201e7a7d01741d4e6e64b5dc9f3197d97b/src/vs/base/common/paths.ts - -'use strict'; - -import { CharCode } from '../charCode'; -import { posix } from '../path'; -import { isWindows } from '../platform'; - -import { startsWithIgnoreCase } from './strings'; - -/** - * The forward slash path separator. - */ -export const sep = '/'; - -/** - * The native path separator depending on the OS. - */ -export const nativeSep = isWindows ? '\\' : '/'; - -const _posixBadPath = /(\/\.\.?\/)|(\/\.\.?)$|^(\.\.?\/)|(\/\/+)|(\\)/; -const _winBadPath = /(\\\.\.?\\)|(\\\.\.?)$|^(\.\.?\\)|(\\\\+)|(\/)/; - -/** - * Takes a Windows OS path and changes backward slashes to forward slashes. - * This should only be done for OS paths from Windows (or user provided paths potentially from Windows). - * Using it on a Linux or MaxOS path might change it. - */ -export function toSlashes(osPath: string) { - return osPath.replace(/[\\/]/g, posix.sep); -} - -function _isNormal(path: string, win: boolean): boolean { - return win ? !_winBadPath.test(path) : !_posixBadPath.test(path); -} - -/** - * @returns the base name of a path. - */ -export function basename(path: string): string { - const idx = ~path.lastIndexOf('/') || ~path.lastIndexOf('\\'); - if (idx === 0) { - return path; - } else if (~idx === path.length - 1) { - return basename(path.substring(0, path.length - 1)); - } else { - return path.substr(~idx + 1); - } -} - -/** - * @returns `.far` from `boo.far` or the empty string. - */ -export function extname(path: string): string { - path = basename(path); - const idx = ~path.lastIndexOf('.'); - return idx ? path.substring(~idx) : ''; -} - -export function normalize(path: string, toOSPath?: boolean): string { - if (path === null || path === void 0) { - return path; - } - - const len = path.length; - if (len === 0) { - return '.'; - } - - const wantsBackslash = isWindows && toOSPath; - if (_isNormal(path, wantsBackslash!)) { - return path; - } - - const sep = wantsBackslash ? '\\' : '/'; - const root = getRoot(path, sep); - - // skip the root-portion of the path - let start = root.length; - let skip = false; - let res = ''; - - for (let end = root.length; end <= len; end++) { - // either at the end or at a path-separator character - if (end === len || path.charCodeAt(end) === CharCode.Slash || path.charCodeAt(end) === CharCode.Backslash) { - if (streql(path, start, end, '..')) { - // skip current and remove parent (if there is already something) - const prev_start = res.lastIndexOf(sep); - const prev_part = res.slice(prev_start + 1); - if ((root || prev_part.length > 0) && prev_part !== '..') { - res = prev_start === -1 ? '' : res.slice(0, prev_start); - skip = true; - } - } else if (streql(path, start, end, '.') && (root || res || end < len - 1)) { - // skip current (if there is already something or if there is more to come) - skip = true; - } - - if (!skip) { - const part = path.slice(start, end); - if (res !== '' && res[res.length - 1] !== sep) { - res += sep; - } - res += part; - } - start = end + 1; - skip = false; - } - } - - return root + res; -} - -function streql(value: string, start: number, end: number, other: string): boolean { - return start + other.length === end && value.indexOf(other, start) === start; -} - -/** - * Computes the _root_ this path, like `getRoot('c:\files') === c:\`, - * `getRoot('files:///files/path') === files:///`, - * or `getRoot('\\server\shares\path') === \\server\shares\` - */ -export function getRoot(path: string, sep = '/'): string { - if (!path) { - return ''; - } - - const len = path.length; - let code = path.charCodeAt(0); - if (code === CharCode.Slash || code === CharCode.Backslash) { - code = path.charCodeAt(1); - if (code === CharCode.Slash || code === CharCode.Backslash) { - // UNC candidate \\localhost\shares\ddd - // ^^^^^^^^^^^^^^^^^^^ - code = path.charCodeAt(2); - if (code !== CharCode.Slash && code !== CharCode.Backslash) { - let pos = 3; - const start = pos; - for (; pos < len; pos++) { - code = path.charCodeAt(pos); - if (code === CharCode.Slash || code === CharCode.Backslash) { - break; - } - } - code = path.charCodeAt(pos + 1); - if (start !== pos && code !== CharCode.Slash && code !== CharCode.Backslash) { - pos += 1; - for (; pos < len; pos++) { - code = path.charCodeAt(pos); - if (code === CharCode.Slash || code === CharCode.Backslash) { - return path - .slice(0, pos + 1) // consume this separator - .replace(/[\\/]/g, sep); - } - } - } - } - } - - // /user/far - // ^ - return sep; - } else if ((code >= CharCode.A && code <= CharCode.Z) || (code >= CharCode.a && code <= CharCode.z)) { - // check for windows drive letter c:\ or c: - - if (path.charCodeAt(1) === CharCode.Colon) { - code = path.charCodeAt(2); - if (code === CharCode.Slash || code === CharCode.Backslash) { - // C:\fff - // ^^^ - return path.slice(0, 2) + sep; - } else { - // C: - // ^^ - return path.slice(0, 2); - } - } - } - - // check for URI - // scheme://authority/path - // ^^^^^^^^^^^^^^^^^^^ - let pos = path.indexOf('://'); - if (pos !== -1) { - pos += 3; // 3 -> "://".length - for (; pos < len; pos++) { - code = path.charCodeAt(pos); - if (code === CharCode.Slash || code === CharCode.Backslash) { - return path.slice(0, pos + 1); // consume this separator - } - } - } - - return ''; -} - -export function isEqualOrParent(path: string, candidate: string, ignoreCase?: boolean): boolean { - if (path === candidate) { - return true; - } - - if (!path || !candidate) { - return false; - } - - if (candidate.length > path.length) { - return false; - } - - if (ignoreCase) { - const beginsWith = startsWithIgnoreCase(path, candidate); - if (!beginsWith) { - return false; - } - - if (candidate.length === path.length) { - return true; // same path, different casing - } - - let sepOffset = candidate.length; - if (candidate.charAt(candidate.length - 1) === nativeSep) { - sepOffset--; // adjust the expected sep offset in case our candidate already ends in separator character - } - - return path.charAt(sepOffset) === nativeSep; - } - - if (candidate.charAt(candidate.length - 1) !== nativeSep) { - candidate += nativeSep; - } - - return path.indexOf(candidate) === 0; -} - -export function resolve(...paths: string[]): string { - let processed: string[] = []; - for (const p of paths) { - if (typeof p !== 'string') { - throw new TypeError('Invalid argument type to path.join: ' + typeof p); - } else if (p !== '') { - if (p.charAt(0) === sep) { - processed = []; - } - processed.push(p); - } - } - - const resolved = normalize(processed.join(sep)); - if (resolved.length > 1 && resolved.charAt(resolved.length - 1) === sep) { - return resolved.substr(0, resolved.length - 1); - } - - return resolved; -} - -export function relative(from: string, to: string): string { - let i: number; - - from = resolve(from); - to = resolve(to); - const fromSegments = from.split(sep); - const toSegments = to.split(sep); - - toSegments.shift(); - fromSegments.shift(); - - let upCount = 0; - let downSegments: string[] = []; - - for (i = 0; i < fromSegments.length; i++) { - const seg = fromSegments[i]; - if (seg === toSegments[i]) { - continue; - } - - upCount = fromSegments.length - i; - break; - } - - downSegments = toSegments.slice(i); - - if (fromSegments.length === 1 && fromSegments[0] === '') { - upCount = 0; - } - - if (upCount > fromSegments.length) { - upCount = fromSegments.length; - } - - let rv = ''; - for (i = 0; i < upCount; i++) { - rv += '../'; - } - rv += downSegments.join(sep); - - if (rv.length > 1 && rv.charAt(rv.length - 1) === sep) { - rv = rv.substr(0, rv.length - 1); - } - return rv; -} - -export function replaceAsarInPath(pathMayInAsar: string) { - const parts = pathMayInAsar.split(normalize('/', true)); - parts.forEach((part, i) => { - if (part.endsWith('.asar')) { - parts[i] = part + '.unpacked'; - } - }); - return parts.join(normalize('/', true)); -} - -// Reference: https://en.wikipedia.org/wiki/Filename -const WINDOWS_INVALID_FILE_CHARS = /[\\/:*?"<>|]/g; -const UNIX_INVALID_FILE_CHARS = /[\\/]/g; -const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i; -export function isValidBasename(name: string | null | undefined, isWindowsOS: boolean = isWindows): boolean { - const invalidFileChars = isWindowsOS ? WINDOWS_INVALID_FILE_CHARS : UNIX_INVALID_FILE_CHARS; - - if (!name || name.length === 0 || /^\s+$/.test(name)) { - return false; // require a name that is not just whitespace - } - - invalidFileChars.lastIndex = 0; // the holy grail of software development - if (invalidFileChars.test(name)) { - return false; // check for certain invalid file characters - } - - if (isWindowsOS && WINDOWS_FORBIDDEN_NAMES.test(name)) { - return false; // check for certain invalid file names - } - - if (name === '.' || name === '..') { - return false; // check for reserved values - } - - if (isWindowsOS && name[name.length - 1] === '.') { - return false; // Windows: file cannot end with a "." - } - - if (isWindowsOS && name.length !== name.trim().length) { - return false; // Windows: file cannot end with a whitespace - } - - if (name.length > 255) { - return false; // most file systems do not allow files > 255 length - } - - return true; -} diff --git a/packages/core-electron-main/src/bootstrap/types.ts b/packages/core-electron-main/src/bootstrap/types.ts index c43181a4b1..b35ae3ad26 100644 --- a/packages/core-electron-main/src/bootstrap/types.ts +++ b/packages/core-electron-main/src/bootstrap/types.ts @@ -2,7 +2,7 @@ import { BrowserWindowConstructorOptions } from 'electron'; import { Injector } from '@opensumi/di'; import { ConstructorOf, ExtensionCandidate } from '@opensumi/ide-core-common'; -import { IDisposable } from '@opensumi/ide-core-common/lib/disposable'; +import { IDisposable } from '@opensumi/ide-core-common'; import { IURLHandler } from '@opensumi/ide-core-common/lib/electron'; import { ElectronMainModule } from '../electron-main-module'; diff --git a/packages/core-electron-main/src/bootstrap/window.ts b/packages/core-electron-main/src/bootstrap/window.ts index d746ab848a..54b06beb08 100644 --- a/packages/core-electron-main/src/bootstrap/window.ts +++ b/packages/core-electron-main/src/bootstrap/window.ts @@ -14,8 +14,15 @@ import semver from 'semver'; import treeKill from 'tree-kill'; import { Injectable, Autowired } from '@opensumi/di'; -import { ExtensionCandidate } from '@opensumi/ide-core-common'; -import { Disposable, getDebugLogger, isOSX, URI, FileUri, Deferred } from '@opensumi/ide-core-common'; +import { + ExtensionCandidate, + getDebugLogger, + Disposable, + isMacintosh, + URI, + FileUri, + Deferred, +} from '@opensumi/ide-core-common'; import { normalizedIpcHandlerPathAsync } from '@opensumi/ide-core-common/lib/utils/ipc'; import { ElectronAppConfig, ICodeWindow, ICodeWindowOptions } from './types'; @@ -78,7 +85,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { nodeIntegration: this.appConfig?.browserNodeIntegrated, preload: this.appConfig?.browserPreload, }, - frame: isOSX, + frame: isMacintosh, titleBarStyle: 'hidden', height: DEFAULT_WINDOW_HEIGHT, width: DEFAULT_WINDOW_WIDTH, diff --git a/packages/core-node/__tests__/common-module/credential.server.test.ts b/packages/core-node/__tests__/common-module/credential.server.test.ts index d27b59d71f..940f02c182 100644 --- a/packages/core-node/__tests__/common-module/credential.server.test.ts +++ b/packages/core-node/__tests__/common-module/credential.server.test.ts @@ -1,5 +1,4 @@ -import { INativeCredentialService, isLinux } from '@opensumi/ide-core-common'; -import { AppConfig } from '@opensumi/ide-core-node'; +import { AppConfig, INativeCredentialService, isLinux } from '@opensumi/ide-core-node'; import { createBrowserInjector } from '../../../../tools/dev-tool/src/injector-helper'; import { MockInjector } from '../../../../tools/dev-tool/src/mock-injector'; diff --git a/packages/core-node/__tests__/common-module/index.test.ts b/packages/core-node/__tests__/common-module/index.test.ts index f237d2f901..27258d7219 100644 --- a/packages/core-node/__tests__/common-module/index.test.ts +++ b/packages/core-node/__tests__/common-module/index.test.ts @@ -19,6 +19,6 @@ describe('NodeLogger', () => { }); test('getBackendOS', async () => { - expect(typeof (await server.getBackendOS())).toBe('string'); + expect(typeof (await server.getBackendOS())).toBe('number'); }); }); diff --git a/packages/core-node/src/common-module/common.server.ts b/packages/core-node/src/common-module/common.server.ts index 976cb50042..f06e5ee5d5 100644 --- a/packages/core-node/src/common-module/common.server.ts +++ b/packages/core-node/src/common-module/common.server.ts @@ -1,9 +1,9 @@ import { Injectable } from '@opensumi/di'; -import { ICommonServer, OS } from '@opensumi/ide-core-common'; +import { ICommonServer, OS, OperatingSystem } from '@opensumi/ide-core-common'; @Injectable() export class CommonServer implements ICommonServer { - async getBackendOS(): Promise { + async getBackendOS(): Promise { return OS.type(); } } diff --git a/packages/debug/src/browser/debug-link-detector.ts b/packages/debug/src/browser/debug-link-detector.ts index afc7f8c068..57524eb899 100644 --- a/packages/debug/src/browser/debug-link-detector.ts +++ b/packages/debug/src/browser/debug-link-detector.ts @@ -6,9 +6,7 @@ import { Injectable, Autowired } from '@opensumi/di'; import { Schemas, IOpenerService, OS, formatLocalize } from '@opensumi/ide-core-browser'; -import { URI, IRange } from '@opensumi/ide-core-common'; -import * as osPath from '@opensumi/ide-core-common/lib/path'; -import * as platform from '@opensumi/ide-core-common/lib/platform'; +import { URI, IRange, isWindows, isMacintosh, path as osPath, OperatingSystem } from '@opensumi/ide-core-common'; import { WorkbenchEditorService } from '@opensumi/ide-editor'; import { IFileServiceClient, FileStat } from '@opensumi/ide-file-service/lib/common'; import { IWorkspaceFolder } from '@opensumi/monaco-editor-core/esm/vs/platform/workspace/common/workspace'; @@ -30,10 +28,7 @@ const WIN_RELATIVE_PATH = /(?:(?:\~|\.)(?:(?:\\|\/)[\w\.-]*)+)/; const WIN_PATH = new RegExp(`(${WIN_ABSOLUTE_PATH.source}|${WIN_RELATIVE_PATH.source})`); const POSIX_PATH = /((?:\~|\.)?(?:\/[\w\.-]*)+)/; const LINE_COLUMN = /(?:\:([\d]+))?(?:\:([\d]+))?/; -const PATH_LINK_REGEX = new RegExp( - `${platform.isWindows ? WIN_PATH.source : POSIX_PATH.source}${LINE_COLUMN.source}`, - 'g', -); +const PATH_LINK_REGEX = new RegExp(`${isWindows ? WIN_PATH.source : POSIX_PATH.source}${LINE_COLUMN.source}`, 'g'); const MAX_LENGTH = 2000; @@ -105,9 +100,9 @@ export class LinkDetector { this.decorateLink(link, async () => { if (uri.scheme === Schemas.file) { const fsPath = uri.toString(); - const path = OS.type() === OS.Type.Windows ? osPath.win32 : osPath.posix; + const path = OS.type() === OperatingSystem.Windows ? osPath.win32 : osPath.posix; const fileUrl = osPath.normalize( - path.sep === osPath.posix.sep && platform.isWindows ? fsPath.replace(/\\/g, osPath.posix.sep) : fsPath, + path.sep === osPath.posix.sep && isWindows ? fsPath.replace(/\\/g, osPath.posix.sep) : fsPath, ); await this.workbenchEditorService.open(URI.parse(fileUrl)); @@ -173,9 +168,9 @@ export class LinkDetector { private decorateLink(link: HTMLElement, onClick: (preserveFocus: boolean) => void) { link.classList.add(styles.link); - link.title = formatLocalize('debug.console.followLink', platform.isMacintosh ? 'Cmd' : 'Ctrl'); + link.title = formatLocalize('debug.console.followLink', isMacintosh ? 'Cmd' : 'Ctrl'); link.onmousemove = (event) => { - link.classList.toggle(styles.pointer, platform.isMacintosh ? event.metaKey : event.ctrlKey); + link.classList.toggle(styles.pointer, isMacintosh ? event.metaKey : event.ctrlKey); }; link.onmouseleave = () => link.classList.remove(styles.pointer); link.onclick = (event) => { @@ -183,7 +178,7 @@ export class LinkDetector { if (!selection || selection.type === 'Range') { return; } - if (!(platform.isMacintosh ? event.metaKey : event.ctrlKey)) { + if (!(isMacintosh ? event.metaKey : event.ctrlKey)) { return; } diff --git a/packages/debug/src/browser/debug-schema-updater.ts b/packages/debug/src/browser/debug-schema-updater.ts index 7ca596b158..adcde35a52 100644 --- a/packages/debug/src/browser/debug-schema-updater.ts +++ b/packages/debug/src/browser/debug-schema-updater.ts @@ -1,11 +1,13 @@ import { Injectable, Autowired } from '@opensumi/di'; -import { deepClone, IJSONSchema, IJSONSchemaRegistry } from '@opensumi/ide-core-browser'; +import { objects, IJSONSchema, IJSONSchemaRegistry } from '@opensumi/ide-core-browser'; import { launchSchemaUri } from '../common'; import { DebugServer, IDebugServer } from '../common/debug-service'; import { DebugConfigurationManager } from './debug-configuration-manager'; +const { deepClone } = objects; + @Injectable() export class DebugSchemaUpdater { @Autowired(IDebugServer) diff --git a/packages/debug/src/browser/debugUtils.ts b/packages/debug/src/browser/debugUtils.ts index 347dffd960..6b531d9e34 100644 --- a/packages/debug/src/browser/debugUtils.ts +++ b/packages/debug/src/browser/debugUtils.ts @@ -1,7 +1,9 @@ -import { equalsIgnoreCase } from '@opensumi/ide-core-browser'; +import { strings } from '@opensumi/ide-core-browser'; import { DebugConfiguration } from '../common'; +const { equalsIgnoreCase } = strings; + export function isExtensionHostDebugging(config: DebugConfiguration) { return ( config.type && diff --git a/packages/debug/src/browser/editor/debug-editor-contribution.ts b/packages/debug/src/browser/editor/debug-editor-contribution.ts index a0d6fb3ff5..f132c6b501 100644 --- a/packages/debug/src/browser/editor/debug-editor-contribution.ts +++ b/packages/debug/src/browser/editor/debug-editor-contribution.ts @@ -4,6 +4,7 @@ import { PreferenceService, MonacoOverrideServiceRegistry, ServiceNames, + Position, } from '@opensumi/ide-core-browser'; import { IDisposable, @@ -11,13 +12,12 @@ import { RunOnceScheduler, CancellationTokenSource, onUnexpectedExternalError, - Position, createMemoizer, Event, -} from '@opensumi/ide-core-common'; -import { flatten } from '@opensumi/ide-core-common/lib/arrays'; -import { Constants } from '@opensumi/ide-core-common/lib/uint'; -import * as strings from '@opensumi/ide-core-common/lib/utils/strings'; + arrays, + Constants, + strings, +} from '@opensumi/ide-core-browser'; import { IEditor, IDecorationApplyOptions } from '@opensumi/ide-editor'; import { WorkbenchEditorService } from '@opensumi/ide-editor'; import { IEditorFeatureContribution } from '@opensumi/ide-editor/lib/browser'; @@ -34,7 +34,7 @@ import { DebugSessionManager } from '../debug-session-manager'; import { DebugStackFrame } from '../model'; import { DebugVariable, DebugWatchNode, DebugWatchRoot } from '../tree'; -import { CONTEXT_DEBUG_STOPPED_KEY, CONTEXT_IN_DEBUG_MODE_KEY, DebugState, IDebugSessionManager } from './../../common'; +import { IDebugSessionManager } from './../../common'; import { InlineValueContext } from './../../common/inline-values'; import { DEFAULT_WORD_REGEXP } from './../debugUtils'; import { DebugModelManager } from './debug-model-manager'; @@ -45,6 +45,8 @@ const MAX_NUM_INLINE_VALUES = 100; const MAX_INLINE_DECORATOR_LENGTH = 150; // 调试时每个内联修饰符的最大字符串长度。超过这个值就在后面显示 ... const MAX_TOKENIZATION_LINE_LEN = 500; // 如果这行太长了,则跳过该行的内联值 +const { flatten } = arrays; + class InlineSegment { constructor(public column: number, public text: string) {} } diff --git a/packages/debug/src/browser/editor/debug-expression-provider.ts b/packages/debug/src/browser/editor/debug-expression-provider.ts index 51fd336c1f..74b49391b8 100644 --- a/packages/debug/src/browser/editor/debug-expression-provider.ts +++ b/packages/debug/src/browser/editor/debug-expression-provider.ts @@ -1,10 +1,11 @@ import { Injectable, Autowired } from '@opensumi/di'; -import { CancellationTokenSource, coalesce, IRange } from '@opensumi/ide-core-common'; +import { CancellationTokenSource, arrays, IRange } from '@opensumi/ide-core-common'; import { ITextModel } from '@opensumi/ide-monaco/lib/browser/monaco-api/types'; import * as monaco from '@opensumi/monaco-editor-core/esm/vs/editor/editor.api'; import { IEvaluatableExpressionService } from './evaluatable-expression'; +const { coalesce } = arrays; @Injectable() export class DebugExpressionProvider { @@ -30,10 +31,10 @@ export class DebugExpressionProvider { const results = await Promise.all(promises).then(coalesce); if (results.length > 0) { - matchingExpression = results[0].expression; - rng = results[0].range; + matchingExpression = results[0]?.expression; + rng = results[0]?.range; - if (!matchingExpression) { + if (!matchingExpression && rng) { const lineContent = model.getLineContent(pos.lineNumber); matchingExpression = lineContent.substring(rng.startColumn - 1, rng.endColumn - 1); } diff --git a/packages/debug/src/browser/editor/debug-hover-tree.model.service.ts b/packages/debug/src/browser/editor/debug-hover-tree.model.service.ts index d9ac958e6d..97297a3666 100644 --- a/packages/debug/src/browser/editor/debug-hover-tree.model.service.ts +++ b/packages/debug/src/browser/editor/debug-hover-tree.model.service.ts @@ -8,8 +8,7 @@ import { WatchEvent, TreeNodeEvent, } from '@opensumi/ide-components'; -import { Emitter, Deferred, Event, DisposableCollection } from '@opensumi/ide-core-browser'; -import { Path } from '@opensumi/ide-core-common/lib/path'; +import { Emitter, Deferred, Event, DisposableCollection, path } from '@opensumi/ide-core-browser'; import { DebugVariable, ExpressionContainer, ExpressionNode } from '../tree/debug-tree-node.define'; import styles from '../view/variables/debug-variables.module.less'; @@ -17,6 +16,8 @@ import styles from '../view/variables/debug-variables.module.less'; import { DebugHoverModel } from './debug-hover-model'; import { ExpressionVariable, DebugHoverSource } from './debug-hover-source'; +const { Path } = path; + export interface IDebugVariablesHandle extends IRecycleTreeHandle { hasDirectFocus: () => boolean; } diff --git a/packages/debug/src/browser/view/console/debug-console-filter.model.ts b/packages/debug/src/browser/view/console/debug-console-filter.model.ts index cca363ad9d..b1717d32aa 100644 --- a/packages/debug/src/browser/view/console/debug-console-filter.model.ts +++ b/packages/debug/src/browser/view/console/debug-console-filter.model.ts @@ -1,6 +1,5 @@ import { Injectable } from '@opensumi/di'; -import { matchesFuzzy } from '@opensumi/ide-core-common/lib/filters'; -import { splitGlobAware } from '@opensumi/ide-core-common/lib/utils/glob'; +import { splitGlobAware, matchesFuzzy } from '@opensumi/ide-core-browser'; interface ParsedQuery { type: 'include' | 'exclude'; diff --git a/packages/debug/src/browser/view/console/debug-console-filter.service.ts b/packages/debug/src/browser/view/console/debug-console-filter.service.ts index 2f9064dc6f..75b3ce9297 100644 --- a/packages/debug/src/browser/view/console/debug-console-filter.service.ts +++ b/packages/debug/src/browser/view/console/debug-console-filter.service.ts @@ -1,12 +1,12 @@ import { Injectable } from '@opensumi/di'; -import { Emitter, Event } from '@opensumi/ide-core-browser'; -import * as strings from '@opensumi/ide-core-common'; +import { Emitter, Event, strings } from '@opensumi/ide-core-browser'; import { matchAll } from '../../debugUtils'; import { DebugConsoleFilterModel } from './debug-console-filter.model'; const Ansi = require('anser'); +const { convertSimple2RegExpPattern } = strings; export interface IDebugConsoleFilter { filter: (t: string) => boolean; @@ -60,7 +60,7 @@ export class DebugConsoleFilterService implements IDebugConsoleFilter { } public findMatches(text: string): IFilterMatches[] { - const regexp = new RegExp(strings.convertSimple2RegExpPattern(this._filterText.toLowerCase()), 'g'); + const regexp = new RegExp(convertSimple2RegExpPattern(this._filterText.toLowerCase()), 'g'); if (this._filterText.trim() === '') { return []; } diff --git a/packages/debug/src/browser/view/console/debug-console-tree.model.service.ts b/packages/debug/src/browser/view/console/debug-console-tree.model.service.ts index b9c11a9609..2e548cdbc6 100644 --- a/packages/debug/src/browser/view/console/debug-console-tree.model.service.ts +++ b/packages/debug/src/browser/view/console/debug-console-tree.model.service.ts @@ -18,9 +18,9 @@ import { Event, DisposableCollection, IClipboardService, + path, } from '@opensumi/ide-core-browser'; import { AbstractContextMenuService, MenuId, ICtxMenuRenderer } from '@opensumi/ide-core-browser/lib/menu/next'; -import { Path } from '@opensumi/ide-core-common/lib/path'; import { IDebugSessionManager } from '../../../common'; import { LinkDetector } from '../../debug-link-detector'; @@ -40,7 +40,7 @@ import { DebugConsoleTreeModel } from './debug-console-model'; import { DebugConsoleSession } from './debug-console-session'; import styles from './debug-console.module.less'; - +const { Path } = path; export interface IDebugConsoleHandle extends IRecycleTreeHandle { hasDirectFocus: () => boolean; } diff --git a/packages/debug/src/browser/view/watch/debug-watch-tree.model.service.ts b/packages/debug/src/browser/view/watch/debug-watch-tree.model.service.ts index ef4e023fd7..48da84a4ac 100644 --- a/packages/debug/src/browser/view/watch/debug-watch-tree.model.service.ts +++ b/packages/debug/src/browser/view/watch/debug-watch-tree.model.service.ts @@ -25,9 +25,9 @@ import { IClipboardService, IContextKey, IReporterService, + path, } from '@opensumi/ide-core-browser'; import { AbstractContextMenuService, MenuId, ICtxMenuRenderer } from '@opensumi/ide-core-browser/lib/menu/next'; -import { Path } from '@opensumi/ide-core-common/lib/path'; import { DebugSessionManager } from '../../debug-session-manager'; import { DebugWatch } from '../../model'; @@ -40,6 +40,7 @@ import { DebugVariableContainer, DebugVariable } from './../../tree/debug-tree-n import { DebugWatchModel } from './debug-watch-model'; import styles from './debug-watch.module.less'; +const { Path } = path; export interface IDebugWatchHandle extends IRecycleTreeHandle { hasDirectFocus: () => boolean; diff --git a/packages/decoration/src/browser/decorationsService.ts b/packages/decoration/src/browser/decorationsService.ts index 4fc4a59e52..afde925ee5 100644 --- a/packages/decoration/src/browser/decorationsService.ts +++ b/packages/decoration/src/browser/decorationsService.ts @@ -11,10 +11,8 @@ import { toDisposable, dispose, } from '@opensumi/ide-core-common'; -import { getDebugLogger, isFalsyOrWhitespace, asArray } from '@opensumi/ide-core-common'; -import { isPromiseCanceledError } from '@opensumi/ide-core-common/lib/errors'; -import { LinkedList } from '@opensumi/ide-core-common/lib/linked-list'; -import { TernarySearchTree } from '@opensumi/ide-core-common/lib/map'; +import { getDebugLogger, strings, arrays } from '@opensumi/ide-core-common'; +import { isPromiseCanceledError, LinkedList, TernarySearchTree } from '@opensumi/ide-core-common'; import { IDecorationsService, @@ -24,6 +22,8 @@ import { IDecorationData, } from '../common/decorations'; +const { isFalsyOrWhitespace } = strings; +const { asArray } = arrays; class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { private readonly _data = TernarySearchTree.forPaths(); diff --git a/packages/editor/src/browser/breadcrumb/default.ts b/packages/editor/src/browser/breadcrumb/default.ts index 253be708cf..18896c8139 100644 --- a/packages/editor/src/browser/breadcrumb/default.ts +++ b/packages/editor/src/browser/breadcrumb/default.ts @@ -14,9 +14,9 @@ import { URI, WithEventBus, LRUMap, + path, } from '@opensumi/ide-core-browser'; import { LabelService } from '@opensumi/ide-core-browser/lib/services'; -import { Path } from '@opensumi/ide-core-common/lib/path'; import { FileStat } from '@opensumi/ide-file-service/lib/common'; import { IFileServiceClient } from '@opensumi/ide-file-service/lib/common/file-service-client'; import { IWorkspaceService } from '@opensumi/ide-workspace'; @@ -26,6 +26,7 @@ import { EditorSelectionChangeEvent, IBreadCrumbPart, IBreadCrumbProvider } from import { DocumentSymbolChangedEvent, DocumentSymbolStore, INormalizedDocumentSymbol } from './document-symbol'; +const { Path } = path; @Injectable() export class DefaultBreadCrumbProvider extends WithEventBus implements IBreadCrumbProvider { private _onDidUpdateBreadCrumb = new Emitter(); @@ -63,7 +64,7 @@ export class DefaultBreadCrumbProvider extends WithEventBus implements IBreadCru ? new URI(this.workspaceService.workspace.uri) : undefined; let root: URI; - let relativePaths: Path; + let relativePaths: path.Path; if (workspaceRoot && workspaceRoot.isEqualOrParent(uri)) { root = workspaceRoot; relativePaths = workspaceRoot.relative(uri)!; diff --git a/packages/editor/src/browser/breadcrumb/index.ts b/packages/editor/src/browser/breadcrumb/index.ts index 5262139cd8..99a87144e0 100644 --- a/packages/editor/src/browser/breadcrumb/index.ts +++ b/packages/editor/src/browser/breadcrumb/index.ts @@ -1,11 +1,12 @@ import { Injectable, Autowired } from '@opensumi/di'; -import { IDisposable, URI, addElement, MaybeNull, Emitter } from '@opensumi/ide-core-browser'; +import { IDisposable, URI, arrays, MaybeNull, Emitter } from '@opensumi/ide-core-browser'; import { IEditor } from '../../common'; import { IBreadCrumbService, IBreadCrumbPart, IBreadCrumbProvider } from '../types'; import { DefaultBreadCrumbProvider } from './default'; +const { addElement } = arrays; @Injectable() export class BreadCrumbServiceImpl implements IBreadCrumbService { diff --git a/packages/editor/src/browser/component.ts b/packages/editor/src/browser/component.ts index 2758d7ae1d..eca4d4a31b 100644 --- a/packages/editor/src/browser/component.ts +++ b/packages/editor/src/browser/component.ts @@ -19,7 +19,6 @@ import { RegisterEditorSideComponentEvent, } from './types'; - type SchemeKey = string; interface INormalizedEditorComponentResolver { diff --git a/packages/editor/src/browser/doc-model/editor-document-model-service.ts b/packages/editor/src/browser/doc-model/editor-document-model-service.ts index 4b0d639ada..c27b2315b9 100644 --- a/packages/editor/src/browser/doc-model/editor-document-model-service.ts +++ b/packages/editor/src/browser/doc-model/editor-document-model-service.ts @@ -14,9 +14,10 @@ import { PreferenceService, ReadyEvent, memoize, + mapToSerializable, + serializableToMap, } from '@opensumi/ide-core-browser'; import { IHashCalculateService } from '@opensumi/ide-core-common/lib/hash-calculate/hash-calculate'; -import { mapToSerializable, serializableToMap } from '@opensumi/ide-core-common/lib/map'; import { EOL } from '@opensumi/ide-monaco/lib/browser/monaco-api/types'; import { EditorDocumentModel } from './editor-document-model'; diff --git a/packages/editor/src/browser/editor-collection.service.ts b/packages/editor/src/browser/editor-collection.service.ts index 7cac3b9c82..f0a6e22043 100644 --- a/packages/editor/src/browser/editor-collection.service.ts +++ b/packages/editor/src/browser/editor-collection.service.ts @@ -9,7 +9,7 @@ import { Emitter as EventEmitter, ISelection, Disposable, - removeUndefined, + objects, } from '@opensumi/ide-core-common'; import { Emitter } from '@opensumi/ide-core-common'; import type { @@ -32,7 +32,6 @@ import { IResourceOpenOptions, } from '../common'; - import { MonacoEditorDecorationApplier } from './decoration-applier'; import { IEditorDocumentModelRef, @@ -44,6 +43,7 @@ import { EditorFeatureRegistryImpl } from './feature'; import { getConvertedMonacoOptions, isEditorOption, isDiffEditorOption } from './preference/converter'; import { IEditorFeatureRegistry } from './types'; +const { removeUndefined } = objects; @Injectable() export class EditorCollectionServiceImpl extends WithEventBus implements EditorCollectionService { diff --git a/packages/editor/src/browser/editor.contribution.ts b/packages/editor/src/browser/editor.contribution.ts index c1e8e000a9..f6004a3c01 100644 --- a/packages/editor/src/browser/editor.contribution.ts +++ b/packages/editor/src/browser/editor.contribution.ts @@ -31,13 +31,13 @@ import { getLanguageIdFromMonaco, QuickPickItem, AppConfig, + SUPPORTED_ENCODINGS, } from '@opensumi/ide-core-browser'; import { ComponentContribution, ComponentRegistry } from '@opensumi/ide-core-browser/lib/layout'; import { MenuContribution, IMenuRegistry, MenuId } from '@opensumi/ide-core-browser/lib/menu/next'; import { AbstractContextMenuService } from '@opensumi/ide-core-browser/lib/menu/next/menu.interface'; import { ICtxMenuRenderer } from '@opensumi/ide-core-browser/lib/menu/next/renderer/ctxmenu/base'; import { isWindows, isOSX, PreferenceScope, ILogger } from '@opensumi/ide-core-common'; -import { SUPPORTED_ENCODINGS } from '@opensumi/ide-core-common/lib/const'; import { EOL } from '@opensumi/ide-monaco/lib/browser/monaco-api/types'; import { EditorContextKeys } from '@opensumi/monaco-editor-core/esm/vs/editor/common/editorContextKeys'; import * as monaco from '@opensumi/monaco-editor-core/esm/vs/editor/editor.api'; diff --git a/packages/editor/src/browser/feature.ts b/packages/editor/src/browser/feature.ts index e942a6373a..dadabf6370 100644 --- a/packages/editor/src/browser/feature.ts +++ b/packages/editor/src/browser/feature.ts @@ -1,10 +1,12 @@ import { Injectable, Autowired } from '@opensumi/di'; -import { IDisposable, addElement, ILogger, Emitter, Event, URI } from '@opensumi/ide-core-browser'; +import { IDisposable, arrays, ILogger, Emitter, Event, URI } from '@opensumi/ide-core-browser'; import { IEditor } from '../common'; import { IEditorFeatureRegistry, IEditorFeatureContribution } from './types'; +const { addElement } = arrays; + @Injectable() export class EditorFeatureRegistryImpl implements IEditorFeatureRegistry { private contributions: IEditorFeatureContribution[] = []; diff --git a/packages/editor/src/browser/fs-resource/fs-editor-doc.ts b/packages/editor/src/browser/fs-resource/fs-editor-doc.ts index 9e6920ed7b..4b91428f8a 100644 --- a/packages/editor/src/browser/fs-resource/fs-editor-doc.ts +++ b/packages/editor/src/browser/fs-resource/fs-editor-doc.ts @@ -5,14 +5,16 @@ import { Event, IApplicationService, FileChangeType, - OS, + OperatingSystem, IEditorDocumentChange, IEditorDocumentModelSaveResult, PreferenceService, getLanguageIdFromMonaco, EncodingRegistry, + UTF8_with_bom, + UTF8, + detectEncodingFromBuffer, } from '@opensumi/ide-core-browser'; -import { UTF8_with_bom, UTF8, detectEncodingFromBuffer } from '@opensumi/ide-core-common/lib/encoding'; import { IFileServiceClient } from '@opensumi/ide-file-service'; import { EOL } from '@opensumi/ide-monaco/lib/browser/monaco-api/types'; @@ -93,7 +95,7 @@ export class BaseFileSystemEditorDocumentProvider implements IEditorDocumentMode if (eol !== 'auto') { return eol; } - return backendOS === OS.Type.Windows ? EOL.CRLF : EOL.LF; + return backendOS === OperatingSystem.Windows ? EOL.CRLF : EOL.LF; } async read(uri: URI, options: ReadEncodingOptions): Promise<{ encoding: string; content: string }> { diff --git a/packages/editor/src/browser/fs-resource/fs-resource.ts b/packages/editor/src/browser/fs-resource/fs-resource.ts index ab9392fd5f..796e7777ae 100644 --- a/packages/editor/src/browser/fs-resource/fs-resource.ts +++ b/packages/editor/src/browser/fs-resource/fs-resource.ts @@ -1,6 +1,6 @@ import { Autowired, Injectable } from '@opensumi/di'; import { - OS, + OperatingSystem, URI, MaybePromise, WithEventBus, @@ -11,8 +11,7 @@ import { IApplicationService, } from '@opensumi/ide-core-browser'; import { LabelService } from '@opensumi/ide-core-browser/lib/services'; -import { FileChangeType } from '@opensumi/ide-core-common'; -import { Path } from '@opensumi/ide-core-common/lib/path'; +import { FileChangeType, path } from '@opensumi/ide-core-common'; import { IFileServiceClient, FileStat } from '@opensumi/ide-file-service/lib/common'; import { IDialogService } from '@opensumi/ide-overlay'; @@ -22,6 +21,8 @@ import { IEditorDocumentModelService } from '../doc-model/types'; import { FileTreeSet } from './file-tree-set'; +const { Path } = path; + @Injectable() export class FileSystemResourceProvider extends WithEventBus implements IResourceProvider { @Autowired() @@ -53,7 +54,7 @@ export class FileSystemResourceProvider extends WithEventBus implements IResourc async init() { const os = await this.applicationService.getBackendOS(); - this.involvedFiles = new FileTreeSet(os === OS.Type.Windows); + this.involvedFiles = new FileTreeSet(os === OperatingSystem.Windows); } handlesUri(uri: URI): number { diff --git a/packages/editor/src/browser/grid/grid.service.ts b/packages/editor/src/browser/grid/grid.service.ts index edf822a76b..e34db11da7 100644 --- a/packages/editor/src/browser/grid/grid.service.ts +++ b/packages/editor/src/browser/grid/grid.service.ts @@ -1,5 +1,5 @@ import { IDisposable, IEventBus, MaybeNull, Emitter } from '@opensumi/ide-core-browser'; -import { makeRandomHexString } from '@opensumi/ide-core-common/lib/functional'; +import { makeRandomHexString } from '@opensumi/ide-core-common'; import { IEditorGroup, IEditorGroupState, Direction } from '../../common'; import { GridResizeEvent } from '../types'; diff --git a/packages/editor/src/browser/language/language-status.service.ts b/packages/editor/src/browser/language/language-status.service.ts index f2278538d9..5e2fcba621 100644 --- a/packages/editor/src/browser/language/language-status.service.ts +++ b/packages/editor/src/browser/language/language-status.service.ts @@ -1,10 +1,11 @@ import { Injectable } from '@opensumi/di'; -import { compare, Event, IDisposable } from '@opensumi/ide-core-common'; +import { strings, Event, IDisposable } from '@opensumi/ide-core-common'; import { ITextModel } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model'; import { LanguageFeatureRegistry } from '@opensumi/monaco-editor-core/esm/vs/editor/common/modes/languageFeatureRegistry'; import { ILanguageStatusService, ILanguageStatus } from '../../common'; +const { compare } = strings; @Injectable() export class LanguageStatusService implements ILanguageStatusService { diff --git a/packages/editor/src/browser/monaco-contrib/callHierarchy/callHierarchy.service.ts b/packages/editor/src/browser/monaco-contrib/callHierarchy/callHierarchy.service.ts index 50ad6c51a4..9c7ef2c5ca 100644 --- a/packages/editor/src/browser/monaco-contrib/callHierarchy/callHierarchy.service.ts +++ b/packages/editor/src/browser/monaco-contrib/callHierarchy/callHierarchy.service.ts @@ -4,7 +4,7 @@ import { IDisposable, IPosition, isFunction, - isNonEmptyArray, + arrays, RefCountedDisposable, onUnexpectedExternalError, URI, @@ -22,6 +22,8 @@ import { ITextModel, Position } from '@opensumi/ide-monaco/lib/browser/monaco-ap import { IEditorDocumentModelService } from '../../doc-model/types'; +const { isNonEmptyArray } = arrays; + declare type ProviderResult = T | undefined | null | Thenable; /* --------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/packages/editor/src/browser/monaco-contrib/typeHierarchy/typeHierarchy.service.ts b/packages/editor/src/browser/monaco-contrib/typeHierarchy/typeHierarchy.service.ts index be2b9168bc..05bf4b7e0a 100644 --- a/packages/editor/src/browser/monaco-contrib/typeHierarchy/typeHierarchy.service.ts +++ b/packages/editor/src/browser/monaco-contrib/typeHierarchy/typeHierarchy.service.ts @@ -3,8 +3,7 @@ import { CancellationToken, IPosition, IDisposable, - isFunction, - isNonEmptyArray, + arrays, RefCountedDisposable, onUnexpectedExternalError, URI, @@ -20,6 +19,8 @@ import { ITextModel, Position } from '@opensumi/ide-monaco/lib/browser/monaco-ap import { IEditorDocumentModelService } from '../../doc-model/types'; +const { isNonEmptyArray } = arrays; + export class TypeHierarchyModel { static async create( model: ITextModel, diff --git a/packages/editor/src/browser/preference/converter.ts b/packages/editor/src/browser/preference/converter.ts index 73be963840..08bd9cc408 100644 --- a/packages/editor/src/browser/preference/converter.ts +++ b/packages/editor/src/browser/preference/converter.ts @@ -1,9 +1,11 @@ -import { removeUndefined, Uri } from '@opensumi/ide-core-browser'; +import { objects, Uri } from '@opensumi/ide-core-browser'; import * as monaco from '@opensumi/monaco-editor-core/esm/vs/editor/editor.api'; import { IConfigurationService } from '@opensumi/monaco-editor-core/esm/vs/platform/configuration/common/configuration'; import { IConvertedMonacoOptions } from '../types'; +const { removeUndefined } = objects; + /** * 计算由ConfigurationService设置值带来的monaco编辑器的属性 * @param configurationService IConfigurationService diff --git a/packages/editor/src/browser/resource.service.ts b/packages/editor/src/browser/resource.service.ts index c8c06b06d2..82ca6b42a8 100644 --- a/packages/editor/src/browser/resource.service.ts +++ b/packages/editor/src/browser/resource.service.ts @@ -2,7 +2,7 @@ import { observable } from 'mobx'; import { Injectable, Autowired } from '@opensumi/di'; import { URI, IDisposable, WithEventBus, OnEvent } from '@opensumi/ide-core-browser'; -import { Disposable, addElement, LRUMap, ILogger, Emitter } from '@opensumi/ide-core-common'; +import { Disposable, arrays, LRUMap, ILogger, Emitter } from '@opensumi/ide-core-common'; import { ResourceService, @@ -15,6 +15,8 @@ import { ResourceDecorationChangeEvent, } from '../common'; +const { addElement } = arrays; + @Injectable() export class ResourceServiceImpl extends WithEventBus implements ResourceService { private providers: IResourceProvider[] = []; diff --git a/packages/editor/src/browser/untitled-resource.ts b/packages/editor/src/browser/untitled-resource.ts index 8eaa7888b6..7efff8d961 100644 --- a/packages/editor/src/browser/untitled-resource.ts +++ b/packages/editor/src/browser/untitled-resource.ts @@ -9,15 +9,15 @@ import { IEditorDocumentModelSaveResult, AppConfig, CommandService, - OS, + OperatingSystem, IApplicationService, PreferenceService, getLanguageIdFromMonaco, localize, formatLocalize, MessageType, + path, } from '@opensumi/ide-core-browser'; -import * as path from '@opensumi/ide-core-common/lib/path'; import { EOL } from '@opensumi/ide-monaco/lib/browser/monaco-api/types'; import { IDialogService } from '@opensumi/ide-overlay'; @@ -75,7 +75,7 @@ export class UntitledSchemeDocumentProvider implements IEditorDocumentModelConte if (eol !== 'auto') { return eol; } - return backendOS === OS.Type.Windows ? EOL.CRLF : EOL.LF; + return backendOS === OperatingSystem.Windows ? EOL.CRLF : EOL.LF; } async provideEditorDocumentModelContent(uri: URI, encoding?: string | undefined): Promise { diff --git a/packages/editor/src/browser/workbench-editor.service.ts b/packages/editor/src/browser/workbench-editor.service.ts index bb9a111ed7..0c705f10ef 100644 --- a/packages/editor/src/browser/workbench-editor.service.ts +++ b/packages/editor/src/browser/workbench-editor.service.ts @@ -37,8 +37,8 @@ import { ReadyEvent, IDisposable, Disposable, + makeRandomHexString, } from '@opensumi/ide-core-common'; -import { makeRandomHexString } from '@opensumi/ide-core-common/lib/functional'; import { IMessageService } from '@opensumi/ide-overlay'; import * as monaco from '@opensumi/monaco-editor-core/esm/vs/editor/editor.api'; @@ -887,7 +887,7 @@ export class EditorGroup extends WithEventBus implements IGridEditorGroup { async onRegisterEditorComponentEvent() { if (this.currentResource) { const resource = this.currentResource; - const openTypes =(await this.editorComponentRegistry.resolveEditorComponent(resource)); + const openTypes = await this.editorComponentRegistry.resolveEditorComponent(resource); if (this.currentResource === resource) { this.availableOpenTypes = openTypes; this.cachedResourcesOpenTypes.set(resource.uri.toString(), openTypes); diff --git a/packages/editor/src/common/language.ts b/packages/editor/src/common/language.ts index c5af67ad97..484f1b8512 100644 --- a/packages/editor/src/common/language.ts +++ b/packages/editor/src/common/language.ts @@ -1,8 +1,7 @@ import LSTypes from 'vscode-languageserver-types'; -import { CancellationToken, Command, IAccessibilityInformation, Severity } from '@opensumi/ide-core-common'; -import { IDisposable, MarkerSeverity } from '@opensumi/ide-core-common'; -import { IRelativePattern } from '@opensumi/ide-core-common/lib/utils/glob'; +import { MarkerSeverity } from '@opensumi/ide-core-common'; +import { CancellationToken, IDisposable, IRelativePattern } from '@opensumi/ide-core-common'; import { URI as Uri } from '@opensumi/monaco-editor-core/esm/vs/base/common/uri'; import { editor } from '@opensumi/monaco-editor-core/esm/vs/editor/editor.api'; import type { IRelatedInformation } from '@opensumi/monaco-editor-core/esm/vs/platform/markers/common/markers'; diff --git a/packages/electron-basic/__tests__/index.test.ts b/packages/electron-basic/__tests__/index.test.ts index 1dde0406b6..5bc8981bc7 100644 --- a/packages/electron-basic/__tests__/index.test.ts +++ b/packages/electron-basic/__tests__/index.test.ts @@ -5,7 +5,7 @@ import { ComponentRegistry, CommandRegistry, KeybindingRegistry, - addElement, + arrays, electronEnv, } from '@opensumi/ide-core-browser'; import { IMenuRegistry } from '@opensumi/ide-core-browser/lib/menu/next'; @@ -21,6 +21,7 @@ import { ElectronBasicContribution } from '../src/browser'; import { ElectronNativeDialogService } from '../src/browser/dialog'; import { WelcomeContribution } from '../src/browser/welcome/contribution'; +const { addElement } = arrays; function mockService(target) { return new Proxy(target, { diff --git a/packages/electron-basic/src/browser/header/header.tsx b/packages/electron-basic/src/browser/header/header.tsx index 76e14be39d..56e94b5c64 100644 --- a/packages/electron-basic/src/browser/header/header.tsx +++ b/packages/electron-basic/src/browser/header/header.tsx @@ -2,26 +2,24 @@ import cls from 'classnames'; import { observer } from 'mobx-react-lite'; import React, { useState, useEffect, useRef } from 'react'; - import { useInjectable, MaybeNull, ComponentRenderer, ComponentRegistry, - Disposable, DomListener, AppConfig, replaceLocalizePlaceholder, electronEnv, - isOSX, IWindowService, } from '@opensumi/ide-core-browser'; import { getIcon } from '@opensumi/ide-core-browser'; +import { path, isMacintosh, Disposable } from '@opensumi/ide-core-browser'; import { localize } from '@opensumi/ide-core-common'; import { IElectronMainUIService } from '@opensumi/ide-core-common/lib/electron'; -import { basename } from '@opensumi/ide-core-common/lib/utils/paths'; import { WorkbenchEditorService, IResource } from '@opensumi/ide-editor'; +const { basename } = path; import styles from './header.module.less'; const useFullScreen = () => { @@ -73,7 +71,7 @@ const useMaximize = () => { }; // Big Sur increases title bar height -const isNewMacHeaderBar = () => isOSX && parseFloat(electronEnv.osRelease) >= 20; +const isNewMacHeaderBar = () => isMacintosh && parseFloat(electronEnv.osRelease) >= 20; /** * autoHide: Hide the HeaderBar when the macOS full screen @@ -87,7 +85,7 @@ export const ElectronHeaderBar = observer( const { maximized, getMaximized } = useMaximize(); const LeftComponent = () => { - if (isOSX) { + if (isMacintosh) { return null; } @@ -106,7 +104,7 @@ export const ElectronHeaderBar = observer( }; const RightComponent = () => { - if (isOSX) { + if (isMacintosh) { return null; } @@ -124,7 +122,7 @@ export const ElectronHeaderBar = observer( }; // in Mac, hide the header bar if it is in full screen mode - if (isOSX && isFullScreen && autoHide) { + if (isMacintosh && isFullScreen && autoHide) { return (