@opensumi/ide-components 3.1.2-next-1718700994.0 → 3.1.2-next-1718701452.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.css +0 -6
- package/dist/index.js +6 -17
- package/lib/markdown/styles.less +0 -12
- package/lib/recycle-tree/tree/TreeNode.d.ts +9 -11
- package/lib/recycle-tree/tree/TreeNode.d.ts.map +1 -1
- package/lib/recycle-tree/tree/TreeNode.js +78 -63
- package/lib/recycle-tree/tree/TreeNode.js.map +1 -1
- package/lib/recycle-tree/tree/model/treeState/TreeStateManager.d.ts +2 -0
- package/lib/recycle-tree/tree/model/treeState/TreeStateManager.d.ts.map +1 -1
- package/lib/recycle-tree/tree/model/treeState/TreeStateManager.js +7 -3
- package/lib/recycle-tree/tree/model/treeState/TreeStateManager.js.map +1 -1
- package/lib/recycle-tree/types/watcher.d.ts +12 -12
- package/lib/recycle-tree/types/watcher.d.ts.map +1 -1
- package/lib/scrollbars/styles.less +0 -10
- package/package.json +4 -4
- package/lib/recycle-tree/path.d.ts +0 -11
- package/lib/recycle-tree/path.d.ts.map +0 -1
- package/lib/recycle-tree/path.js +0 -28
- package/lib/recycle-tree/path.js.map +0 -1
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
|
|
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
|
|
|
@@ -5796,7 +5785,7 @@ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\ncons
|
|
|
5796
5785
|
/***/ ((__unused_webpack_module, exports) => {
|
|
5797
5786
|
|
|
5798
5787
|
"use strict";
|
|
5799
|
-
eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.
|
|
5788
|
+
eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.AIInlineChatContentWidgetId = void 0;\nexports.AIInlineChatContentWidgetId = 'AI-Inline-Chat-Content-Widget';\n//# sourceMappingURL=views.js.map\n\n//# sourceURL=webpack://@opensumi/ide-components/../core-common/lib/ai-native/views.js?");
|
|
5800
5789
|
|
|
5801
5790
|
/***/ }),
|
|
5802
5791
|
|
|
@@ -6753,7 +6742,7 @@ eval("\n/* ---------------------------------------------------------------------
|
|
|
6753
6742
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
6754
6743
|
|
|
6755
6744
|
"use strict";
|
|
6756
|
-
eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.FileUri = void 0;\nconst
|
|
6745
|
+
eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.FileUri = void 0;\nconst platform_1 = __webpack_require__(/*! ./platform */ \"../utils/lib/platform.js\");\nconst uri_1 = __webpack_require__(/*! ./uri */ \"../utils/lib/uri.js\");\nvar FileUri;\n(function (FileUri) {\n const windowsDriveRegex = /^([^:/?#]+?):$/;\n /**\n * Creates a new file URI from the filesystem path argument.\n * @param fsPath the filesystem path.\n */\n function create(_fsPath) {\n return new uri_1.URI(uri_1.Uri.file(_fsPath));\n }\n FileUri.create = create;\n /**\n * Returns with the platform specific FS path that is represented by the URI argument.\n *\n * @param uri the file URI that has to be resolved to a platform specific FS path.\n */\n function fsPath(uri) {\n if (typeof uri === 'string') {\n return fsPath(new uri_1.URI(uri));\n }\n else {\n /*\n * A uri for the root of a Windows drive, eg file:\\\\\\c%3A, is converted to c:\n * by the Uri class. However file:\\\\\\c%3A is unambiguously a uri to the root of\n * the drive and c: is interpreted as the default directory for the c drive\n * (by, for example, the readdir function in the fs-extra module).\n * A backslash must be appended to the drive, eg c:\\, to ensure the correct path.\n */\n const fsPathFromVsCodeUri = uri.codeUri.fsPath;\n if (platform_1.isWindows) {\n const isWindowsDriveRoot = windowsDriveRegex.exec(fsPathFromVsCodeUri);\n if (isWindowsDriveRoot) {\n return fsPathFromVsCodeUri + '\\\\';\n }\n }\n return fsPathFromVsCodeUri;\n }\n }\n FileUri.fsPath = fsPath;\n})(FileUri = exports.FileUri || (exports.FileUri = {}));\n//# sourceMappingURL=file-uri.js.map\n\n//# sourceURL=webpack://@opensumi/ide-components/../utils/lib/file-uri.js?");
|
|
6757
6746
|
|
|
6758
6747
|
/***/ }),
|
|
6759
6748
|
|
|
@@ -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.
|
|
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
|
|