@opensumi/ide-components 3.1.2-next-1718700994.0 → 3.1.2-next-1718766864.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5362,17 +5362,6 @@ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\ncons
5362
5362
 
5363
5363
  /***/ }),
5364
5364
 
5365
- /***/ "./src/recycle-tree/path.ts":
5366
- /*!**********************************!*\
5367
- !*** ./src/recycle-tree/path.ts ***!
5368
- \**********************************/
5369
- /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
5370
-
5371
- "use strict";
5372
- eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.treePath = void 0;\nconst path_1 = __webpack_require__(/*! @opensumi/ide-utils/lib/path */ \"../utils/lib/path.js\");\nfunction parse(path) {\n const parts = path.split(path_1.Path.separator);\n const basename = parts.pop() || '';\n return { dirname: parts.join(path_1.Path.separator), basename };\n}\nfunction relative(parent, child) {\n if (parent === child) {\n return '';\n }\n if (!parent || !child) {\n return undefined;\n }\n const raw = !parent.endsWith(path_1.Path.separator) ? parent + path_1.Path.separator : parent;\n if (!child.startsWith(raw)) {\n return undefined;\n }\n const relativePath = child.substring(raw.length);\n return relativePath;\n}\nexports.treePath = {\n parse,\n relative,\n};\n\n\n//# sourceURL=webpack://@opensumi/ide-components/./src/recycle-tree/path.ts?");
5373
-
5374
- /***/ }),
5375
-
5376
5365
  /***/ "./src/recycle-tree/prompt/NewPromptHandle.ts":
5377
5366
  /*!****************************************************!*\
5378
5367
  !*** ./src/recycle-tree/prompt/NewPromptHandle.ts ***!
@@ -5435,7 +5424,7 @@ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexpo
5435
5424
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
5436
5425
 
5437
5426
  "use strict";
5438
- eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.CompositeTreeNode = exports.TreeNode = exports.BranchOperatorStatus = exports.spliceArray = void 0;\nconst tslib_1 = __webpack_require__(/*! tslib */ \"../../node_modules/tslib/tslib.es6.mjs\");\n/* eslint-disable @typescript-eslint/prefer-for-of */\nconst ide_utils_1 = __webpack_require__(/*! @opensumi/ide-utils */ \"../utils/lib/index.js\");\nconst path_1 = __webpack_require__(/*! @opensumi/ide-utils/lib/path */ \"../utils/lib/path.js\");\nconst utils_1 = __webpack_require__(/*! ../../utils */ \"./src/utils/index.ts\");\nconst path_2 = __webpack_require__(/*! ../path */ \"./src/recycle-tree/path.ts\");\nconst types_1 = __webpack_require__(/*! ../types */ \"./src/recycle-tree/types/index.ts\");\nconst { Path } = ide_utils_1.path;\n/**\n * 裁剪数组\n *\n * @param arr 裁剪数组\n * @param start 起始位置\n * @param deleteCount 删除或替换位置\n * @param items 插入的数组\n */\nfunction spliceArray(arr, start, deleteCount = 0, items) {\n const a = arr.slice(0);\n a.splice(start, deleteCount, ...(items || []));\n return a;\n}\nexports.spliceArray = spliceArray;\nvar BranchOperatorStatus;\n(function (BranchOperatorStatus) {\n BranchOperatorStatus[BranchOperatorStatus[\"EXPANDED\"] = 1] = \"EXPANDED\";\n BranchOperatorStatus[BranchOperatorStatus[\"SHRINKED\"] = 2] = \"SHRINKED\";\n})(BranchOperatorStatus = exports.BranchOperatorStatus || (exports.BranchOperatorStatus = {}));\nconst nextIdFactory = () => {\n let id = 0;\n return () => id++;\n};\nclass TreeNode {\n static is(node) {\n return !!node && 'depth' in node && 'name' in node && 'path' in node && 'id' in node;\n }\n static getTreeNodeById(id) {\n return TreeNode.idToTreeNode.get(id);\n }\n static getTreeNodeByPath(path) {\n return TreeNode.pathToTreeNode.get(path);\n }\n static setTreeNode(id, path, node) {\n TreeNode.idToTreeNode.set(id, node);\n TreeNode.pathToTreeNode.set(path, node);\n }\n static removeTreeNode(id, path) {\n TreeNode.idToTreeNode.delete(id);\n TreeNode.pathToTreeNode.delete(path);\n }\n static getIdByPath(path) {\n return TreeNode.pathToId.get(path);\n }\n static setIdByPath(path, id) {\n return TreeNode.pathToId.set(path, id);\n }\n static getGlobalTreeState(path) {\n let state = TreeNode.pathToGlobalTreeState.get(path);\n if (!state) {\n state = {\n isExpanding: false,\n isLoadingPath: false,\n isRefreshing: false,\n refreshCancelToken: new ide_utils_1.CancellationTokenSource(),\n loadPathCancelToken: new ide_utils_1.CancellationTokenSource(),\n };\n }\n return state;\n }\n static setGlobalTreeState(path, updateState) {\n let state = TreeNode.pathToGlobalTreeState.get(path);\n if (!state) {\n state = {\n isExpanding: false,\n isLoadingPath: false,\n isRefreshing: false,\n refreshCancelToken: new ide_utils_1.CancellationTokenSource(),\n loadPathCancelToken: new ide_utils_1.CancellationTokenSource(),\n };\n }\n state = Object.assign(Object.assign({}, state), updateState);\n TreeNode.pathToGlobalTreeState.set(path, state);\n return state;\n }\n constructor(tree, parent, watcher, metadata) {\n this._uid = TreeNode.nextId();\n this._parent = parent;\n this._tree = tree;\n this._disposed = false;\n this._visible = true;\n this._metadata = Object.assign({}, (metadata || {}));\n this._depth = parent ? parent.depth + 1 : 0;\n if (watcher) {\n this._watcher = watcher;\n }\n else if (parent) {\n this._watcher = parent.watcher;\n }\n }\n get disposed() {\n return this._disposed;\n }\n /**\n * 获取基础信息\n */\n get depth() {\n return this._depth;\n }\n get parent() {\n return this._parent;\n }\n set parent(node) {\n this._parent = node;\n // 节点 `parent` 变化,更新当前节点的 `path` 属性\n this._path = '';\n }\n get type() {\n return types_1.TreeNodeType.TreeNode;\n }\n get id() {\n return this._uid;\n }\n set id(id) {\n this._uid = id;\n }\n get displayName() {\n return this.name;\n }\n /**\n * 由于 Tree 对于唯一路径的 path 的依赖\n * 在传入 `name` 值时必须保证其在路径上的唯一性\n * 一般不建议手动管理 `name`,采用默认值即可\n */\n get name() {\n // 根节点保证唯一性\n if (!this.parent) {\n return `root_${this.id}`;\n }\n let name = this.getMetadata('name');\n this.validateName(name);\n if (!name) {\n name = String(TreeNode.nextId());\n this._metadata['name'] = name;\n }\n return name;\n }\n set name(name) {\n this.validateName(name);\n this.addMetadata('name', name);\n // 节点 `name` 变化,更新当前节点的 `path` 属性\n this._path = '';\n }\n validateName(name) {\n if (!name) {\n return;\n }\n (0, utils_1.warning)(!name.includes(Path.separator), `[TreeNode] name should not include path separator: ${name}`);\n }\n // 节点绝对路径\n get path() {\n if (!this._path) {\n if (this.parent) {\n this._path = Path.joinPath(this.parent.path, this.name);\n }\n else {\n this._path = `${Path.separator}${this.name}`;\n }\n }\n return this._path;\n }\n joinPath(...paths) {\n return Path.joinPath(this.path, ...paths);\n }\n get accessibilityInformation() {\n return {\n label: this.name,\n role: 'treeitem',\n };\n }\n getMetadata(withKey) {\n return this._metadata[withKey];\n }\n addMetadata(withKey, value) {\n if (!(withKey in this._metadata)) {\n this._metadata[withKey] = value;\n this._watcher.notifyDidChangeMetadata(this, {\n type: types_1.MetadataChangeType.Added,\n key: withKey,\n prevValue: void 0,\n value,\n });\n }\n else {\n const prevValue = this._metadata[withKey];\n this._metadata[withKey] = value;\n this._watcher.notifyDidChangeMetadata(this, { type: types_1.MetadataChangeType.Updated, key: withKey, prevValue, value });\n }\n }\n removeMetadata(withKey) {\n if (withKey in this._metadata) {\n const prevValue = this._metadata[withKey];\n delete this._metadata[withKey];\n this._watcher.notifyDidChangeMetadata(this, {\n type: types_1.MetadataChangeType.Removed,\n key: withKey,\n prevValue,\n value: undefined,\n });\n }\n }\n /**\n * 这里的move操作可能为移动,也可能为重命名\n *\n * @param {ICompositeTreeNode} to\n * @param {string} [name=this.name]\n * @returns\n * @memberof TreeNode\n */\n mv(to, name = this.name) {\n // 一个普通节点必含有父节点,根节点不允许任何操作\n const prevParent = this._parent;\n if (to === null || !CompositeTreeNode.is(to)) {\n this.parent = undefined;\n this.dispose();\n return;\n }\n const didChangeParent = prevParent !== to;\n const prevPath = this.path;\n this._depth = to.depth + 1;\n if (didChangeParent || name !== this.name) {\n this.name = name;\n if (didChangeParent) {\n this._watcher.notifyWillChangeParent(this, prevParent, to);\n }\n if (this.parent) {\n this.parent.unlinkItem(this, true);\n this.parent = to;\n this.parent.insertItem(this);\n }\n if (didChangeParent) {\n this._watcher.notifyDidChangeParent(this, prevParent, to);\n }\n }\n if (this.path !== prevPath) {\n this._watcher.notifyDidChangePath(this);\n }\n }\n get visible() {\n return this._visible;\n }\n setVisible(b) {\n this._visible = b;\n return this;\n }\n dispose() {\n if (this._disposed) {\n return;\n }\n TreeNode.removeTreeNode(this.id, this.path);\n this._disposed = true;\n this._watcher.notifyDidDispose(this);\n }\n}\nexports.TreeNode = TreeNode;\nTreeNode.nextId = nextIdFactory();\nTreeNode.idToTreeNode = new Map();\nTreeNode.pathToTreeNode = new Map();\nTreeNode.pathToId = new Map();\n// 每颗树都只会在根节点上绑定一个可取消的对象,即同个时间点只能存在一个改变树数据结构的事情\nTreeNode.pathToGlobalTreeState = new Map();\nclass CompositeTreeNode extends TreeNode {\n static defaultSortComparator(a, b) {\n if (a.constructor === b.constructor) {\n return a.name > b.name ? 1 : a.name < b.name ? -1 : 0;\n }\n return CompositeTreeNode.is(a) ? -1 : CompositeTreeNode.is(b) ? 1 : 0;\n }\n static is(node) {\n return !!node && 'children' in node;\n }\n static isRoot(node) {\n return CompositeTreeNode.is(node) && !node.parent;\n }\n generatorWatcher() {\n const emitter = new ide_utils_1.Emitter();\n const onEventChanges = emitter.event;\n const disposeCollection = new ide_utils_1.DisposableCollection();\n const terminateWatch = (path) => {\n this.watchEvents.delete(path);\n };\n const watcher = {\n notifyWillProcessWatchEvent: (target, event) => {\n emitter.fire({ type: types_1.TreeNodeEvent.WillProcessWatchEvent, args: [target, event] });\n },\n notifyWillChangeParent: (target, prevParent, newParent) => {\n emitter.fire({ type: types_1.TreeNodeEvent.WillChangeParent, args: [target, prevParent, newParent] });\n },\n notifyDidChangeParent: (target, prevParent, newParent) => {\n emitter.fire({ type: types_1.TreeNodeEvent.DidChangeParent, args: [target, prevParent, newParent] });\n },\n notifyDidDispose: (target) => {\n emitter.fire({ type: types_1.TreeNodeEvent.DidDispose, args: [target] });\n },\n notifyDidProcessWatchEvent: (target, event) => {\n emitter.fire({ type: types_1.TreeNodeEvent.DidProcessWatchEvent, args: [target, event] });\n },\n notifyDidChangePath: (target) => {\n emitter.fire({ type: types_1.TreeNodeEvent.DidChangePath, args: [target] });\n },\n notifyWillChangeExpansionState: (target, nowExpanded) => {\n const isVisible = this.isItemVisibleAtSurface(target);\n emitter.fire({ type: types_1.TreeNodeEvent.WillChangeExpansionState, args: [target, nowExpanded, isVisible] });\n },\n notifyDidChangeExpansionState: (target, nowExpanded) => {\n const isVisible = this.isItemVisibleAtSurface(target);\n emitter.fire({ type: types_1.TreeNodeEvent.DidChangeExpansionState, args: [target, nowExpanded, isVisible] });\n },\n notifyDidChangeMetadata: (target, change) => {\n emitter.fire({ type: types_1.TreeNodeEvent.DidChangeMetadata, args: [target, change] });\n },\n notifyDidUpdateBranch: () => {\n emitter.fire({ type: types_1.TreeNodeEvent.BranchDidUpdate, args: [] });\n },\n notifyWillResolveChildren: (target, nowExpanded) => {\n emitter.fire({ type: types_1.TreeNodeEvent.WillResolveChildren, args: [target, nowExpanded] });\n },\n notifyDidResolveChildren: (target, nowExpanded) => {\n emitter.fire({ type: types_1.TreeNodeEvent.DidResolveChildren, args: [target, nowExpanded] });\n },\n // 监听所有事件\n on: (event, callback) => {\n const dispose = onEventChanges((data) => {\n if (data.type === event) {\n callback(...data.args);\n }\n });\n disposeCollection.push(dispose);\n return dispose;\n },\n // 监听Watch事件变化\n onWatchEvent: (path, callback) => {\n const terminator = terminateWatch;\n this.watchEvents.set(path, { terminator, callback });\n return terminator;\n },\n dispose: disposeCollection,\n };\n return watcher;\n }\n // parent 为 undefined 即表示该节点为根节点\n constructor(tree, parent, watcher, metadata) {\n super(tree, parent, watcher, metadata);\n this._children = null;\n this._lock = false;\n this.refreshThrottler = new ide_utils_1.ThrottledDelayer(CompositeTreeNode.REFRESH_DELAY);\n this.toRefreshPathQueue = new Set();\n /**\n * 处理 Watch 事件,同时可通过外部手动调 g用节点更新函数进行节点替换,这里为通用的事件管理\n * 如: transferItem,insertItem, unlinkItem等\n * @private\n * @memberof CompositeTreeNode\n */\n this.handleWatchEvent = (event) => tslib_1.__awaiter(this, void 0, void 0, function* () {\n this.watcher.notifyWillProcessWatchEvent(this, event);\n switch (event.type) {\n case types_1.WatchEvent.Moved: {\n const { oldPath, newPath } = event;\n if (typeof oldPath !== 'string') {\n throw new TypeError('Expected oldPath to be a string');\n }\n if (typeof newPath !== 'string') {\n throw new TypeError('Expected newPath to be a string');\n }\n if (Path.isRelative(oldPath)) {\n throw new TypeError('oldPath must be absolute');\n }\n if (Path.isRelative(newPath)) {\n throw new TypeError('newPath must be absolute');\n }\n this.transferItem(oldPath, newPath);\n break;\n }\n case types_1.WatchEvent.Added: {\n const { node } = event;\n if (!TreeNode.is(node)) {\n throw new TypeError('Expected node to be a TreeNode');\n }\n this.insertItem(node);\n break;\n }\n case types_1.WatchEvent.Removed: {\n const { path } = event;\n const { basename, dirname } = path_2.treePath.parse(path);\n if (dirname === this.path && !!this.children) {\n const item = this.children.find((c) => c.name === basename);\n if (item) {\n this.unlinkItem(item);\n }\n }\n break;\n }\n default:\n // 如果当前变化的节点已在数据视图(并非滚动到不可见区域)中不可见,则将该节点折叠,待下次更新即可,\n if (!this.isItemVisibleAtRootSurface(this)) {\n this.isExpanded = false;\n this._children = null;\n }\n else {\n yield this.refresh();\n }\n break;\n }\n this.watcher.notifyDidProcessWatchEvent(this, event);\n });\n this.isExpanded = parent ? false : true;\n this._branchSize = 0;\n if (!parent) {\n this.watchEvents = new Map();\n // 为根节点创建监听器\n this._watcher = this.generatorWatcher();\n this._root = this;\n TreeNode.setTreeNode(this.id, this.path, this);\n }\n else {\n this._watcher = parent.watcher;\n }\n }\n /**\n * 重载 setter 后,必须要重载 getter\n */\n get name() {\n return super.name;\n }\n /**\n * 重载 name 的 setter,路径改变时需要重新监听文件节点变化\n */\n set name(name) {\n const prevPath = this.path;\n if (!CompositeTreeNode.isRoot(this) && typeof this.watchTerminator === 'function') {\n this.watchTerminator(prevPath);\n this.watchTerminator = this.watcher.onWatchEvent(this.path, this.handleWatchEvent);\n }\n this.addMetadata('name', name);\n // 节点 `name` 变化,更新当前节点的 `path` 属性\n this._path = '';\n }\n // 作为根节点唯一的watcher需要在生成新节点的时候传入\n get watcher() {\n return this._watcher;\n }\n get type() {\n return types_1.TreeNodeType.CompositeTreeNode;\n }\n get children() {\n return this._children;\n }\n get expanded() {\n return this.isExpanded;\n }\n /**\n * 当前可见的分支数量\n *\n * 当节点为展开状态时,其整个分支(递归展平)由上一级的分支(根(位于数据层可见)或处于折叠状态的分支)拥有\n * 当节点为折叠状态时,其整个分支(递归展平)由其上一级父目录展开该节点\n *\n * @readonly\n * @memberof CompositeTreeNode\n */\n get branchSize() {\n return this._branchSize;\n }\n /**\n * 获取当前节点的分支数,一般为顶层节点,如Root上获取\n *\n * @readonly\n * @memberof CompositeTreeNode\n */\n get flattenedBranch() {\n return this._flattenedBranch;\n }\n get lock() {\n return this._lock;\n }\n get root() {\n if ((0, ide_utils_1.isUndefined)(this._root)) {\n this._root = this.getRoot() || null;\n }\n return this._root;\n }\n getRoot() {\n let root = this.parent;\n while (root && root.parent) {\n root = root.parent;\n }\n return root;\n }\n /**\n * 确保此“目录”的子级已加载(不影响“展开”状态)\n * 如果子级已经加载,则返回的Promise将立即解决\n * 否则,将发出重新加载请求并返回Promise\n * 一旦返回的Promise.resolve,“CompositeTreeNode#children” 便可以访问到对于节点\n */\n ensureLoaded(token) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n if (this._children) {\n return;\n }\n return yield this.hardReloadChildren(token);\n });\n }\n // 展开节点\n setExpanded(ensureVisible = true, quiet = false, isOwner = true, token) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n if (this.disposed) {\n return;\n }\n // 根节点不可折叠\n if (CompositeTreeNode.isRoot(this)) {\n return;\n }\n if (this.isExpanded) {\n return;\n }\n if (isOwner) {\n const state = TreeNode.getGlobalTreeState(this.path);\n state.loadPathCancelToken.cancel();\n state.refreshCancelToken.cancel();\n TreeNode.setGlobalTreeState(this.path, {\n isExpanding: true,\n });\n }\n this.isExpanded = true;\n if (this._children === null) {\n this._watcher.notifyWillResolveChildren(this, this.isExpanded);\n yield this.hardReloadChildren(token);\n this._watcher.notifyDidResolveChildren(this, this.isExpanded);\n // 检查其是否展开;可能同时执行了 setCollapsed 方法\n if (!this.isExpanded || (token === null || token === void 0 ? void 0 : token.isCancellationRequested)) {\n if (isOwner) {\n TreeNode.setGlobalTreeState(this.path, {\n isExpanding: false,\n });\n }\n return;\n }\n }\n if (ensureVisible && this.parent && CompositeTreeNode.is(this.parent)) {\n /**\n * 在传入 ensureVisible = true 时,这里传入的 token 不能取消所有副作用\n * 故在使用 ensureVisible = true 时必须保证 `setExpanded` 与 `setCollapsed` 的独立性\n * 如需要 `await node.setExpanded(true)` 后再执行 `node.setCollapsed()`\n */\n yield this.parent.setExpanded(true, !quiet, false, token);\n }\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n if (isOwner) {\n TreeNode.setGlobalTreeState(this.path, {\n isExpanding: false,\n });\n }\n return;\n }\n if (this.isExpanded) {\n this._watcher.notifyWillChangeExpansionState(this, true);\n // 与根节点合并分支\n this.expandBranch(this, quiet);\n this._watcher.notifyDidChangeExpansionState(this, true);\n }\n if (isOwner) {\n TreeNode.setGlobalTreeState(this.path, {\n isExpanding: false,\n });\n TreeNode.setTreeNode(this.id, this.path, this);\n }\n });\n }\n // 获取当前节点下所有展开的节点路径\n getAllExpandedNodePath() {\n var _a, _b;\n const paths = [];\n let start = 0;\n if (!CompositeTreeNode.isRoot(this)) {\n // 找到节点位置下标,向下进一步查找展开目录\n start = ((_a = this.root) === null || _a === void 0 ? void 0 : _a.getIndexAtTreeNodeId(this.id)) + 1;\n }\n const end = start + this.branchSize;\n for (let i = start; i < end; i++) {\n const node = (_b = this.root) === null || _b === void 0 ? void 0 : _b.getTreeNodeAtIndex(i);\n if (CompositeTreeNode.is(node) && node.expanded) {\n paths.push(node.path);\n }\n }\n return paths;\n }\n // 获取当前节点下所有折叠的节点路径\n getAllCollapsedNodePath() {\n let paths = [];\n if (this.children) {\n for (let i = 0; i < this.children.length; i++) {\n const child = this.children[i];\n if (!CompositeTreeNode.is(child)) {\n continue;\n }\n if (child.isExpanded) {\n paths = paths.concat(child.getAllCollapsedNodePath());\n }\n else {\n paths.push(child.path);\n }\n }\n return paths;\n }\n else {\n return paths;\n }\n }\n /**\n * 处理节点数据,让节点重新加载子节点及初始化 flattenedBranch\n * @param token CancellationToken\n */\n resolveChildrens(token) {\n var _a, _b, _c;\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n let childrens = this.children;\n let expandedPaths = [];\n try {\n childrens = (yield this._tree.resolveChildren(this)) || [];\n }\n catch (e) {\n childrens = [];\n }\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return false;\n }\n const flatTree = new Array(childrens.length);\n this._children = Array(childrens.length);\n for (let i = 0; i < childrens.length; i++) {\n const child = childrens[i];\n // 如果存在上一次缓存的节点,则使用缓存节点的 ID\n child.id = TreeNode.getIdByPath(child.path) || child.id;\n this._children[i] = child;\n TreeNode.setIdByPath(child.path, child.id);\n }\n (_a = this._children) === null || _a === void 0 ? void 0 : _a.sort(this._tree.sortComparator || CompositeTreeNode.defaultSortComparator);\n for (let i = 0; i < childrens.length; i++) {\n flatTree[i] = this._children[i].id;\n }\n const expandedChilds = [];\n for (let i = 0, len = ((_b = this.children) === null || _b === void 0 ? void 0 : _b.length) || 0; i < len; i++) {\n const subChild = (_c = this.children) === null || _c === void 0 ? void 0 : _c[i];\n if (CompositeTreeNode.is(subChild) && subChild.expanded) {\n const paths = yield subChild.resolveChildrens(token);\n if (paths) {\n expandedPaths = expandedPaths.concat(paths);\n }\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return;\n }\n expandedChilds.push(subChild);\n }\n }\n this._branchSize = flatTree.length;\n this.setFlattenedBranch(flatTree);\n for (let i = 0; i < expandedChilds.length; i++) {\n const child = expandedChilds[i];\n child.expandBranch(child, true);\n }\n return expandedPaths.concat(expandedChilds.map((child) => child.path.toString()));\n });\n }\n updateTreeNodeCache(child) {\n var _a;\n TreeNode.setTreeNode(child.id, child.path, child);\n if (CompositeTreeNode.is(child) && child.expanded && ((_a = child.children) === null || _a === void 0 ? void 0 : _a.length)) {\n for (let i = 0; i < child.children.length; i++) {\n const subChild = child.children[i];\n this.updateTreeNodeCache(subChild);\n }\n }\n }\n /**\n * 静默刷新子节点, 即不触发分支更新事件\n * @param toExpandPaths 待展开的路径\n * @param token CancellationToken\n * @param origin 当 this === origin 时,说明此节点为调用的源头节点\n */\n refreshTreeNodeByPaths(toExpandPaths = this.getAllExpandedNodePath(), token, origin) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n if (!CompositeTreeNode.is(this)) {\n return;\n }\n // 如果某次刷新操作被取消,则下次刷新依旧使用上一次刷新的展开目录进行刷新\n let toExpandPath;\n const originChildren = this.children;\n let childrens = this.children || [];\n if (this.expanded) {\n if (this === origin) {\n try {\n childrens = (yield this._tree.resolveChildren(this)) || [];\n }\n catch (e) {\n childrens = [];\n }\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return;\n }\n if (!this.expanded) {\n // 当请求刷新节点时,如果该节点已经不应该被处理,则清理 Children\n // 下次再被展开时便会自动更新 Children 最新内容\n if (this.children) {\n // 清理子节点,等待下次展开时更新\n if (!!this.children && this.parent) {\n for (let i = 0; i < this.children.length; i++) {\n const child = this.children[i];\n child.dispose();\n }\n this._children = null;\n }\n }\n return;\n }\n }\n while ((toExpandPath = toExpandPaths.shift())) {\n const isRelative = toExpandPath.indexOf(`${this.path}${Path.separator}`) > -1;\n if (!isRelative) {\n if (toExpandPath === this.path) {\n toExpandPath = undefined;\n }\n break;\n }\n const child = childrens === null || childrens === void 0 ? void 0 : childrens.find((child) => child.path === toExpandPath);\n // 对于压缩情况的路径需要额外处理一下\n // 如果这里加载的路径是 a/b/c, 有可能目前只加载到 a/b\n if (!child) {\n if (!childrens || childrens.length === 0) {\n break;\n }\n for (let i = 0; i < childrens.length; i++) {\n const child = childrens[i];\n const isInclude = toExpandPath.indexOf(`${child.path}${Path.separator}`) === 0; // 展开路径包含子节点路径\n if (isInclude && CompositeTreeNode.is(child)) {\n // 包含压缩节点的情况\n if (!CompositeTreeNode.is(child)) {\n // 说明此节点为非折叠节点时不处理\n continue;\n }\n child.isExpanded = true;\n // 加载路径包含当前判断路径,尝试加载该节点再匹配\n const extraExpandedPaths = yield child.resolveChildrens(token);\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return;\n }\n if (extraExpandedPaths) {\n toExpandPaths = toExpandPaths.filter((path) => !extraExpandedPaths.find((a) => a === path));\n }\n if (child.path !== toExpandPath && !toExpandPaths.includes(child.path)) {\n toExpandPaths.unshift(toExpandPath);\n }\n if (toExpandPaths.length > 0) {\n // 不需要重新加载压缩节点的子节点内容\n toExpandPaths =\n (yield child.refreshTreeNodeByPaths([...toExpandPaths], token, origin)) || [];\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return;\n }\n }\n break;\n }\n }\n }\n else if (CompositeTreeNode.is(child)) {\n // 如果节点默认展开,则忽略后续操作\n if (!child.expanded) {\n child.isExpanded = true;\n const extraExpandedPaths = yield child.resolveChildrens(token);\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return;\n }\n if (extraExpandedPaths) {\n toExpandPaths = toExpandPaths.filter((path) => !extraExpandedPaths.find((a) => a.includes(path)));\n }\n if (toExpandPaths.length > 0 && !(token === null || token === void 0 ? void 0 : token.isCancellationRequested)) {\n toExpandPaths =\n (yield child.refreshTreeNodeByPaths([...toExpandPaths], token, origin)) || [];\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return;\n }\n }\n }\n }\n }\n if (toExpandPath) {\n // 仍然存在需要进一步处理的待展开路径\n toExpandPaths.unshift(toExpandPath);\n if (this === origin) {\n // 说明待展开的路径已经不存在,直接处理子节点\n if (originChildren) {\n this.shrinkBranch(this, true);\n for (let i = 0; i < originChildren.length; i++) {\n const child = originChildren[i];\n child === null || child === void 0 ? void 0 : child.dispose();\n }\n }\n const expandedChilds = [];\n const flatTree = new Array(childrens.length);\n this._children = Array(childrens.length);\n for (let i = 0; i < childrens.length; i++) {\n const child = childrens[i];\n // 如果存在上一次缓存的节点,则使用缓存节点的 ID\n child.id = TreeNode.getIdByPath(child.path) || child.id;\n this._children[i] = child;\n TreeNode.setIdByPath(child.path, child.id);\n if (CompositeTreeNode.is(child) && child.expanded) {\n expandedChilds.push(child);\n }\n }\n this._children.sort(this._tree.sortComparator || CompositeTreeNode.defaultSortComparator);\n for (let i = 0; i < childrens.length; i++) {\n flatTree[i] = this._children[i].id;\n }\n this._branchSize = flatTree.length;\n this.setFlattenedBranch(flatTree, true);\n this.watcher.notifyDidUpdateBranch();\n }\n if (this.parent !== origin) {\n // 将所有子节点合并至第二层 Children 上,减少后续递归拼接带来额外成本\n this.expandBranch(this, true);\n }\n return toExpandPaths;\n }\n else if (CompositeTreeNode.isRoot(this)) {\n if (this.children) {\n this.shrinkBranch(this, true);\n for (let i = 0; i < this.children.length; i++) {\n const child = this.children[i];\n child === null || child === void 0 ? void 0 : child.dispose();\n }\n }\n const expandedChilds = [];\n const otherChilds = [];\n const flatTree = new Array(childrens.length);\n this._children = Array(childrens.length);\n for (let i = 0; i < childrens.length; i++) {\n const child = childrens[i];\n // 如果存在上一次缓存的节点,则使用缓存节点的 ID\n child.id = TreeNode.getIdByPath(child.path) || child.id;\n this._children[i] = child;\n TreeNode.setIdByPath(child.path, child.id);\n if (CompositeTreeNode.is(child) && child.expanded) {\n if (!child.children) {\n yield child.resolveChildrens(token);\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return;\n }\n }\n expandedChilds.push(child);\n }\n else {\n otherChilds.push(child);\n }\n }\n this._children.sort(this._tree.sortComparator || CompositeTreeNode.defaultSortComparator);\n for (let i = 0; i < childrens.length; i++) {\n flatTree[i] = this._children[i].id;\n }\n this._branchSize = flatTree.length;\n this.setFlattenedBranch(flatTree, true);\n for (let i = 0; i < expandedChilds.length; i++) {\n const child = expandedChilds[i];\n child.expandBranch(child, true);\n this.updateTreeNodeCache(child);\n }\n for (let i = 0; i < otherChilds.length; i++) {\n const child = otherChilds[i];\n this.updateTreeNodeCache(child);\n }\n // 清理上一次监听函数\n if (typeof this.watchTerminator === 'function') {\n this.watchTerminator(this.path);\n }\n this.watchTerminator = this.watcher.onWatchEvent(this.path, this.handleWatchEvent);\n this.watcher.notifyDidUpdateBranch();\n }\n else {\n // 非根节点刷新的情况\n const expandedChilds = [];\n if (this === origin) {\n // 通知节点更新\n if (this.children) {\n // 重置旧的节点分支\n this.shrinkBranch(this, true);\n }\n if (this.children) {\n for (let i = 0, len = this.children.length; i < len; i++) {\n const child = this.children[i];\n child.dispose();\n }\n }\n const flatTree = new Array(childrens.length);\n this._children = Array(childrens.length);\n for (let i = 0, len = childrens.length; i < len; i++) {\n const child = childrens[i];\n child.id = TreeNode.getIdByPath(child.path) || child.id;\n this._children[i] = child;\n TreeNode.setIdByPath(child.path, child.id);\n if (CompositeTreeNode.is(child) && child.expanded) {\n expandedChilds.push(child);\n }\n this.updateTreeNodeCache(child);\n }\n this._children.sort(this._tree.sortComparator || CompositeTreeNode.defaultSortComparator);\n for (let i = 0; i < childrens.length; i++) {\n flatTree[i] = this._children[i].id;\n }\n this._branchSize = flatTree.length;\n this.setFlattenedBranch(flatTree);\n for (let i = 0; i < expandedChilds.length; i++) {\n const child = expandedChilds[i];\n child.expandBranch(child, true);\n }\n }\n else {\n for (let i = 0; i < childrens.length; i++) {\n const child = childrens[i];\n if (child.expanded) {\n expandedChilds.push(child);\n }\n }\n }\n for (let i = 0; i < expandedChilds.length; i++) {\n const child = expandedChilds[i];\n child.expandBranch(child, true);\n }\n if (typeof this.watchTerminator === 'function') {\n this.watchTerminator(this.path);\n }\n this.watchTerminator = this.watcher.onWatchEvent(this.path, this.handleWatchEvent);\n if (this === origin) {\n this.expandBranch(this);\n }\n }\n }\n else {\n // 仅需处理存在子节点的情况,否则将会影响刷新后的节点长度\n if (this.children) {\n // 清理子节点,等待下次展开时更新\n if (!!this.children && this.parent) {\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0, len = this.children.length; i < len; i++) {\n const child = this.children[i];\n child.dispose();\n }\n this._children = null;\n }\n }\n return;\n }\n });\n }\n expandedAll(collapsedPaths = this.getAllCollapsedNodePath()) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n // 仅根节点使用\n if (!CompositeTreeNode.isRoot(this)) {\n return;\n }\n collapsedPaths = (0, path_1.sortPathByDepth)(collapsedPaths);\n let path;\n while (collapsedPaths.length > 0) {\n path = collapsedPaths.pop();\n const item = TreeNode.getTreeNodeByPath(path);\n if (CompositeTreeNode.is(item)) {\n yield item.setExpanded(false, true);\n }\n }\n // 通知分支树已更新\n this.watcher.notifyDidUpdateBranch();\n });\n }\n collapsedAll(expandedPaths = this.getAllExpandedNodePath()) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n // 仅根节点使用\n if (!CompositeTreeNode.isRoot(this)) {\n return;\n }\n expandedPaths = (0, path_1.sortPathByDepth)(expandedPaths);\n let path;\n while (expandedPaths.length > 0) {\n path = expandedPaths.pop();\n const item = TreeNode.getTreeNodeByPath(path);\n if (CompositeTreeNode.is(item)) {\n item.setCollapsed(true);\n }\n }\n // 通知分支树已更新\n this.watcher.notifyDidUpdateBranch();\n });\n }\n // 折叠节点\n setCollapsed(quiet = false) {\n // 根节点不可折叠\n if (CompositeTreeNode.isRoot(this) || this.disposed) {\n return;\n }\n if (!this.isExpanded) {\n return;\n }\n const state = TreeNode.getGlobalTreeState(this.path);\n if (state.isExpanding) {\n // 当节点处于加载子节点过程时,尽管为展开状态,但此时不应该支持折叠节点\n return;\n }\n state.loadPathCancelToken.cancel();\n state.refreshCancelToken.cancel();\n this._watcher.notifyWillChangeExpansionState(this, false);\n if (this._children && this.parent) {\n // 从根节点裁剪分支\n this.shrinkBranch(this, quiet);\n }\n this.isExpanded = false;\n TreeNode.setTreeNode(this.id, this.path, this);\n this._watcher.notifyDidChangeExpansionState(this, false);\n }\n mv(to, name = this.name) {\n const prevPath = this.path;\n super.mv(to, name);\n if (typeof this.watchTerminator === 'function') {\n this.watchTerminator(prevPath);\n this.watchTerminator = this.watcher.onWatchEvent(this.path, this.handleWatchEvent);\n }\n // 同时移动过子节点\n if (this.children) {\n for (let i = 0; i < this.children.length; i++) {\n const child = this.children[i];\n child.mv(child.parent, child.name);\n }\n }\n }\n /**\n * 在节点中插入新的节点\n *\n * 直接调用此方法将不会触发onWillHandleWatchEvent和onDidHandleWatchEvent事件\n */\n insertItem(item) {\n if (item.parent !== this) {\n item.mv(this, item.name);\n return;\n }\n if (this.children) {\n for (let i = 0; i < this.children.length; i++) {\n // path / id 是节点唯一标识\n if (this.children[i].path === item.path) {\n this.children[i] = item;\n return;\n }\n }\n }\n const branchSizeIncrease = 1 + (item instanceof CompositeTreeNode && item.expanded ? item._branchSize : 0);\n if (this._children) {\n this._children.push(item);\n this._children.sort(this._tree.sortComparator || CompositeTreeNode.defaultSortComparator);\n }\n this._branchSize += branchSizeIncrease;\n let master = this;\n // 如果该节点无叶子节点,则继续往上查找合适的插入位置\n while (!master._flattenedBranch) {\n if (master.parent) {\n master = master.parent;\n master._branchSize += branchSizeIncrease;\n }\n }\n if (!this._children) {\n return;\n }\n let relativeInsertionIndex = this._children.indexOf(item);\n let absInsertionIndex;\n const leadingSibling = this._children[relativeInsertionIndex - 1];\n if (leadingSibling) {\n const siblingIdx = master._flattenedBranch.indexOf(leadingSibling.id);\n relativeInsertionIndex =\n siblingIdx +\n (leadingSibling instanceof CompositeTreeNode && leadingSibling.expanded ? leadingSibling._branchSize : 0);\n }\n else {\n relativeInsertionIndex = master._flattenedBranch.indexOf(this.id);\n }\n if (relativeInsertionIndex === -1) {\n if (this._branchSize === 1) {\n // 在空Tree中插入节点时,相对插入位置为0\n relativeInsertionIndex = 0;\n }\n }\n // 非空Tree情况下需要+1,为了容纳自身节点位置,在插入节点下方插入新增节点\n absInsertionIndex = relativeInsertionIndex + 1;\n // 空 Tree 情况下需要重置为 0,避免设置 Uint32Array 时超出范围\n if (master._flattenedBranch.length === 0) {\n absInsertionIndex = 0;\n }\n let branch = [item.id];\n if (item instanceof CompositeTreeNode && item.expanded && item._flattenedBranch) {\n branch = branch.concat(item._flattenedBranch);\n item.setFlattenedBranch(null);\n }\n master.setFlattenedBranch(spliceArray(master._flattenedBranch, absInsertionIndex, 0, branch));\n TreeNode.setTreeNode(item.id, item.path, item);\n return item;\n }\n /**\n * 从父节点中移除节点\n *\n * 直接调用此方法将不会触发onWillHandleWatchEvent和onDidHandleWatchEvent事件\n */\n unlinkItem(item, reparenting) {\n var _a;\n if (!this._children) {\n return;\n }\n const idx = this._children.indexOf(item);\n if (idx === -1) {\n return;\n }\n // 当删除时父节点已不存在界面上时,跳过插入操作\n if (!this.isItemVisibleAtRootSurface(this)) {\n return;\n }\n (_a = this._children) === null || _a === void 0 ? void 0 : _a.splice(idx, 1);\n const branchSizeDecrease = 1 + (item instanceof CompositeTreeNode && item.expanded ? item._branchSize : 0);\n this._branchSize -= branchSizeDecrease;\n // 逐级往上查找节点的父节点,并沿途裁剪分支数\n let master = this;\n while (!master._flattenedBranch) {\n if (master.parent) {\n master = master.parent;\n master._branchSize -= branchSizeDecrease;\n }\n }\n const removalBeginIdx = master._flattenedBranch.indexOf(item.id);\n if (removalBeginIdx === -1) {\n return;\n }\n if (item instanceof CompositeTreeNode && item.expanded) {\n item.setFlattenedBranch(master._flattenedBranch.slice(removalBeginIdx + 1, removalBeginIdx + branchSizeDecrease));\n }\n master.setFlattenedBranch(spliceArray(master._flattenedBranch, removalBeginIdx, branchSizeDecrease));\n if (!reparenting && item.parent === this) {\n item.mv(null);\n }\n }\n /**\n * 转换节点路径\n */\n transferItem(oldPath, newPath) {\n var _a;\n const oldP = path_2.treePath.parse(oldPath);\n const from = oldP.dirname;\n if (from !== this.path) {\n return;\n }\n const name = oldP.basename;\n const item = (_a = this._children) === null || _a === void 0 ? void 0 : _a.find((c) => c.name === name);\n if (!item) {\n return;\n }\n const newP = path_2.treePath.parse(newPath);\n const to = newP.dirname;\n const destDir = to === from ? this : TreeNode.getTreeNodeByPath(to);\n if (!CompositeTreeNode.is(destDir)) {\n this.unlinkItem(item);\n return;\n }\n item.mv(destDir, newP.basename);\n return item;\n }\n dispose() {\n // 如果存在对应文件路径下的监听,同样需要清理掉\n if (this.watchEvents) {\n const watcher = this.watchEvents.get(this.path);\n if (watcher) {\n watcher.terminator();\n }\n this.watchEvents.clear();\n }\n if (this._children) {\n // 移除后应该折叠,因为下次初始化默认值为折叠,否则将会导致下次插入异常\n this.isExpanded = false;\n this._children.forEach((child) => {\n child.dispose();\n });\n this._children = null;\n this._flattenedBranch = null;\n }\n super.dispose();\n }\n /**\n * 设置扁平化的分支信息\n */\n setFlattenedBranch(leaves, withoutNotify) {\n this._flattenedBranch = leaves;\n // Root节点才通知更新\n if (CompositeTreeNode.isRoot(this) && !withoutNotify) {\n this.watcher.notifyDidUpdateBranch();\n }\n }\n /**\n * 展开分支节点\n * @param branch 分支节点\n */\n expandBranch(branch, withoutNotify) {\n if (this !== branch) {\n // 但节点为展开状态时进行裁剪\n if (branch._flattenedBranch) {\n this._branchSize += branch._branchSize;\n }\n }\n // 当前节点为折叠状态,更新分支信息\n if (this !== branch && this._flattenedBranch) {\n const injectionStartIdx = this._flattenedBranch.indexOf(branch.id) + 1;\n if (injectionStartIdx === 0) {\n // 中途发生了branch更新事件,此时的_flattenedBranch可能已被更新,即查找不到branch.id\n // 这种情况在父节点发生了多路径目录的创建定位动作下更易复现\n // 例:文件树在执行a/b/c定位操作时需要请求三次数据,而更新操作可能只需要一次\n // 导致就算更新操作后置执行,也可能比定位操作先执行完,同时将_flattenedBranch更新\n // 最终导致此处查询不到对应节点,下面的shrinkBranch同样可能有相同问题,如点击折叠全部功能时\n return;\n }\n this.setFlattenedBranch(spliceArray(this._flattenedBranch, injectionStartIdx, 0, branch._flattenedBranch), withoutNotify);\n // 取消展开分支对于分支的所有权,即最终只会有顶部Root拥有所有分支信息\n branch.setFlattenedBranch(null, withoutNotify);\n }\n else if (this.parent) {\n this.parent.expandBranch(branch, withoutNotify);\n }\n }\n /**\n * 清理分支节点\n * @param branch 分支节点\n */\n shrinkBranch(branch, withoutNotify) {\n if (this !== branch) {\n // 这里的`this`实际上为父节点\n // `this`的分支大小没有改变,仍然具有相同数量的叶子,但是从父级参照系(即根节点)来看,其分支缩小了\n this._branchSize -= branch._branchSize;\n }\n if (this !== branch && this._flattenedBranch) {\n const removalStartIdx = this._flattenedBranch.indexOf(branch.id) + 1;\n if (removalStartIdx === 0) {\n // 中途发生了branch更新事件,此时的_flattenedBranch可能已被更新,即查找不到branch.id\n return;\n }\n // 返回分支对于分支信息所有权,即将折叠的节点信息再次存储于折叠了的节点中\n branch.setFlattenedBranch(this._flattenedBranch.slice(removalStartIdx, removalStartIdx + branch._branchSize), withoutNotify);\n this.setFlattenedBranch(spliceArray(this._flattenedBranch, removalStartIdx, branch._flattenedBranch ? branch._flattenedBranch.length : 0), withoutNotify);\n }\n else if (this.parent) {\n this.parent.shrinkBranch(branch, withoutNotify);\n }\n }\n /**\n * 加载子节点信息\n * 当返回值为 true 时,正常加载完子节点并同步到数据结构中\n * 返回值为 false 时,加载节点的过程被中断\n *\n * @memberof CompositeTreeNode\n */\n hardReloadChildren(token) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n let rawItems;\n const oldPath = this.path;\n try {\n // ! `this.path` maybe changed after `resolveChildren` in file tree compact mode\n rawItems = (yield this._tree.resolveChildren(this)) || [];\n }\n catch (e) {\n rawItems = [];\n }\n // 当获取到新的子节点时,如果当前节点正处于非展开状态时,忽略后续裁切逻辑\n // 后续的 expandBranch 也不应该被响应\n if (!this.expanded || (token === null || token === void 0 ? void 0 : token.isCancellationRequested)) {\n return false;\n }\n if (this.path !== oldPath) {\n // do some clean up\n TreeNode.setGlobalTreeState(oldPath, {\n isExpanding: false,\n isLoadingPath: false,\n isRefreshing: false,\n });\n }\n const expandedChilds = [];\n const flatTree = new Array(rawItems.length);\n const tempChildren = new Array(rawItems.length);\n for (let i = 0; i < rawItems.length; i++) {\n const child = rawItems[i];\n child.id = TreeNode.getIdByPath(child.path) || child.id;\n tempChildren[i] = child;\n TreeNode.setIdByPath(child.path, child.id);\n if (CompositeTreeNode.is(child) && child.expanded) {\n if (!child.children) {\n yield child.resolveChildrens(token);\n }\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return false;\n }\n expandedChilds.push(child);\n }\n }\n tempChildren.sort(this._tree.sortComparator || CompositeTreeNode.defaultSortComparator);\n for (let i = 0; i < rawItems.length; i++) {\n flatTree[i] = tempChildren[i].id;\n }\n if (this.children) {\n this.shrinkBranch(this);\n }\n if (this.children) {\n for (let i = 0; i < this.children.length; i++) {\n const child = this.children[i];\n // The Child maybe `undefined`.\n child === null || child === void 0 ? void 0 : child.dispose();\n }\n }\n for (let i = 0; i < tempChildren.length; i++) {\n this.updateTreeNodeCache(tempChildren[i]);\n }\n this._children = tempChildren;\n this._branchSize = flatTree.length;\n this.setFlattenedBranch(flatTree);\n for (let i = 0; i < expandedChilds.length; i++) {\n const child = expandedChilds[i];\n child.expandBranch(child, true);\n }\n // 清理上一次监听函数\n if (typeof this.watchTerminator === 'function') {\n this.watchTerminator(this.path);\n }\n this.watchTerminator = this.watcher.onWatchEvent(this.path, this.handleWatchEvent);\n return true;\n });\n }\n moveNode(oldPath, newPath) {\n if (typeof oldPath !== 'string') {\n throw new TypeError('Expected oldPath to be a string');\n }\n if (typeof newPath !== 'string') {\n throw new TypeError('Expected newPath to be a string');\n }\n if (Path.isRelative(oldPath)) {\n throw new TypeError('oldPath must be absolute');\n }\n if (Path.isRelative(newPath)) {\n throw new TypeError('newPath must be absolute');\n }\n return this.transferItem(oldPath, newPath);\n }\n addNode(node) {\n if (!TreeNode.is(node)) {\n throw new TypeError('Expected node to be a TreeNode');\n }\n return this.insertItem(node);\n }\n removeNode(path) {\n const { basename, dirname } = path_2.treePath.parse(path);\n if (dirname === this.path && !!this.children) {\n const item = this.children.find((c) => c.name === basename);\n if (item) {\n this.unlinkItem(item);\n }\n }\n }\n // 当没有传入具体路径时,使用当前展开目录作为刷新路径\n refresh(tokenSource, target) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n if (!CompositeTreeNode.isRoot(this)) {\n // 刷新操作只能从根节点进行,便于对重复的刷新操作进行合并\n return yield this.root.refresh(tokenSource, this);\n }\n const state = TreeNode.getGlobalTreeState(this.path);\n if (state.isLoadingPath || state.isExpanding) {\n return;\n }\n let token;\n if (tokenSource && !tokenSource.token.isCancellationRequested) {\n TreeNode.setGlobalTreeState(this.path, {\n isRefreshing: true,\n refreshCancelToken: tokenSource,\n });\n token = tokenSource.token;\n }\n else {\n if (state.refreshCancelToken.token.isCancellationRequested) {\n const refreshCancelToken = new ide_utils_1.CancellationTokenSource();\n TreeNode.setGlobalTreeState(this.path, {\n isRefreshing: true,\n refreshCancelToken,\n });\n token = refreshCancelToken.token;\n }\n else {\n token = state.refreshCancelToken.token;\n }\n }\n this.toRefreshPathQueue.add((target || this).path);\n yield this.refreshThrottler.trigger(() => this.doRefresh(token));\n TreeNode.setGlobalTreeState(this.path, {\n isRefreshing: false,\n });\n });\n }\n doRefresh(token) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n const target = this.getRefreshNode() || this;\n if (!CompositeTreeNode.is(target)) {\n return;\n }\n const paths = target.getAllExpandedNodePath();\n yield target.refreshTreeNodeByPaths(paths, token, target);\n });\n }\n getRefreshNode() {\n const paths = (0, path_1.sortPathByDepth)(Array.from(this.toRefreshPathQueue));\n this.toRefreshPathQueue.clear();\n if (!paths.length) {\n return this.root;\n }\n if (paths.length === 1 || Path.pathDepth(paths[0]) === 1) {\n // 说明刷新队列中包含根节点,直接返回根节点进行刷新\n return TreeNode.getTreeNodeByPath(paths[0]);\n }\n const rootPath = (0, path_1.findCommonRoot)(paths);\n if (rootPath) {\n return TreeNode.getTreeNodeByPath(rootPath);\n }\n return this.root;\n }\n isItemVisibleAtRootSurface(node) {\n let parent = node;\n while (parent.parent) {\n parent = parent.parent;\n }\n return parent.isItemVisibleAtSurface(node);\n }\n /**\n * 检查节点是否可见,而不是被隐藏在节点中\n *\n * 这里的可见并不表示节点在当前视图中可见,而是在用户滚动到特定位置便可看见\n *\n * 隐藏在节点中可能的原因为其父节点中有一个以上处于折叠状态\n */\n isItemVisibleAtSurface(item) {\n if (item === this) {\n return true;\n }\n return !!this._flattenedBranch && this._flattenedBranch.indexOf(item.id) > -1;\n }\n transformToRelativePath(path) {\n const pathFlag = Path.splitPath(path);\n pathFlag.shift();\n return pathFlag;\n }\n /**\n * 根据路径展开节点树\n */\n loadTreeNodeByPath(path, quiet = false) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n if (!CompositeTreeNode.isRoot(this)) {\n return;\n }\n const state = TreeNode.getGlobalTreeState(this.path);\n if (state.isExpanding) {\n return;\n }\n state.refreshCancelToken.cancel();\n state.loadPathCancelToken.cancel();\n const loadPathCancelToken = new ide_utils_1.CancellationTokenSource();\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: true,\n loadPathCancelToken,\n });\n const token = loadPathCancelToken.token;\n const flattenedBranchChilds = [];\n const { splitPath, isRelative } = Path;\n const pathFlag = isRelative(path) ? splitPath(path) : this.transformToRelativePath(path);\n if (pathFlag.length === 0) {\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: false,\n });\n return this;\n }\n if (!this.children) {\n yield this.ensureLoaded(token);\n }\n if (token.isCancellationRequested) {\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: false,\n });\n return;\n }\n let next = this._children;\n let preItem;\n let preItemPath = '';\n let name;\n while (next && (name = pathFlag.shift())) {\n let item = next.find((c) => c.name.indexOf(name) === 0);\n if (item) {\n if (CompositeTreeNode.is(item)) {\n item._watcher.notifyWillChangeExpansionState(item, true);\n item.isExpanded = true;\n if (!item.children) {\n yield item.resolveChildrens(token);\n if (token.isCancellationRequested) {\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: false,\n });\n return;\n }\n }\n flattenedBranchChilds.push(item);\n item._watcher.notifyDidChangeExpansionState(item, true);\n }\n if (pathFlag.length === 0) {\n preItem = item;\n break;\n }\n }\n // 可能展开后路径发生了变化, 需要重新处理一下当前加载路径\n if (!item && preItem) {\n const compactPath = splitPath(preItem.name).slice(1);\n if (compactPath[0] === name) {\n compactPath.shift();\n while (compactPath.length > 0) {\n if (compactPath[0] === pathFlag[0]) {\n compactPath.shift();\n pathFlag.shift();\n }\n else {\n break;\n }\n }\n name = pathFlag.shift();\n item = next.find((c) => c.name.indexOf(name) === 0);\n }\n }\n // 最终加载到的路径节点\n if (!item || (!CompositeTreeNode.is(item) && pathFlag.length > 0)) {\n break;\n }\n if (CompositeTreeNode.is(item)) {\n const isCompactName = item.name.indexOf(Path.separator) > 0;\n if (isCompactName) {\n const compactPath = splitPath(item.name).slice(1);\n while (compactPath.length > 0) {\n if (compactPath[0] === pathFlag[0]) {\n compactPath.shift();\n pathFlag.shift();\n }\n else {\n break;\n }\n }\n }\n if (!item._children) {\n preItemPath = item.path;\n if (CompositeTreeNode.is(item)) {\n item.isExpanded = true;\n if (!item.children) {\n yield item.resolveChildrens(token);\n if (token.isCancellationRequested) {\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: false,\n });\n return;\n }\n }\n flattenedBranchChilds.push(item);\n }\n }\n if (item && pathFlag.length === 0) {\n preItem = item;\n break;\n }\n else {\n if (!!preItemPath && preItemPath !== item.path) {\n // 说明此时已发生了路径压缩,如从 a -> a/b/c\n // 需要根据路径变化移除对应的展开路径, 这里只需考虑短变长场景\n const prePaths = splitPath(preItemPath);\n const nextPaths = splitPath(item.path);\n if (nextPaths.length > prePaths.length) {\n pathFlag.splice(0, nextPaths.length - prePaths.length);\n }\n }\n next = item._children;\n preItem = item;\n }\n }\n }\n if (preItem) {\n let child;\n if (preItem.disposed) {\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: false,\n });\n return;\n }\n while ((child = flattenedBranchChilds.pop())) {\n child.expandBranch(child, true);\n if (flattenedBranchChilds.length === 0) {\n this.updateTreeNodeCache(child);\n }\n }\n if (!quiet) {\n this.watcher.notifyDidUpdateBranch();\n }\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: false,\n });\n return preItem;\n }\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: false,\n });\n });\n }\n /**\n * 根据节点获取节点ID下标位置\n * @param {number} id\n * @returns\n */\n getIndexAtTreeNodeId(id) {\n if (this._flattenedBranch) {\n return this._flattenedBranch.indexOf(id);\n }\n return -1;\n }\n /**\n * 根据节点获取节点下标位置\n * @param {ITreeNodeOrCompositeTreeNode} node\n * @returns\n */\n getIndexAtTreeNode(node) {\n if (this._flattenedBranch) {\n return this._flattenedBranch.indexOf(node.id);\n }\n return -1;\n }\n /**\n * 根据下标位置获取节点\n * @param {number} index\n * @returns\n */\n getTreeNodeAtIndex(index) {\n var _a;\n const id = (_a = this._flattenedBranch) === null || _a === void 0 ? void 0 : _a[index];\n if (!id) {\n return undefined;\n }\n return TreeNode.getTreeNodeById(id);\n }\n /**\n * 根据节点ID获取节点\n * @param {number} id\n * @returns\n */\n getTreeNodeById(id) {\n return TreeNode.getTreeNodeById(id);\n }\n /**\n * 根据节点路径获取节点\n * @param {string} path\n * @returns\n */\n getTreeNodeByPath(path) {\n return TreeNode.getTreeNodeByPath(path);\n }\n}\nexports.CompositeTreeNode = CompositeTreeNode;\nCompositeTreeNode.REFRESH_DELAY = 200;\n\n\n//# sourceURL=webpack://@opensumi/ide-components/./src/recycle-tree/tree/TreeNode.ts?");
5427
+ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.CompositeTreeNode = exports.TreeNode = exports.BranchOperatorStatus = exports.spliceArray = void 0;\nconst tslib_1 = __webpack_require__(/*! tslib */ \"../../node_modules/tslib/tslib.es6.mjs\");\n/* eslint-disable @typescript-eslint/prefer-for-of */\nconst ide_utils_1 = __webpack_require__(/*! @opensumi/ide-utils */ \"../utils/lib/index.js\");\nconst types_1 = __webpack_require__(/*! ../types */ \"./src/recycle-tree/types/index.ts\");\nconst { Path } = ide_utils_1.path;\n/**\n * 裁剪数组\n *\n * @param arr 裁剪数组\n * @param start 起始位置\n * @param deleteCount 删除或替换位置\n * @param items 插入的数组\n */\nfunction spliceArray(arr, start, deleteCount = 0, items) {\n const a = arr.slice(0);\n a.splice(start, deleteCount, ...(items || []));\n return a;\n}\nexports.spliceArray = spliceArray;\nvar BranchOperatorStatus;\n(function (BranchOperatorStatus) {\n BranchOperatorStatus[BranchOperatorStatus[\"EXPANDED\"] = 1] = \"EXPANDED\";\n BranchOperatorStatus[BranchOperatorStatus[\"SHRINKED\"] = 2] = \"SHRINKED\";\n})(BranchOperatorStatus = exports.BranchOperatorStatus || (exports.BranchOperatorStatus = {}));\nclass TreeNode {\n static is(node) {\n return !!node && 'depth' in node && 'name' in node && 'path' in node && 'id' in node;\n }\n static getTreeNodeById(id) {\n return TreeNode.idToTreeNode.get(id);\n }\n static getTreeNodeByPath(path) {\n return TreeNode.pathToTreeNode.get(path);\n }\n static setTreeNode(id, path, node) {\n TreeNode.idToTreeNode.set(id, node);\n TreeNode.pathToTreeNode.set(path, node);\n }\n static removeTreeNode(id, path) {\n TreeNode.idToTreeNode.delete(id);\n TreeNode.pathToTreeNode.delete(path);\n }\n static getIdByPath(path) {\n return TreeNode.pathToId.get(path);\n }\n static setIdByPath(path, id) {\n return TreeNode.pathToId.set(path, id);\n }\n static getGlobalTreeState(path) {\n let state = TreeNode.pathToGlobalTreeState.get(path);\n if (!state) {\n state = {\n isExpanding: false,\n isLoadingPath: false,\n isRefreshing: false,\n refreshCancelToken: new ide_utils_1.CancellationTokenSource(),\n loadPathCancelToken: new ide_utils_1.CancellationTokenSource(),\n };\n }\n return state;\n }\n static setGlobalTreeState(path, updateState) {\n let state = TreeNode.pathToGlobalTreeState.get(path);\n if (!state) {\n state = {\n isExpanding: false,\n isLoadingPath: false,\n isRefreshing: false,\n refreshCancelToken: new ide_utils_1.CancellationTokenSource(),\n loadPathCancelToken: new ide_utils_1.CancellationTokenSource(),\n };\n }\n state = Object.assign(Object.assign({}, state), updateState);\n TreeNode.pathToGlobalTreeState.set(path, state);\n return state;\n }\n constructor(tree, parent, watcher, optionalMetadata) {\n this._uid = TreeNode.nextId();\n this._parent = parent;\n this._tree = tree;\n this._disposed = false;\n this._visible = true;\n this._metadata = Object.assign({}, (optionalMetadata || {}));\n this._depth = parent ? parent.depth + 1 : 0;\n if (watcher) {\n this._watcher = watcher;\n }\n else if (parent) {\n this._watcher = parent.watcher;\n }\n }\n get disposed() {\n return this._disposed;\n }\n /**\n * 获取基础信息\n */\n get depth() {\n return this._depth;\n }\n get parent() {\n return this._parent;\n }\n set parent(node) {\n this._parent = node;\n // 节点 `parent` 变化,更新当前节点的 `path` 属性\n this._path = '';\n }\n get type() {\n return types_1.TreeNodeType.TreeNode;\n }\n get id() {\n return this._uid;\n }\n set id(id) {\n this._uid = id;\n }\n get displayName() {\n return this.name;\n }\n /**\n * 由于 Tree 对于唯一路径的 path 的依赖\n * 在传入 `name` 值时必须保证其在路径上的唯一性\n * 一般不建议手动管理 `name`,采用默认值即可\n */\n get name() {\n if (!this.parent) {\n return `root_${this.id}`;\n }\n return this.getMetadata('name') || String(this.id);\n }\n set name(name) {\n this.addMetadata('name', name);\n // 节点 `name` 变化,更新当前节点的 `path` 属性\n this._path = '';\n }\n // 节点绝对路径\n get path() {\n if (!this._path) {\n if (!this.parent) {\n this._path = new Path(`${Path.separator}${this.name}`).toString();\n }\n else {\n this._path = new Path(this.parent.path).join(this.name).toString();\n }\n }\n return this._path;\n }\n get accessibilityInformation() {\n return {\n label: this.name,\n role: 'treeitem',\n };\n }\n getMetadata(withKey) {\n if (withKey === 'name' && !this._metadata[withKey]) {\n this._metadata[withKey] = String(TreeNode.nextId());\n }\n return this._metadata[withKey];\n }\n addMetadata(withKey, value) {\n if (!(withKey in this._metadata)) {\n this._metadata[withKey] = value;\n this._watcher.notifyDidChangeMetadata(this, {\n type: types_1.MetadataChangeType.Added,\n key: withKey,\n prevValue: void 0,\n value,\n });\n }\n else {\n const prevValue = this._metadata[withKey];\n this._metadata[withKey] = value;\n this._watcher.notifyDidChangeMetadata(this, { type: types_1.MetadataChangeType.Updated, key: withKey, prevValue, value });\n }\n }\n removeMetadata(withKey) {\n if (withKey in this._metadata) {\n const prevValue = this._metadata[withKey];\n delete this._metadata[withKey];\n this._watcher.notifyDidChangeMetadata(this, {\n type: types_1.MetadataChangeType.Removed,\n key: withKey,\n prevValue,\n value: void 0,\n });\n }\n }\n /**\n * 这里的move操作可能为移动,也可能为重命名\n *\n * @param {ICompositeTreeNode} to\n * @param {string} [name=this.name]\n * @returns\n * @memberof TreeNode\n */\n mv(to, name = this.name) {\n // 一个普通节点必含有父节点,根节点不允许任何操作\n const prevParent = this._parent;\n if (to === null || !CompositeTreeNode.is(to)) {\n this.parent = undefined;\n this.dispose();\n return;\n }\n const didChangeParent = prevParent !== to;\n const prevPath = this.path;\n this._depth = to.depth + 1;\n if (didChangeParent || name !== this.name) {\n this.name = name;\n if (didChangeParent) {\n this._watcher.notifyWillChangeParent(this, prevParent, to);\n }\n if (this.parent) {\n this.parent.unlinkItem(this, true);\n this.parent = to;\n this.parent.insertItem(this);\n }\n if (didChangeParent) {\n this._watcher.notifyDidChangeParent(this, prevParent, to);\n }\n }\n if (this.path !== prevPath) {\n this._watcher.notifyDidChangePath(this);\n }\n }\n get visible() {\n return this._visible;\n }\n setVisible(b) {\n this._visible = b;\n return this;\n }\n dispose() {\n if (this._disposed) {\n return;\n }\n TreeNode.removeTreeNode(this.id, this.path);\n this._disposed = true;\n this._watcher.notifyDidDispose(this);\n }\n}\nexports.TreeNode = TreeNode;\nTreeNode.nextId = (() => {\n let id = 0;\n return () => id++;\n})();\nTreeNode.idToTreeNode = new Map();\nTreeNode.pathToTreeNode = new Map();\nTreeNode.pathToId = new Map();\n// 每颗树都只会在根节点上绑定一个可取消的对象,即同个时间点只能存在一个改变树数据结构的事情\nTreeNode.pathToGlobalTreeState = new Map();\nclass CompositeTreeNode extends TreeNode {\n static defaultSortComparator(a, b) {\n if (a.constructor === b.constructor) {\n return a.name > b.name ? 1 : a.name < b.name ? -1 : 0;\n }\n return CompositeTreeNode.is(a) ? -1 : CompositeTreeNode.is(b) ? 1 : 0;\n }\n static is(node) {\n return !!node && 'children' in node;\n }\n static isRoot(node) {\n return CompositeTreeNode.is(node) && !node.parent;\n }\n generatorWatcher() {\n const emitter = new ide_utils_1.Emitter();\n const onEventChanges = emitter.event;\n const disposeCollection = new ide_utils_1.DisposableCollection();\n const terminateWatch = (path) => {\n this.watchEvents.delete(path);\n };\n const watcher = {\n notifyWillProcessWatchEvent: (target, event) => {\n emitter.fire({ type: types_1.TreeNodeEvent.WillProcessWatchEvent, args: [target, event] });\n },\n notifyWillChangeParent: (target, prevParent, newParent) => {\n emitter.fire({ type: types_1.TreeNodeEvent.WillChangeParent, args: [target, prevParent, newParent] });\n },\n notifyDidChangeParent: (target, prevParent, newParent) => {\n emitter.fire({ type: types_1.TreeNodeEvent.DidChangeParent, args: [target, prevParent, newParent] });\n },\n notifyDidDispose: (target) => {\n emitter.fire({ type: types_1.TreeNodeEvent.DidDispose, args: [target] });\n },\n notifyDidProcessWatchEvent: (target, event) => {\n emitter.fire({ type: types_1.TreeNodeEvent.DidProcessWatchEvent, args: [target, event] });\n },\n notifyDidChangePath: (target) => {\n emitter.fire({ type: types_1.TreeNodeEvent.DidChangePath, args: [target] });\n },\n notifyWillChangeExpansionState: (target, nowExpanded) => {\n const isVisible = this.isItemVisibleAtSurface(target);\n emitter.fire({ type: types_1.TreeNodeEvent.WillChangeExpansionState, args: [target, nowExpanded, isVisible] });\n },\n notifyDidChangeExpansionState: (target, nowExpanded) => {\n const isVisible = this.isItemVisibleAtSurface(target);\n emitter.fire({ type: types_1.TreeNodeEvent.DidChangeExpansionState, args: [target, nowExpanded, isVisible] });\n },\n notifyDidChangeMetadata: (target, change) => {\n emitter.fire({ type: types_1.TreeNodeEvent.DidChangeMetadata, args: [target, change] });\n },\n notifyDidUpdateBranch: () => {\n emitter.fire({ type: types_1.TreeNodeEvent.BranchDidUpdate, args: [] });\n },\n notifyWillResolveChildren: (target, nowExpanded) => {\n emitter.fire({ type: types_1.TreeNodeEvent.WillResolveChildren, args: [target, nowExpanded] });\n },\n notifyDidResolveChildren: (target, nowExpanded) => {\n emitter.fire({ type: types_1.TreeNodeEvent.DidResolveChildren, args: [target, nowExpanded] });\n },\n // 监听所有事件\n on: (event, callback) => {\n const dispose = onEventChanges((data) => {\n if (data.type === event) {\n callback(...data.args);\n }\n });\n disposeCollection.push(dispose);\n return dispose;\n },\n // 监听Watch事件变化\n onWatchEvent: (path, callback) => {\n const terminator = terminateWatch;\n this.watchEvents.set(path, { terminator, callback });\n return terminator;\n },\n dispose: disposeCollection,\n };\n return watcher;\n }\n // parent 为undefined即表示该节点为根节点\n constructor(tree, parent, watcher, optionalMetadata) {\n super(tree, parent, watcher, optionalMetadata);\n this._children = null;\n this._lock = false;\n this.refreshThrottler = new ide_utils_1.ThrottledDelayer(CompositeTreeNode.REFRESH_DELAY);\n this.toRefreshPathQueue = new Set();\n /**\n * 处理 Watch 事件,同时可通过外部手动调 g用节点更新函数进行节点替换,这里为通用的事件管理\n * 如: transferItem,insertItem, unlinkItem等\n * @private\n * @memberof CompositeTreeNode\n */\n this.handleWatchEvent = (event) => tslib_1.__awaiter(this, void 0, void 0, function* () {\n this.watcher.notifyWillProcessWatchEvent(this, event);\n switch (event.type) {\n case types_1.WatchEvent.Moved: {\n const { oldPath, newPath } = event;\n if (typeof oldPath !== 'string') {\n throw new TypeError('Expected oldPath to be a string');\n }\n if (typeof newPath !== 'string') {\n throw new TypeError('Expected newPath to be a string');\n }\n if (Path.isRelative(oldPath)) {\n throw new TypeError('oldPath must be absolute');\n }\n if (Path.isRelative(newPath)) {\n throw new TypeError('newPath must be absolute');\n }\n this.transferItem(oldPath, newPath);\n break;\n }\n case types_1.WatchEvent.Added: {\n const { node } = event;\n if (!TreeNode.is(node)) {\n throw new TypeError('Expected node to be a TreeNode');\n }\n this.insertItem(node);\n break;\n }\n case types_1.WatchEvent.Removed: {\n const { path } = event;\n const pathObject = new Path(path);\n const dirName = pathObject.dir.toString();\n const name = pathObject.base.toString();\n if (dirName === this.path && !!this.children) {\n const item = this.children.find((c) => c.name === name);\n if (item) {\n this.unlinkItem(item);\n }\n }\n break;\n }\n default:\n // 如果当前变化的节点已在数据视图(并非滚动到不可见区域)中不可见,则将该节点折叠,待下次更新即可,\n if (!this.isItemVisibleAtRootSurface(this)) {\n this.isExpanded = false;\n this._children = null;\n }\n else {\n yield this.refresh();\n }\n break;\n }\n this.watcher.notifyDidProcessWatchEvent(this, event);\n });\n this.isExpanded = parent ? false : true;\n this._branchSize = 0;\n if (!parent) {\n this.watchEvents = new Map();\n // 为根节点创建监听器\n this._watcher = this.generatorWatcher();\n this._root = this;\n TreeNode.setTreeNode(this.id, this.path, this);\n }\n else {\n this._watcher = parent.watcher;\n }\n }\n // 重载 name 的 getter/setter,路径改变时需要重新监听文件节点变化\n set name(name) {\n const prevPath = this.path;\n if (!CompositeTreeNode.isRoot(this) && typeof this.watchTerminator === 'function') {\n this.watchTerminator(prevPath);\n this.addMetadata('name', name);\n this.watchTerminator = this.watcher.onWatchEvent(this.path, this.handleWatchEvent);\n }\n else {\n this.addMetadata('name', name);\n }\n // 节点 `name` 变化,更新当前节点的 `path` 属性\n this._path = '';\n }\n get name() {\n // 根节点保证路径不重复\n if (!this.parent) {\n return `root_${this.id}`;\n }\n return this.getMetadata('name');\n }\n // 作为根节点唯一的watcher需要在生成新节点的时候传入\n get watcher() {\n return this._watcher;\n }\n get type() {\n return types_1.TreeNodeType.CompositeTreeNode;\n }\n get children() {\n return this._children;\n }\n get expanded() {\n return this.isExpanded;\n }\n /**\n * 当前可见的分支数量\n *\n * 当节点为展开状态时,其整个分支(递归展平)由上一级的分支(根(位于数据层可见)或处于折叠状态的分支)拥有\n * 当节点为折叠状态时,其整个分支(递归展平)由其上一级父目录展开该节点\n *\n * @readonly\n * @memberof CompositeTreeNode\n */\n get branchSize() {\n return this._branchSize;\n }\n /**\n * 获取当前节点的分支数,一般为顶层节点,如Root上获取\n *\n * @readonly\n * @memberof CompositeTreeNode\n */\n get flattenedBranch() {\n return this._flattenedBranch;\n }\n get lock() {\n return this._lock;\n }\n get root() {\n if ((0, ide_utils_1.isUndefined)(this._root)) {\n this._root = this.getRoot() || null;\n }\n return this._root;\n }\n getRoot() {\n let root = this.parent;\n while (root && root.parent) {\n root = root.parent;\n }\n return root;\n }\n /**\n * 确保此“目录”的子级已加载(不影响“展开”状态)\n * 如果子级已经加载,则返回的Promise将立即解决\n * 否则,将发出重新加载请求并返回Promise\n * 一旦返回的Promise.resolve,“CompositeTreeNode#children” 便可以访问到对于节点\n */\n ensureLoaded(token) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n if (this._children) {\n return;\n }\n return yield this.hardReloadChildren(token);\n });\n }\n // 展开节点\n setExpanded(ensureVisible = true, quiet = false, isOwner = true, token) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n if (this.disposed) {\n return;\n }\n // 根节点不可折叠\n if (CompositeTreeNode.isRoot(this)) {\n return;\n }\n if (this.isExpanded) {\n return;\n }\n if (isOwner) {\n const state = TreeNode.getGlobalTreeState(this.path);\n state.loadPathCancelToken.cancel();\n state.refreshCancelToken.cancel();\n TreeNode.setGlobalTreeState(this.path, {\n isExpanding: true,\n });\n }\n this.isExpanded = true;\n if (this._children === null) {\n this._watcher.notifyWillResolveChildren(this, this.isExpanded);\n yield this.hardReloadChildren(token);\n this._watcher.notifyDidResolveChildren(this, this.isExpanded);\n // 检查其是否展开;可能同时执行了 setCollapsed 方法\n if (!this.isExpanded || (token === null || token === void 0 ? void 0 : token.isCancellationRequested)) {\n if (isOwner) {\n TreeNode.setGlobalTreeState(this.path, {\n isExpanding: false,\n });\n }\n return;\n }\n }\n if (ensureVisible && this.parent && CompositeTreeNode.is(this.parent)) {\n /**\n * 在传入 ensureVisible = true 时,这里传入的 token 不能取消所有副作用\n * 故在使用 ensureVisible = true 时必须保证 `setExpanded` 与 `setCollapsed` 的独立性\n * 如需要 `await node.setExpanded(true)` 后再执行 `node.setCollapsed()`\n */\n yield this.parent.setExpanded(true, !quiet, false, token);\n }\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n if (isOwner) {\n TreeNode.setGlobalTreeState(this.path, {\n isExpanding: false,\n });\n }\n return;\n }\n if (this.isExpanded) {\n this._watcher.notifyWillChangeExpansionState(this, true);\n // 与根节点合并分支\n this.expandBranch(this, quiet);\n this._watcher.notifyDidChangeExpansionState(this, true);\n }\n if (isOwner) {\n TreeNode.setGlobalTreeState(this.path, {\n isExpanding: false,\n });\n TreeNode.setTreeNode(this.id, this.path, this);\n }\n });\n }\n // 获取当前节点下所有展开的节点路径\n getAllExpandedNodePath() {\n var _a, _b;\n const paths = [];\n let start = 0;\n if (!CompositeTreeNode.isRoot(this)) {\n // 找到节点位置下标,向下进一步查找展开目录\n start = ((_a = this.root) === null || _a === void 0 ? void 0 : _a.getIndexAtTreeNodeId(this.id)) + 1;\n }\n const end = start + this.branchSize;\n for (let i = start; i < end; i++) {\n const node = (_b = this.root) === null || _b === void 0 ? void 0 : _b.getTreeNodeAtIndex(i);\n if (CompositeTreeNode.is(node) && node.expanded) {\n paths.push(node.path);\n }\n }\n return paths;\n }\n // 获取当前节点下所有折叠的节点路径\n getAllCollapsedNodePath() {\n let paths = [];\n if (this.children) {\n for (let i = 0; i < this.children.length; i++) {\n const child = this.children[i];\n if (!CompositeTreeNode.is(child)) {\n continue;\n }\n if (child.isExpanded) {\n paths = paths.concat(child.getAllCollapsedNodePath());\n }\n else {\n paths.push(child.path);\n }\n }\n return paths;\n }\n else {\n return paths;\n }\n }\n /**\n * 处理节点数据,让节点重新加载子节点及初始化 flattenedBranch\n * @param token CancellationToken\n */\n resolveChildrens(token) {\n var _a, _b, _c;\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n let childrens = this.children;\n let expandedPaths = [];\n try {\n childrens = (yield this._tree.resolveChildren(this)) || [];\n }\n catch (e) {\n childrens = [];\n }\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return false;\n }\n const flatTree = new Array(childrens.length);\n this._children = Array(childrens.length);\n for (let i = 0; i < childrens.length; i++) {\n const child = childrens[i];\n // 如果存在上一次缓存的节点,则使用缓存节点的 ID\n child.id = TreeNode.getIdByPath(child.path) || child.id;\n this._children[i] = child;\n TreeNode.setIdByPath(child.path, child.id);\n }\n (_a = this._children) === null || _a === void 0 ? void 0 : _a.sort(this._tree.sortComparator || CompositeTreeNode.defaultSortComparator);\n for (let i = 0; i < childrens.length; i++) {\n flatTree[i] = this._children[i].id;\n }\n const expandedChilds = [];\n for (let i = 0, len = ((_b = this.children) === null || _b === void 0 ? void 0 : _b.length) || 0; i < len; i++) {\n const subChild = (_c = this.children) === null || _c === void 0 ? void 0 : _c[i];\n if (CompositeTreeNode.is(subChild) && subChild.expanded) {\n const paths = yield subChild.resolveChildrens(token);\n if (paths) {\n expandedPaths = expandedPaths.concat(paths);\n }\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return;\n }\n expandedChilds.push(subChild);\n }\n }\n this._branchSize = flatTree.length;\n this.setFlattenedBranch(flatTree);\n for (let i = 0; i < expandedChilds.length; i++) {\n const child = expandedChilds[i];\n child.expandBranch(child, true);\n }\n return expandedPaths.concat(expandedChilds.map((child) => child.path.toString()));\n });\n }\n updateTreeNodeCache(child) {\n var _a;\n TreeNode.setTreeNode(child.id, child.path, child);\n if (CompositeTreeNode.is(child) && child.expanded && ((_a = child.children) === null || _a === void 0 ? void 0 : _a.length)) {\n for (let i = 0; i < child.children.length; i++) {\n const subChild = child.children[i];\n this.updateTreeNodeCache(subChild);\n }\n }\n }\n /**\n * 静默刷新子节点, 即不触发分支更新事件\n * @param toExpandPaths 待展开的路径\n * @param token CancellationToken\n * @param origin 当 this === origin 时,说明此节点为调用的源头节点\n */\n refreshTreeNodeByPaths(toExpandPaths = this.getAllExpandedNodePath(), token, origin) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n if (!CompositeTreeNode.is(this)) {\n return;\n }\n // 如果某次刷新操作被取消,则下次刷新依旧使用上一次刷新的展开目录进行刷新\n let toExpandPath;\n const originChildren = this.children;\n let childrens = this.children || [];\n if (this.expanded) {\n if (this === origin) {\n try {\n childrens = (yield this._tree.resolveChildren(this)) || [];\n }\n catch (e) {\n childrens = [];\n }\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return;\n }\n if (!this.expanded) {\n // 当请求刷新节点时,如果该节点已经不应该被处理,则清理 Children\n // 下次再被展开时便会自动更新 Children 最新内容\n if (this.children) {\n // 清理子节点,等待下次展开时更新\n if (!!this.children && this.parent) {\n for (let i = 0; i < this.children.length; i++) {\n const child = this.children[i];\n child.dispose();\n }\n this._children = null;\n }\n }\n return;\n }\n }\n while ((toExpandPath = toExpandPaths.shift())) {\n const isRelative = toExpandPath.indexOf(`${this.path}${Path.separator}`) > -1;\n if (!isRelative) {\n if (toExpandPath === this.path) {\n toExpandPath = undefined;\n }\n break;\n }\n const child = childrens === null || childrens === void 0 ? void 0 : childrens.find((child) => child.path === toExpandPath);\n // 对于压缩情况的路径需要额外处理一下\n // 如果这里加载的路径是 a/b/c, 有可能目前只加载到 a/b\n if (!child) {\n if (!childrens || childrens.length === 0) {\n break;\n }\n for (let i = 0; i < childrens.length; i++) {\n const child = childrens[i];\n const isInclude = toExpandPath.indexOf(`${child.path}${Path.separator}`) === 0; // 展开路径包含子节点路径\n if (isInclude && CompositeTreeNode.is(child)) {\n // 包含压缩节点的情况\n if (!CompositeTreeNode.is(child)) {\n // 说明此节点为非折叠节点时不处理\n continue;\n }\n child.isExpanded = true;\n // 加载路径包含当前判断路径,尝试加载该节点再匹配\n const extraExpandedPaths = yield child.resolveChildrens(token);\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return;\n }\n if (extraExpandedPaths) {\n toExpandPaths = toExpandPaths.filter((path) => !extraExpandedPaths.find((a) => a === path));\n }\n if (child.path !== toExpandPath && !toExpandPaths.includes(child.path)) {\n toExpandPaths.unshift(toExpandPath);\n }\n if (toExpandPaths.length > 0) {\n // 不需要重新加载压缩节点的子节点内容\n toExpandPaths =\n (yield child.refreshTreeNodeByPaths([...toExpandPaths], token, origin)) || [];\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return;\n }\n }\n break;\n }\n }\n }\n else if (CompositeTreeNode.is(child)) {\n // 如果节点默认展开,则忽略后续操作\n if (!child.expanded) {\n child.isExpanded = true;\n const extraExpandedPaths = yield child.resolveChildrens(token);\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return;\n }\n if (extraExpandedPaths) {\n toExpandPaths = toExpandPaths.filter((path) => !extraExpandedPaths.find((a) => a.includes(path)));\n }\n if (toExpandPaths.length > 0 && !(token === null || token === void 0 ? void 0 : token.isCancellationRequested)) {\n toExpandPaths =\n (yield child.refreshTreeNodeByPaths([...toExpandPaths], token, origin)) || [];\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return;\n }\n }\n }\n }\n }\n if (toExpandPath) {\n // 仍然存在需要进一步处理的待展开路径\n toExpandPaths.unshift(toExpandPath);\n if (this === origin) {\n // 说明待展开的路径已经不存在,直接处理子节点\n if (originChildren) {\n this.shrinkBranch(this, true);\n for (let i = 0; i < originChildren.length; i++) {\n const child = originChildren[i];\n child === null || child === void 0 ? void 0 : child.dispose();\n }\n }\n const expandedChilds = [];\n const flatTree = new Array(childrens.length);\n this._children = Array(childrens.length);\n for (let i = 0; i < childrens.length; i++) {\n const child = childrens[i];\n // 如果存在上一次缓存的节点,则使用缓存节点的 ID\n child.id = TreeNode.getIdByPath(child.path) || child.id;\n this._children[i] = child;\n TreeNode.setIdByPath(child.path, child.id);\n if (CompositeTreeNode.is(child) && child.expanded) {\n expandedChilds.push(child);\n }\n }\n this._children.sort(this._tree.sortComparator || CompositeTreeNode.defaultSortComparator);\n for (let i = 0; i < childrens.length; i++) {\n flatTree[i] = this._children[i].id;\n }\n this._branchSize = flatTree.length;\n this.setFlattenedBranch(flatTree, true);\n this.watcher.notifyDidUpdateBranch();\n }\n if (this.parent !== origin) {\n // 将所有子节点合并至第二层 Children 上,减少后续递归拼接带来额外成本\n this.expandBranch(this, true);\n }\n return toExpandPaths;\n }\n else if (CompositeTreeNode.isRoot(this)) {\n if (this.children) {\n this.shrinkBranch(this, true);\n for (let i = 0; i < this.children.length; i++) {\n const child = this.children[i];\n child === null || child === void 0 ? void 0 : child.dispose();\n }\n }\n const expandedChilds = [];\n const otherChilds = [];\n const flatTree = new Array(childrens.length);\n this._children = Array(childrens.length);\n for (let i = 0; i < childrens.length; i++) {\n const child = childrens[i];\n // 如果存在上一次缓存的节点,则使用缓存节点的 ID\n child.id = TreeNode.getIdByPath(child.path) || child.id;\n this._children[i] = child;\n TreeNode.setIdByPath(child.path, child.id);\n if (CompositeTreeNode.is(child) && child.expanded) {\n if (!child.children) {\n yield child.resolveChildrens(token);\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return;\n }\n }\n expandedChilds.push(child);\n }\n else {\n otherChilds.push(child);\n }\n }\n this._children.sort(this._tree.sortComparator || CompositeTreeNode.defaultSortComparator);\n for (let i = 0; i < childrens.length; i++) {\n flatTree[i] = this._children[i].id;\n }\n this._branchSize = flatTree.length;\n this.setFlattenedBranch(flatTree, true);\n for (let i = 0; i < expandedChilds.length; i++) {\n const child = expandedChilds[i];\n child.expandBranch(child, true);\n this.updateTreeNodeCache(child);\n }\n for (let i = 0; i < otherChilds.length; i++) {\n const child = otherChilds[i];\n this.updateTreeNodeCache(child);\n }\n // 清理上一次监听函数\n if (typeof this.watchTerminator === 'function') {\n this.watchTerminator(this.path);\n }\n this.watchTerminator = this.watcher.onWatchEvent(this.path, this.handleWatchEvent);\n this.watcher.notifyDidUpdateBranch();\n }\n else {\n // 非根节点刷新的情况\n const expandedChilds = [];\n if (this === origin) {\n // 通知节点更新\n if (this.children) {\n // 重置旧的节点分支\n this.shrinkBranch(this, true);\n }\n if (this.children) {\n for (let i = 0, len = this.children.length; i < len; i++) {\n const child = this.children[i];\n child.dispose();\n }\n }\n const flatTree = new Array(childrens.length);\n this._children = Array(childrens.length);\n for (let i = 0, len = childrens.length; i < len; i++) {\n const child = childrens[i];\n child.id = TreeNode.getIdByPath(child.path) || child.id;\n this._children[i] = child;\n TreeNode.setIdByPath(child.path, child.id);\n if (CompositeTreeNode.is(child) && child.expanded) {\n expandedChilds.push(child);\n }\n this.updateTreeNodeCache(child);\n }\n this._children.sort(this._tree.sortComparator || CompositeTreeNode.defaultSortComparator);\n for (let i = 0; i < childrens.length; i++) {\n flatTree[i] = this._children[i].id;\n }\n this._branchSize = flatTree.length;\n this.setFlattenedBranch(flatTree);\n for (let i = 0; i < expandedChilds.length; i++) {\n const child = expandedChilds[i];\n child.expandBranch(child, true);\n }\n }\n else {\n for (let i = 0; i < childrens.length; i++) {\n const child = childrens[i];\n if (child.expanded) {\n expandedChilds.push(child);\n }\n }\n }\n for (let i = 0; i < expandedChilds.length; i++) {\n const child = expandedChilds[i];\n child.expandBranch(child, true);\n }\n if (typeof this.watchTerminator === 'function') {\n this.watchTerminator(this.path);\n }\n this.watchTerminator = this.watcher.onWatchEvent(this.path, this.handleWatchEvent);\n if (this === origin) {\n this.expandBranch(this);\n }\n }\n }\n else {\n // 仅需处理存在子节点的情况,否则将会影响刷新后的节点长度\n if (this.children) {\n // 清理子节点,等待下次展开时更新\n if (!!this.children && this.parent) {\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0, len = this.children.length; i < len; i++) {\n const child = this.children[i];\n child.dispose();\n }\n this._children = null;\n }\n }\n return;\n }\n });\n }\n expandedAll(collapsedPaths = this.getAllCollapsedNodePath()) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n // 仅根节点使用\n if (!CompositeTreeNode.isRoot(this)) {\n return;\n }\n collapsedPaths = collapsedPaths.sort((a, b) => Path.pathDepth(a) - Path.pathDepth(b));\n let path;\n while (collapsedPaths.length > 0) {\n path = collapsedPaths.pop();\n const item = TreeNode.getTreeNodeByPath(path);\n if (CompositeTreeNode.is(item)) {\n yield item.setExpanded(false, true);\n }\n }\n // 通知分支树已更新\n this.watcher.notifyDidUpdateBranch();\n });\n }\n collapsedAll(expandedPaths = this.getAllExpandedNodePath()) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n // 仅根节点使用\n if (!CompositeTreeNode.isRoot(this)) {\n return;\n }\n expandedPaths = expandedPaths.sort((a, b) => Path.pathDepth(a) - Path.pathDepth(b));\n let path;\n while (expandedPaths.length > 0) {\n path = expandedPaths.pop();\n const item = TreeNode.getTreeNodeByPath(path);\n if (CompositeTreeNode.is(item)) {\n item.setCollapsed(true);\n }\n }\n // 通知分支树已更新\n this.watcher.notifyDidUpdateBranch();\n });\n }\n // 折叠节点\n setCollapsed(quiet = false) {\n // 根节点不可折叠\n if (CompositeTreeNode.isRoot(this) || this.disposed) {\n return;\n }\n if (!this.isExpanded) {\n return;\n }\n const state = TreeNode.getGlobalTreeState(this.path);\n if (state.isExpanding) {\n // 当节点处于加载子节点过程时,尽管为展开状态,但此时不应该支持折叠节点\n return;\n }\n state.loadPathCancelToken.cancel();\n state.refreshCancelToken.cancel();\n this._watcher.notifyWillChangeExpansionState(this, false);\n if (this._children && this.parent) {\n // 从根节点裁剪分支\n this.shrinkBranch(this, quiet);\n }\n this.isExpanded = false;\n TreeNode.setTreeNode(this.id, this.path, this);\n this._watcher.notifyDidChangeExpansionState(this, false);\n }\n mv(to, name = this.name) {\n const prevPath = this.path;\n super.mv(to, name);\n if (typeof this.watchTerminator === 'function') {\n this.watchTerminator(prevPath);\n this.watchTerminator = this.watcher.onWatchEvent(this.path, this.handleWatchEvent);\n }\n // 同时移动过子节点\n if (this.children) {\n for (let i = 0; i < this.children.length; i++) {\n const child = this.children[i];\n child.mv(child.parent, child.name);\n }\n }\n }\n /**\n * 在节点中插入新的节点\n *\n * 直接调用此方法将不会触发onWillHandleWatchEvent和onDidHandleWatchEvent事件\n */\n insertItem(item) {\n if (item.parent !== this) {\n item.mv(this, item.name);\n return;\n }\n if (this.children) {\n for (let i = 0; i < this.children.length; i++) {\n // path / id 是节点唯一标识\n if (this.children[i].path === item.path) {\n this.children[i] = item;\n return;\n }\n }\n }\n const branchSizeIncrease = 1 + (item instanceof CompositeTreeNode && item.expanded ? item._branchSize : 0);\n if (this._children) {\n this._children.push(item);\n this._children.sort(this._tree.sortComparator || CompositeTreeNode.defaultSortComparator);\n }\n this._branchSize += branchSizeIncrease;\n let master = this;\n // 如果该节点无叶子节点,则继续往上查找合适的插入位置\n while (!master._flattenedBranch) {\n if (master.parent) {\n master = master.parent;\n master._branchSize += branchSizeIncrease;\n }\n }\n if (!this._children) {\n return;\n }\n let relativeInsertionIndex = this._children.indexOf(item);\n let absInsertionIndex;\n const leadingSibling = this._children[relativeInsertionIndex - 1];\n if (leadingSibling) {\n const siblingIdx = master._flattenedBranch.indexOf(leadingSibling.id);\n relativeInsertionIndex =\n siblingIdx +\n (leadingSibling instanceof CompositeTreeNode && leadingSibling.expanded ? leadingSibling._branchSize : 0);\n }\n else {\n relativeInsertionIndex = master._flattenedBranch.indexOf(this.id);\n }\n if (relativeInsertionIndex === -1) {\n if (this._branchSize === 1) {\n // 在空Tree中插入节点时,相对插入位置为0\n relativeInsertionIndex = 0;\n }\n }\n // 非空Tree情况下需要+1,为了容纳自身节点位置,在插入节点下方插入新增节点\n absInsertionIndex = relativeInsertionIndex + 1;\n // 空 Tree 情况下需要重置为 0,避免设置 Uint32Array 时超出范围\n if (master._flattenedBranch.length === 0) {\n absInsertionIndex = 0;\n }\n let branch = [item.id];\n if (item instanceof CompositeTreeNode && item.expanded && item._flattenedBranch) {\n branch = branch.concat(item._flattenedBranch);\n item.setFlattenedBranch(null);\n }\n master.setFlattenedBranch(spliceArray(master._flattenedBranch, absInsertionIndex, 0, branch));\n TreeNode.setTreeNode(item.id, item.path, item);\n return item;\n }\n /**\n * 从父节点中移除节点\n *\n * 直接调用此方法将不会触发onWillHandleWatchEvent和onDidHandleWatchEvent事件\n */\n unlinkItem(item, reparenting) {\n var _a;\n if (!this._children) {\n return;\n }\n const idx = this._children.indexOf(item);\n if (idx === -1) {\n return;\n }\n // 当删除时父节点已不存在界面上时,跳过插入操作\n if (!this.isItemVisibleAtRootSurface(this)) {\n return;\n }\n (_a = this._children) === null || _a === void 0 ? void 0 : _a.splice(idx, 1);\n const branchSizeDecrease = 1 + (item instanceof CompositeTreeNode && item.expanded ? item._branchSize : 0);\n this._branchSize -= branchSizeDecrease;\n // 逐级往上查找节点的父节点,并沿途裁剪分支数\n let master = this;\n while (!master._flattenedBranch) {\n if (master.parent) {\n master = master.parent;\n master._branchSize -= branchSizeDecrease;\n }\n }\n const removalBeginIdx = master._flattenedBranch.indexOf(item.id);\n if (removalBeginIdx === -1) {\n return;\n }\n if (item instanceof CompositeTreeNode && item.expanded) {\n item.setFlattenedBranch(master._flattenedBranch.slice(removalBeginIdx + 1, removalBeginIdx + branchSizeDecrease));\n }\n master.setFlattenedBranch(spliceArray(master._flattenedBranch, removalBeginIdx, branchSizeDecrease));\n if (!reparenting && item.parent === this) {\n item.mv(null);\n }\n }\n /**\n * 转换节点路径\n */\n transferItem(oldPath, newPath) {\n var _a;\n const oldP = new Path(oldPath);\n const from = oldP.dir.toString();\n if (from !== this.path) {\n return;\n }\n const name = oldP.base.toString();\n const item = (_a = this._children) === null || _a === void 0 ? void 0 : _a.find((c) => c.name === name);\n if (!item) {\n return;\n }\n const newP = new Path(newPath);\n const to = newP.dir.toString();\n const destDir = to === from ? this : TreeNode.getTreeNodeByPath(to);\n if (!CompositeTreeNode.is(destDir)) {\n this.unlinkItem(item);\n return;\n }\n item.mv(destDir, newP.base.toString());\n return item;\n }\n dispose() {\n // 如果存在对应文件路径下的监听,同样需要清理掉\n if (this.watchEvents) {\n const watcher = this.watchEvents.get(this.path);\n if (watcher) {\n watcher.terminator();\n }\n this.watchEvents.clear();\n }\n if (this._children) {\n // 移除后应该折叠,因为下次初始化默认值为折叠,否则将会导致下次插入异常\n this.isExpanded = false;\n this._children.forEach((child) => {\n child.dispose();\n });\n this._children = null;\n this._flattenedBranch = null;\n }\n super.dispose();\n }\n /**\n * 设置扁平化的分支信息\n */\n setFlattenedBranch(leaves, withoutNotify) {\n this._flattenedBranch = leaves;\n // Root节点才通知更新\n if (CompositeTreeNode.isRoot(this) && !withoutNotify) {\n this.watcher.notifyDidUpdateBranch();\n }\n }\n /**\n * 展开分支节点\n * @param branch 分支节点\n */\n expandBranch(branch, withoutNotify) {\n if (this !== branch) {\n // 但节点为展开状态时进行裁剪\n if (branch._flattenedBranch) {\n this._branchSize += branch._branchSize;\n }\n }\n // 当前节点为折叠状态,更新分支信息\n if (this !== branch && this._flattenedBranch) {\n const injectionStartIdx = this._flattenedBranch.indexOf(branch.id) + 1;\n if (injectionStartIdx === 0) {\n // 中途发生了branch更新事件,此时的_flattenedBranch可能已被更新,即查找不到branch.id\n // 这种情况在父节点发生了多路径目录的创建定位动作下更易复现\n // 例:文件树在执行a/b/c定位操作时需要请求三次数据,而更新操作可能只需要一次\n // 导致就算更新操作后置执行,也可能比定位操作先执行完,同时将_flattenedBranch更新\n // 最终导致此处查询不到对应节点,下面的shrinkBranch同样可能有相同问题,如点击折叠全部功能时\n return;\n }\n this.setFlattenedBranch(spliceArray(this._flattenedBranch, injectionStartIdx, 0, branch._flattenedBranch), withoutNotify);\n // 取消展开分支对于分支的所有权,即最终只会有顶部Root拥有所有分支信息\n branch.setFlattenedBranch(null, withoutNotify);\n }\n else if (this.parent) {\n this.parent.expandBranch(branch, withoutNotify);\n }\n }\n /**\n * 清理分支节点\n * @param branch 分支节点\n */\n shrinkBranch(branch, withoutNotify) {\n if (this !== branch) {\n // 这里的`this`实际上为父节点\n // `this`的分支大小没有改变,仍然具有相同数量的叶子,但是从父级参照系(即根节点)来看,其分支缩小了\n this._branchSize -= branch._branchSize;\n }\n if (this !== branch && this._flattenedBranch) {\n const removalStartIdx = this._flattenedBranch.indexOf(branch.id) + 1;\n if (removalStartIdx === 0) {\n // 中途发生了branch更新事件,此时的_flattenedBranch可能已被更新,即查找不到branch.id\n return;\n }\n // 返回分支对于分支信息所有权,即将折叠的节点信息再次存储于折叠了的节点中\n branch.setFlattenedBranch(this._flattenedBranch.slice(removalStartIdx, removalStartIdx + branch._branchSize), withoutNotify);\n this.setFlattenedBranch(spliceArray(this._flattenedBranch, removalStartIdx, branch._flattenedBranch ? branch._flattenedBranch.length : 0), withoutNotify);\n }\n else if (this.parent) {\n this.parent.shrinkBranch(branch, withoutNotify);\n }\n }\n /**\n * 加载子节点信息\n * 当返回值为 true 时,正常加载完子节点并同步到数据结构中\n * 返回值为 false 时,加载节点的过程被中断\n *\n * @memberof CompositeTreeNode\n */\n hardReloadChildren(token) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n let rawItems;\n const oldPath = this.path;\n try {\n // ! `this.path` maybe changed after `resolveChildren` in file tree compact mode\n rawItems = (yield this._tree.resolveChildren(this)) || [];\n }\n catch (e) {\n rawItems = [];\n }\n // 当获取到新的子节点时,如果当前节点正处于非展开状态时,忽略后续裁切逻辑\n // 后续的 expandBranch 也不应该被响应\n if (!this.expanded || (token === null || token === void 0 ? void 0 : token.isCancellationRequested)) {\n return false;\n }\n if (this.path !== oldPath) {\n // do some clean up\n TreeNode.setGlobalTreeState(oldPath, {\n isExpanding: false,\n isLoadingPath: false,\n isRefreshing: false,\n });\n }\n const expandedChilds = [];\n const flatTree = new Array(rawItems.length);\n const tempChildren = new Array(rawItems.length);\n for (let i = 0; i < rawItems.length; i++) {\n const child = rawItems[i];\n child.id = TreeNode.getIdByPath(child.path) || child.id;\n tempChildren[i] = child;\n TreeNode.setIdByPath(child.path, child.id);\n if (CompositeTreeNode.is(child) && child.expanded) {\n if (!child.children) {\n yield child.resolveChildrens(token);\n }\n if (token === null || token === void 0 ? void 0 : token.isCancellationRequested) {\n return false;\n }\n expandedChilds.push(child);\n }\n }\n tempChildren.sort(this._tree.sortComparator || CompositeTreeNode.defaultSortComparator);\n for (let i = 0; i < rawItems.length; i++) {\n flatTree[i] = tempChildren[i].id;\n }\n if (this.children) {\n this.shrinkBranch(this);\n }\n if (this.children) {\n for (let i = 0; i < this.children.length; i++) {\n const child = this.children[i];\n // The Child maybe `undefined`.\n child === null || child === void 0 ? void 0 : child.dispose();\n }\n }\n for (let i = 0; i < tempChildren.length; i++) {\n this.updateTreeNodeCache(tempChildren[i]);\n }\n this._children = tempChildren;\n this._branchSize = flatTree.length;\n this.setFlattenedBranch(flatTree);\n for (let i = 0; i < expandedChilds.length; i++) {\n const child = expandedChilds[i];\n child.expandBranch(child, true);\n }\n // 清理上一次监听函数\n if (typeof this.watchTerminator === 'function') {\n this.watchTerminator(this.path);\n }\n this.watchTerminator = this.watcher.onWatchEvent(this.path, this.handleWatchEvent);\n return true;\n });\n }\n moveNode(oldPath, newPath) {\n if (typeof oldPath !== 'string') {\n throw new TypeError('Expected oldPath to be a string');\n }\n if (typeof newPath !== 'string') {\n throw new TypeError('Expected newPath to be a string');\n }\n if (Path.isRelative(oldPath)) {\n throw new TypeError('oldPath must be absolute');\n }\n if (Path.isRelative(newPath)) {\n throw new TypeError('newPath must be absolute');\n }\n return this.transferItem(oldPath, newPath);\n }\n addNode(node) {\n if (!TreeNode.is(node)) {\n throw new TypeError('Expected node to be a TreeNode');\n }\n return this.insertItem(node);\n }\n removeNode(path) {\n const pathObject = new Path(path);\n const dirName = pathObject.dir.toString();\n const name = pathObject.base.toString();\n if (dirName === this.path && !!this.children) {\n const item = this.children.find((c) => c.name === name);\n if (item) {\n this.unlinkItem(item);\n }\n }\n }\n // 当没有传入具体路径时,使用当前展开目录作为刷新路径\n refresh(tokenSource, target) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n if (!CompositeTreeNode.isRoot(this)) {\n // 刷新操作只能从根节点进行,便于对重复的刷新操作进行合并\n return yield this.root.refresh(tokenSource, this);\n }\n const state = TreeNode.getGlobalTreeState(this.path);\n if (state.isLoadingPath || state.isExpanding) {\n return;\n }\n let token;\n if (tokenSource && !tokenSource.token.isCancellationRequested) {\n TreeNode.setGlobalTreeState(this.path, {\n isRefreshing: true,\n refreshCancelToken: tokenSource,\n });\n token = tokenSource.token;\n }\n else {\n if (state.refreshCancelToken.token.isCancellationRequested) {\n const refreshCancelToken = new ide_utils_1.CancellationTokenSource();\n TreeNode.setGlobalTreeState(this.path, {\n isRefreshing: true,\n refreshCancelToken,\n });\n token = refreshCancelToken.token;\n }\n else {\n token = state.refreshCancelToken.token;\n }\n }\n this.toRefreshPathQueue.add((target || this).path);\n yield this.refreshThrottler.trigger(() => this.doRefresh(token));\n TreeNode.setGlobalTreeState(this.path, {\n isRefreshing: false,\n });\n });\n }\n doRefresh(token) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n const target = this.getRefreshNode() || this;\n if (!CompositeTreeNode.is(target)) {\n return;\n }\n const paths = target.getAllExpandedNodePath();\n yield target.refreshTreeNodeByPaths(paths, token, target);\n });\n }\n getRefreshNode() {\n let paths = Array.from(this.toRefreshPathQueue);\n this.toRefreshPathQueue.clear();\n if (!paths.length) {\n return this.root;\n }\n // 根据路径层级深度进行排序\n paths = paths.sort((a, b) => {\n const depthA = Path.pathDepth(a);\n const depthB = Path.pathDepth(b);\n return depthA - depthB;\n });\n if (paths.length === 1 || Path.pathDepth(paths[0]) === 1) {\n // 说明刷新队列中包含根节点,直接返回根节点进行刷新\n return TreeNode.getTreeNodeByPath(paths[0]);\n }\n const sortedPaths = paths.map((p) => new Path(p));\n let rootPath = sortedPaths[0];\n for (let i = 1, len = sortedPaths.length; i < len; i++) {\n if (rootPath.isEqualOrParent(sortedPaths[i])) {\n continue;\n }\n else {\n while (!rootPath.isRoot) {\n rootPath = rootPath.dir;\n if (!rootPath || rootPath.isEqualOrParent(sortedPaths[i])) {\n break;\n }\n }\n }\n }\n if (rootPath) {\n return TreeNode.getTreeNodeByPath(rootPath.toString());\n }\n return this.root;\n }\n isItemVisibleAtRootSurface(node) {\n let parent = node;\n while (parent.parent) {\n parent = parent.parent;\n }\n return parent.isItemVisibleAtSurface(node);\n }\n /**\n * 检查节点是否可见,而不是被隐藏在节点中\n *\n * 这里的可见并不表示节点在当前视图中可见,而是在用户滚动到特定位置便可看见\n *\n * 隐藏在节点中可能的原因为其父节点中有一个以上处于折叠状态\n */\n isItemVisibleAtSurface(item) {\n if (item === this) {\n return true;\n }\n return !!this._flattenedBranch && this._flattenedBranch.indexOf(item.id) > -1;\n }\n transformToRelativePath(path) {\n const { splitPath } = Path;\n const pathFlag = splitPath(path);\n pathFlag.shift();\n return pathFlag;\n }\n /**\n * 根据路径展开节点树\n * @memberof CompositeTreeNode\n */\n loadTreeNodeByPath(path, quiet = false) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n if (!CompositeTreeNode.isRoot(this)) {\n return;\n }\n const state = TreeNode.getGlobalTreeState(this.path);\n if (state.isExpanding) {\n return;\n }\n state.refreshCancelToken.cancel();\n state.loadPathCancelToken.cancel();\n const loadPathCancelToken = new ide_utils_1.CancellationTokenSource();\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: true,\n loadPathCancelToken,\n });\n const token = loadPathCancelToken.token;\n const flattenedBranchChilds = [];\n const { splitPath, isRelative } = Path;\n const pathFlag = isRelative(path) ? splitPath(path) : this.transformToRelativePath(path);\n if (pathFlag.length === 0) {\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: false,\n });\n return this;\n }\n if (!this.children) {\n yield this.ensureLoaded(token);\n }\n if (token.isCancellationRequested) {\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: false,\n });\n return;\n }\n let next = this._children;\n let preItem;\n let preItemPath = '';\n let name;\n while (next && (name = pathFlag.shift())) {\n let item = next.find((c) => c.name.indexOf(name) === 0);\n if (item) {\n if (CompositeTreeNode.is(item)) {\n item._watcher.notifyWillChangeExpansionState(item, true);\n item.isExpanded = true;\n if (!item.children) {\n yield item.resolveChildrens(token);\n if (token.isCancellationRequested) {\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: false,\n });\n return;\n }\n }\n flattenedBranchChilds.push(item);\n item._watcher.notifyDidChangeExpansionState(item, true);\n }\n if (pathFlag.length === 0) {\n preItem = item;\n break;\n }\n }\n // 可能展开后路径发生了变化, 需要重新处理一下当前加载路径\n if (!item && preItem) {\n const compactPath = splitPath(preItem.name).slice(1);\n if (compactPath[0] === name) {\n compactPath.shift();\n while (compactPath.length > 0) {\n if (compactPath[0] === pathFlag[0]) {\n compactPath.shift();\n pathFlag.shift();\n }\n else {\n break;\n }\n }\n name = pathFlag.shift();\n item = next.find((c) => c.name.indexOf(name) === 0);\n }\n }\n // 最终加载到的路径节点\n if (!item || (!CompositeTreeNode.is(item) && pathFlag.length > 0)) {\n break;\n }\n if (CompositeTreeNode.is(item)) {\n const isCompactName = item.name.indexOf(Path.separator) > 0;\n if (isCompactName) {\n const compactPath = splitPath(item.name).slice(1);\n while (compactPath.length > 0) {\n if (compactPath[0] === pathFlag[0]) {\n compactPath.shift();\n pathFlag.shift();\n }\n else {\n break;\n }\n }\n }\n if (!item._children) {\n preItemPath = item.path;\n if (CompositeTreeNode.is(item)) {\n item.isExpanded = true;\n if (!item.children) {\n yield item.resolveChildrens(token);\n if (token.isCancellationRequested) {\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: false,\n });\n return;\n }\n }\n flattenedBranchChilds.push(item);\n }\n }\n if (item && pathFlag.length === 0) {\n preItem = item;\n break;\n }\n else {\n if (!!preItemPath && preItemPath !== item.path) {\n // 说明此时已发生了路径压缩,如从 a -> a/b/c\n // 需要根据路径变化移除对应的展开路径, 这里只需考虑短变长场景\n const prePaths = splitPath(preItemPath);\n const nextPaths = splitPath(item.path);\n if (nextPaths.length > prePaths.length) {\n pathFlag.splice(0, nextPaths.length - prePaths.length);\n }\n }\n next = item._children;\n preItem = item;\n }\n }\n }\n if (preItem) {\n let child;\n if (preItem.disposed) {\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: false,\n });\n return;\n }\n while ((child = flattenedBranchChilds.pop())) {\n child.expandBranch(child, true);\n if (flattenedBranchChilds.length === 0) {\n this.updateTreeNodeCache(child);\n }\n }\n if (!quiet) {\n this.watcher.notifyDidUpdateBranch();\n }\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: false,\n });\n return preItem;\n }\n TreeNode.setGlobalTreeState(this.path, {\n isLoadingPath: false,\n });\n });\n }\n /**\n * 根据节点获取节点ID下标位置\n * @param {number} id\n * @returns\n * @memberof CompositeTreeNode\n */\n getIndexAtTreeNodeId(id) {\n if (this._flattenedBranch) {\n return this._flattenedBranch.indexOf(id);\n }\n return -1;\n }\n /**\n * 根据节点获取节点下标位置\n * @param {ITreeNodeOrCompositeTreeNode} node\n * @returns\n * @memberof CompositeTreeNode\n */\n getIndexAtTreeNode(node) {\n if (this._flattenedBranch) {\n return this._flattenedBranch.indexOf(node.id);\n }\n return -1;\n }\n /**\n * 根据下标位置获取节点\n * @param {number} index\n * @returns\n * @memberof CompositeTreeNode\n */\n getTreeNodeAtIndex(index) {\n var _a;\n const id = (_a = this._flattenedBranch) === null || _a === void 0 ? void 0 : _a[index];\n if (!id) {\n return undefined;\n }\n return TreeNode.getTreeNodeById(id);\n }\n /**\n * 根据节点ID获取节点\n * @param {number} id\n * @returns\n * @memberof CompositeTreeNode\n */\n getTreeNodeById(id) {\n return TreeNode.getTreeNodeById(id);\n }\n /**\n * 根据节点路径获取节点\n * @param {string} path\n * @returns\n * @memberof CompositeTreeNode\n */\n getTreeNodeByPath(path) {\n return TreeNode.getTreeNodeByPath(path);\n }\n}\nexports.CompositeTreeNode = CompositeTreeNode;\nCompositeTreeNode.REFRESH_DELAY = 200;\n\n\n//# sourceURL=webpack://@opensumi/ide-components/./src/recycle-tree/tree/TreeNode.ts?");
5439
5428
 
5440
5429
  /***/ }),
5441
5430
 
@@ -5523,7 +5512,7 @@ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\ncons
5523
5512
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
5524
5513
 
5525
5514
  "use strict";
5526
- eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.TreeStateManager = exports.Operation = void 0;\nconst tslib_1 = __webpack_require__(/*! tslib */ \"../../node_modules/tslib/tslib.es6.mjs\");\nconst ide_utils_1 = __webpack_require__(/*! @opensumi/ide-utils */ \"../utils/lib/index.js\");\nconst path_1 = __webpack_require__(/*! ../../../path */ \"./src/recycle-tree/path.ts\");\nconst types_1 = __webpack_require__(/*! ../../../types */ \"./src/recycle-tree/types/index.ts\");\nconst TreeNode_1 = __webpack_require__(/*! ../../TreeNode */ \"./src/recycle-tree/tree/TreeNode.ts\");\nvar Operation;\n(function (Operation) {\n Operation[Operation[\"SetExpanded\"] = 1] = \"SetExpanded\";\n Operation[Operation[\"SetCollapsed\"] = 2] = \"SetCollapsed\";\n Operation[Operation[\"SetActive\"] = 3] = \"SetActive\";\n})(Operation = exports.Operation || (exports.Operation = {}));\nvar StashKeyFrameFlag;\n(function (StashKeyFrameFlag) {\n StashKeyFrameFlag[StashKeyFrameFlag[\"Expanded\"] = 1] = \"Expanded\";\n StashKeyFrameFlag[StashKeyFrameFlag[\"Collapsed\"] = 2] = \"Collapsed\";\n StashKeyFrameFlag[StashKeyFrameFlag[\"Disabled\"] = 4] = \"Disabled\";\n})(StashKeyFrameFlag || (StashKeyFrameFlag = {}));\nclass TreeStateManager {\n constructor(root) {\n this.expandedDirectories = new Map();\n this._scrollOffset = 0;\n this.stashing = false;\n this.stashLockingItems = new Set();\n this.onDidLoadStateEmitter = new ide_utils_1.Emitter();\n this.onChangeScrollOffsetEmitter = new ide_utils_1.Emitter();\n this.onDidChangeExpansionStateEmitter = new ide_utils_1.Emitter();\n this.onDidChangeRelativePathEmitter = new ide_utils_1.Emitter();\n /**\n * 处理展开状态的变更\n */\n this.handleExpansionChange = (target, isExpanded, isVisibleAtSurface) => {\n if (this.stashing && this.stashKeyframes) {\n this.stashKeyframes.set(target.id, isExpanded ? StashKeyFrameFlag.Expanded : StashKeyFrameFlag.Collapsed);\n }\n if (this.stashKeyframes && !this.stashing) {\n // 如果用户通过交互手动修改了展开属性,则需要在记录结束后将其父节点从撤销队列中移除\n if (isExpanded) {\n let p = target;\n while (p) {\n if (this.stashKeyframes.has(p.id)) {\n let flags = this.stashKeyframes.get(p.id);\n flags = flags | StashKeyFrameFlag.Disabled;\n this.stashKeyframes.set(p.id, flags);\n }\n p = p.parent;\n }\n this.stashLockingItems.add(target);\n }\n if (this.stashLockingItems && this.stashLockingItems.has(target) && !isExpanded) {\n let p = target;\n while (p) {\n if (this.stashKeyframes.has(p.id)) {\n let flags = this.stashKeyframes.get(p.id);\n flags &= ~StashKeyFrameFlag.Disabled;\n this.stashKeyframes.set(p.id, flags);\n }\n p = p.parent;\n }\n this.stashLockingItems.delete(target);\n }\n }\n let relativePath = this.expandedDirectories.get(target);\n if (isExpanded && !relativePath) {\n relativePath = path_1.treePath.relative(this.root.path, target.path);\n this.expandedDirectories.set(target, relativePath);\n this.onDidChangeExpansionStateEmitter.fire({ relativePath, isExpanded, isVisibleAtSurface });\n }\n else if (!isExpanded && relativePath) {\n this.expandedDirectories.delete(target);\n this.onDidChangeExpansionStateEmitter.fire({ relativePath, isExpanded, isVisibleAtSurface });\n }\n };\n this.handleDidChangePath = (target) => {\n if (this.expandedDirectories.has(target)) {\n const prevPath = this.expandedDirectories.get(target);\n const newPath = path_1.treePath.relative(this.root.path, target.path);\n this.expandedDirectories.set(target, newPath);\n this.onDidChangeRelativePathEmitter.fire({ prevPath, newPath });\n }\n };\n this.root = root;\n // 监听节点的折叠展开状态变化\n this.root.watcher.on(types_1.TreeNodeEvent.DidChangeExpansionState, this.handleExpansionChange);\n this.root.watcher.on(types_1.TreeNodeEvent.DidChangePath, this.handleDidChangePath);\n }\n get scrollOffset() {\n return this._scrollOffset;\n }\n saveScrollOffset(scrollOffset) {\n this._scrollOffset = scrollOffset;\n this.onChangeScrollOffsetEmitter.fire(scrollOffset);\n }\n get onDidLoadState() {\n return this.onDidLoadStateEmitter.event;\n }\n get onChangeScrollOffset() {\n return this.onChangeScrollOffsetEmitter.event;\n }\n get onDidChangeExpansionState() {\n return this.onDidChangeExpansionStateEmitter.event;\n }\n get onDidChangeRelativePath() {\n return this.onDidChangeRelativePathEmitter.event;\n }\n loadTreeState(state) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n if (state) {\n for (const relPath of state.expandedDirectories.buried) {\n try {\n const node = yield this.root.loadTreeNodeByPath(relPath);\n if (!node) {\n break;\n }\n if (node && TreeNode_1.CompositeTreeNode.is(node)) {\n node.setCollapsed();\n }\n }\n catch (error) { }\n }\n for (const relPath of state.expandedDirectories.atSurface) {\n try {\n const node = yield this.root.loadTreeNodeByPath(relPath, true);\n if (!node) {\n break;\n }\n }\n catch (error) { }\n }\n this._scrollOffset =\n typeof state.scrollPosition === 'number' && state.scrollPosition > -1\n ? state.scrollPosition\n : this._scrollOffset;\n this.root.watcher.notifyDidUpdateBranch();\n this.onDidLoadStateEmitter.fire();\n }\n });\n }\n /**\n * 确保在调用`reverseStash`时,目录扩展不会被更改,以免导致节点内文件被排除\n */\n excludeFromStash(file) {\n if (this.stashKeyframes && !this.stashing) {\n this.handleExpansionChange(!TreeNode_1.CompositeTreeNode.is(file) ? file.parent : file, true, this.root.isItemVisibleAtSurface(file));\n }\n }\n /**\n * 开始记录点\n */\n beginStashing() {\n this.stashing = true;\n this.stashKeyframes = new Map();\n }\n /**\n * 结束记录点\n */\n endStashing() {\n this.stashing = false;\n this.stashLockingItems.clear();\n }\n /**\n * 反转记录的所有折叠/展开状态\n * 用于实现一些临时的查看操作\n * 例如:\n * 调用beginStashing ==> 展开/折叠某个目录 ==> 调用endStashing ==> 处理完毕后调用reverseStash,回到原来的状态\n */\n reverseStash() {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n if (!this.stashKeyframes) {\n return;\n }\n this.endStashing();\n const keyframes = Array.from(this.stashKeyframes);\n this.stashKeyframes = null;\n for (const [targetID, flags] of keyframes) {\n const frameDisabled = (flags & StashKeyFrameFlag.Disabled) === StashKeyFrameFlag.Disabled;\n const target = TreeNode_1.TreeNode.getTreeNodeById(targetID);\n // 判断当前操作对象是否有效,无效则做下一步操作\n if (!target || frameDisabled) {\n continue;\n }\n if ((flags & StashKeyFrameFlag.Expanded) === StashKeyFrameFlag.Expanded) {\n target.setCollapsed();\n }\n else if ((flags & StashKeyFrameFlag.Collapsed) === StashKeyFrameFlag.Collapsed) {\n yield target.setExpanded();\n }\n }\n });\n }\n}\nexports.TreeStateManager = TreeStateManager;\n\n\n//# sourceURL=webpack://@opensumi/ide-components/./src/recycle-tree/tree/model/treeState/TreeStateManager.ts?");
5515
+ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.TreeStateManager = exports.Operation = void 0;\nconst tslib_1 = __webpack_require__(/*! tslib */ \"../../node_modules/tslib/tslib.es6.mjs\");\nconst ide_utils_1 = __webpack_require__(/*! @opensumi/ide-utils */ \"../utils/lib/index.js\");\nconst types_1 = __webpack_require__(/*! ../../../types */ \"./src/recycle-tree/types/index.ts\");\nconst TreeNode_1 = __webpack_require__(/*! ../../TreeNode */ \"./src/recycle-tree/tree/TreeNode.ts\");\nconst { Path } = ide_utils_1.path;\nvar Operation;\n(function (Operation) {\n Operation[Operation[\"SetExpanded\"] = 1] = \"SetExpanded\";\n Operation[Operation[\"SetCollapsed\"] = 2] = \"SetCollapsed\";\n Operation[Operation[\"SetActive\"] = 3] = \"SetActive\";\n})(Operation = exports.Operation || (exports.Operation = {}));\nvar StashKeyFrameFlag;\n(function (StashKeyFrameFlag) {\n StashKeyFrameFlag[StashKeyFrameFlag[\"Expanded\"] = 1] = \"Expanded\";\n StashKeyFrameFlag[StashKeyFrameFlag[\"Collapsed\"] = 2] = \"Collapsed\";\n StashKeyFrameFlag[StashKeyFrameFlag[\"Disabled\"] = 4] = \"Disabled\";\n})(StashKeyFrameFlag || (StashKeyFrameFlag = {}));\nclass TreeStateManager {\n constructor(root) {\n this.expandedDirectories = new Map();\n this._scrollOffset = 0;\n this.stashing = false;\n this.stashLockingItems = new Set();\n this.onDidLoadStateEmitter = new ide_utils_1.Emitter();\n this.onChangeScrollOffsetEmitter = new ide_utils_1.Emitter();\n this.onDidChangeExpansionStateEmitter = new ide_utils_1.Emitter();\n this.onDidChangeRelativePathEmitter = new ide_utils_1.Emitter();\n /**\n * 处理展开状态的变更\n * @private\n * @memberof TreeStateManager\n */\n this.handleExpansionChange = (target, isExpanded, isVisibleAtSurface) => {\n var _a;\n if (this.stashing && this.stashKeyframes) {\n this.stashKeyframes.set(target.id, isExpanded ? StashKeyFrameFlag.Expanded : StashKeyFrameFlag.Collapsed);\n }\n if (this.stashKeyframes && !this.stashing) {\n // 如果用户通过交互手动修改了展开属性,则需要在记录结束后将其父节点从撤销队列中移除\n if (isExpanded) {\n let p = target;\n while (p) {\n if (this.stashKeyframes.has(p.id)) {\n let flags = this.stashKeyframes.get(p.id);\n flags = flags | StashKeyFrameFlag.Disabled;\n this.stashKeyframes.set(p.id, flags);\n }\n p = p.parent;\n }\n this.stashLockingItems.add(target);\n }\n if (this.stashLockingItems && this.stashLockingItems.has(target) && !isExpanded) {\n let p = target;\n while (p) {\n if (this.stashKeyframes.has(p.id)) {\n let flags = this.stashKeyframes.get(p.id);\n flags &= ~StashKeyFrameFlag.Disabled;\n this.stashKeyframes.set(p.id, flags);\n }\n p = p.parent;\n }\n this.stashLockingItems.delete(target);\n }\n }\n let relativePath = this.expandedDirectories.get(target);\n if (isExpanded && !relativePath) {\n relativePath = (_a = new Path(this.root.path).relative(new Path(target.path))) === null || _a === void 0 ? void 0 : _a.toString();\n this.expandedDirectories.set(target, relativePath);\n this.onDidChangeExpansionStateEmitter.fire({ relativePath, isExpanded, isVisibleAtSurface });\n }\n else if (!isExpanded && relativePath) {\n this.expandedDirectories.delete(target);\n this.onDidChangeExpansionStateEmitter.fire({ relativePath, isExpanded, isVisibleAtSurface });\n }\n };\n this.handleDidChangePath = (target) => {\n var _a;\n if (this.expandedDirectories.has(target)) {\n const prevPath = this.expandedDirectories.get(target);\n const newPath = (_a = new Path(this.root.path).relative(new Path(target.path))) === null || _a === void 0 ? void 0 : _a.toString();\n this.expandedDirectories.set(target, newPath);\n this.onDidChangeRelativePathEmitter.fire({ prevPath, newPath });\n }\n };\n this.root = root;\n // 监听节点的折叠展开状态变化\n this.root.watcher.on(types_1.TreeNodeEvent.DidChangeExpansionState, this.handleExpansionChange);\n this.root.watcher.on(types_1.TreeNodeEvent.DidChangePath, this.handleDidChangePath);\n }\n get scrollOffset() {\n return this._scrollOffset;\n }\n saveScrollOffset(scrollOffset) {\n this._scrollOffset = scrollOffset;\n this.onChangeScrollOffsetEmitter.fire(scrollOffset);\n }\n get onDidLoadState() {\n return this.onDidLoadStateEmitter.event;\n }\n get onChangeScrollOffset() {\n return this.onChangeScrollOffsetEmitter.event;\n }\n get onDidChangeExpansionState() {\n return this.onDidChangeExpansionStateEmitter.event;\n }\n get onDidChangeRelativePath() {\n return this.onDidChangeRelativePathEmitter.event;\n }\n loadTreeState(state) {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n if (state) {\n for (const relPath of state.expandedDirectories.buried) {\n try {\n const node = yield this.root.loadTreeNodeByPath(relPath);\n if (!node) {\n break;\n }\n if (node && TreeNode_1.CompositeTreeNode.is(node)) {\n node.setCollapsed();\n }\n }\n catch (error) { }\n }\n for (const relPath of state.expandedDirectories.atSurface) {\n try {\n const node = yield this.root.loadTreeNodeByPath(relPath, true);\n if (!node) {\n break;\n }\n }\n catch (error) { }\n }\n this._scrollOffset =\n typeof state.scrollPosition === 'number' && state.scrollPosition > -1\n ? state.scrollPosition\n : this._scrollOffset;\n this.root.watcher.notifyDidUpdateBranch();\n this.onDidLoadStateEmitter.fire();\n }\n });\n }\n /**\n * 确保在调用`reverseStash`时,目录扩展不会被更改,以免导致节点内文件被排除\n */\n excludeFromStash(file) {\n if (this.stashKeyframes && !this.stashing) {\n this.handleExpansionChange(!TreeNode_1.CompositeTreeNode.is(file) ? file.parent : file, true, this.root.isItemVisibleAtSurface(file));\n }\n }\n /**\n * 开始记录点\n */\n beginStashing() {\n this.stashing = true;\n this.stashKeyframes = new Map();\n }\n /**\n * 结束记录点\n */\n endStashing() {\n this.stashing = false;\n this.stashLockingItems.clear();\n }\n /**\n * 反转记录的所有折叠/展开状态\n * 用于实现一些临时的查看操作\n * 例如:\n * 调用beginStashing ==> 展开/折叠某个目录 ==> 调用endStashing ==> 处理完毕后调用reverseStash,回到原来的状态\n */\n reverseStash() {\n return tslib_1.__awaiter(this, void 0, void 0, function* () {\n if (!this.stashKeyframes) {\n return;\n }\n this.endStashing();\n const keyframes = Array.from(this.stashKeyframes);\n this.stashKeyframes = null;\n for (const [targetID, flags] of keyframes) {\n const frameDisabled = (flags & StashKeyFrameFlag.Disabled) === StashKeyFrameFlag.Disabled;\n const target = TreeNode_1.TreeNode.getTreeNodeById(targetID);\n // 判断当前操作对象是否有效,无效则做下一步操作\n if (!target || frameDisabled) {\n continue;\n }\n if ((flags & StashKeyFrameFlag.Expanded) === StashKeyFrameFlag.Expanded) {\n target.setCollapsed();\n }\n else if ((flags & StashKeyFrameFlag.Collapsed) === StashKeyFrameFlag.Collapsed) {\n yield target.setExpanded();\n }\n }\n });\n }\n}\nexports.TreeStateManager = TreeStateManager;\n\n\n//# sourceURL=webpack://@opensumi/ide-components/./src/recycle-tree/tree/model/treeState/TreeStateManager.ts?");
5527
5516
 
5528
5517
  /***/ }),
5529
5518
 
@@ -6742,7 +6731,7 @@ eval("\n/* ---------------------------------------------------------------------
6742
6731
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
6743
6732
 
6744
6733
  "use strict";
6745
- eval("\n/* ---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n// Some code copied and modified from https://github.com/microsoft/vscode/blob/1.44.0/src/vs/base/common/event.ts\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.EventQueue = exports.Dispatcher = exports.ReadyEvent = exports.Relay = exports.EventBufferer = exports.EventMultiplexer = exports.AsyncEmitter = exports.WaitUntilEvent = exports.PauseableEmitter = exports.Emitter = exports.setGlobalLeakWarningThreshold = exports.Event = void 0;\nconst disposable_1 = __webpack_require__(/*! ./disposable */ \"../utils/lib/disposable.js\");\nconst errors_1 = __webpack_require__(/*! ./errors */ \"../utils/lib/errors.js\");\nconst functional_1 = __webpack_require__(/*! ./functional */ \"../utils/lib/functional.js\");\nconst linked_list_1 = __webpack_require__(/*! ./linked-list */ \"../utils/lib/linked-list.js\");\nconst uuid_1 = __webpack_require__(/*! ./uuid */ \"../utils/lib/uuid.js\");\nvar Event;\n(function (Event) {\n const _disposable = { dispose() { } };\n Event.None = function () {\n return _disposable;\n };\n /**\n * Given an event, returns another event which only fires once.\n */\n function once(event) {\n return (listener, thisArgs = null, disposables) => {\n // we need this, in case the event fires during the listener call\n let didFire = false;\n const result = event((e) => {\n if (didFire) {\n return;\n }\n else if (result) {\n result.dispose();\n }\n else {\n didFire = true;\n }\n return listener.call(thisArgs, e);\n }, null, disposables);\n if (didFire) {\n result.dispose();\n }\n return result;\n };\n }\n Event.once = once;\n /**\n * Given an event and a `map` function, returns another event which maps each element\n * throught the mapping function.\n */\n function map(event, map) {\n return snapshot((listener, thisArgs = null, disposables) => event((i) => listener.call(thisArgs, map(i)), null, disposables));\n }\n Event.map = map;\n /**\n * Given an event and an `each` function, returns another identical event and calls\n * the `each` function per each element.\n */\n function forEach(event, each) {\n return snapshot((listener, thisArgs = null, disposables) => event((i) => {\n each(i);\n listener.call(thisArgs, i);\n }, null, disposables));\n }\n Event.forEach = forEach;\n function filter(event, filter) {\n return snapshot((listener, thisArgs = null, disposables) => event((e) => filter(e) && listener.call(thisArgs, e), null, disposables));\n }\n Event.filter = filter;\n /**\n * Given an event, returns the same event but typed as `Event<void>`.\n */\n function signal(event) {\n return event;\n }\n Event.signal = signal;\n /**\n * Given a collection of events, returns a single event which emits\n * whenever any of the provided events emit.\n */\n function any(...events) {\n return (listener, thisArgs = null, disposables) => (0, disposable_1.combinedDisposable)(events.map((event) => event((e) => listener.call(thisArgs, e), null, disposables)));\n }\n Event.any = any;\n /**\n * Given an event and a `merge` function, returns another event which maps each element\n * and the cummulative result throught the `merge` function. Similar to `map`, but with memory.\n */\n function reduce(event, merge, initial) {\n let output = initial;\n return map(event, (e) => {\n output = merge(output, e);\n return output;\n });\n }\n Event.reduce = reduce;\n /**\n * Given a chain of event processing functions (filter, map, etc), each\n * function will be invoked per event & per listener. Snapshotting an event\n * chain allows each function to be invoked just once per event.\n */\n function snapshot(event) {\n let listener;\n const emitter = new Emitter({\n onFirstListenerAdd() {\n listener = event(emitter.fire, emitter);\n },\n onLastListenerRemove() {\n listener.dispose();\n },\n });\n return emitter.event;\n }\n Event.snapshot = snapshot;\n function debounce(event, merge, delay = 100, leading = false, leakWarningThreshold) {\n let subscription;\n let output;\n let handle;\n let numDebouncedCalls = 0;\n const emitter = new Emitter({\n leakWarningThreshold,\n onFirstListenerAdd() {\n subscription = event((cur) => {\n numDebouncedCalls++;\n output = merge(output, cur);\n if (leading && !handle) {\n emitter.fire(output);\n }\n clearTimeout(handle);\n handle = setTimeout(() => {\n const _output = output;\n output = undefined;\n handle = undefined;\n if (!leading || numDebouncedCalls > 1) {\n emitter.fire(_output);\n }\n numDebouncedCalls = 0;\n }, delay);\n });\n },\n onLastListenerRemove() {\n subscription.dispose();\n },\n });\n return emitter.event;\n }\n Event.debounce = debounce;\n /**\n * Given an event, it returns another event which fires only once and as soon as\n * the input event emits. The event data is the number of millis it took for the\n * event to fire.\n */\n function stopwatch(event) {\n const start = new Date().getTime();\n return map(once(event), (_) => new Date().getTime() - start);\n }\n Event.stopwatch = stopwatch;\n /**\n * Given an event, it returns another event which fires only when the event\n * element changes.\n */\n function latch(event) {\n let firstCall = true;\n let cache;\n return filter(event, (value) => {\n const shouldEmit = firstCall || value !== cache;\n firstCall = false;\n cache = value;\n return shouldEmit;\n });\n }\n Event.latch = latch;\n /**\n * Buffers the provided event until a first listener comes\n * along, at which point fire all the events at once and\n * pipe the event from then on.\n *\n * ```typescript\n * const emitter = new Emitter<number>();\n * const event = emitter.event;\n * const bufferedEvent = buffer(event);\n *\n * emitter.fire(1);\n * emitter.fire(2);\n * emitter.fire(3);\n * // nothing...\n *\n * const listener = bufferedEvent(num => console.log(num));\n * // 1, 2, 3\n *\n * emitter.fire(4);\n * // 4\n * ```\n */\n function buffer(event, nextTick = false, _buffer = []) {\n let buffer = _buffer.slice();\n let listener = event((e) => {\n if (buffer) {\n buffer.push(e);\n }\n else {\n emitter.fire(e);\n }\n });\n const flush = () => {\n if (buffer) {\n buffer.forEach((e) => emitter.fire(e));\n }\n buffer = null;\n };\n const emitter = new Emitter({\n onFirstListenerAdd() {\n if (!listener) {\n listener = event((e) => emitter.fire(e));\n }\n },\n onFirstListenerDidAdd() {\n if (buffer) {\n if (nextTick) {\n setTimeout(flush);\n }\n else {\n flush();\n }\n }\n },\n onLastListenerRemove() {\n if (listener) {\n listener.dispose();\n }\n listener = null;\n },\n });\n return emitter.event;\n }\n Event.buffer = buffer;\n class ChainableEvent {\n constructor(event) {\n this.event = event;\n }\n map(fn) {\n return new ChainableEvent(map(this.event, fn));\n }\n forEach(fn) {\n return new ChainableEvent(forEach(this.event, fn));\n }\n filter(fn) {\n return new ChainableEvent(filter(this.event, fn));\n }\n reduce(merge, initial) {\n return new ChainableEvent(reduce(this.event, merge, initial));\n }\n latch() {\n return new ChainableEvent(latch(this.event));\n }\n on(listener, thisArgs, disposables) {\n return this.event(listener, thisArgs, disposables);\n }\n once(listener, thisArgs, disposables) {\n return once(this.event)(listener, thisArgs, disposables);\n }\n }\n function chain(event) {\n return new ChainableEvent(event);\n }\n Event.chain = chain;\n function fromNodeEventEmitter(emitter, eventName, map = (id) => id) {\n const fn = (...args) => result.fire(map(...args));\n const onFirstListenerAdd = () => emitter.on(eventName, fn);\n const onLastListenerRemove = () => emitter.removeListener(eventName, fn);\n const result = new Emitter({ onFirstListenerAdd, onLastListenerRemove });\n return result.event;\n }\n Event.fromNodeEventEmitter = fromNodeEventEmitter;\n function fromPromise(promise) {\n const emitter = new Emitter();\n let shouldEmit = false;\n promise\n .then(undefined, () => null)\n .then(() => {\n if (!shouldEmit) {\n setTimeout(() => emitter.fire(undefined), 0);\n }\n else {\n emitter.fire(undefined);\n }\n });\n shouldEmit = true;\n return emitter.event;\n }\n Event.fromPromise = fromPromise;\n function toPromise(event) {\n return new Promise((c) => once(event)(c));\n }\n Event.toPromise = toPromise;\n})(Event = exports.Event || (exports.Event = {}));\nlet _globalLeakWarningThreshold = -1;\nfunction setGlobalLeakWarningThreshold(n) {\n const oldValue = _globalLeakWarningThreshold;\n _globalLeakWarningThreshold = n;\n return {\n dispose() {\n _globalLeakWarningThreshold = oldValue;\n },\n };\n}\nexports.setGlobalLeakWarningThreshold = setGlobalLeakWarningThreshold;\nclass LeakageMonitor {\n constructor(customThreshold, name = (0, uuid_1.randomString)(3)) {\n this.customThreshold = customThreshold;\n this.name = name;\n this._warnCountdown = 0;\n }\n dispose() {\n if (this._stacks) {\n this._stacks.clear();\n }\n }\n check(listenerCount) {\n let threshold = _globalLeakWarningThreshold;\n if (typeof this.customThreshold === 'number') {\n threshold = this.customThreshold;\n }\n if (threshold <= 0 || listenerCount < threshold) {\n return undefined;\n }\n if (!this._stacks) {\n this._stacks = new Map();\n }\n const stack = new Error().stack.split('\\n').slice(3).join('\\n');\n const count = this._stacks.get(stack) || 0;\n this._stacks.set(stack, count + 1);\n this._warnCountdown -= 1;\n if (this._warnCountdown <= 0) {\n // only warn on first exceed and then every time the limit\n // is exceeded by 50% again\n this._warnCountdown = threshold * 0.5;\n // find most frequent listener and print warning\n let topStack = '';\n let topCount = 0;\n this._stacks.forEach((count, stack) => {\n if (!topStack || topCount < count) {\n topStack = stack;\n topCount = count;\n }\n });\n // eslint-disable-next-line no-console\n console.warn(`[${this.name}] potential listener LEAK detected, having ${listenerCount} listeners already. MOST frequent listener (${topCount}):`);\n // eslint-disable-next-line no-console\n console.warn(topStack);\n }\n return () => {\n const count = this._stacks.get(stack) || 0;\n this._stacks.set(stack, count - 1);\n };\n }\n}\nclass Emitter {\n constructor(options) {\n this._disposed = false;\n this._options = options;\n this._leakageMon =\n _globalLeakWarningThreshold > 0\n ? new LeakageMonitor(this._options && this._options.leakWarningThreshold)\n : undefined;\n }\n /**\n * For the public to allow to subscribe\n * to events from this Emitter\n */\n get event() {\n if (!this._event) {\n this._event = (listener, thisArgs, disposables) => {\n if (!this._listeners) {\n this._listeners = new linked_list_1.LinkedList();\n }\n const firstListener = this._listeners.isEmpty();\n if (firstListener && this._options && this._options.onFirstListenerAdd) {\n this._options.onFirstListenerAdd(this);\n }\n const remove = this._listeners.push(!thisArgs ? listener : [listener, thisArgs]);\n if (firstListener && this._options && this._options.onFirstListenerDidAdd) {\n this._options.onFirstListenerDidAdd(this);\n }\n if (this._options && this._options.onListenerDidAdd) {\n this._options.onListenerDidAdd(this, listener, thisArgs);\n }\n // check and record this emitter for potential leakage\n let removeMonitor;\n if (this._leakageMon) {\n removeMonitor = this._leakageMon.check(this._listeners.size);\n }\n let result;\n result = {\n dispose: () => {\n if (removeMonitor) {\n removeMonitor();\n }\n result.dispose = Emitter._noop;\n if (!this._disposed) {\n remove();\n if (this._options && this._options.onLastListenerRemove) {\n const hasListeners = this._listeners && !this._listeners.isEmpty();\n if (!hasListeners) {\n this._options.onLastListenerRemove(this);\n }\n }\n }\n },\n };\n if (disposables instanceof disposable_1.DisposableStore) {\n disposables.add(result);\n }\n else if (Array.isArray(disposables)) {\n disposables.push(result);\n }\n return result;\n };\n }\n return this._event;\n }\n /**\n * To be kept private to fire an event to\n * subscribers\n */\n fire(event) {\n if (this._listeners) {\n // put all [listener,event]-pairs into delivery queue\n // then emit all event. an inner/nested event might be\n // the driver of this\n if (!this._deliveryQueue) {\n this._deliveryQueue = new linked_list_1.LinkedList();\n }\n for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) {\n this._deliveryQueue.push([e.value, event]);\n }\n while (this._deliveryQueue.size > 0) {\n const [listener, event] = this._deliveryQueue.shift();\n try {\n if (typeof listener === 'function') {\n listener.call(undefined, event);\n }\n else {\n listener[0].call(listener[1], event);\n }\n }\n catch (e) {\n (0, errors_1.onUnexpectedError)(e);\n }\n }\n }\n }\n /**\n * 发送一个异步事件,等待所有监听器返回,并收集返回值\n * @param e\n * @param timeout\n */\n async fireAndAwait(event, timeout = 2000) {\n if (this._listeners) {\n if (!this._deliveryQueue) {\n this._deliveryQueue = new linked_list_1.LinkedList();\n }\n for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) {\n this._deliveryQueue.push([e.value, event]);\n }\n const promises = [];\n const timeoutPromise = new Promise((resolve) => {\n setTimeout(() => {\n resolve({\n err: new Error('timeout'),\n });\n }, timeout);\n });\n while (this._deliveryQueue.size > 0) {\n const [listener, event] = this._deliveryQueue.shift();\n try {\n const promise = (async () => {\n try {\n if (typeof listener === 'function') {\n return {\n result: (await listener.call(undefined, event)),\n };\n }\n else {\n return {\n result: (await listener[0].call(listener[1], event)),\n };\n }\n }\n catch (e) {\n return {\n err: e,\n };\n }\n })();\n promises.push(Promise.race([timeoutPromise, promise]));\n }\n catch (e) {\n (0, errors_1.onUnexpectedError)(e);\n }\n }\n return Promise.all(promises);\n }\n else {\n return [];\n }\n }\n get listenerSize() {\n return this._listeners ? this._listeners.size : 0;\n }\n dispose() {\n if (this._listeners) {\n this._listeners.clear();\n }\n if (this._deliveryQueue) {\n this._deliveryQueue.clear();\n }\n if (this._leakageMon) {\n this._leakageMon.dispose();\n }\n this._disposed = true;\n }\n}\nexports.Emitter = Emitter;\nEmitter._noop = function () { };\nclass PauseableEmitter extends Emitter {\n constructor(options) {\n super(options);\n this._isPaused = 0;\n this._eventQueue = new linked_list_1.LinkedList();\n this._mergeFn = options && options.merge;\n }\n pause() {\n this._isPaused++;\n }\n resume() {\n if (this._isPaused !== 0 && --this._isPaused === 0) {\n if (this._mergeFn) {\n // use the merge function to create a single composite\n // event. make a copy in case firing pauses this emitter\n const events = this._eventQueue.toArray();\n this._eventQueue.clear();\n super.fire(this._mergeFn(events));\n }\n else {\n // no merging, fire each event individually and test\n // that this emitter isn't paused halfway through\n while (!this._isPaused && this._eventQueue.size !== 0) {\n super.fire(this._eventQueue.shift());\n }\n }\n }\n }\n fire(event) {\n if (this._listeners) {\n if (this._isPaused !== 0) {\n this._eventQueue.push(event);\n }\n else {\n super.fire(event);\n }\n }\n }\n}\nexports.PauseableEmitter = PauseableEmitter;\nvar WaitUntilEvent;\n(function (WaitUntilEvent) {\n async function fire(emitter, event, timeout = undefined) {\n const waitables = [];\n const asyncEvent = Object.assign(event, {\n waitUntil: (thenable) => {\n if (Object.isFrozen(waitables)) {\n throw new Error('waitUntil cannot be called asynchronously.');\n }\n waitables.push(thenable);\n },\n });\n emitter.fire(asyncEvent);\n // Asynchronous calls to `waitUntil` should fail.\n Object.freeze(waitables);\n // ts 要求 delete 的属性是 optional\n delete asyncEvent.waitUntil;\n if (!waitables.length) {\n return;\n }\n if (timeout !== undefined) {\n await Promise.race([Promise.all(waitables), new Promise((resolve) => setTimeout(resolve, timeout))]);\n }\n else {\n await Promise.all(waitables);\n }\n }\n WaitUntilEvent.fire = fire;\n})(WaitUntilEvent = exports.WaitUntilEvent || (exports.WaitUntilEvent = {}));\nclass AsyncEmitter extends Emitter {\n async fireAsync(data, token, promiseJoin) {\n if (!this._listeners) {\n return;\n }\n if (!this._asyncDeliveryQueue) {\n this._asyncDeliveryQueue = new linked_list_1.LinkedList();\n }\n for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) {\n this._asyncDeliveryQueue.push([e.value, data]);\n }\n while (this._asyncDeliveryQueue.size > 0 && !token.isCancellationRequested) {\n const [listener, data] = this._asyncDeliveryQueue.shift();\n const thenables = [];\n const event = Object.assign(Object.assign({}, data), { waitUntil: (p) => {\n if (Object.isFrozen(thenables)) {\n throw new Error('waitUntil can NOT be called asynchronous');\n }\n if (promiseJoin) {\n p = promiseJoin(p, typeof listener === 'function' ? listener : listener[0]);\n }\n thenables.push(p);\n } });\n try {\n if (typeof listener === 'function') {\n listener.call(undefined, event);\n }\n else {\n listener[0].call(listener[1], event);\n }\n }\n catch (e) {\n (0, errors_1.onUnexpectedError)(e);\n continue;\n }\n // freeze thenables-collection to enforce sync-calls to\n // wait until and then wait for all thenables to resolve\n Object.freeze(thenables);\n await Promise.all(\n // Promise.allSettled 只有 core-js3 才支持,先手动加 catch 处理下\n thenables.map((thenable) => thenable.catch((e) => e))).catch((e) => (0, errors_1.onUnexpectedError)(e));\n }\n }\n}\nexports.AsyncEmitter = AsyncEmitter;\nclass EventMultiplexer {\n constructor() {\n this.hasListeners = false;\n this.events = [];\n this.emitter = new Emitter({\n onFirstListenerAdd: () => this.onFirstListenerAdd(),\n onLastListenerRemove: () => this.onLastListenerRemove(),\n });\n }\n get event() {\n return this.emitter.event;\n }\n add(event) {\n const e = { event, listener: null };\n this.events.push(e);\n if (this.hasListeners) {\n this.hook(e);\n }\n const dispose = () => {\n if (this.hasListeners) {\n this.unhook(e);\n }\n const idx = this.events.indexOf(e);\n this.events.splice(idx, 1);\n };\n return (0, disposable_1.toDisposable)((0, functional_1.once)(dispose));\n }\n onFirstListenerAdd() {\n this.hasListeners = true;\n this.events.forEach((e) => this.hook(e));\n }\n onLastListenerRemove() {\n this.hasListeners = false;\n this.events.forEach((e) => this.unhook(e));\n }\n hook(e) {\n e.listener = e.event((r) => this.emitter.fire(r));\n }\n unhook(e) {\n if (e.listener) {\n e.listener.dispose();\n }\n e.listener = null;\n }\n dispose() {\n this.emitter.dispose();\n }\n}\nexports.EventMultiplexer = EventMultiplexer;\n/**\n * The EventBufferer is useful in situations in which you want\n * to delay firing your events during some code.\n * You can wrap that code and be sure that the event will not\n * be fired during that wrap.\n *\n * ```\n * const emitter: Emitter;\n * const delayer = new EventDelayer();\n * const delayedEvent = delayer.wrapEvent(emitter.event);\n *\n * delayedEvent(console.log);\n *\n * delayer.bufferEvents(() => {\n * emitter.fire(); // event will not be fired yet\n * });\n *\n * // event will only be fired at this point\n * ```\n */\nclass EventBufferer {\n constructor() {\n this.buffers = [];\n }\n wrapEvent(event) {\n return (listener, thisArgs, disposables) => event((i) => {\n const buffer = this.buffers[this.buffers.length - 1];\n if (buffer) {\n buffer.push(() => listener.call(thisArgs, i));\n }\n else {\n listener.call(thisArgs, i);\n }\n }, undefined, disposables);\n }\n bufferEvents(fn) {\n const buffer = [];\n this.buffers.push(buffer);\n const r = fn();\n this.buffers.pop();\n buffer.forEach((flush) => flush());\n return r;\n }\n}\nexports.EventBufferer = EventBufferer;\n/**\n * A Relay is an event forwarder which functions as a replugabble event pipe.\n * Once created, you can connect an input event to it and it will simply forward\n * events from that input event through its own `event` property. The `input`\n * can be changed at any point in time.\n */\nclass Relay {\n constructor() {\n this.listening = false;\n this.inputEvent = Event.None;\n this.inputEventListener = disposable_1.Disposable.None;\n this.emitter = new Emitter({\n onFirstListenerDidAdd: () => {\n this.listening = true;\n this.inputEventListener = this.inputEvent(this.emitter.fire, this.emitter);\n },\n onLastListenerRemove: () => {\n this.listening = false;\n this.inputEventListener.dispose();\n },\n });\n this.event = this.emitter.event;\n }\n set input(event) {\n this.inputEvent = event;\n if (this.listening) {\n this.inputEventListener.dispose();\n this.inputEventListener = event(this.emitter.fire, this.emitter);\n }\n }\n dispose() {\n this.inputEventListener.dispose();\n this.emitter.dispose();\n }\n}\nexports.Relay = Relay;\n/**\n * 同步执行的 Ready, 对 ready 的实时响应比 promise 快,多用在需要快速响应初始化回调的场景\n */\nclass ReadyEvent {\n constructor() {\n this._isReady = false;\n this._param = undefined;\n this._emitter = new Emitter();\n }\n onceReady(cb) {\n if (this._isReady) {\n try {\n return Promise.resolve(cb(this._param));\n }\n catch (e) {\n return Promise.reject(e);\n }\n }\n else {\n return new Promise((resolve, reject) => {\n this._emitter.event((param) => {\n try {\n resolve(cb(param));\n }\n catch (e) {\n reject(e);\n }\n });\n });\n }\n }\n ready(param) {\n if (!this._isReady) {\n this._isReady = true;\n this._param = param;\n }\n this._emitter.fire(param);\n this._emitter.dispose();\n this._emitter = null;\n }\n dispose() {\n if (this._emitter) {\n this._emitter.dispose();\n }\n }\n}\nexports.ReadyEvent = ReadyEvent;\nclass Dispatcher {\n constructor() {\n this._emitter = new Emitter();\n }\n on(type) {\n return Event.map(Event.filter(this._emitter.event, (e) => e.type === type), (v) => v.data);\n }\n dispatch(type, data) {\n this._emitter.fire({\n type,\n data,\n });\n }\n dispose() {\n if (this._emitter) {\n this._emitter.dispose();\n }\n }\n}\nexports.Dispatcher = Dispatcher;\nclass EventQueue {\n constructor() {\n this.emitter = new Emitter();\n this.queue = [];\n this.isOpened = false;\n }\n open() {\n this.isOpened = true;\n this.queue.forEach((data) => {\n this.emitter.fire(data);\n });\n this.queue = [];\n }\n push(data) {\n if (this.isOpened) {\n this.emitter.fire(data);\n }\n else {\n this.queue.push(data);\n }\n }\n on(cb) {\n const disposable = this.emitter.event(cb);\n if (!this.isOpened) {\n this.open();\n }\n return disposable;\n }\n dispose() {\n this.emitter.dispose();\n }\n}\nexports.EventQueue = EventQueue;\n//# sourceMappingURL=event.js.map\n\n//# sourceURL=webpack://@opensumi/ide-components/../utils/lib/event.js?");
6734
+ eval("\n/* ---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n// Some code copied and modified from https://github.com/microsoft/vscode/blob/1.44.0/src/vs/base/common/event.ts\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.EventQueue = exports.Dispatcher = exports.ReadyEvent = exports.Relay = exports.EventBufferer = exports.EventMultiplexer = exports.AsyncEmitter = exports.WaitUntilEvent = exports.PauseableEmitter = exports.Emitter = exports.setGlobalLeakWarningThreshold = exports.Event = void 0;\nconst disposable_1 = __webpack_require__(/*! ./disposable */ \"../utils/lib/disposable.js\");\nconst errors_1 = __webpack_require__(/*! ./errors */ \"../utils/lib/errors.js\");\nconst functional_1 = __webpack_require__(/*! ./functional */ \"../utils/lib/functional.js\");\nconst linked_list_1 = __webpack_require__(/*! ./linked-list */ \"../utils/lib/linked-list.js\");\nconst uuid_1 = __webpack_require__(/*! ./uuid */ \"../utils/lib/uuid.js\");\nvar Event;\n(function (Event) {\n const _disposable = { dispose() { } };\n Event.None = function () {\n return _disposable;\n };\n /**\n * Given an event, returns another event which only fires once.\n */\n function once(event) {\n return (listener, thisArgs = null, disposables) => {\n // we need this, in case the event fires during the listener call\n let didFire = false;\n const result = event((e) => {\n if (didFire) {\n return;\n }\n else if (result) {\n result.dispose();\n }\n else {\n didFire = true;\n }\n return listener.call(thisArgs, e);\n }, null, disposables);\n if (didFire) {\n result.dispose();\n }\n return result;\n };\n }\n Event.once = once;\n /**\n * Given an event and a `map` function, returns another event which maps each element\n * throught the mapping function.\n */\n function map(event, map) {\n return snapshot((listener, thisArgs = null, disposables) => event((i) => listener.call(thisArgs, map(i)), null, disposables));\n }\n Event.map = map;\n /**\n * Given an event and an `each` function, returns another identical event and calls\n * the `each` function per each element.\n */\n function forEach(event, each) {\n return snapshot((listener, thisArgs = null, disposables) => event((i) => {\n each(i);\n listener.call(thisArgs, i);\n }, null, disposables));\n }\n Event.forEach = forEach;\n function filter(event, filter) {\n return snapshot((listener, thisArgs = null, disposables) => event((e) => filter(e) && listener.call(thisArgs, e), null, disposables));\n }\n Event.filter = filter;\n /**\n * Given an event, returns the same event but typed as `Event<void>`.\n */\n function signal(event) {\n return event;\n }\n Event.signal = signal;\n /**\n * Given a collection of events, returns a single event which emits\n * whenever any of the provided events emit.\n */\n function any(...events) {\n return (listener, thisArgs = null, disposables) => (0, disposable_1.combinedDisposable)(events.map((event) => event((e) => listener.call(thisArgs, e), null, disposables)));\n }\n Event.any = any;\n /**\n * Given an event and a `merge` function, returns another event which maps each element\n * and the cummulative result throught the `merge` function. Similar to `map`, but with memory.\n */\n function reduce(event, merge, initial) {\n let output = initial;\n return map(event, (e) => {\n output = merge(output, e);\n return output;\n });\n }\n Event.reduce = reduce;\n /**\n * Given a chain of event processing functions (filter, map, etc), each\n * function will be invoked per event & per listener. Snapshotting an event\n * chain allows each function to be invoked just once per event.\n */\n function snapshot(event) {\n let listener;\n const emitter = new Emitter({\n onFirstListenerAdd() {\n listener = event(emitter.fire, emitter);\n },\n onLastListenerRemove() {\n listener.dispose();\n },\n });\n return emitter.event;\n }\n Event.snapshot = snapshot;\n function debounce(event, merge, delay = 100, leading = false, leakWarningThreshold) {\n let subscription;\n let output;\n let handle;\n let numDebouncedCalls = 0;\n const emitter = new Emitter({\n leakWarningThreshold,\n onFirstListenerAdd() {\n subscription = event((cur) => {\n numDebouncedCalls++;\n output = merge(output, cur);\n if (leading && !handle) {\n emitter.fire(output);\n }\n clearTimeout(handle);\n handle = setTimeout(() => {\n const _output = output;\n output = undefined;\n handle = undefined;\n if (!leading || numDebouncedCalls > 1) {\n emitter.fire(_output);\n }\n numDebouncedCalls = 0;\n }, delay);\n });\n },\n onLastListenerRemove() {\n subscription.dispose();\n },\n });\n return emitter.event;\n }\n Event.debounce = debounce;\n /**\n * Given an event, it returns another event which fires only once and as soon as\n * the input event emits. The event data is the number of millis it took for the\n * event to fire.\n */\n function stopwatch(event) {\n const start = new Date().getTime();\n return map(once(event), (_) => new Date().getTime() - start);\n }\n Event.stopwatch = stopwatch;\n /**\n * Given an event, it returns another event which fires only when the event\n * element changes.\n */\n function latch(event) {\n let firstCall = true;\n let cache;\n return filter(event, (value) => {\n const shouldEmit = firstCall || value !== cache;\n firstCall = false;\n cache = value;\n return shouldEmit;\n });\n }\n Event.latch = latch;\n /**\n * Buffers the provided event until a first listener comes\n * along, at which point fire all the events at once and\n * pipe the event from then on.\n *\n * ```typescript\n * const emitter = new Emitter<number>();\n * const event = emitter.event;\n * const bufferedEvent = buffer(event);\n *\n * emitter.fire(1);\n * emitter.fire(2);\n * emitter.fire(3);\n * // nothing...\n *\n * const listener = bufferedEvent(num => console.log(num));\n * // 1, 2, 3\n *\n * emitter.fire(4);\n * // 4\n * ```\n */\n function buffer(event, nextTick = false, _buffer = []) {\n let buffer = _buffer.slice();\n let listener = event((e) => {\n if (buffer) {\n buffer.push(e);\n }\n else {\n emitter.fire(e);\n }\n });\n const flush = () => {\n if (buffer) {\n buffer.forEach((e) => emitter.fire(e));\n }\n buffer = null;\n };\n const emitter = new Emitter({\n onFirstListenerAdd() {\n if (!listener) {\n listener = event((e) => emitter.fire(e));\n }\n },\n onFirstListenerDidAdd() {\n if (buffer) {\n if (nextTick) {\n setTimeout(flush);\n }\n else {\n flush();\n }\n }\n },\n onLastListenerRemove() {\n if (listener) {\n listener.dispose();\n }\n listener = null;\n },\n });\n return emitter.event;\n }\n Event.buffer = buffer;\n class ChainableEvent {\n constructor(event) {\n this.event = event;\n }\n map(fn) {\n return new ChainableEvent(map(this.event, fn));\n }\n forEach(fn) {\n return new ChainableEvent(forEach(this.event, fn));\n }\n filter(fn) {\n return new ChainableEvent(filter(this.event, fn));\n }\n reduce(merge, initial) {\n return new ChainableEvent(reduce(this.event, merge, initial));\n }\n latch() {\n return new ChainableEvent(latch(this.event));\n }\n on(listener, thisArgs, disposables) {\n return this.event(listener, thisArgs, disposables);\n }\n once(listener, thisArgs, disposables) {\n return once(this.event)(listener, thisArgs, disposables);\n }\n }\n function chain(event) {\n return new ChainableEvent(event);\n }\n Event.chain = chain;\n function fromNodeEventEmitter(emitter, eventName, map = (id) => id) {\n const fn = (...args) => result.fire(map(...args));\n const onFirstListenerAdd = () => emitter.on(eventName, fn);\n const onLastListenerRemove = () => emitter.removeListener(eventName, fn);\n const result = new Emitter({ onFirstListenerAdd, onLastListenerRemove });\n return result.event;\n }\n Event.fromNodeEventEmitter = fromNodeEventEmitter;\n function fromPromise(promise) {\n const emitter = new Emitter();\n let shouldEmit = false;\n promise\n .then(undefined, () => null)\n .then(() => {\n if (!shouldEmit) {\n setTimeout(() => emitter.fire(undefined), 0);\n }\n else {\n emitter.fire(undefined);\n }\n });\n shouldEmit = true;\n return emitter.event;\n }\n Event.fromPromise = fromPromise;\n function toPromise(event) {\n return new Promise((c) => once(event)(c));\n }\n Event.toPromise = toPromise;\n})(Event = exports.Event || (exports.Event = {}));\nlet _globalLeakWarningThreshold = -1;\nfunction setGlobalLeakWarningThreshold(n) {\n const oldValue = _globalLeakWarningThreshold;\n _globalLeakWarningThreshold = n;\n return {\n dispose() {\n _globalLeakWarningThreshold = oldValue;\n },\n };\n}\nexports.setGlobalLeakWarningThreshold = setGlobalLeakWarningThreshold;\nclass LeakageMonitor {\n constructor(customThreshold, name = (0, uuid_1.randomString)(3)) {\n this.customThreshold = customThreshold;\n this.name = name;\n this._warnCountdown = 0;\n }\n dispose() {\n if (this._stacks) {\n this._stacks.clear();\n }\n }\n check(listenerCount) {\n let threshold = _globalLeakWarningThreshold;\n if (typeof this.customThreshold === 'number') {\n threshold = this.customThreshold;\n }\n if (threshold <= 0 || listenerCount < threshold) {\n return undefined;\n }\n if (!this._stacks) {\n this._stacks = new Map();\n }\n const stack = new Error().stack.split('\\n').slice(3).join('\\n');\n const count = this._stacks.get(stack) || 0;\n this._stacks.set(stack, count + 1);\n this._warnCountdown -= 1;\n if (this._warnCountdown <= 0) {\n // only warn on first exceed and then every time the limit\n // is exceeded by 50% again\n this._warnCountdown = threshold * 0.5;\n // find most frequent listener and print warning\n let topStack = '';\n let topCount = 0;\n this._stacks.forEach((count, stack) => {\n if (!topStack || topCount < count) {\n topStack = stack;\n topCount = count;\n }\n });\n // eslint-disable-next-line no-console\n console.warn(`[${this.name}] potential listener LEAK detected, having ${listenerCount} listeners already. MOST frequent listener (${topCount}):`);\n // eslint-disable-next-line no-console\n console.warn(topStack);\n }\n return () => {\n const count = this._stacks.get(stack) || 0;\n this._stacks.set(stack, count - 1);\n };\n }\n}\nclass Emitter {\n constructor(options) {\n this._disposed = false;\n this._options = options;\n this._leakageMon =\n _globalLeakWarningThreshold > 0\n ? new LeakageMonitor(this._options && this._options.leakWarningThreshold)\n : undefined;\n }\n /**\n * For the public to allow to subscribe\n * to events from this Emitter\n */\n get event() {\n if (!this._event) {\n this._event = (listener, thisArgs, disposables) => {\n if (!this._listeners) {\n this._listeners = new linked_list_1.LinkedList();\n }\n const firstListener = this._listeners.isEmpty();\n if (firstListener && this._options && this._options.onFirstListenerAdd) {\n this._options.onFirstListenerAdd(this);\n }\n const remove = this._listeners.push(!thisArgs ? listener : [listener, thisArgs]);\n if (firstListener && this._options && this._options.onFirstListenerDidAdd) {\n this._options.onFirstListenerDidAdd(this);\n }\n if (this._options && this._options.onListenerDidAdd) {\n this._options.onListenerDidAdd(this, listener, thisArgs);\n }\n // check and record this emitter for potential leakage\n let removeMonitor;\n if (this._leakageMon) {\n removeMonitor = this._leakageMon.check(this._listeners.size);\n }\n let result;\n result = {\n dispose: () => {\n if (removeMonitor) {\n removeMonitor();\n }\n result.dispose = Emitter._noop;\n if (!this._disposed) {\n remove();\n if (this._options && this._options.onLastListenerRemove) {\n const hasListeners = this._listeners && !this._listeners.isEmpty();\n if (!hasListeners) {\n this._options.onLastListenerRemove(this);\n }\n }\n }\n },\n };\n if (disposables instanceof disposable_1.DisposableStore) {\n disposables.add(result);\n }\n else if (Array.isArray(disposables)) {\n disposables.push(result);\n }\n return result;\n };\n }\n return this._event;\n }\n /**\n * To be kept private to fire an event to\n * subscribers\n */\n fire(event) {\n if (this._listeners) {\n // put all [listener,event]-pairs into delivery queue\n // then emit all event. an inner/nested event might be\n // the driver of this\n if (!this._deliveryQueue) {\n this._deliveryQueue = new linked_list_1.LinkedList();\n }\n for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) {\n this._deliveryQueue.push([e.value, event]);\n }\n while (this._deliveryQueue.size > 0) {\n const [listener, event] = this._deliveryQueue.shift();\n try {\n if (typeof listener === 'function') {\n listener.call(undefined, event);\n }\n else {\n listener[0].call(listener[1], event);\n }\n }\n catch (e) {\n (0, errors_1.onUnexpectedError)(e);\n }\n }\n }\n }\n /**\n * 发送一个异步事件,等待所有监听器返回,并收集返回值\n * @param e\n * @param timeout\n */\n async fireAndAwait(event, timeout = 2000) {\n if (this._listeners) {\n if (!this._deliveryQueue) {\n this._deliveryQueue = new linked_list_1.LinkedList();\n }\n for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) {\n this._deliveryQueue.push([e.value, event]);\n }\n const promises = [];\n const timeoutPromise = new Promise((resolve) => {\n setTimeout(() => {\n resolve({\n err: new Error('timeout'),\n });\n }, timeout);\n });\n while (this._deliveryQueue.size > 0) {\n const [listener, event] = this._deliveryQueue.shift();\n try {\n const promise = (async () => {\n try {\n if (typeof listener === 'function') {\n return {\n result: (await listener.call(undefined, event)),\n };\n }\n else {\n return {\n result: (await listener[0].call(listener[1], event)),\n };\n }\n }\n catch (e) {\n return {\n err: e,\n };\n }\n })();\n promises.push(Promise.race([timeoutPromise, promise]));\n }\n catch (e) {\n (0, errors_1.onUnexpectedError)(e);\n }\n }\n return Promise.all(promises);\n }\n else {\n return [];\n }\n }\n get listenerSize() {\n return this._listeners ? this._listeners.size : 0;\n }\n dispose() {\n if (this._listeners) {\n this._listeners.clear();\n }\n if (this._deliveryQueue) {\n this._deliveryQueue.clear();\n }\n if (this._leakageMon) {\n this._leakageMon.dispose();\n }\n this._disposed = true;\n }\n}\nexports.Emitter = Emitter;\nEmitter._noop = function () { };\nclass PauseableEmitter extends Emitter {\n constructor(options) {\n super(options);\n this._isPaused = 0;\n this._eventQueue = new linked_list_1.LinkedList();\n this._mergeFn = options && options.merge;\n }\n pause() {\n this._isPaused++;\n }\n resume() {\n if (this._isPaused !== 0 && --this._isPaused === 0) {\n if (this._mergeFn) {\n // use the merge function to create a single composite\n // event. make a copy in case firing pauses this emitter\n const events = this._eventQueue.toArray();\n this._eventQueue.clear();\n super.fire(this._mergeFn(events));\n }\n else {\n // no merging, fire each event individually and test\n // that this emitter isn't paused halfway through\n while (!this._isPaused && this._eventQueue.size !== 0) {\n super.fire(this._eventQueue.shift());\n }\n }\n }\n }\n fire(event) {\n if (this._listeners) {\n if (this._isPaused !== 0) {\n this._eventQueue.push(event);\n }\n else {\n super.fire(event);\n }\n }\n }\n}\nexports.PauseableEmitter = PauseableEmitter;\nvar WaitUntilEvent;\n(function (WaitUntilEvent) {\n async function fire(emitter, event, timeout = undefined) {\n const waitables = [];\n const asyncEvent = Object.assign(event, {\n waitUntil: (thenable) => {\n if (Object.isFrozen(waitables)) {\n throw new Error('waitUntil cannot be called asynchronously.');\n }\n waitables.push(thenable);\n },\n });\n emitter.fire(asyncEvent);\n // Asynchronous calls to `waitUntil` should fail.\n Object.freeze(waitables);\n // ts 要求 delete 的属性是 optional\n delete asyncEvent.waitUntil;\n if (!waitables.length) {\n return;\n }\n if (timeout !== undefined) {\n await Promise.race([Promise.all(waitables), new Promise((resolve) => setTimeout(resolve, timeout))]);\n }\n else {\n await Promise.all(waitables);\n }\n }\n WaitUntilEvent.fire = fire;\n})(WaitUntilEvent = exports.WaitUntilEvent || (exports.WaitUntilEvent = {}));\nclass AsyncEmitter extends Emitter {\n async fireAsync(data, token, promiseJoin) {\n if (!this._listeners) {\n return;\n }\n if (!this._asyncDeliveryQueue) {\n this._asyncDeliveryQueue = new linked_list_1.LinkedList();\n }\n for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) {\n this._asyncDeliveryQueue.push([e.value, data]);\n }\n while (this._asyncDeliveryQueue.size > 0 && !token.isCancellationRequested) {\n const [listener, data] = this._asyncDeliveryQueue.shift();\n const thenables = [];\n const event = Object.assign(Object.assign({}, data), { waitUntil: (p) => {\n if (Object.isFrozen(thenables)) {\n throw new Error('waitUntil can NOT be called asynchronous');\n }\n if (promiseJoin) {\n p = promiseJoin(p, typeof listener === 'function' ? listener : listener[0]);\n }\n thenables.push(p);\n } });\n try {\n if (typeof listener === 'function') {\n listener.call(undefined, event);\n }\n else {\n listener[0].call(listener[1], event);\n }\n }\n catch (e) {\n (0, errors_1.onUnexpectedError)(e);\n continue;\n }\n // freeze thenables-collection to enforce sync-calls to\n // wait until and then wait for all thenables to resolve\n Object.freeze(thenables);\n await Promise.all(\n // Promise.allSettled 只有 core-js3 才支持,先手动加 catch 处理下\n thenables.map((thenable) => thenable.catch((e) => e))).catch((e) => (0, errors_1.onUnexpectedError)(e));\n }\n }\n}\nexports.AsyncEmitter = AsyncEmitter;\nclass EventMultiplexer {\n constructor() {\n this.hasListeners = false;\n this.events = [];\n this.emitter = new Emitter({\n onFirstListenerAdd: () => this.onFirstListenerAdd(),\n onLastListenerRemove: () => this.onLastListenerRemove(),\n });\n }\n get event() {\n return this.emitter.event;\n }\n add(event) {\n const e = { event, listener: null };\n this.events.push(e);\n if (this.hasListeners) {\n this.hook(e);\n }\n const dispose = () => {\n if (this.hasListeners) {\n this.unhook(e);\n }\n const idx = this.events.indexOf(e);\n this.events.splice(idx, 1);\n };\n return (0, disposable_1.toDisposable)((0, functional_1.once)(dispose));\n }\n onFirstListenerAdd() {\n this.hasListeners = true;\n this.events.forEach((e) => this.hook(e));\n }\n onLastListenerRemove() {\n this.hasListeners = false;\n this.events.forEach((e) => this.unhook(e));\n }\n hook(e) {\n e.listener = e.event((r) => this.emitter.fire(r));\n }\n unhook(e) {\n if (e.listener) {\n e.listener.dispose();\n }\n e.listener = null;\n }\n dispose() {\n this.emitter.dispose();\n }\n}\nexports.EventMultiplexer = EventMultiplexer;\n/**\n * The EventBufferer is useful in situations in which you want\n * to delay firing your events during some code.\n * You can wrap that code and be sure that the event will not\n * be fired during that wrap.\n *\n * ```\n * const emitter: Emitter;\n * const delayer = new EventDelayer();\n * const delayedEvent = delayer.wrapEvent(emitter.event);\n *\n * delayedEvent(console.log);\n *\n * delayer.bufferEvents(() => {\n * emitter.fire(); // event will not be fired yet\n * });\n *\n * // event will only be fired at this point\n * ```\n */\nclass EventBufferer {\n constructor() {\n this.buffers = [];\n }\n wrapEvent(event) {\n return (listener, thisArgs, disposables) => event((i) => {\n const buffer = this.buffers[this.buffers.length - 1];\n if (buffer) {\n buffer.push(() => listener.call(thisArgs, i));\n }\n else {\n listener.call(thisArgs, i);\n }\n }, undefined, disposables);\n }\n bufferEvents(fn) {\n const buffer = [];\n this.buffers.push(buffer);\n const r = fn();\n this.buffers.pop();\n buffer.forEach((flush) => flush());\n return r;\n }\n}\nexports.EventBufferer = EventBufferer;\n/**\n * A Relay is an event forwarder which functions as a replugabble event pipe.\n * Once created, you can connect an input event to it and it will simply forward\n * events from that input event through its own `event` property. The `input`\n * can be changed at any point in time.\n */\nclass Relay {\n constructor() {\n this.listening = false;\n this.inputEvent = Event.None;\n this.inputEventListener = disposable_1.Disposable.None;\n this.emitter = new Emitter({\n onFirstListenerDidAdd: () => {\n this.listening = true;\n this.inputEventListener = this.inputEvent(this.emitter.fire, this.emitter);\n },\n onLastListenerRemove: () => {\n this.listening = false;\n this.inputEventListener.dispose();\n },\n });\n this.event = this.emitter.event;\n }\n set input(event) {\n this.inputEvent = event;\n if (this.listening) {\n this.inputEventListener.dispose();\n this.inputEventListener = event(this.emitter.fire, this.emitter);\n }\n }\n dispose() {\n this.inputEventListener.dispose();\n this.emitter.dispose();\n }\n}\nexports.Relay = Relay;\n/**\n * 同步执行的 Ready, 对 ready 的实时响应比 promise 快,多用在需要快速响应初始化回调的场景\n */\nclass ReadyEvent {\n constructor() {\n this._isReady = false;\n this._param = undefined;\n this._emitter = new Emitter();\n }\n onceReady(cb) {\n if (this._isReady) {\n try {\n return Promise.resolve(cb(this._param));\n }\n catch (e) {\n return Promise.reject(e);\n }\n }\n else {\n return new Promise((resolve, reject) => {\n this._emitter.event((param) => {\n try {\n resolve(cb(param));\n }\n catch (e) {\n reject(e);\n }\n });\n });\n }\n }\n ready(param) {\n if (!this._isReady) {\n this._isReady = true;\n this._param = param;\n }\n this._emitter.fire(param);\n this._emitter.dispose();\n this._emitter = null;\n }\n dispose() {\n if (this._emitter) {\n this._emitter.dispose();\n }\n }\n}\nexports.ReadyEvent = ReadyEvent;\nclass Dispatcher {\n constructor() {\n this._emitter = new Emitter();\n }\n on(type) {\n return Event.map(Event.filter(this._emitter.event, (e) => e.type === type), (v) => v.data);\n }\n dispatch(type, data) {\n this._emitter.fire({\n type,\n data,\n });\n }\n dispose() {\n if (this._emitter) {\n this._emitter.dispose();\n }\n }\n}\nexports.Dispatcher = Dispatcher;\nclass EventQueue {\n constructor() {\n this._listeners = new linked_list_1.LinkedList();\n this.queue = [];\n this.isOpened = false;\n this.open = () => {\n this.isOpened = true;\n this.queue.forEach((data) => {\n this.fire(data);\n });\n this.queue = [];\n };\n this.close = () => {\n this.isOpened = false;\n };\n this.push = (data) => {\n if (this.isOpened) {\n this.fire(data);\n }\n else {\n this.queue.push(data);\n }\n };\n this.fire = (data) => {\n this._listeners.forEach((listener) => {\n listener(data);\n });\n };\n this.on = (cb) => {\n const toRemove = this._listeners.push(cb);\n if (!this.isOpened) {\n this.open();\n }\n return disposable_1.Disposable.create(() => {\n toRemove();\n if (this._listeners.size === 0) {\n this.close();\n }\n });\n };\n this.dispose = () => {\n this._listeners.clear();\n };\n }\n}\nexports.EventQueue = EventQueue;\n//# sourceMappingURL=event.js.map\n\n//# sourceURL=webpack://@opensumi/ide-components/../utils/lib/event.js?");
6746
6735
 
6747
6736
  /***/ }),
6748
6737
 
@@ -6841,7 +6830,7 @@ eval("\n/* ---------------------------------------------------------------------
6841
6830
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
6842
6831
 
6843
6832
  "use strict";
6844
- eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.LinkedList = void 0;\nconst iterator_1 = __webpack_require__(/*! ./iterator */ \"../utils/lib/iterator.js\");\nclass Node {\n constructor(element) {\n this.element = element;\n this.next = Node.Undefined;\n this.prev = Node.Undefined;\n }\n}\nNode.Undefined = new Node(undefined);\nclass LinkedList {\n constructor() {\n this._first = Node.Undefined;\n this._last = Node.Undefined;\n this._size = 0;\n }\n get size() {\n return this._size;\n }\n isEmpty() {\n return this._first === Node.Undefined;\n }\n clear() {\n this._first = Node.Undefined;\n this._last = Node.Undefined;\n this._size = 0;\n }\n unshift(element) {\n return this._insert(element, false);\n }\n push(element) {\n return this._insert(element, true);\n }\n _insert(element, atTheEnd) {\n const newNode = new Node(element);\n if (this._first === Node.Undefined) {\n this._first = newNode;\n this._last = newNode;\n }\n else if (atTheEnd) {\n // push\n const oldLast = this._last;\n this._last = newNode;\n newNode.prev = oldLast;\n oldLast.next = newNode;\n }\n else {\n // unshift\n const oldFirst = this._first;\n this._first = newNode;\n newNode.next = oldFirst;\n oldFirst.prev = newNode;\n }\n this._size += 1;\n let didRemove = false;\n return () => {\n if (!didRemove) {\n didRemove = true;\n this._remove(newNode);\n }\n };\n }\n shift() {\n if (this._first === Node.Undefined) {\n return undefined;\n }\n else {\n const res = this._first.element;\n this._remove(this._first);\n return res;\n }\n }\n pop() {\n if (this._last === Node.Undefined) {\n return undefined;\n }\n else {\n const res = this._last.element;\n this._remove(this._last);\n return res;\n }\n }\n _remove(node) {\n if (node.prev !== Node.Undefined && node.next !== Node.Undefined) {\n // middle\n const anchor = node.prev;\n anchor.next = node.next;\n node.next.prev = anchor;\n }\n else if (node.prev === Node.Undefined && node.next === Node.Undefined) {\n // only node\n this._first = Node.Undefined;\n this._last = Node.Undefined;\n }\n else if (node.next === Node.Undefined) {\n // last\n this._last = this._last.prev;\n this._last.next = Node.Undefined;\n }\n else if (node.prev === Node.Undefined) {\n // first\n this._first = this._first.next;\n this._first.prev = Node.Undefined;\n }\n // done\n this._size -= 1;\n }\n iterator() {\n let element;\n let node = this._first;\n return {\n next() {\n if (node === Node.Undefined) {\n return iterator_1.FIN;\n }\n if (!element) {\n element = { done: false, value: node.element };\n }\n else {\n element.value = node.element;\n }\n node = node.next;\n return element;\n },\n };\n }\n toArray() {\n const result = [];\n for (let node = this._first; node !== Node.Undefined; node = node.next) {\n result.push(node.element);\n }\n return result;\n }\n}\nexports.LinkedList = LinkedList;\n//# sourceMappingURL=linked-list.js.map\n\n//# sourceURL=webpack://@opensumi/ide-components/../utils/lib/linked-list.js?");
6833
+ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.LinkedList = void 0;\nconst errors_1 = __webpack_require__(/*! ./errors */ \"../utils/lib/errors.js\");\nconst iterator_1 = __webpack_require__(/*! ./iterator */ \"../utils/lib/iterator.js\");\nclass Node {\n constructor(element) {\n this.element = element;\n this.next = Node.Undefined;\n this.prev = Node.Undefined;\n }\n}\nNode.Undefined = new Node(undefined);\nclass LinkedList {\n constructor() {\n this._first = Node.Undefined;\n this._last = Node.Undefined;\n this._size = 0;\n }\n get size() {\n return this._size;\n }\n isEmpty() {\n return this._first === Node.Undefined;\n }\n clear() {\n this._first = Node.Undefined;\n this._last = Node.Undefined;\n this._size = 0;\n }\n unshift(element) {\n return this._insert(element, false);\n }\n push(element) {\n return this._insert(element, true);\n }\n _insert(element, atTheEnd) {\n const newNode = new Node(element);\n if (this._first === Node.Undefined) {\n this._first = newNode;\n this._last = newNode;\n }\n else if (atTheEnd) {\n // push\n const oldLast = this._last;\n this._last = newNode;\n newNode.prev = oldLast;\n oldLast.next = newNode;\n }\n else {\n // unshift\n const oldFirst = this._first;\n this._first = newNode;\n newNode.next = oldFirst;\n oldFirst.prev = newNode;\n }\n this._size += 1;\n let didRemove = false;\n return () => {\n if (!didRemove) {\n didRemove = true;\n this._remove(newNode);\n }\n };\n }\n shift() {\n if (this._first === Node.Undefined) {\n return undefined;\n }\n else {\n const res = this._first.element;\n this._remove(this._first);\n return res;\n }\n }\n pop() {\n if (this._last === Node.Undefined) {\n return undefined;\n }\n else {\n const res = this._last.element;\n this._remove(this._last);\n return res;\n }\n }\n _remove(node) {\n if (node.prev !== Node.Undefined && node.next !== Node.Undefined) {\n // middle\n const anchor = node.prev;\n anchor.next = node.next;\n node.next.prev = anchor;\n }\n else if (node.prev === Node.Undefined && node.next === Node.Undefined) {\n // only node\n this._first = Node.Undefined;\n this._last = Node.Undefined;\n }\n else if (node.next === Node.Undefined) {\n // last\n this._last = this._last.prev;\n this._last.next = Node.Undefined;\n }\n else if (node.prev === Node.Undefined) {\n // first\n this._first = this._first.next;\n this._first.prev = Node.Undefined;\n }\n // done\n this._size -= 1;\n }\n iterator() {\n let element;\n let node = this._first;\n return {\n next() {\n if (node === Node.Undefined) {\n return iterator_1.FIN;\n }\n if (!element) {\n element = { done: false, value: node.element };\n }\n else {\n element.value = node.element;\n }\n node = node.next;\n return element;\n },\n };\n }\n forEach(callback) {\n for (let node = this._first; node !== Node.Undefined; node = node.next) {\n try {\n callback(node.element);\n }\n catch (error) {\n (0, errors_1.onUnexpectedError)(error);\n }\n }\n }\n toArray() {\n const result = [];\n for (let node = this._first; node !== Node.Undefined; node = node.next) {\n result.push(node.element);\n }\n return result;\n }\n}\nexports.LinkedList = LinkedList;\n//# sourceMappingURL=linked-list.js.map\n\n//# sourceURL=webpack://@opensumi/ide-components/../utils/lib/linked-list.js?");
6845
6834
 
6846
6835
  /***/ }),
6847
6836
 
@@ -6918,7 +6907,7 @@ eval("/* provided dependency */ var process = __webpack_require__(/*! ../../node
6918
6907
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
6919
6908
 
6920
6909
  "use strict";
6921
- eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.findCommonRoot = exports.sortPathByDepth = exports.isValidBasename = exports.replaceAsarInPath = exports.delimiter = exports.sep = exports.toNamespacedPath = exports.parse = exports.format = exports.extname = exports.basename = exports.dirname = exports.relative = exports.resolve = exports.join = exports.isAbsolute = exports.normalize = exports.toSlashes = exports.posix = exports.win32 = exports.Path = void 0;\nconst tslib_1 = __webpack_require__(/*! tslib */ \"../../node_modules/tslib/tslib.es6.mjs\");\nconst platform_1 = __webpack_require__(/*! ./platform */ \"../utils/lib/platform.js\");\nconst process = tslib_1.__importStar(__webpack_require__(/*! ./process */ \"../utils/lib/process.js\"));\nconst SystemPathSeparatorRegex = platform_1.isWindows ? /\\\\/g : /\\//g;\n/**\n * On POSIX:\n * ┌──────────────────────┬────────────┐\n * │ dir │ base │\n * ├──────┬ ├──────┬─────┤\n * │ root │ │ name │ ext │\n * \" / home/user/dir / file .txt \"\n * └──────┴───────────────┴──────┴─────┘\n *\n * On Windows:\n * ┌──────────────────────┬────────────┐\n * │ dir │ base │\n * ├──────┬ ├──────┬─────┤\n * │ root │ │ name │ ext │\n * \" /c: / home/user/dir / file .txt \"\n * └──────┴───────────────┴──────┴─────┘\n */\nclass Path {\n static isDrive(segment) {\n return segment.endsWith(':');\n }\n static splitPath(path) {\n return path.split(Path.separator).filter((path) => !!path);\n }\n static joinPath(...parts) {\n return parts.join(Path.separator);\n }\n static isRelative(path) {\n return !path.startsWith(Path.separator);\n }\n static pathDepth(path) {\n return path.split(Path.separator).length;\n }\n /**\n * vscode-uri always normalizes drive letters to lower case:\n * https://github.com/Microsoft/vscode-uri/blob/b1d3221579f97f28a839b6f996d76fc45e9964d8/src/index.ts#L1025\n * Theia path should be adjusted to this.\n */\n static normalizeDrive(path) {\n // lower-case windows drive letters in /C:/fff or C:/fff\n if (path.length >= 3 && path.charCodeAt(0) === 47 /* '/' */ && path.charCodeAt(2) === 58 /* ':' */) {\n const code = path.charCodeAt(1);\n if (code >= 65 /* A */ && code <= 90 /* Z */) {\n path = `/${String.fromCharCode(code + 32)}:${path.substr(3)}`; // \"/c:\".length === 3\n }\n }\n else if (path.length >= 2 && path.charCodeAt(1) === 58 /* ':' */) {\n const code = path.charCodeAt(0);\n if (code >= 65 /* A */ && code <= 90 /* Z */) {\n path = `${String.fromCharCode(code + 32)}:${path.substr(2)}`; // \"/c:\".length === 3\n }\n }\n return path;\n }\n /**\n * The raw should be normalized, meaning that only '/' is allowed as a path separator.\n */\n constructor(raw) {\n raw = raw.replace(SystemPathSeparatorRegex, Path.separator);\n this.raw = Path.normalizeDrive(raw);\n const firstIndex = raw.indexOf(Path.separator);\n const lastIndex = raw.lastIndexOf(Path.separator);\n this.isAbsolute = firstIndex === 0;\n this.base = lastIndex === -1 ? raw : raw.substr(lastIndex + 1);\n this.isRoot = this.isAbsolute && firstIndex === lastIndex && (!this.base || Path.isDrive(this.base));\n this.root = this.computeRoot();\n const extIndex = this.base.lastIndexOf('.');\n // 处理无后缀文件或者 dot 打头的无后缀文件\n // file like 'a/b/c/test'\n if (extIndex === -1) {\n this.name = this.base;\n this.ext = '';\n }\n else if (extIndex === 0) {\n // dot file like `a/b/c/.eslintrc`\n this.name = this.base;\n this.ext = '';\n }\n else {\n this.name = this.base.substr(0, extIndex);\n this.ext = this.base.substr(extIndex);\n }\n }\n computeRoot() {\n // '/' -> '/'\n // '/c:' -> '/c:'\n if (this.isRoot) {\n return this;\n }\n // 'foo/bar' -> `undefined`\n if (!this.isAbsolute) {\n return undefined;\n }\n const index = this.raw.indexOf(Path.separator, Path.separator.length);\n if (index === -1) {\n // '/foo/bar' -> '/'\n return new Path(Path.separator);\n }\n // '/c:/foo/bar' -> '/c:'\n // '/foo/bar' -> '/'\n return new Path(this.raw.substr(0, index)).root;\n }\n get dir() {\n if (this._dir === undefined) {\n this._dir = this.computeDir();\n }\n return this._dir;\n }\n computeDir() {\n if (this.isRoot) {\n return this;\n }\n const lastIndex = this.raw.lastIndexOf(Path.separator);\n if (lastIndex === -1) {\n return this;\n }\n if (this.isAbsolute) {\n const firstIndex = this.raw.indexOf(Path.separator);\n if (firstIndex === lastIndex) {\n return new Path(this.raw.substr(0, firstIndex + 1));\n }\n }\n return new Path(this.raw.substr(0, lastIndex));\n }\n join(...paths) {\n const code = this.raw.charCodeAt(0);\n const isWindows = isWindowsDeviceRoot(code);\n /**\n * 只针对 IDE 后端运行在 Windows 的情况\n * join('C:\\\\path\\\\to\\\\file', 'path/to/other') === 'C:\\\\path\\\\to\\\\file\\\\path\\\\to\\\\other'\n */\n if (isWindows) {\n return new Path(exports.win32.join(this.raw, ...paths));\n }\n const relativePath = paths.filter((s) => !!s).join(Path.separator);\n if (!relativePath) {\n return this;\n }\n if (this.raw.endsWith(Path.separator) || relativePath.startsWith(Path.separator)) {\n return new Path(exports.posix.join(this.raw, relativePath));\n }\n return new Path(exports.posix.join(this.raw, Path.separator, relativePath));\n }\n toString() {\n return this.raw;\n }\n relative(path) {\n if (this.raw === path.raw) {\n return new Path('');\n }\n if (!this.raw || !path.raw) {\n return undefined;\n }\n const raw = this.base ? this.raw + Path.separator : this.raw;\n if (!path.raw.startsWith(raw)) {\n return undefined;\n }\n const relativePath = path.raw.substr(raw.length);\n return new Path(relativePath);\n }\n isEqualOrParent(path) {\n return !!this.relative(path);\n }\n isEqual(path) {\n return this.raw === path.raw;\n }\n relativity(path) {\n const relative = this.relative(path);\n if (relative) {\n const relativeStr = relative.toString();\n if (relativeStr === '') {\n return 0;\n }\n return relativeStr.split(Path.separator).length;\n }\n return -1;\n }\n}\nexports.Path = Path;\nPath.separator = '/';\nPath.nativeSeparator = platform_1.isWindows ? '\\\\' : '/';\nconst CHAR_UPPERCASE_A = 65; /* A */\nconst CHAR_LOWERCASE_A = 97; /* a */\nconst CHAR_UPPERCASE_Z = 90; /* Z */\nconst CHAR_LOWERCASE_Z = 122; /* z */\nconst CHAR_DOT = 46; /* . */\nconst CHAR_FORWARD_SLASH = 47; /* / */\nconst CHAR_BACKWARD_SLASH = 92; /* \\ */\nconst CHAR_COLON = 58; /* : */\nconst CHAR_QUESTION_MARK = 63; /* ? */\nclass ErrorInvalidArgType extends Error {\n constructor(name, expected, actual) {\n // determiner: 'must be' or 'must not be'\n let determiner;\n if (typeof expected === 'string' && expected.indexOf('not ') === 0) {\n determiner = 'must not be';\n expected = expected.replace(/^not /, '');\n }\n else {\n determiner = 'must be';\n }\n const type = name.indexOf('.') !== -1 ? 'property' : 'argument';\n let msg = `The \"${name}\" ${type} ${determiner} of type ${expected}`;\n msg += `. Received type ${typeof actual}`;\n super(msg);\n }\n}\nfunction validateString(value, name) {\n if (typeof value !== 'string') {\n throw new ErrorInvalidArgType(name, 'string', value);\n }\n}\nfunction isPathSeparator(code) {\n return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;\n}\nfunction isPosixPathSeparator(code) {\n return code === CHAR_FORWARD_SLASH;\n}\nfunction isWindowsDeviceRoot(code) {\n return ((code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z));\n}\n// Resolves . and .. elements in a path with directory names\nfunction normalizeString(path, allowAboveRoot, separator, isPathSeparator) {\n let res = '';\n let lastSegmentLength = 0;\n let lastSlash = -1;\n let dots = 0;\n let code;\n for (let i = 0; i <= path.length; ++i) {\n if (i < path.length) {\n code = path.charCodeAt(i);\n }\n else if (isPathSeparator(code)) {\n break;\n }\n else {\n code = CHAR_FORWARD_SLASH;\n }\n if (isPathSeparator(code)) {\n if (lastSlash === i - 1 || dots === 1) {\n // NOOP\n }\n else if (lastSlash !== i - 1 && dots === 2) {\n if (res.length < 2 ||\n lastSegmentLength !== 2 ||\n res.charCodeAt(res.length - 1) !== CHAR_DOT ||\n res.charCodeAt(res.length - 2) !== CHAR_DOT) {\n if (res.length > 2) {\n const lastSlashIndex = res.lastIndexOf(separator);\n if (lastSlashIndex === -1) {\n res = '';\n lastSegmentLength = 0;\n }\n else {\n res = res.slice(0, lastSlashIndex);\n lastSegmentLength = res.length - 1 - res.lastIndexOf(separator);\n }\n lastSlash = i;\n dots = 0;\n continue;\n }\n else if (res.length === 2 || res.length === 1) {\n res = '';\n lastSegmentLength = 0;\n lastSlash = i;\n dots = 0;\n continue;\n }\n }\n if (allowAboveRoot) {\n if (res.length > 0) {\n res += `${separator}..`;\n }\n else {\n res = '..';\n }\n lastSegmentLength = 2;\n }\n }\n else {\n if (res.length > 0) {\n res += separator + path.slice(lastSlash + 1, i);\n }\n else {\n res = path.slice(lastSlash + 1, i);\n }\n lastSegmentLength = i - lastSlash - 1;\n }\n lastSlash = i;\n dots = 0;\n }\n else if (code === CHAR_DOT && dots !== -1) {\n ++dots;\n }\n else {\n dots = -1;\n }\n }\n return res;\n}\nfunction _format(sep, pathObject) {\n const dir = pathObject.dir || pathObject.root;\n const base = pathObject.base || (pathObject.name || '') + (pathObject.ext || '');\n if (!dir) {\n return base;\n }\n if (dir === pathObject.root) {\n return dir + base;\n }\n return dir + sep + base;\n}\nexports.win32 = {\n // path.resolve([from ...], to)\n resolve(...pathSegments) {\n let resolvedDevice = '';\n let resolvedTail = '';\n let resolvedAbsolute = false;\n for (let i = pathSegments.length - 1; i >= -1; i--) {\n let path;\n if (i >= 0) {\n path = pathSegments[i];\n }\n else if (!resolvedDevice) {\n path = process.cwd();\n }\n else {\n // Windows has the concept of drive-specific current working\n // directories. If we've resolved a drive letter but not yet an\n // absolute path, get cwd for that drive, or the process cwd if\n // the drive cwd is not available. We're sure the device is not\n // a UNC path at this points, because UNC paths are always absolute.\n path = process.env['=' + resolvedDevice] || process.cwd();\n // Verify that a cwd was found and that it actually points\n // to our drive. If not, default to the drive's root.\n if (path === undefined || path.slice(0, 3).toLowerCase() !== resolvedDevice.toLowerCase() + '\\\\') {\n path = resolvedDevice + '\\\\';\n }\n }\n validateString(path, 'path');\n // Skip empty entries\n if (path.length === 0) {\n continue;\n }\n const len = path.length;\n let rootEnd = 0;\n let device = '';\n let isAbsolute = false;\n const code = path.charCodeAt(0);\n // Try to match a root\n if (len > 1) {\n if (isPathSeparator(code)) {\n // Possible UNC root\n // If we started with a separator, we know we at least have an\n // absolute path of some kind (UNC or otherwise)\n isAbsolute = true;\n if (isPathSeparator(path.charCodeAt(1))) {\n // Matched double path separator at beginning\n let j = 2;\n let last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n const firstPart = path.slice(last, j);\n // Matched!\n last = j;\n // Match 1 or more path separators\n for (; j < len; ++j) {\n if (!isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n // Matched!\n last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j === len) {\n // We matched a UNC root only\n device = '\\\\\\\\' + firstPart + '\\\\' + path.slice(last);\n rootEnd = j;\n }\n else if (j !== last) {\n // We matched a UNC root with leftovers\n device = '\\\\\\\\' + firstPart + '\\\\' + path.slice(last, j);\n rootEnd = j;\n }\n }\n }\n }\n else {\n rootEnd = 1;\n }\n }\n else if (isWindowsDeviceRoot(code)) {\n // Possible device root\n if (path.charCodeAt(1) === CHAR_COLON) {\n device = path.slice(0, 2);\n rootEnd = 2;\n if (len > 2) {\n if (isPathSeparator(path.charCodeAt(2))) {\n // Treat separator following drive name as an absolute path\n // indicator\n isAbsolute = true;\n rootEnd = 3;\n }\n }\n }\n }\n }\n else if (isPathSeparator(code)) {\n // `path` contains just a path separator\n rootEnd = 1;\n isAbsolute = true;\n }\n if (device.length > 0 && resolvedDevice.length > 0 && device.toLowerCase() !== resolvedDevice.toLowerCase()) {\n // This path points to another device so it is not applicable\n continue;\n }\n if (resolvedDevice.length === 0 && device.length > 0) {\n resolvedDevice = device;\n }\n if (!resolvedAbsolute) {\n resolvedTail = path.slice(rootEnd) + '\\\\' + resolvedTail;\n resolvedAbsolute = isAbsolute;\n }\n if (resolvedDevice.length > 0 && resolvedAbsolute) {\n break;\n }\n }\n // At this point the path should be resolved to a full absolute path,\n // but handle relative paths to be safe (might happen when process.cwd()\n // fails)\n // Normalize the tail path\n resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\\\', isPathSeparator);\n return resolvedDevice + (resolvedAbsolute ? '\\\\' : '') + resolvedTail || '.';\n },\n normalize(path) {\n validateString(path, 'path');\n const len = path.length;\n if (len === 0) {\n return '.';\n }\n let rootEnd = 0;\n let device;\n let isAbsolute = false;\n const code = path.charCodeAt(0);\n // Try to match a root\n if (len > 1) {\n if (isPathSeparator(code)) {\n // Possible UNC root\n // If we started with a separator, we know we at least have an absolute\n // path of some kind (UNC or otherwise)\n isAbsolute = true;\n if (isPathSeparator(path.charCodeAt(1))) {\n // Matched double path separator at beginning\n let j = 2;\n let last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n const firstPart = path.slice(last, j);\n // Matched!\n last = j;\n // Match 1 or more path separators\n for (; j < len; ++j) {\n if (!isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n // Matched!\n last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j === len) {\n // We matched a UNC root only\n // Return the normalized version of the UNC root since there\n // is nothing left to process\n return '\\\\\\\\' + firstPart + '\\\\' + path.slice(last) + '\\\\';\n }\n else if (j !== last) {\n // We matched a UNC root with leftovers\n device = '\\\\\\\\' + firstPart + '\\\\' + path.slice(last, j);\n rootEnd = j;\n }\n }\n }\n }\n else {\n rootEnd = 1;\n }\n }\n else if (isWindowsDeviceRoot(code)) {\n // Possible device root\n if (path.charCodeAt(1) === CHAR_COLON) {\n device = path.slice(0, 2);\n rootEnd = 2;\n if (len > 2) {\n if (isPathSeparator(path.charCodeAt(2))) {\n // Treat separator following drive name as an absolute path\n // indicator\n isAbsolute = true;\n rootEnd = 3;\n }\n }\n }\n }\n }\n else if (isPathSeparator(code)) {\n // `path` contains just a path separator, exit early to avoid unnecessary\n // work\n return '\\\\';\n }\n let tail;\n if (rootEnd < len) {\n tail = normalizeString(path.slice(rootEnd), !isAbsolute, '\\\\', isPathSeparator);\n }\n else {\n tail = '';\n }\n if (tail.length === 0 && !isAbsolute) {\n tail = '.';\n }\n if (tail.length > 0 && isPathSeparator(path.charCodeAt(len - 1))) {\n tail += '\\\\';\n }\n if (device === undefined) {\n if (isAbsolute) {\n if (tail.length > 0) {\n return '\\\\' + tail;\n }\n else {\n return '\\\\';\n }\n }\n else if (tail.length > 0) {\n return tail;\n }\n else {\n return '';\n }\n }\n else if (isAbsolute) {\n if (tail.length > 0) {\n return device + '\\\\' + tail;\n }\n else {\n return device + '\\\\';\n }\n }\n else if (tail.length > 0) {\n return device + tail;\n }\n else {\n return device;\n }\n },\n isAbsolute(path) {\n validateString(path, 'path');\n const len = path.length;\n if (len === 0) {\n return false;\n }\n const code = path.charCodeAt(0);\n if (isPathSeparator(code)) {\n return true;\n }\n else if (isWindowsDeviceRoot(code)) {\n // Possible device root\n if (len > 2 && path.charCodeAt(1) === CHAR_COLON) {\n if (isPathSeparator(path.charCodeAt(2))) {\n return true;\n }\n }\n }\n return false;\n },\n join(...paths) {\n if (paths.length === 0) {\n return '.';\n }\n let joined;\n let firstPart;\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0; i < paths.length; ++i) {\n const arg = paths[i];\n validateString(arg, 'path');\n if (arg.length > 0) {\n if (joined === undefined) {\n joined = firstPart = arg;\n }\n else {\n joined += '\\\\' + arg;\n }\n }\n }\n if (joined === undefined) {\n return '.';\n }\n // Make sure that the joined path doesn't start with two slashes, because\n // normalize() will mistake it for an UNC path then.\n //\n // This step is skipped when it is very clear that the user actually\n // intended to point at an UNC path. This is assumed when the first\n // non-empty string arguments starts with exactly two slashes followed by\n // at least one more non-slash character.\n //\n // Note that for normalize() to treat a path as an UNC path it needs to\n // have at least 2 components, so we don't filter for that here.\n // This means that the user can use join to construct UNC paths from\n // a server name and a share name; for example:\n // path.join('//server', 'share') -> '\\\\\\\\server\\\\share\\\\')\n let needsReplace = true;\n let slashCount = 0;\n if (typeof firstPart === 'string' && isPathSeparator(firstPart.charCodeAt(0))) {\n ++slashCount;\n const firstLen = firstPart.length;\n if (firstLen > 1) {\n if (isPathSeparator(firstPart.charCodeAt(1))) {\n ++slashCount;\n if (firstLen > 2) {\n if (isPathSeparator(firstPart.charCodeAt(2))) {\n ++slashCount;\n }\n else {\n // We matched a UNC path in the first part\n needsReplace = false;\n }\n }\n }\n }\n }\n if (needsReplace) {\n // Find any more consecutive slashes we need to replace\n for (; slashCount < joined.length; ++slashCount) {\n if (!isPathSeparator(joined.charCodeAt(slashCount))) {\n break;\n }\n }\n // Replace the slashes if needed\n if (slashCount >= 2) {\n joined = '\\\\' + joined.slice(slashCount);\n }\n }\n return exports.win32.normalize(joined);\n },\n // It will solve the relative path from `from` to `to`, for instance:\n // from = 'C:\\\\orandea\\\\test\\\\aaa'\n // to = 'C:\\\\orandea\\\\impl\\\\bbb'\n // The output of the function should be: '..\\\\..\\\\impl\\\\bbb'\n relative(from, to) {\n validateString(from, 'from');\n validateString(to, 'to');\n if (from === to) {\n return '';\n }\n const fromOrig = exports.win32.resolve(from);\n const toOrig = exports.win32.resolve(to);\n if (fromOrig === toOrig) {\n return '';\n }\n from = fromOrig.toLowerCase();\n to = toOrig.toLowerCase();\n if (from === to) {\n return '';\n }\n // Trim any leading backslashes\n let fromStart = 0;\n for (; fromStart < from.length; ++fromStart) {\n if (from.charCodeAt(fromStart) !== CHAR_BACKWARD_SLASH) {\n break;\n }\n }\n // Trim trailing backslashes (applicable to UNC paths only)\n let fromEnd = from.length;\n for (; fromEnd - 1 > fromStart; --fromEnd) {\n if (from.charCodeAt(fromEnd - 1) !== CHAR_BACKWARD_SLASH) {\n break;\n }\n }\n const fromLen = fromEnd - fromStart;\n // Trim any leading backslashes\n let toStart = 0;\n for (; toStart < to.length; ++toStart) {\n if (to.charCodeAt(toStart) !== CHAR_BACKWARD_SLASH) {\n break;\n }\n }\n // Trim trailing backslashes (applicable to UNC paths only)\n let toEnd = to.length;\n for (; toEnd - 1 > toStart; --toEnd) {\n if (to.charCodeAt(toEnd - 1) !== CHAR_BACKWARD_SLASH) {\n break;\n }\n }\n const toLen = toEnd - toStart;\n // Compare paths to find the longest common path from root\n const length = fromLen < toLen ? fromLen : toLen;\n let lastCommonSep = -1;\n let i = 0;\n for (; i <= length; ++i) {\n if (i === length) {\n if (toLen > length) {\n if (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) {\n // We get here if `from` is the exact base path for `to`.\n // For example: from='C:\\\\foo\\\\bar'; to='C:\\\\foo\\\\bar\\\\baz'\n return toOrig.slice(toStart + i + 1);\n }\n else if (i === 2) {\n // We get here if `from` is the device root.\n // For example: from='C:\\\\'; to='C:\\\\foo'\n return toOrig.slice(toStart + i);\n }\n }\n if (fromLen > length) {\n if (from.charCodeAt(fromStart + i) === CHAR_BACKWARD_SLASH) {\n // We get here if `to` is the exact base path for `from`.\n // For example: from='C:\\\\foo\\\\bar'; to='C:\\\\foo'\n lastCommonSep = i;\n }\n else if (i === 2) {\n // We get here if `to` is the device root.\n // For example: from='C:\\\\foo\\\\bar'; to='C:\\\\'\n lastCommonSep = 3;\n }\n }\n break;\n }\n const fromCode = from.charCodeAt(fromStart + i);\n const toCode = to.charCodeAt(toStart + i);\n if (fromCode !== toCode) {\n break;\n }\n else if (fromCode === CHAR_BACKWARD_SLASH) {\n lastCommonSep = i;\n }\n }\n // We found a mismatch before the first common path separator was seen, so\n // return the original `to`.\n if (i !== length && lastCommonSep === -1) {\n return toOrig;\n }\n let out = '';\n if (lastCommonSep === -1) {\n lastCommonSep = 0;\n }\n // Generate the relative path based on the path difference between `to` and\n // `from`\n for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {\n if (i === fromEnd || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) {\n if (out.length === 0) {\n out += '..';\n }\n else {\n out += '\\\\..';\n }\n }\n }\n // Lastly, append the rest of the destination (`to`) path that comes after\n // the common path parts\n if (out.length > 0) {\n return out + toOrig.slice(toStart + lastCommonSep, toEnd);\n }\n else {\n toStart += lastCommonSep;\n if (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) {\n ++toStart;\n }\n return toOrig.slice(toStart, toEnd);\n }\n },\n toNamespacedPath(path) {\n // Note: this will *probably* throw somewhere.\n if (typeof path !== 'string') {\n return path;\n }\n if (path.length === 0) {\n return '';\n }\n const resolvedPath = exports.win32.resolve(path);\n if (resolvedPath.length >= 3) {\n if (resolvedPath.charCodeAt(0) === CHAR_BACKWARD_SLASH) {\n // Possible UNC root\n if (resolvedPath.charCodeAt(1) === CHAR_BACKWARD_SLASH) {\n const code = resolvedPath.charCodeAt(2);\n if (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) {\n // Matched non-long UNC root, convert the path to a long UNC path\n return '\\\\\\\\?\\\\UNC\\\\' + resolvedPath.slice(2);\n }\n }\n }\n else if (isWindowsDeviceRoot(resolvedPath.charCodeAt(0))) {\n // Possible device root\n if (resolvedPath.charCodeAt(1) === CHAR_COLON && resolvedPath.charCodeAt(2) === CHAR_BACKWARD_SLASH) {\n // Matched device root, convert the path to a long UNC path\n return '\\\\\\\\?\\\\' + resolvedPath;\n }\n }\n }\n return path;\n },\n dirname(path) {\n validateString(path, 'path');\n const len = path.length;\n if (len === 0) {\n return '.';\n }\n let rootEnd = -1;\n let end = -1;\n let matchedSlash = true;\n let offset = 0;\n const code = path.charCodeAt(0);\n // Try to match a root\n if (len > 1) {\n if (isPathSeparator(code)) {\n // Possible UNC root\n rootEnd = offset = 1;\n if (isPathSeparator(path.charCodeAt(1))) {\n // Matched double path separator at beginning\n let j = 2;\n let last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n // Matched!\n last = j;\n // Match 1 or more path separators\n for (; j < len; ++j) {\n if (!isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n // Matched!\n last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j === len) {\n // We matched a UNC root only\n return path;\n }\n if (j !== last) {\n // We matched a UNC root with leftovers\n // Offset by 1 to include the separator after the UNC root to\n // treat it as a \"normal root\" on top of a (UNC) root\n rootEnd = offset = j + 1;\n }\n }\n }\n }\n }\n else if (isWindowsDeviceRoot(code)) {\n // Possible device root\n if (path.charCodeAt(1) === CHAR_COLON) {\n rootEnd = offset = 2;\n if (len > 2) {\n if (isPathSeparator(path.charCodeAt(2))) {\n rootEnd = offset = 3;\n }\n }\n }\n }\n }\n else if (isPathSeparator(code)) {\n // `path` contains just a path separator, exit early to avoid\n // unnecessary work\n return path;\n }\n for (let i = len - 1; i >= offset; --i) {\n if (isPathSeparator(path.charCodeAt(i))) {\n if (!matchedSlash) {\n end = i;\n break;\n }\n }\n else {\n // We saw the first non-path separator\n matchedSlash = false;\n }\n }\n if (end === -1) {\n if (rootEnd === -1) {\n return '.';\n }\n else {\n end = rootEnd;\n }\n }\n return path.slice(0, end);\n },\n basename(path, ext) {\n if (ext !== undefined) {\n validateString(ext, 'ext');\n }\n validateString(path, 'path');\n let start = 0;\n let end = -1;\n let matchedSlash = true;\n let i;\n // Check for a drive letter prefix so as not to mistake the following\n // path separator as an extra separator at the end of the path that can be\n // disregarded\n if (path.length >= 2) {\n const drive = path.charCodeAt(0);\n if (isWindowsDeviceRoot(drive)) {\n if (path.charCodeAt(1) === CHAR_COLON) {\n start = 2;\n }\n }\n }\n if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {\n if (ext.length === path.length && ext === path) {\n return '';\n }\n let extIdx = ext.length - 1;\n let firstNonSlashEnd = -1;\n for (i = path.length - 1; i >= start; --i) {\n const code = path.charCodeAt(i);\n if (isPathSeparator(code)) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n start = i + 1;\n break;\n }\n }\n else {\n if (firstNonSlashEnd === -1) {\n // We saw the first non-path separator, remember this index in case\n // we need it if the extension ends up not matching\n matchedSlash = false;\n firstNonSlashEnd = i + 1;\n }\n if (extIdx >= 0) {\n // Try to match the explicit extension\n if (code === ext.charCodeAt(extIdx)) {\n if (--extIdx === -1) {\n // We matched the extension, so mark this as the end of our path\n // component\n end = i;\n }\n }\n else {\n // Extension does not match, so our result is the entire path\n // component\n extIdx = -1;\n end = firstNonSlashEnd;\n }\n }\n }\n }\n if (start === end) {\n end = firstNonSlashEnd;\n }\n else if (end === -1) {\n end = path.length;\n }\n return path.slice(start, end);\n }\n else {\n for (i = path.length - 1; i >= start; --i) {\n if (isPathSeparator(path.charCodeAt(i))) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n start = i + 1;\n break;\n }\n }\n else if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // path component\n matchedSlash = false;\n end = i + 1;\n }\n }\n if (end === -1) {\n return '';\n }\n return path.slice(start, end);\n }\n },\n extname(path) {\n validateString(path, 'path');\n let start = 0;\n let startDot = -1;\n let startPart = 0;\n let end = -1;\n let matchedSlash = true;\n // Track the state of characters (if any) we see before our first dot and\n // after any path separator we find\n let preDotState = 0;\n // Check for a drive letter prefix so as not to mistake the following\n // path separator as an extra separator at the end of the path that can be\n // disregarded\n if (path.length >= 2 && path.charCodeAt(1) === CHAR_COLON && isWindowsDeviceRoot(path.charCodeAt(0))) {\n start = startPart = 2;\n }\n for (let i = path.length - 1; i >= start; --i) {\n const code = path.charCodeAt(i);\n if (isPathSeparator(code)) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n startPart = i + 1;\n break;\n }\n continue;\n }\n if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // extension\n matchedSlash = false;\n end = i + 1;\n }\n if (code === CHAR_DOT) {\n // If this is our first dot, mark it as the start of our extension\n if (startDot === -1) {\n startDot = i;\n }\n else if (preDotState !== 1) {\n preDotState = 1;\n }\n }\n else if (startDot !== -1) {\n // We saw a non-dot and non-path separator before our dot, so we should\n // have a good chance at having a non-empty extension\n preDotState = -1;\n }\n }\n if (startDot === -1 ||\n end === -1 ||\n // We saw a non-dot character immediately before the dot\n preDotState === 0 ||\n // The (right-most) trimmed path component is exactly '..'\n (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {\n return '';\n }\n return path.slice(startDot, end);\n },\n format(pathObject) {\n if (pathObject === null || typeof pathObject !== 'object') {\n throw new ErrorInvalidArgType('pathObject', 'Object', pathObject);\n }\n return _format('\\\\', pathObject);\n },\n parse(path) {\n validateString(path, 'path');\n const ret = { root: '', dir: '', base: '', ext: '', name: '' };\n if (path.length === 0) {\n return ret;\n }\n const len = path.length;\n let rootEnd = 0;\n let code = path.charCodeAt(0);\n // Try to match a root\n if (len > 1) {\n if (isPathSeparator(code)) {\n // Possible UNC root\n rootEnd = 1;\n if (isPathSeparator(path.charCodeAt(1))) {\n // Matched double path separator at beginning\n let j = 2;\n let last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n // Matched!\n last = j;\n // Match 1 or more path separators\n for (; j < len; ++j) {\n if (!isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n // Matched!\n last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j === len) {\n // We matched a UNC root only\n rootEnd = j;\n }\n else if (j !== last) {\n // We matched a UNC root with leftovers\n rootEnd = j + 1;\n }\n }\n }\n }\n }\n else if (isWindowsDeviceRoot(code)) {\n // Possible device root\n if (path.charCodeAt(1) === CHAR_COLON) {\n rootEnd = 2;\n if (len > 2) {\n if (isPathSeparator(path.charCodeAt(2))) {\n if (len === 3) {\n // `path` contains just a drive root, exit early to avoid\n // unnecessary work\n ret.root = ret.dir = path;\n return ret;\n }\n rootEnd = 3;\n }\n }\n else {\n // `path` contains just a drive root, exit early to avoid\n // unnecessary work\n ret.root = ret.dir = path;\n return ret;\n }\n }\n }\n }\n else if (isPathSeparator(code)) {\n // `path` contains just a path separator, exit early to avoid\n // unnecessary work\n ret.root = ret.dir = path;\n return ret;\n }\n if (rootEnd > 0) {\n ret.root = path.slice(0, rootEnd);\n }\n let startDot = -1;\n let startPart = rootEnd;\n let end = -1;\n let matchedSlash = true;\n let i = path.length - 1;\n // Track the state of characters (if any) we see before our first dot and\n // after any path separator we find\n let preDotState = 0;\n // Get non-dir info\n for (; i >= rootEnd; --i) {\n code = path.charCodeAt(i);\n if (isPathSeparator(code)) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n startPart = i + 1;\n break;\n }\n continue;\n }\n if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // extension\n matchedSlash = false;\n end = i + 1;\n }\n if (code === CHAR_DOT) {\n // If this is our first dot, mark it as the start of our extension\n if (startDot === -1) {\n startDot = i;\n }\n else if (preDotState !== 1) {\n preDotState = 1;\n }\n }\n else if (startDot !== -1) {\n // We saw a non-dot and non-path separator before our dot, so we should\n // have a good chance at having a non-empty extension\n preDotState = -1;\n }\n }\n if (startDot === -1 ||\n end === -1 ||\n // We saw a non-dot character immediately before the dot\n preDotState === 0 ||\n // The (right-most) trimmed path component is exactly '..'\n (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {\n if (end !== -1) {\n ret.base = ret.name = path.slice(startPart, end);\n }\n }\n else {\n ret.name = path.slice(startPart, startDot);\n ret.base = path.slice(startPart, end);\n ret.ext = path.slice(startDot, end);\n }\n // If the directory is the root, use the entire root as the `dir` including\n // the trailing slash if any (`C:\\abc` -> `C:\\`). Otherwise, strip out the\n // trailing slash (`C:\\abc\\def` -> `C:\\abc`).\n if (startPart > 0 && startPart !== rootEnd) {\n ret.dir = path.slice(0, startPart - 1);\n }\n else {\n ret.dir = ret.root;\n }\n return ret;\n },\n sep: '\\\\',\n delimiter: ';',\n win32: null,\n posix: null,\n};\nexports.posix = {\n // path.resolve([from ...], to)\n resolve(...pathSegments) {\n let resolvedPath = '';\n let resolvedAbsolute = false;\n for (let i = pathSegments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n let path;\n if (i >= 0) {\n path = pathSegments[i];\n }\n else {\n path = process.cwd();\n }\n validateString(path, 'path');\n // Skip empty entries\n if (path.length === 0) {\n continue;\n }\n resolvedPath = path + '/' + resolvedPath;\n resolvedAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n }\n // At this point the path should be resolved to a full absolute path, but\n // handle relative paths to be safe (might happen when process.cwd() fails)\n // Normalize the path\n resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/', isPosixPathSeparator);\n if (resolvedAbsolute) {\n if (resolvedPath.length > 0) {\n return '/' + resolvedPath;\n }\n else {\n return '/';\n }\n }\n else if (resolvedPath.length > 0) {\n return resolvedPath;\n }\n else {\n return '.';\n }\n },\n normalize(path) {\n validateString(path, 'path');\n if (path.length === 0) {\n return '.';\n }\n const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n const trailingSeparator = path.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH;\n // Normalize the path\n path = normalizeString(path, !isAbsolute, '/', isPosixPathSeparator);\n if (path.length === 0 && !isAbsolute) {\n path = '.';\n }\n if (path.length > 0 && trailingSeparator) {\n path += '/';\n }\n if (isAbsolute) {\n return '/' + path;\n }\n return path;\n },\n isAbsolute(path) {\n validateString(path, 'path');\n return path.length > 0 && path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n },\n join(...paths) {\n if (paths.length === 0) {\n return '.';\n }\n let joined;\n for (let i = 0; i < paths.length; ++i) {\n const arg = arguments[i];\n validateString(arg, 'path');\n if (arg.length > 0) {\n if (joined === undefined) {\n joined = arg;\n }\n else {\n joined += '/' + arg;\n }\n }\n }\n if (joined === undefined) {\n return '.';\n }\n return exports.posix.normalize(joined);\n },\n relative(from, to) {\n validateString(from, 'from');\n validateString(to, 'to');\n if (from === to) {\n return '';\n }\n from = exports.posix.resolve(from);\n to = exports.posix.resolve(to);\n if (from === to) {\n return '';\n }\n // Trim any leading backslashes\n let fromStart = 1;\n for (; fromStart < from.length; ++fromStart) {\n if (from.charCodeAt(fromStart) !== CHAR_FORWARD_SLASH) {\n break;\n }\n }\n const fromEnd = from.length;\n const fromLen = fromEnd - fromStart;\n // Trim any leading backslashes\n let toStart = 1;\n for (; toStart < to.length; ++toStart) {\n if (to.charCodeAt(toStart) !== CHAR_FORWARD_SLASH) {\n break;\n }\n }\n const toEnd = to.length;\n const toLen = toEnd - toStart;\n // Compare paths to find the longest common path from root\n const length = fromLen < toLen ? fromLen : toLen;\n let lastCommonSep = -1;\n let i = 0;\n for (; i <= length; ++i) {\n if (i === length) {\n if (toLen > length) {\n if (to.charCodeAt(toStart + i) === CHAR_FORWARD_SLASH) {\n // We get here if `from` is the exact base path for `to`.\n // For example: from='/foo/bar'; to='/foo/bar/baz'\n return to.slice(toStart + i + 1);\n }\n else if (i === 0) {\n // We get here if `from` is the root\n // For example: from='/'; to='/foo'\n return to.slice(toStart + i);\n }\n }\n else if (fromLen > length) {\n if (from.charCodeAt(fromStart + i) === CHAR_FORWARD_SLASH) {\n // We get here if `to` is the exact base path for `from`.\n // For example: from='/foo/bar/baz'; to='/foo/bar'\n lastCommonSep = i;\n }\n else if (i === 0) {\n // We get here if `to` is the root.\n // For example: from='/foo'; to='/'\n lastCommonSep = 0;\n }\n }\n break;\n }\n const fromCode = from.charCodeAt(fromStart + i);\n const toCode = to.charCodeAt(toStart + i);\n if (fromCode !== toCode) {\n break;\n }\n else if (fromCode === CHAR_FORWARD_SLASH) {\n lastCommonSep = i;\n }\n }\n let out = '';\n // Generate the relative path based on the path difference between `to`\n // and `from`\n for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {\n if (i === fromEnd || from.charCodeAt(i) === CHAR_FORWARD_SLASH) {\n if (out.length === 0) {\n out += '..';\n }\n else {\n out += '/..';\n }\n }\n }\n // Lastly, append the rest of the destination (`to`) path that comes after\n // the common path parts\n if (out.length > 0) {\n return out + to.slice(toStart + lastCommonSep);\n }\n else {\n toStart += lastCommonSep;\n if (to.charCodeAt(toStart) === CHAR_FORWARD_SLASH) {\n ++toStart;\n }\n return to.slice(toStart);\n }\n },\n toNamespacedPath(path) {\n // Non-op on posix systems\n return path;\n },\n dirname(path) {\n validateString(path, 'path');\n if (path.length === 0) {\n return '.';\n }\n const hasRoot = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n let end = -1;\n let matchedSlash = true;\n for (let i = path.length - 1; i >= 1; --i) {\n if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) {\n if (!matchedSlash) {\n end = i;\n break;\n }\n }\n else {\n // We saw the first non-path separator\n matchedSlash = false;\n }\n }\n if (end === -1) {\n return hasRoot ? '/' : '.';\n }\n if (hasRoot && end === 1) {\n return '//';\n }\n return path.slice(0, end);\n },\n basename(path, ext) {\n if (ext !== undefined) {\n validateString(ext, 'ext');\n }\n validateString(path, 'path');\n let start = 0;\n let end = -1;\n let matchedSlash = true;\n let i;\n if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {\n if (ext.length === path.length && ext === path) {\n return '';\n }\n let extIdx = ext.length - 1;\n let firstNonSlashEnd = -1;\n for (i = path.length - 1; i >= 0; --i) {\n const code = path.charCodeAt(i);\n if (code === CHAR_FORWARD_SLASH) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n start = i + 1;\n break;\n }\n }\n else {\n if (firstNonSlashEnd === -1) {\n // We saw the first non-path separator, remember this index in case\n // we need it if the extension ends up not matching\n matchedSlash = false;\n firstNonSlashEnd = i + 1;\n }\n if (extIdx >= 0) {\n // Try to match the explicit extension\n if (code === ext.charCodeAt(extIdx)) {\n if (--extIdx === -1) {\n // We matched the extension, so mark this as the end of our path\n // component\n end = i;\n }\n }\n else {\n // Extension does not match, so our result is the entire path\n // component\n extIdx = -1;\n end = firstNonSlashEnd;\n }\n }\n }\n }\n if (start === end) {\n end = firstNonSlashEnd;\n }\n else if (end === -1) {\n end = path.length;\n }\n return path.slice(start, end);\n }\n else {\n for (i = path.length - 1; i >= 0; --i) {\n if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n start = i + 1;\n break;\n }\n }\n else if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // path component\n matchedSlash = false;\n end = i + 1;\n }\n }\n if (end === -1) {\n return '';\n }\n return path.slice(start, end);\n }\n },\n extname(path) {\n validateString(path, 'path');\n let startDot = -1;\n let startPart = 0;\n let end = -1;\n let matchedSlash = true;\n // Track the state of characters (if any) we see before our first dot and\n // after any path separator we find\n let preDotState = 0;\n for (let i = path.length - 1; i >= 0; --i) {\n const code = path.charCodeAt(i);\n if (code === CHAR_FORWARD_SLASH) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n startPart = i + 1;\n break;\n }\n continue;\n }\n if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // extension\n matchedSlash = false;\n end = i + 1;\n }\n if (code === CHAR_DOT) {\n // If this is our first dot, mark it as the start of our extension\n if (startDot === -1) {\n startDot = i;\n }\n else if (preDotState !== 1) {\n preDotState = 1;\n }\n }\n else if (startDot !== -1) {\n // We saw a non-dot and non-path separator before our dot, so we should\n // have a good chance at having a non-empty extension\n preDotState = -1;\n }\n }\n if (startDot === -1 ||\n end === -1 ||\n // We saw a non-dot character immediately before the dot\n preDotState === 0 ||\n // The (right-most) trimmed path component is exactly '..'\n (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {\n return '';\n }\n return path.slice(startDot, end);\n },\n format(pathObject) {\n if (pathObject === null || typeof pathObject !== 'object') {\n throw new ErrorInvalidArgType('pathObject', 'Object', pathObject);\n }\n return _format('/', pathObject);\n },\n parse(path) {\n validateString(path, 'path');\n const ret = { root: '', dir: '', base: '', ext: '', name: '' };\n if (path.length === 0) {\n return ret;\n }\n const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n let start;\n if (isAbsolute) {\n ret.root = '/';\n start = 1;\n }\n else {\n start = 0;\n }\n let startDot = -1;\n let startPart = 0;\n let end = -1;\n let matchedSlash = true;\n let i = path.length - 1;\n // Track the state of characters (if any) we see before our first dot and\n // after any path separator we find\n let preDotState = 0;\n // Get non-dir info\n for (; i >= start; --i) {\n const code = path.charCodeAt(i);\n if (code === CHAR_FORWARD_SLASH) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n startPart = i + 1;\n break;\n }\n continue;\n }\n if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // extension\n matchedSlash = false;\n end = i + 1;\n }\n if (code === CHAR_DOT) {\n // If this is our first dot, mark it as the start of our extension\n if (startDot === -1) {\n startDot = i;\n }\n else if (preDotState !== 1) {\n preDotState = 1;\n }\n }\n else if (startDot !== -1) {\n // We saw a non-dot and non-path separator before our dot, so we should\n // have a good chance at having a non-empty extension\n preDotState = -1;\n }\n }\n if (startDot === -1 ||\n end === -1 ||\n // We saw a non-dot character immediately before the dot\n preDotState === 0 ||\n // The (right-most) trimmed path component is exactly '..'\n (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {\n if (end !== -1) {\n if (startPart === 0 && isAbsolute) {\n ret.base = ret.name = path.slice(1, end);\n }\n else {\n ret.base = ret.name = path.slice(startPart, end);\n }\n }\n }\n else {\n if (startPart === 0 && isAbsolute) {\n ret.name = path.slice(1, startDot);\n ret.base = path.slice(1, end);\n }\n else {\n ret.name = path.slice(startPart, startDot);\n ret.base = path.slice(startPart, end);\n }\n ret.ext = path.slice(startDot, end);\n }\n if (startPart > 0) {\n ret.dir = path.slice(0, startPart - 1);\n }\n else if (isAbsolute) {\n ret.dir = '/';\n }\n return ret;\n },\n sep: '/',\n delimiter: ':',\n win32: null,\n posix: null,\n};\nexports.posix.win32 = exports.win32.win32 = exports.win32;\nexports.posix.posix = exports.win32.posix = exports.posix;\n/**\n * Takes a Windows OS path and changes backward slashes to forward slashes.\n * This should only be done for OS paths from Windows (or user provided paths potentially from Windows).\n * Using it on a Linux or MaxOS path might change it.\n */\nfunction toSlashes(osPath) {\n return osPath.replace(/[\\\\/]/g, exports.posix.sep);\n}\nexports.toSlashes = toSlashes;\nexports.normalize = process.platform === 'win32' ? exports.win32.normalize : exports.posix.normalize;\nexports.isAbsolute = process.platform === 'win32' ? exports.win32.isAbsolute : exports.posix.isAbsolute;\nexports.join = process.platform === 'win32' ? exports.win32.join : exports.posix.join;\nexports.resolve = process.platform === 'win32' ? exports.win32.resolve : exports.posix.resolve;\nexports.relative = process.platform === 'win32' ? exports.win32.relative : exports.posix.relative;\nexports.dirname = process.platform === 'win32' ? exports.win32.dirname : exports.posix.dirname;\nexports.basename = process.platform === 'win32' ? exports.win32.basename : exports.posix.basename;\nexports.extname = process.platform === 'win32' ? exports.win32.extname : exports.posix.extname;\nexports.format = process.platform === 'win32' ? exports.win32.format : exports.posix.format;\nexports.parse = process.platform === 'win32' ? exports.win32.parse : exports.posix.parse;\nexports.toNamespacedPath = process.platform === 'win32' ? exports.win32.toNamespacedPath : exports.posix.toNamespacedPath;\nexports.sep = process.platform === 'win32' ? exports.win32.sep : exports.posix.sep;\nexports.delimiter = process.platform === 'win32' ? exports.win32.delimiter : exports.posix.delimiter;\nfunction replaceAsarInPath(pathMayInAsar) {\n (0, exports.parse)(pathMayInAsar);\n const parts = pathMayInAsar.split((0, exports.normalize)('/'));\n parts.forEach((part, i) => {\n if (part.endsWith('.asar')) {\n parts[i] = part + '.unpacked';\n }\n });\n return parts.join((0, exports.normalize)('/'));\n}\nexports.replaceAsarInPath = replaceAsarInPath;\n// Reference: https://en.wikipedia.org/wiki/Filename\nconst WINDOWS_INVALID_FILE_CHARS = /[\\\\/:*?\"<>|]/g;\nconst UNIX_INVALID_FILE_CHARS = /[\\\\/]/g;\nconst WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\\$|nul|lpt[0-9]|com[0-9])$/i;\nfunction isValidBasename(name, isWindowsOS = platform_1.isWindows) {\n const invalidFileChars = isWindowsOS ? WINDOWS_INVALID_FILE_CHARS : UNIX_INVALID_FILE_CHARS;\n if (!name || name.length === 0 || /^\\s+$/.test(name)) {\n return false; // require a name that is not just whitespace\n }\n invalidFileChars.lastIndex = 0; // the holy grail of software development\n if (invalidFileChars.test(name)) {\n return false; // check for certain invalid file characters\n }\n if (isWindowsOS && WINDOWS_FORBIDDEN_NAMES.test(name)) {\n return false; // check for certain invalid file names\n }\n if (name === '.' || name === '..') {\n return false; // check for reserved values\n }\n if (isWindowsOS && name[name.length - 1] === '.') {\n return false; // Windows: file cannot end with a \".\"\n }\n if (isWindowsOS && name.length !== name.trim().length) {\n return false; // Windows: file cannot end with a whitespace\n }\n if (name.length > 255) {\n return false; // most file systems do not allow files > 255 length\n }\n return true;\n}\nexports.isValidBasename = isValidBasename;\nfunction sortPathByDepth(paths, sep = Path.separator) {\n const depths = {};\n for (const path of paths) {\n const parts = path.split(sep);\n depths[path] = parts.length;\n }\n return paths.sort((a, b) => depths[a] - depths[b]);\n}\nexports.sortPathByDepth = sortPathByDepth;\nfunction findCommonRoot(paths, sep = Path.separator) {\n const [first = '', ...remaining] = paths;\n if (first === '' || remaining.length === 0) {\n return '';\n }\n const parts = first.split(sep);\n let endOfPrefix = parts.length;\n for (const path of remaining) {\n const compare = path.split(sep);\n for (let i = 0; i < endOfPrefix; i++) {\n if (compare[i] !== parts[i]) {\n endOfPrefix = i;\n }\n }\n if (endOfPrefix === 0) {\n return '';\n }\n }\n return parts.slice(0, endOfPrefix).join(sep);\n}\nexports.findCommonRoot = findCommonRoot;\n//# sourceMappingURL=path.js.map\n\n//# sourceURL=webpack://@opensumi/ide-components/../utils/lib/path.js?");
6910
+ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.isValidBasename = exports.replaceAsarInPath = exports.delimiter = exports.sep = exports.toNamespacedPath = exports.parse = exports.format = exports.extname = exports.basename = exports.dirname = exports.relative = exports.resolve = exports.join = exports.isAbsolute = exports.normalize = exports.toSlashes = exports.posix = exports.win32 = exports.Path = void 0;\nconst tslib_1 = __webpack_require__(/*! tslib */ \"../../node_modules/tslib/tslib.es6.mjs\");\nconst platform_1 = __webpack_require__(/*! ./platform */ \"../utils/lib/platform.js\");\nconst process = tslib_1.__importStar(__webpack_require__(/*! ./process */ \"../utils/lib/process.js\"));\nconst SystemPathSeparatorRegex = platform_1.isWindows ? /\\\\/g : /\\//g;\n/**\n * On POSIX:\n * ┌──────────────────────┬────────────┐\n * │ dir │ base │\n * ├──────┬ ├──────┬─────┤\n * │ root │ │ name │ ext │\n * \" / home/user/dir / file .txt \"\n * └──────┴───────────────┴──────┴─────┘\n *\n * On Windows:\n * ┌──────────────────────┬────────────┐\n * │ dir │ base │\n * ├──────┬ ├──────┬─────┤\n * │ root │ │ name │ ext │\n * \" /c: / home/user/dir / file .txt \"\n * └──────┴───────────────┴──────┴─────┘\n */\nclass Path {\n static isDrive(segment) {\n return segment.endsWith(':');\n }\n static splitPath(path) {\n return path.split(Path.separator).filter((path) => !!path);\n }\n static isRelative(path) {\n return !path.startsWith(Path.separator);\n }\n static pathDepth(path) {\n return path.split(Path.separator).length;\n }\n /**\n * vscode-uri always normalizes drive letters to lower case:\n * https://github.com/Microsoft/vscode-uri/blob/b1d3221579f97f28a839b6f996d76fc45e9964d8/src/index.ts#L1025\n * Theia path should be adjusted to this.\n */\n static normalizeDrive(path) {\n // lower-case windows drive letters in /C:/fff or C:/fff\n if (path.length >= 3 && path.charCodeAt(0) === 47 /* '/' */ && path.charCodeAt(2) === 58 /* ':' */) {\n const code = path.charCodeAt(1);\n if (code >= 65 /* A */ && code <= 90 /* Z */) {\n path = `/${String.fromCharCode(code + 32)}:${path.substr(3)}`; // \"/c:\".length === 3\n }\n }\n else if (path.length >= 2 && path.charCodeAt(1) === 58 /* ':' */) {\n const code = path.charCodeAt(0);\n if (code >= 65 /* A */ && code <= 90 /* Z */) {\n path = `${String.fromCharCode(code + 32)}:${path.substr(2)}`; // \"/c:\".length === 3\n }\n }\n return path;\n }\n /**\n * The raw should be normalized, meaning that only '/' is allowed as a path separator.\n */\n constructor(raw) {\n raw = raw.replace(SystemPathSeparatorRegex, Path.separator);\n this.raw = Path.normalizeDrive(raw);\n const firstIndex = raw.indexOf(Path.separator);\n const lastIndex = raw.lastIndexOf(Path.separator);\n this.isAbsolute = firstIndex === 0;\n this.base = lastIndex === -1 ? raw : raw.substr(lastIndex + 1);\n this.isRoot = this.isAbsolute && firstIndex === lastIndex && (!this.base || Path.isDrive(this.base));\n this.root = this.computeRoot();\n const extIndex = this.base.lastIndexOf('.');\n // 处理无后缀文件或者 dot 打头的无后缀文件\n // file like 'a/b/c/test'\n if (extIndex === -1) {\n this.name = this.base;\n this.ext = '';\n }\n else if (extIndex === 0) {\n // dot file like `a/b/c/.eslintrc`\n this.name = this.base;\n this.ext = '';\n }\n else {\n this.name = this.base.substr(0, extIndex);\n this.ext = this.base.substr(extIndex);\n }\n }\n computeRoot() {\n // '/' -> '/'\n // '/c:' -> '/c:'\n if (this.isRoot) {\n return this;\n }\n // 'foo/bar' -> `undefined`\n if (!this.isAbsolute) {\n return undefined;\n }\n const index = this.raw.indexOf(Path.separator, Path.separator.length);\n if (index === -1) {\n // '/foo/bar' -> '/'\n return new Path(Path.separator);\n }\n // '/c:/foo/bar' -> '/c:'\n // '/foo/bar' -> '/'\n return new Path(this.raw.substr(0, index)).root;\n }\n get dir() {\n if (this._dir === undefined) {\n this._dir = this.computeDir();\n }\n return this._dir;\n }\n computeDir() {\n if (this.isRoot) {\n return this;\n }\n const lastIndex = this.raw.lastIndexOf(Path.separator);\n if (lastIndex === -1) {\n return this;\n }\n if (this.isAbsolute) {\n const firstIndex = this.raw.indexOf(Path.separator);\n if (firstIndex === lastIndex) {\n return new Path(this.raw.substr(0, firstIndex + 1));\n }\n }\n return new Path(this.raw.substr(0, lastIndex));\n }\n join(...paths) {\n const code = this.raw.charCodeAt(0);\n const isWindows = isWindowsDeviceRoot(code);\n /**\n * 只针对 IDE 后端运行在 Windows 的情况\n * join('C:\\\\path\\\\to\\\\file', 'path/to/other') === 'C:\\\\path\\\\to\\\\file\\\\path\\\\to\\\\other'\n */\n if (isWindows) {\n return new Path(exports.win32.join(this.raw, ...paths));\n }\n const relativePath = paths.filter((s) => !!s).join(Path.separator);\n if (!relativePath) {\n return this;\n }\n if (this.raw.endsWith(Path.separator) || relativePath.startsWith(Path.separator)) {\n return new Path(exports.posix.join(this.raw, relativePath));\n }\n return new Path(exports.posix.join(this.raw, Path.separator, relativePath));\n }\n toString() {\n return this.raw;\n }\n relative(path) {\n if (this.raw === path.raw) {\n return new Path('');\n }\n if (!this.raw || !path.raw) {\n return undefined;\n }\n const raw = this.base ? this.raw + Path.separator : this.raw;\n if (!path.raw.startsWith(raw)) {\n return undefined;\n }\n const relativePath = path.raw.substr(raw.length);\n return new Path(relativePath);\n }\n isEqualOrParent(path) {\n return !!this.relative(path);\n }\n isEqual(path) {\n return this.raw === path.raw;\n }\n relativity(path) {\n const relative = this.relative(path);\n if (relative) {\n const relativeStr = relative.toString();\n if (relativeStr === '') {\n return 0;\n }\n return relativeStr.split(Path.separator).length;\n }\n return -1;\n }\n}\nexports.Path = Path;\nPath.separator = '/';\nPath.nativeSeparator = platform_1.isWindows ? '\\\\' : '/';\nconst CHAR_UPPERCASE_A = 65; /* A */\nconst CHAR_LOWERCASE_A = 97; /* a */\nconst CHAR_UPPERCASE_Z = 90; /* Z */\nconst CHAR_LOWERCASE_Z = 122; /* z */\nconst CHAR_DOT = 46; /* . */\nconst CHAR_FORWARD_SLASH = 47; /* / */\nconst CHAR_BACKWARD_SLASH = 92; /* \\ */\nconst CHAR_COLON = 58; /* : */\nconst CHAR_QUESTION_MARK = 63; /* ? */\nclass ErrorInvalidArgType extends Error {\n constructor(name, expected, actual) {\n // determiner: 'must be' or 'must not be'\n let determiner;\n if (typeof expected === 'string' && expected.indexOf('not ') === 0) {\n determiner = 'must not be';\n expected = expected.replace(/^not /, '');\n }\n else {\n determiner = 'must be';\n }\n const type = name.indexOf('.') !== -1 ? 'property' : 'argument';\n let msg = `The \"${name}\" ${type} ${determiner} of type ${expected}`;\n msg += `. Received type ${typeof actual}`;\n super(msg);\n }\n}\nfunction validateString(value, name) {\n if (typeof value !== 'string') {\n throw new ErrorInvalidArgType(name, 'string', value);\n }\n}\nfunction isPathSeparator(code) {\n return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;\n}\nfunction isPosixPathSeparator(code) {\n return code === CHAR_FORWARD_SLASH;\n}\nfunction isWindowsDeviceRoot(code) {\n return ((code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z));\n}\n// Resolves . and .. elements in a path with directory names\nfunction normalizeString(path, allowAboveRoot, separator, isPathSeparator) {\n let res = '';\n let lastSegmentLength = 0;\n let lastSlash = -1;\n let dots = 0;\n let code;\n for (let i = 0; i <= path.length; ++i) {\n if (i < path.length) {\n code = path.charCodeAt(i);\n }\n else if (isPathSeparator(code)) {\n break;\n }\n else {\n code = CHAR_FORWARD_SLASH;\n }\n if (isPathSeparator(code)) {\n if (lastSlash === i - 1 || dots === 1) {\n // NOOP\n }\n else if (lastSlash !== i - 1 && dots === 2) {\n if (res.length < 2 ||\n lastSegmentLength !== 2 ||\n res.charCodeAt(res.length - 1) !== CHAR_DOT ||\n res.charCodeAt(res.length - 2) !== CHAR_DOT) {\n if (res.length > 2) {\n const lastSlashIndex = res.lastIndexOf(separator);\n if (lastSlashIndex === -1) {\n res = '';\n lastSegmentLength = 0;\n }\n else {\n res = res.slice(0, lastSlashIndex);\n lastSegmentLength = res.length - 1 - res.lastIndexOf(separator);\n }\n lastSlash = i;\n dots = 0;\n continue;\n }\n else if (res.length === 2 || res.length === 1) {\n res = '';\n lastSegmentLength = 0;\n lastSlash = i;\n dots = 0;\n continue;\n }\n }\n if (allowAboveRoot) {\n if (res.length > 0) {\n res += `${separator}..`;\n }\n else {\n res = '..';\n }\n lastSegmentLength = 2;\n }\n }\n else {\n if (res.length > 0) {\n res += separator + path.slice(lastSlash + 1, i);\n }\n else {\n res = path.slice(lastSlash + 1, i);\n }\n lastSegmentLength = i - lastSlash - 1;\n }\n lastSlash = i;\n dots = 0;\n }\n else if (code === CHAR_DOT && dots !== -1) {\n ++dots;\n }\n else {\n dots = -1;\n }\n }\n return res;\n}\nfunction _format(sep, pathObject) {\n const dir = pathObject.dir || pathObject.root;\n const base = pathObject.base || (pathObject.name || '') + (pathObject.ext || '');\n if (!dir) {\n return base;\n }\n if (dir === pathObject.root) {\n return dir + base;\n }\n return dir + sep + base;\n}\nexports.win32 = {\n // path.resolve([from ...], to)\n resolve(...pathSegments) {\n let resolvedDevice = '';\n let resolvedTail = '';\n let resolvedAbsolute = false;\n for (let i = pathSegments.length - 1; i >= -1; i--) {\n let path;\n if (i >= 0) {\n path = pathSegments[i];\n }\n else if (!resolvedDevice) {\n path = process.cwd();\n }\n else {\n // Windows has the concept of drive-specific current working\n // directories. If we've resolved a drive letter but not yet an\n // absolute path, get cwd for that drive, or the process cwd if\n // the drive cwd is not available. We're sure the device is not\n // a UNC path at this points, because UNC paths are always absolute.\n path = process.env['=' + resolvedDevice] || process.cwd();\n // Verify that a cwd was found and that it actually points\n // to our drive. If not, default to the drive's root.\n if (path === undefined || path.slice(0, 3).toLowerCase() !== resolvedDevice.toLowerCase() + '\\\\') {\n path = resolvedDevice + '\\\\';\n }\n }\n validateString(path, 'path');\n // Skip empty entries\n if (path.length === 0) {\n continue;\n }\n const len = path.length;\n let rootEnd = 0;\n let device = '';\n let isAbsolute = false;\n const code = path.charCodeAt(0);\n // Try to match a root\n if (len > 1) {\n if (isPathSeparator(code)) {\n // Possible UNC root\n // If we started with a separator, we know we at least have an\n // absolute path of some kind (UNC or otherwise)\n isAbsolute = true;\n if (isPathSeparator(path.charCodeAt(1))) {\n // Matched double path separator at beginning\n let j = 2;\n let last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n const firstPart = path.slice(last, j);\n // Matched!\n last = j;\n // Match 1 or more path separators\n for (; j < len; ++j) {\n if (!isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n // Matched!\n last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j === len) {\n // We matched a UNC root only\n device = '\\\\\\\\' + firstPart + '\\\\' + path.slice(last);\n rootEnd = j;\n }\n else if (j !== last) {\n // We matched a UNC root with leftovers\n device = '\\\\\\\\' + firstPart + '\\\\' + path.slice(last, j);\n rootEnd = j;\n }\n }\n }\n }\n else {\n rootEnd = 1;\n }\n }\n else if (isWindowsDeviceRoot(code)) {\n // Possible device root\n if (path.charCodeAt(1) === CHAR_COLON) {\n device = path.slice(0, 2);\n rootEnd = 2;\n if (len > 2) {\n if (isPathSeparator(path.charCodeAt(2))) {\n // Treat separator following drive name as an absolute path\n // indicator\n isAbsolute = true;\n rootEnd = 3;\n }\n }\n }\n }\n }\n else if (isPathSeparator(code)) {\n // `path` contains just a path separator\n rootEnd = 1;\n isAbsolute = true;\n }\n if (device.length > 0 && resolvedDevice.length > 0 && device.toLowerCase() !== resolvedDevice.toLowerCase()) {\n // This path points to another device so it is not applicable\n continue;\n }\n if (resolvedDevice.length === 0 && device.length > 0) {\n resolvedDevice = device;\n }\n if (!resolvedAbsolute) {\n resolvedTail = path.slice(rootEnd) + '\\\\' + resolvedTail;\n resolvedAbsolute = isAbsolute;\n }\n if (resolvedDevice.length > 0 && resolvedAbsolute) {\n break;\n }\n }\n // At this point the path should be resolved to a full absolute path,\n // but handle relative paths to be safe (might happen when process.cwd()\n // fails)\n // Normalize the tail path\n resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\\\', isPathSeparator);\n return resolvedDevice + (resolvedAbsolute ? '\\\\' : '') + resolvedTail || '.';\n },\n normalize(path) {\n validateString(path, 'path');\n const len = path.length;\n if (len === 0) {\n return '.';\n }\n let rootEnd = 0;\n let device;\n let isAbsolute = false;\n const code = path.charCodeAt(0);\n // Try to match a root\n if (len > 1) {\n if (isPathSeparator(code)) {\n // Possible UNC root\n // If we started with a separator, we know we at least have an absolute\n // path of some kind (UNC or otherwise)\n isAbsolute = true;\n if (isPathSeparator(path.charCodeAt(1))) {\n // Matched double path separator at beginning\n let j = 2;\n let last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n const firstPart = path.slice(last, j);\n // Matched!\n last = j;\n // Match 1 or more path separators\n for (; j < len; ++j) {\n if (!isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n // Matched!\n last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j === len) {\n // We matched a UNC root only\n // Return the normalized version of the UNC root since there\n // is nothing left to process\n return '\\\\\\\\' + firstPart + '\\\\' + path.slice(last) + '\\\\';\n }\n else if (j !== last) {\n // We matched a UNC root with leftovers\n device = '\\\\\\\\' + firstPart + '\\\\' + path.slice(last, j);\n rootEnd = j;\n }\n }\n }\n }\n else {\n rootEnd = 1;\n }\n }\n else if (isWindowsDeviceRoot(code)) {\n // Possible device root\n if (path.charCodeAt(1) === CHAR_COLON) {\n device = path.slice(0, 2);\n rootEnd = 2;\n if (len > 2) {\n if (isPathSeparator(path.charCodeAt(2))) {\n // Treat separator following drive name as an absolute path\n // indicator\n isAbsolute = true;\n rootEnd = 3;\n }\n }\n }\n }\n }\n else if (isPathSeparator(code)) {\n // `path` contains just a path separator, exit early to avoid unnecessary\n // work\n return '\\\\';\n }\n let tail;\n if (rootEnd < len) {\n tail = normalizeString(path.slice(rootEnd), !isAbsolute, '\\\\', isPathSeparator);\n }\n else {\n tail = '';\n }\n if (tail.length === 0 && !isAbsolute) {\n tail = '.';\n }\n if (tail.length > 0 && isPathSeparator(path.charCodeAt(len - 1))) {\n tail += '\\\\';\n }\n if (device === undefined) {\n if (isAbsolute) {\n if (tail.length > 0) {\n return '\\\\' + tail;\n }\n else {\n return '\\\\';\n }\n }\n else if (tail.length > 0) {\n return tail;\n }\n else {\n return '';\n }\n }\n else if (isAbsolute) {\n if (tail.length > 0) {\n return device + '\\\\' + tail;\n }\n else {\n return device + '\\\\';\n }\n }\n else if (tail.length > 0) {\n return device + tail;\n }\n else {\n return device;\n }\n },\n isAbsolute(path) {\n validateString(path, 'path');\n const len = path.length;\n if (len === 0) {\n return false;\n }\n const code = path.charCodeAt(0);\n if (isPathSeparator(code)) {\n return true;\n }\n else if (isWindowsDeviceRoot(code)) {\n // Possible device root\n if (len > 2 && path.charCodeAt(1) === CHAR_COLON) {\n if (isPathSeparator(path.charCodeAt(2))) {\n return true;\n }\n }\n }\n return false;\n },\n join(...paths) {\n if (paths.length === 0) {\n return '.';\n }\n let joined;\n let firstPart;\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0; i < paths.length; ++i) {\n const arg = paths[i];\n validateString(arg, 'path');\n if (arg.length > 0) {\n if (joined === undefined) {\n joined = firstPart = arg;\n }\n else {\n joined += '\\\\' + arg;\n }\n }\n }\n if (joined === undefined) {\n return '.';\n }\n // Make sure that the joined path doesn't start with two slashes, because\n // normalize() will mistake it for an UNC path then.\n //\n // This step is skipped when it is very clear that the user actually\n // intended to point at an UNC path. This is assumed when the first\n // non-empty string arguments starts with exactly two slashes followed by\n // at least one more non-slash character.\n //\n // Note that for normalize() to treat a path as an UNC path it needs to\n // have at least 2 components, so we don't filter for that here.\n // This means that the user can use join to construct UNC paths from\n // a server name and a share name; for example:\n // path.join('//server', 'share') -> '\\\\\\\\server\\\\share\\\\')\n let needsReplace = true;\n let slashCount = 0;\n if (typeof firstPart === 'string' && isPathSeparator(firstPart.charCodeAt(0))) {\n ++slashCount;\n const firstLen = firstPart.length;\n if (firstLen > 1) {\n if (isPathSeparator(firstPart.charCodeAt(1))) {\n ++slashCount;\n if (firstLen > 2) {\n if (isPathSeparator(firstPart.charCodeAt(2))) {\n ++slashCount;\n }\n else {\n // We matched a UNC path in the first part\n needsReplace = false;\n }\n }\n }\n }\n }\n if (needsReplace) {\n // Find any more consecutive slashes we need to replace\n for (; slashCount < joined.length; ++slashCount) {\n if (!isPathSeparator(joined.charCodeAt(slashCount))) {\n break;\n }\n }\n // Replace the slashes if needed\n if (slashCount >= 2) {\n joined = '\\\\' + joined.slice(slashCount);\n }\n }\n return exports.win32.normalize(joined);\n },\n // It will solve the relative path from `from` to `to`, for instance:\n // from = 'C:\\\\orandea\\\\test\\\\aaa'\n // to = 'C:\\\\orandea\\\\impl\\\\bbb'\n // The output of the function should be: '..\\\\..\\\\impl\\\\bbb'\n relative(from, to) {\n validateString(from, 'from');\n validateString(to, 'to');\n if (from === to) {\n return '';\n }\n const fromOrig = exports.win32.resolve(from);\n const toOrig = exports.win32.resolve(to);\n if (fromOrig === toOrig) {\n return '';\n }\n from = fromOrig.toLowerCase();\n to = toOrig.toLowerCase();\n if (from === to) {\n return '';\n }\n // Trim any leading backslashes\n let fromStart = 0;\n for (; fromStart < from.length; ++fromStart) {\n if (from.charCodeAt(fromStart) !== CHAR_BACKWARD_SLASH) {\n break;\n }\n }\n // Trim trailing backslashes (applicable to UNC paths only)\n let fromEnd = from.length;\n for (; fromEnd - 1 > fromStart; --fromEnd) {\n if (from.charCodeAt(fromEnd - 1) !== CHAR_BACKWARD_SLASH) {\n break;\n }\n }\n const fromLen = fromEnd - fromStart;\n // Trim any leading backslashes\n let toStart = 0;\n for (; toStart < to.length; ++toStart) {\n if (to.charCodeAt(toStart) !== CHAR_BACKWARD_SLASH) {\n break;\n }\n }\n // Trim trailing backslashes (applicable to UNC paths only)\n let toEnd = to.length;\n for (; toEnd - 1 > toStart; --toEnd) {\n if (to.charCodeAt(toEnd - 1) !== CHAR_BACKWARD_SLASH) {\n break;\n }\n }\n const toLen = toEnd - toStart;\n // Compare paths to find the longest common path from root\n const length = fromLen < toLen ? fromLen : toLen;\n let lastCommonSep = -1;\n let i = 0;\n for (; i <= length; ++i) {\n if (i === length) {\n if (toLen > length) {\n if (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) {\n // We get here if `from` is the exact base path for `to`.\n // For example: from='C:\\\\foo\\\\bar'; to='C:\\\\foo\\\\bar\\\\baz'\n return toOrig.slice(toStart + i + 1);\n }\n else if (i === 2) {\n // We get here if `from` is the device root.\n // For example: from='C:\\\\'; to='C:\\\\foo'\n return toOrig.slice(toStart + i);\n }\n }\n if (fromLen > length) {\n if (from.charCodeAt(fromStart + i) === CHAR_BACKWARD_SLASH) {\n // We get here if `to` is the exact base path for `from`.\n // For example: from='C:\\\\foo\\\\bar'; to='C:\\\\foo'\n lastCommonSep = i;\n }\n else if (i === 2) {\n // We get here if `to` is the device root.\n // For example: from='C:\\\\foo\\\\bar'; to='C:\\\\'\n lastCommonSep = 3;\n }\n }\n break;\n }\n const fromCode = from.charCodeAt(fromStart + i);\n const toCode = to.charCodeAt(toStart + i);\n if (fromCode !== toCode) {\n break;\n }\n else if (fromCode === CHAR_BACKWARD_SLASH) {\n lastCommonSep = i;\n }\n }\n // We found a mismatch before the first common path separator was seen, so\n // return the original `to`.\n if (i !== length && lastCommonSep === -1) {\n return toOrig;\n }\n let out = '';\n if (lastCommonSep === -1) {\n lastCommonSep = 0;\n }\n // Generate the relative path based on the path difference between `to` and\n // `from`\n for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {\n if (i === fromEnd || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) {\n if (out.length === 0) {\n out += '..';\n }\n else {\n out += '\\\\..';\n }\n }\n }\n // Lastly, append the rest of the destination (`to`) path that comes after\n // the common path parts\n if (out.length > 0) {\n return out + toOrig.slice(toStart + lastCommonSep, toEnd);\n }\n else {\n toStart += lastCommonSep;\n if (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) {\n ++toStart;\n }\n return toOrig.slice(toStart, toEnd);\n }\n },\n toNamespacedPath(path) {\n // Note: this will *probably* throw somewhere.\n if (typeof path !== 'string') {\n return path;\n }\n if (path.length === 0) {\n return '';\n }\n const resolvedPath = exports.win32.resolve(path);\n if (resolvedPath.length >= 3) {\n if (resolvedPath.charCodeAt(0) === CHAR_BACKWARD_SLASH) {\n // Possible UNC root\n if (resolvedPath.charCodeAt(1) === CHAR_BACKWARD_SLASH) {\n const code = resolvedPath.charCodeAt(2);\n if (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) {\n // Matched non-long UNC root, convert the path to a long UNC path\n return '\\\\\\\\?\\\\UNC\\\\' + resolvedPath.slice(2);\n }\n }\n }\n else if (isWindowsDeviceRoot(resolvedPath.charCodeAt(0))) {\n // Possible device root\n if (resolvedPath.charCodeAt(1) === CHAR_COLON && resolvedPath.charCodeAt(2) === CHAR_BACKWARD_SLASH) {\n // Matched device root, convert the path to a long UNC path\n return '\\\\\\\\?\\\\' + resolvedPath;\n }\n }\n }\n return path;\n },\n dirname(path) {\n validateString(path, 'path');\n const len = path.length;\n if (len === 0) {\n return '.';\n }\n let rootEnd = -1;\n let end = -1;\n let matchedSlash = true;\n let offset = 0;\n const code = path.charCodeAt(0);\n // Try to match a root\n if (len > 1) {\n if (isPathSeparator(code)) {\n // Possible UNC root\n rootEnd = offset = 1;\n if (isPathSeparator(path.charCodeAt(1))) {\n // Matched double path separator at beginning\n let j = 2;\n let last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n // Matched!\n last = j;\n // Match 1 or more path separators\n for (; j < len; ++j) {\n if (!isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n // Matched!\n last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j === len) {\n // We matched a UNC root only\n return path;\n }\n if (j !== last) {\n // We matched a UNC root with leftovers\n // Offset by 1 to include the separator after the UNC root to\n // treat it as a \"normal root\" on top of a (UNC) root\n rootEnd = offset = j + 1;\n }\n }\n }\n }\n }\n else if (isWindowsDeviceRoot(code)) {\n // Possible device root\n if (path.charCodeAt(1) === CHAR_COLON) {\n rootEnd = offset = 2;\n if (len > 2) {\n if (isPathSeparator(path.charCodeAt(2))) {\n rootEnd = offset = 3;\n }\n }\n }\n }\n }\n else if (isPathSeparator(code)) {\n // `path` contains just a path separator, exit early to avoid\n // unnecessary work\n return path;\n }\n for (let i = len - 1; i >= offset; --i) {\n if (isPathSeparator(path.charCodeAt(i))) {\n if (!matchedSlash) {\n end = i;\n break;\n }\n }\n else {\n // We saw the first non-path separator\n matchedSlash = false;\n }\n }\n if (end === -1) {\n if (rootEnd === -1) {\n return '.';\n }\n else {\n end = rootEnd;\n }\n }\n return path.slice(0, end);\n },\n basename(path, ext) {\n if (ext !== undefined) {\n validateString(ext, 'ext');\n }\n validateString(path, 'path');\n let start = 0;\n let end = -1;\n let matchedSlash = true;\n let i;\n // Check for a drive letter prefix so as not to mistake the following\n // path separator as an extra separator at the end of the path that can be\n // disregarded\n if (path.length >= 2) {\n const drive = path.charCodeAt(0);\n if (isWindowsDeviceRoot(drive)) {\n if (path.charCodeAt(1) === CHAR_COLON) {\n start = 2;\n }\n }\n }\n if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {\n if (ext.length === path.length && ext === path) {\n return '';\n }\n let extIdx = ext.length - 1;\n let firstNonSlashEnd = -1;\n for (i = path.length - 1; i >= start; --i) {\n const code = path.charCodeAt(i);\n if (isPathSeparator(code)) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n start = i + 1;\n break;\n }\n }\n else {\n if (firstNonSlashEnd === -1) {\n // We saw the first non-path separator, remember this index in case\n // we need it if the extension ends up not matching\n matchedSlash = false;\n firstNonSlashEnd = i + 1;\n }\n if (extIdx >= 0) {\n // Try to match the explicit extension\n if (code === ext.charCodeAt(extIdx)) {\n if (--extIdx === -1) {\n // We matched the extension, so mark this as the end of our path\n // component\n end = i;\n }\n }\n else {\n // Extension does not match, so our result is the entire path\n // component\n extIdx = -1;\n end = firstNonSlashEnd;\n }\n }\n }\n }\n if (start === end) {\n end = firstNonSlashEnd;\n }\n else if (end === -1) {\n end = path.length;\n }\n return path.slice(start, end);\n }\n else {\n for (i = path.length - 1; i >= start; --i) {\n if (isPathSeparator(path.charCodeAt(i))) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n start = i + 1;\n break;\n }\n }\n else if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // path component\n matchedSlash = false;\n end = i + 1;\n }\n }\n if (end === -1) {\n return '';\n }\n return path.slice(start, end);\n }\n },\n extname(path) {\n validateString(path, 'path');\n let start = 0;\n let startDot = -1;\n let startPart = 0;\n let end = -1;\n let matchedSlash = true;\n // Track the state of characters (if any) we see before our first dot and\n // after any path separator we find\n let preDotState = 0;\n // Check for a drive letter prefix so as not to mistake the following\n // path separator as an extra separator at the end of the path that can be\n // disregarded\n if (path.length >= 2 && path.charCodeAt(1) === CHAR_COLON && isWindowsDeviceRoot(path.charCodeAt(0))) {\n start = startPart = 2;\n }\n for (let i = path.length - 1; i >= start; --i) {\n const code = path.charCodeAt(i);\n if (isPathSeparator(code)) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n startPart = i + 1;\n break;\n }\n continue;\n }\n if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // extension\n matchedSlash = false;\n end = i + 1;\n }\n if (code === CHAR_DOT) {\n // If this is our first dot, mark it as the start of our extension\n if (startDot === -1) {\n startDot = i;\n }\n else if (preDotState !== 1) {\n preDotState = 1;\n }\n }\n else if (startDot !== -1) {\n // We saw a non-dot and non-path separator before our dot, so we should\n // have a good chance at having a non-empty extension\n preDotState = -1;\n }\n }\n if (startDot === -1 ||\n end === -1 ||\n // We saw a non-dot character immediately before the dot\n preDotState === 0 ||\n // The (right-most) trimmed path component is exactly '..'\n (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {\n return '';\n }\n return path.slice(startDot, end);\n },\n format(pathObject) {\n if (pathObject === null || typeof pathObject !== 'object') {\n throw new ErrorInvalidArgType('pathObject', 'Object', pathObject);\n }\n return _format('\\\\', pathObject);\n },\n parse(path) {\n validateString(path, 'path');\n const ret = { root: '', dir: '', base: '', ext: '', name: '' };\n if (path.length === 0) {\n return ret;\n }\n const len = path.length;\n let rootEnd = 0;\n let code = path.charCodeAt(0);\n // Try to match a root\n if (len > 1) {\n if (isPathSeparator(code)) {\n // Possible UNC root\n rootEnd = 1;\n if (isPathSeparator(path.charCodeAt(1))) {\n // Matched double path separator at beginning\n let j = 2;\n let last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n // Matched!\n last = j;\n // Match 1 or more path separators\n for (; j < len; ++j) {\n if (!isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j < len && j !== last) {\n // Matched!\n last = j;\n // Match 1 or more non-path separators\n for (; j < len; ++j) {\n if (isPathSeparator(path.charCodeAt(j))) {\n break;\n }\n }\n if (j === len) {\n // We matched a UNC root only\n rootEnd = j;\n }\n else if (j !== last) {\n // We matched a UNC root with leftovers\n rootEnd = j + 1;\n }\n }\n }\n }\n }\n else if (isWindowsDeviceRoot(code)) {\n // Possible device root\n if (path.charCodeAt(1) === CHAR_COLON) {\n rootEnd = 2;\n if (len > 2) {\n if (isPathSeparator(path.charCodeAt(2))) {\n if (len === 3) {\n // `path` contains just a drive root, exit early to avoid\n // unnecessary work\n ret.root = ret.dir = path;\n return ret;\n }\n rootEnd = 3;\n }\n }\n else {\n // `path` contains just a drive root, exit early to avoid\n // unnecessary work\n ret.root = ret.dir = path;\n return ret;\n }\n }\n }\n }\n else if (isPathSeparator(code)) {\n // `path` contains just a path separator, exit early to avoid\n // unnecessary work\n ret.root = ret.dir = path;\n return ret;\n }\n if (rootEnd > 0) {\n ret.root = path.slice(0, rootEnd);\n }\n let startDot = -1;\n let startPart = rootEnd;\n let end = -1;\n let matchedSlash = true;\n let i = path.length - 1;\n // Track the state of characters (if any) we see before our first dot and\n // after any path separator we find\n let preDotState = 0;\n // Get non-dir info\n for (; i >= rootEnd; --i) {\n code = path.charCodeAt(i);\n if (isPathSeparator(code)) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n startPart = i + 1;\n break;\n }\n continue;\n }\n if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // extension\n matchedSlash = false;\n end = i + 1;\n }\n if (code === CHAR_DOT) {\n // If this is our first dot, mark it as the start of our extension\n if (startDot === -1) {\n startDot = i;\n }\n else if (preDotState !== 1) {\n preDotState = 1;\n }\n }\n else if (startDot !== -1) {\n // We saw a non-dot and non-path separator before our dot, so we should\n // have a good chance at having a non-empty extension\n preDotState = -1;\n }\n }\n if (startDot === -1 ||\n end === -1 ||\n // We saw a non-dot character immediately before the dot\n preDotState === 0 ||\n // The (right-most) trimmed path component is exactly '..'\n (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {\n if (end !== -1) {\n ret.base = ret.name = path.slice(startPart, end);\n }\n }\n else {\n ret.name = path.slice(startPart, startDot);\n ret.base = path.slice(startPart, end);\n ret.ext = path.slice(startDot, end);\n }\n // If the directory is the root, use the entire root as the `dir` including\n // the trailing slash if any (`C:\\abc` -> `C:\\`). Otherwise, strip out the\n // trailing slash (`C:\\abc\\def` -> `C:\\abc`).\n if (startPart > 0 && startPart !== rootEnd) {\n ret.dir = path.slice(0, startPart - 1);\n }\n else {\n ret.dir = ret.root;\n }\n return ret;\n },\n sep: '\\\\',\n delimiter: ';',\n win32: null,\n posix: null,\n};\nexports.posix = {\n // path.resolve([from ...], to)\n resolve(...pathSegments) {\n let resolvedPath = '';\n let resolvedAbsolute = false;\n for (let i = pathSegments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n let path;\n if (i >= 0) {\n path = pathSegments[i];\n }\n else {\n path = process.cwd();\n }\n validateString(path, 'path');\n // Skip empty entries\n if (path.length === 0) {\n continue;\n }\n resolvedPath = path + '/' + resolvedPath;\n resolvedAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n }\n // At this point the path should be resolved to a full absolute path, but\n // handle relative paths to be safe (might happen when process.cwd() fails)\n // Normalize the path\n resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/', isPosixPathSeparator);\n if (resolvedAbsolute) {\n if (resolvedPath.length > 0) {\n return '/' + resolvedPath;\n }\n else {\n return '/';\n }\n }\n else if (resolvedPath.length > 0) {\n return resolvedPath;\n }\n else {\n return '.';\n }\n },\n normalize(path) {\n validateString(path, 'path');\n if (path.length === 0) {\n return '.';\n }\n const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n const trailingSeparator = path.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH;\n // Normalize the path\n path = normalizeString(path, !isAbsolute, '/', isPosixPathSeparator);\n if (path.length === 0 && !isAbsolute) {\n path = '.';\n }\n if (path.length > 0 && trailingSeparator) {\n path += '/';\n }\n if (isAbsolute) {\n return '/' + path;\n }\n return path;\n },\n isAbsolute(path) {\n validateString(path, 'path');\n return path.length > 0 && path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n },\n join(...paths) {\n if (paths.length === 0) {\n return '.';\n }\n let joined;\n for (let i = 0; i < paths.length; ++i) {\n const arg = arguments[i];\n validateString(arg, 'path');\n if (arg.length > 0) {\n if (joined === undefined) {\n joined = arg;\n }\n else {\n joined += '/' + arg;\n }\n }\n }\n if (joined === undefined) {\n return '.';\n }\n return exports.posix.normalize(joined);\n },\n relative(from, to) {\n validateString(from, 'from');\n validateString(to, 'to');\n if (from === to) {\n return '';\n }\n from = exports.posix.resolve(from);\n to = exports.posix.resolve(to);\n if (from === to) {\n return '';\n }\n // Trim any leading backslashes\n let fromStart = 1;\n for (; fromStart < from.length; ++fromStart) {\n if (from.charCodeAt(fromStart) !== CHAR_FORWARD_SLASH) {\n break;\n }\n }\n const fromEnd = from.length;\n const fromLen = fromEnd - fromStart;\n // Trim any leading backslashes\n let toStart = 1;\n for (; toStart < to.length; ++toStart) {\n if (to.charCodeAt(toStart) !== CHAR_FORWARD_SLASH) {\n break;\n }\n }\n const toEnd = to.length;\n const toLen = toEnd - toStart;\n // Compare paths to find the longest common path from root\n const length = fromLen < toLen ? fromLen : toLen;\n let lastCommonSep = -1;\n let i = 0;\n for (; i <= length; ++i) {\n if (i === length) {\n if (toLen > length) {\n if (to.charCodeAt(toStart + i) === CHAR_FORWARD_SLASH) {\n // We get here if `from` is the exact base path for `to`.\n // For example: from='/foo/bar'; to='/foo/bar/baz'\n return to.slice(toStart + i + 1);\n }\n else if (i === 0) {\n // We get here if `from` is the root\n // For example: from='/'; to='/foo'\n return to.slice(toStart + i);\n }\n }\n else if (fromLen > length) {\n if (from.charCodeAt(fromStart + i) === CHAR_FORWARD_SLASH) {\n // We get here if `to` is the exact base path for `from`.\n // For example: from='/foo/bar/baz'; to='/foo/bar'\n lastCommonSep = i;\n }\n else if (i === 0) {\n // We get here if `to` is the root.\n // For example: from='/foo'; to='/'\n lastCommonSep = 0;\n }\n }\n break;\n }\n const fromCode = from.charCodeAt(fromStart + i);\n const toCode = to.charCodeAt(toStart + i);\n if (fromCode !== toCode) {\n break;\n }\n else if (fromCode === CHAR_FORWARD_SLASH) {\n lastCommonSep = i;\n }\n }\n let out = '';\n // Generate the relative path based on the path difference between `to`\n // and `from`\n for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {\n if (i === fromEnd || from.charCodeAt(i) === CHAR_FORWARD_SLASH) {\n if (out.length === 0) {\n out += '..';\n }\n else {\n out += '/..';\n }\n }\n }\n // Lastly, append the rest of the destination (`to`) path that comes after\n // the common path parts\n if (out.length > 0) {\n return out + to.slice(toStart + lastCommonSep);\n }\n else {\n toStart += lastCommonSep;\n if (to.charCodeAt(toStart) === CHAR_FORWARD_SLASH) {\n ++toStart;\n }\n return to.slice(toStart);\n }\n },\n toNamespacedPath(path) {\n // Non-op on posix systems\n return path;\n },\n dirname(path) {\n validateString(path, 'path');\n if (path.length === 0) {\n return '.';\n }\n const hasRoot = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n let end = -1;\n let matchedSlash = true;\n for (let i = path.length - 1; i >= 1; --i) {\n if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) {\n if (!matchedSlash) {\n end = i;\n break;\n }\n }\n else {\n // We saw the first non-path separator\n matchedSlash = false;\n }\n }\n if (end === -1) {\n return hasRoot ? '/' : '.';\n }\n if (hasRoot && end === 1) {\n return '//';\n }\n return path.slice(0, end);\n },\n basename(path, ext) {\n if (ext !== undefined) {\n validateString(ext, 'ext');\n }\n validateString(path, 'path');\n let start = 0;\n let end = -1;\n let matchedSlash = true;\n let i;\n if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {\n if (ext.length === path.length && ext === path) {\n return '';\n }\n let extIdx = ext.length - 1;\n let firstNonSlashEnd = -1;\n for (i = path.length - 1; i >= 0; --i) {\n const code = path.charCodeAt(i);\n if (code === CHAR_FORWARD_SLASH) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n start = i + 1;\n break;\n }\n }\n else {\n if (firstNonSlashEnd === -1) {\n // We saw the first non-path separator, remember this index in case\n // we need it if the extension ends up not matching\n matchedSlash = false;\n firstNonSlashEnd = i + 1;\n }\n if (extIdx >= 0) {\n // Try to match the explicit extension\n if (code === ext.charCodeAt(extIdx)) {\n if (--extIdx === -1) {\n // We matched the extension, so mark this as the end of our path\n // component\n end = i;\n }\n }\n else {\n // Extension does not match, so our result is the entire path\n // component\n extIdx = -1;\n end = firstNonSlashEnd;\n }\n }\n }\n }\n if (start === end) {\n end = firstNonSlashEnd;\n }\n else if (end === -1) {\n end = path.length;\n }\n return path.slice(start, end);\n }\n else {\n for (i = path.length - 1; i >= 0; --i) {\n if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n start = i + 1;\n break;\n }\n }\n else if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // path component\n matchedSlash = false;\n end = i + 1;\n }\n }\n if (end === -1) {\n return '';\n }\n return path.slice(start, end);\n }\n },\n extname(path) {\n validateString(path, 'path');\n let startDot = -1;\n let startPart = 0;\n let end = -1;\n let matchedSlash = true;\n // Track the state of characters (if any) we see before our first dot and\n // after any path separator we find\n let preDotState = 0;\n for (let i = path.length - 1; i >= 0; --i) {\n const code = path.charCodeAt(i);\n if (code === CHAR_FORWARD_SLASH) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n startPart = i + 1;\n break;\n }\n continue;\n }\n if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // extension\n matchedSlash = false;\n end = i + 1;\n }\n if (code === CHAR_DOT) {\n // If this is our first dot, mark it as the start of our extension\n if (startDot === -1) {\n startDot = i;\n }\n else if (preDotState !== 1) {\n preDotState = 1;\n }\n }\n else if (startDot !== -1) {\n // We saw a non-dot and non-path separator before our dot, so we should\n // have a good chance at having a non-empty extension\n preDotState = -1;\n }\n }\n if (startDot === -1 ||\n end === -1 ||\n // We saw a non-dot character immediately before the dot\n preDotState === 0 ||\n // The (right-most) trimmed path component is exactly '..'\n (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {\n return '';\n }\n return path.slice(startDot, end);\n },\n format(pathObject) {\n if (pathObject === null || typeof pathObject !== 'object') {\n throw new ErrorInvalidArgType('pathObject', 'Object', pathObject);\n }\n return _format('/', pathObject);\n },\n parse(path) {\n validateString(path, 'path');\n const ret = { root: '', dir: '', base: '', ext: '', name: '' };\n if (path.length === 0) {\n return ret;\n }\n const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n let start;\n if (isAbsolute) {\n ret.root = '/';\n start = 1;\n }\n else {\n start = 0;\n }\n let startDot = -1;\n let startPart = 0;\n let end = -1;\n let matchedSlash = true;\n let i = path.length - 1;\n // Track the state of characters (if any) we see before our first dot and\n // after any path separator we find\n let preDotState = 0;\n // Get non-dir info\n for (; i >= start; --i) {\n const code = path.charCodeAt(i);\n if (code === CHAR_FORWARD_SLASH) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n startPart = i + 1;\n break;\n }\n continue;\n }\n if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // extension\n matchedSlash = false;\n end = i + 1;\n }\n if (code === CHAR_DOT) {\n // If this is our first dot, mark it as the start of our extension\n if (startDot === -1) {\n startDot = i;\n }\n else if (preDotState !== 1) {\n preDotState = 1;\n }\n }\n else if (startDot !== -1) {\n // We saw a non-dot and non-path separator before our dot, so we should\n // have a good chance at having a non-empty extension\n preDotState = -1;\n }\n }\n if (startDot === -1 ||\n end === -1 ||\n // We saw a non-dot character immediately before the dot\n preDotState === 0 ||\n // The (right-most) trimmed path component is exactly '..'\n (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {\n if (end !== -1) {\n if (startPart === 0 && isAbsolute) {\n ret.base = ret.name = path.slice(1, end);\n }\n else {\n ret.base = ret.name = path.slice(startPart, end);\n }\n }\n }\n else {\n if (startPart === 0 && isAbsolute) {\n ret.name = path.slice(1, startDot);\n ret.base = path.slice(1, end);\n }\n else {\n ret.name = path.slice(startPart, startDot);\n ret.base = path.slice(startPart, end);\n }\n ret.ext = path.slice(startDot, end);\n }\n if (startPart > 0) {\n ret.dir = path.slice(0, startPart - 1);\n }\n else if (isAbsolute) {\n ret.dir = '/';\n }\n return ret;\n },\n sep: '/',\n delimiter: ':',\n win32: null,\n posix: null,\n};\nexports.posix.win32 = exports.win32.win32 = exports.win32;\nexports.posix.posix = exports.win32.posix = exports.posix;\n/**\n * Takes a Windows OS path and changes backward slashes to forward slashes.\n * This should only be done for OS paths from Windows (or user provided paths potentially from Windows).\n * Using it on a Linux or MaxOS path might change it.\n */\nfunction toSlashes(osPath) {\n return osPath.replace(/[\\\\/]/g, exports.posix.sep);\n}\nexports.toSlashes = toSlashes;\nexports.normalize = process.platform === 'win32' ? exports.win32.normalize : exports.posix.normalize;\nexports.isAbsolute = process.platform === 'win32' ? exports.win32.isAbsolute : exports.posix.isAbsolute;\nexports.join = process.platform === 'win32' ? exports.win32.join : exports.posix.join;\nexports.resolve = process.platform === 'win32' ? exports.win32.resolve : exports.posix.resolve;\nexports.relative = process.platform === 'win32' ? exports.win32.relative : exports.posix.relative;\nexports.dirname = process.platform === 'win32' ? exports.win32.dirname : exports.posix.dirname;\nexports.basename = process.platform === 'win32' ? exports.win32.basename : exports.posix.basename;\nexports.extname = process.platform === 'win32' ? exports.win32.extname : exports.posix.extname;\nexports.format = process.platform === 'win32' ? exports.win32.format : exports.posix.format;\nexports.parse = process.platform === 'win32' ? exports.win32.parse : exports.posix.parse;\nexports.toNamespacedPath = process.platform === 'win32' ? exports.win32.toNamespacedPath : exports.posix.toNamespacedPath;\nexports.sep = process.platform === 'win32' ? exports.win32.sep : exports.posix.sep;\nexports.delimiter = process.platform === 'win32' ? exports.win32.delimiter : exports.posix.delimiter;\nfunction replaceAsarInPath(pathMayInAsar) {\n (0, exports.parse)(pathMayInAsar);\n const parts = pathMayInAsar.split((0, exports.normalize)('/'));\n parts.forEach((part, i) => {\n if (part.endsWith('.asar')) {\n parts[i] = part + '.unpacked';\n }\n });\n return parts.join((0, exports.normalize)('/'));\n}\nexports.replaceAsarInPath = replaceAsarInPath;\n// Reference: https://en.wikipedia.org/wiki/Filename\nconst WINDOWS_INVALID_FILE_CHARS = /[\\\\/:*?\"<>|]/g;\nconst UNIX_INVALID_FILE_CHARS = /[\\\\/]/g;\nconst WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\\$|nul|lpt[0-9]|com[0-9])$/i;\nfunction isValidBasename(name, isWindowsOS = platform_1.isWindows) {\n const invalidFileChars = isWindowsOS ? WINDOWS_INVALID_FILE_CHARS : UNIX_INVALID_FILE_CHARS;\n if (!name || name.length === 0 || /^\\s+$/.test(name)) {\n return false; // require a name that is not just whitespace\n }\n invalidFileChars.lastIndex = 0; // the holy grail of software development\n if (invalidFileChars.test(name)) {\n return false; // check for certain invalid file characters\n }\n if (isWindowsOS && WINDOWS_FORBIDDEN_NAMES.test(name)) {\n return false; // check for certain invalid file names\n }\n if (name === '.' || name === '..') {\n return false; // check for reserved values\n }\n if (isWindowsOS && name[name.length - 1] === '.') {\n return false; // Windows: file cannot end with a \".\"\n }\n if (isWindowsOS && name.length !== name.trim().length) {\n return false; // Windows: file cannot end with a whitespace\n }\n if (name.length > 255) {\n return false; // most file systems do not allow files > 255 length\n }\n return true;\n}\nexports.isValidBasename = isValidBasename;\n//# sourceMappingURL=path.js.map\n\n//# sourceURL=webpack://@opensumi/ide-components/../utils/lib/path.js?");
6922
6911
 
6923
6912
  /***/ }),
6924
6913
 
@@ -6962,7 +6951,7 @@ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexpo
6962
6951
  /***/ ((__unused_webpack_module, exports) => {
6963
6952
 
6964
6953
  "use strict";
6965
- eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.PromiseTasks = exports.pSeries = exports.Deferred = void 0;\n/**\n * Simple implementation of the deferred pattern.\n * An object that exposes a promise and functions to resolve and reject it.\n */\nclass Deferred {\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\nexports.Deferred = Deferred;\nasync function pSeries(tasks) {\n const results = [];\n for (const task of tasks) {\n results.push(await task());\n }\n return results;\n}\nexports.pSeries = pSeries;\nclass PromiseTasks {\n constructor() {\n this.tasks = [];\n }\n add(task) {\n this.tasks.push(task);\n }\n addPromise(task) {\n this.tasks.push(() => task);\n }\n promisify() {\n return this.tasks.map((task) => task());\n }\n async allSettled() {\n return Promise.allSettled(this.promisify());\n }\n async all() {\n return Promise.all(this.promisify());\n }\n async race() {\n return Promise.race(this.promisify());\n }\n /**\n * This returned promise fulfills when any of the input's promises fulfills, with this first fulfillment value.\n * It return `undefined` when all of the input's promises reject (including when an empty iterable is passed).\n */\n async any() {\n try {\n return await Promise.any(this.promisify());\n }\n catch (error) {\n return undefined;\n }\n }\n}\nexports.PromiseTasks = PromiseTasks;\n//# sourceMappingURL=promises.js.map\n\n//# sourceURL=webpack://@opensumi/ide-components/../utils/lib/promises.js?");
6954
+ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.pSeries = exports.Deferred = void 0;\n/**\n * Simple implementation of the deferred pattern.\n * An object that exposes a promise and functions to resolve and reject it.\n */\nclass Deferred {\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\nexports.Deferred = Deferred;\nasync function pSeries(tasks) {\n const results = [];\n for (const task of tasks) {\n results.push(await task());\n }\n return results;\n}\nexports.pSeries = pSeries;\n//# sourceMappingURL=promises.js.map\n\n//# sourceURL=webpack://@opensumi/ide-components/../utils/lib/promises.js?");
6966
6955
 
6967
6956
  /***/ }),
6968
6957
 
@@ -6984,7 +6973,7 @@ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexpo
6984
6973
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
6985
6974
 
6986
6975
  "use strict";
6987
- eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.containsUppercaseCharacter = exports.fuzzyContains = exports.repeat = exports.safeBtoa = exports.stripUTF8BOM = exports.startsWithUTF8BOM = exports.UTF8_BOM_CHARACTER = exports.removeAccents = exports.removeAnsiEscapeCodes = exports.lcut = exports.isFullWidthCharacter = exports.containsFullWidthCharacter = exports.isBasicASCII = exports.containsEmoji = exports.containsRTL = exports.isLowSurrogate = exports.isHighSurrogate = exports.overlap = exports.commonSuffixLength = exports.commonPrefixLength = exports.startsWithIgnoreCase = exports.equalsIgnoreCase = exports.isUpperAsciiLetter = exports.isLowerAsciiLetter = exports.compareIgnoreCase = exports.compare = exports.lastNonWhitespaceIndex = exports.getLeadingWhitespace = exports.firstNonWhitespaceIndex = exports.regExpFlags = exports.regExpContainsBackreference = exports.regExpLeadsToEndlessLoop = exports.createRegExp = exports.endsWith = exports.startsWith = exports.stripWildcards = exports.convertSimple2RegExpPattern = exports.rtrim = exports.multiRightTrim = exports.ltrim = exports.trim = exports.count = exports.escapeRegExpCharacters = exports.escape = exports.mnemonicButtonLabel = exports.format = exports.pad = exports.isFalsyOrWhitespace = exports.stringUtils = exports.empty = void 0;\nexports.format2 = exports.template = exports.decodeUTF8 = exports.encodeUTF8 = exports.getNextCodePoint = exports.computeCodePoint = exports.getNLines = exports.uppercaseFirstLetter = void 0;\nconst platform_1 = __webpack_require__(/*! ./platform */ \"../utils/lib/platform.js\");\n/**\n * The empty string.\n */\nexports.empty = '';\nconst hasTextEncoder = typeof TextEncoder !== 'undefined';\nconst hasTextDecoder = typeof TextDecoder !== 'undefined';\n/**\n * 浏览器全局可以直接使用 TextEncoder/TextDecoder\n * Node.js 11+ 才可以全局使用,以下需要 require('util')\n */\nvar stringUtils;\n(function (stringUtils) {\n stringUtils.StringTextEncoder = hasTextEncoder ? TextEncoder : (__webpack_require__(/*! util */ \"../../node_modules/util/util.js\").TextEncoder);\n stringUtils.StringTextDecoder = hasTextDecoder ? TextDecoder : (__webpack_require__(/*! util */ \"../../node_modules/util/util.js\").TextDecoder);\n})(stringUtils = exports.stringUtils || (exports.stringUtils = {}));\nfunction isFalsyOrWhitespace(str) {\n if (!str || typeof str !== 'string') {\n return true;\n }\n return str.trim().length === 0;\n}\nexports.isFalsyOrWhitespace = isFalsyOrWhitespace;\n/**\n * @returns the provided number with the given number of preceding zeros.\n */\nfunction pad(n, l, char = '0') {\n const str = '' + n;\n const r = [str];\n for (let i = str.length; i < l; i++) {\n r.push(char);\n }\n return r.reverse().join('');\n}\nexports.pad = pad;\nconst _formatRegexp = /{(\\d+)}/g;\n/**\n * Helper to produce a string with a variable number of arguments. Insert variable segments\n * into the string using the {n} notation where N is the index of the argument following the string.\n * @param value string to which formatting is applied\n * @param args replacements for {n}-entries\n */\nfunction format(value, ...args) {\n if (args.length === 0) {\n return value;\n }\n return value.replace(_formatRegexp, function (match, group) {\n const idx = parseInt(group, 10);\n return isNaN(idx) || idx < 0 || idx >= args.length ? match : args[idx];\n });\n}\nexports.format = format;\n/**\n * Handles mnemonics for buttons. Depending on OS:\n * - Windows: Supported via & character (replace && with & and & with && for escaping)\n * - Linux: Supported via _ character (replace && with _)\n * - macOS: Unsupported (replace && with empty string)\n */\nfunction mnemonicButtonLabel(label, forceDisableMnemonics) {\n if (platform_1.isMacintosh || forceDisableMnemonics) {\n return label.replace(/\\(&&\\w\\)|&&/g, '');\n }\n if (platform_1.isWindows) {\n return label.replace(/&&|&/g, (m) => (m === '&' ? '&&' : '&'));\n }\n return label.replace(/&&/g, '_');\n}\nexports.mnemonicButtonLabel = mnemonicButtonLabel;\n/**\n * Converts HTML characters inside the string to use entities instead. Makes the string safe from\n * being used e.g. in HTMLElement.innerHTML.\n */\nfunction escape(html) {\n return html.replace(/[<>&]/g, function (match) {\n switch (match) {\n case '<':\n return '&lt;';\n case '>':\n return '&gt;';\n case '&':\n return '&amp;';\n default:\n return match;\n }\n });\n}\nexports.escape = escape;\n/**\n * Escapes regular expression characters in a given string\n */\nfunction escapeRegExpCharacters(value) {\n return value.replace(/[\\\\\\{\\}\\*\\+\\?\\|\\^\\$\\.\\[\\]\\(\\)]/g, '\\\\$&');\n}\nexports.escapeRegExpCharacters = escapeRegExpCharacters;\n/**\n * Counts how often `character` occurs inside `value`.\n */\nfunction count(value, character) {\n let result = 0;\n const ch = character.charCodeAt(0);\n for (let i = value.length - 1; i >= 0; i--) {\n if (value.charCodeAt(i) === ch) {\n result++;\n }\n }\n return result;\n}\nexports.count = count;\n/**\n * Removes all occurrences of needle from the beginning and end of haystack.\n * @param haystack string to trim\n * @param needle the thing to trim (default is a blank)\n */\nfunction trim(haystack, needle = ' ') {\n const trimmed = ltrim(haystack, needle);\n return rtrim(trimmed, needle);\n}\nexports.trim = trim;\n/**\n * Removes all occurrences of needle from the beginning of haystack.\n * @param haystack string to trim\n * @param needle the thing to trim\n */\nfunction ltrim(haystack, needle) {\n if (!haystack || !needle) {\n return haystack;\n }\n const needleLen = needle.length;\n if (needleLen === 0 || haystack.length === 0) {\n return haystack;\n }\n let offset = 0;\n while (haystack.indexOf(needle, offset) === offset) {\n offset = offset + needleLen;\n }\n return haystack.substring(offset);\n}\nexports.ltrim = ltrim;\n/**\n * Removes all occurrences of needles from the end of haystack.\n * @param source\n * @param needles\n * @example\n * ```ts\n * let source = '/path/to/file.ts,;';\n * const res = multiRightTrim(source, [`,`, ';']);\n * // res === '/path/to/file.ts';\n * ```\n */\nfunction multiRightTrim(source, needles) {\n let result = decodeURIComponent(source);\n for (const needle of needles) {\n result = rtrim(result, needle);\n }\n return result;\n}\nexports.multiRightTrim = multiRightTrim;\n/**\n * Removes all occurrences of needle from the end of haystack.\n * @param haystack string to trim\n * @param needle the thing to trim\n */\nfunction rtrim(haystack, needle) {\n if (!haystack || !needle) {\n return haystack;\n }\n const needleLen = needle.length;\n const haystackLen = haystack.length;\n if (needleLen === 0 || haystackLen === 0) {\n return haystack;\n }\n let offset = haystackLen;\n let idx = -1;\n while (true) {\n idx = haystack.lastIndexOf(needle, offset - 1);\n if (idx === -1 || idx + needleLen !== offset) {\n break;\n }\n if (idx === 0) {\n return '';\n }\n offset = idx;\n }\n return haystack.substring(0, offset);\n}\nexports.rtrim = rtrim;\nfunction convertSimple2RegExpPattern(pattern) {\n return pattern.replace(/[\\-\\\\\\{\\}\\+\\?\\|\\^\\$\\.\\,\\[\\]\\(\\)\\#\\s]/g, '\\\\$&').replace(/[\\*]/g, '.*');\n}\nexports.convertSimple2RegExpPattern = convertSimple2RegExpPattern;\nfunction stripWildcards(pattern) {\n return pattern.replace(/\\*/g, '');\n}\nexports.stripWildcards = stripWildcards;\n/**\n * Determines if haystack starts with needle.\n */\nfunction startsWith(haystack, needle) {\n if (haystack.length < needle.length) {\n return false;\n }\n if (haystack === needle) {\n return true;\n }\n for (let i = 0; i < needle.length; i++) {\n if (haystack[i] !== needle[i]) {\n return false;\n }\n }\n return true;\n}\nexports.startsWith = startsWith;\n/**\n * Determines if haystack ends with needle.\n */\nfunction endsWith(haystack, needle) {\n const diff = haystack.length - needle.length;\n if (diff > 0) {\n return haystack.indexOf(needle, diff) === diff;\n }\n else if (diff === 0) {\n return haystack === needle;\n }\n else {\n return false;\n }\n}\nexports.endsWith = endsWith;\nfunction createRegExp(searchString, isRegex, options = {}) {\n if (!searchString) {\n throw new Error('Cannot create regex from empty string');\n }\n if (!isRegex) {\n searchString = escapeRegExpCharacters(searchString);\n }\n if (options.wholeWord) {\n if (!/\\B/.test(searchString.charAt(0))) {\n searchString = '\\\\b' + searchString;\n }\n if (!/\\B/.test(searchString.charAt(searchString.length - 1))) {\n searchString = searchString + '\\\\b';\n }\n }\n let modifiers = '';\n if (options.global) {\n modifiers += 'g';\n }\n if (!options.matchCase) {\n modifiers += 'i';\n }\n if (options.multiline) {\n modifiers += 'm';\n }\n if (options.unicode) {\n modifiers += 'u';\n }\n return new RegExp(searchString, modifiers);\n}\nexports.createRegExp = createRegExp;\nfunction regExpLeadsToEndlessLoop(regexp) {\n // Exit early if it's one of these special cases which are meant to match\n // against an empty string\n if (regexp.source === '^' || regexp.source === '^$' || regexp.source === '$' || regexp.source === '^\\\\s*$') {\n return false;\n }\n // We check against an empty string. If the regular expression doesn't advance\n // (e.g. ends in an endless loop) it will match an empty string.\n const match = regexp.exec('');\n return !!(match && regexp.lastIndex === 0);\n}\nexports.regExpLeadsToEndlessLoop = regExpLeadsToEndlessLoop;\nfunction regExpContainsBackreference(regexpValue) {\n return !!regexpValue.match(/([^\\\\]|^)(\\\\\\\\)*\\\\\\d+/);\n}\nexports.regExpContainsBackreference = regExpContainsBackreference;\nfunction regExpFlags(regexp) {\n return ((regexp.global ? 'g' : '') +\n (regexp.ignoreCase ? 'i' : '') +\n (regexp.multiline ? 'm' : '') +\n (regexp.unicode ? 'u' : ''));\n}\nexports.regExpFlags = regExpFlags;\n/**\n * Returns first index of the string that is not whitespace.\n * If string is empty or contains only whitespaces, returns -1\n */\nfunction firstNonWhitespaceIndex(str) {\n for (let i = 0, len = str.length; i < len; i++) {\n const chCode = str.charCodeAt(i);\n if (chCode !== 32 /* CharCode.Space */ && chCode !== 9 /* CharCode.Tab */) {\n return i;\n }\n }\n return -1;\n}\nexports.firstNonWhitespaceIndex = firstNonWhitespaceIndex;\n/**\n * Returns the leading whitespace of the string.\n * If the string contains only whitespaces, returns entire string\n */\nfunction getLeadingWhitespace(str, start = 0, end = str.length) {\n for (let i = start; i < end; i++) {\n const chCode = str.charCodeAt(i);\n if (chCode !== 32 /* CharCode.Space */ && chCode !== 9 /* CharCode.Tab */) {\n return str.substring(start, i);\n }\n }\n return str.substring(start, end);\n}\nexports.getLeadingWhitespace = getLeadingWhitespace;\n/**\n * Returns last index of the string that is not whitespace.\n * If string is empty or contains only whitespaces, returns -1\n */\nfunction lastNonWhitespaceIndex(str, startIndex = str.length - 1) {\n for (let i = startIndex; i >= 0; i--) {\n const chCode = str.charCodeAt(i);\n if (chCode !== 32 /* CharCode.Space */ && chCode !== 9 /* CharCode.Tab */) {\n return i;\n }\n }\n return -1;\n}\nexports.lastNonWhitespaceIndex = lastNonWhitespaceIndex;\nfunction compare(a, b) {\n if (a < b) {\n return -1;\n }\n else if (a > b) {\n return 1;\n }\n else {\n return 0;\n }\n}\nexports.compare = compare;\nfunction compareIgnoreCase(a, b) {\n const len = Math.min(a.length, b.length);\n for (let i = 0; i < len; i++) {\n let codeA = a.charCodeAt(i);\n let codeB = b.charCodeAt(i);\n if (codeA === codeB) {\n // equal\n continue;\n }\n if (isUpperAsciiLetter(codeA)) {\n codeA += 32;\n }\n if (isUpperAsciiLetter(codeB)) {\n codeB += 32;\n }\n const diff = codeA - codeB;\n if (diff === 0) {\n // equal -> ignoreCase\n continue;\n }\n else if (isLowerAsciiLetter(codeA) && isLowerAsciiLetter(codeB)) {\n //\n return diff;\n }\n else {\n return compare(a.toLowerCase(), b.toLowerCase());\n }\n }\n if (a.length < b.length) {\n return -1;\n }\n else if (a.length > b.length) {\n return 1;\n }\n else {\n return 0;\n }\n}\nexports.compareIgnoreCase = compareIgnoreCase;\nfunction isLowerAsciiLetter(code) {\n return code >= 97 /* CharCode.a */ && code <= 122 /* CharCode.z */;\n}\nexports.isLowerAsciiLetter = isLowerAsciiLetter;\nfunction isUpperAsciiLetter(code) {\n return code >= 65 /* CharCode.A */ && code <= 90 /* CharCode.Z */;\n}\nexports.isUpperAsciiLetter = isUpperAsciiLetter;\nfunction isAsciiLetter(code) {\n return isLowerAsciiLetter(code) || isUpperAsciiLetter(code);\n}\nfunction equalsIgnoreCase(a, b) {\n const len1 = a ? a.length : 0;\n const len2 = b ? b.length : 0;\n if (len1 !== len2) {\n return false;\n }\n return doEqualsIgnoreCase(a, b);\n}\nexports.equalsIgnoreCase = equalsIgnoreCase;\nfunction doEqualsIgnoreCase(a, b, stopAt = a.length) {\n if (typeof a !== 'string' || typeof b !== 'string') {\n return false;\n }\n for (let i = 0; i < stopAt; i++) {\n const codeA = a.charCodeAt(i);\n const codeB = b.charCodeAt(i);\n if (codeA === codeB) {\n continue;\n }\n // a-z A-Z\n if (isAsciiLetter(codeA) && isAsciiLetter(codeB)) {\n const diff = Math.abs(codeA - codeB);\n if (diff !== 0 && diff !== 32) {\n return false;\n }\n }\n else {\n // Any other charcode\n if (String.fromCharCode(codeA).toLowerCase() !== String.fromCharCode(codeB).toLowerCase()) {\n return false;\n }\n }\n }\n return true;\n}\nfunction startsWithIgnoreCase(str, candidate) {\n const candidateLength = candidate.length;\n if (candidate.length > str.length) {\n return false;\n }\n return doEqualsIgnoreCase(str, candidate, candidateLength);\n}\nexports.startsWithIgnoreCase = startsWithIgnoreCase;\n/**\n * @returns the length of the common prefix of the two strings.\n */\nfunction commonPrefixLength(a, b) {\n let i;\n const len = Math.min(a.length, b.length);\n for (i = 0; i < len; i++) {\n if (a.charCodeAt(i) !== b.charCodeAt(i)) {\n return i;\n }\n }\n return len;\n}\nexports.commonPrefixLength = commonPrefixLength;\n/**\n * @returns the length of the common suffix of the two strings.\n */\nfunction commonSuffixLength(a, b) {\n let i;\n const len = Math.min(a.length, b.length);\n const aLastIndex = a.length - 1;\n const bLastIndex = b.length - 1;\n for (i = 0; i < len; i++) {\n if (a.charCodeAt(aLastIndex - i) !== b.charCodeAt(bLastIndex - i)) {\n return i;\n }\n }\n return len;\n}\nexports.commonSuffixLength = commonSuffixLength;\nfunction substrEquals(a, aStart, aEnd, b, bStart, bEnd) {\n while (aStart < aEnd && bStart < bEnd) {\n if (a[aStart] !== b[bStart]) {\n return false;\n }\n aStart += 1;\n bStart += 1;\n }\n return true;\n}\n/**\n * Return the overlap between the suffix of `a` and the prefix of `b`.\n * For instance `overlap(\"foobar\", \"arr, I'm a pirate\") === 2`.\n */\nfunction overlap(a, b) {\n const aEnd = a.length;\n let bEnd = b.length;\n let aStart = aEnd - bEnd;\n if (aStart === 0) {\n return a === b ? aEnd : 0;\n }\n else if (aStart < 0) {\n bEnd += aStart;\n aStart = 0;\n }\n while (aStart < aEnd && bEnd > 0) {\n if (substrEquals(a, aStart, aEnd, b, 0, bEnd)) {\n return bEnd;\n }\n bEnd -= 1;\n aStart += 1;\n }\n return 0;\n}\nexports.overlap = overlap;\n// --- unicode\n// http://en.wikipedia.org/wiki/Surrogate_pair\n// Returns the code point starting at a specified index in a string\n// Code points U+0000 to U+D7FF and U+E000 to U+FFFF are represented on a single character\n// Code points U+10000 to U+10FFFF are represented on two consecutive characters\n// export function getUnicodePoint(str:string, index:number, len:number):number {\n//\tconst chrCode = str.charCodeAt(index);\n//\tif (0xD800 <= chrCode && chrCode <= 0xDBFF && index + 1 < len) {\n//\t\tconst nextChrCode = str.charCodeAt(index + 1);\n//\t\tif (0xDC00 <= nextChrCode && nextChrCode <= 0xDFFF) {\n//\t\t\treturn (chrCode - 0xD800) << 10 + (nextChrCode - 0xDC00) + 0x10000;\n//\t\t}\n//\t}\n//\treturn chrCode;\n// }\nfunction isHighSurrogate(charCode) {\n return 0xd800 <= charCode && charCode <= 0xdbff;\n}\nexports.isHighSurrogate = isHighSurrogate;\nfunction isLowSurrogate(charCode) {\n return 0xdc00 <= charCode && charCode <= 0xdfff;\n}\nexports.isLowSurrogate = isLowSurrogate;\n/**\n * Generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-rtl-test.js\n */\nconst CONTAINS_RTL = /(?:[\\u05BE\\u05C0\\u05C3\\u05C6\\u05D0-\\u05F4\\u0608\\u060B\\u060D\\u061B-\\u064A\\u066D-\\u066F\\u0671-\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1-\\u07EA\\u07F4\\u07F5\\u07FA-\\u0815\\u081A\\u0824\\u0828\\u0830-\\u0858\\u085E-\\u08BD\\u200F\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFD3D\\uFD50-\\uFDFC\\uFE70-\\uFEFC]|\\uD802[\\uDC00-\\uDD1B\\uDD20-\\uDE00\\uDE10-\\uDE33\\uDE40-\\uDEE4\\uDEEB-\\uDF35\\uDF40-\\uDFFF]|\\uD803[\\uDC00-\\uDCFF]|\\uD83A[\\uDC00-\\uDCCF\\uDD00-\\uDD43\\uDD50-\\uDFFF]|\\uD83B[\\uDC00-\\uDEBB])/;\n/**\n * Returns true if `str` contains any Unicode character that is classified as \"R\" or \"AL\".\n */\nfunction containsRTL(str) {\n return CONTAINS_RTL.test(str);\n}\nexports.containsRTL = containsRTL;\n/**\n * Generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-emoji-test.js\n */\nconst CONTAINS_EMOJI = /(?:[\\u231A\\u231B\\u23F0\\u23F3\\u2600-\\u27BF\\u2B50\\u2B55]|\\uD83C[\\uDDE6-\\uDDFF\\uDF00-\\uDFFF]|\\uD83D[\\uDC00-\\uDE4F\\uDE80-\\uDEF8]|\\uD83E[\\uDD00-\\uDDE6])/;\nfunction containsEmoji(str) {\n return CONTAINS_EMOJI.test(str);\n}\nexports.containsEmoji = containsEmoji;\nconst IS_BASIC_ASCII = /^[\\t\\n\\r\\x20-\\x7E]*$/;\n/**\n * Returns true if `str` contains only basic ASCII characters in the range 32 - 126 (including 32 and 126) or \\n, \\r, \\t\n */\nfunction isBasicASCII(str) {\n return IS_BASIC_ASCII.test(str);\n}\nexports.isBasicASCII = isBasicASCII;\nfunction containsFullWidthCharacter(str) {\n for (let i = 0, len = str.length; i < len; i++) {\n if (isFullWidthCharacter(str.charCodeAt(i))) {\n return true;\n }\n }\n return false;\n}\nexports.containsFullWidthCharacter = containsFullWidthCharacter;\nfunction isFullWidthCharacter(charCode) {\n // Do a cheap trick to better support wrapping of wide characters, treat them as 2 columns\n // http://jrgraphix.net/research/unicode_blocks.php\n // 2E80 — 2EFF CJK Radicals Supplement\n // 2F00 — 2FDF Kangxi Radicals\n // 2FF0 — 2FFF Ideographic Description Characters\n // 3000 — 303F CJK Symbols and Punctuation\n // 3040 — 309F Hiragana\n // 30A0 — 30FF Katakana\n // 3100 — 312F Bopomofo\n // 3130 — 318F Hangul Compatibility Jamo\n // 3190 — 319F Kanbun\n // 31A0 — 31BF Bopomofo Extended\n // 31F0 — 31FF Katakana Phonetic Extensions\n // 3200 — 32FF Enclosed CJK Letters and Months\n // 3300 — 33FF CJK Compatibility\n // 3400 — 4DBF CJK Unified Ideographs Extension A\n // 4DC0 — 4DFF Yijing Hexagram Symbols\n // 4E00 — 9FFF CJK Unified Ideographs\n // A000 — A48F Yi Syllables\n // A490 — A4CF Yi Radicals\n // AC00 — D7AF Hangul Syllables\n // [IGNORE] D800 — DB7F High Surrogates\n // [IGNORE] DB80 — DBFF High Private Use Surrogates\n // [IGNORE] DC00 — DFFF Low Surrogates\n // [IGNORE] E000 — F8FF Private Use Area\n // F900 — FAFF CJK Compatibility Ideographs\n // [IGNORE] FB00 — FB4F Alphabetic Presentation Forms\n // [IGNORE] FB50 — FDFF Arabic Presentation Forms-A\n // [IGNORE] FE00 — FE0F Variation Selectors\n // [IGNORE] FE20 — FE2F Combining Half Marks\n // [IGNORE] FE30 — FE4F CJK Compatibility Forms\n // [IGNORE] FE50 — FE6F Small Form Variants\n // [IGNORE] FE70 — FEFF Arabic Presentation Forms-B\n // FF00 — FFEF Halfwidth and Fullwidth Forms\n // [https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms]\n // of which FF01 - FF5E fullwidth ASCII of 21 to 7E\n // [IGNORE] and FF65 - FFDC halfwidth of Katakana and Hangul\n // [IGNORE] FFF0 — FFFF Specials\n charCode = +charCode; // @perf\n return ((charCode >= 0x2e80 && charCode <= 0xd7af) ||\n (charCode >= 0xf900 && charCode <= 0xfaff) ||\n (charCode >= 0xff01 && charCode <= 0xff5e));\n}\nexports.isFullWidthCharacter = isFullWidthCharacter;\n/**\n * Given a string and a max length returns a shorted version. Shorting\n * happens at favorable positions - such as whitespace or punctuation characters.\n */\nfunction lcut(text, n) {\n if (text.length < n) {\n return text;\n }\n const re = /\\b/g;\n let i = 0;\n while (re.test(text)) {\n if (text.length - re.lastIndex < n) {\n break;\n }\n i = re.lastIndex;\n re.lastIndex += 1;\n }\n return text.substring(i).replace(/^\\s/, exports.empty);\n}\nexports.lcut = lcut;\n// Escape codes\n// http://en.wikipedia.org/wiki/ANSI_escape_code\nconst EL = /\\x1B\\x5B[12]?K/g; // Erase in line\nconst COLOR_START = /\\x1b\\[\\d+m/g; // Color\nconst COLOR_END = /\\x1b\\[0?m/g; // Color\nfunction removeAnsiEscapeCodes(str) {\n if (str) {\n str = str.replace(EL, '');\n str = str.replace(COLOR_START, '');\n str = str.replace(COLOR_END, '');\n }\n return str;\n}\nexports.removeAnsiEscapeCodes = removeAnsiEscapeCodes;\nexports.removeAccents = (function () {\n if (typeof String.prototype.normalize !== 'function') {\n // ☹️ no ES6 features...\n return function (str) {\n return str;\n };\n }\n else {\n // transform into NFD form and remove accents\n // see: https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript/37511463#37511463\n const regex = /[\\u0300-\\u036f]/g;\n return function (str) {\n return str.normalize('NFD').replace(regex, exports.empty);\n };\n }\n})();\n// -- UTF-8 BOM\nexports.UTF8_BOM_CHARACTER = String.fromCharCode(65279 /* CharCode.UTF8_BOM */);\nfunction startsWithUTF8BOM(str) {\n return !!(str && str.length > 0 && str.charCodeAt(0) === 65279 /* CharCode.UTF8_BOM */);\n}\nexports.startsWithUTF8BOM = startsWithUTF8BOM;\nfunction stripUTF8BOM(str) {\n return startsWithUTF8BOM(str) ? str.substr(1) : str;\n}\nexports.stripUTF8BOM = stripUTF8BOM;\nfunction safeBtoa(str) {\n return btoa(encodeURIComponent(str)); // we use encodeURIComponent because btoa fails for non Latin 1 values\n}\nexports.safeBtoa = safeBtoa;\nfunction repeat(s, count) {\n let result = '';\n for (let i = 0; i < count; i++) {\n result += s;\n }\n return result;\n}\nexports.repeat = repeat;\n/**\n * Checks if the characters of the provided query string are included in the\n * target string. The characters do not have to be contiguous within the string.\n */\nfunction fuzzyContains(target, query) {\n if (!target || !query) {\n return false; // return early if target or query are undefined\n }\n if (target.length < query.length) {\n return false; // impossible for query to be contained in target\n }\n const queryLen = query.length;\n const targetLower = target.toLowerCase();\n let index = 0;\n let lastIndexOf = -1;\n while (index < queryLen) {\n const indexOf = targetLower.indexOf(query[index], lastIndexOf + 1);\n if (indexOf < 0) {\n return false;\n }\n lastIndexOf = indexOf;\n index++;\n }\n return true;\n}\nexports.fuzzyContains = fuzzyContains;\nfunction containsUppercaseCharacter(target, ignoreEscapedChars = false) {\n if (!target) {\n return false;\n }\n if (ignoreEscapedChars) {\n target = target.replace(/\\\\./g, '');\n }\n return target.toLowerCase() !== target;\n}\nexports.containsUppercaseCharacter = containsUppercaseCharacter;\nfunction uppercaseFirstLetter(str) {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\nexports.uppercaseFirstLetter = uppercaseFirstLetter;\nfunction getNLines(str, n = 1) {\n if (n === 0) {\n return '';\n }\n let idx = -1;\n do {\n idx = str.indexOf('\\n', idx + 1);\n n--;\n } while (n > 0 && idx >= 0);\n return idx >= 0 ? str.substr(0, idx) : str;\n}\nexports.getNLines = getNLines;\n/**\n * See http://en.wikipedia.org/wiki/Surrogate_pair\n */\nfunction computeCodePoint(highSurrogate, lowSurrogate) {\n return ((highSurrogate - 0xd800) << 10) + (lowSurrogate - 0xdc00) + 0x10000;\n}\nexports.computeCodePoint = computeCodePoint;\n/**\n * get the code point that begins at offset `offset`\n */\nfunction getNextCodePoint(str, len, offset) {\n const charCode = str.charCodeAt(offset);\n if (isHighSurrogate(charCode) && offset + 1 < len) {\n const nextCharCode = str.charCodeAt(offset + 1);\n if (isLowSurrogate(nextCharCode)) {\n return computeCodePoint(charCode, nextCharCode);\n }\n }\n return charCode;\n}\nexports.getNextCodePoint = getNextCodePoint;\n/**\n * A manual encoding of `str` to UTF8.\n * Use only in environments which do not offer native conversion methods!\n */\nfunction encodeUTF8(str) {\n const strLen = str.length;\n // See https://en.wikipedia.org/wiki/UTF-8\n // first loop to establish needed buffer size\n let neededSize = 0;\n let strOffset = 0;\n while (strOffset < strLen) {\n const codePoint = getNextCodePoint(str, strLen, strOffset);\n strOffset += codePoint >= 65536 /* Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN */ ? 2 : 1;\n if (codePoint < 0x0080) {\n neededSize += 1;\n }\n else if (codePoint < 0x0800) {\n neededSize += 2;\n }\n else if (codePoint < 0x10000) {\n neededSize += 3;\n }\n else {\n neededSize += 4;\n }\n }\n // second loop to actually encode\n const arr = new Uint8Array(neededSize);\n strOffset = 0;\n let arrOffset = 0;\n while (strOffset < strLen) {\n const codePoint = getNextCodePoint(str, strLen, strOffset);\n strOffset += codePoint >= 65536 /* Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN */ ? 2 : 1;\n if (codePoint < 0x0080) {\n arr[arrOffset++] = codePoint;\n }\n else if (codePoint < 0x0800) {\n arr[arrOffset++] = 0b11000000 | ((codePoint & 0b00000000000000000000011111000000) >>> 6);\n arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);\n }\n else if (codePoint < 0x10000) {\n arr[arrOffset++] = 0b11100000 | ((codePoint & 0b00000000000000001111000000000000) >>> 12);\n arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6);\n arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);\n }\n else {\n arr[arrOffset++] = 0b11110000 | ((codePoint & 0b00000000000111000000000000000000) >>> 18);\n arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000111111000000000000) >>> 12);\n arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6);\n arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);\n }\n }\n return arr;\n}\nexports.encodeUTF8 = encodeUTF8;\n/**\n * A manual decoding of a UTF8 string.\n * Use only in environments which do not offer native conversion methods!\n */\nfunction decodeUTF8(buffer) {\n // https://en.wikipedia.org/wiki/UTF-8\n const len = buffer.byteLength;\n const result = [];\n let offset = 0;\n while (offset < len) {\n const v0 = buffer[offset];\n let codePoint;\n if (v0 >= 0b11110000 && offset + 3 < len) {\n // 4 bytes\n codePoint =\n (((buffer[offset++] & 0b00000111) << 18) >>> 0) |\n (((buffer[offset++] & 0b00111111) << 12) >>> 0) |\n (((buffer[offset++] & 0b00111111) << 6) >>> 0) |\n (((buffer[offset++] & 0b00111111) << 0) >>> 0);\n }\n else if (v0 >= 0b11100000 && offset + 2 < len) {\n // 3 bytes\n codePoint =\n (((buffer[offset++] & 0b00001111) << 12) >>> 0) |\n (((buffer[offset++] & 0b00111111) << 6) >>> 0) |\n (((buffer[offset++] & 0b00111111) << 0) >>> 0);\n }\n else if (v0 >= 0b11000000 && offset + 1 < len) {\n // 2 bytes\n codePoint = (((buffer[offset++] & 0b00011111) << 6) >>> 0) | (((buffer[offset++] & 0b00111111) << 0) >>> 0);\n }\n else {\n // 1 byte\n codePoint = buffer[offset++];\n }\n if ((codePoint >= 0 && codePoint <= 0xd7ff) || (codePoint >= 0xe000 && codePoint <= 0xffff)) {\n // Basic Multilingual Plane\n result.push(String.fromCharCode(codePoint));\n }\n else if (codePoint >= 0x010000 && codePoint <= 0x10ffff) {\n // Supplementary Planes\n const uPrime = codePoint - 0x10000;\n const w1 = 0xd800 + ((uPrime & 0b11111111110000000000) >>> 10);\n const w2 = 0xdc00 + ((uPrime & 0b00000000001111111111) >>> 0);\n result.push(String.fromCharCode(w1));\n result.push(String.fromCharCode(w2));\n }\n else {\n // illegal code point\n result.push(String.fromCharCode(0xfffd));\n }\n }\n return result.join('');\n}\nexports.decodeUTF8 = decodeUTF8;\n/**\n * 插值表达式的标记使用的是 ${}\n * 该函数会对 options 中的 separator 会有特殊处理,\n */\nfunction template(tpl, variables, options) {\n const result = [];\n let placeHolderStack = [];\n for (let idx = 0; idx < tpl.length; idx++) {\n const char = tpl[idx];\n const nextChar = tpl[idx + 1];\n // 往后多看一位\n if (char === '$' && nextChar === '{') {\n // 往后的可能是占位符了,注入进栈标志位(即 $)\n // 如果 placeHolder 栈已经有值了,现在不支持嵌套 ${},直接吐出所有值放到 result 中即可\n if (placeHolderStack.length > 0) {\n result.push(...placeHolderStack);\n placeHolderStack = [];\n }\n placeHolderStack.push(char);\n placeHolderStack.push(nextChar);\n idx++;\n continue;\n }\n // 如果当前 placeHolder 栈有字符,一直将字符入栈,直到匹配到 }\n if (placeHolderStack.length > 0) {\n if (char === '}') {\n // 占位符匹配结束\n // 拿出占位符进行值替换\n const placeholder = placeHolderStack.slice(2).join('');\n let v;\n if (placeholder === 'separator') {\n if (result[result.length - 1] === options.separator) {\n // 不需要重复 separator\n placeHolderStack = [];\n continue;\n }\n // 分隔符有单独的优化\n v = options.separator;\n }\n else {\n v = variables[placeholder];\n }\n const toPush = v !== null && v !== void 0 ? v : options.defaultValue;\n if (toPush) {\n result.push(toPush);\n }\n placeHolderStack = [];\n }\n else {\n placeHolderStack.push(char);\n }\n continue;\n }\n result.push(tpl[idx]);\n }\n // 去除前面和后面的 sep\n // 这些 sep 也是不需要的\n while (result[result.length - 1] === options.separator) {\n result.pop();\n }\n while (result[0] === options.separator) {\n result.shift();\n }\n return result.join('');\n}\nexports.template = template;\nconst _format2Regexp = /{([^}]+)}/g;\n/**\n * Helper to create a string from a template and a string record.\n * Similar to `format` but with objects instead of positional arguments.\n */\nfunction format2(template, values) {\n return template.replace(_format2Regexp, (match, group) => { var _a; return ((_a = values[group]) !== null && _a !== void 0 ? _a : match); });\n}\nexports.format2 = format2;\n//# sourceMappingURL=strings.js.map\n\n//# sourceURL=webpack://@opensumi/ide-components/../utils/lib/strings.js?");
6976
+ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.containsUppercaseCharacter = exports.fuzzyContains = exports.repeat = exports.safeBtoa = exports.stripUTF8BOM = exports.startsWithUTF8BOM = exports.UTF8_BOM_CHARACTER = exports.removeAccents = exports.removeAnsiEscapeCodes = exports.lcut = exports.isFullWidthCharacter = exports.containsFullWidthCharacter = exports.isBasicASCII = exports.containsEmoji = exports.containsRTL = exports.isLowSurrogate = exports.isHighSurrogate = exports.overlap = exports.commonSuffixLength = exports.commonPrefixLength = exports.startsWithIgnoreCase = exports.equalsIgnoreCase = exports.isUpperAsciiLetter = exports.isLowerAsciiLetter = exports.compareIgnoreCase = exports.compare = exports.lastNonWhitespaceIndex = exports.getLeadingWhitespace = exports.firstNonWhitespaceIndex = exports.regExpFlags = exports.regExpContainsBackreference = exports.regExpLeadsToEndlessLoop = exports.createRegExp = exports.endsWith = exports.startsWith = exports.stripWildcards = exports.convertSimple2RegExpPattern = exports.rtrim = exports.multiRightTrim = exports.ltrim = exports.trim = exports.count = exports.escapeRegExpCharacters = exports.escape = exports.mnemonicButtonLabel = exports.format = exports.pad = exports.isFalsyOrWhitespace = exports.stringUtils = exports.empty = void 0;\nexports.getChunks = exports.format2 = exports.template = exports.decodeUTF8 = exports.encodeUTF8 = exports.getNextCodePoint = exports.computeCodePoint = exports.getNLines = exports.uppercaseFirstLetter = void 0;\nconst platform_1 = __webpack_require__(/*! ./platform */ \"../utils/lib/platform.js\");\n/**\n * The empty string.\n */\nexports.empty = '';\nconst hasTextEncoder = typeof TextEncoder !== 'undefined';\nconst hasTextDecoder = typeof TextDecoder !== 'undefined';\n/**\n * 浏览器全局可以直接使用 TextEncoder/TextDecoder\n * Node.js 11+ 才可以全局使用,以下需要 require('util')\n */\nvar stringUtils;\n(function (stringUtils) {\n stringUtils.StringTextEncoder = hasTextEncoder ? TextEncoder : (__webpack_require__(/*! util */ \"../../node_modules/util/util.js\").TextEncoder);\n stringUtils.StringTextDecoder = hasTextDecoder ? TextDecoder : (__webpack_require__(/*! util */ \"../../node_modules/util/util.js\").TextDecoder);\n})(stringUtils = exports.stringUtils || (exports.stringUtils = {}));\nfunction isFalsyOrWhitespace(str) {\n if (!str || typeof str !== 'string') {\n return true;\n }\n return str.trim().length === 0;\n}\nexports.isFalsyOrWhitespace = isFalsyOrWhitespace;\n/**\n * @returns the provided number with the given number of preceding zeros.\n */\nfunction pad(n, l, char = '0') {\n const str = '' + n;\n const r = [str];\n for (let i = str.length; i < l; i++) {\n r.push(char);\n }\n return r.reverse().join('');\n}\nexports.pad = pad;\nconst _formatRegexp = /{(\\d+)}/g;\n/**\n * Helper to produce a string with a variable number of arguments. Insert variable segments\n * into the string using the {n} notation where N is the index of the argument following the string.\n * @param value string to which formatting is applied\n * @param args replacements for {n}-entries\n */\nfunction format(value, ...args) {\n if (args.length === 0) {\n return value;\n }\n return value.replace(_formatRegexp, function (match, group) {\n const idx = parseInt(group, 10);\n return isNaN(idx) || idx < 0 || idx >= args.length ? match : args[idx];\n });\n}\nexports.format = format;\n/**\n * Handles mnemonics for buttons. Depending on OS:\n * - Windows: Supported via & character (replace && with & and & with && for escaping)\n * - Linux: Supported via _ character (replace && with _)\n * - macOS: Unsupported (replace && with empty string)\n */\nfunction mnemonicButtonLabel(label, forceDisableMnemonics) {\n if (platform_1.isMacintosh || forceDisableMnemonics) {\n return label.replace(/\\(&&\\w\\)|&&/g, '');\n }\n if (platform_1.isWindows) {\n return label.replace(/&&|&/g, (m) => (m === '&' ? '&&' : '&'));\n }\n return label.replace(/&&/g, '_');\n}\nexports.mnemonicButtonLabel = mnemonicButtonLabel;\n/**\n * Converts HTML characters inside the string to use entities instead. Makes the string safe from\n * being used e.g. in HTMLElement.innerHTML.\n */\nfunction escape(html) {\n return html.replace(/[<>&]/g, function (match) {\n switch (match) {\n case '<':\n return '&lt;';\n case '>':\n return '&gt;';\n case '&':\n return '&amp;';\n default:\n return match;\n }\n });\n}\nexports.escape = escape;\n/**\n * Escapes regular expression characters in a given string\n */\nfunction escapeRegExpCharacters(value) {\n return value.replace(/[\\\\\\{\\}\\*\\+\\?\\|\\^\\$\\.\\[\\]\\(\\)]/g, '\\\\$&');\n}\nexports.escapeRegExpCharacters = escapeRegExpCharacters;\n/**\n * Counts how often `character` occurs inside `value`.\n */\nfunction count(value, character) {\n let result = 0;\n const ch = character.charCodeAt(0);\n for (let i = value.length - 1; i >= 0; i--) {\n if (value.charCodeAt(i) === ch) {\n result++;\n }\n }\n return result;\n}\nexports.count = count;\n/**\n * Removes all occurrences of needle from the beginning and end of haystack.\n * @param haystack string to trim\n * @param needle the thing to trim (default is a blank)\n */\nfunction trim(haystack, needle = ' ') {\n const trimmed = ltrim(haystack, needle);\n return rtrim(trimmed, needle);\n}\nexports.trim = trim;\n/**\n * Removes all occurrences of needle from the beginning of haystack.\n * @param haystack string to trim\n * @param needle the thing to trim\n */\nfunction ltrim(haystack, needle) {\n if (!haystack || !needle) {\n return haystack;\n }\n const needleLen = needle.length;\n if (needleLen === 0 || haystack.length === 0) {\n return haystack;\n }\n let offset = 0;\n while (haystack.indexOf(needle, offset) === offset) {\n offset = offset + needleLen;\n }\n return haystack.substring(offset);\n}\nexports.ltrim = ltrim;\n/**\n * Removes all occurrences of needles from the end of haystack.\n * @param source\n * @param needles\n * @example\n * ```ts\n * let source = '/path/to/file.ts,;';\n * const res = multiRightTrim(source, [`,`, ';']);\n * // res === '/path/to/file.ts';\n * ```\n */\nfunction multiRightTrim(source, needles) {\n let result = decodeURIComponent(source);\n for (const needle of needles) {\n result = rtrim(result, needle);\n }\n return result;\n}\nexports.multiRightTrim = multiRightTrim;\n/**\n * Removes all occurrences of needle from the end of haystack.\n * @param haystack string to trim\n * @param needle the thing to trim\n */\nfunction rtrim(haystack, needle) {\n if (!haystack || !needle) {\n return haystack;\n }\n const needleLen = needle.length;\n const haystackLen = haystack.length;\n if (needleLen === 0 || haystackLen === 0) {\n return haystack;\n }\n let offset = haystackLen;\n let idx = -1;\n while (true) {\n idx = haystack.lastIndexOf(needle, offset - 1);\n if (idx === -1 || idx + needleLen !== offset) {\n break;\n }\n if (idx === 0) {\n return '';\n }\n offset = idx;\n }\n return haystack.substring(0, offset);\n}\nexports.rtrim = rtrim;\nfunction convertSimple2RegExpPattern(pattern) {\n return pattern.replace(/[\\-\\\\\\{\\}\\+\\?\\|\\^\\$\\.\\,\\[\\]\\(\\)\\#\\s]/g, '\\\\$&').replace(/[\\*]/g, '.*');\n}\nexports.convertSimple2RegExpPattern = convertSimple2RegExpPattern;\nfunction stripWildcards(pattern) {\n return pattern.replace(/\\*/g, '');\n}\nexports.stripWildcards = stripWildcards;\n/**\n * Determines if haystack starts with needle.\n */\nfunction startsWith(haystack, needle) {\n if (haystack.length < needle.length) {\n return false;\n }\n if (haystack === needle) {\n return true;\n }\n for (let i = 0; i < needle.length; i++) {\n if (haystack[i] !== needle[i]) {\n return false;\n }\n }\n return true;\n}\nexports.startsWith = startsWith;\n/**\n * Determines if haystack ends with needle.\n */\nfunction endsWith(haystack, needle) {\n const diff = haystack.length - needle.length;\n if (diff > 0) {\n return haystack.indexOf(needle, diff) === diff;\n }\n else if (diff === 0) {\n return haystack === needle;\n }\n else {\n return false;\n }\n}\nexports.endsWith = endsWith;\nfunction createRegExp(searchString, isRegex, options = {}) {\n if (!searchString) {\n throw new Error('Cannot create regex from empty string');\n }\n if (!isRegex) {\n searchString = escapeRegExpCharacters(searchString);\n }\n if (options.wholeWord) {\n if (!/\\B/.test(searchString.charAt(0))) {\n searchString = '\\\\b' + searchString;\n }\n if (!/\\B/.test(searchString.charAt(searchString.length - 1))) {\n searchString = searchString + '\\\\b';\n }\n }\n let modifiers = '';\n if (options.global) {\n modifiers += 'g';\n }\n if (!options.matchCase) {\n modifiers += 'i';\n }\n if (options.multiline) {\n modifiers += 'm';\n }\n if (options.unicode) {\n modifiers += 'u';\n }\n return new RegExp(searchString, modifiers);\n}\nexports.createRegExp = createRegExp;\nfunction regExpLeadsToEndlessLoop(regexp) {\n // Exit early if it's one of these special cases which are meant to match\n // against an empty string\n if (regexp.source === '^' || regexp.source === '^$' || regexp.source === '$' || regexp.source === '^\\\\s*$') {\n return false;\n }\n // We check against an empty string. If the regular expression doesn't advance\n // (e.g. ends in an endless loop) it will match an empty string.\n const match = regexp.exec('');\n return !!(match && regexp.lastIndex === 0);\n}\nexports.regExpLeadsToEndlessLoop = regExpLeadsToEndlessLoop;\nfunction regExpContainsBackreference(regexpValue) {\n return !!regexpValue.match(/([^\\\\]|^)(\\\\\\\\)*\\\\\\d+/);\n}\nexports.regExpContainsBackreference = regExpContainsBackreference;\nfunction regExpFlags(regexp) {\n return ((regexp.global ? 'g' : '') +\n (regexp.ignoreCase ? 'i' : '') +\n (regexp.multiline ? 'm' : '') +\n (regexp.unicode ? 'u' : ''));\n}\nexports.regExpFlags = regExpFlags;\n/**\n * Returns first index of the string that is not whitespace.\n * If string is empty or contains only whitespaces, returns -1\n */\nfunction firstNonWhitespaceIndex(str) {\n for (let i = 0, len = str.length; i < len; i++) {\n const chCode = str.charCodeAt(i);\n if (chCode !== 32 /* CharCode.Space */ && chCode !== 9 /* CharCode.Tab */) {\n return i;\n }\n }\n return -1;\n}\nexports.firstNonWhitespaceIndex = firstNonWhitespaceIndex;\n/**\n * Returns the leading whitespace of the string.\n * If the string contains only whitespaces, returns entire string\n */\nfunction getLeadingWhitespace(str, start = 0, end = str.length) {\n for (let i = start; i < end; i++) {\n const chCode = str.charCodeAt(i);\n if (chCode !== 32 /* CharCode.Space */ && chCode !== 9 /* CharCode.Tab */) {\n return str.substring(start, i);\n }\n }\n return str.substring(start, end);\n}\nexports.getLeadingWhitespace = getLeadingWhitespace;\n/**\n * Returns last index of the string that is not whitespace.\n * If string is empty or contains only whitespaces, returns -1\n */\nfunction lastNonWhitespaceIndex(str, startIndex = str.length - 1) {\n for (let i = startIndex; i >= 0; i--) {\n const chCode = str.charCodeAt(i);\n if (chCode !== 32 /* CharCode.Space */ && chCode !== 9 /* CharCode.Tab */) {\n return i;\n }\n }\n return -1;\n}\nexports.lastNonWhitespaceIndex = lastNonWhitespaceIndex;\nfunction compare(a, b) {\n if (a < b) {\n return -1;\n }\n else if (a > b) {\n return 1;\n }\n else {\n return 0;\n }\n}\nexports.compare = compare;\nfunction compareIgnoreCase(a, b) {\n const len = Math.min(a.length, b.length);\n for (let i = 0; i < len; i++) {\n let codeA = a.charCodeAt(i);\n let codeB = b.charCodeAt(i);\n if (codeA === codeB) {\n // equal\n continue;\n }\n if (isUpperAsciiLetter(codeA)) {\n codeA += 32;\n }\n if (isUpperAsciiLetter(codeB)) {\n codeB += 32;\n }\n const diff = codeA - codeB;\n if (diff === 0) {\n // equal -> ignoreCase\n continue;\n }\n else if (isLowerAsciiLetter(codeA) && isLowerAsciiLetter(codeB)) {\n //\n return diff;\n }\n else {\n return compare(a.toLowerCase(), b.toLowerCase());\n }\n }\n if (a.length < b.length) {\n return -1;\n }\n else if (a.length > b.length) {\n return 1;\n }\n else {\n return 0;\n }\n}\nexports.compareIgnoreCase = compareIgnoreCase;\nfunction isLowerAsciiLetter(code) {\n return code >= 97 /* CharCode.a */ && code <= 122 /* CharCode.z */;\n}\nexports.isLowerAsciiLetter = isLowerAsciiLetter;\nfunction isUpperAsciiLetter(code) {\n return code >= 65 /* CharCode.A */ && code <= 90 /* CharCode.Z */;\n}\nexports.isUpperAsciiLetter = isUpperAsciiLetter;\nfunction isAsciiLetter(code) {\n return isLowerAsciiLetter(code) || isUpperAsciiLetter(code);\n}\nfunction equalsIgnoreCase(a, b) {\n const len1 = a ? a.length : 0;\n const len2 = b ? b.length : 0;\n if (len1 !== len2) {\n return false;\n }\n return doEqualsIgnoreCase(a, b);\n}\nexports.equalsIgnoreCase = equalsIgnoreCase;\nfunction doEqualsIgnoreCase(a, b, stopAt = a.length) {\n if (typeof a !== 'string' || typeof b !== 'string') {\n return false;\n }\n for (let i = 0; i < stopAt; i++) {\n const codeA = a.charCodeAt(i);\n const codeB = b.charCodeAt(i);\n if (codeA === codeB) {\n continue;\n }\n // a-z A-Z\n if (isAsciiLetter(codeA) && isAsciiLetter(codeB)) {\n const diff = Math.abs(codeA - codeB);\n if (diff !== 0 && diff !== 32) {\n return false;\n }\n }\n else {\n // Any other charcode\n if (String.fromCharCode(codeA).toLowerCase() !== String.fromCharCode(codeB).toLowerCase()) {\n return false;\n }\n }\n }\n return true;\n}\nfunction startsWithIgnoreCase(str, candidate) {\n const candidateLength = candidate.length;\n if (candidate.length > str.length) {\n return false;\n }\n return doEqualsIgnoreCase(str, candidate, candidateLength);\n}\nexports.startsWithIgnoreCase = startsWithIgnoreCase;\n/**\n * @returns the length of the common prefix of the two strings.\n */\nfunction commonPrefixLength(a, b) {\n let i;\n const len = Math.min(a.length, b.length);\n for (i = 0; i < len; i++) {\n if (a.charCodeAt(i) !== b.charCodeAt(i)) {\n return i;\n }\n }\n return len;\n}\nexports.commonPrefixLength = commonPrefixLength;\n/**\n * @returns the length of the common suffix of the two strings.\n */\nfunction commonSuffixLength(a, b) {\n let i;\n const len = Math.min(a.length, b.length);\n const aLastIndex = a.length - 1;\n const bLastIndex = b.length - 1;\n for (i = 0; i < len; i++) {\n if (a.charCodeAt(aLastIndex - i) !== b.charCodeAt(bLastIndex - i)) {\n return i;\n }\n }\n return len;\n}\nexports.commonSuffixLength = commonSuffixLength;\nfunction substrEquals(a, aStart, aEnd, b, bStart, bEnd) {\n while (aStart < aEnd && bStart < bEnd) {\n if (a[aStart] !== b[bStart]) {\n return false;\n }\n aStart += 1;\n bStart += 1;\n }\n return true;\n}\n/**\n * Return the overlap between the suffix of `a` and the prefix of `b`.\n * For instance `overlap(\"foobar\", \"arr, I'm a pirate\") === 2`.\n */\nfunction overlap(a, b) {\n const aEnd = a.length;\n let bEnd = b.length;\n let aStart = aEnd - bEnd;\n if (aStart === 0) {\n return a === b ? aEnd : 0;\n }\n else if (aStart < 0) {\n bEnd += aStart;\n aStart = 0;\n }\n while (aStart < aEnd && bEnd > 0) {\n if (substrEquals(a, aStart, aEnd, b, 0, bEnd)) {\n return bEnd;\n }\n bEnd -= 1;\n aStart += 1;\n }\n return 0;\n}\nexports.overlap = overlap;\n// --- unicode\n// http://en.wikipedia.org/wiki/Surrogate_pair\n// Returns the code point starting at a specified index in a string\n// Code points U+0000 to U+D7FF and U+E000 to U+FFFF are represented on a single character\n// Code points U+10000 to U+10FFFF are represented on two consecutive characters\n// export function getUnicodePoint(str:string, index:number, len:number):number {\n//\tconst chrCode = str.charCodeAt(index);\n//\tif (0xD800 <= chrCode && chrCode <= 0xDBFF && index + 1 < len) {\n//\t\tconst nextChrCode = str.charCodeAt(index + 1);\n//\t\tif (0xDC00 <= nextChrCode && nextChrCode <= 0xDFFF) {\n//\t\t\treturn (chrCode - 0xD800) << 10 + (nextChrCode - 0xDC00) + 0x10000;\n//\t\t}\n//\t}\n//\treturn chrCode;\n// }\nfunction isHighSurrogate(charCode) {\n return 0xd800 <= charCode && charCode <= 0xdbff;\n}\nexports.isHighSurrogate = isHighSurrogate;\nfunction isLowSurrogate(charCode) {\n return 0xdc00 <= charCode && charCode <= 0xdfff;\n}\nexports.isLowSurrogate = isLowSurrogate;\n/**\n * Generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-rtl-test.js\n */\nconst CONTAINS_RTL = /(?:[\\u05BE\\u05C0\\u05C3\\u05C6\\u05D0-\\u05F4\\u0608\\u060B\\u060D\\u061B-\\u064A\\u066D-\\u066F\\u0671-\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1-\\u07EA\\u07F4\\u07F5\\u07FA-\\u0815\\u081A\\u0824\\u0828\\u0830-\\u0858\\u085E-\\u08BD\\u200F\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFD3D\\uFD50-\\uFDFC\\uFE70-\\uFEFC]|\\uD802[\\uDC00-\\uDD1B\\uDD20-\\uDE00\\uDE10-\\uDE33\\uDE40-\\uDEE4\\uDEEB-\\uDF35\\uDF40-\\uDFFF]|\\uD803[\\uDC00-\\uDCFF]|\\uD83A[\\uDC00-\\uDCCF\\uDD00-\\uDD43\\uDD50-\\uDFFF]|\\uD83B[\\uDC00-\\uDEBB])/;\n/**\n * Returns true if `str` contains any Unicode character that is classified as \"R\" or \"AL\".\n */\nfunction containsRTL(str) {\n return CONTAINS_RTL.test(str);\n}\nexports.containsRTL = containsRTL;\n/**\n * Generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-emoji-test.js\n */\nconst CONTAINS_EMOJI = /(?:[\\u231A\\u231B\\u23F0\\u23F3\\u2600-\\u27BF\\u2B50\\u2B55]|\\uD83C[\\uDDE6-\\uDDFF\\uDF00-\\uDFFF]|\\uD83D[\\uDC00-\\uDE4F\\uDE80-\\uDEF8]|\\uD83E[\\uDD00-\\uDDE6])/;\nfunction containsEmoji(str) {\n return CONTAINS_EMOJI.test(str);\n}\nexports.containsEmoji = containsEmoji;\nconst IS_BASIC_ASCII = /^[\\t\\n\\r\\x20-\\x7E]*$/;\n/**\n * Returns true if `str` contains only basic ASCII characters in the range 32 - 126 (including 32 and 126) or \\n, \\r, \\t\n */\nfunction isBasicASCII(str) {\n return IS_BASIC_ASCII.test(str);\n}\nexports.isBasicASCII = isBasicASCII;\nfunction containsFullWidthCharacter(str) {\n for (let i = 0, len = str.length; i < len; i++) {\n if (isFullWidthCharacter(str.charCodeAt(i))) {\n return true;\n }\n }\n return false;\n}\nexports.containsFullWidthCharacter = containsFullWidthCharacter;\nfunction isFullWidthCharacter(charCode) {\n // Do a cheap trick to better support wrapping of wide characters, treat them as 2 columns\n // http://jrgraphix.net/research/unicode_blocks.php\n // 2E80 — 2EFF CJK Radicals Supplement\n // 2F00 — 2FDF Kangxi Radicals\n // 2FF0 — 2FFF Ideographic Description Characters\n // 3000 — 303F CJK Symbols and Punctuation\n // 3040 — 309F Hiragana\n // 30A0 — 30FF Katakana\n // 3100 — 312F Bopomofo\n // 3130 — 318F Hangul Compatibility Jamo\n // 3190 — 319F Kanbun\n // 31A0 — 31BF Bopomofo Extended\n // 31F0 — 31FF Katakana Phonetic Extensions\n // 3200 — 32FF Enclosed CJK Letters and Months\n // 3300 — 33FF CJK Compatibility\n // 3400 — 4DBF CJK Unified Ideographs Extension A\n // 4DC0 — 4DFF Yijing Hexagram Symbols\n // 4E00 — 9FFF CJK Unified Ideographs\n // A000 — A48F Yi Syllables\n // A490 — A4CF Yi Radicals\n // AC00 — D7AF Hangul Syllables\n // [IGNORE] D800 — DB7F High Surrogates\n // [IGNORE] DB80 — DBFF High Private Use Surrogates\n // [IGNORE] DC00 — DFFF Low Surrogates\n // [IGNORE] E000 — F8FF Private Use Area\n // F900 — FAFF CJK Compatibility Ideographs\n // [IGNORE] FB00 — FB4F Alphabetic Presentation Forms\n // [IGNORE] FB50 — FDFF Arabic Presentation Forms-A\n // [IGNORE] FE00 — FE0F Variation Selectors\n // [IGNORE] FE20 — FE2F Combining Half Marks\n // [IGNORE] FE30 — FE4F CJK Compatibility Forms\n // [IGNORE] FE50 — FE6F Small Form Variants\n // [IGNORE] FE70 — FEFF Arabic Presentation Forms-B\n // FF00 — FFEF Halfwidth and Fullwidth Forms\n // [https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms]\n // of which FF01 - FF5E fullwidth ASCII of 21 to 7E\n // [IGNORE] and FF65 - FFDC halfwidth of Katakana and Hangul\n // [IGNORE] FFF0 — FFFF Specials\n charCode = +charCode; // @perf\n return ((charCode >= 0x2e80 && charCode <= 0xd7af) ||\n (charCode >= 0xf900 && charCode <= 0xfaff) ||\n (charCode >= 0xff01 && charCode <= 0xff5e));\n}\nexports.isFullWidthCharacter = isFullWidthCharacter;\n/**\n * Given a string and a max length returns a shorted version. Shorting\n * happens at favorable positions - such as whitespace or punctuation characters.\n */\nfunction lcut(text, n) {\n if (text.length < n) {\n return text;\n }\n const re = /\\b/g;\n let i = 0;\n while (re.test(text)) {\n if (text.length - re.lastIndex < n) {\n break;\n }\n i = re.lastIndex;\n re.lastIndex += 1;\n }\n return text.substring(i).replace(/^\\s/, exports.empty);\n}\nexports.lcut = lcut;\n// Escape codes\n// http://en.wikipedia.org/wiki/ANSI_escape_code\nconst EL = /\\x1B\\x5B[12]?K/g; // Erase in line\nconst COLOR_START = /\\x1b\\[\\d+m/g; // Color\nconst COLOR_END = /\\x1b\\[0?m/g; // Color\nfunction removeAnsiEscapeCodes(str) {\n if (str) {\n str = str.replace(EL, '');\n str = str.replace(COLOR_START, '');\n str = str.replace(COLOR_END, '');\n }\n return str;\n}\nexports.removeAnsiEscapeCodes = removeAnsiEscapeCodes;\nexports.removeAccents = (function () {\n if (typeof String.prototype.normalize !== 'function') {\n // ☹️ no ES6 features...\n return function (str) {\n return str;\n };\n }\n else {\n // transform into NFD form and remove accents\n // see: https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript/37511463#37511463\n const regex = /[\\u0300-\\u036f]/g;\n return function (str) {\n return str.normalize('NFD').replace(regex, exports.empty);\n };\n }\n})();\n// -- UTF-8 BOM\nexports.UTF8_BOM_CHARACTER = String.fromCharCode(65279 /* CharCode.UTF8_BOM */);\nfunction startsWithUTF8BOM(str) {\n return !!(str && str.length > 0 && str.charCodeAt(0) === 65279 /* CharCode.UTF8_BOM */);\n}\nexports.startsWithUTF8BOM = startsWithUTF8BOM;\nfunction stripUTF8BOM(str) {\n return startsWithUTF8BOM(str) ? str.substr(1) : str;\n}\nexports.stripUTF8BOM = stripUTF8BOM;\nfunction safeBtoa(str) {\n return btoa(encodeURIComponent(str)); // we use encodeURIComponent because btoa fails for non Latin 1 values\n}\nexports.safeBtoa = safeBtoa;\nfunction repeat(s, count) {\n let result = '';\n for (let i = 0; i < count; i++) {\n result += s;\n }\n return result;\n}\nexports.repeat = repeat;\n/**\n * Checks if the characters of the provided query string are included in the\n * target string. The characters do not have to be contiguous within the string.\n */\nfunction fuzzyContains(target, query) {\n if (!target || !query) {\n return false; // return early if target or query are undefined\n }\n if (target.length < query.length) {\n return false; // impossible for query to be contained in target\n }\n const queryLen = query.length;\n const targetLower = target.toLowerCase();\n let index = 0;\n let lastIndexOf = -1;\n while (index < queryLen) {\n const indexOf = targetLower.indexOf(query[index], lastIndexOf + 1);\n if (indexOf < 0) {\n return false;\n }\n lastIndexOf = indexOf;\n index++;\n }\n return true;\n}\nexports.fuzzyContains = fuzzyContains;\nfunction containsUppercaseCharacter(target, ignoreEscapedChars = false) {\n if (!target) {\n return false;\n }\n if (ignoreEscapedChars) {\n target = target.replace(/\\\\./g, '');\n }\n return target.toLowerCase() !== target;\n}\nexports.containsUppercaseCharacter = containsUppercaseCharacter;\nfunction uppercaseFirstLetter(str) {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\nexports.uppercaseFirstLetter = uppercaseFirstLetter;\nfunction getNLines(str, n = 1) {\n if (n === 0) {\n return '';\n }\n let idx = -1;\n do {\n idx = str.indexOf('\\n', idx + 1);\n n--;\n } while (n > 0 && idx >= 0);\n return idx >= 0 ? str.substr(0, idx) : str;\n}\nexports.getNLines = getNLines;\n/**\n * See http://en.wikipedia.org/wiki/Surrogate_pair\n */\nfunction computeCodePoint(highSurrogate, lowSurrogate) {\n return ((highSurrogate - 0xd800) << 10) + (lowSurrogate - 0xdc00) + 0x10000;\n}\nexports.computeCodePoint = computeCodePoint;\n/**\n * get the code point that begins at offset `offset`\n */\nfunction getNextCodePoint(str, len, offset) {\n const charCode = str.charCodeAt(offset);\n if (isHighSurrogate(charCode) && offset + 1 < len) {\n const nextCharCode = str.charCodeAt(offset + 1);\n if (isLowSurrogate(nextCharCode)) {\n return computeCodePoint(charCode, nextCharCode);\n }\n }\n return charCode;\n}\nexports.getNextCodePoint = getNextCodePoint;\n/**\n * A manual encoding of `str` to UTF8.\n * Use only in environments which do not offer native conversion methods!\n */\nfunction encodeUTF8(str) {\n const strLen = str.length;\n // See https://en.wikipedia.org/wiki/UTF-8\n // first loop to establish needed buffer size\n let neededSize = 0;\n let strOffset = 0;\n while (strOffset < strLen) {\n const codePoint = getNextCodePoint(str, strLen, strOffset);\n strOffset += codePoint >= 65536 /* Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN */ ? 2 : 1;\n if (codePoint < 0x0080) {\n neededSize += 1;\n }\n else if (codePoint < 0x0800) {\n neededSize += 2;\n }\n else if (codePoint < 0x10000) {\n neededSize += 3;\n }\n else {\n neededSize += 4;\n }\n }\n // second loop to actually encode\n const arr = new Uint8Array(neededSize);\n strOffset = 0;\n let arrOffset = 0;\n while (strOffset < strLen) {\n const codePoint = getNextCodePoint(str, strLen, strOffset);\n strOffset += codePoint >= 65536 /* Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN */ ? 2 : 1;\n if (codePoint < 0x0080) {\n arr[arrOffset++] = codePoint;\n }\n else if (codePoint < 0x0800) {\n arr[arrOffset++] = 0b11000000 | ((codePoint & 0b00000000000000000000011111000000) >>> 6);\n arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);\n }\n else if (codePoint < 0x10000) {\n arr[arrOffset++] = 0b11100000 | ((codePoint & 0b00000000000000001111000000000000) >>> 12);\n arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6);\n arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);\n }\n else {\n arr[arrOffset++] = 0b11110000 | ((codePoint & 0b00000000000111000000000000000000) >>> 18);\n arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000111111000000000000) >>> 12);\n arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6);\n arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);\n }\n }\n return arr;\n}\nexports.encodeUTF8 = encodeUTF8;\n/**\n * A manual decoding of a UTF8 string.\n * Use only in environments which do not offer native conversion methods!\n */\nfunction decodeUTF8(buffer) {\n // https://en.wikipedia.org/wiki/UTF-8\n const len = buffer.byteLength;\n const result = [];\n let offset = 0;\n while (offset < len) {\n const v0 = buffer[offset];\n let codePoint;\n if (v0 >= 0b11110000 && offset + 3 < len) {\n // 4 bytes\n codePoint =\n (((buffer[offset++] & 0b00000111) << 18) >>> 0) |\n (((buffer[offset++] & 0b00111111) << 12) >>> 0) |\n (((buffer[offset++] & 0b00111111) << 6) >>> 0) |\n (((buffer[offset++] & 0b00111111) << 0) >>> 0);\n }\n else if (v0 >= 0b11100000 && offset + 2 < len) {\n // 3 bytes\n codePoint =\n (((buffer[offset++] & 0b00001111) << 12) >>> 0) |\n (((buffer[offset++] & 0b00111111) << 6) >>> 0) |\n (((buffer[offset++] & 0b00111111) << 0) >>> 0);\n }\n else if (v0 >= 0b11000000 && offset + 1 < len) {\n // 2 bytes\n codePoint = (((buffer[offset++] & 0b00011111) << 6) >>> 0) | (((buffer[offset++] & 0b00111111) << 0) >>> 0);\n }\n else {\n // 1 byte\n codePoint = buffer[offset++];\n }\n if ((codePoint >= 0 && codePoint <= 0xd7ff) || (codePoint >= 0xe000 && codePoint <= 0xffff)) {\n // Basic Multilingual Plane\n result.push(String.fromCharCode(codePoint));\n }\n else if (codePoint >= 0x010000 && codePoint <= 0x10ffff) {\n // Supplementary Planes\n const uPrime = codePoint - 0x10000;\n const w1 = 0xd800 + ((uPrime & 0b11111111110000000000) >>> 10);\n const w2 = 0xdc00 + ((uPrime & 0b00000000001111111111) >>> 0);\n result.push(String.fromCharCode(w1));\n result.push(String.fromCharCode(w2));\n }\n else {\n // illegal code point\n result.push(String.fromCharCode(0xfffd));\n }\n }\n return result.join('');\n}\nexports.decodeUTF8 = decodeUTF8;\n/**\n * 插值表达式的标记使用的是 ${}\n * 该函数会对 options 中的 separator 会有特殊处理,\n */\nfunction template(tpl, variables, options) {\n const result = [];\n let placeHolderStack = [];\n for (let idx = 0; idx < tpl.length; idx++) {\n const char = tpl[idx];\n const nextChar = tpl[idx + 1];\n // 往后多看一位\n if (char === '$' && nextChar === '{') {\n // 往后的可能是占位符了,注入进栈标志位(即 $)\n // 如果 placeHolder 栈已经有值了,现在不支持嵌套 ${},直接吐出所有值放到 result 中即可\n if (placeHolderStack.length > 0) {\n result.push(...placeHolderStack);\n placeHolderStack = [];\n }\n placeHolderStack.push(char);\n placeHolderStack.push(nextChar);\n idx++;\n continue;\n }\n // 如果当前 placeHolder 栈有字符,一直将字符入栈,直到匹配到 }\n if (placeHolderStack.length > 0) {\n if (char === '}') {\n // 占位符匹配结束\n // 拿出占位符进行值替换\n const placeholder = placeHolderStack.slice(2).join('');\n let v;\n if (placeholder === 'separator') {\n if (result[result.length - 1] === options.separator) {\n // 不需要重复 separator\n placeHolderStack = [];\n continue;\n }\n // 分隔符有单独的优化\n v = options.separator;\n }\n else {\n v = variables[placeholder];\n }\n const toPush = v !== null && v !== void 0 ? v : options.defaultValue;\n if (toPush) {\n result.push(toPush);\n }\n placeHolderStack = [];\n }\n else {\n placeHolderStack.push(char);\n }\n continue;\n }\n result.push(tpl[idx]);\n }\n // 去除前面和后面的 sep\n // 这些 sep 也是不需要的\n while (result[result.length - 1] === options.separator) {\n result.pop();\n }\n while (result[0] === options.separator) {\n result.shift();\n }\n return result.join('');\n}\nexports.template = template;\nconst _format2Regexp = /{([^}]+)}/g;\n/**\n * Helper to create a string from a template and a string record.\n * Similar to `format` but with objects instead of positional arguments.\n */\nfunction format2(template, values) {\n return template.replace(_format2Regexp, (match, group) => { var _a; return ((_a = values[group]) !== null && _a !== void 0 ? _a : match); });\n}\nexports.format2 = format2;\nfunction getChunks(str, size) {\n const strLength = str.length;\n const numChunks = Math.ceil(strLength / size);\n const chunks = new Array(numChunks);\n let i = 0;\n let o = 0;\n for (; i < numChunks; ++i, o += size) {\n chunks[i] = str.substr(o, size);\n }\n return chunks;\n}\nexports.getChunks = getChunks;\n//# sourceMappingURL=strings.js.map\n\n//# sourceURL=webpack://@opensumi/ide-components/../utils/lib/strings.js?");
6988
6977
 
6989
6978
  /***/ }),
6990
6979